From d837cc11f982b7f898a07c9c1f7e43c8100c48a6 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 17 Aug 2019 23:32:26 +0200 Subject: [PATCH] sort() added (bytes+words) --- .../src/compiler/target/c64/codegen/AsmGen.kt | 2 +- compiler/res/prog8lib/prog8lib.asm | 187 ++++++++++++++++++ .../src/prog8/ast/processing/AstChecker.kt | 5 +- .../compiler/target/c64/codegen/AsmGen.kt | 2 +- .../c64/codegen/BuiltinFunctionsAsmGen.kt | 38 ++++ .../src/prog8/functions/BuiltinFunctions.kt | 11 +- examples/cube3d-sprites.p8 | 21 +- examples/test.p8 | 34 +++- 8 files changed, 279 insertions(+), 21 deletions(-) diff --git a/DeprecatedStackVm/src/compiler/target/c64/codegen/AsmGen.kt b/DeprecatedStackVm/src/compiler/target/c64/codegen/AsmGen.kt index 57b28e182..96b472263 100644 --- a/DeprecatedStackVm/src/compiler/target/c64/codegen/AsmGen.kt +++ b/DeprecatedStackVm/src/compiler/target/c64/codegen/AsmGen.kt @@ -232,7 +232,7 @@ class AsmGen(private val options: CompilationOptions, private val program: Inter private fun block2asm(blk: IntermediateProgram.ProgramBlock) { block = blk - out("\n; ---- block: '${block.name}' ----") + out("\n\n; ---- block: '${block.name}' ----") if(!blk.force_output) out("${block.name}\t.proc\n") if(block.address!=null) { diff --git a/compiler/res/prog8lib/prog8lib.asm b/compiler/res/prog8lib/prog8lib.asm index f506f18b8..d7016acce 100644 --- a/compiler/res/prog8lib/prog8lib.asm +++ b/compiler/res/prog8lib/prog8lib.asm @@ -1384,3 +1384,190 @@ _mod2b lda #0 ; self-modified _done rts .pend + +sort_ub .proc + ; 8bit unsigned sort + ; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int) + ; input: address of array to sort in c64.SCRATCH_ZPWORD1, length in c64.SCRATCH_ZPB1 + ; first, put pointer BEFORE array + lda c64.SCRATCH_ZPWORD1 + bne + + dec c64.SCRATCH_ZPWORD1+1 ++ dec c64.SCRATCH_ZPWORD1 +_sortloop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort + lda (c64.SCRATCH_ZPWORD1),y ;last value in (what is left of) sequence to be sorted + sta c64.SCRATCH_ZPREG ;save value. will be over-written by largest number + jmp _l2 +_l1 dey + beq _l3 + lda (c64.SCRATCH_ZPWORD1),y + cmp c64.SCRATCH_ZPWORD2+1 + bcc _l1 +_l2 sty c64.SCRATCH_ZPWORD2 ;index of potentially largest value + sta c64.SCRATCH_ZPWORD2+1 ;potentially largest value + jmp _l1 +_l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put + lda c64.SCRATCH_ZPWORD2+1 ;the largest value + sta (c64.SCRATCH_ZPWORD1),y ;put largest value in place + ldy c64.SCRATCH_ZPWORD2 ;index of free space + lda c64.SCRATCH_ZPREG ;the over-written value + sta (c64.SCRATCH_ZPWORD1),y ;put the over-written value in the free space + dec c64.SCRATCH_ZPB1 ;end of the shorter sequence still left + bne _sortloop ;start working with the shorter sequence + rts + .pend + + +sort_b .proc + ; 8bit signed sort + ; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int) + ; input: address of array to sort in c64.SCRATCH_ZPWORD1, length in c64.SCRATCH_ZPB1 + ; first, put pointer BEFORE array + lda c64.SCRATCH_ZPWORD1 + bne + + dec c64.SCRATCH_ZPWORD1+1 ++ dec c64.SCRATCH_ZPWORD1 +_sortloop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort + lda (c64.SCRATCH_ZPWORD1),y ;last value in (what is left of) sequence to be sorted + sta c64.SCRATCH_ZPREG ;save value. will be over-written by largest number + jmp _l2 +_l1 dey + beq _l3 + lda (c64.SCRATCH_ZPWORD1),y + cmp c64.SCRATCH_ZPWORD2+1 + bmi _l1 +_l2 sty c64.SCRATCH_ZPWORD2 ;index of potentially largest value + sta c64.SCRATCH_ZPWORD2+1 ;potentially largest value + jmp _l1 +_l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put + lda c64.SCRATCH_ZPWORD2+1 ;the largest value + sta (c64.SCRATCH_ZPWORD1),y ;put largest value in place + ldy c64.SCRATCH_ZPWORD2 ;index of free space + lda c64.SCRATCH_ZPREG ;the over-written value + sta (c64.SCRATCH_ZPWORD1),y ;put the over-written value in the free space + dec c64.SCRATCH_ZPB1 ;end of the shorter sequence still left + bne _sortloop ;start working with the shorter sequence + rts + .pend + + +sort_uw .proc + ; 16bit unsigned sort + ; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int) + ; input: address of array to sort in c64.SCRATCH_ZPWORD1, length in c64.SCRATCH_ZPB1 + ; first: subtract 2 of the pointer + asl c64.SCRATCH_ZPB1 ; *2 because words + lda c64.SCRATCH_ZPWORD1 + sec + sbc #2 + sta c64.SCRATCH_ZPWORD1 + bcs _sort_loop + dec c64.SCRATCH_ZPWORD1+1 +_sort_loop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort + lda (c64.SCRATCH_ZPWORD1),y ;last value in (what is left of) sequence to be sorted + sta _work3 ;save value. will be over-written by largest number + iny + lda (c64.SCRATCH_ZPWORD1),y + sta _work3+1 + dey + jmp _l2 +_l1 dey + dey + beq _l3 + iny + lda (c64.SCRATCH_ZPWORD1),y + dey + cmp c64.SCRATCH_ZPWORD2+1 + bne + + lda (c64.SCRATCH_ZPWORD1),y + cmp c64.SCRATCH_ZPWORD2 ++ bcc _l1 +_l2 sty _work1 ;index of potentially largest value + lda (c64.SCRATCH_ZPWORD1),y + sta c64.SCRATCH_ZPWORD2 ;potentially largest value + iny + lda (c64.SCRATCH_ZPWORD1),y + sta c64.SCRATCH_ZPWORD2+1 + dey + jmp _l1 +_l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put + lda c64.SCRATCH_ZPWORD2 ;the largest value + sta (c64.SCRATCH_ZPWORD1),y ;put largest value in place + iny + lda c64.SCRATCH_ZPWORD2+1 + sta (c64.SCRATCH_ZPWORD1),y + ldy _work1 ;index of free space + lda _work3 ;the over-written value + sta (c64.SCRATCH_ZPWORD1),y ;put the over-written value in the free space + iny + lda _work3+1 + sta (c64.SCRATCH_ZPWORD1),y + dey + dec c64.SCRATCH_ZPB1 ;end of the shorter sequence still left + dec c64.SCRATCH_ZPB1 + bne _sort_loop ;start working with the shorter sequence + rts +_work1 .byte 0 +_work3 .word 0 + .pend + + +sort_w .proc + ; 16bit signed sort + ; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int) + ; input: address of array to sort in c64.SCRATCH_ZPWORD1, length in c64.SCRATCH_ZPB1 + ; first: subtract 2 of the pointer + asl c64.SCRATCH_ZPB1 ; *2 because words + lda c64.SCRATCH_ZPWORD1 + sec + sbc #2 + sta c64.SCRATCH_ZPWORD1 + bcs _sort_loop + dec c64.SCRATCH_ZPWORD1+1 +_sort_loop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort + lda (c64.SCRATCH_ZPWORD1),y ;last value in (what is left of) sequence to be sorted + sta _work3 ;save value. will be over-written by largest number + iny + lda (c64.SCRATCH_ZPWORD1),y + sta _work3+1 + dey + jmp _l2 +_l1 dey + dey + beq _l3 + iny + lda (c64.SCRATCH_ZPWORD1),y + dey + cmp c64.SCRATCH_ZPWORD2+1 + bne + + lda (c64.SCRATCH_ZPWORD1),y + cmp c64.SCRATCH_ZPWORD2 ++ bmi _l1 +_l2 sty _work1 ;index of potentially largest value + lda (c64.SCRATCH_ZPWORD1),y + sta c64.SCRATCH_ZPWORD2 ;potentially largest value + iny + lda (c64.SCRATCH_ZPWORD1),y + sta c64.SCRATCH_ZPWORD2+1 + dey + jmp _l1 +_l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put + lda c64.SCRATCH_ZPWORD2 ;the largest value + sta (c64.SCRATCH_ZPWORD1),y ;put largest value in place + iny + lda c64.SCRATCH_ZPWORD2+1 + sta (c64.SCRATCH_ZPWORD1),y + ldy _work1 ;index of free space + lda _work3 ;the over-written value + sta (c64.SCRATCH_ZPWORD1),y ;put the over-written value in the free space + iny + lda _work3+1 + sta (c64.SCRATCH_ZPWORD1),y + dey + dec c64.SCRATCH_ZPB1 ;end of the shorter sequence still left + dec c64.SCRATCH_ZPB1 + bne _sort_loop ;start working with the shorter sequence + rts +_work1 .byte 0 +_work3 .word 0 + .pend diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 18343c5b7..8fd01b731 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -1,5 +1,6 @@ package prog8.ast.processing +import prog8.ast.IFunctionCall import prog8.ast.INameScope import prog8.ast.Module import prog8.ast.Program @@ -694,7 +695,7 @@ internal class AstChecker(private val program: Program, super.visit(array) - if(array.heapId==null && array.parent !is FunctionCall) + if(array.heapId==null && array.parent !is IFunctionCall) throw FatalAstException("array should have been moved to heap at ${array.position}") } @@ -831,7 +832,7 @@ internal class AstChecker(private val program: Program, printWarning("result values of subroutine call are discarded", functionCallStatement.position) } - if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap")) { + if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap", "sort")) { // in-place modification, can't be done on literals if(functionCallStatement.arglist.any { it !is IdentifierReference && it !is RegisterExpr && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) { checkResult.add(ExpressionError("can't use that as argument to a in-place modifying function", functionCallStatement.position)) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 9cb34c7d5..a7649cbe7 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -149,7 +149,7 @@ internal class AsmGen(val program: Program, } private fun block2asm(block: Block) { - out("\n; ---- block: '${block.name}' ----") + out("\n\n; ---- block: '${block.name}' ----") out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n")) if(block.address!=null) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index 69c46361a..2ce4ae7a7 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -9,6 +9,8 @@ import prog8.ast.base.WordDatatypes import prog8.ast.expressions.* import prog8.ast.statements.AssignTarget import prog8.ast.statements.FunctionCallStatement +import prog8.compiler.target.c64.MachineDefinition +import prog8.compiler.target.c64.MachineDefinition.C64Zeropage import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX @@ -298,6 +300,42 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val else -> throw AssemblyError("weird type") } } + "sort" -> { + val variable = fcall.arglist.single() + if(variable is IdentifierReference) { + val decl = variable.targetVarDecl(program.namespace)!! + val varName = asmgen.asmIdentifierName(variable) + val numElements = decl.arraysize!!.size() + when(decl.datatype) { + DataType.ARRAY_UB, DataType.ARRAY_B -> { + asmgen.out(""" + lda #<$varName + ldy #>$varName + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #$numElements + sta ${C64Zeropage.SCRATCH_B1} + """) + asmgen.out(if(decl.datatype==DataType.ARRAY_UB) " jsr prog8_lib.sort_ub" else " jsr prog8_lib.sort_b") + } + DataType.ARRAY_UW, DataType.ARRAY_W -> { + asmgen.out(""" + lda #<$varName + ldy #>$varName + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1+1} + lda #$numElements + sta ${C64Zeropage.SCRATCH_B1} + """) + asmgen.out(if(decl.datatype==DataType.ARRAY_UW) " jsr prog8_lib.sort_uw" else " jsr prog8_lib.sort_w") + } + DataType.ARRAY_F -> TODO("sort floats (consider another solution if possible - this will be very slow, if ever implemented)") + else -> throw AssemblyError("weird type") + } + } + else + throw AssemblyError("weird type") + } else -> { translateFunctionArguments(fcall.arglist, func) asmgen.out(" jsr prog8_lib.func_$functionName") diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 0d68cbf1a..a5bda744d 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -27,6 +27,7 @@ val BuiltinFunctions = mapOf( "ror2" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), "lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), "lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), + "sort" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null), // these few have a return value depending on the argument(s): "max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args @@ -75,18 +76,20 @@ val BuiltinFunctions = mapOf( "read_flags" to FunctionSignature(false, emptyList(), DataType.UBYTE), "swap" to FunctionSignature(false, listOf(BuiltinFunctionParam("first", NumericDatatypes), BuiltinFunctionParam("second", NumericDatatypes)), null), "memcopy" to FunctionSignature(false, listOf( - BuiltinFunctionParam("from", IterableDatatypes + setOf(DataType.UWORD)), - BuiltinFunctionParam("to", IterableDatatypes + setOf(DataType.UWORD)), + BuiltinFunctionParam("from", IterableDatatypes + DataType.UWORD), + BuiltinFunctionParam("to", IterableDatatypes + DataType.UWORD), BuiltinFunctionParam("numbytes", setOf(DataType.UBYTE))), null), "memset" to FunctionSignature(false, listOf( - BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)), + BuiltinFunctionParam("address", IterableDatatypes + DataType.UWORD), BuiltinFunctionParam("numbytes", setOf(DataType.UWORD)), BuiltinFunctionParam("bytevalue", ByteDatatypes)), null), "memsetw" to FunctionSignature(false, listOf( - BuiltinFunctionParam("address", IterableDatatypes + setOf(DataType.UWORD)), + BuiltinFunctionParam("address", IterableDatatypes + DataType.UWORD), BuiltinFunctionParam("numwords", setOf(DataType.UWORD)), BuiltinFunctionParam("wordvalue", setOf(DataType.UWORD, DataType.WORD))), null), "strlen" to FunctionSignature(true, listOf(BuiltinFunctionParam("string", StringDatatypes)), DataType.UBYTE, ::builtinStrlen), + + // TODO clean up these vm-specific functions "vm_write_memchr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null), "vm_write_memstr" to FunctionSignature(false, listOf(BuiltinFunctionParam("address", setOf(DataType.UWORD))), null), "vm_write_num" to FunctionSignature(false, listOf(BuiltinFunctionParam("number", NumericDatatypes)), null), diff --git a/examples/cube3d-sprites.p8 b/examples/cube3d-sprites.p8 index 60c6c6366..7e16e82d1 100644 --- a/examples/cube3d-sprites.p8 +++ b/examples/cube3d-sprites.p8 @@ -136,16 +136,17 @@ main { ; first sort vertices to sprite order so the back/front order is correct as well ; (simple bubble sort as it's only 8 items to sort) ; TODO make a builtin function sort() - for ubyte sorti in 6 to 0 step -1 { - for ubyte i1 in 0 to sorti { - ubyte i2 = i1+1 - if(rotatedz[i1] > rotatedz[i2]) { - swap(rotatedx[i1], rotatedx[i2]) - swap(rotatedy[i1], rotatedy[i2]) - swap(rotatedz[i1], rotatedz[i2]) - } - } - } + sort(rotatedz) +; for ubyte sorti in 6 to 0 step -1 { +; for ubyte i1 in 0 to sorti { +; ubyte i2 = i1+1 +; if(rotatedz[i1] > rotatedz[i2]) { +; swap(rotatedx[i1], rotatedx[i2]) +; swap(rotatedy[i1], rotatedy[i2]) +; swap(rotatedz[i1], rotatedz[i2]) +; } +; } +; } ubyte[] spritecolors = [1,1,7,15,12,11,9,9] diff --git a/examples/test.p8 b/examples/test.p8 index 177b5cdf2..8dc83daec 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,7 +7,6 @@ main { sub start() { - ubyte[] uba = [10,0,2,8,5,4,3,9] uword[] uwa = [1000,0,200,8000,50,40000,3,900] byte[] ba = [-10,0,-2,8,5,4,-3,9] @@ -37,12 +36,41 @@ main { c64.CHROUT(',') } c64.CHROUT('\n') + c64.CHROUT('\n') - for ubyte i in 0 to len(fla)-1 { - c64flt.print_f(fla[i]) + sort(uba) + sort(uwa) + sort(ba) + sort(wa) + + for ubyte ub2 in uba { + c64scr.print_ub(ub2) c64.CHROUT(',') } c64.CHROUT('\n') + for uword uw2 in uwa { + c64scr.print_uw(uw2) + c64.CHROUT(',') + } + c64.CHROUT('\n') + + for byte bb2 in ba { + c64scr.print_b(bb2) + c64.CHROUT(',') + } + c64.CHROUT('\n') + + for word ww2 in wa { + c64scr.print_w(ww2) + c64.CHROUT(',') + } + c64.CHROUT('\n') + + ubyte qq=X + c64scr.print_ub(qq) + + ; TODO 2 for loops that both define the same loopvar -> double definition -> fix second for -> 'unknown symbol' ???? + } }