prog8/compiler/test/TestMemory.kt

280 lines
18 KiB
Kotlin
Raw Normal View History

package prog8tests.compiler
2021-06-01 19:21:33 +00:00
2024-09-08 13:24:47 +00:00
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
2024-09-08 13:24:47 +00:00
import io.kotest.datatest.withData
import io.kotest.matchers.shouldBe
2022-03-07 20:41:12 +00:00
import io.kotest.matchers.shouldNotBe
2021-06-01 19:21:33 +00:00
import prog8.ast.Module
import prog8.ast.Program
2021-10-10 22:22:04 +00:00
import prog8.ast.expressions.ArrayIndexedExpression
import prog8.ast.expressions.IdentifierReference
2022-02-10 23:21:40 +00:00
import prog8.ast.expressions.NumericLiteral
2021-10-10 22:22:04 +00:00
import prog8.ast.expressions.PrefixExpression
2021-06-01 19:21:33 +00:00
import prog8.ast.statements.*
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.core.SourceCode
import prog8.code.core.ZeropageWish
2024-09-08 13:24:47 +00:00
import prog8.code.target.*
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.compileText
2021-06-01 19:21:33 +00:00
class TestMemory: FunSpec({
2021-10-10 22:22:04 +00:00
val c64target = C64Target()
fun wrapWithProgram(statements: List<Statement>): Program {
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements.toMutableList(), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
program.addModule(module)
return program
}
2021-06-01 19:21:33 +00:00
test("assignment target not in mapped IO space C64") {
2022-02-10 23:21:40 +00:00
var memexpr = NumericLiteral.optimalInteger(0x0002, Position.DUMMY)
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
}
test("assign target in mapped IO space C64") {
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
var memexpr = NumericLiteral.optimalInteger(0x0000, Position.DUMMY)
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
2022-02-10 23:21:40 +00:00
memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
}
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget {
val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY)
2021-06-01 19:21:33 +00:00
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(decl, assignment))
2021-06-01 19:21:33 +00:00
return target
}
test("identifier mapped to IO memory on C64") {
var target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.VAR)
target.isIOAddress(c64target.machine) shouldBe false
target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.VAR)
target.isIOAddress(c64target.machine) shouldBe false
target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.CONST)
target.isIOAddress(c64target.machine) shouldBe false
target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.CONST)
target.isIOAddress(c64target.machine) shouldBe true
target = createTestProgramForMemoryRefViaVar(0x1000u, VarDeclType.MEMORY)
target.isIOAddress(c64target.machine) shouldBe false
target = createTestProgramForMemoryRefViaVar(0xd020u, VarDeclType.MEMORY)
target.isIOAddress(c64target.machine) shouldBe true
}
2021-06-01 19:21:33 +00:00
test("memory expression mapped to IO memory on C64") {
2022-02-10 23:21:40 +00:00
var memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe false
2022-02-10 23:21:40 +00:00
memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
wrapWithProgram(listOf(assign))
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
}
test("regular variable not in mapped IO ram on C64") {
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, 0u, false, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
2021-11-18 21:54:49 +00:00
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module)
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
}
test("memory mapped variable not in mapped IO ram on C64") {
val address = 0x1000u
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
2021-11-18 21:54:49 +00:00
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module)
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
}
test("memory mapped variable in mapped IO ram on C64") {
val address = 0xd020u
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
2021-11-18 21:54:49 +00:00
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module)
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
}
test("array not in mapped IO ram") {
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, 0u, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
2021-11-18 21:54:49 +00:00
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module)
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
}
test("memory mapped array not in mapped IO ram") {
val address = 0x1000u
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
2021-11-18 21:54:49 +00:00
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module)
target.isIOAddress(c64target.machine) shouldBe false
2021-06-01 19:21:33 +00:00
}
test("memory mapped array in mapped IO ram") {
val address = 0xd800u
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, 0u, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
2022-02-10 23:21:40 +00:00
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
2024-03-09 14:38:46 +00:00
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
2021-11-18 21:54:49 +00:00
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
.addModule(module)
target.isIOAddress(c64target.machine) shouldBe true
2021-06-01 19:21:33 +00:00
}
test("memory() with spaces in name works") {
2022-03-11 19:35:25 +00:00
compileText(
C64Target(), false, """
main {
sub start() {
uword @shared mem = memory("a b c", 100, $100)
}
}
2022-03-07 20:41:12 +00:00
""", writeAssembly = true) shouldNotBe null
}
test("memory() with invalid argument") {
2022-03-11 19:35:25 +00:00
compileText(
C64Target(), false, """
main {
sub start() {
uword @shared mem1 = memory("abc", 100, -2)
}
}
2022-03-07 20:41:12 +00:00
""", writeAssembly = true) shouldBe null
}
2024-09-08 13:24:47 +00:00
context("memsizer") {
withData(VMTarget(), AtariTarget(), C64Target(), PETTarget(), AtariTarget(), C128Target()) { target ->
shouldThrow<IllegalArgumentException> {
target.memorySize(DataType.UNDEFINED)
}
shouldThrow<IllegalArgumentException> {
target.memorySize(DataType.LONG)
}
target.memorySize(DataType.BOOL) shouldBe 1
target.memorySize(DataType.BYTE) shouldBe 1
target.memorySize(DataType.WORD) shouldBe 2
target.memorySize(DataType.FLOAT) shouldBe target.machine.FLOAT_MEM_SIZE
target.memorySize(DataType.STR) shouldBe 2
target.memorySize(DataType.ARRAY_UB) shouldBe 2
target.memorySize(DataType.ARRAY_UW) shouldBe 2
target.memorySize(DataType.ARRAY_F) shouldBe 2
shouldThrow<NoSuchElementException> {
target.memorySize(DataType.UBYTE, 10)
}
target.memorySize(DataType.UWORD, 10) shouldBe 10 // uword is pointer to array of bytes
target.memorySize(DataType.ARRAY_B, 10) shouldBe 10
target.memorySize(DataType.ARRAY_UB, 10) shouldBe 10
target.memorySize(DataType.ARRAY_F, 10) shouldBe 10*target.machine.FLOAT_MEM_SIZE
target.memorySize(DataType.ARRAY_UW, 10) shouldBe 20
target.memorySize(DataType.ARRAY_W_SPLIT, 10) shouldBe 20
target.memorySize(DataType.ARRAY_UW_SPLIT, 10) shouldBe 20
}
}
})