incbin in IR

This commit is contained in:
Irmen de Jong 2022-09-10 14:51:46 +02:00
parent 6886b61186
commit aacea3e9db
9 changed files with 86 additions and 41 deletions

View File

@ -97,11 +97,12 @@ private fun BufferedWriter.writeLine(line: IRCodeLine) {
write(line.ins.toString() + "\n")
}
is IRCodeInlineBinary -> {
write("incbin \"${line.file}\"")
if(line.offset!=null)
write(",${line.offset}")
if(line.length!=null)
write(",${line.length}")
write("!binary ")
line.data.withIndex().forEach {(index, byte) ->
write(byte.toString(16).padStart(2,'0'))
if(index and 63 == 63 && index<line.data.size-1)
write("\n!binary ")
}
write("\n")
}
is IRCodeLabel -> {

View File

@ -6,6 +6,7 @@ import prog8.code.SymbolTable
import prog8.code.ast.*
import prog8.code.core.*
import prog8.intermediate.*
import kotlin.io.path.readBytes
import kotlin.math.pow
@ -204,7 +205,10 @@ class CodeGen(internal val program: PtProgram,
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.position)
is PtIncludeBinary -> {
val chunk = IRCodeChunk(node.position)
chunk += IRCodeInlineBinary(node.file, node.offset, node.length)
val data = node.file.readBytes()
.drop(node.offset?.toInt() ?: 0)
.take(node.length?.toInt() ?: Int.MAX_VALUE)
chunk += IRCodeInlineBinary(data.toByteArray())
return chunk
}
is PtAddressOf,

View File

@ -136,4 +136,9 @@ internal class VmCodeInlineAsm(asm: String): VmCodeLine() {
val assembly: String = asm.trimIndent()
}
internal class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine()
internal class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine() {
init {
require(file.isAbsolute)
require(file.toFile().isFile)
}
}

View File

@ -10,6 +10,7 @@ import prog8.ast.walk.IAstModification
import prog8.code.core.*
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
class AstPreprocessor(val program: Program,
@ -24,7 +25,7 @@ class AstPreprocessor(val program: Program,
relocateCx16VirtualRegisters(program, 0x0004u)
}
}
else if(options.compTarget.name!=Cx16Target.NAME) {
else if(options.compTarget.name !in setOf(Cx16Target.NAME, VMTarget.NAME)) {
relocateCx16VirtualRegisters(program, options.compTarget.machine.ESTACK_HI)
}
return noModifications

View File

@ -180,11 +180,19 @@ class IntermediateAstMaker(val program: Program) {
return when(directive.directive) {
"%breakpoint" -> PtBreakpoint(directive.position)
"%asmbinary" -> {
val filename = directive.args[0].str!!
val offset: UInt? = if(directive.args.size>=2) directive.args[1].int!! else null
val length: UInt? = if(directive.args.size>=3) directive.args[2].int!! else null
val sourcePath = Path(directive.definingModule.source.origin)
val includedPath = sourcePath.resolveSibling(directive.args[0].str!!)
PtIncludeBinary(includedPath, offset, length, directive.position)
val abspath = if(File(filename).isFile) {
Path(filename).toAbsolutePath()
} else {
val sourcePath = Path(directive.definingModule.source.origin)
sourcePath.resolveSibling(filename).toAbsolutePath()
}
if(abspath.toFile().isFile)
PtIncludeBinary(abspath, offset, length, directive.position)
else
throw FatalAstException("included file doesn't exist")
}
"%asminclude" -> {
val result = loadAsmIncludeFile(directive.args[0].str!!, directive.definingModule.source)

View File

@ -3,7 +3,8 @@
main {
uword global1 = 1234
uword @shared global1 = 1234
str @shared globalstring = "irmen"
%asm {{
nop
@ -27,6 +28,8 @@ main {
}}
a_label:
%asmbinary "LICENSE", 200, 513
; TODO add proper memory SLAB support to IR+VM
; uword @shared slab1 = memory("slab 1", 2000, 0)
; uword @shared slab2 = memory("slab 1", 2000, 0)

View File

@ -1,9 +1,6 @@
package prog8.intermediate
import prog8.code.StMemVar
import prog8.code.StMemorySlab
import prog8.code.StStaticVariable
import prog8.code.SymbolTable
import prog8.code.*
import prog8.code.ast.PtBlock
import prog8.code.core.*
import prog8.code.target.*
@ -29,7 +26,7 @@ class IRFileReader(outputDir: Path, programName: String) {
val match = programPattern.matchEntire(line) ?: throw IRParseException("invalid PROGRAM")
val programName = match.groups[1]!!.value
val options = parseOptions(lines)
val variables = parseVariables(lines)
val variables = parseVariables(lines, options.dontReinitGlobals)
val memorymapped = parseMemMapped(lines)
val slabs = parseSlabs(lines)
val initGlobals = parseInitGlobals(lines)
@ -104,7 +101,7 @@ class IRFileReader(outputDir: Path, programName: String) {
)
}
private fun parseVariables(lines: Iterator<String>): List<StStaticVariable> {
private fun parseVariables(lines: Iterator<String>, dontReinitGlobals: Boolean): List<StStaticVariable> {
var line = lines.next()
while(line.isBlank())
line = lines.next()
@ -121,11 +118,25 @@ class IRFileReader(outputDir: Path, programName: String) {
// ubyte[6] main.start.namestring=105,114,109,101,110,0
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLE $line")
val (type, arrayspec, name, value, _, zpwish) = match.destructured
// TODO what to do with 'value' ??
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt: DataType = parseDatatype(type, arraysize!=null)
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
variables.add(StStaticVariable(name, dt, null, null, null, arraysize, zp, Position.DUMMY))
var initNumeric: Double? = null
var initArray: StArray? = null
when(dt) {
in NumericDatatypes -> {
if(dontReinitGlobals) {
// we need to specify a one time initialization value
initNumeric = value.toDouble()
}
}
in ArrayDatatypes -> {
initArray = value.split(',').map { StArrayElement(it.toDouble(), null) }
}
DataType.STR -> throw IRParseException("STR should have been converted to byte array")
else -> throw IRParseException("weird dt")
}
variables.add(StStaticVariable(name, dt, initNumeric, null, initArray, arraysize, zp, Position.DUMMY))
}
return variables
}
@ -204,8 +215,12 @@ class IRFileReader(outputDir: Path, programName: String) {
line = lines.next()
if(line!="<INITGLOBALS>")
throw IRParseException("invalid INITGLOBALS")
val chunk = parseCodeChunk(lines.next(), lines)!!
line = lines.next()
var chunk = IRCodeChunk(Position.DUMMY)
if(line=="<CODE>") {
chunk = parseCodeChunk(line, lines)!!
line = lines.next()
}
if(line!="</INITGLOBALS>")
throw IRParseException("missing INITGLOBALS close tag")
return chunk
@ -322,12 +337,24 @@ class IRFileReader(outputDir: Path, programName: String) {
}
val chunk = IRCodeChunk(Position.DUMMY)
while(true) {
val line = lines.next()
var line = lines.next()
if (line == "</CODE>")
return chunk
if (line.isBlank() || line.startsWith(';'))
continue
chunk += parseCodeLine(line)
if(line=="<BYTES>") {
val bytes = mutableListOf<Byte>()
line = lines.next()
while(line!="</BYTES>") {
line.trimEnd().windowed(size=2, step=2) {
bytes.add(it.toString().toByte(16))
}
line = lines.next()
}
chunk += IRCodeInlineBinary(bytes.toByteArray())
} else {
chunk += parseCodeLine(line)
}
}
}
@ -341,9 +368,6 @@ class IRFileReader(outputDir: Path, programName: String) {
// it's an instruction.
val (_, instr, typestr, rest) = match.groupValues
if(instr=="incbin") {
TODO("incbin")
}
val opcode = try {
Opcode.valueOf(instr.uppercase())
} catch (ax: IllegalArgumentException) {

View File

@ -8,9 +8,6 @@ import kotlin.io.path.bufferedWriter
import kotlin.io.path.div
// TODO incbins
class IRFileWriter(private val irProgram: IRProgram) {
private val outfile = irProgram.options.outputDir / ("${irProgram.name}.p8ir")
private val out = outfile.bufferedWriter()
@ -21,12 +18,14 @@ class IRFileWriter(private val irProgram: IRProgram) {
writeOptions()
writeVariableAllocations()
out.write("\n<INITGLOBALS>\n")
if(!irProgram.options.dontReinitGlobals) {
out.write("<CODE>\n")
// note: this a block of code that loads values and stores them into the global variables to reset their values.
out.write("\n<INITGLOBALS>\n<CODE>\n")
irProgram.globalInits.forEach { out.writeLine(it) }
out.write("</CODE>\n</INITGLOBALS>\n")
out.write("</CODE>\n")
}
out.write("</INITGLOBALS>\n")
writeBlocks()
out.write("</PROGRAM>\n")
out.close()
@ -91,9 +90,9 @@ class IRFileWriter(private val irProgram: IRProgram) {
out.write("\n<VARIABLES>\n")
for (variable in irProgram.st.allVariables) {
val typeStr = getTypeString(variable)
val value = when(variable.dt) {
val value: String = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue ?: 0)
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: "0")
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }
@ -171,12 +170,13 @@ class IRFileWriter(private val irProgram: IRProgram) {
}
is IRCodeLabel -> write("_${line.name}:\n")
is IRCodeInlineBinary -> {
write("incbin \"${line.file}\"")
if(line.offset!=null)
write(",${line.offset}")
if(line.length!=null)
write(",${line.length}")
write("\n")
write("<BYTES>\n")
line.data.withIndex().forEach {(index, byte) ->
write(byte.toString(16).padStart(2,'0'))
if(index and 63 == 63 && index < line.data.size-1)
write("\n")
}
write("\n</BYTES>\n")
}
else -> throw AssemblyError("invalid vm code line")
}

View File

@ -6,7 +6,6 @@ import prog8.code.core.CompilationOptions
import prog8.code.core.DataType
import prog8.code.core.IStringEncoding
import prog8.code.core.Position
import java.nio.file.Path
/*
@ -158,7 +157,7 @@ class IRCodeLabel(val name: String): IRCodeLine()
class IRCodeComment(val comment: String): IRCodeLine()
class IRCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): IRCodeLine()
class IRCodeInlineBinary(val data: ByteArray): IRCodeLine()
abstract class IRCodeChunkBase(val position: Position) {
val lines = mutableListOf<IRCodeLine>()