mirror of
https://github.com/irmen/prog8.git
synced 2025-08-14 22:27:48 +00:00
removed @stack in subroutine args and returnvalues, can only use variables or registers now
This commit is contained in:
@@ -143,7 +143,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
|||||||
for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) {
|
for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) {
|
||||||
val reg =
|
val reg =
|
||||||
when {
|
when {
|
||||||
param.second.stack -> "stack"
|
|
||||||
param.second.registerOrPair!=null -> param.second.registerOrPair.toString()
|
param.second.registerOrPair!=null -> param.second.registerOrPair.toString()
|
||||||
param.second.statusflag!=null -> param.second.statusflag.toString()
|
param.second.statusflag!=null -> param.second.statusflag.toString()
|
||||||
else -> "?????"
|
else -> "?????"
|
||||||
|
@@ -254,8 +254,8 @@ private fun prog8Parser.Asmsub_declContext.toAst(): AsmsubDecl {
|
|||||||
val clobbers = asmsub_clobbers()?.clobber()?.toAst() ?: emptySet()
|
val clobbers = asmsub_clobbers()?.clobber()?.toAst() ?: emptySet()
|
||||||
val normalParameters = params.map { SubroutineParameter(it.name, it.type, it.position) }
|
val normalParameters = params.map { SubroutineParameter(it.name, it.type, it.position) }
|
||||||
val normalReturntypes = returns.map { it.type }
|
val normalReturntypes = returns.map { it.type }
|
||||||
val paramRegisters = params.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag, false) }
|
val paramRegisters = params.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag) }
|
||||||
val returnRegisters = returns.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag, it.stack) }
|
val returnRegisters = returns.map { RegisterOrStatusflag(it.registerOrPair, it.statusflag) }
|
||||||
return AsmsubDecl(name, normalParameters, normalReturntypes, paramRegisters, returnRegisters, clobbers)
|
return AsmsubDecl(name, normalParameters, normalReturntypes, paramRegisters, returnRegisters, clobbers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +268,6 @@ private class AsmSubroutineParameter(name: String,
|
|||||||
private class AsmSubroutineReturn(val type: DataType,
|
private class AsmSubroutineReturn(val type: DataType,
|
||||||
val registerOrPair: RegisterOrPair?,
|
val registerOrPair: RegisterOrPair?,
|
||||||
val statusflag: Statusflag?,
|
val statusflag: Statusflag?,
|
||||||
val stack: Boolean,
|
|
||||||
val position: Position)
|
val position: Position)
|
||||||
|
|
||||||
private fun prog8Parser.Asmsub_returnsContext.toAst(): List<AsmSubroutineReturn>
|
private fun prog8Parser.Asmsub_returnsContext.toAst(): List<AsmSubroutineReturn>
|
||||||
@@ -287,7 +286,7 @@ private fun prog8Parser.Asmsub_returnsContext.toAst(): List<AsmSubroutineReturn>
|
|||||||
it.datatype().toAst(),
|
it.datatype().toAst(),
|
||||||
registerorpair,
|
registerorpair,
|
||||||
statusregister,
|
statusregister,
|
||||||
!it.stack?.text.isNullOrEmpty(), toPosition())
|
toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prog8Parser.Asmsub_paramsContext.toAst(): List<AsmSubroutineParameter>
|
private fun prog8Parser.Asmsub_paramsContext.toAst(): List<AsmSubroutineParameter>
|
||||||
|
@@ -44,7 +44,7 @@ class BuiltinFunctionStatementPlaceholder(val name: String, override val positio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?, val stack: Boolean) // TODO get rid of stack?
|
data class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?)
|
||||||
|
|
||||||
class Block(override val name: String,
|
class Block(override val name: String,
|
||||||
val address: Int?,
|
val address: Int?,
|
||||||
@@ -697,11 +697,11 @@ class Subroutine(override val name: String,
|
|||||||
private fun determineReturnRegisters(returntypes: List<DataType>): List<RegisterOrStatusflag> {
|
private fun determineReturnRegisters(returntypes: List<DataType>): List<RegisterOrStatusflag> {
|
||||||
// for non-asm subroutines, determine the return registers based on the type of the return value
|
// for non-asm subroutines, determine the return registers based on the type of the return value
|
||||||
return when(returntypes.singleOrNull()) {
|
return when(returntypes.singleOrNull()) {
|
||||||
in ByteDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null, false))
|
in ByteDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.A, null))
|
||||||
in WordDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
in WordDatatypes -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null))
|
||||||
DataType.FLOAT -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
DataType.FLOAT -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null))
|
||||||
null -> emptyList()
|
null -> emptyList()
|
||||||
else -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null, false))
|
else -> listOf(RegisterOrStatusflag(RegisterOrPair.AY, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1155,7 +1155,6 @@ $counterVar .byte 0""")
|
|||||||
val returnValueTarget =
|
val returnValueTarget =
|
||||||
when {
|
when {
|
||||||
returnReg.registerOrPair!=null -> AsmAssignTarget.fromRegisters(returnReg.registerOrPair, sub, program, this)
|
returnReg.registerOrPair!=null -> AsmAssignTarget.fromRegisters(returnReg.registerOrPair, sub, program, this)
|
||||||
returnReg.stack -> AsmAssignTarget(TargetStorageKind.STACK, program, this, returnType, sub)
|
|
||||||
else -> throw AssemblyError("normal subroutines can't return value in status register directly")
|
else -> throw AssemblyError("normal subroutines can't return value in status register directly")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1055,41 +1055,41 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
asmgen.translateFunctionCall(expression, preserveStatusRegisterAfterCall)
|
asmgen.translateFunctionCall(expression, preserveStatusRegisterAfterCall)
|
||||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
||||||
for ((_, reg) in returns) {
|
for ((_, reg) in returns) {
|
||||||
if (!reg.stack) {
|
// result value in cpu or status registers, put it on the stack
|
||||||
// result value in cpu or status registers, put it on the stack
|
if (reg.registerOrPair != null) {
|
||||||
if (reg.registerOrPair != null) {
|
when (reg.registerOrPair) {
|
||||||
when (reg.registerOrPair) {
|
RegisterOrPair.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||||
RegisterOrPair.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
|
RegisterOrPair.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
||||||
RegisterOrPair.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
||||||
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
RegisterOrPair.X -> {
|
||||||
RegisterOrPair.X -> {
|
// return value in X register has been discarded, just push a zero
|
||||||
// return value in X register has been discarded, just push a zero
|
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
asmgen.out(" stz P8ESTACK_LO,x")
|
||||||
asmgen.out(" stz P8ESTACK_LO,x")
|
else
|
||||||
else
|
asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
|
||||||
asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
|
asmgen.out(" dex")
|
||||||
asmgen.out(" dex")
|
}
|
||||||
}
|
RegisterOrPair.AX -> {
|
||||||
RegisterOrPair.AX -> {
|
// return value in X register has been discarded, just push a zero in this place
|
||||||
// return value in X register has been discarded, just push a zero in this place
|
asmgen.out(" sta P8ESTACK_LO,x")
|
||||||
asmgen.out(" sta P8ESTACK_LO,x")
|
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
asmgen.out(" stz P8ESTACK_HI,x")
|
||||||
asmgen.out(" stz P8ESTACK_HI,x")
|
else
|
||||||
else
|
asmgen.out(" lda #0 | sta P8ESTACK_HI,x")
|
||||||
asmgen.out(" lda #0 | sta P8ESTACK_HI,x")
|
asmgen.out(" dex")
|
||||||
asmgen.out(" dex")
|
}
|
||||||
}
|
RegisterOrPair.XY -> {
|
||||||
RegisterOrPair.XY -> {
|
// return value in X register has been discarded, just push a zero in this place
|
||||||
// return value in X register has been discarded, just push a zero in this place
|
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
||||||
if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02)
|
asmgen.out(" stz P8ESTACK_LO,x")
|
||||||
asmgen.out(" stz P8ESTACK_LO,x")
|
else
|
||||||
else
|
asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
|
||||||
asmgen.out(" lda #0 | sta P8ESTACK_LO,x")
|
asmgen.out(" tya | sta P8ESTACK_HI,x | dex")
|
||||||
asmgen.out(" tya | sta P8ESTACK_HI,x | dex")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// return value from a statusregister is not put on the stack, it should be acted on via a conditional branch such as if_cc
|
}
|
||||||
|
else if(reg.statusflag!=null) {
|
||||||
|
TODO("statusflag result onto stack")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,14 +18,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
val sub = stmt.target.targetSubroutine(program.namespace)!!
|
val sub = stmt.target.targetSubroutine(program.namespace)!!
|
||||||
val preserveStatusRegisterAfterCall = sub.asmReturnvaluesRegisters.any {it.statusflag!=null}
|
val preserveStatusRegisterAfterCall = sub.asmReturnvaluesRegisters.any {it.statusflag!=null}
|
||||||
translateFunctionCall(stmt, preserveStatusRegisterAfterCall)
|
translateFunctionCall(stmt, preserveStatusRegisterAfterCall)
|
||||||
// discard resultvalues that might be on the stack:
|
// functioncalls no longer return results on the stack, so simply ignore the results in the registers
|
||||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
|
||||||
for ((t, reg) in returns) {
|
|
||||||
if (reg.stack) {
|
|
||||||
if (t in IntegerDatatypes || t in PassByReferenceDatatypes) asmgen.out(" inx")
|
|
||||||
else if (t == DataType.FLOAT) asmgen.out(" inx | inx | inx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(preserveStatusRegisterAfterCall)
|
if(preserveStatusRegisterAfterCall)
|
||||||
asmgen.out(" plp\t; restore status flags from call")
|
asmgen.out(" plp\t; restore status flags from call")
|
||||||
}
|
}
|
||||||
@@ -104,7 +97,6 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
|
|
||||||
for(argi in stmt.args.zip(sub.asmParameterRegisters).withIndex()) {
|
for(argi in stmt.args.zip(sub.asmParameterRegisters).withIndex()) {
|
||||||
when {
|
when {
|
||||||
argi.value.second.stack -> TODO("asmsub @stack parameter")
|
|
||||||
argi.value.second.statusflag == Statusflag.Pc -> {
|
argi.value.second.statusflag == Statusflag.Pc -> {
|
||||||
require(argForCarry == null)
|
require(argForCarry == null)
|
||||||
argForCarry = argi
|
argForCarry = argi
|
||||||
@@ -191,20 +183,12 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
val paramRegister = sub.asmParameterRegisters[parameter.index]
|
val paramRegister = sub.asmParameterRegisters[parameter.index]
|
||||||
val statusflag = paramRegister.statusflag
|
val statusflag = paramRegister.statusflag
|
||||||
val register = paramRegister.registerOrPair
|
val register = paramRegister.registerOrPair
|
||||||
val stack = paramRegister.stack
|
|
||||||
val requiredDt = parameter.value.type
|
val requiredDt = parameter.value.type
|
||||||
if(requiredDt!=valueDt) {
|
if(requiredDt!=valueDt) {
|
||||||
if(valueDt largerThan requiredDt)
|
if(valueDt largerThan requiredDt)
|
||||||
throw AssemblyError("can only convert byte values to word param types")
|
throw AssemblyError("can only convert byte values to word param types")
|
||||||
}
|
}
|
||||||
when {
|
when {
|
||||||
stack -> {
|
|
||||||
// push arg onto the stack
|
|
||||||
// note: argument order is reversed (first argument will be deepest on the stack)
|
|
||||||
asmgen.translateExpression(value)
|
|
||||||
if(requiredDt!=valueDt)
|
|
||||||
asmgen.signExtendStackLsb(valueDt)
|
|
||||||
}
|
|
||||||
statusflag!=null -> {
|
statusflag!=null -> {
|
||||||
if(requiredDt!=valueDt)
|
if(requiredDt!=valueDt)
|
||||||
throw AssemblyError("for statusflag, byte value is required")
|
throw AssemblyError("for statusflag, byte value is required")
|
||||||
|
@@ -6,7 +6,6 @@ TODO
|
|||||||
- make memset(w) and memcopy able to work with >256 bytes
|
- make memset(w) and memcopy able to work with >256 bytes
|
||||||
- make memset and memcopy use the ROM routines on the CX16
|
- 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)
|
- calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines)
|
||||||
- get rid of @stack in asmsub (syntax, ast) altogether (because all subroutines are no longer using this calling convention anymore)
|
|
||||||
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
|
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
|
||||||
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
|
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)
|
||||||
- see if we can group some errors together for instance the (now single) errors about unidentified symbols
|
- see if we can group some errors together for instance the (now single) errors about unidentified symbols
|
||||||
|
@@ -271,7 +271,7 @@ asmsub_decl : identifier '(' asmsub_params? ')' asmsub_clobbers? asmsub_returns?
|
|||||||
|
|
||||||
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
|
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
|
||||||
|
|
||||||
asmsub_param : vardecl '@' identifier ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed. TODO implement stack='stack'
|
asmsub_param : vardecl '@' identifier ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed.
|
||||||
|
|
||||||
asmsub_clobbers : 'clobbers' '(' clobber? ')' ;
|
asmsub_clobbers : 'clobbers' '(' clobber? ')' ;
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ clobber : identifier (',' identifier)* ; // A,X,Y allowed
|
|||||||
|
|
||||||
asmsub_returns : '->' asmsub_return (',' EOL? asmsub_return)* ;
|
asmsub_returns : '->' asmsub_return (',' EOL? asmsub_return)* ;
|
||||||
|
|
||||||
asmsub_return : datatype '@' (identifier | stack='stack') ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed
|
asmsub_return : datatype '@' identifier ; // A,X,Y,AX,AY,XY,Pc,Pz,Pn,Pv allowed
|
||||||
|
|
||||||
|
|
||||||
if_stmt : 'if' expression EOL? (statement | statement_block) EOL? else_part? ; // statement is constrained later
|
if_stmt : 'if' expression EOL? (statement | statement_block) EOL? else_part? ; // statement is constrained later
|
||||||
|
Reference in New Issue
Block a user