mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
various code generation fixes, slight optimization of 16-bit word additions
This commit is contained in:
parent
72d58d5856
commit
aea1292f92
@ -1,20 +1,63 @@
|
||||
%import c64utils
|
||||
%option enable_floats
|
||||
|
||||
~ main {
|
||||
|
||||
ubyte[3] balloonsprite = [ %00000000,%01111111,%00000000 ]
|
||||
|
||||
sub start() {
|
||||
ubyte i=0
|
||||
A= @($d020)
|
||||
A= @($d020+i)
|
||||
@($d020) = 0
|
||||
@($d020+i) = 0
|
||||
@($d020+i) = 1
|
||||
@($d020+i) = 2
|
||||
@($d020) = @($d020+i) + 1
|
||||
@($d020+i) = @($d020+i) + 1
|
||||
c64scr.print_ub(X)
|
||||
uword uw1 = 0
|
||||
uword uw2 = $77ff
|
||||
uword uw3 = $55aa
|
||||
word w1 = 0
|
||||
word w2 = $22ff
|
||||
word w3 = $55aa
|
||||
memory uword muw1 = $2000
|
||||
memory uword muw2 = $3000
|
||||
memory uword muw3 = $4000
|
||||
memory word mw1 = $4100
|
||||
memory word mw2 = $4200
|
||||
memory word mw3 = $4300
|
||||
|
||||
uword[3] uwarr = $55aa
|
||||
word[3] warr = $55aa
|
||||
memory uword[3] muwarr = $4400
|
||||
memory word[3] mwarr = $4500
|
||||
|
||||
muw3 = $55aa
|
||||
uwarr[0] = $55aa
|
||||
uwarr[1] = $55aa
|
||||
uwarr[2] = $55aa
|
||||
muwarr[0] = $55aa
|
||||
muwarr[1] = $55aa
|
||||
muwarr[2] = $55aa
|
||||
mwarr[0] = $55aa
|
||||
mwarr[1] = $55aa
|
||||
mwarr[2] = $55aa
|
||||
|
||||
uw1 = uw2 + $55aa ;52649
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
uw1 = uw2 + uw3 ;52649
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
uw1 = uw2 + muw3 ;52649
|
||||
c64scr.print_uw(uw1)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
; uw1 = uw2 + uwarr[2] ;52649
|
||||
; c64scr.print_uw(uw1)
|
||||
; c64.CHROUT('\n')
|
||||
|
||||
|
||||
; w1 = w2 + $55aa ; 30889
|
||||
; c64scr.print_w(w1)
|
||||
; c64.CHROUT('\n')
|
||||
; w1 = w2 + w3 ; 30889
|
||||
; c64scr.print_w(w1)
|
||||
; c64.CHROUT('\n')
|
||||
;
|
||||
; uwarr[2] = uwarr[1] + $55aa
|
||||
; uwarr[2] = uwarr[1] + uw3
|
||||
; uwarr[2] = uwarr[1] + uwarr[1]
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ class Block(override val name: String,
|
||||
return "Block(name=$name, address=$address, ${statements.size} statements)"
|
||||
}
|
||||
|
||||
val options = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
|
||||
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
|
||||
}
|
||||
|
||||
|
||||
|
@ -617,17 +617,17 @@ class AstChecker(private val namespace: INameScope,
|
||||
err("invalid import directive, cannot import itself")
|
||||
}
|
||||
"%breakpoint" -> {
|
||||
if(directive.parent !is Block) err("this directive may only occur in a block")
|
||||
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
|
||||
if(directive.args.isNotEmpty())
|
||||
err("invalid breakpoint directive, expected no arguments")
|
||||
}
|
||||
"%asminclude" -> {
|
||||
if(directive.parent !is Block) err("this directive may only occur in a block")
|
||||
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
|
||||
if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].name==null)
|
||||
err("invalid asminclude directive, expected arguments: \"filename\", scopelabel")
|
||||
}
|
||||
"%asmbinary" -> {
|
||||
if(directive.parent !is Block) err("this directive may only occur in a block")
|
||||
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
|
||||
val errormsg = "invalid asmbinary directive, expected arguments: \"filename\" [, offset [, length ] ]"
|
||||
if(directive.args.isEmpty()) err(errormsg)
|
||||
if(directive.args.isNotEmpty() && directive.args[0].str==null) err(errormsg)
|
||||
|
@ -31,6 +31,7 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
||||
val varDecls = module.statements.filterIsInstance<VarDecl>()
|
||||
module.statements.removeAll(varDecls)
|
||||
module.statements.addAll(0, varDecls)
|
||||
|
||||
val directives = module.statements.filter {it is Directive && it.directive in directivesToMove}
|
||||
module.statements.removeAll(directives)
|
||||
module.statements.addAll(0, directives)
|
||||
|
@ -151,7 +151,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
val continueStmtLabelStack : Stack<String> = Stack()
|
||||
|
||||
override fun process(block: Block): IStatement {
|
||||
prog.newBlock(block.scopedname, block.name, block.address, block.options)
|
||||
prog.newBlock(block.scopedname, block.name, block.address, block.options())
|
||||
processVariables(block) // @todo optimize initializations with same value: load the value only once (sort on initalization value, datatype ?)
|
||||
prog.label("block."+block.scopedname)
|
||||
prog.line(block.position)
|
||||
@ -182,18 +182,6 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
||||
override fun process(directive: Directive): IStatement {
|
||||
when(directive.directive) {
|
||||
"%asminclude" -> throw CompilerException("can't use %asminclude in stackvm")
|
||||
"%asmbinary" -> throw CompilerException("can't use %asmbinary in stackvm")
|
||||
"%breakpoint" -> {
|
||||
prog.line(directive.position)
|
||||
prog.instr(Opcode.BREAKPOINT)
|
||||
}
|
||||
}
|
||||
return super.process(directive)
|
||||
}
|
||||
|
||||
private fun translate(statements: List<IStatement>) {
|
||||
for (stmt: IStatement in statements) {
|
||||
generatedLabelSequenceNumber++
|
||||
@ -214,7 +202,17 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
is AnonymousScope -> translate(stmt)
|
||||
is ReturnFromIrq -> translate(stmt)
|
||||
is Return -> translate(stmt)
|
||||
is Directive, is VarDecl, is Subroutine -> {} // skip this, already processed these.
|
||||
is Directive -> {
|
||||
when(stmt.directive) {
|
||||
"%asminclude" -> throw CompilerException("can't use %asminclude in stackvm")
|
||||
"%asmbinary" -> throw CompilerException("can't use %asmbinary in stackvm")
|
||||
"%breakpoint" -> {
|
||||
prog.line(stmt.position)
|
||||
prog.instr(Opcode.BREAKPOINT)
|
||||
}
|
||||
}
|
||||
}
|
||||
is VarDecl, is Subroutine -> {} // skip this, already processed these.
|
||||
is InlineAssembly -> translate(stmt)
|
||||
else -> TODO("translate statement $stmt to stackvm")
|
||||
}
|
||||
|
@ -502,7 +502,7 @@ _prog8_irq_handler_excl
|
||||
}
|
||||
}
|
||||
Opcode.PUSH_VAR_WORD -> {
|
||||
" lda ${ins.callLabel} | ldy ${ins.callLabel}+1 | sta ${ESTACK_LO.toHex()},x | pha | tya | sta ${ESTACK_HI.toHex()},x | pla | dex"
|
||||
" lda ${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda ${ins.callLabel}+1 | sta ${ESTACK_HI.toHex()},x | dex"
|
||||
}
|
||||
Opcode.PUSH_VAR_FLOAT -> " lda #<${ins.callLabel} | ldy #>${ins.callLabel}| jsr prog8_lib.push_float"
|
||||
Opcode.PUSH_MEM_B, Opcode.PUSH_MEM_UB -> {
|
||||
@ -782,7 +782,7 @@ _prog8_irq_handler_excl
|
||||
Opcode.CAST_B_TO_UW, Opcode.CAST_B_TO_W -> " lda ${(ESTACK_LO+1)},x | ${signExtendA("${(ESTACK_HI+1).toHex()},x")}" // sign extend the lsb
|
||||
Opcode.MSB -> " lda ${(ESTACK_HI+1).toHex()},x | sta ${(ESTACK_LO+1).toHex()},x"
|
||||
|
||||
Opcode.ADD_UB, Opcode.ADD_B -> {
|
||||
Opcode.ADD_UB, Opcode.ADD_B -> { // TODO inline better?
|
||||
"""
|
||||
lda ${(ESTACK_LO + 2).toHex()},x
|
||||
clc
|
||||
@ -791,7 +791,7 @@ _prog8_irq_handler_excl
|
||||
sta ${(ESTACK_LO + 1).toHex()},x
|
||||
"""
|
||||
}
|
||||
Opcode.SUB_UB, Opcode.SUB_B -> {
|
||||
Opcode.SUB_UB, Opcode.SUB_B -> { // TODO inline better?
|
||||
"""
|
||||
lda ${(ESTACK_LO + 2).toHex()},x
|
||||
sec
|
||||
@ -2921,6 +2921,46 @@ _prog8_irq_handler_excl
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_B, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE),
|
||||
listOf(Opcode.PUSH_MEM_UB, Opcode.PUSH_BYTE, Opcode.BITXOR_BYTE)) { segment ->
|
||||
" lda ${hexVal(segment[0])} | eor #${hexVal(segment[1])} | sta ${ESTACK_LO.toHex()},x | dex "
|
||||
},
|
||||
|
||||
|
||||
// 16 bit addition avoiding excessive stack usage
|
||||
// @todo optimize this even more with longer asmpatterns (avoid stack use altogether on most common operations)
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.ADD_UW),
|
||||
listOf(Opcode.PUSH_VAR_WORD, Opcode.ADD_W)) { segment ->
|
||||
"""
|
||||
clc
|
||||
lda ${segment[0].callLabel}
|
||||
adc ${(ESTACK_LO+1).toHex()},x
|
||||
sta ${(ESTACK_LO+1).toHex()},x
|
||||
lda ${segment[0].callLabel}+1
|
||||
adc ${(ESTACK_HI+1).toHex()},x
|
||||
sta ${(ESTACK_HI+1).toHex()},x
|
||||
"""
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.ADD_UW),
|
||||
listOf(Opcode.PUSH_MEM_W, Opcode.ADD_W)) { segment ->
|
||||
"""
|
||||
clc
|
||||
lda ${hexVal(segment[0])}
|
||||
adc ${(ESTACK_LO + 1).toHex()},x
|
||||
sta ${(ESTACK_LO + 1).toHex()},x
|
||||
lda ${hexValPlusOne(segment[0])}
|
||||
adc ${(ESTACK_HI + 1).toHex()},x
|
||||
sta ${(ESTACK_HI + 1).toHex()},x
|
||||
"""
|
||||
},
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.ADD_UW),
|
||||
listOf(Opcode.PUSH_WORD, Opcode.ADD_W)) { segment ->
|
||||
"""
|
||||
clc
|
||||
lda #<${hexVal(segment[0])}
|
||||
adc ${(ESTACK_LO+1).toHex()},x
|
||||
sta ${(ESTACK_LO+1).toHex()},x
|
||||
lda #>${hexVal(segment[0])}
|
||||
adc ${(ESTACK_HI+1).toHex()},x
|
||||
sta ${(ESTACK_HI+1).toHex()},x
|
||||
"""
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -243,8 +243,9 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
val result = variables[name]
|
||||
if(result!=null)
|
||||
return result
|
||||
if(name in memoryPointers)
|
||||
if(name in memoryPointers) {
|
||||
throw VmExecutionException("variable is memory-mapped: $name = ${memoryPointers[name]}")
|
||||
}
|
||||
throw VmExecutionException("unknown variable: $name")
|
||||
}
|
||||
|
||||
@ -1205,51 +1206,81 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
Opcode.READ_INDEXED_VAR_BYTE -> {
|
||||
// put the byte value of variable[index] onto the stack
|
||||
val index = evalstack.pop().integerValue()
|
||||
val variable = getVar(ins.callLabel!!)
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the ubyte value from that memory location
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed byte element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UB-> evalstack.push(Value(DataType.UBYTE, array.array!![index]))
|
||||
DataType.ARRAY_B -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0]))
|
||||
if(ins.callLabel in memoryPointers) {
|
||||
val variable = memoryPointers[ins.callLabel]!!
|
||||
val address = variable.first + index
|
||||
when(variable.second) {
|
||||
DataType.ARRAY_UB -> evalstack.push(Value(DataType.UBYTE, mem.getUByte(address)))
|
||||
DataType.ARRAY_B -> evalstack.push(Value(DataType.BYTE, mem.getSByte(address)))
|
||||
else -> throw VmExecutionException("not a proper array/string variable with byte elements")
|
||||
}
|
||||
} else {
|
||||
val variable = getVar(ins.callLabel!!)
|
||||
if (variable.type == DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the ubyte value from that memory location
|
||||
evalstack.push(Value(DataType.UBYTE, mem.getUByte(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed byte element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when (array.type) {
|
||||
DataType.ARRAY_UB -> evalstack.push(Value(DataType.UBYTE, array.array!![index]))
|
||||
DataType.ARRAY_B -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> evalstack.push(Value(DataType.UBYTE, Petscii.encodePetscii(array.str!![index].toString(), true)[0]))
|
||||
else -> throw VmExecutionException("not a proper array/string variable with byte elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Opcode.READ_INDEXED_VAR_WORD -> {
|
||||
// put the word value of variable[index] onto the stack
|
||||
val index = evalstack.pop().integerValue()
|
||||
val variable = getVar(ins.callLabel!!)
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the word value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed word element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type){
|
||||
DataType.ARRAY_UW -> evalstack.push(Value(DataType.UWORD, array.array!![index]))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||
if(ins.callLabel in memoryPointers) {
|
||||
val variable = memoryPointers[ins.callLabel]!!
|
||||
val address = variable.first + index*2
|
||||
when(variable.second) {
|
||||
DataType.ARRAY_UW -> evalstack.push(Value(DataType.UWORD, mem.getUWord(address)))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, mem.getSWord(address)))
|
||||
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
|
||||
}
|
||||
} else {
|
||||
// normal variable
|
||||
val variable = getVar(ins.callLabel!!)
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the word value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getUWord(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed word element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
when(array.type){
|
||||
DataType.ARRAY_UW -> evalstack.push(Value(DataType.UWORD, array.array!![index]))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||
else -> throw VmExecutionException("not a proper arrayspec var with word elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Opcode.READ_INDEXED_VAR_FLOAT -> {
|
||||
// put the f;pat value of variable[index] onto the stack
|
||||
// put the float value of variable[index] onto the stack
|
||||
val index = evalstack.pop().integerValue()
|
||||
val variable = getVar(ins.callLabel!!)
|
||||
if(variable.type==DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the float value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getFloat(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed float element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
if(array.type!=DataType.ARRAY_F)
|
||||
if(ins.callLabel in memoryPointers) {
|
||||
val variable = memoryPointers[ins.callLabel]!!
|
||||
val address = variable.first + index*5
|
||||
if(variable.second==DataType.ARRAY_F)
|
||||
evalstack.push(Value(DataType.FLOAT, mem.getFloat(address)))
|
||||
else
|
||||
throw VmExecutionException("not a proper arrayspec var with float elements")
|
||||
evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index]))
|
||||
} else {
|
||||
val variable = getVar(ins.callLabel!!)
|
||||
if (variable.type == DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and get the float value from that memory location
|
||||
evalstack.push(Value(DataType.UWORD, mem.getFloat(variable.integerValue())))
|
||||
} else {
|
||||
// get indexed float element from the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
if (array.type != DataType.ARRAY_F)
|
||||
throw VmExecutionException("not a proper arrayspec var with float elements")
|
||||
evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index]))
|
||||
}
|
||||
}
|
||||
}
|
||||
Opcode.WRITE_INDEXED_VAR_BYTE -> {
|
||||
@ -1310,21 +1341,21 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
if(value.type==DataType.UWORD) {
|
||||
if(memloc.second!=DataType.ARRAY_UW)
|
||||
throw VmExecutionException("invalid memory pointer type $memloc")
|
||||
mem.setUWord(memloc.first, value.integerValue())
|
||||
mem.setUWord(memloc.first+index*2, value.integerValue())
|
||||
}
|
||||
else {
|
||||
if(memloc.second!=DataType.ARRAY_W)
|
||||
throw VmExecutionException("invalid memory pointer type $memloc")
|
||||
mem.setSWord(memloc.first, value.integerValue())
|
||||
mem.setSWord(memloc.first+index*2, value.integerValue())
|
||||
}
|
||||
} else {
|
||||
val variable = getVar(varname)
|
||||
if (variable.type == DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the word value to that memory location
|
||||
if(value.type==DataType.UWORD)
|
||||
mem.setUWord(variable.integerValue(), value.integerValue())
|
||||
mem.setUWord(variable.integerValue()+index*2, value.integerValue())
|
||||
else
|
||||
mem.setSWord(variable.integerValue(), value.integerValue())
|
||||
mem.setSWord(variable.integerValue()+index*2, value.integerValue())
|
||||
} else {
|
||||
// set indexed word element in the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
@ -1347,12 +1378,12 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
// variable is the name of a pointer, write the float value to that memory location
|
||||
if(memloc.second!=DataType.ARRAY_F)
|
||||
throw VmExecutionException("invalid memory pointer type $memloc")
|
||||
mem.setFloat(memloc.first, value.numericValue().toDouble())
|
||||
mem.setFloat(memloc.first+index*5, value.numericValue().toDouble())
|
||||
} else {
|
||||
val variable = getVar(varname)
|
||||
if (variable.type == DataType.UWORD) {
|
||||
// assume the variable is a pointer (address) and write the float value to that memory location
|
||||
mem.setFloat(variable.integerValue(), value.numericValue().toDouble())
|
||||
mem.setFloat(variable.integerValue()+index*5, value.numericValue().toDouble())
|
||||
} else {
|
||||
// set indexed float element in the arrayspec
|
||||
val array = heap.get(variable.heapId)
|
||||
|
Loading…
Reference in New Issue
Block a user