allow passing byte/word for register/registerpair arguments, fix stackvm string parameter handling

This commit is contained in:
Irmen de Jong 2018-12-15 00:07:25 +01:00
parent 8597ea2ec7
commit b9958412c7
8 changed files with 56 additions and 249 deletions

View File

@ -39,7 +39,7 @@
ask_guess: ask_guess:
c64.STROUT("\nYou have ") c64.STROUT("\nYou have ")
c64scr.print_byte_decimal(attempts_left) c64scr.print_ubyte_decimal(attempts_left)
c64.STROUT(" guess") c64.STROUT(" guess")
if(attempts_left>1) if(attempts_left>1)
c64.STROUT("es") c64.STROUT("es")
@ -66,7 +66,7 @@ ask_guess:
; game over. ; game over.
c64.STROUT("\nToo bad! It was: ") c64.STROUT("\nToo bad! It was: ")
c64scr.print_byte_decimal(secretnumber) c64scr.print_ubyte_decimal(secretnumber)
c64.CHROUT('\n') c64.CHROUT('\n')
goodbye: goodbye:

View File

@ -26,7 +26,7 @@
; c64.CHROUT('\n') ; c64.CHROUT('\n')
c64scr.print_string("\nYou have ") c64scr.print_string("\nYou have ")
c64scr.print_byte_decimal(attempts_left) c64scr.print_ubyte_decimal(attempts_left)
c64scr.print_string(" guess") c64scr.print_string(" guess")
if attempts_left>1 if attempts_left>1
c64scr.print_string("es") c64scr.print_string("es")
@ -66,7 +66,7 @@
c64scr.print_string("\n\nYou guessed it, impressive!\n") c64scr.print_string("\n\nYou guessed it, impressive!\n")
else { else {
c64scr.print_string("\nToo bad! My number was: ") c64scr.print_string("\nToo bad! My number was: ")
c64scr.print_byte_decimal(secretnumber) c64scr.print_ubyte_decimal(secretnumber)
c64scr.print_string(".\n") c64scr.print_string(".\n")
} }
c64scr.print_string("Thanks for playing, ") c64scr.print_string("Thanks for playing, ")

View File

