more asm, constants now also outputted in asm source

This commit is contained in:
Irmen de Jong 2018-12-04 22:30:35 +01:00
parent 08224d5367
commit 0c64d7ffe5
9 changed files with 200 additions and 121 deletions

View File

@ -1,7 +1,6 @@
%output prg
%import c64lib
%import c64utils
%import mathlib
~ main {
sub start() {
@ -28,7 +27,7 @@
c64.MUL10() ; .. and now *100
c64.FADDH() ; add 0.5..
c64.FADDH() ; and again, so +1 total
A, Y = c64flt.GETADRAY() ; @todo fix return value type check "cannot assign word to byte, use msb() or lsb()"
A, Y = c64flt.GETADRAY()
secretnumber = A
c64scr.print_string("I am thinking of a number from 1 to 100!You'll have to guess it!\n")
@ -44,7 +43,7 @@ ask_guess:
c64.CHROUT('\n')
freadstr_arg = guess
c64.FREADSTR(A)
A, Y = c64flt.GETADRAY() ; @todo fix return value type check "cannot assign word to byte, use msb() or lsb()"
A, Y = c64flt.GETADRAY()
if(A==secretnumber) {
c64scr.print_string("\nThat's my number, impressive!\n")
goto goodbye

View File

@ -8,18 +8,18 @@
c64scr.print_string("Let's play a number guessing game!\n")
c64scr.print_string("Enter your name: ")
vm_input_str(name)
Y=c64scr.input_chars(name)
c64scr.print_string("\nHello, ")
c64scr.print_string(name)
c64scr.print_string(".\nI am thinking of a number from 1 to 100! You'll have to guess it!\n")
for ubyte attempts_left in 10 to 1 step -1 {
c64scr.print_string("\nYou have ")
vm_write_num(attempts_left)
c64scr.print_byte_decimal(attempts_left)
c64scr.print_string(" guess")
if attempts_left>1 c64scr.print_string("es")
c64scr.print_string(" left. What is your next guess? ")
vm_input_str(guess)
Y=c64scr.input_chars(guess)
ubyte guessednumber = str2ubyte(guess)
if guessednumber==secretnumber {
c64scr.print_string("\nYou guessed it, impressive!\n")
@ -35,7 +35,7 @@
}
c64scr.print_string("\nToo bad! My number was: ")
vm_write_num(secretnumber)
c64scr.print_byte_decimal(secretnumber)
c64scr.print_string(".\n")
return
}

View File

@ -1,63 +1,11 @@
%output raw
%launcher none
%import c64utils
%option enable_floats
~ main {
sub start() {
; memory ubyte[40] firstScreenLine = $0400
; word ww=333
;
; Y=33
;
; if(Y>3) {
; A=99
; } else {
; A=100
; }
;
; if(ww>33) {
; A=99
; } else {
; A=100
; }
;
; for ubyte c in 10 to 30 {
; firstScreenLine[c] = c
; }
ubyte bv = 99
word wv = 14443
float fv = 3.14
memory ubyte mb = $c000
memory word mw = $c100
memory float mf = $c200
memory ubyte[10] mba = $d000
memory word[10] mwa = $d100
memory float[10] mfa = $d200
memory str mstr = $d300
memory str_p mstrp = $d300
memory str_s mstrs = $d300
memory str_ps mstrps = $d300
mb = 5
mb = Y
mb = bv
mw = 22334
mw = wv
mf = 4.45
mf = fv
mba[9] = 5
mba[9] = Y
mba[9] = bv
mwa[9] = 22334
mwa[9] = wv
mfa[9] = 5.667
mfa[9] = fv
return
}
~ main {
memory ubyte[40*25] Screen = $0400
sub start() {
A, Y = c64flt.GETADRAY()
}
}

View File

@ -413,7 +413,7 @@ class AstChecker(private val namespace: INameScope,
}
}
else
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.position)
checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.value, assignment.targets, assignment.position)
}
}
return assignment
@ -482,13 +482,13 @@ class AstChecker(private val namespace: INameScope,
when(decl.datatype) {
DataType.ARRAY_B, DataType.ARRAY_UB ->
if(arraySize > 256)
err("byte arrayspec length must be 1-256")
err("byte array length must be 1-256")
DataType.ARRAY_W, DataType.ARRAY_UW ->
if(arraySize > 128)
err("word arrayspec length must be 1-128")
err("word array length must be 1-128")
DataType.ARRAY_F ->
if(arraySize > 51)
err("float arrayspec length must be 1-51")
err("float array length must be 1-51")
else -> {}
}
}
@ -891,13 +891,13 @@ class AstChecker(private val namespace: INameScope,
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize<1 || arraySpecSize>256)
return err("byte arrayspec length must be 1-256")
return err("byte array length must be 1-256")
val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
return err("arrayspec size specifier must be constant integer value")
return err("array size specifier must be constant integer value")
val expectedSize = constX.asIntegerValue
if (arraySize != expectedSize)
return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return true
}
return err("invalid byte array size, must be 1-256")
@ -911,18 +911,18 @@ class AstChecker(private val namespace: INameScope,
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).arraysize
if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize<1 || arraySpecSize>128)
return err("word arrayspec length must be 1-128")
return err("word array length must be 1-128")
val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
return err("arrayspec size specifier must be constant integer value")
return err("array size specifier must be constant integer value")
val expectedSize = constX.asIntegerValue
if (arraySize != expectedSize)
return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
return true
}
return err("invalid word arrayspec size, must be 1-128")
return err("invalid word array size, must be 1-128")
}
return err("invalid word arrayspec initialization value ${value.type}, expected $targetDt")
return err("invalid word array initialization value ${value.type}, expected $targetDt")
}
DataType.ARRAY_F -> {
// value may be either a single float, or a float arrayspec
@ -931,15 +931,15 @@ class AstChecker(private val namespace: INameScope,
val arraySpecSize = arrayspec.size()
if(arraySpecSize!=null && arraySpecSize>0) {
if(arraySpecSize < 1 || arraySpecSize>51)
return err("float arrayspec length must be 1-51")
return err("float array length must be 1-51")
val constX = arrayspec.x.constValue(namespace, heap)
if(constX?.asIntegerValue==null)
return err("arrayspec size specifier must be constant integer value")
return err("array size specifier must be constant integer value")
val expectedSize = constX.asIntegerValue
if (arraySize != expectedSize)
return err("initializer arrayspec size mismatch (expecting $expectedSize, got $arraySize)")
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
} else
return err("invalid float arrayspec size, must be 1-51")
return err("invalid float array size, must be 1-51")
// check if the floating point values are all within range
val doubles = if(value.arrayvalue!=null)
@ -950,7 +950,7 @@ class AstChecker(private val namespace: INameScope,
return err("floating point value overflow")
return true
}
return err("invalid float arrayspec initialization value ${value.type}, expected $targetDt")
return err("invalid float array initialization value ${value.type}, expected $targetDt")
}
}
return true
@ -959,6 +959,7 @@ class AstChecker(private val namespace: INameScope,
private fun checkAssignmentCompatible(targetDatatype: DataType,
sourceDatatype: DataType,
sourceValue: IExpression,
assignTargets: List<AssignTarget>,
position: Position) : Boolean {
if(sourceValue is RangeExpr)
@ -980,8 +981,12 @@ class AstChecker(private val namespace: INameScope,
if(result)
return true
if((sourceDatatype==DataType.UWORD || sourceDatatype==DataType.WORD) && (targetDatatype==DataType.UBYTE || targetDatatype==DataType.BYTE))
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
if((sourceDatatype==DataType.UWORD || sourceDatatype==DataType.WORD) && (targetDatatype==DataType.UBYTE || targetDatatype==DataType.BYTE)) {
if(assignTargets.size==2 && assignTargets[0].register!=null && assignTargets[1].register!=null)
return true // for asm subroutine calls that return a (U)WORD that's going to be stored into two BYTES (registers), we make an exception.
else
checkResult.add(ExpressionError("cannot assign word to byte, use msb() or lsb()?", position))
}
else if(sourceDatatype==DataType.FLOAT && targetDatatype in IntegerDatatypes)
checkResult.add(ExpressionError("cannot assign float to ${targetDatatype.toString().toLowerCase()}; possible loss of precision. Suggestion: round the value or revert to integer arithmetic", position))
else

View File

@ -21,7 +21,7 @@ abstract class Zeropage(private val options: CompilationOptions) {
DataType.UBYTE -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!!
DataType.UWORD -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! * 2
DataType.FLOAT -> (vardecl.arrayspec.x as LiteralValue).asIntegerValue!! * 5
else -> throw CompilerException("arrayspec can only be of byte, word, float")
else -> throw CompilerException("array can only be of byte, word, float")
}
} else {
when (vardecl.datatype) {

View File

@ -274,8 +274,8 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
}
currentBlock.variables[scopedname] = value
}
VarDeclType.CONST -> {} // constants are all folded away
VarDeclType.MEMORY -> {
VarDeclType.MEMORY, VarDeclType.CONST -> {
// note that constants are all folded away, but assembly code may still refer to them
val lv = decl.value as LiteralValue
if(lv.type!=DataType.UWORD && lv.type!=DataType.UBYTE)
throw CompilerException("expected integer memory address $lv")

View File

@ -619,10 +619,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
Opcode.INV_WORD -> {
"""
lda ${(ESTACK_LO + 1).toHex()},x
lda ${(ESTACK_LO+1).toHex()},x
eor #255
sta ${(ESTACK_LO+1).toHex()},x
lda ${(ESTACK_HI + 1).toHex()},x
lda ${(ESTACK_HI+1).toHex()},x
eor #255
sta ${(ESTACK_HI+1).toHex()},x
"""
@ -732,11 +732,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.MUL_W -> " jsr prog8_lib.mul_w"
Opcode.MUL_UW -> " jsr prog8_lib.mul_uw"
Opcode.MUL_F -> " jsr prog8_lib.mul_f"
Opcode.LESS_UB -> " jsr prog8_lib.less_ub"
Opcode.LESS_B -> " jsr prog8_lib.less_b"
Opcode.LESS_UW -> " jsr prog8_lib.less_uw"
Opcode.LESS_W -> " jsr prog8_lib.less_w"
Opcode.LESS_F -> " jsr prog8_lib.less_f"
Opcode.AND_BYTE -> {
"""
@ -754,6 +749,39 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
sta ${(ESTACK_LO + 1).toHex()},x
"""
}
Opcode.REMAINDER_B -> " jsr prog8_lib.remainder_b"
Opcode.REMAINDER_UB -> " jsr prog8_lib.remainder_ub"
Opcode.REMAINDER_W -> " jsr prog8_lib.remainder_w"
Opcode.REMAINDER_UW -> " jsr prog8_lib.remainder_uw"
Opcode.REMAINDER_F -> " jsr prog8_lib.remainder_f"
Opcode.GREATER_B -> " jsr prog8_lib.greater_b"
Opcode.GREATER_UB -> " jsr prog8_lib.greater_ub"
Opcode.GREATER_W -> " jsr prog8_lib.greater_w"
Opcode.GREATER_UW -> " jsr prog8_lib.greater_uw"
Opcode.GREATER_F -> " jsr prog8_lib.greater_f"
Opcode.GREATEREQ_B -> " jsr prog8_lib.greatereq_b"
Opcode.GREATEREQ_UB -> " jsr prog8_lib.greatereq_ub"
Opcode.GREATEREQ_W -> " jsr prog8_lib.greatereq_w"
Opcode.GREATEREQ_UW -> " jsr prog8_lib.greatereq_uw"
Opcode.GREATEREQ_F -> " jsr prog8_lib.greatereq_f"
Opcode.EQUAL_BYTE -> " jsr prog8_lib.equal_b"
Opcode.EQUAL_WORD -> " jsr prog8_lib.equal_w"
Opcode.EQUAL_F -> " jsr prog8_lib.equal_f"
Opcode.LESS_UB -> " jsr prog8_lib.less_ub"
Opcode.LESS_B -> " jsr prog8_lib.less_b"
Opcode.LESS_UW -> " jsr prog8_lib.less_uw"
Opcode.LESS_W -> " jsr prog8_lib.less_w"
Opcode.LESS_F -> " jsr prog8_lib.less_f"
Opcode.LESSEQ_UB -> " jsr prog8_lib.lesseq_ub"
Opcode.LESSEQ_B -> " jsr prog8_lib.lesseq_b"
Opcode.LESSEQ_UW -> " jsr prog8_lib.lesseq_uw"
Opcode.LESSEQ_W -> " jsr prog8_lib.lesseq_w"
Opcode.LESSEQ_F -> " jsr prog8_lib.lesseq_f"
else -> null
}
@ -830,6 +858,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
private fun sameConstantIndexedVarOperation(variable: String, index: Int, ins: Instruction): AsmFragment? {
// an in place operation that consists of a push-value / op / push-index-value / pop-into-indexed-var
return when(ins.opcode) {
Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8)
Opcode.SHR_BYTE -> AsmFragment(" lsr $variable+$index", 8)
@ -848,6 +877,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
private fun sameIndexedVarOperation(variable: String, indexVar: String, ins: Instruction): AsmFragment? {
// an in place operation that consists of a push-value / op / push-index-var / pop-into-indexed-var
val saveX = " stx ${C64Zeropage.SCRATCH_B1} |"
val restoreX = " | ldx ${C64Zeropage.SCRATCH_B1}"
val loadXWord: String
@ -891,6 +921,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
private fun sameMemOperation(address: Int, ins: Instruction): AsmFragment? {
// an in place operation that consists of a push-mem / op / pop-mem sequence
val addr = address.toHex()
val addrHi = (address+1).toHex()
return when(ins.opcode) {
@ -911,6 +942,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
private fun sameVarOperation(variable: String, ins: Instruction): AsmFragment? {
// an in place operation that consists of a push-var / op / pop-var
return when(ins.opcode) {
Opcode.SHL_BYTE -> {
when (variable) {
@ -2705,9 +2737,28 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
// push msb(word var)
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.MSB)) { segment ->
" lda #>${segment[0].callLabel} | sta ${ESTACK_LO.toHex()},x | dex "
},
// set a register pair to a certain memory address (of a variable)
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_REGAX_WORD)) { segment ->
" lda #<${segment[0].callLabel} | ldx #>${segment[0].callLabel} "
},
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_REGAY_WORD)) { segment ->
" lda #<${segment[0].callLabel} | ldy #>${segment[0].callLabel} "
},
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_REGXY_WORD)) { segment ->
" ldx #<${segment[0].callLabel} | ldy #>${segment[0].callLabel} "
},
// set a register pair to a certain memory address (of a literal string value)
AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGAX_WORD)) { segment ->
TODO("$segment")
},
AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGAY_WORD)) { segment ->
TODO("$segment")
},
AsmPattern(listOf(Opcode.PUSH_ADDR_STR, Opcode.POP_REGXY_WORD)) { segment ->
TODO("$segment")
}
)
}

