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
- 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
- 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:

View File

@ -1535,13 +1535,14 @@ _sort_loop ldy c64.SCRATCH_ZPB1 ;start of subroutine sort
_l1 dey
dey
beq _l3
lda (c64.SCRATCH_ZPWORD1),y
cmp c64.SCRATCH_ZPWORD2
iny
lda (c64.SCRATCH_ZPWORD1),y
dey
cmp c64.SCRATCH_ZPWORD2+1
bne +
lda (c64.SCRATCH_ZPWORD1),y
cmp c64.SCRATCH_ZPWORD2
sbc c64.SCRATCH_ZPWORD2+1
bvc +
eor #$80
+ bmi _l1
_l2 sty _work1 ;index of potentially largest value
lda (c64.SCRATCH_ZPWORD1),y
@ -1571,3 +1572,102 @@ _l3 ldy c64.SCRATCH_ZPB1 ;where the largest value shall be put
_work1 .byte 0
_work3 .word 0
.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)
}
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
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))

View File

@ -336,6 +336,38 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
else
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 -> {
translateFunctionArguments(fcall.arglist, func)
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),
"lsr" to FunctionSignature(false, listOf(BuiltinFunctionParam("item", IntegerDatatypes)), 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):
"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

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
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.
- 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:

View File

@ -710,6 +710,12 @@ min(x)
sum(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)
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.

View File

@ -135,18 +135,16 @@ 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()
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])
; }
; }
; }
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]

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 c64utils
%import c64flt
%zeropage dontuse
%zeropage basicsafe
main {
@ -9,9 +8,8 @@ main {
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]
byte[] ba = [-10,0,-2,8,5,4,-3,9,-99]
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 {
c64scr.print_ub(ub)
@ -66,11 +64,41 @@ main {
c64.CHROUT(',')
}
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 code runs into a subroutine that follows it instead of inserting an implicit return
}
}