mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
change for subroutine return values via registers instead of stack
This commit is contained in:
parent
83cc19ad6f
commit
44949460ed
@ -31,7 +31,7 @@ enum class DataType {
|
||||
WORD -> targetType in setOf(WORD, FLOAT)
|
||||
FLOAT -> targetType == FLOAT
|
||||
STR -> targetType == STR || targetType == UWORD
|
||||
in ArrayDatatypes -> targetType == this
|
||||
in ArrayDatatypes -> targetType == this || targetType == UWORD
|
||||
else -> false
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,10 @@ object InferredTypes {
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = Objects.hash(isVoid, datatype)
|
||||
|
||||
infix fun isAssignableTo(targetDt: InferredType): Boolean {
|
||||
return isKnown && targetDt.isKnown && (datatype!! isAssignableTo targetDt.datatype!!)
|
||||
}
|
||||
}
|
||||
|
||||
private val unknownInstance = InferredType.unknown()
|
||||
|
@ -380,7 +380,7 @@ internal class AstChecker(private val program: Program,
|
||||
|
||||
val targetDt = assignment.target.inferType(program, assignment)
|
||||
val valueDt = assignment.value.inferType(program)
|
||||
if(valueDt.isKnown && valueDt != targetDt) {
|
||||
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) {
|
||||
if(targetDt.typeOrElse(DataType.STRUCT) in IterableDatatypes)
|
||||
errors.err("cannot assign value to string or array", assignment.value.position)
|
||||
else
|
||||
@ -1350,9 +1350,7 @@ internal class AstChecker(private val program: Program,
|
||||
else if(sourceDatatype== DataType.FLOAT && targetDatatype in IntegerDatatypes)
|
||||
errors.err("cannot assign float to ${targetDatatype.name.toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position)
|
||||
else {
|
||||
if(targetDatatype==DataType.UWORD && sourceDatatype in PassByReferenceDatatypes)
|
||||
errors.err("cannot assign ${sourceDatatype.name.toLowerCase()} to ${targetDatatype.name.toLowerCase()}, perhaps forgot '&' ?", position)
|
||||
else
|
||||
if(targetDatatype!=DataType.UWORD && sourceDatatype !in PassByReferenceDatatypes)
|
||||
errors.err("cannot assign ${sourceDatatype.name.toLowerCase()} to ${targetDatatype.name.toLowerCase()}", position)
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,9 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
val valuetype = valueItype.typeOrElse(DataType.STRUCT)
|
||||
if (valuetype != targettype) {
|
||||
if (valuetype isAssignableTo targettype) {
|
||||
if(valuetype in IterableDatatypes && targettype==DataType.UWORD)
|
||||
// special case, don't typecast STR/arrays to UWORD, we support those assignments "directly"
|
||||
return noModifications
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
assignment.value,
|
||||
TypecastExpression(assignment.value, targettype, true, assignment.value.position),
|
||||
|
@ -697,10 +697,9 @@ class Subroutine(override val name: String,
|
||||
private fun determineReturnRegisters(returntypes: List<DataType>): List<RegisterOrStatusflag> {
|
||||
// for non-asm subroutines, determine the return registers based on the type of the return value
|
||||
return when(returntypes.singleOrNull()) {
|
||||
in NumericDatatypes -> listOf(RegisterOrStatusflag(null, null, true)) // TODO for now, all return values via the stack
|
||||
// in ByteDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, false))
|
||||
// in WordDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
||||
// DataType.FLOAT -> listOf(RegisterOrStatusflag(null, null, true)) // TODO floats eventually via pointer in AY as well
|
||||
in ByteDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, false))
|
||||
in WordDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
||||
DataType.FLOAT -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
||||
null -> emptyList()
|
||||
else -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ fun compileProgram(filepath: Path,
|
||||
optimizeAst(programAst, errors)
|
||||
postprocessAst(programAst, errors, compilationOptions)
|
||||
|
||||
// printAst(programAst)
|
||||
printAst(programAst) // TODO
|
||||
|
||||
if(writeAssembly)
|
||||
programName = writeAssembly(programAst, errors, outputDir, optimize, compilationOptions)
|
||||
@ -223,7 +223,7 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
|
||||
programAst.processAstBeforeAsmGeneration(errors)
|
||||
errors.handle()
|
||||
|
||||
// printAst(programAst)
|
||||
printAst(programAst) // TODO
|
||||
|
||||
CompilationTarget.instance.machine.initializeZeropage(compilerOptions)
|
||||
val assembly = CompilationTarget.instance.asmGenerator(
|
||||
|
@ -743,8 +743,8 @@ internal class AsmGen(private val program: Program,
|
||||
internal fun translateExpression(indexer: ArrayIndex) =
|
||||
expressionsAsmGen.translateExpression(indexer)
|
||||
|
||||
internal fun translateFunctioncallExpression(functionCall: FunctionCall, signature: FSignature) =
|
||||
builtinFunctionsAsmGen.translateFunctioncallExpression(functionCall, signature)
|
||||
internal fun translateBuiltinFunctionCallExpression(functionCall: FunctionCall, signature: FSignature, resultToStack: Boolean) =
|
||||
builtinFunctionsAsmGen.translateFunctioncallExpression(functionCall, signature, resultToStack)
|
||||
|
||||
internal fun translateFunctionCall(functionCall: FunctionCall, preserveStatusRegisterAfterCall: Boolean) =
|
||||
functioncallAsmGen.translateFunctionCall(functionCall, preserveStatusRegisterAfterCall)
|
||||
@ -1164,15 +1164,20 @@ $counterVar .byte 0""")
|
||||
else -> throw AssemblyError("normal subroutines can't return value in status register directly")
|
||||
}
|
||||
|
||||
if (returnType in NumericDatatypes) {
|
||||
val src = AsmAssignSource.fromAstSource(returnvalue, program, this)
|
||||
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
|
||||
}
|
||||
else {
|
||||
// all else take its address and assign that also to AY register pair
|
||||
val addrofValue = AddressOf(returnvalue as IdentifierReference, returnvalue.position)
|
||||
val src = AsmAssignSource.fromAstSource(addrofValue, program, this)
|
||||
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
|
||||
when (returnType) {
|
||||
in IntegerDatatypes -> {
|
||||
val src = AsmAssignSource.fromAstSource(returnvalue, program, this)
|
||||
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
TODO("must return the float's address in AY")
|
||||
}
|
||||
else -> {
|
||||
// all else take its address and assign that also to AY register pair
|
||||
val addrofValue = AddressOf(returnvalue as IdentifierReference, returnvalue.position)
|
||||
val src = AsmAssignSource.fromAstSource(addrofValue, program, this)
|
||||
assignmentAsmGen.translateNormalAssignment(AsmAssignment(src, returnValueTarget, false, ret.position))
|
||||
}
|
||||
}
|
||||
}
|
||||
out(" rts")
|
||||
|
@ -17,37 +17,36 @@ import prog8.functions.FSignature
|
||||
|
||||
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
||||
|
||||
internal fun translateFunctioncallExpression(fcall: FunctionCall, func: FSignature) {
|
||||
translateFunctioncall(fcall, func, false)
|
||||
internal fun translateFunctioncallExpression(fcall: FunctionCall, func: FSignature, resultToStack: Boolean) {
|
||||
translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack)
|
||||
}
|
||||
|
||||
internal fun translateFunctioncallStatement(fcall: FunctionCallStatement, func: FSignature) {
|
||||
translateFunctioncall(fcall, func, true)
|
||||
translateFunctioncall(fcall, func, discardResult = true, resultToStack = false)
|
||||
}
|
||||
|
||||
private fun translateFunctioncall(fcall: IFunctionCall, func: FSignature, discardResult: Boolean) {
|
||||
private fun translateFunctioncall(fcall: IFunctionCall, func: FSignature, discardResult: Boolean, resultToStack: Boolean) {
|
||||
val functionName = fcall.target.nameInSource.last()
|
||||
if (discardResult) {
|
||||
if (func.pure)
|
||||
return // can just ignore the whole function call altogether
|
||||
else if (func.returntype != null)
|
||||
throw AssemblyError("discarding result of non-pure function $fcall")
|
||||
}
|
||||
if (discardResult && func.pure)
|
||||
return // can just ignore the whole function call altogether
|
||||
|
||||
if(discardResult && resultToStack)
|
||||
throw AssemblyError("cannot both discard the result AND put it onto stack")
|
||||
|
||||
when (functionName) {
|
||||
"msb" -> funcMsb(fcall)
|
||||
"lsb" -> funcLsb(fcall)
|
||||
"mkword" -> funcMkword(fcall, func)
|
||||
"abs" -> funcAbs(fcall, func)
|
||||
"msb" -> funcMsb(fcall, resultToStack)
|
||||
"lsb" -> funcLsb(fcall, resultToStack)
|
||||
"mkword" -> funcMkword(fcall, func) // TODO resultToStack
|
||||
"abs" -> funcAbs(fcall, func) // TODO resultToStack
|
||||
"swap" -> funcSwap(fcall)
|
||||
"strlen" -> funcStrlen(fcall)
|
||||
"min", "max", "sum" -> funcMinMaxSum(fcall, functionName)
|
||||
"any", "all" -> funcAnyAll(fcall, functionName)
|
||||
"sgn" -> funcSgn(fcall, func)
|
||||
"strlen" -> funcStrlen(fcall) // TODO resultToStack
|
||||
"min", "max", "sum" -> funcMinMaxSum(fcall, functionName) // TODO resultToStack
|
||||
"any", "all" -> funcAnyAll(fcall, functionName) // TODO resultToStack
|
||||
"sgn" -> funcSgn(fcall, func) // TODO resultToStack
|
||||
"sin", "cos", "tan", "atan",
|
||||
"ln", "log2", "sqrt", "rad",
|
||||
"deg", "round", "floor", "ceil",
|
||||
"rdnf" -> funcVariousFloatFuncs(fcall, func, functionName)
|
||||
"rdnf" -> funcVariousFloatFuncs(fcall, func, functionName) // TODO resultToStack
|
||||
"rol" -> funcRol(fcall)
|
||||
"rol2" -> funcRol2(fcall)
|
||||
"ror" -> funcRor(fcall)
|
||||
@ -69,7 +68,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
"set_irqd" -> asmgen.out(" sei")
|
||||
else -> {
|
||||
translateFunctionArguments(fcall.args, func)
|
||||
asmgen.out(" jsr prog8_lib.func_$functionName")
|
||||
asmgen.out(" jsr prog8_lib.func_$functionName") // TODO resultToStack
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -777,7 +776,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
asmgen.out(" inx | lda P8ESTACK_LO,x | sta P8ESTACK_HI+1,x")
|
||||
}
|
||||
|
||||
private fun funcMsb(fcall: IFunctionCall) {
|
||||
private fun funcMsb(fcall: IFunctionCall, resultToStack: Boolean) {
|
||||
val arg = fcall.args.single()
|
||||
if (arg.inferType(program).typeOrElse(DataType.STRUCT) !in WordDatatypes)
|
||||
throw AssemblyError("msb required word argument")
|
||||
@ -785,14 +784,17 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
throw AssemblyError("msb(const) should have been const-folded away")
|
||||
if (arg is IdentifierReference) {
|
||||
val sourceName = asmgen.asmVariableName(arg)
|
||||
asmgen.out(" lda $sourceName+1 | sta P8ESTACK_LO,x | dex")
|
||||
asmgen.out(" lda $sourceName+1")
|
||||
if(resultToStack)
|
||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||
} else {
|
||||
asmgen.translateExpression(arg)
|
||||
asmgen.out(" lda P8ESTACK_HI+1,x | sta P8ESTACK_LO+1,x")
|
||||
TODO("msb from non-identifier expression $arg")
|
||||
// asmgen.translateExpression(arg)
|
||||
// asmgen.out(" lda P8ESTACK_HI+1,x | sta P8ESTACK_LO+1,x")
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcLsb(fcall: IFunctionCall) {
|
||||
private fun funcLsb(fcall: IFunctionCall, resultToStack: Boolean) {
|
||||
val arg = fcall.args.single()
|
||||
if (arg.inferType(program).typeOrElse(DataType.STRUCT) !in WordDatatypes)
|
||||
throw AssemblyError("lsb required word argument")
|
||||
@ -800,9 +802,12 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
throw AssemblyError("lsb(const) should have been const-folded away")
|
||||
if (arg is IdentifierReference) {
|
||||
val sourceName = asmgen.asmVariableName(arg)
|
||||
asmgen.out(" lda $sourceName | sta P8ESTACK_LO,x | dex")
|
||||
asmgen.out(" lda $sourceName")
|
||||
if(resultToStack)
|
||||
asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||
} else {
|
||||
asmgen.translateExpression(arg)
|
||||
TODO("lsb from non-identifier expression $arg")
|
||||
// asmgen.translateExpression(arg)
|
||||
// just ignore any high-byte
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.ArrayIndex
|
||||
import prog8.ast.statements.BuiltinFunctionStatementPlaceholder
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.CpuType
|
||||
@ -1041,12 +1043,14 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
|
||||
private fun translateFunctionCallResultOntoStack(expression: FunctionCall) {
|
||||
val functionName = expression.target.nameInSource.last()
|
||||
val builtinFunc = BuiltinFunctions[functionName]
|
||||
if (builtinFunc != null) {
|
||||
asmgen.translateFunctioncallExpression(expression, builtinFunc)
|
||||
// only for use in nested expression evaluation
|
||||
|
||||
val sub = expression.target.targetStatement(program.namespace)
|
||||
if(sub is BuiltinFunctionStatementPlaceholder) {
|
||||
val builtinFunc = BuiltinFunctions.getValue(sub.name)
|
||||
asmgen.translateBuiltinFunctionCallExpression(expression, builtinFunc, true)
|
||||
} else {
|
||||
val sub = expression.target.targetSubroutine(program.namespace)!!
|
||||
sub as Subroutine
|
||||
val preserveStatusRegisterAfterCall = sub.asmReturnvaluesRegisters.any {it.statusflag!=null}
|
||||
asmgen.translateFunctionCall(expression, preserveStatusRegisterAfterCall)
|
||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
||||
|
@ -3,10 +3,7 @@ package prog8.compiler.target.c64.codegen.assignment
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.AssignTarget
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.DirectMemoryWrite
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
|
||||
@ -121,33 +118,26 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
||||
val dt = value.inferType(program).typeOrElse(DataType.STRUCT)
|
||||
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value)
|
||||
}
|
||||
else -> {
|
||||
if(value is FunctionCall) {
|
||||
// functioncall.
|
||||
val asmSub = value.target.targetStatement(program.namespace)
|
||||
if(asmSub is Subroutine && asmSub.isAsmSubroutine) {
|
||||
when (asmSub.asmReturnvaluesRegisters.count { rr -> rr.registerOrPair!=null }) {
|
||||
0 -> throw AssemblyError("can't translate zero return values in assignment")
|
||||
1 -> {
|
||||
// assignment generation itself must make sure the status register is correct after the subroutine call, if status register is involved!
|
||||
val reg = asmSub.asmReturnvaluesRegisters.single { rr->rr.registerOrPair!=null }.registerOrPair!!
|
||||
val dt = when(reg) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
RegisterOrPair.Y -> DataType.UBYTE
|
||||
RegisterOrPair.AX,
|
||||
RegisterOrPair.AY,
|
||||
RegisterOrPair.XY -> DataType.UWORD
|
||||
}
|
||||
return AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt, expression = value)
|
||||
}
|
||||
else -> throw AssemblyError("can't translate multiple return values in assignment")
|
||||
}
|
||||
is FunctionCall -> {
|
||||
when (val sub = value.target.targetStatement(program.namespace)) {
|
||||
is Subroutine -> {
|
||||
val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null }?.first
|
||||
?: throw AssemblyError("can't translate zero return values in assignment")
|
||||
|
||||
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value)
|
||||
}
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
val returnType = value.inferType(program).typeOrElse(DataType.STRUCT)
|
||||
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value)
|
||||
}
|
||||
else -> {
|
||||
throw AssemblyError("weird call")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else -> {
|
||||
val dt = value.inferType(program).typeOrElse(DataType.STRUCT)
|
||||
return AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt, expression = value)
|
||||
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt, expression = value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import prog8.compiler.target.CpuType
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.c64.codegen.ExpressionsAsmGen
|
||||
import prog8.compiler.toHex
|
||||
import prog8.functions.BuiltinFunctions
|
||||
|
||||
|
||||
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen, private val exprAsmgen: ExpressionsAsmGen) {
|
||||
@ -124,28 +125,36 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
|
||||
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, assign)
|
||||
is FunctionCall -> {
|
||||
if(value.target.targetSubroutine(program.namespace)?.isAsmSubroutine==true) {
|
||||
// handle asmsub functioncalls specifically, without shoving stuff on the estack
|
||||
val sub = value.target.targetSubroutine(program.namespace)!!
|
||||
val preserveStatusRegisterAfterCall = sub.asmReturnvaluesRegisters.any { it.statusflag != null }
|
||||
asmgen.translateFunctionCall(value, preserveStatusRegisterAfterCall)
|
||||
when((sub.asmReturnvaluesRegisters.single { it.registerOrPair!=null }).registerOrPair) {
|
||||
RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A)
|
||||
RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X)
|
||||
RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y)
|
||||
RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX)
|
||||
RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
||||
RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY)
|
||||
else -> throw AssemblyError("should be just one register byte result value")
|
||||
when (val sub = value.target.targetStatement(program.namespace)) {
|
||||
is Subroutine -> {
|
||||
val preserveStatusRegisterAfterCall = sub.asmReturnvaluesRegisters.any { it.statusflag != null }
|
||||
asmgen.translateFunctionCall(value, preserveStatusRegisterAfterCall)
|
||||
when ((sub.asmReturnvaluesRegisters.single { it.registerOrPair != null }).registerOrPair) {
|
||||
RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A)
|
||||
RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X)
|
||||
RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y)
|
||||
RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX)
|
||||
RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
||||
RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY)
|
||||
else -> throw AssemblyError("should be just one register byte result value")
|
||||
}
|
||||
if (preserveStatusRegisterAfterCall)
|
||||
asmgen.out(" plp\t; restore status flags from call")
|
||||
}
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
val signature = BuiltinFunctions.getValue(sub.name)
|
||||
asmgen.translateBuiltinFunctionCallExpression(value, signature, false)
|
||||
when(signature.returntype) {
|
||||
in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A)
|
||||
in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
||||
DataType.FLOAT -> TODO("assign float result from ${sub.name}")
|
||||
null -> {}
|
||||
else -> throw AssemblyError("weird result type ${signature.returntype}")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
throw AssemblyError("weird func call")
|
||||
}
|
||||
if(preserveStatusRegisterAfterCall)
|
||||
asmgen.out(" plp\t; restore status flags from call")
|
||||
} else {
|
||||
// regular subroutine, return values are (for now) always done via the stack... TODO optimize this
|
||||
asmgen.translateExpression(value)
|
||||
if(assign.target.datatype in WordDatatypes && assign.source.datatype in ByteDatatypes)
|
||||
asmgen.signExtendStackLsb(assign.source.datatype)
|
||||
assignStackValue(assign.target)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@ -763,7 +772,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
}
|
||||
|
||||
private fun assignRegisterpairWord(target: AsmAssignTarget, regs: RegisterOrPair) {
|
||||
require(target.datatype in WordDatatypes)
|
||||
require(target.datatype in NumericDatatypes)
|
||||
if(target.datatype==DataType.FLOAT) {
|
||||
if (regs == RegisterOrPair.AY) {
|
||||
asmgen.out(" brk ; TODO FLOAT RETURN VALUE") // TODO
|
||||
return
|
||||
}
|
||||
else throw AssemblyError("float reaturn value should be via AY return pointer")
|
||||
}
|
||||
when(target.kind) {
|
||||
TargetStorageKind.VARIABLE -> {
|
||||
when(regs) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- get rid of all the .typeOrElse(STRUCT) 'shortcuts' and replace them with proper error handling
|
||||
- make memset(w) and memcopy able to work with >256 bytes
|
||||
- make memset and memcopy use the ROM routines on the CX16
|
||||
- calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines)
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
; Note: this program is compatible with C64 and CX16.
|
||||
|
||||
; TODO the LINES are all wrong...
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
|
@ -6,13 +6,38 @@
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
ubyte char = c64.CHRIN()
|
||||
ubyte char2 = chrin()
|
||||
uword ssss = getstr()
|
||||
float fl = getfloat()
|
||||
ubyte char
|
||||
uword ssss
|
||||
float fl
|
||||
|
||||
;char = 1+(lsb(ssss) * 2)
|
||||
;fl = 2.0*(abs(fl) + 1.0)
|
||||
|
||||
char = lsb(ssss)
|
||||
char++
|
||||
char2++
|
||||
char = msb(ssss)
|
||||
char++
|
||||
char = c64.CHRIN()
|
||||
|
||||
txt.print_ub(char)
|
||||
txt.chrout('\n')
|
||||
|
||||
char = chrin()
|
||||
|
||||
txt.print_ub(char)
|
||||
txt.chrout('\n')
|
||||
|
||||
void getstr()
|
||||
ssss = getstr()
|
||||
|
||||
txt.print_uwhex(ssss, true)
|
||||
txt.chrout('\n')
|
||||
|
||||
; fl = getfloat()
|
||||
;
|
||||
; floats.print_f(fl)
|
||||
; txt.chrout('\n')
|
||||
|
||||
testX()
|
||||
;char=strlen(ssss)
|
||||
}
|
||||
@ -22,12 +47,13 @@ main {
|
||||
}
|
||||
|
||||
sub getstr() -> str {
|
||||
@($d020)++
|
||||
return "foo"
|
||||
}
|
||||
|
||||
sub getfloat() -> float {
|
||||
return 4.56789
|
||||
}
|
||||
; sub getfloat() -> float {
|
||||
; return 4.56789
|
||||
; }
|
||||
|
||||
sub mcp(uword from, uword dest, ubyte length) {
|
||||
txt.print_uw(from)
|
||||
|
Loading…
Reference in New Issue
Block a user