mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
added free words counting method to zeropage
This commit is contained in:
parent
572bb38ddb
commit
c03f6604af
@ -19,7 +19,29 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
||||
|
||||
val allowedDatatypes = NumericDatatypes
|
||||
|
||||
fun available() = if(options.zeropage==ZeropageType.DONTUSE) 0 else free.size
|
||||
fun availableBytes() = if(options.zeropage==ZeropageType.DONTUSE) 0 else free.size
|
||||
fun hasByteAvailable() = if(options.zeropage==ZeropageType.DONTUSE) false else free.isNotEmpty()
|
||||
fun availableWords(): Int {
|
||||
if(options.zeropage==ZeropageType.DONTUSE)
|
||||
return 0
|
||||
|
||||
val words = free.windowed(2).filter { it[0] == it[1]-1 }
|
||||
var nonOverlappingWordsCount = 0
|
||||
var prevMsbLoc = -1
|
||||
for(w in words) {
|
||||
if(w[0]!=prevMsbLoc) {
|
||||
nonOverlappingWordsCount++
|
||||
prevMsbLoc = w[1]
|
||||
}
|
||||
}
|
||||
return nonOverlappingWordsCount
|
||||
}
|
||||
fun hasWordAvailable(): Boolean {
|
||||
if(options.zeropage==ZeropageType.DONTUSE)
|
||||
return false
|
||||
|
||||
return free.windowed(2).any { it[0] == it[1] - 1 }
|
||||
}
|
||||
|
||||
fun allocate(scopedname: String, datatype: DataType, position: Position?, errors: IErrorReporter): Int {
|
||||
assert(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"scopedname can't be allocated twice"}
|
||||
|
@ -1070,16 +1070,33 @@ $repeatLabel lda $counterVar
|
||||
private fun createRepeatCounterVar(dt: DataType, constIterations: Int?, stmt: RepeatLoop): Pair<String, Boolean> {
|
||||
// TODO share counter variables between subroutines or even between repeat loops as long as they're not nested
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
val zpAvail = if(dt==DataType.UWORD) 2 else 1
|
||||
return if(constIterations!=null && constIterations>=16 && zeropage.available() >= zpAvail) {
|
||||
|
||||
// println("REPEATCOUNTERVAR $counterVar SIZE $dt CTX ${stmt.definingSubroutine()}")
|
||||
|
||||
when(dt) {
|
||||
DataType.UBYTE -> {
|
||||
return if(constIterations!=null && constIterations>=16 && zeropage.hasByteAvailable()) {
|
||||
// allocate count var on ZP
|
||||
val zpAddr = zeropage.allocate(counterVar, dt, stmt.position, errors)
|
||||
out("$counterVar = $zpAddr ; auto zp $dt")
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UBYTE, stmt.position, errors)
|
||||
out("$counterVar = $zpAddr ; auto zp byte")
|
||||
Pair(counterVar, false)
|
||||
} else {
|
||||
Pair(counterVar, true)
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
return if(constIterations!=null && constIterations>=16 && zeropage.hasWordAvailable()) {
|
||||
// allocate count var on ZP
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UWORD, stmt.position, errors)
|
||||
out("$counterVar = $zpAddr ; auto zp word")
|
||||
Pair(counterVar, false)
|
||||
} else {
|
||||
Pair(counterVar, true)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("invalidt dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(stmt: WhileLoop) {
|
||||
checkBooleanExpression(stmt.condition) // we require the condition to be of the form 'x <comparison> <value>'
|
||||
|
@ -288,7 +288,7 @@ $loopLabel sty $indexVar
|
||||
bne $loopLabel
|
||||
beq $endLabel""")
|
||||
}
|
||||
if(length>=16 && asmgen.zeropage.available() > 0) {
|
||||
if(length>=16 && asmgen.zeropage.hasByteAvailable()) {
|
||||
// allocate index var on ZP
|
||||
val zpAddr = asmgen.zeropage.allocate(indexVar, DataType.UBYTE, stmt.position, asmgen.errors)
|
||||
asmgen.out("""$indexVar = $zpAddr ; auto zp UBYTE""")
|
||||
@ -327,7 +327,7 @@ $loopLabel sty $indexVar
|
||||
bne $loopLabel
|
||||
beq $endLabel""")
|
||||
}
|
||||
if(length>=16 && asmgen.zeropage.available() > 0) {
|
||||
if(length>=16 && asmgen.zeropage.hasByteAvailable()) {
|
||||
// allocate index var on ZP
|
||||
val zpAddr = asmgen.zeropage.allocate(indexVar, DataType.UBYTE, stmt.position, asmgen.errors)
|
||||
asmgen.out("""$indexVar = $zpAddr ; auto zp UBYTE""")
|
||||
|
@ -179,28 +179,48 @@ class TestC64Zeropage {
|
||||
fun testZpDontuse() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.DONTUSE, emptyList(), false, false, C64Target))
|
||||
println(zp.free)
|
||||
assertEquals(0, zp.available())
|
||||
assertEquals(0, zp.availableBytes())
|
||||
assertFailsWith<CompilerException> {
|
||||
zp.allocate("", DataType.BYTE, null, errors)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFreeSpaces() {
|
||||
fun testFreeSpacesBytes() {
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
||||
assertEquals(18, zp1.available())
|
||||
assertEquals(18, zp1.availableBytes())
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target))
|
||||
assertEquals(85, zp2.available())
|
||||
assertEquals(85, zp2.availableBytes())
|
||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target))
|
||||
assertEquals(125, zp3.available())
|
||||
assertEquals(125, zp3.availableBytes())
|
||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
||||
assertEquals(238, zp4.available())
|
||||
assertEquals(238, zp4.availableBytes())
|
||||
zp4.allocate("test", DataType.UBYTE, null, errors)
|
||||
assertEquals(237, zp4.availableBytes())
|
||||
zp4.allocate("test2", DataType.UBYTE, null, errors)
|
||||
assertEquals(236, zp4.availableBytes())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFreeSpacesWords() {
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
||||
assertEquals(6, zp1.availableWords())
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, C64Target))
|
||||
assertEquals(38, zp2.availableWords())
|
||||
val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, C64Target))
|
||||
assertEquals(57, zp3.availableWords())
|
||||
val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
||||
assertEquals(116, zp4.availableWords())
|
||||
zp4.allocate("test", DataType.UWORD, null, errors)
|
||||
assertEquals(115, zp4.availableWords())
|
||||
zp4.allocate("test2", DataType.UWORD, null, errors)
|
||||
assertEquals(114, zp4.availableWords())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReservedSpace() {
|
||||
val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
||||
assertEquals(238, zp1.available())
|
||||
assertEquals(238, zp1.availableBytes())
|
||||
assertTrue(50 in zp1.free)
|
||||
assertTrue(100 in zp1.free)
|
||||
assertTrue(49 in zp1.free)
|
||||
@ -209,7 +229,7 @@ class TestC64Zeropage {
|
||||
assertTrue(255 in zp1.free)
|
||||
assertTrue(199 in zp1.free)
|
||||
val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, listOf(50 .. 100, 200..255), false, false, C64Target))
|
||||
assertEquals(139, zp2.available())
|
||||
assertEquals(139, zp2.availableBytes())
|
||||
assertFalse(50 in zp2.free)
|
||||
assertFalse(100 in zp2.free)
|
||||
assertTrue(49 in zp2.free)
|
||||
@ -222,18 +242,22 @@ class TestC64Zeropage {
|
||||
@Test
|
||||
fun testBasicsafeAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
||||
assertEquals(18, zp.available())
|
||||
assertEquals(18, zp.availableBytes())
|
||||
assertTrue(zp.hasByteAvailable())
|
||||
assertTrue(zp.hasWordAvailable())
|
||||
|
||||
assertFailsWith<ZeropageDepletedError> {
|
||||
// in regular zp there aren't 5 sequential bytes free
|
||||
zp.allocate("", DataType.FLOAT, null, errors)
|
||||
}
|
||||
|
||||
for (i in 0 until zp.available()) {
|
||||
for (i in 0 until zp.availableBytes()) {
|
||||
val loc = zp.allocate("", DataType.UBYTE, null, errors)
|
||||
assertTrue(loc > 0)
|
||||
}
|
||||
assertEquals(0, zp.available())
|
||||
assertEquals(0, zp.availableBytes())
|
||||
assertFalse(zp.hasByteAvailable())
|
||||
assertFalse(zp.hasWordAvailable())
|
||||
assertFailsWith<ZeropageDepletedError> {
|
||||
zp.allocate("", DataType.UBYTE, null, errors)
|
||||
}
|
||||
@ -245,16 +269,18 @@ class TestC64Zeropage {
|
||||
@Test
|
||||
fun testFullAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, C64Target))
|
||||
assertEquals(238, zp.available())
|
||||
assertEquals(238, zp.availableBytes())
|
||||
assertTrue(zp.hasByteAvailable())
|
||||
assertTrue(zp.hasWordAvailable())
|
||||
val loc = zp.allocate("", DataType.UWORD, null, errors)
|
||||
assertTrue(loc > 3)
|
||||
assertFalse(loc in zp.free)
|
||||
val num = zp.available() / 2
|
||||
val num = zp.availableBytes() / 2
|
||||
|
||||
for(i in 0..num-4) {
|
||||
zp.allocate("", DataType.UWORD, null, errors)
|
||||
}
|
||||
assertEquals(6,zp.available())
|
||||
assertEquals(6,zp.availableBytes())
|
||||
|
||||
assertFailsWith<ZeropageDepletedError> {
|
||||
// can't allocate because no more sequential bytes, only fragmented
|
||||
@ -265,7 +291,9 @@ class TestC64Zeropage {
|
||||
zp.allocate("", DataType.UBYTE, null, errors)
|
||||
}
|
||||
|
||||
assertEquals(0, zp.available())
|
||||
assertEquals(0, zp.availableBytes())
|
||||
assertFalse(zp.hasByteAvailable())
|
||||
assertFalse(zp.hasWordAvailable())
|
||||
assertFailsWith<ZeropageDepletedError> {
|
||||
// no more space
|
||||
zp.allocate("", DataType.UBYTE, null, errors)
|
||||
@ -275,7 +303,7 @@ class TestC64Zeropage {
|
||||
@Test
|
||||
fun testEfficientAllocation() {
|
||||
val zp = C64Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, C64Target))
|
||||
assertEquals(18, zp.available())
|
||||
assertEquals(18, zp.availableBytes())
|
||||
assertEquals(0x04, zp.allocate("", DataType.WORD, null, errors))
|
||||
assertEquals(0x06, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
assertEquals(0x0a, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
@ -288,7 +316,7 @@ class TestC64Zeropage {
|
||||
assertEquals(0x92, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
assertEquals(0x96, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
assertEquals(0xf9, zp.allocate("", DataType.UBYTE, null, errors))
|
||||
assertEquals(0, zp.available())
|
||||
assertEquals(0, zp.availableBytes())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -301,6 +329,8 @@ class TestC64Zeropage {
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TestCx16Zeropage {
|
||||
private val errors = ErrorReporter()
|
||||
|
||||
@Test
|
||||
fun testReservedLocations() {
|
||||
val zp = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), false, false, Cx16Target))
|
||||
@ -308,19 +338,37 @@ class TestCx16Zeropage {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFreeSpaces() {
|
||||
fun testFreeSpacesBytes() {
|
||||
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, Cx16Target))
|
||||
assertEquals(88, zp1.available())
|
||||
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(175, zp3.available())
|
||||
val zp4 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(216, zp4.available())
|
||||
assertEquals(88, zp1.availableBytes())
|
||||
val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(175, zp2.availableBytes())
|
||||
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(216, zp3.availableBytes())
|
||||
zp3.allocate("test", DataType.UBYTE, null, errors)
|
||||
assertEquals(215, zp3.availableBytes())
|
||||
zp3.allocate("test2", DataType.UBYTE, null, errors)
|
||||
assertEquals(214, zp3.availableBytes())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFreeSpacesWords() {
|
||||
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(108, zp1.availableWords())
|
||||
val zp2 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(87, zp2.availableWords())
|
||||
val zp3 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, Cx16Target))
|
||||
assertEquals(44, zp3.availableWords())
|
||||
zp3.allocate("test", DataType.UWORD, null, errors)
|
||||
assertEquals(43, zp3.availableWords())
|
||||
zp3.allocate("test2", DataType.UWORD, null, errors)
|
||||
assertEquals(42, zp3.availableWords())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReservedSpace() {
|
||||
val zp1 = CX16Zeropage(CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, Cx16Target))
|
||||
assertEquals(216, zp1.available())
|
||||
assertEquals(216, zp1.availableBytes())
|
||||
assertTrue(0x22 in zp1.free)
|
||||
assertTrue(0x80 in zp1.free)
|
||||
assertTrue(0xff in zp1.free)
|
||||
|
114
examples/test.p8
114
examples/test.p8
@ -1,11 +1,16 @@
|
||||
%import textio ; txt.*
|
||||
%zeropage kernalsafe
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
; test program for the optimization of repeat var allocation (asmgen.createRepeatCounterVar)
|
||||
; output must be: 60 6164 6224 12328
|
||||
|
||||
uword xx
|
||||
|
||||
sub start() {
|
||||
|
||||
ubyte xx
|
||||
xx=0
|
||||
|
||||
repeat 10 {
|
||||
xx++
|
||||
@ -19,55 +24,86 @@ main {
|
||||
repeat 10 {
|
||||
xx++
|
||||
}
|
||||
repeat 5 {
|
||||
repeat 4 {
|
||||
xx++
|
||||
}
|
||||
}
|
||||
txt.print_uw(xx)
|
||||
txt.nl()
|
||||
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
repeat 260 {
|
||||
repeat 4 {
|
||||
xx++
|
||||
}
|
||||
}
|
||||
repeat 260 {
|
||||
repeat 260 {
|
||||
xx++
|
||||
}
|
||||
}
|
||||
txt.print_uw(xx)
|
||||
txt.nl()
|
||||
|
||||
sub2()
|
||||
|
||||
if xx!=12328
|
||||
txt.print("\n!fail!\n")
|
||||
else
|
||||
txt.print("\nok\n")
|
||||
}
|
||||
|
||||
sub sub2() {
|
||||
|
||||
repeat 10 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
repeat 10 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
repeat 10 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
repeat 10 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
repeat 5 {
|
||||
repeat 4 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
txt.print_uw(xx)
|
||||
txt.nl()
|
||||
|
||||
str string1 = "stringvalue\n"
|
||||
str string2 = "stringvalue\n"
|
||||
str string3 = "stringvalue\n"
|
||||
str string4 = "a"
|
||||
str string5 = "bb"
|
||||
|
||||
txt.print(string1)
|
||||
txt.print(string2)
|
||||
txt.print(string3)
|
||||
string1[1]='?'
|
||||
string2[2] = '?'
|
||||
string3[3] = '?'
|
||||
txt.print(string1)
|
||||
txt.print(string2)
|
||||
txt.print(string3)
|
||||
|
||||
txt.print("a")
|
||||
txt.print("a")
|
||||
txt.print(string4)
|
||||
txt.print("bb")
|
||||
txt.print("bb")
|
||||
txt.print(string5)
|
||||
txt.print("\n")
|
||||
txt.print("\n\n")
|
||||
txt.print("hello\n")
|
||||
txt.print("hello\n")
|
||||
txt.print("hello\n")
|
||||
txt.print("bye\n")
|
||||
txt.print("bye\n")
|
||||
txt.print("bye\n")
|
||||
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
repeat 1000 {
|
||||
xx++
|
||||
}
|
||||
repeat 260 {
|
||||
repeat 4 {
|
||||
xx++
|
||||
}
|
||||
}
|
||||
repeat 260 {
|
||||
repeat 260 {
|
||||
xx++
|
||||
}
|
||||
}
|
||||
txt.print_uw(xx)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user