reverse() added (byte+word)

This commit is contained in:
Irmen de Jong 2019-08-18 01:39:48 +02:00
parent d837cc11f9
commit 1cc1f2d91d
10 changed files with 268 additions and 41 deletions

View File

@ -26,7 +26,7 @@ which aims to provide many conveniences over raw assembly code (even when using
- abstracting away low level aspects such as ZeroPage handling, program startup, explicit memory addresses - abstracting away low level aspects such as ZeroPage handling, program startup, explicit memory addresses
- various code optimizations (code structure, logical and numerical expressions, unused code removal...) - various code optimizations (code structure, logical and numerical expressions, unused code removal...)
- inline assembly allows you to have full control when every cycle or byte matters - inline assembly allows you to have full control when every cycle or byte matters
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy`` - many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``, ``sort`` and ``reverse``
Rapid edit-compile-run-debug cycle: Rapid edit-compile-run-debug cycle:

View File

@ -1535,13 +1535,14 @@ _sort_loop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort
_l1 dey _l1 dey
dey dey
beq _l3 beq _l3
lda (c64.SCRATCH_ZPWORD1),y
cmp c64.SCRATCH_ZPWORD2
iny iny
lda (c64.SCRATCH_ZPWORD1),y lda (c64.SCRATCH_ZPWORD1),y
dey dey
cmp c64.SCRATCH_ZPWORD2+1 sbc c64.SCRATCH_ZPWORD2+1
bne + bvc +
lda (c64.SCRATCH_ZPWORD1),y eor #$80
cmp c64.SCRATCH_ZPWORD2
+ bmi _l1 + bmi _l1
_l2 sty _work1 ;index of potentially largest value _l2 sty _work1 ;index of potentially largest value
lda (c64.SCRATCH_ZPWORD1),y lda (c64.SCRATCH_ZPWORD1),y
@ -1571,3 +1572,102 @@ _l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put
_work1 .byte 0 _work1 .byte 0
_work3 .word 0 _work3 .word 0
.pend .pend
reverse_b .proc
; --- reverse an array of bytes (in-place)
; inputs: pointer to array in c64.SCRATCH_ZPWORD1, length in A
_left_index = c64.SCRATCH_ZPWORD2
_right_index = c64.SCRATCH_ZPWORD2+1
pha
sec
sbc #1
sta _left_index
lda #0
sta _right_index
pla
lsr a
tay
_loop sty c64.SCRATCH_ZPREG
ldy _left_index
lda (c64.SCRATCH_ZPWORD1),y
pha
ldy _right_index
lda (c64.SCRATCH_ZPWORD1),y
ldy _left_index
sta (c64.SCRATCH_ZPWORD1),y
pla
ldy _right_index
sta (c64.SCRATCH_ZPWORD1),y
inc _right_index
dec _left_index
ldy c64.SCRATCH_ZPREG
dey
bne _loop
rts
.pend
reverse_w .proc
; --- reverse an array of words (in-place)
; inputs: pointer to array in c64.SCRATCH_ZPWORD1, length in A
_left_index = c64.SCRATCH_ZPWORD2
_right_index = c64.SCRATCH_ZPWORD2+1
pha
asl a ; *2 because words
sec
sbc #2
sta _left_index
lda #0
sta _right_index
pla
lsr a
pha
tay
; first reverse the lsbs
_loop_lo sty c64.SCRATCH_ZPREG
ldy _left_index
lda (c64.SCRATCH_ZPWORD1),y
pha
ldy _right_index
lda (c64.SCRATCH_ZPWORD1),y
ldy _left_index
sta (c64.SCRATCH_ZPWORD1),y
pla
ldy _right_index
sta (c64.SCRATCH_ZPWORD1),y
inc _right_index
inc _right_index
dec _left_index
dec _left_index
ldy c64.SCRATCH_ZPREG
dey
bne _loop_lo
; now reverse the msbs
dec _right_index
inc _left_index
inc _left_index
inc _left_index
pla
tay
_loop_hi sty c64.SCRATCH_ZPREG
ldy _left_index
lda (c64.SCRATCH_ZPWORD1),y
pha
ldy _right_index
lda (c64.SCRATCH_ZPWORD1),y
ldy _left_index
sta (c64.SCRATCH_ZPWORD1),y
pla
ldy _right_index
sta (c64.SCRATCH_ZPWORD1),y
dec _right_index
dec _right_index
inc _left_index
inc _left_index
ldy c64.SCRATCH_ZPREG
dey
bne _loop_hi
rts
.pend

View File

@ -832,7 +832,7 @@ internal class AstChecker(private val program: Program,
printWarning("result values of subroutine call are discarded", functionCallStatement.position) printWarning("result values of subroutine call are discarded", functionCallStatement.position)
} }
if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap", "sort")) { if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap", "sort", "reverse")) {
// in-place modification, can't be done on literals // 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 }) { 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)) checkResult.add(ExpressionError("can't use that as argument to a in-place modifying function", functionCallStatement.position))

View File

@ -336,6 +336,38 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
else else
throw AssemblyError("weird type") throw AssemblyError("weird type")
} }
"reverse" -> {
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
jsr prog8_lib.reverse_b
""")
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta ${C64Zeropage.SCRATCH_W1}
sty ${C64Zeropage.SCRATCH_W1 + 1}
lda #$numElements
jsr prog8_lib.reverse_w
""")
}
DataType.ARRAY_F -> TODO("reverse floats (consider another solution if possible - this will be quite slow, if ever implemented)")
else -> throw AssemblyError("weird type")
}
}
}
else -> { else -> {
translateFunctionArguments(fcall.arglist, func) translateFunctionArguments(fcall.arglist, func)
asmgen.out(" jsr prog8_lib.func_$functionName") asmgen.out(" jsr prog8_lib.func_$functionName")

View File

@ -28,6 +28,7 @@ val BuiltinFunctions = mapOf(
"lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null), "lsl" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), null),
"lsr" 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), "sort" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null),
"reverse" to FunctionSignature(false, listOf(BuiltinFunctionParam("array", ArrayDatatypes)), null),
// these few have a return value depending on the argument(s): // 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 "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 "min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", ArrayDatatypes)), null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args

View File

@ -158,7 +158,7 @@ Design principles and features
- The compiler tries to optimize the program and generated code, but hand-tuning of the - The compiler tries to optimize the program and generated code, but hand-tuning of the
performance or space-critical parts will likely still be required. This is supported by performance or space-critical parts will likely still be required. This is supported by
the ability to easily write embedded assembly code directly in the program source code. the ability to easily write embedded assembly code directly in the program source code.
- There are many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy`` - There are many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``memset``, ``memcopy``, ``sort`` and ``reverse``
.. _requirements: .. _requirements:

View File

@ -710,6 +710,12 @@ min(x)
sum(x) sum(x)
Sum of the values in the array value x Sum of the values in the array value x
sort(array)
Sort the array in ascending order (in-place)
reverse(array)
Reverse the values in the array (in-place). Can be used after sort() to sort an array in descending order.
len(x) len(x)
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte). Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte).
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte. Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte.

