From 8597ea2ec7ae2061f21f082762b0510fb4382c13 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 14 Dec 2018 23:15:44 +0100 Subject: [PATCH] correct printing of numbers --- compiler/examples/test.p8 | 222 ++++++++++++++--- compiler/src/prog8/ast/AST.kt | 4 + .../src/prog8/compiler/target/c64/AsmGen.kt | 5 +- .../src/prog8/functions/BuiltinFunctions.kt | 8 +- .../src/prog8/optimizing/ConstantFolding.kt | 1 - compiler/test/UnitTests.kt | 15 +- prog8lib/c64utils.p8 | 229 +++++++----------- prog8lib/mathlib.p8 | 44 ++-- prog8lib/prog8lib.p8 | 74 ++++-- 9 files changed, 370 insertions(+), 232 deletions(-) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 3c6cd5b82..7c2dae954 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -6,60 +6,220 @@ sub start() { ubyte ub1 + ubyte ub2 byte b1 + byte b2 uword uw1 + uword uw2 word w1 + word w2 float f1 float f2 float f3 - - f1=22.555 - f2=15.123 - f3 = f1+f2 - c64flt.print_float(f3) + ; byte and ubyte output via print are all OK! + 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') + c64scr.print_ubyte_decimal(0) + 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') + c64scr.print_ubyte_hex(0, 0) + 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') - f1=22.555 - f2=15.123 - f3 = f1-f2 - c64flt.print_float(f3) + ; 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') + 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') - f1=22.555 - f2=15.123 - f3 = f1*f2 - c64flt.print_float(f3) + + ; 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') - f1=22.555 - f2=15.123 - f3 = f1/f2 - c64flt.print_float(f3) + + 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') - f3 = -f1 - c64flt.print_float(f3) + 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') - f3++ - c64flt.print_float(f3) + 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') - f3++ - c64flt.print_float(f3) + + 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') - f3++ - c64flt.print_float(f3) + + + 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') - f3-- - c64flt.print_float(f3) + + 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') - f3-- - c64flt.print_float(f3) + + 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') - f3-- - c64flt.print_float(f3) + + 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') + } } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index c293fdcd1..e513114a0 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -775,6 +775,10 @@ class PrefixExpression(val operator: String, var expression: IExpression, overri override fun referencesIdentifier(name: String) = expression.referencesIdentifier(name) override fun resultingDatatype(namespace: INameScope, heap: HeapValues): DataType? = expression.resultingDatatype(namespace, heap) override fun isIterable(namespace: INameScope, heap: HeapValues) = false + + override fun toString(): String { + return "Prefix($operator $expression)" + } } diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 9b5b37ac0..875e89d9b 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -434,7 +434,10 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr }) throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}") val call = Syscall.values().find { it.callNr==ins.arg.numericValue() } - " jsr prog8_lib.${call.toString().toLowerCase()}" + when(call) { + Syscall.FUNC_WRD, Syscall.FUNC_UWRD -> "" + else -> " jsr prog8_lib.${call.toString().toLowerCase()}" + } } Opcode.BREAKPOINT -> { breakpointCounter++ diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 3424dd63b..dbdb592ef 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -255,7 +255,7 @@ private fun builtinWrd(args: List, position: Position, namespace:IN val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() if(constval.type!=DataType.UBYTE && constval.type!=DataType.BYTE && constval.type!=DataType.UWORD) throw SyntaxError("wrd requires one argument of type ubyte, byte or uword", position) - return LiteralValue(DataType.WORD, wordvalue = constval.bytevalue!!.toInt(), position = position) + return LiteralValue(DataType.WORD, wordvalue = constval.asIntegerValue, position = position) } private fun builtinUwrd(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { @@ -266,7 +266,7 @@ private fun builtinUwrd(args: List, position: Position, namespace:I val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() if(constval.type!=DataType.BYTE && constval.type!=DataType.WORD && constval.type!=DataType.UWORD) throw SyntaxError("uwrd requires one argument of type byte, word or uword", position) - return LiteralValue(DataType.UWORD, wordvalue = constval.bytevalue!!.toInt(), position = position) + return LiteralValue(DataType.UWORD, wordvalue = constval.asIntegerValue!! and 65535, position = position) } private fun builtinB2ub(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { @@ -275,8 +275,8 @@ private fun builtinB2ub(args: List, position: Position, namespace:I throw SyntaxError("b2ub requires one byte argument", position) val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() - if(constval.type!=DataType.BYTE) - throw SyntaxError("b2ub requires one argument of type byte", position) + if(constval.type!=DataType.BYTE && constval.type!=DataType.UBYTE) + throw SyntaxError("b2ub requires one argument of type byte or ubyte", position) return LiteralValue(DataType.UBYTE, bytevalue=(constval.bytevalue!!.toInt() and 255).toShort(), position = position) } diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index d7c275340..ed5df244f 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -5,7 +5,6 @@ import prog8.compiler.CompilerException import prog8.compiler.HeapValues import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE -import prog8.compiler.target.c64.Petscii import kotlin.math.floor diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index ab452c24e..5c4744632 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -9,6 +9,7 @@ import prog8.ast.* import prog8.compiler.* import prog8.compiler.intermediate.Value import prog8.compiler.target.c64.* +import java.io.CharConversionException import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse @@ -272,8 +273,8 @@ class TestPetscii { listOf(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c))) assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(listOf(0x12))) // reverse vid assertThat(Petscii.encodePetscii("✓", true), equalTo(listOf(0xfa))) - assertFailsWith { Petscii.encodePetscii("π", true) } - assertFailsWith { Petscii.encodePetscii("♥", true) } + assertFailsWith { Petscii.encodePetscii("π", true) } + assertFailsWith { Petscii.encodePetscii("♥", true) } assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A")) assertFailsWith { Petscii.decodePetscii(listOf(-1), true) } @@ -287,7 +288,7 @@ class TestPetscii { assertThat(Petscii.encodePetscii("\uf11a"), equalTo(listOf(0x12))) // reverse vid assertThat(Petscii.encodePetscii("♥"), equalTo(listOf(0xd3))) assertThat(Petscii.encodePetscii("π"), equalTo(listOf(0xff))) - assertFailsWith { Petscii.encodePetscii("✓") } + assertFailsWith { Petscii.encodePetscii("✓") } assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π")) assertFailsWith { Petscii.decodePetscii(listOf(-1)) } @@ -300,8 +301,8 @@ class TestPetscii { listOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c) )) assertThat(Petscii.encodeScreencode("✓", true), equalTo(listOf(0x7a))) - assertFailsWith { Petscii.encodeScreencode("♥", true) } - assertFailsWith { Petscii.encodeScreencode("π", true) } + assertFailsWith { Petscii.encodeScreencode("♥", true) } + assertFailsWith { Petscii.encodeScreencode("π", true) } assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓")) assertFailsWith { Petscii.decodeScreencode(listOf(-1), true) } @@ -314,8 +315,8 @@ class TestPetscii { listOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c))) assertThat(Petscii.encodeScreencode("♥"), equalTo(listOf(0x53))) assertThat(Petscii.encodeScreencode("π"), equalTo(listOf(0x5e))) - assertFailsWith { Petscii.encodeScreencode("✓") } - assertFailsWith { Petscii.encodeScreencode("hello") } + assertFailsWith { Petscii.encodeScreencode("✓") } + assertFailsWith { Petscii.encodeScreencode("hello") } assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π")) assertFailsWith { Petscii.decodeScreencode(listOf(-1)) } diff --git a/prog8lib/c64utils.p8 b/prog8lib/c64utils.p8 index 3d12c9d1a..691d95b8e 100644 --- a/prog8lib/c64utils.p8 +++ b/prog8lib/c64utils.p8 @@ -44,7 +44,7 @@ asmsub init_system () -> clobbers(A,X,Y) -> () { }} } -asmsub byte2decimal (value: ubyte @ A) -> clobbers() -> (ubyte @ Y, ubyte @ X, ubyte @ A) { +asmsub ubyte2decimal (value: ubyte @ A) -> clobbers() -> (ubyte @ Y, ubyte @ X, ubyte @ A) { ; ---- A to decimal string in Y/X/A (100s in Y, 10s in X, 1s in A) %asm {{ ldy #$2f @@ -61,8 +61,21 @@ asmsub byte2decimal (value: ubyte @ A) -> clobbers() -> (ubyte @ Y, ubyte @ X, }} } -asmsub byte2hex (value: ubyte @ A) -> clobbers(A) -> (ubyte @ X, ubyte @ Y) { - ; ---- A to hex string in XY (first hex char in X, second hex char in Y) +asmsub byte2decimal (value: ubyte @ A) -> clobbers() -> (ubyte @ Y, ubyte @ X, ubyte @ A) { + ; ---- A (signed byte) to decimal string in Y/X/A (100s in Y, 10s in X, 1s in A) + ; note: the '-' is not part of the conversion here if it's a negative number + %asm {{ + cmp #0 + bpl + + eor #255 + clc + adc #1 ++ jmp ubyte2decimal + }} +} + +asmsub ubyte2hex (value: ubyte @ A) -> clobbers(X) -> (ubyte @ A, ubyte @ Y) { + ; ---- A to hex string in AY (first hex char in A, second hex char in Y) %asm {{ pha and #$0f @@ -75,7 +88,6 @@ asmsub byte2hex (value: ubyte @ A) -> clobbers(A) -> (ubyte @ X, ubyte @ Y) { lsr a tax lda hex_digits,x - tax rts hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well @@ -84,33 +96,33 @@ hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as str word2hex_output = "1234" ; 0-terminated, to make printing easier -asmsub word2hex (dataword: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- convert 16 bit word in X/Y into 4-character hexadecimal string into memory 'word2hex_output' +asmsub uword2hex (value: uword @ AY) -> clobbers(A,X,Y) -> () { + ; ---- convert 16 bit uword in A/Y into 4-character hexadecimal string into memory 'word2hex_output' %asm {{ - stx c64.SCRATCH_ZPREG + sta c64.SCRATCH_ZPREG tya - jsr byte2hex + jsr ubyte2hex stx word2hex_output sty word2hex_output+1 lda c64.SCRATCH_ZPREG - jsr byte2hex - stx word2hex_output+2 + jsr ubyte2hex + sta word2hex_output+2 sty word2hex_output+3 rts }} } ubyte[3] word2bcd_bcdbuff = [0, 0, 0] -asmsub word2bcd (dataword: uword @ XY) -> clobbers(A,X) -> () { +asmsub uword2bcd (dataword: uword @ AY) -> clobbers(A,X) -> () { ; Convert an 16 bit binary value to BCD ; - ; This function converts a 16 bit binary value in X/Y into a 24 bit BCD. It + ; This function converts a 16 bit binary value in A/Y into a 24 bit BCD. It ; works by transferring one bit a time from the source and adding it ; into a BCD value that is being doubled on each iteration. As all the ; arithmetic is being done in BCD the result is a binary to decimal ; conversion. %asm {{ - stx c64.SCRATCH_ZPB1 + sta c64.SCRATCH_ZPB1 sty c64.SCRATCH_ZPREG sed ; switch to decimal mode lda #0 ; ensure the result is clear @@ -139,10 +151,10 @@ asmsub word2bcd (dataword: uword @ XY) -> clobbers(A,X) -> () { ubyte[5] word2decimal_output = 0 -asmsub word2decimal (dataword: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- convert 16 bit word in X/Y into decimal string into memory 'word2decimal_output' +asmsub uword2decimal (dataword: uword @ AY) -> clobbers(A,X,Y) -> () { + ; ---- convert 16 bit uword in A/Y into decimal string into memory 'word2decimal_output' %asm {{ - jsr word2bcd + jsr uword2bcd lda word2bcd_bcdbuff+2 clc adc #'0' @@ -264,102 +276,10 @@ asmsub GETADRAY () -> clobbers(X) -> (uword @ AY) { }} } - -asmsub copy_mflt (source: uword @ XY) -> clobbers(A) -> () { - ; ---- copy a 5 byte MFLT floating point variable to another place - ; input: X/Y = source address, c64.SCRATCH_ZPWORD1 = destination address - %asm {{ - stx c64.SCRATCH_ZPB1 - sty c64.SCRATCH_ZPWORD1+1 - ldy #0 - lda (c64.SCRATCH_ZPB1),y - sta (c64.SCRATCH_ZPWORD1),y - iny - lda (c64.SCRATCH_ZPB1),y - sta (c64.SCRATCH_ZPWORD1),y - iny - lda (c64.SCRATCH_ZPB1),y - sta (c64.SCRATCH_ZPWORD1),y - iny - lda (c64.SCRATCH_ZPB1),y - sta (c64.SCRATCH_ZPWORD1),y - iny - lda (c64.SCRATCH_ZPB1),y - sta (c64.SCRATCH_ZPWORD1),y - ldy c64.SCRATCH_ZPWORD1+1 - rts - }} -} - -asmsub float_add_one (mflt: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- add 1 to the MFLT pointed to by X/Y. Clobbers A, X, Y - %asm {{ - stx c64.SCRATCH_ZPB1 - sty c64.SCRATCH_ZPREG - txa - jsr c64.MOVFM ; fac1 = float XY - lda #c64.FL_FONE - jsr c64.FADD ; fac1 += 1 - ldx c64.SCRATCH_ZPB1 - ldy c64.SCRATCH_ZPREG - jmp c64.MOVMF ; float XY = fac1 - }} -} - -asmsub float_sub_one (mflt: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- subtract 1 from the MFLT pointed to by X/Y. Clobbers A, X, Y - %asm {{ - stx c64.SCRATCH_ZPB1 - sty c64.SCRATCH_ZPREG - lda #c64.FL_FONE - jsr c64.MOVFM ; fac1 = 1 - txa - ldy c64.SCRATCH_ZPREG - jsr c64.FSUB ; fac1 = float XY - 1 - ldx c64.SCRATCH_ZPB1 - ldy c64.SCRATCH_ZPREG - jmp c64.MOVMF ; float XY = fac1 - }} -} - -asmsub float_add_SW1_to_XY (mflt: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- add MFLT pointed to by SCRATCH_ZPWORD1 to the MFLT pointed to by X/Y. Clobbers A, X, Y - %asm {{ - stx c64.SCRATCH_ZPB1 - sty c64.SCRATCH_ZPREG - txa - jsr c64.MOVFM ; fac1 = float XY - lda c64.SCRATCH_ZPWORD1 - ldy c64.SCRATCH_ZPWORD1+1 - jsr c64.FADD ; fac1 += SCRATCH_ZPWORD1 - ldx c64.SCRATCH_ZPB1 - ldy c64.SCRATCH_ZPREG - jmp c64.MOVMF ; float XY = fac1 - }} -} - -asmsub float_sub_SW1_from_XY (mflt: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- subtract MFLT pointed to by SCRATCH_ZPWORD1 from the MFLT pointed to by X/Y. Clobbers A, X, Y - %asm {{ - stx c64.SCRATCH_ZPB1 - sty c64.SCRATCH_ZPREG - lda c64.SCRATCH_ZPWORD1 - ldy c64.SCRATCH_ZPWORD1+1 - jsr c64.MOVFM ; fac1 = SCRATCH_ZPWORD1 - txa - ldy c64.SCRATCH_ZPREG - jsr c64.FSUB ; fac1 = float XY - SCRATCH_ZPWORD1 - ldx c64.SCRATCH_ZPB1 - ldy c64.SCRATCH_ZPREG - jmp c64.MOVMF ; float XY = fac1 - }} -} - sub print_float (value: float) { ; ---- prints the floating point value (without a newline) using basic rom routines. ; clobbers no registers. + ; @todo version that takes A/Y pointer to float instead %asm {{ pha tya @@ -383,6 +303,7 @@ sub print_float (value: float) { sub print_float_ln (value: float) { ; ---- prints the floating point value (with a newline at the end) using basic rom routines ; clobbers no registers. + ; @todo version that takes A/Y pointer to float instead %asm {{ pha tya @@ -654,13 +575,13 @@ _scroll_screen ; scroll the screen memory -asmsub print_string (text: str @ XY) -> clobbers(A,Y) -> () { - ; ---- print null terminated string from X/Y +asmsub print_string (text: str @ AY) -> clobbers(A,Y) -> () { + ; ---- print null terminated string from A/Y ; note: the compiler contains an optimization that will replace ; a call to this subroutine with a string argument of just one char, ; by just one call to c64.CHROUT of that single char. @todo do this %asm {{ - stx c64.SCRATCH_ZPB1 + sta c64.SCRATCH_ZPB1 sty c64.SCRATCH_ZPREG ldy #0 - lda (c64.SCRATCH_ZPB1),y @@ -673,10 +594,10 @@ asmsub print_string (text: str @ XY) -> clobbers(A,Y) -> () { } -asmsub print_pstring (text: str_p @ XY) -> clobbers(A,X) -> (ubyte @ Y) { - ; ---- print pstring (length as first byte) from X/Y, returns str len in Y +asmsub print_pstring (text: str_p @ AY) -> clobbers(A,X) -> (ubyte @ Y) { + ; ---- print pstring (length as first byte) from A/Y, returns str len in Y %asm {{ - stx c64.SCRATCH_ZPB1 + sta c64.SCRATCH_ZPB1 sty c64.SCRATCH_ZPREG ldy #0 lda (c64.SCRATCH_ZPB1),y @@ -692,10 +613,10 @@ 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) +asmsub print_ubyte_decimal0 (value: ubyte @ A) -> clobbers(A,X,Y) -> () { + ; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total) %asm {{ - jsr c64utils.byte2decimal + jsr c64utils.ubyte2decimal pha tya jsr c64.CHROUT @@ -707,10 +628,11 @@ 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 +asmsub print_ubyte_decimal (value: ubyte @ A) -> clobbers(A,X,Y) -> () { + ; ---- print the ubyte in A in decimal form, without left padding 0s %asm {{ - jsr c64utils.byte2decimal + jsr c64utils.ubyte2decimal +_print_byte_digits pha cpy #'0' bne _print_hundreds @@ -726,18 +648,31 @@ _print_tens txa jmp c64.CHROUT }} } + +asmsub print_byte_decimal (value: ubyte @ A) -> clobbers(A,X,Y) -> () { + ; ---- print the byte in A in decimal form, without left padding 0s + %asm {{ + pha + cmp #0 + bpl + + lda #'-' + jsr c64.CHROUT ++ pla + jsr c64utils.byte2decimal + jmp print_ubyte_decimal._print_byte_digits + }} +} -asmsub print_byte_hex (prefix: ubyte @ Pc, value: ubyte @ A) -> clobbers(A,X,Y) -> () { - ; ---- print the byte in A in hex form (if Carry is set, a radix prefix '$' is printed as well) +asmsub print_ubyte_hex (prefix: ubyte @ Pc, value: ubyte @ A) -> clobbers(A,X,Y) -> () { + ; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well) %asm {{ bcc + pha lda #'$' jsr c64.CHROUT pla -+ jsr c64utils.byte2hex - txa ++ jsr c64utils.ubyte2hex jsr c64.CHROUT tya jmp c64.CHROUT @@ -745,25 +680,25 @@ asmsub print_byte_hex (prefix: ubyte @ Pc, value: ubyte @ A) -> clobbers(A,X,Y } -asmsub print_word_hex (prefix: ubyte @ Pc, dataword: uword @ XY) -> clobbers(A,X,Y) -> () { - ; ---- print the (unsigned) word in X/Y in hexadecimal form (4 digits) +asmsub print_uword_hex (prefix: ubyte @ Pc, value: uword @ AY) -> clobbers(A,X,Y) -> () { + ; ---- print the uword in A/Y in hexadecimal form (4 digits) ; (if Carry is set, a radix prefix '$' is printed as well) %asm {{ - stx c64.SCRATCH_ZPB1 + pha tya - jsr print_byte_hex - lda c64.SCRATCH_ZPB1 + jsr print_ubyte_hex + pla clc - jmp print_byte_hex + jmp print_ubyte_hex }} } -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) +asmsub print_uword_decimal0 (value: uword @ AY) -> clobbers(A,X,Y) -> () { + ; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total) ; @todo shorter in loop form? %asm {{ - jsr c64utils.word2decimal + jsr c64utils.uword2decimal lda c64utils.word2decimal_output jsr c64.CHROUT lda c64utils.word2decimal_output+1 @@ -778,10 +713,10 @@ 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 +asmsub print_uword_decimal (value: uword @ AY) -> clobbers(A,X,Y) -> () { + ; ---- print the uword in A/Y in decimal form, without left padding 0s %asm {{ - jsr c64utils.word2decimal + jsr c64utils.uword2decimal ldy #0 lda c64utils.word2decimal_output cmp #'0' @@ -810,6 +745,26 @@ _pr_decimal }} } +asmsub print_word_decimal (value: uword @ AY) -> clobbers(A,X,Y) -> () { + ; ---- print the (signed) word in A/Y in decimal form, without left padding 0s + %asm {{ + cpy #0 + bpl + + pha + lda #'-' + jsr c64.CHROUT + tya + eor #255 + tay + pla + eor #255 + clc + adc #1 + bcc + + iny ++ jmp print_uword_decimal + }} +} asmsub input_chars (buffer: uword @ AY) -> clobbers(A, X) -> (ubyte @ Y) { ; ---- Input a string (max. 80 chars) from the keyboard. Returns length in Y. diff --git a/prog8lib/mathlib.p8 b/prog8lib/mathlib.p8 index d73206f52..bdd79df33 100644 --- a/prog8lib/mathlib.p8 +++ b/prog8lib/mathlib.p8 @@ -19,10 +19,10 @@ -asmsub multiply_bytes (byte1: ubyte @ X, byte2: ubyte @ Y) -> clobbers(X) -> (ubyte @ A) { +asmsub multiply_bytes (byte1: ubyte @ A, byte2: ubyte @ Y) -> clobbers(X) -> (ubyte @ A) { ; ---- multiply 2 bytes, result as byte in A (signed or unsigned) %asm {{ - stx SCRATCH_ZPB1 + sta SCRATCH_ZPB1 sty SCRATCH_ZPREG ldx #8 - asl a @@ -37,12 +37,12 @@ asmsub multiply_bytes (byte1: ubyte @ X, byte2: ubyte @ Y) -> clobbers(X) -> ( } -asmsub multiply_bytes_16 (byte1: ubyte @ X, byte2: ubyte @ Y) -> clobbers(A) -> (uword @ XY) { - ; ---- multiply 2 bytes, result as word in X/Y (unsigned) +asmsub multiply_bytes_16 (byte1: ubyte @ A, byte2: ubyte @ Y) -> clobbers(X) -> (uword @ AY) { + ; ---- multiply 2 bytes, result as word in A/Y (unsigned) %asm {{ - lda #0 -_m_with_add stx SCRATCH_ZPB1 + sta SCRATCH_ZPB1 sty SCRATCH_ZPREG + lda #0 ldx #8 lsr SCRATCH_ZPB1 - bcc + @@ -53,26 +53,19 @@ _m_with_add stx SCRATCH_ZPB1 dex bne - tay - ldx SCRATCH_ZPB1 + lda SCRATCH_ZPB1 rts }} } -asmsub multiply_bytes_addA_16 (byte1: ubyte @ X, byte2: ubyte @ Y, add: ubyte @ A) -> clobbers(A) -> (uword @ XY) { - ; ---- multiply 2 bytes and add A, result as word in X/Y (unsigned) - %asm {{ - jmp multiply_bytes_16._m_with_add - }} -} - word[2] multiply_words_product = 0 -asmsub multiply_words (number: uword @ XY) -> clobbers(A,X) -> () { +asmsub multiply_words (number: uword @ AY) -> clobbers(A,X) -> () { ; ---- multiply two 16-bit words into a 32-bit result - ; input: X/Y = first 16-bit number, SCRATCH_ZPWORD1 in ZP = second 16-bit number + ; input: A/Y = first 16-bit number, SCRATCH_ZPWORD1 in ZP = second 16-bit number ; output: multiply_words_product 32-bits product, LSB order (low-to-high) %asm {{ - stx SCRATCH_ZPWORD2 + sta SCRATCH_ZPWORD2 sty SCRATCH_ZPWORD2+1 mult16 lda #$00 @@ -123,16 +116,16 @@ asmsub divmod_bytes (number: ubyte @ X, divisor: ubyte @ Y) -> clobbers() -> ( }} } -asmsub divmod_words (divisor: uword @ XY) -> clobbers(A) -> (uword @ XY) { +asmsub divmod_words (divisor: uword @ AY) -> clobbers(X) -> (uword @ AY) { ; ---- divide two words (16 bit each) into 16 bit results - ; input: SCRATCH_ZPWORD1 in ZP: 16 bit number, X/Y: 16 bit divisor - ; output: SCRATCH_ZPWORD1 in ZP: 16 bit result, X/Y: 16 bit remainder + ; input: SCRATCH_ZPWORD1 in ZP: 16 bit number, A/Y: 16 bit divisor + ; output: SCRATCH_ZPWORD1 in ZP: 16 bit result, A/Y: 16 bit remainder ; division by zero will result in quotient = 65535 and remainder = divident %asm {{ remainder = SCRATCH_ZPB1 - stx SCRATCH_ZPWORD2 + sta SCRATCH_ZPWORD2 sty SCRATCH_ZPWORD2+1 lda #0 ;preset remainder to 0 sta remainder @@ -163,7 +156,7 @@ remainder = SCRATCH_ZPB1 lda remainder+1 sta SCRATCH_ZPWORD2+1 - ldx SCRATCH_ZPWORD1 ; load division result in X/Y + lda SCRATCH_ZPWORD1 ; load division result in A/Y ldy SCRATCH_ZPWORD1+1 rts @@ -211,8 +204,8 @@ _magiceors .byte $1d, $2b, $2d, $4d, $5f, $63, $65, $69 }} } -asmsub randword () -> clobbers() -> (uword @ XY) { - ; ---- 16 bit pseudo random number generator into XY +asmsub randword () -> clobbers() -> (uword @ AY) { + ; ---- 16 bit pseudo random number generator into AY %asm {{ lda _seed @@ -230,7 +223,6 @@ _doEor ; high byte is in A lda _seed eor _magic ; #