vm: fix memory slabs (bsieve example)

This commit is contained in:
Irmen de Jong 2022-09-27 16:32:44 +02:00
parent 9d219ae4b9
commit 06cf2e0bd7
9 changed files with 49 additions and 64 deletions

View File

@ -8,7 +8,6 @@ import prog8.ast.Program
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.StMemorySlab
import prog8.code.SymbolTable
import prog8.code.core.*
import prog8.codegen.cpu6502.assignment.*
@ -42,7 +41,7 @@ class AsmGen(internal val program: Program,
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen, allocator)
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
override fun compileToAssembly(): IAssemblyProgram? {
@ -2897,12 +2896,6 @@ $repeatLabel lda $counterVar
else
extra
}
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
val prefixedName = "prog8_memoryslab_$name"
symbolTable.add(StMemorySlab(prefixedName, size, align, position))
return prefixedName
}
}

View File

@ -15,8 +15,7 @@ import prog8.compiler.FSignature
internal class BuiltinFunctionsAsmGen(private val program: Program,
private val asmgen: AsmGen,
private val assignAsmGen: AssignmentAsmGen,
private val allocations: VariableAllocator) {
private val assignAsmGen: AssignmentAsmGen) {
internal fun translateFunctioncallExpression(fcall: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single())
@ -309,10 +308,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
throw AssemblyError("should not discard result of memory allocation at $fcall")
val name = (fcall.args[0] as StringLiteral).value
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
val prefixedName = asmgen.addMemorySlab(name, size, align, fcall.position)
val slabname = IdentifierReference(listOf("prog8_slabs", prefixedName), fcall.position)
val slabname = IdentifierReference(listOf("prog8_slabs", "prog8_memoryslab_$name"), fcall.position)
slabname.linkParents(fcall)
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position))
val target =

View File

@ -323,11 +323,8 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
val name = (call.args[0] as PtString).value
val size = (call.args[1] as PtNumber).number.toUInt()
val align = (call.args[2] as PtNumber).number.toUInt()
val label = codeGen.addMemorySlab(name, size, align, call.position)
val code = IRCodeChunk(call.position)
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = label)
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name")
return code
}

View File

@ -1,7 +1,6 @@
package prog8.codegen.intermediate
import prog8.code.StMemVar
import prog8.code.StMemorySlab
import prog8.code.StStaticVariable
import prog8.code.SymbolTable
import prog8.code.ast.*
@ -1037,10 +1036,4 @@ class IRCodeGen(
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
internal fun isOne(expression: PtExpression): Boolean = expression is PtNumber && expression.number==1.0
fun addMemorySlab(name: String, size: UInt, align: UInt, position: Position): String {
val scopedName = "prog8_memoryslab_$name"
symbolTable.add(StMemorySlab(scopedName, size, align, position))
return scopedName
}
}

View File

@ -104,4 +104,16 @@ internal class SymbolTableMaker: IAstVisitor {
scopestack.peek().add(node)
// st.origAstLinks[label] = node
}
override fun visit(fcall: BuiltinFunctionCall) {
if(fcall.name=="memory") {
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
val name = (fcall.args[0] as StringLiteral).value
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
st.add(StMemorySlab("prog8_memoryslab_$name", size, align, fcall.position))
}
super.visit(fcall)
}
}

View File

@ -1,15 +1,10 @@
package prog8tests.helpers
import prog8.ast.Program
import prog8.code.core.*
import prog8.code.target.C64Target
import prog8.code.target.c64.C64Zeropage
import prog8.codegen.cpu6502.AsmGen
import prog8.code.core.ICompilationTarget
import prog8.code.core.IErrorReporter
import prog8.compiler.CompilationResult
import prog8.compiler.CompilerArguments
import prog8.compiler.astprocessing.SymbolTableMaker
import prog8.compiler.compileProgram
import prog8.compiler.determineProgramLoadAddress
import java.nio.file.Path
import kotlin.io.path.name
@ -67,23 +62,3 @@ internal fun compileText(
return compileFile(platform, optimize, filePath.parent, filePath.name,
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, keepIR=keepIR)
}
internal fun generateAssembly(
program: Program,
options: CompilationOptions? = null
): IAssemblyProgram? {
val coptions = options ?: CompilationOptions(OutputType.RAW, CbmPrgLauncherType.BASIC, ZeropageType.DONTUSE, emptyList(),
floats = true,
noSysInit = true,
compTarget = C64Target(),
loadAddress = 0u, outputDir = outputDir)
coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
val st = SymbolTableMaker().makeFrom(program)
val errors = ErrorReporterForTests()
determineProgramLoadAddress(program, coptions, errors)
errors.report()
val asmgen = AsmGen(program, st, coptions, errors)
errors.report()
return asmgen.compileToAssembly()
}

View File

@ -3,6 +3,8 @@ package prog8tests.vm
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.ast.expressions.BuiltinFunctionCall
import prog8.ast.statements.Assignment
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8.vm.VmRunner
@ -135,4 +137,27 @@ skipLABEL:
vm.memory.getUB(3) shouldBe 66u
}
}
test("memory slabs") {
val src = """
main {
sub start() {
uword slab1 = memory("slab1", 2000, 64)
slab1[10]=42
slab1[11]=43
ubyte @shared value1 = slab1[10] ; var at 2
ubyte @shared value2 = slab1[11] ; var at 3
}
}"""
val target = VMTarget()
val result = compileText(target, true, src, writeAssembly = true)!!
val start = result.program.entrypoint
start.statements.size shouldBe 9
((start.statements[1] as Assignment).value as BuiltinFunctionCall).name shouldBe "memory"
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
vm.memory.getUB(2) shouldBe 42u
vm.memory.getUB(3) shouldBe 43u
}
}
})

View File

@ -4,8 +4,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- vm: replace addAssemblyToProgram() by call to IRFileLoader's logic, instead of duplicating it.
- vm: fix memory slabs (bsieve example)
- replace throw IllegalArgumentException() by require()?
...
@ -21,6 +19,7 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- replace throw IllegalArgumentException() by require()?
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.

View File

@ -97,15 +97,10 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
}
fun add(variable: StMemorySlab) {
val scopedName: String
val varToadd: StMemorySlab
if('.' in variable.name) {
scopedName = variable.name
varToadd = variable
} else {
scopedName = variable.scopedName.joinToString(".")
varToadd = StMemorySlab(scopedName, variable.size, variable.align, variable.position)
}
table[scopedName] = varToadd
val varToadd = if('.' in variable.name)
variable
else
StMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align, variable.position)
table[varToadd.name] = varToadd
}
}