add a split-array version for word containment check

This commit is contained in:
Irmen de Jong 2024-12-15 13:35:22 +01:00
parent 8f799567cf
commit 28c721fa7d
6 changed files with 43 additions and 86 deletions

View File

@ -1941,12 +1941,15 @@ $endLabel""")
}
dt.isWordArray -> {
assignExpressionToVariable(containment.needle, "P8ZP_SCRATCH_W1", elementDt)
if(dt.isSplitWordArray) {
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName+"_lsb", null, null)
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_splitwordarray")
} else {
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.forDt(BaseDataType.UWORD), containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null)
asmgen.out(" ldy #$numElements")
if(dt.isSplitWordArray)
asmgen.out(" jsr prog8_lib.containment_splitwordarray")
else
asmgen.out(" jsr prog8_lib.containment_wordarray")
asmgen.out(" jsr prog8_lib.containment_linearwordarray")
}
}
else -> throw AssemblyError("invalid dt")
}

View File

@ -317,7 +317,7 @@ containment_bytearray .proc
rts
.pend
containment_wordarray .proc
containment_linearwordarray .proc
; -- check if a value exists in a linear word array.
; parameters: P8ZP_SCRATCH_W1: value to check, P8ZP_SCRATCH_W2: address of the word array, Y = number of elements in the array (>=1).
; returns boolean 0/1 in A.
@ -348,22 +348,31 @@ containment_splitwordarray .proc
; parameters: P8ZP_SCRATCH_W1: value to check, P8ZP_SCRATCH_W2: start address of the lsb word array, Y = number of elements in the array (>=1).
; returns boolean 0/1 in A.
; TODO FIX THIS!
dey
tya
asl a
tay
- lda P8ZP_SCRATCH_W1
cmp (P8ZP_SCRATCH_W2),y
bne +
; store the needle value in SCRATCH_B1(lsb) and SCRATCH_REG(msb)
lda P8ZP_SCRATCH_W1
sta P8ZP_SCRATCH_B1
lda P8ZP_SCRATCH_W1+1
iny
sta P8ZP_SCRATCH_REG
; calculate where the msb array starts and put this in P8ZP_SCRATCH_W1 (_W2 is the start of the lsb array)
tya
clc
adc P8ZP_SCRATCH_W2
sta P8ZP_SCRATCH_W1
lda P8ZP_SCRATCH_W2+1
adc #0
sta P8ZP_SCRATCH_W1+1
; search needle
dey
- lda P8ZP_SCRATCH_REG
cmp (P8ZP_SCRATCH_W1),y
bne +
lda P8ZP_SCRATCH_B1
cmp (P8ZP_SCRATCH_W2),y
beq _found
dey
+ dey
dey
cpy #254
cpy #255
bne -
lda #0
rts

View File

@ -83,10 +83,7 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
val decl = elt.targetVarDecl(program)
if(decl!=null && decl.datatype.isSplitWordArray) {
// you can't take the adress of a split-word array.
// instead of a fatal error, we give a warning and turn it back into a regular array.
errors.warn("cannot take address of split word array - the array is turned back into a regular word array", decl.position)
val normalArray = makeNormalArrayFromSplit(decl)
mods.add(IAstModification.ReplaceNode(decl, normalArray, decl.parent))
errors.err("cannot take address of split word array", decl.position)
}
}
return mods
@ -160,22 +157,9 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
if (variable!=null) {
if (variable.datatype.isSplitWordArray) {
// you can't take the adress of a split-word array.
// instead of giving a fatal error, we remove the
// instead of a fatal error, we give a warning and turn it back into a regular array.
errors.warn("cannot take address of split word array - the array is turned back into a regular word array", addressOf.position)
val normalArray = makeNormalArrayFromSplit(variable)
return listOf(IAstModification.ReplaceNode(variable, normalArray, variable.parent))
errors.err("cannot take address of split word array", addressOf.position)
}
}
return noModifications
}
private fun makeNormalArrayFromSplit(variable: VarDecl): VarDecl {
val normalDt = DataType.arrayFor(variable.datatype.sub!!.dt, false)
return VarDecl(
variable.type, variable.origin, normalDt, variable.zeropage, variable.arraysize, variable.name, emptyList(),
variable.value?.copy(), variable.sharedWithAsm, variable.alignment, variable.dirty, variable.position
)
}
}

View File

@ -95,43 +95,6 @@ main {
compileText(VMTarget(), false, text, writeAssembly = true) shouldNotBe null
}
test("split only for word arrays") {
val srcGood = """
main {
uword[10] @nosplit sw
word[10] @nosplit sw2
sub start() {
}
}"""
compileText(C64Target(), false, srcGood, writeAssembly = false) shouldNotBe null
val srcWrong1 = """
main {
ubyte[10] @nosplit sb
sub start() {
}
}"""
val errors = ErrorReporterForTests()
compileText(C64Target(), false, srcWrong1, writeAssembly = false, errors=errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "nosplit can only be used on word arrays"
val srcWrong2 = """
%option enable_floats
main {
float[10] @nosplit sf
sub start() {
}
}"""
errors.clear()
compileText(C64Target(), false, srcWrong2, writeAssembly = false, errors=errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "nosplit can only be used on word arrays"
}
test("split word arrays in asm as lsb/msb, nosplit as single linear") {
val text = """
main {

View File

@ -3,9 +3,8 @@ TODO
- DONE: make word arrays split by default (remove @split tag) and use new @nosplit tag to make an array use the old storage format? Also invert -splitarrays command line option.
- DONE: remove "splitarrays" %option switch
- Regular & will just return the start of the split array in memory whatever byte comes first.
- Regular & will just return the start of the split array in memory whatever byte comes first. Search "cannot take address of split word array"
- add &< and &> operators to get the address of the lsb-array and msb-array, respectively.
- fix containment_splitwordarray
- fix sprites.pos_batch
- fix anyall.anyw/allw
- update Syntax files + Document all of this (also that word arrays can then have length 256 by default as well, and that @linear will reduce it to half.)

View File

@ -2,14 +2,13 @@
%zeropage basicsafe
main {
uword[] array = [1000, 2000, 9000, 8000, 5000]
sub start() {
txt.print_bool(1000 in array)
txt.spc()
txt.print_bool(9000 in array)
txt.spc()
txt.print_bool(5000 in array)
txt.spc()
txt.print_bool(9001 in array)
uword[] addresses = [scores2, start]
uword[] scores1 = [10, 25, 50, 100]
uword[] scores2 = [100, 250, 500, 1000]
cx16.r0 = &scores1
cx16.r1 = &scores2
cx16.r2 = &addresses
}
}