diff --git a/compiler/res/prog8lib/c64flt.p8 b/compiler/res/prog8lib/c64flt.p8 index 8f02ba27c..a2a536a6b 100644 --- a/compiler/res/prog8lib/c64flt.p8 +++ b/compiler/res/prog8lib/c64flt.p8 @@ -9,11 +9,11 @@ ~ c64flt { ; ---- this block contains C-64 floating point related functions ---- - + const float PI = 3.141592653589793 const float TWOPI = 6.283185307179586 - + ; ---- C64 basic and kernal ROM float constants and functions ---- ; note: the fac1 and fac2 are working registers and take 6 bytes each, @@ -34,7 +34,6 @@ memory float FL_PIHALF = $e2e0 ; PI / 2 memory float FL_TWOPI = $e2e5 ; 2 * PI memory float FL_FR4 = $e2ea ; .25 - float FL_ZERO = 0.0 ; oddly enough 0.0 isn't available in the kernel ; note: fac1/2 might get clobbered even if not mentioned in the function's name. @@ -193,7 +192,7 @@ asmsub GETADRAY () -> clobbers(X) -> (uword @ AY) { } sub print_f (float value) { - ; ---- prints the floating point value (without a newline) using basic rom routines. + ; ---- prints the floating point value (without a newline) using basic rom routines. %asm {{ stx c64.SCRATCH_ZPREGX lda #fmath_float1 jmp c64flt.MOVFM .pend - + pop_float_to_indexed_var .proc ; -- pop the float on the stack, to the memory in the array at A/Y indexed by the byte on stack sta c64.SCRATCH_ZPWORD1 @@ -436,7 +435,7 @@ pop_float_to_indexed_var .proc .pend copy_float .proc - ; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_ZPWORD1, + ; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_ZPWORD1, ; into the 5 bytes pointed to by A/Y. Clobbers A,Y. sta c64.SCRATCH_ZPWORD2 sty c64.SCRATCH_ZPWORD2+1 @@ -473,7 +472,7 @@ inc_var_f .proc ldx c64.SCRATCH_ZPREGX rts .pend - + dec_var_f .proc ; -- subtract 1 from float pointed to by A/Y sta c64.SCRATCH_ZPWORD1 @@ -491,7 +490,7 @@ dec_var_f .proc ldx c64.SCRATCH_ZPREGX rts .pend - + inc_indexed_var_f .proc ; -- add 1 to float in array pointed to by A/Y, at index X pha @@ -509,7 +508,7 @@ inc_indexed_var_f .proc iny + jmp inc_var_f .pend - + dec_indexed_var_f .proc ; -- subtract 1 to float in array pointed to by A/Y, at index X pha @@ -527,7 +526,7 @@ dec_indexed_var_f .proc iny + jmp dec_var_f .pend - + pop_2_floats_f2_in_fac1 .proc ; -- pop 2 floats from stack, load the second one in FAC1 as well @@ -556,7 +555,7 @@ push_fac1_as_result .proc ldx c64.SCRATCH_ZPREGX jmp push_float .pend - + pow_f .proc ; -- push f1 ** f2 on stack lda #FL_LOG2 + lda #c64.FL_LOG2 jsr c64flt.MOVFM jsr c64flt.FDIVT jmp push_fac1_as_result .pend - + func_sqrt .proc jsr pop_float_fac1 stx c64.SCRATCH_ZPREGX jsr c64flt.SQR jmp push_fac1_as_result .pend - + func_rad .proc ; -- convert degrees to radians (d * pi / 180) jsr pop_float_fac1 @@ -800,7 +799,7 @@ func_rad .proc jmp push_fac1_as_result _pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180 .pend - + func_deg .proc ; -- convert radians to degrees (d * (1/ pi * 180)) jsr pop_float_fac1 @@ -811,7 +810,7 @@ func_deg .proc jmp push_fac1_as_result _one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180) .pend - + func_round .proc jsr pop_float_fac1 stx c64.SCRATCH_ZPREGX @@ -819,14 +818,14 @@ func_round .proc jsr c64flt.INT jmp push_fac1_as_result .pend - + func_floor .proc jsr pop_float_fac1 stx c64.SCRATCH_ZPREGX jsr c64flt.INT jmp push_fac1_as_result .pend - + func_ceil .proc ; -- ceil: tr = int(f); if tr==f -> return else return tr+1 jsr pop_float_fac1 @@ -854,7 +853,7 @@ func_any_f .proc asl a clc adc c64.SCRATCH_ZPB1 ; times 5 because of float - jmp prog8_lib.func_any_b._entry + jmp func_any_b._entry .pend func_all_f .proc @@ -866,7 +865,7 @@ func_all_f .proc clc adc c64.SCRATCH_ZPB1 ; times 5 because of float sta _cmp_mod+1 ; self-modifying code - jsr prog8_lib.peek_address + jsr peek_address ldy #0 - lda (c64.SCRATCH_ZPWORD1),y bne + @@ -894,18 +893,51 @@ _cmp_mod cpy #255 ; modified .pend func_max_f .proc - .warn "todo: fix func_max_f / func_min_f" ; TODO + lda #255 + sta _minmax_cmp+1 + lda #<_largest_neg_float + ldy #>_largest_neg_float +_minmax_entry jsr MOVFM + jsr prog8_lib.pop_array_and_lengthmin1Y + stx c64.SCRATCH_ZPREGX +- sty c64.SCRATCH_ZPREG + lda c64.SCRATCH_ZPWORD1 + ldy c64.SCRATCH_ZPWORD1+1 + jsr FCOMP +_minmax_cmp cmp #255 ; modified + bne + + lda c64.SCRATCH_ZPWORD1 + ldy c64.SCRATCH_ZPWORD1+1 + jsr MOVFM ++ lda c64.SCRATCH_ZPWORD1 + clc + adc #5 + sta c64.SCRATCH_ZPWORD1 + bcc + + inc c64.SCRATCH_ZPWORD1+1 ++ ldy c64.SCRATCH_ZPREG + dey + bne - + jmp push_fac1_as_result + rts +_largest_neg_float .byte 255,255,255,255,255 ; largest negative float -1.7014118345e+38 .pend func_min_f .proc - .warn "todo: fix func_max_f / func_min_f" ; TODO + lda #1 + sta func_max_f._minmax_cmp+1 + lda #<_largest_pos_float + ldy #>_largest_pos_float + jmp func_max_f._minmax_entry +_largest_pos_float .byte 255,127,255,255,255 ; largest positive float + rts .pend func_sum_f .proc - lda #FL_ZERO + lda #c64.FL_NEGHLF jsr c64flt.MOVFM - jsr prog8_lib.pop_array_and_lengthmin1Y + jsr pop_array_and_lengthmin1Y stx c64.SCRATCH_ZPREGX - sty c64.SCRATCH_ZPREG lda c64.SCRATCH_ZPWORD1 @@ -922,7 +954,8 @@ func_sum_f .proc bcc - inc c64.SCRATCH_ZPWORD1+1 bne - -+ jmp push_fac1_as_result ++ jsr c64flt.FADDH + jmp push_fac1_as_result .pend }} diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 2b5c708a9..7e1cb0654 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -494,7 +494,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Syscall.FUNC_ALL_F, Syscall.FUNC_MAX_F, Syscall.FUNC_MIN_F, - Syscall.FUNC_AVG_F, Syscall.FUNC_SUM_F -> " jsr c64flt.${call.name.toLowerCase()}" null -> "" else -> " jsr prog8_lib.${call.name.toLowerCase()}" diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index f4836da89..fb5947ae9 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -70,11 +70,6 @@ enum class Syscall(val callNr: Short) { FUNC_MIN_UW(122), FUNC_MIN_W(123), FUNC_MIN_F(124), - FUNC_AVG_UB(125), - FUNC_AVG_B(126), - FUNC_AVG_UW(127), - FUNC_AVG_W(128), - FUNC_AVG_F(129), FUNC_SUM_UB(130), FUNC_SUM_B(131), FUNC_SUM_UW(132), @@ -1052,24 +1047,48 @@ class StackVm(private var traceOutputFile: String?) { } Opcode.POP_REGAX_WORD -> { val value=evalstack.pop().integerValue() - val valueA=Value(DataType.UBYTE, value and 255) - val valueX=Value(DataType.UBYTE, value shr 8) + val valueA: Value + val valueX: Value + if(value>=0) { + valueA = Value(DataType.UBYTE, value and 255) + valueX = Value(DataType.UBYTE, value shr 8) + } else { + val value2c = 65536+value + valueA = Value(DataType.UBYTE, value2c and 255) + valueX = Value(DataType.UBYTE, value2c shr 8) + } variables["A"] = valueA variables["X"] = valueX setFlags(valueA.bitor(valueX)) } Opcode.POP_REGAY_WORD -> { val value=evalstack.pop().integerValue() - val valueA=Value(DataType.UBYTE, value and 255) - val valueY=Value(DataType.UBYTE, value shr 8) + val valueA: Value + val valueY: Value + if(value>=0) { + valueA = Value(DataType.UBYTE, value and 255) + valueY = Value(DataType.UBYTE, value shr 8) + } else { + val value2c = 65536+value + valueA = Value(DataType.UBYTE, value2c and 255) + valueY = Value(DataType.UBYTE, value2c shr 8) + } variables["A"] = valueA variables["Y"] = valueY setFlags(valueA.bitor(valueY)) } Opcode.POP_REGXY_WORD -> { val value=evalstack.pop().integerValue() - val valueX=Value(DataType.UBYTE, value and 255) - val valueY=Value(DataType.UBYTE, value shr 8) + val valueX: Value + val valueY: Value + if(value>=0) { + valueX = Value(DataType.UBYTE, value and 255) + valueY = Value(DataType.UBYTE, value shr 8) + } else { + val value2c = 65536+value + valueX = Value(DataType.UBYTE, value2c and 255) + valueY = Value(DataType.UBYTE, value2c shr 8) + } variables["X"] = valueX variables["Y"] = valueY setFlags(valueX.bitor(valueY)) @@ -1079,8 +1098,11 @@ class StackVm(private var traceOutputFile: String?) { checkDt(value, DataType.UBYTE, DataType.BYTE) val variable = getVar(ins.callLabel!!) checkDt(variable, DataType.UBYTE, DataType.BYTE) - if(value.type!=variable.type) - throw VmExecutionException("datatype mismatch") + if(value.type!=variable.type) { + if(ins.callLabel !in Register.values().map { it.name }) { + throw VmExecutionException("datatype mismatch") + } + } variables[ins.callLabel] = value setFlags(value) } @@ -2056,128 +2078,140 @@ class StackVm(private var traceOutputFile: String?) { else throw VmExecutionException("cannot get ceil of $value") } Syscall.FUNC_MAX_UB -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.max() ?: 0 - evalstack.push(Value(DataType.UBYTE, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UBYTE, value.array.max() ?: 0)) } Syscall.FUNC_MAX_B -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.max() ?: 0 - evalstack.push(Value(DataType.BYTE, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.BYTE, value.array.max() ?: 0)) } Syscall.FUNC_MAX_UW -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.max() ?: 0 - evalstack.push(Value(DataType.UWORD, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UWORD, value.array.max() ?: 0)) } Syscall.FUNC_MAX_W -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.max() ?: 0 - evalstack.push(Value(DataType.WORD, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.WORD, value.array.max() ?: 0)) } Syscall.FUNC_MAX_F -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - val result = value.doubleArray!!.max() ?: 0.0 - evalstack.push(Value(DataType.FLOAT, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.doubleArray!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.FLOAT, value.doubleArray.max() ?: 0.0)) } Syscall.FUNC_MIN_UB -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.min() ?: 0 - evalstack.push(Value(DataType.UBYTE, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UBYTE, value.array.min() ?: 0)) } Syscall.FUNC_MIN_B -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.min() ?: 0 - evalstack.push(Value(DataType.BYTE, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.BYTE, value.array.min() ?: 0)) } Syscall.FUNC_MIN_UW -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.min() ?: 0 - evalstack.push(Value(DataType.UWORD, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UWORD, value.array.min() ?: 0)) } Syscall.FUNC_MIN_W -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - val result = value.array.map{it.integer!!}.min() ?: 0 - evalstack.push(Value(DataType.WORD, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.WORD, value.array.min() ?: 0)) } Syscall.FUNC_MIN_F -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - val result = value.doubleArray!!.min() ?: 0.0 - evalstack.push(Value(DataType.FLOAT, result)) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.doubleArray!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.FLOAT, value.doubleArray.min() ?: 0.0)) } - Syscall.FUNC_AVG_UB, Syscall.FUNC_AVG_B, Syscall.FUNC_AVG_UW, Syscall.FUNC_AVG_W -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - evalstack.push(Value(DataType.FLOAT, value.array.map{it.integer!!}.average())) + Syscall.FUNC_SUM_W, Syscall.FUNC_SUM_B -> { + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.WORD, value.array.sum())) } - Syscall.FUNC_AVG_F -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - evalstack.push(Value(DataType.FLOAT, value.doubleArray!!.average())) - } - Syscall.FUNC_SUM_UB -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - evalstack.push(Value(DataType.UWORD, value.array.map{it.integer!!}.sum())) - } - Syscall.FUNC_SUM_B -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - evalstack.push(Value(DataType.WORD, value.array.map{it.integer!!}.sum())) - } - Syscall.FUNC_SUM_UW, Syscall.FUNC_SUM_W -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - if(value.array!!.any{it.integer==null}) - throw VmExecutionException("cannot deal with PointerTo value in array $value") - evalstack.push(Value(DataType.FLOAT, value.array.map{it.integer!!}.sum())) + Syscall.FUNC_SUM_UW, Syscall.FUNC_SUM_UB -> { + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UWORD, value.array.sum())) } Syscall.FUNC_SUM_F -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - evalstack.push(Value(DataType.FLOAT, value.doubleArray!!.sum())) + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.doubleArray!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.FLOAT, value.doubleArray.sum())) } - Syscall.FUNC_ANY_B, Syscall.FUNC_ANY_W, Syscall.FUNC_ANY_F -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - evalstack.push(Value(DataType.UBYTE, if (value.array!!.any { v -> v.pointerOf!=null || (v.integer!=null && v.integer != 0) }) 1 else 0)) + Syscall.FUNC_ANY_B, Syscall.FUNC_ANY_W -> { + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UBYTE, if (value.array.any { v -> v != 0 }) 1 else 0)) } - Syscall.FUNC_ALL_B, Syscall.FUNC_ALL_W, Syscall.FUNC_ALL_F -> { - val iterable = evalstack.pop() - val value = heap.get(iterable.heapId) - evalstack.push(Value(DataType.UBYTE, if (value.array!!.all { v -> v.pointerOf!=null || (v.integer!=null && v.integer != 0) }) 1 else 0)) + Syscall.FUNC_ANY_F -> { + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.doubleArray!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UBYTE, if (value.doubleArray.any { v -> v.pointerOf!=null || (v.integer!=null && v.integer != 0.0) }) 1 else 0)) + } + Syscall.FUNC_ALL_B, Syscall.FUNC_ALL_W -> { + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.array!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UBYTE, if (value.array.all { v -> v != 0 }) 1 else 0)) + } + Syscall.FUNC_ALL_F -> { + val length = evalstack.pop().integerValue() + val heapVarId = evalstack.pop().integerValue() + val value = heap.get(heapVarId) + if(length!=value.doubleArray!!.size) + throw VmExecutionException("iterable length mismatch") + evalstack.push(Value(DataType.UBYTE, if (value.doubleArray.all { v -> v.pointerOf!=null || (v.integer!=null && v.integer != 0.0) }) 1 else 0)) } Syscall.FUNC_MEMCOPY -> { val numbytes = evalstack.pop().integerValue() @@ -2226,12 +2260,28 @@ class StackVm(private var traceOutputFile: String?) { val num = variables.getValue("A").integerValue() canvas?.printText(num.toString(), 1, true) } + Syscall.SYSASM_c64scr_print_b -> { + val num = variables.getValue("A").integerValue() + if(num<=127) + canvas?.printText(num.toString(), 1, true) + else + canvas?.printText("-${256-num}", 1, true) + } Syscall.SYSASM_c64scr_print_uw -> { val lo = variables.getValue("A").integerValue() val hi = variables.getValue("Y").integerValue() val number = lo+256*hi canvas?.printText(number.toString(), 1, true) } + Syscall.SYSASM_c64scr_print_w -> { + val lo = variables.getValue("A").integerValue() + val hi = variables.getValue("Y").integerValue() + val number = lo+256*hi + if(number<=32767) + canvas?.printText(number.toString(), 1, true) + else + canvas?.printText("-${65536-number}", 1, true) + } Syscall.SYSASM_c64flt_print_f -> { val number = variables.getValue("c64flt.print_f.value").numericValue() canvas?.printText(number.toString(), 1, true)