tweaking multiple assignment targets

This commit is contained in:
Irmen de Jong 2018-11-18 23:26:05 +01:00
parent a2a8a772ec
commit fad74a6ae0
8 changed files with 241 additions and 88 deletions

View File

@ -11,16 +11,24 @@ sub start() {
ubyte v2 ubyte v2
float f2 float f2
uword address uword address
memory uword memaddr = $c000
uword[2] wordarray
byte b1
v1=foo() ;v1=foo() ; @todo fix return type value error see sub
X, Y =c64.GETADR()
v1, v2 =c64.GETADR() A, Y =c64.GETADR() ; ok!
address =c64.MEMBOT(1, 0.w) Y, A =c64.GETADR() ; ok!
address =c64.IOBASE() address = c64flt.GETADRAY() ; ok!
A = c64.CHRIN() memaddr = c64flt.GETADRAY() ; ok!
X = c64.CHRIN() wordarray[1] = c64flt.GETADRAY() ; ok!
v1 = c64.CHRIN() 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 return
} }

View File

@ -394,7 +394,6 @@ interface INameScope {
} }
} }
private object ParentSentinel : Node { private object ParentSentinel : Node {
override val position = Position("<<sentinel>>", 0, 0, 0) override val position = Position("<<sentinel>>", 0, 0, 0)
override var parent: Node = this 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>, class AnonymousScope(override var statements: MutableList<IStatement>,
override val position: Position) : INameScope, 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()) Module(name, modulestatement().asSequence().map { it.toAst() }.toMutableList(), toPosition())
/************** Helper extension methods (private) ************/
private fun ParserRuleContext.toPosition() : Position { private fun ParserRuleContext.toPosition() : Position {
val file = Paths.get(this.start.inputStream.sourceName).fileName.toString() 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... // 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()) val scope = AnonymousScope(statements, statement_block()?.toPosition() ?: statement().toPosition())
return RepeatLoop(scope, untilCondition, 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
}

View File

@ -177,7 +177,6 @@ class AstChecker(private val namespace: INameScope,
return super.process(label) return super.process(label)
} }
/** /**
* Check subroutine definition * Check subroutine definition
*/ */
@ -300,9 +299,32 @@ class AstChecker(private val namespace: INameScope,
/** /**
* Assignment target must be register, or a variable name * 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 { 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 var resultingAssignment = assignment
for (target in assignment.targets) { for (target in assignment.targets) {
resultingAssignment = processAssignmentTarget(resultingAssignment, target) resultingAssignment = processAssignmentTarget(resultingAssignment, target)
@ -367,31 +389,15 @@ class AstChecker(private val namespace: INameScope,
} else { } else {
val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap) val sourceDatatype: DataType? = assignment.value.resultingDatatype(namespace, heap)
if(sourceDatatype==null) { if(sourceDatatype==null) {
if(assignment.value is FunctionCall) { if(assignment.targets.size<=1) {
// a functioncall COULD return multiple values (from an asm subroutine), treat that differently 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 {
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("function call doesn't return a suitable value to use in assignment", assignment.value.position)) 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
checkResult.add(ExpressionError("assignment value is invalid or has no proper datatype", assignment.value.position))
} }
else { else
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position) checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
}
} }
} }
return assignment return assignment

View File

@ -792,13 +792,18 @@ private class StatementTranslator(private val prog: IntermediateProgram,
private fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>, callPosition: Position) { private fun translateSubroutineCall(subroutine: Subroutine, arguments: List<IExpression>, callPosition: Position) {
// evaluate the arguments and assign them into the subroutine's argument variables. // evaluate the arguments and assign them into the subroutine's argument variables.
prog.line(callPosition)
for(arg in arguments.zip(subroutine.parameters)) { if(subroutine.asmReturnvaluesRegisters.isNotEmpty()) {
translate(arg.first) TODO("call asmsub by loading registers instead")
val opcode=opcodePopvar(arg.second.type) } else {
prog.instr(opcode, callLabel = subroutine.scopedname+"."+arg.second.name) 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) prog.instr(Opcode.CALL, callLabel = subroutine.scopedname)
} }
private fun translateBinaryOperator(operator: String, dt: DataType) { private fun translateBinaryOperator(operator: String, dt: DataType) {
@ -1080,7 +1085,6 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
} }
private fun translate(stmt: VariableInitializationAssignment) { private fun translate(stmt: VariableInitializationAssignment) {
// this is an assignment to initialize a variable's value in the scope. // this is an assignment to initialize a variable's value in the scope.
// the compiler can perhaps optimize this phase. // the compiler can perhaps optimize this phase.
@ -1089,48 +1093,16 @@ private class StatementTranslator(private val prog: IntermediateProgram,
} }
private fun translate(stmt: Assignment) { private fun translate(stmt: Assignment) {
val assignTarget= stmt.singleTarget prog.line(stmt.position)
translate(stmt.value)
val assignTarget= stmt.singleTarget
if(assignTarget==null) { if(assignTarget==null) {
// we're dealing with multiple return values // we're dealing with multiple return values
val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace) translateMultiReturnAssignment(stmt)
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")
return return
} }
prog.line(stmt.position)
translate(stmt.value)
val valueDt = stmt.value.resultingDatatype(namespace, heap) val valueDt = stmt.value.resultingDatatype(namespace, heap)
val targetDt = assignTarget.determineDatatype(namespace, heap, stmt) val targetDt = assignTarget.determineDatatype(namespace, heap, stmt)
if(valueDt!=targetDt) { if(valueDt!=targetDt) {
@ -1181,11 +1153,90 @@ private class StatementTranslator(private val prog: IntermediateProgram,
translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap)) 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 // pop the result value back into the assignment target
val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!! val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!!
popValueIntoTarget(assignTarget, datatype) 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) { private fun popValueIntoTarget(assignTarget: AssignTarget, datatype: DataType) {
when { when {
assignTarget.identifier != null -> { assignTarget.identifier != null -> {

View File

@ -14,6 +14,9 @@ enum class Opcode {
PUSH_VAR_BYTE, // push byte variable (ubyte, byte) PUSH_VAR_BYTE, // push byte variable (ubyte, byte)
PUSH_VAR_WORD, // push word variable (uword, word) PUSH_VAR_WORD, // push word variable (uword, word)
PUSH_VAR_FLOAT, // push float variable 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 // popping values off the (evaluation) stack, possibly storing them in another location
DISCARD_BYTE, // discard top byte value DISCARD_BYTE, // discard top byte value

View File

@ -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? Opcode.READ_INDEXED_VAR_BYTE -> { // @todo is this correct?
""" """
ldy ${(ESTACK_LO+1).toHex()},x ldy ${(ESTACK_LO+1).toHex()},x
@ -998,8 +1002,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
""" """
private val patterns = listOf( private val patterns = listOf(
// -------------- simple conversions ----------------
// ----------- assignment to BYTE VARIABLE ---------------- // ----------- assignment to BYTE VARIABLE ----------------
// var = (u)bytevalue // var = (u)bytevalue
AsmPattern(listOf(Opcode.PUSH_BYTE, Opcode.POP_VAR_BYTE)) { segment -> 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])} ldy #>${hexVal(segment[2])}
jsr prog8_lib.copy_float 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 -> // AsmPattern(listOf(Opcode.PUSH_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
// val floatConst = getFloatConst(segment[0].arg!!) // val floatConst = getFloatConst(segment[0].arg!!)
// val index = intVal(segment[1]) * Mflpt5.MemorySize // val index = intVal(segment[1]) * Mflpt5.MemorySize
@ -2451,7 +2499,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// jsr prog8_lib.copy_float // 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 -> // AsmPattern(listOf(Opcode.PUSH_VAR_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
// val index = intVal(segment[1]) * Mflpt5.MemorySize // val index = intVal(segment[1]) * Mflpt5.MemorySize
// """ // """
@ -2464,7 +2512,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// jsr prog8_lib.copy_float // 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 -> // AsmPattern(listOf(Opcode.PUSH_MEM_FLOAT, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_FLOAT)) { segment ->
// val index = intVal(segment[1]) * Mflpt5.MemorySize // val index = intVal(segment[1]) * Mflpt5.MemorySize
// """ // """

View File

@ -762,6 +762,21 @@ class StackVm(private var traceOutputFile: String?) {
checkDt(value, DataType.FLOAT) checkDt(value, DataType.FLOAT)
evalstack.push(value) 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 -> { Opcode.POP_VAR_BYTE -> {
val value = evalstack.pop() val value = evalstack.pop()
checkDt(value, DataType.UBYTE, DataType.BYTE) checkDt(value, DataType.UBYTE, DataType.BYTE)

View File

@ -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 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) ; 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 asmsub FTOSWORDYA () -> clobbers(X) -> (ubyte @ Y, ubyte @ A) = $b1aa
; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15) ; 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 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 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) 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 ; 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.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.FREADS32 that reads from 98-101 ($62-$65) MSB FIRST
; there is also c64flt.FREADUS32 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 SQR () -> clobbers(A,X,Y) -> () = $bf71 ; fac1 = SQRT(fac1)
asmsub EXP () -> clobbers(A,X,Y) -> () = $bfed ; fac1 = EXP(fac1) (e ** fac1) asmsub EXP () -> clobbers(A,X,Y) -> () = $bfed ; fac1 = EXP(fac1) (e ** fac1)
asmsub NEGOP () -> clobbers(A) -> () = $bfb4 ; switch the sign of 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 RNDA (acc: ubyte @ A) -> clobbers(A,X,Y) -> () = $e09a ; fac1 = RND(A)
asmsub COS () -> clobbers(A,X,Y) -> () = $e264 ; fac1 = COS(fac1) asmsub COS () -> clobbers(A,X,Y) -> () = $e264 ; fac1 = COS(fac1)
asmsub SIN () -> clobbers(A,X,Y) -> () = $e26b ; fac1 = SIN(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 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 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 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 ---- ; ---- end of C64 kernal routines ----