View File

@ -648,7 +648,7 @@ asmsub print_pstring (text: str_p @ XY) -> clobbers(A,X) -> (ubyte @ Y) {
asmsub print_byte_decimal0 (value: ubyte @ A) -> clobbers(A,X,Y) -> () {
; ---- print the byte in A in decimal form, with left padding 0s (3 positions total)
%asm {{
jsr byte2decimal
jsr c64utils.byte2decimal
pha
tya
jsr c64.CHROUT
@ -663,7 +663,7 @@ asmsub print_byte_decimal0 (value: ubyte @ A) -> clobbers(A,X,Y) -> () {
asmsub print_byte_decimal (value: ubyte @ A) -> clobbers(A,X,Y) -> () {
; ---- print the byte in A in decimal form, without left padding 0s
%asm {{
jsr byte2decimal
jsr c64utils.byte2decimal
pha
cpy #'0'
bne _print_hundreds
@ -689,7 +689,7 @@ asmsub print_byte_hex (prefix: ubyte @ Pc, value: ubyte @ A) -> clobbers(A,X,Y
lda #'$'
jsr c64.CHROUT
pla
+ jsr byte2hex
+ jsr c64utils.byte2hex
txa
jsr c64.CHROUT
tya
@ -716,16 +716,16 @@ asmsub print_word_decimal0 (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
; ---- print the (unsigned) word in X/Y in decimal form, with left padding 0s (5 positions total)
; @todo shorter in loop form?
%asm {{
jsr word2decimal
lda word2decimal_output
jsr c64utils.word2decimal
lda c64utils.word2decimal_output
jsr c64.CHROUT
lda word2decimal_output+1
lda c64utils.word2decimal_output+1
jsr c64.CHROUT
lda word2decimal_output+2
lda c64utils.word2decimal_output+2
jsr c64.CHROUT
lda word2decimal_output+3
lda c64utils.word2decimal_output+3
jsr c64.CHROUT
lda word2decimal_output+4
lda c64utils.word2decimal_output+4
jmp c64.CHROUT
}}
}
@ -734,27 +734,27 @@ asmsub print_word_decimal0 (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
asmsub print_word_decimal (dataword: uword @ XY) -> clobbers(A,X,Y) -> () {
; ---- print the word in X/Y in decimal form, without left padding 0s
%asm {{
jsr word2decimal
jsr c64utils.word2decimal
ldy #0
lda word2decimal_output
lda c64utils.word2decimal_output
cmp #'0'
bne _pr_decimal
iny
lda word2decimal_output+1
lda c64utils.word2decimal_output+1
cmp #'0'
bne _pr_decimal
iny
lda word2decimal_output+2
lda c64utils.word2decimal_output+2
cmp #'0'
bne _pr_decimal
iny
lda word2decimal_output+3
lda c64utils.word2decimal_output+3
cmp #'0'
bne _pr_decimal
iny
_pr_decimal
lda word2decimal_output,y
lda c64utils.word2decimal_output,y
jsr c64.CHROUT
iny
cpy #5

View File

@ -82,15 +82,6 @@ mul_f
neg_f
rts
less_ub
rts
less_b
rts
less_f
rts
add_w
rts ; @todo inline?
@ -120,7 +111,92 @@ div_w
div_uw
rts
remainder_b
rts
remainder_ub
rts
remainder_w
rts
remainder_uw
rts
remainder_f
rts
equal_ub
rts
equal_b
rts
equal_w
rts
equal_uw
rts
equal_f
rts
less_ub
rts
less_b
rts
less_w
rts
less_uw
rts
less_f
rts
lesseq_ub
rts
lesseq_b
rts
lesseq_w
rts
lesseq_uw
rts
lesseq_f
rts
greater_ub
rts
greater_b
rts
greater_w
rts
greater_uw
rts
greater_f
rts
greatereq_ub
rts
greatereq_b
rts
greatereq_w
rts
greatereq_uw
rts
greatereq_f
rts
func_sin
rts
func_cos