@ -3,7 +3,7 @@
~ main { ~ main {
sub start() { sub start() {
str name = "????????????????????????????????????????" str name = "????????????????????????????????????????"
str guessstr = "??????????" str input = "??????????"
ubyte secretnumber = rnd() % 100 ubyte secretnumber = rnd() % 100
vm_write_str("Let's play a number guessing game!\n") vm_write_str("Let's play a number guessing game!\n")
@ -20,15 +20,15 @@
if attempts_left>1 if attempts_left>1
vm_write_str("es") vm_write_str("es")
vm_write_str(" left. What is your next guess? ") vm_write_str(" left. What is your next guess? ")
vm_input_str(guess) vm_input_str(input)
ubyte guessednumber = str2ubyte(guess) ubyte guess = str2ubyte(input)
if guessednumber==secretnumber { if guess==secretnumber {
vm_write_str("\nYou guessed it, impressive!\n") vm_write_str("\nYou guessed it, impressive!\n")
vm_write_str("Thanks for playing.\n") vm_write_str("Thanks for playing.\n")
return return
} else { } else {
vm_write_str("That is too ") vm_write_str("That is too ")
if guessednumber<secretnumber if guess<secretnumber
vm_write_str("low!\n") vm_write_str("low!\n")
else else
vm_write_str("high!\n") vm_write_str("high!\n")

View File

@ -7,219 +7,24 @@
ubyte ub1 ubyte ub1
ubyte ub2 ubyte ub2
byte b1 byte b1 = -99
byte b2 byte b2
uword uw1 uword uw1
uword uw2 uword uw2
word w1 word w1 = -9999
word w2 word w2
float f1 float f1
float f2 float f2
float f3 float f3
; byte and ubyte output via print are all OK! c64scr.print_byte_decimal(-99)
c64scr.print_byte_decimal(0)
c64.CHROUT(' ')
c64scr.print_byte_decimal(123)
c64.CHROUT(' ')
c64scr.print_byte_decimal(b2ub(-99)) ; @todo allow signed values for register
c64.CHROUT('\n') c64.CHROUT('\n')
c64scr.print_ubyte_decimal(0) c64scr.print_byte_decimal(b1)
c64.CHROUT(' ')
c64scr.print_ubyte_decimal0(0)
c64.CHROUT(' ')
c64scr.print_ubyte_decimal(55)
c64.CHROUT(' ')
c64scr.print_ubyte_decimal0(55)
c64.CHROUT(' ')
c64scr.print_ubyte_decimal(254)
c64.CHROUT(' ')
c64scr.print_ubyte_decimal0(254)
c64.CHROUT('\n') c64.CHROUT('\n')
c64scr.print_ubyte_hex(0, 0) c64scr.print_word_decimal(-9999)
c64.CHROUT(' ')
c64scr.print_ubyte_hex(1, 0)
c64.CHROUT(' ')
c64scr.print_ubyte_hex(0, $99)
c64.CHROUT(' ')
c64scr.print_ubyte_hex(1, $99)
c64.CHROUT(' ')
c64scr.print_ubyte_hex(0, $ea)
c64.CHROUT(' ')
c64scr.print_ubyte_hex(1, $ea)
c64.CHROUT('\n') c64.CHROUT('\n')
c64scr.print_word_decimal(w1)
; print_uword_decimal are all OK!
c64scr.print_uword_decimal(0)
c64.CHROUT(' ')
c64scr.print_uword_decimal0(0)
c64.CHROUT(' ')
c64scr.print_uword_decimal(987)
c64.CHROUT(' ')
c64scr.print_uword_decimal0(987)
c64.CHROUT(' ')
c64scr.print_uword_decimal(55666)
c64.CHROUT(' ')
c64scr.print_uword_decimal0(55666)
c64.CHROUT('\n') c64.CHROUT('\n')
c64scr.print_uword_hex(0, 0)
c64.CHROUT(' ')
c64scr.print_uword_hex(1, 0)
c64.CHROUT(' ')
c64scr.print_uword_hex(0, $99)
c64.CHROUT(' ')
c64scr.print_uword_hex(1, $99)
c64.CHROUT(' ')
c64scr.print_uword_hex(0, $1200)
c64.CHROUT(' ')
c64scr.print_uword_hex(1, $1200)
c64.CHROUT(' ')
c64scr.print_uword_hex(0, $fe98)
c64.CHROUT(' ')
c64scr.print_uword_hex(1, $fe98)
c64.CHROUT('\n')
; print_word_decimal works OK!
c64scr.print_word_decimal(0)
c64.CHROUT(' ')
c64scr.print_word_decimal(12345)
c64.CHROUT(' ')
c64scr.print_word_decimal(32555)
c64.CHROUT(' ')
c64scr.print_word_decimal(uwrd(-1)) ; @todo allow signed values for registerpair
c64.CHROUT(' ')
c64scr.print_word_decimal(uwrd(-9999)) ; @todo allow signed values for registerpair
c64.CHROUT(' ')
c64scr.print_word_decimal(uwrd(-$5fff)) ; @todo allow signed values for registerpair
c64.CHROUT(' ')
c64scr.print_word_decimal(uwrd(-$6000)) ; @todo allow signed values for registerpair
c64.CHROUT(' ')
c64scr.print_word_decimal(uwrd(-$6001)) ; @todo allow signed values for registerpair
c64.CHROUT('\n')
b1 = -6
b2 = 30
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('+')
c64scr.print_byte_decimal(b2ub(b2))
c64.CHROUT('=')
b1 += b2
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('\n')
b1 = 60
b2 = -3
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('+')
c64scr.print_byte_decimal(b2ub(b2))
c64.CHROUT('=')
b1 += b2
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('\n')
ub1 = 90
ub2 = 50
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('+')
c64scr.print_ubyte_decimal(ub2)
c64.CHROUT('=')
ub1 += ub2
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('\n')
ub1 = 50
ub2 = 90
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('+')
c64scr.print_ubyte_decimal(ub2)
c64.CHROUT('=')
ub1 += ub2
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('\n')
b1 = -6
b2 = 30
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('-')
c64scr.print_byte_decimal(b2ub(b2))
c64.CHROUT('=')
b1 -= b2
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('\n')
b1 = 60
b2 = -3
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('-')
c64scr.print_byte_decimal(b2ub(b2))
c64.CHROUT('=')
b1 -= b2
c64scr.print_byte_decimal(b2ub(b1))
c64.CHROUT('\n')
ub1 = 90
ub2 = 50
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('-')
c64scr.print_ubyte_decimal(ub2)
c64.CHROUT('=')
ub1 -= ub2
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('\n')
ub1 = 50
ub2 = 90
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('-')
c64scr.print_ubyte_decimal(ub2)
c64.CHROUT('=')
ub1 -= ub2
c64scr.print_ubyte_decimal(ub1)
c64.CHROUT('\n')
w1 = -600
w2 = 30000
c64scr.print_uword_hex(1, uwrd(w1))
c64.CHROUT('+')
c64scr.print_uword_hex(1, uwrd(w2))
c64.CHROUT('=')
w1 += w2
c64scr.print_uword_hex(1, uwrd(w1))
c64.CHROUT('\n')
w1 = 600
w2 = -30000
c64scr.print_uword_hex(1, uwrd(w1))
c64.CHROUT('+')
c64scr.print_uword_hex(1, uwrd(w2))
c64.CHROUT('=')
w1 += w2
c64scr.print_uword_hex(1, uwrd(w1))
c64.CHROUT('\n')
uw1 = 600
uw2 = 40000
c64scr.print_uword_decimal(uw1)
c64.CHROUT('+')
c64scr.print_uword_decimal(uw2)
c64.CHROUT('=')
uw1 += uw2
c64scr.print_uword_decimal(uw1)
c64.CHROUT('\n')
uw1 = 40000
uw2 = 600
c64scr.print_uword_decimal(uw1)
c64.CHROUT('+')
c64scr.print_uword_decimal(uw2)
c64.CHROUT('=')
uw1 += uw2
c64scr.print_uword_decimal(uw1)
c64.CHROUT('\n')
} }
} }

View File

@ -234,26 +234,32 @@ class AstChecker(private val namespace: INameScope,
if(subroutine.asmReturnvaluesRegisters.size != subroutine.returntypes.size) if(subroutine.asmReturnvaluesRegisters.size != subroutine.returntypes.size)
err("number of return registers is not the same as number of return values") err("number of return registers is not the same as number of return values")
for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) { for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) {
if(param.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) if(param.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) {
if(param.first.type!=DataType.UBYTE) if (param.first.type != DataType.UBYTE && param.first.type != DataType.BYTE)
err("parameter '${param.first.name}' should be ubyte") err("parameter '${param.first.name}' should be (u)byte")
else if(param.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) }
if(param.first.type!=DataType.UWORD) else if(param.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
err("parameter '${param.first.name}' should be uword") if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD && param.first.type !in StringDatatypes && param.first.type !in ArrayDatatypes)
else if(param.second.statusflag!=null) err("parameter '${param.first.name}' should be (u)word/address")
if(param.first.type!=DataType.UBYTE) }
else if(param.second.statusflag!=null) {
if (param.first.type != DataType.UBYTE)
err("parameter '${param.first.name}' should be ubyte") err("parameter '${param.first.name}' should be ubyte")
}
} }
for(ret in subroutine.returntypes.withIndex().zip(subroutine.asmReturnvaluesRegisters)) { for(ret in subroutine.returntypes.withIndex().zip(subroutine.asmReturnvaluesRegisters)) {
if(ret.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) if(ret.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) {
if(ret.first.value!=DataType.UBYTE) if (ret.first.value != DataType.UBYTE && ret.first.value != DataType.BYTE)
err("return value #${ret.first.index+1} should be ubyte") err("return value #${ret.first.index + 1} should be (u)byte")
else if(ret.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) }
if(ret.first.value!=DataType.UWORD) else if(ret.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) {
err("return value #${ret.first.index+1} should be uword") if (ret.first.value != DataType.UWORD && ret.first.value != DataType.WORD && ret.first.value !in StringDatatypes && ret.first.value !in ArrayDatatypes)
else if(ret.second.statusflag!=null) err("return value #${ret.first.index + 1} should be (u)word/address")
if(ret.first.value!=DataType.UBYTE) }
err("return value #${ret.first.index+1} should be ubyte") else if(ret.second.statusflag!=null) {
if (ret.first.value != DataType.UBYTE)
err("return value #${ret.first.index + 1} should be ubyte")
}
} }
val regCounts = mutableMapOf<Register, Int>().withDefault { 0 } val regCounts = mutableMapOf<Register, Int>().withDefault { 0 }

