mirror of
https://github.com/irmen/prog8.git
synced 2024-10-17 10:24:55 +00:00
tweaking multiple assignment targets
This commit is contained in:
parent
a2a8a772ec
commit
fad74a6ae0
@ -11,16 +11,24 @@ sub start() {
|
||||
ubyte v2
|
||||
float f2
|
||||
uword address
|
||||
memory uword memaddr = $c000
|
||||
uword[2] wordarray
|
||||
byte b1
|
||||
|
||||
|
||||
v1=foo()
|
||||
X, Y =c64.GETADR()
|
||||
v1, v2 =c64.GETADR()
|
||||
address =c64.MEMBOT(1, 0.w)
|
||||
address =c64.IOBASE()
|
||||
A = c64.CHRIN()
|
||||
X = c64.CHRIN()
|
||||
v1 = c64.CHRIN()
|
||||
;v1=foo() ; @todo fix return type value error see sub
|
||||
|
||||
A, Y =c64.GETADR() ; ok!
|
||||
Y, A =c64.GETADR() ; ok!
|
||||
address = c64flt.GETADRAY() ; ok!
|
||||
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 !
|
||||
v1 = c64.CHRIN() ; ok !
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -394,7 +394,6 @@ interface INameScope {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private object ParentSentinel : Node {
|
||||
override val position = Position("<<sentinel>>", 0, 0, 0)
|
||||
override var parent: Node = this
|
||||
@ -1436,7 +1435,7 @@ class InlineAssembly(val assembly: String, override val position: Position) : IS
|
||||
}
|
||||
|
||||
|
||||
class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?)
|
||||
data class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?)
|
||||
|
||||
class AnonymousScope(override var statements: MutableList<IStatement>,
|
||||
override val position: Position) : INameScope, IStatement {
|
||||
@ -1592,8 +1591,6 @@ fun prog8Parser.ModuleContext.toAst(name: String) : Module =
|
||||
Module(name, modulestatement().asSequence().map { it.toAst() }.toMutableList(), toPosition())
|
||||
|
||||
|
||||
/************** Helper extension methods (private) ************/
|
||||
|
||||
private fun ParserRuleContext.toPosition() : Position {
|
||||
val file = Paths.get(this.start.inputStream.sourceName).fileName.toString()
|
||||
// note: be ware of TAB characters in the source text, they count as 1 column...
|
||||
@ -2056,3 +2053,28 @@ private fun prog8Parser.RepeatloopContext.toAst(): RepeatLoop {
|
||||
val scope = AnonymousScope(statements, statement_block()?.toPosition() ?: statement().toPosition())
|
||||
return RepeatLoop(scope, untilCondition, toPosition())
|
||||
}
|
||||
|
||||
|
||||
internal fun registerSet(asmReturnvaluesRegisters: Iterable<RegisterOrStatusflag>): Set<Register> {
|
||||
val resultRegisters = mutableSetOf<Register>()
|
||||
for(x in asmReturnvaluesRegisters) {
|
||||
when(x.registerOrPair) {
|
||||
RegisterOrPair.A -> resultRegisters.add(Register.A)
|
||||
RegisterOrPair.X -> resultRegisters.add(Register.X)
|
||||
RegisterOrPair.Y -> resultRegisters.add(Register.Y)
|
||||
RegisterOrPair.AX -> {
|
||||
resultRegisters.add(Register.A)
|
||||
resultRegisters.add(Register.X)
|
||||
}
|
||||
RegisterOrPair.AY -> {
|
||||
resultRegisters.add(Register.A)
|
||||
resultRegisters.add(Register.Y)
|
||||
}
|
||||
RegisterOrPair.XY -> {
|
||||
resultRegisters.add(Register.X)
|
||||
resultRegisters.add(Register.Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultRegisters
|
||||
}
|
||||
|
@ -177,7 +177,6 @@ class AstChecker(private val namespace: INameScope,
|
||||
return super.process(label)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check subroutine definition
|
||||
*/
|
||||
@ -300,9 +299,32 @@ class AstChecker(private val namespace: INameScope,
|
||||
|
||||
/**
|
||||
* Assignment target must be register, or a variable name
|
||||
* Also check data type compatibility
|
||||
* Also check data type compatibility and number of values
|
||||
*/
|
||||
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))
|
||||
}
|
||||
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))
|
||||
}
|
||||
|
||||
var resultingAssignment = assignment
|
||||
for (target in assignment.targets) {
|
||||
resultingAssignment = processAssignmentTarget(resultingAssignment, target)
|
||||
@ -367,31 +389,15 @@ class AstChecker(private val namespace: INameScope,
|
||||
} else {
|
||||
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap)
|
||||
if(sourceDatatype==null) {
|
||||
if(assignment.value is FunctionCall) {
|
||||
// a functioncall COULD return multiple values (from an asm subroutine), treat that differently
|
||||
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 {
|
||||
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
|
||||
if(assignment.targets.size<=1) {
|
||||
if (assignment.value is FunctionCall)
|
||||
checkResult.add(ExpressionError("function call doesn't return a suitable value to use in assignment", assignment.value.position))
|
||||
}
|
||||
else
|
||||
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
|
||||
}
|
||||
else {
|
||||
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
|
||||
}
|
||||
else
|
||||
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
|
||||
}
|
||||
}
|
||||
return assignment
|
||||
|
@ -792,12 +792,17 @@ 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.
|
||||
|
||||
if(subroutine.asmReturnvaluesRegisters.isNotEmpty()) {
|
||||
TODO("call asmsub by loading registers instead")
|
||||
} else {
|
||||
prog.line(callPosition)
|
||||
for (arg in arguments.zip(subroutine.parameters)) {
|
||||
translate(arg.first)
|
||||
val opcode = opcodePopvar(arg.second.type)
|
||||
prog.instr(opcode, callLabel = subroutine.scopedname + "." + arg.second.name)
|
||||
}
|
||||
}
|
||||
prog.instr(Opcode.CALL, callLabel = subroutine.scopedname)
|
||||
}
|
||||
|
||||
@ -1080,7 +1085,6 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun translate(stmt: VariableInitializationAssignment) {
|
||||
// this is an assignment to initialize a variable's value in the scope.
|
||||
// the compiler can perhaps optimize this phase.
|
||||
@ -1089,48 +1093,16 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
}
|
||||
|
||||
private fun translate(stmt: Assignment) {
|
||||
val assignTarget= stmt.singleTarget
|
||||
prog.line(stmt.position)
|
||||
translate(stmt.value)
|
||||
|
||||
val assignTarget= stmt.singleTarget
|
||||
if(assignTarget==null) {
|
||||
// we're dealing with multiple return values
|
||||
val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace)
|
||||
if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) {
|
||||
// we're dealing with the one case where multiple assignment targets are allowed: a call to an asmsub with multiple return values
|
||||
// for now, we only support multiple return values as long as they're returned in registers as well.
|
||||
if(targetStmt.asmReturnvaluesRegisters.isEmpty())
|
||||
throw CompilerException("we only support multiple return values / assignment when the asmsub returns values in registers")
|
||||
// if the result registers are not assigned in the exact same registers, or in variables, we need some code
|
||||
if(stmt.targets.all{it.register!=null}) {
|
||||
val resultRegisters = mutableListOf<Register>()
|
||||
for(x in targetStmt.asmReturnvaluesRegisters) {
|
||||
when(x.registerOrPair) {
|
||||
RegisterOrPair.A -> resultRegisters.add(Register.A)
|
||||
RegisterOrPair.X -> resultRegisters.add(Register.X)
|
||||
RegisterOrPair.Y -> resultRegisters.add(Register.Y)
|
||||
RegisterOrPair.AX -> {
|
||||
resultRegisters.add(Register.A)
|
||||
resultRegisters.add(Register.X)
|
||||
}
|
||||
RegisterOrPair.AY -> {
|
||||
resultRegisters.add(Register.A)
|
||||
resultRegisters.add(Register.Y)
|
||||
}
|
||||
RegisterOrPair.XY -> {
|
||||
resultRegisters.add(Register.X)
|
||||
resultRegisters.add(Register.Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
TODO("$resultRegisters")
|
||||
} else {
|
||||
TODO("store results from registers ${targetStmt.asmReturnvaluesRegisters}")
|
||||
}
|
||||
} else throw CompilerException("can only use multiple assignment targets on an asmsub call")
|
||||
translateMultiReturnAssignment(stmt)
|
||||
return
|
||||
}
|
||||
|
||||
prog.line(stmt.position)
|
||||
translate(stmt.value)
|
||||
val valueDt = stmt.value.resultingDatatype(namespace, heap)
|
||||
val targetDt = assignTarget.determineDatatype(namespace, heap, stmt)
|
||||
if(valueDt!=targetDt) {
|
||||
@ -1181,11 +1153,90 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap))
|
||||
}
|
||||
|
||||
if(stmt.value is FunctionCall) {
|
||||
val sub = (stmt.value as FunctionCall).target.targetStatement(namespace)
|
||||
if(sub is Subroutine && sub.asmReturnvaluesRegisters.isNotEmpty()) {
|
||||
// the subroutine call returns its values in registers
|
||||
storeRegisterIntoTarget(sub.asmReturnvaluesRegisters.single(), assignTarget, stmt)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// pop the result value back into the assignment target
|
||||
val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!!
|
||||
popValueIntoTarget(assignTarget, datatype)
|
||||
}
|
||||
|
||||
private fun translateMultiReturnAssignment(stmt: Assignment) {
|
||||
val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace)
|
||||
if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) {
|
||||
// we're dealing with the one case where multiple assignment targets are allowed: a call to an asmsub with multiple return values
|
||||
// for now, we only support multiple return values as long as they're returned in registers as well.
|
||||
if(targetStmt.asmReturnvaluesRegisters.isEmpty())
|
||||
throw CompilerException("we only support multiple return values / assignment when the asmsub returns values in registers")
|
||||
// if the result registers are not assigned in the exact same registers, or in variables, we need some code
|
||||
if(stmt.targets.all{it.register!=null}) {
|
||||
val resultRegisters = registerSet(targetStmt.asmReturnvaluesRegisters)
|
||||
if(stmt.targets.size!=resultRegisters.size)
|
||||
throw CompilerException("asmsub number of return values doesn't match number of assignment targets ${stmt.position}")
|
||||
val targetRegs = stmt.targets.filter {it.register!=null}.map{it.register}.toSet()
|
||||
if(resultRegisters!=targetRegs)
|
||||
throw CompilerException("asmsub return registers don't match assignment target registers ${stmt.position}")
|
||||
// output is in registers already, no need to emit any asm code
|
||||
} else {
|
||||
// output is in registers but has to be stored somewhere
|
||||
for(result in targetStmt.asmReturnvaluesRegisters.zip(stmt.targets))
|
||||
storeRegisterIntoTarget(result.first, result.second, stmt)
|
||||
}
|
||||
} else throw CompilerException("can only use multiple assignment targets on an asmsub call")
|
||||
}
|
||||
|
||||
private fun storeRegisterIntoTarget(registerOrStatus: RegisterOrStatusflag, target: AssignTarget, parent: IStatement) {
|
||||
if(registerOrStatus.statusflag!=null)
|
||||
return
|
||||
when(registerOrStatus.registerOrPair){
|
||||
RegisterOrPair.A -> {
|
||||
val assignment = Assignment(listOf(target), null, RegisterExpr(Register.A, target.position), target.position)
|
||||
assignment.linkParents(parent)
|
||||
translate(assignment)
|
||||
}
|
||||
RegisterOrPair.X -> {
|
||||
val assignment = Assignment(listOf(target), null, RegisterExpr(Register.X, target.position), target.position)
|
||||
assignment.linkParents(parent)
|
||||
translate(assignment)
|
||||
}
|
||||
RegisterOrPair.Y -> {
|
||||
val assignment = Assignment(listOf(target), null, RegisterExpr(Register.Y, target.position), target.position)
|
||||
assignment.linkParents(parent)
|
||||
translate(assignment)
|
||||
}
|
||||
RegisterOrPair.AX -> {
|
||||
// deal with register pair AX: target = A + X*256
|
||||
val targetDt = target.determineDatatype(namespace, heap, parent)
|
||||
if(targetDt!=DataType.UWORD)
|
||||
throw CompilerException("invalid target datatype for registerpair $targetDt")
|
||||
prog.instr(Opcode.PUSH_REGAX_WORD)
|
||||
popValueIntoTarget(target, targetDt)
|
||||
}
|
||||
RegisterOrPair.AY -> {
|
||||
// deal with register pair AY: target = A + Y*256
|
||||
val targetDt = target.determineDatatype(namespace, heap, parent)
|
||||
if(targetDt!=DataType.UWORD)
|
||||
throw CompilerException("invalid target datatype for registerpair $targetDt")
|
||||
prog.instr(Opcode.PUSH_REGAY_WORD)
|
||||
popValueIntoTarget(target, targetDt)
|
||||
}
|
||||
RegisterOrPair.XY -> {
|
||||
// deal with register pair XY: target = X + Y*256
|
||||
val targetDt = target.determineDatatype(namespace, heap, parent)
|
||||
if(targetDt!=DataType.UWORD)
|
||||
throw CompilerException("invalid target datatype for registerpair $targetDt")
|
||||
prog.instr(Opcode.PUSH_REGXY_WORD)
|
||||
popValueIntoTarget(target, targetDt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun popValueIntoTarget(assignTarget: AssignTarget, datatype: DataType) {
|
||||
when {
|
||||
assignTarget.identifier != null -> {
|
||||
|
@ -14,6 +14,9 @@ enum class Opcode {
|
||||
PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
|
||||
PUSH_VAR_WORD, // push word variable (uword, word)
|
||||
PUSH_VAR_FLOAT, // push float variable
|
||||
PUSH_REGAX_WORD, // push registers A/X as a 16-bit word
|
||||
PUSH_REGAY_WORD, // push registers A/Y as a 16-bit word
|
||||
PUSH_REGXY_WORD, // push registers X/Y as a 16-bit word
|
||||
|
||||
// popping values off the (evaluation) stack, possibly storing them in another location
|
||||
DISCARD_BYTE, // discard top byte value
|
||||
|
@ -459,6 +459,10 @@ 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.READ_INDEXED_VAR_BYTE -> { // @todo is this correct?
|
||||
"""
|
||||
ldy ${(ESTACK_LO+1).toHex()},x
|
||||
@ -998,8 +1002,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
"""
|
||||
|
||||
private val patterns = listOf(
|
||||
// -------------- simple conversions ----------------
|
||||
|
||||
// ----------- assignment to BYTE VARIABLE ----------------
|
||||
// var = (u)bytevalue
|
||||
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE)) { segment ->
|
||||
@ -2434,10 +2436,56 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
ldy #>${hexVal(segment[2])}
|
||||
jsr prog8_lib.copy_float
|
||||
"""
|
||||
},
|
||||
|
||||
|
||||
// ---------- 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 ->
|
||||
"""
|
||||
sta ${segment[1].callLabel}
|
||||
stx ${segment[1].callLabel}+1
|
||||
"""
|
||||
},
|
||||
// var word = XY register pair
|
||||
AsmPattern(listOf(Opcode.PUSH_REGXY_WORD, Opcode.POP_VAR_WORD)) { segment ->
|
||||
"""
|
||||
stx ${segment[1].callLabel}
|
||||
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 ->
|
||||
"""
|
||||
sta ${hexVal(segment[1])}
|
||||
stx ${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])}
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
// // assignment: floatarray[idxbyte] = float
|
||||
|
||||
// // @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!!)
|
||||
// val index = intVal(segment[1]) * Mflpt5.MemorySize
|
||||
@ -2451,7 +2499,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// jsr prog8_lib.copy_float
|
||||
// """
|
||||
// },
|
||||
// // assignment: floatarray[idxbyte] = floatvar
|
||||
// // @todo assignment: floatarray[idxbyte] = floatvar
|
||||
// AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
|
||||
// val index = intVal(segment[1]) * Mflpt5.MemorySize
|
||||
// """
|
||||
@ -2464,7 +2512,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// jsr prog8_lib.copy_float
|
||||
// """
|
||||
// },
|
||||
// // assignment: floatarray[idxbyte] = memfloat
|
||||
// // @todo assignment: floatarray[idxbyte] = memfloat
|
||||
// AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
|
||||
// val index = intVal(segment[1]) * Mflpt5.MemorySize
|
||||
// """
|
||||
|
@ -762,6 +762,21 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
checkDt(value, DataType.FLOAT)
|
||||
evalstack.push(value)
|
||||
}
|
||||
Opcode.PUSH_REGAX_WORD -> {
|
||||
val a=variables["A"]!!.integerValue()
|
||||
val x=variables["X"]!!.integerValue()
|
||||
evalstack.push(Value(DataType.UWORD, x*256+a))
|
||||
}
|
||||
Opcode.PUSH_REGAY_WORD -> {
|
||||
val a=variables["A"]!!.integerValue()
|
||||
val y=variables["Y"]!!.integerValue()
|
||||
evalstack.push(Value(DataType.UWORD, y*256+a))
|
||||
}
|
||||
Opcode.PUSH_REGXY_WORD -> {
|
||||
val x=variables["X"]!!.integerValue()
|
||||
val y=variables["Y"]!!.integerValue()
|
||||
evalstack.push(Value(DataType.UWORD, y*256+x))
|
||||
}
|
||||
Opcode.POP_VAR_BYTE -> {
|
||||
val value = evalstack.pop()
|
||||
checkDt(value, DataType.UBYTE, DataType.BYTE)
|
||||
|
@ -120,18 +120,18 @@ asmsub MOVEF () -> clobbers(A,X) -> () = $bc0f ; copy fac1 to fac2
|
||||
asmsub FTOMEMXY (mflpt: uword @ XY) -> clobbers(A,Y) -> () = $bbd4 ; store fac1 to memory X/Y as 5-byte mflpt
|
||||
|
||||
; fac1-> signed word in Y/A (might throw ILLEGAL QUANTITY)
|
||||
; (use c64flt.FTOSWRDAY to get A/Y output; lo/hi switched to normal order)
|
||||
; (tip: use c64flt.FTOSWRDAY to get A/Y output; lo/hi switched to normal little endian order)
|
||||
asmsub FTOSWORDYA () -> clobbers(X) -> (ubyte @ Y, ubyte @ A) = $b1aa
|
||||
|
||||
; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15)
|
||||
; (use c64flt.GETADRAY to get A/Y output; lo/hi switched to normal order)
|
||||
; (tip: use c64flt.GETADRAY to get A/Y output; lo/hi switched to normal little endian order)
|
||||
asmsub GETADR () -> clobbers(X) -> (ubyte @ Y, ubyte @ A) = $b7f7
|
||||
|
||||
asmsub QINT () -> clobbers(A,X,Y) -> () = $bc9b ; fac1 -> 4-byte signed integer in 98-101 ($62-$65), with the MSB FIRST.
|
||||
asmsub AYINT () -> clobbers(A,X,Y) -> () = $b1bf ; fac1-> signed word in 100-101 ($64-$65) MSB FIRST. (might throw ILLEGAL QUANTITY)
|
||||
|
||||
; signed word in Y/A -> float in fac1
|
||||
; (use c64flt.GIVAYFAY to use A/Y input; lo/hi switched to normal order)
|
||||
; (tip: use c64flt.GIVAYFAY to use A/Y input; lo/hi switched to normal order)
|
||||
; there is also c64flt.GIVUAYF - unsigned word in A/Y (lo/hi) to fac1
|
||||
; there is also c64flt.FREADS32 that reads from 98-101 ($62-$65) MSB FIRST
|
||||
; there is also c64flt.FREADUS32 that reads from 98-101 ($62-$65) MSB FIRST
|
||||
@ -169,7 +169,7 @@ asmsub ABS () -> clobbers() -> () = $bc58 ; fac1 = ABS(fac1)
|
||||
asmsub SQR () -> clobbers(A,X,Y) -> () = $bf71 ; fac1 = SQRT(fac1)
|
||||
asmsub EXP () -> clobbers(A,X,Y) -> () = $bfed ; fac1 = EXP(fac1) (e ** fac1)
|
||||
asmsub NEGOP () -> clobbers(A) -> () = $bfb4 ; switch the sign of fac1
|
||||
asmsub RND () -> clobbers(A,X,Y) -> () = $e097 ; fac1 = RND() (use RNDA instead)
|
||||
asmsub RND () -> clobbers(A,X,Y) -> () = $e097 ; fac1 = RND() (tip: use RNDA instead)
|
||||
asmsub RNDA (acc: ubyte @ A) -> clobbers(A,X,Y) -> () = $e09a ; fac1 = RND(A)
|
||||
asmsub COS () -> clobbers(A,X,Y) -> () = $e264 ; fac1 = COS(fac1)
|
||||
asmsub SIN () -> clobbers(A,X,Y) -> () = $e26b ; fac1 = SIN(fac1)
|
||||
@ -229,7 +229,7 @@ asmsub CLALL () -> clobbers(A,X) -> () = $FFE7 ; (via 812 ($32C)) close al
|
||||
asmsub UDTIM () -> clobbers(A,X) -> () = $FFEA ; update the software clock
|
||||
asmsub SCREEN () -> clobbers() -> (ubyte @ X, ubyte @ Y) = $FFED ; read number of screen rows and columns
|
||||
asmsub PLOT (dir: ubyte @ Pc, col: ubyte @ Y, row: ubyte @ X) -> clobbers() -> (ubyte @ X, ubyte @ Y) = $FFF0 ; read/set position of cursor on screen
|
||||
asmsub IOBASE () -> clobbers() -> (ubyte @ X, ubyte @ Y) = $FFF3 ; read base address of I/O devices
|
||||
asmsub IOBASE () -> clobbers() -> (uword @ XY) = $FFF3 ; read base address of I/O devices
|
||||
|
||||
; ---- end of C64 kernal routines ----
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user