View File

@ -135,18 +135,16 @@ main {
; first sort vertices to sprite order so the back/front order is correct as well ; 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) ; (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 {
sort(rotatedz) for ubyte i1 in 0 to sorti {
; for ubyte sorti in 6 to 0 step -1 { ubyte i2 = i1+1
; for ubyte i1 in 0 to sorti { if(rotatedz[i1] > rotatedz[i2]) {
; ubyte i2 = i1+1 swap(rotatedx[i1], rotatedx[i2])
; if(rotatedz[i1] > rotatedz[i2]) { swap(rotatedy[i1], rotatedy[i2])
; swap(rotatedx[i1], rotatedx[i2]) swap(rotatedz[i1], rotatedz[i2])
; swap(rotatedy[i1], rotatedy[i2]) }
; swap(rotatedz[i1], rotatedz[i2]) }
; } }
; }
; }
ubyte[] spritecolors = [1,1,7,15,12,11,9,9] ubyte[] spritecolors = [1,1,7,15,12,11,9,9]

62
examples/sorting.p8 Normal file
View File

@ -0,0 +1,62 @@
%import c64lib
%import c64utils
%zeropage basicsafe
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,-99]
word[] wa = [-1000,0,-200,8000,50,31111,3,-900]
c64scr.print("original\n")
print_arrays()
sort(uba)
sort(uwa)
sort(ba)
sort(wa)
c64scr.print("sorted\n")
print_arrays()
reverse(uba)
reverse(uwa)
reverse(ba)
reverse(wa)
c64scr.print("reversed\n")
print_arrays()
return
sub print_arrays() {
for ubyte ub in uba {
c64scr.print_ub(ub)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for uword uw in uwa {
c64scr.print_uw(uw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for byte bb in ba {
c64scr.print_b(bb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for word ww in wa {
c64scr.print_w(ww)
c64.CHROUT(',')
}
c64.CHROUT('\n')
c64.CHROUT('\n')
}
}
}

View File

@ -1,7 +1,6 @@
%import c64lib %import c64lib
%import c64utils %import c64utils
%import c64flt %zeropage basicsafe
%zeropage dontuse
main { main {
@ -9,9 +8,8 @@ main {
ubyte[] uba = [10,0,2,8,5,4,3,9] ubyte[] uba = [10,0,2,8,5,4,3,9]
uword[] uwa = [1000,0,200,8000,50,40000,3,900] uword[] uwa = [1000,0,200,8000,50,40000,3,900]
byte[] ba = [-10,0,-2,8,5,4,-3,9] byte[] ba = [-10,0,-2,8,5,4,-3,9,-99]
word[] wa = [-1000,0,-200,8000,50,31111,3,-900] word[] wa = [-1000,0,-200,8000,50,31111,3,-900]
float[] fla = [-2.2, 1.1, 3.3, 0.0]
for ubyte ub in uba { for ubyte ub in uba {
c64scr.print_ub(ub) c64scr.print_ub(ub)
@ -66,11 +64,41 @@ main {
c64.CHROUT(',') c64.CHROUT(',')
} }
c64.CHROUT('\n') c64.CHROUT('\n')
c64.CHROUT('\n')
reverse(uba)
reverse(uwa)
reverse(ba)
reverse(wa)
for ubyte ub3 in uba {
c64scr.print_ub(ub3)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for uword uw3 in uwa {
c64scr.print_uw(uw3)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for byte bb3 in ba {
c64scr.print_b(bb3)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for word ww3 in wa {
c64scr.print_w(ww3)
c64.CHROUT(',')
}
c64.CHROUT('\n')
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' ???? ; TODO 2 for loops that both define the same loopvar -> double definition -> fix second for -> 'unknown symbol' ????
; TODO code runs into a subroutine that follows it instead of inserting an implicit return
} }
} }