mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
tweaking multiple assignment targets
This commit is contained in:
parent
fad74a6ae0
commit
c90230d33a
31
compiler/examples/swirl-novm.p8
Normal file
31
compiler/examples/swirl-novm.p8
Normal file
@ -0,0 +1,31 @@
|
||||
%import c64utils
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
||||
const uword width = 320
|
||||
const uword height = 200
|
||||
|
||||
sub start() {
|
||||
|
||||
;vm_gfx_clearscr(0)
|
||||
|
||||
float t
|
||||
ubyte color
|
||||
|
||||
while(1) {
|
||||
float x = sin(t*1.01) + cos(t*1.1234)
|
||||
float y = cos(t) + sin(t*0.03456)
|
||||
;vm_gfx_pixel(screenx(x), screeny(y), color//16)
|
||||
t += 0.01
|
||||
color++
|
||||
}
|
||||
}
|
||||
|
||||
sub screenx(x: float) -> word {
|
||||
return floor(x * flt(width)/4.1) + width // 2
|
||||
}
|
||||
sub screeny(y: float) -> word {
|
||||
return floor(y * flt(height)/4.1) + height // 2
|
||||
}
|
||||
}
|
@ -16,7 +16,12 @@ sub start() {
|
||||
byte b1
|
||||
|
||||
|
||||
;v1=foo() ; @todo fix return type value error see sub
|
||||
;v1=foo()
|
||||
|
||||
address =c64.MEMBOT(1, 40000.w) ; ok!
|
||||
address =c64.MEMBOT(1, address) ; ok!
|
||||
address =c64.MEMBOT(1, memaddr) ; ok!i
|
||||
;address =c64.MEMBOT(1, wordarray[1]) ; @todo nice error about loading X register from stack
|
||||
|
||||
A, Y =c64.GETADR() ; ok!
|
||||
Y, A =c64.GETADR() ; ok!
|
||||
@ -24,7 +29,6 @@ sub start() {
|
||||
memaddr = c64flt.GETADRAY() ; ok!
|
||||
wordarray[1] = c64flt.GETADRAY() ; ok!
|
||||
v1, v2 =c64.GETADR() ; ok!
|
||||
address =c64.MEMBOT(1, 0.w) ; ok !
|
||||
address =c64.IOBASE() ; ok!
|
||||
A = c64.CHRIN() ; ok !
|
||||
X = c64.CHRIN() ; ok !
|
||||
@ -34,8 +38,8 @@ sub start() {
|
||||
}
|
||||
|
||||
|
||||
sub foo() -> ubyte {
|
||||
return 1 ; @todo not ubyte but byte (if sub returns byte)
|
||||
sub foo() -> byte {
|
||||
return 1 ; @todo fix error: '1' as byte literal (not ubyte)
|
||||
}
|
||||
|
||||
|
||||
|
@ -304,25 +304,27 @@ class AstChecker(private val namespace: INameScope,
|
||||
override fun process(assignment: Assignment): IStatement {
|
||||
|
||||
// assigning from a functioncall COULD return multiple values (from an asm subroutine)
|
||||
val stmt = (assignment.value as FunctionCall).target.targetStatement(namespace)
|
||||
if(stmt is Subroutine && stmt.returntypes.size>1) {
|
||||
if(stmt.isAsmSubroutine) {
|
||||
if(stmt.returntypes.size != assignment.targets.size)
|
||||
checkResult.add(ExpressionError("number of return values doesn't match number of assignment targets", assignment.value.position))
|
||||
else {
|
||||
if(assignment.targets.all{it.register!=null}) {
|
||||
val returnRegisters = registerSet(stmt.asmReturnvaluesRegisters)
|
||||
val targetRegisters = assignment.targets.filter { it.register != null }.map { it.register }.toSet()
|
||||
if (returnRegisters != targetRegisters)
|
||||
checkResult.add(ExpressionError("asmsub return registers $returnRegisters don't match assignment target registers", assignment.position))
|
||||
if(assignment.value is FunctionCall) {
|
||||
val stmt = (assignment.value as FunctionCall).target.targetStatement(namespace)
|
||||
if (stmt is Subroutine && stmt.returntypes.size > 1) {
|
||||
if (stmt.isAsmSubroutine) {
|
||||
if (stmt.returntypes.size != assignment.targets.size)
|
||||
checkResult.add(ExpressionError("number of return values doesn't match number of assignment targets", assignment.value.position))
|
||||
else {
|
||||
if (assignment.targets.all { it.register != null }) {
|
||||
val returnRegisters = registerSet(stmt.asmReturnvaluesRegisters)
|
||||
val targetRegisters = assignment.targets.filter { it.register != null }.map { it.register }.toSet()
|
||||
if (returnRegisters != targetRegisters)
|
||||
checkResult.add(ExpressionError("asmsub return registers $returnRegisters don't match assignment target registers", assignment.position))
|
||||
}
|
||||
for (thing in stmt.returntypes.zip(assignment.targets)) {
|
||||
if (thing.second.determineDatatype(namespace, heap, assignment) != thing.first)
|
||||
checkResult.add(ExpressionError("return type mismatch for target ${thing.second.shortString()}", assignment.value.position))
|
||||
}
|
||||
}
|
||||
for(thing in stmt.returntypes.zip(assignment.targets)) {
|
||||
if(thing.second.determineDatatype(namespace, heap, assignment)!=thing.first)
|
||||
checkResult.add(ExpressionError("return type mismatch for target ${thing.second.shortString()}", assignment.value.position))
|
||||
}
|
||||
}
|
||||
} else
|
||||
checkResult.add(ExpressionError("only asmsub subroutines can return multiple values", assignment.value.position))
|
||||
} else
|
||||
checkResult.add(ExpressionError("only asmsub subroutines can return multiple values", assignment.value.position))
|
||||
}
|
||||
}
|
||||
|
||||
var resultingAssignment = assignment
|
||||
|
@ -1,6 +1,8 @@
|
||||
package prog8.compiler
|
||||
|
||||
import com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile
|
||||
import prog8.ast.*
|
||||
import prog8.ast.RegisterOrPair.*
|
||||
import prog8.compiler.intermediate.IntermediateProgram
|
||||
import prog8.compiler.intermediate.Opcode
|
||||
import prog8.compiler.intermediate.Value
|
||||
@ -792,11 +794,109 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
|
||||
private fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>, callPosition: Position) {
|
||||
// evaluate the arguments and assign them into the subroutine's argument variables.
|
||||
prog.line(callPosition)
|
||||
|
||||
if(subroutine.asmParameterRegisters.isNotEmpty()) {
|
||||
if(subroutine.parameters.size!=subroutine.asmParameterRegisters.size)
|
||||
throw CompilerException("no support for mix of register and non-register subroutine arguments")
|
||||
|
||||
// only register arguments (or status-flag bits)
|
||||
var carryParam: Boolean? = null
|
||||
for(arg in arguments.zip(subroutine.asmParameterRegisters)) {
|
||||
if(arg.second.statusflag!=null) {
|
||||
if(arg.second.statusflag==Statusflag.Pc)
|
||||
carryParam = arg.first.constValue(namespace, heap)!!.asBooleanValue
|
||||
else
|
||||
throw CompilerException("no support for status flag parameter: ${arg.second.statusflag}")
|
||||
} else {
|
||||
when (arg.second.registerOrPair!!) {
|
||||
A -> {
|
||||
val assign = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, arg.first, callPosition)
|
||||
assign.linkParents(subroutine.parent)
|
||||
translate(assign)
|
||||
}
|
||||
X -> {
|
||||
// TODO: save X on stack & restore after call
|
||||
val assign = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, arg.first, callPosition)
|
||||
assign.linkParents(subroutine.parent)
|
||||
translate(assign)
|
||||
}
|
||||
Y -> {
|
||||
val assign = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, arg.first, callPosition)
|
||||
assign.linkParents(subroutine.parent)
|
||||
translate(assign)
|
||||
}
|
||||
AX -> {
|
||||
// TODO: save X on stack & restore after call
|
||||
val valueA: IExpression
|
||||
val valueX: IExpression
|
||||
val paramDt = arg.first.resultingDatatype(namespace, heap)
|
||||
if(paramDt==DataType.UBYTE) {
|
||||
valueA=arg.first
|
||||
valueX=LiteralValue.optimalInteger(0, callPosition)
|
||||
val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition)
|
||||
val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition)
|
||||
assignA.linkParents(subroutine.parent)
|
||||
assignX.linkParents(subroutine.parent)
|
||||
translate(assignA)
|
||||
translate(assignX)
|
||||
} else if(paramDt==DataType.UWORD) {
|
||||
translate(arg.first)
|
||||
prog.instr(Opcode.POP_REGAX_WORD)
|
||||
} else
|
||||
throw CompilerException("don't know how to pass register parameter of type $paramDt")
|
||||
}
|
||||
AY -> {
|
||||
val valueA: IExpression
|
||||
val valueY: IExpression
|
||||
val paramDt = arg.first.resultingDatatype(namespace, heap)
|
||||
if(paramDt==DataType.UBYTE) {
|
||||
valueA=arg.first
|
||||
valueY=LiteralValue.optimalInteger(0, callPosition)
|
||||
val assignA = Assignment(listOf(AssignTarget(Register.A, null, null, callPosition)), null, valueA, callPosition)
|
||||
val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition)
|
||||
assignA.linkParents(subroutine.parent)
|
||||
assignY.linkParents(subroutine.parent)
|
||||
translate(assignA)
|
||||
translate(assignY)
|
||||
} else if(paramDt==DataType.UWORD) {
|
||||
translate(arg.first)
|
||||
prog.instr(Opcode.POP_REGAY_WORD)
|
||||
} else
|
||||
throw CompilerException("don't know how to pass register parameter of type $paramDt")
|
||||
}
|
||||
XY -> {
|
||||
// TODO: save X on stack & restore after call
|
||||
val valueX: IExpression
|
||||
val valueY: IExpression
|
||||
val paramDt = arg.first.resultingDatatype(namespace, heap)
|
||||
if(paramDt==DataType.UBYTE) {
|
||||
valueX=arg.first
|
||||
valueY=LiteralValue.optimalInteger(0, callPosition)
|
||||
val assignX = Assignment(listOf(AssignTarget(Register.X, null, null, callPosition)), null, valueX, callPosition)
|
||||
val assignY = Assignment(listOf(AssignTarget(Register.Y, null, null, callPosition)), null, valueY, callPosition)
|
||||
assignX.linkParents(subroutine.parent)
|
||||
assignY.linkParents(subroutine.parent)
|
||||
translate(assignX)
|
||||
translate(assignY)
|
||||
} else if(paramDt==DataType.UWORD) {
|
||||
translate(arg.first)
|
||||
prog.instr(Opcode.POP_REGXY_WORD)
|
||||
} else
|
||||
throw CompilerException("don't know how to pass register parameter of type $paramDt")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// carry is set last, to avoid clobbering it when loading the other parameters
|
||||
when(carryParam) {
|
||||
true -> prog.instr(Opcode.SEC)
|
||||
false -> prog.instr(Opcode.CLC)
|
||||
}
|
||||
|
||||
if(subroutine.asmReturnvaluesRegisters.isNotEmpty()) {
|
||||
TODO("call asmsub by loading registers instead")
|
||||
} else {
|
||||
prog.line(callPosition)
|
||||
// only regular (non-register) arguments
|
||||
for (arg in arguments.zip(subroutine.parameters)) {
|
||||
translate(arg.first)
|
||||
val opcode = opcodePopvar(arg.second.type)
|
||||
@ -1195,22 +1295,22 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
if(registerOrStatus.statusflag!=null)
|
||||
return
|
||||
when(registerOrStatus.registerOrPair){
|
||||
RegisterOrPair.A -> {
|
||||
A -> {
|
||||
val assignment = Assignment(listOf(target), null, RegisterExpr(Register.A, target.position), target.position)
|
||||
assignment.linkParents(parent)
|
||||
translate(assignment)
|
||||
}
|
||||
RegisterOrPair.X -> {
|
||||
X -> {
|
||||
val assignment = Assignment(listOf(target), null, RegisterExpr(Register.X, target.position), target.position)
|
||||
assignment.linkParents(parent)
|
||||
translate(assignment)
|
||||
}
|
||||
RegisterOrPair.Y -> {
|
||||
Y -> {
|
||||
val assignment = Assignment(listOf(target), null, RegisterExpr(Register.Y, target.position), target.position)
|
||||
assignment.linkParents(parent)
|
||||
translate(assignment)
|
||||
}
|
||||
RegisterOrPair.AX -> {
|
||||
AX -> {
|
||||
// deal with register pair AX: target = A + X*256
|
||||
val targetDt = target.determineDatatype(namespace, heap, parent)
|
||||
if(targetDt!=DataType.UWORD)
|
||||
@ -1218,7 +1318,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
prog.instr(Opcode.PUSH_REGAX_WORD)
|
||||
popValueIntoTarget(target, targetDt)
|
||||
}
|
||||
RegisterOrPair.AY -> {
|
||||
AY -> {
|
||||
// deal with register pair AY: target = A + Y*256
|
||||
val targetDt = target.determineDatatype(namespace, heap, parent)
|
||||
if(targetDt!=DataType.UWORD)
|
||||
@ -1226,7 +1326,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
prog.instr(Opcode.PUSH_REGAY_WORD)
|
||||
popValueIntoTarget(target, targetDt)
|
||||
}
|
||||
RegisterOrPair.XY -> {
|
||||
XY -> {
|
||||
// deal with register pair XY: target = X + Y*256
|
||||
val targetDt = target.determineDatatype(namespace, heap, parent)
|
||||
if(targetDt!=DataType.UWORD)
|
||||
|
@ -28,6 +28,9 @@ enum class Opcode {
|
||||
POP_VAR_BYTE, // pop (u)byte value into variable
|
||||
POP_VAR_WORD, // pop (u)word value into variable
|
||||
POP_VAR_FLOAT, // pop float value into variable
|
||||
POP_REGAX_WORD, // pop uword from stack into A/X registers
|
||||
POP_REGAY_WORD, // pop uword from stack into A/Y registers
|
||||
POP_REGXY_WORD, // pop uword from stack into X/Y registers
|
||||
|
||||
// numeric arithmetic
|
||||
ADD_UB,
|
||||
|
@ -462,6 +462,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
Opcode.PUSH_REGAY_WORD -> {
|
||||
" sta ${ESTACK_LO.toHex()},x | tya | sta ${ESTACK_HI.toHex()},x | dex "
|
||||
}
|
||||
Opcode.POP_REGAX_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
|
||||
Opcode.POP_REGXY_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
|
||||
Opcode.POP_REGAY_WORD -> {
|
||||
" inx | lda ${ESTACK_LO.toHex()},x | ldy ${ESTACK_HI.toHex()},x "
|
||||
}
|
||||
|
||||
Opcode.READ_INDEXED_VAR_BYTE -> { // @todo is this correct?
|
||||
"""
|
||||
@ -2440,13 +2445,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
|
||||
|
||||
// ---------- some special operations ------------------
|
||||
// var word = AY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGAY_WORD, Opcode.POP_VAR_WORD)) { segment ->
|
||||
"""
|
||||
sta ${segment[1].callLabel}
|
||||
sty ${segment[1].callLabel}+1
|
||||
"""
|
||||
},
|
||||
// var word = AX register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGAX_WORD, Opcode.POP_VAR_WORD)) { segment ->
|
||||
"""
|
||||
@ -2454,6 +2452,13 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
stx ${segment[1].callLabel}+1
|
||||
"""
|
||||
},
|
||||
// var word = AY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGAY_WORD, Opcode.POP_VAR_WORD)) { segment ->
|
||||
"""
|
||||
sta ${segment[1].callLabel}
|
||||
sty ${segment[1].callLabel}+1
|
||||
"""
|
||||
},
|
||||
// var word = XY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGXY_WORD, Opcode.POP_VAR_WORD)) { segment ->
|
||||
"""
|
||||
@ -2461,13 +2466,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
sty ${segment[1].callLabel}+1
|
||||
"""
|
||||
},
|
||||
// mem word = AY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGAY_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
"""
|
||||
sta ${hexVal(segment[1])}
|
||||
sty ${hexValPlusOne(segment[1])}
|
||||
"""
|
||||
},
|
||||
// mem word = AX register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGAX_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
"""
|
||||
@ -2475,16 +2473,70 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
stx ${hexValPlusOne(segment[1])}
|
||||
"""
|
||||
},
|
||||
// mem word = AY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGAY_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
"""
|
||||
sta ${hexVal(segment[1])}
|
||||
sty ${hexValPlusOne(segment[1])}
|
||||
"""
|
||||
},
|
||||
// mem word = XY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGXY_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
"""
|
||||
stx ${hexVal(segment[1])}
|
||||
sty ${hexValPlusOne(segment[1])}
|
||||
"""
|
||||
},
|
||||
|
||||
// AX register pair = word value
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_REGAX_WORD)) { segment ->
|
||||
val value = hexVal(segment[0])
|
||||
" lda #<$value | ldx #>$value"
|
||||
},
|
||||
// AY register pair = word value
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_REGAY_WORD)) { segment ->
|
||||
val value = hexVal(segment[0])
|
||||
" lda #<$value | ldy #>$value"
|
||||
},
|
||||
// XY register pair = word value
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_REGXY_WORD)) { segment ->
|
||||
val value = hexVal(segment[0])
|
||||
" ldx #<$value | ldy #>$value"
|
||||
},
|
||||
// AX register pair = word var
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGAX_WORD)) { segment ->
|
||||
" lda #<${segment[0].callLabel} | ldx #>${segment[0].callLabel}"
|
||||
},
|
||||
// AY register pair = word var
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGAY_WORD)) { segment ->
|
||||
" lda #<${segment[0].callLabel} | ldy #>${segment[0].callLabel}"
|
||||
},
|
||||
// XY register pair = word var
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_REGXY_WORD)) { segment ->
|
||||
" ldx #<${segment[0].callLabel} | ldy #>${segment[0].callLabel}"
|
||||
},
|
||||
// AX register pair = mem word
|
||||
AsmPattern(
|
||||
listOf(Opcode.PUSH_MEM_UW, Opcode.POP_REGAX_WORD),
|
||||
listOf(Opcode.PUSH_MEM_W, Opcode.POP_REGAX_WORD)) { segment ->
|
||||
" lda ${hexVal(segment[0])} | ldx ${hexValPlusOne(segment[0])}"
|
||||
},
|
||||
// AY register pair = mem word
|
||||
AsmPattern(
|
||||
listOf(Opcode.PUSH_MEM_UW, Opcode.POP_REGAY_WORD),
|
||||
listOf(Opcode.PUSH_MEM_W, Opcode.POP_REGAY_WORD)) { segment ->
|
||||
" lda ${hexVal(segment[0])} | ldy ${hexValPlusOne(segment[0])}"
|
||||
},
|
||||
// XY register pair = mem word
|
||||
AsmPattern(
|
||||
listOf(Opcode.PUSH_MEM_UW, Opcode.POP_REGXY_WORD),
|
||||
listOf(Opcode.PUSH_MEM_W, Opcode.POP_REGXY_WORD)) { segment ->
|
||||
" ldx ${hexVal(segment[0])} | ldy ${hexValPlusOne(segment[0])}"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// // @todo assignment: floatarray[idxbyte] = float
|
||||
// AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
|
||||
// val floatConst = getFloatConst(segment[0].arg!!)
|
||||
|
@ -777,6 +777,21 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val y=variables["Y"]!!.integerValue()
|
||||
evalstack.push(Value(DataType.UWORD, y*256+x))
|
||||
}
|
||||
Opcode.POP_REGAX_WORD -> {
|
||||
val value=evalstack.pop().integerValue()
|
||||
variables["A"] = Value(DataType.UBYTE, value and 255)
|
||||
variables["X"] = Value(DataType.UBYTE, value shr 8)
|
||||
}
|
||||
Opcode.POP_REGAY_WORD -> {
|
||||
val value=evalstack.pop().integerValue()
|
||||
variables["A"] = Value(DataType.UBYTE, value and 255)
|
||||
variables["Y"] = Value(DataType.UBYTE, value shr 8)
|
||||
}
|
||||
Opcode.POP_REGXY_WORD -> {
|
||||
val value=evalstack.pop().integerValue()
|
||||
variables["X"] = Value(DataType.UBYTE, value and 255)
|
||||
variables["Y"] = Value(DataType.UBYTE, value shr 8)
|
||||
}
|
||||
Opcode.POP_VAR_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
|
Loading…
x
Reference in New Issue
Block a user