View File

@ -847,7 +847,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
translate(assignA) translate(assignA)
translate(assignY) translate(assignY)
} }
DataType.UWORD -> { DataType.UWORD, DataType.WORD -> {
translate(arg.first) translate(arg.first)
prog.instr(Opcode.POP_REGAY_WORD) prog.instr(Opcode.POP_REGAY_WORD)
} }
@ -1212,7 +1212,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
// convert value to target datatype if possible // convert value to target datatype if possible
when(targetDt) { when(targetDt) {
DataType.UBYTE, DataType.BYTE -> DataType.UBYTE, DataType.BYTE ->
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") if(valueDt!=DataType.BYTE && valueDt!=DataType.UBYTE)
throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
DataType.WORD -> { DataType.WORD -> {
when (valueDt) { when (valueDt) {
DataType.UBYTE -> prog.instr(Opcode.UB2UWORD) DataType.UBYTE -> prog.instr(Opcode.UB2UWORD)

View File

@ -1417,20 +1417,15 @@ class StackVm(private var traceOutputFile: String?) {
print(Petscii.decodePetscii(listOf(evalstack.pop().integerValue().toShort()), true)) print(Petscii.decodePetscii(listOf(evalstack.pop().integerValue().toShort()), true))
} }
Syscall.VM_WRITE_STR -> { Syscall.VM_WRITE_STR -> {
val value = evalstack.pop() val heapId = evalstack.pop().integerValue()
when(value.type){ print(heap.get(heapId).str?.substringBefore('\u0000'))
DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT -> print(value.numericValue())
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> print(heap.get(value.heapId).str)
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> print(heap.get(value.heapId).array!!.toList())
DataType.ARRAY_F -> print(heap.get(value.heapId).doubleArray!!.toList())
}
} }
Syscall.VM_INPUT_STR -> { Syscall.VM_INPUT_STR -> {
val variable = evalstack.pop() val heapId = evalstack.pop().integerValue()
val value = heap.get(variable.heapId) val value = heap.get(heapId)
val maxlen = value.str!!.length val maxlen = value.str!!.length
val input = readLine() ?: "" val input = readLine() ?: ""
heap.update(variable.heapId, input.padEnd(maxlen, '\u0000').substring(0, maxlen)) heap.update(heapId, input.padEnd(maxlen, '\u0000').substring(0, maxlen))
} }
Syscall.VM_GFX_PIXEL -> { Syscall.VM_GFX_PIXEL -> {
// plot pixel at (x, y, color) from stack // plot pixel at (x, y, color) from stack
@ -1575,28 +1570,28 @@ class StackVm(private var traceOutputFile: String?) {
evalstack.push(Value(DataType.BYTE, y.toShort())) evalstack.push(Value(DataType.BYTE, y.toShort()))
} }
Syscall.FUNC_STR2UBYTE -> { Syscall.FUNC_STR2UBYTE -> {
val strvar = evalstack.pop() val heapId = evalstack.pop().integerValue()
val str = heap.get(strvar.heapId) val str = heap.get(heapId)
val y = str.str!!.trim().trimEnd('\u0000') val y = str.str!!.trim().trimEnd('\u0000')
val number = (y.toInt() and 255).toShort() val number = (y.toInt() and 255).toShort()
evalstack.push(Value(DataType.UBYTE, number)) evalstack.push(Value(DataType.UBYTE, number))
} }
Syscall.FUNC_STR2WORD -> { Syscall.FUNC_STR2WORD -> {
val strvar = evalstack.pop() val heapId = evalstack.pop().integerValue()
val str = heap.get(strvar.heapId) val str = heap.get(heapId)
val y = str.str!!.trim().trimEnd('\u0000') val y = str.str!!.trim().trimEnd('\u0000')
evalstack.push(Value(DataType.WORD, y.toInt())) evalstack.push(Value(DataType.WORD, y.toInt()))
} }
Syscall.FUNC_STR2UWORD -> { Syscall.FUNC_STR2UWORD -> {
val strvar = evalstack.pop() val heapId = evalstack.pop().integerValue()
val str = heap.get(strvar.heapId) val str = heap.get(heapId)
val y = str.str!!.trim().trimEnd('\u0000') val y = str.str!!.trim().trimEnd('\u0000')
val number = y.toInt() and 65535 val number = y.toInt() and 65535
evalstack.push(Value(DataType.UWORD, number)) evalstack.push(Value(DataType.UWORD, number))
} }
Syscall.FUNC_STR2FLOAT -> { Syscall.FUNC_STR2FLOAT -> {
val strvar = evalstack.pop() val heapId = evalstack.pop().integerValue()
val str = heap.get(strvar.heapId) val str = heap.get(heapId)
val y = str.str!!.trim().trimEnd('\u0000') val y = str.str!!.trim().trimEnd('\u0000')
evalstack.push(Value(DataType.FLOAT, y.toDouble())) evalstack.push(Value(DataType.FLOAT, y.toDouble()))
} }

View File

@ -649,7 +649,7 @@ _print_tens txa
}} }}
} }
asmsub print_byte_decimal (value: ubyte @ A) -> clobbers(A,X,Y) -> () { asmsub print_byte_decimal (value: byte @ A) -> clobbers(A,X,Y) -> () {
; ---- print the byte in A in decimal form, without left padding 0s ; ---- print the byte in A in decimal form, without left padding 0s
%asm {{ %asm {{
pha pha
@ -745,7 +745,7 @@ _pr_decimal
}} }}
} }
asmsub print_word_decimal (value: uword @ AY) -> clobbers(A,X,Y) -> () { asmsub print_word_decimal (value: word @ AY) -> clobbers(A,X,Y) -> () {
; ---- print the (signed) word in A/Y in decimal form, without left padding 0s ; ---- print the (signed) word in A/Y in decimal form, without left padding 0s
%asm {{ %asm {{
cpy #0 cpy #0