mirror of
https://github.com/irmen/prog8.git
synced 2025-02-02 04:30:46 +00:00
added '%ir' to write inline IR code, '%asm' is now only for real 6502 assembly.
(%ir is probably only used in the library modules for the virtual machine target)
This commit is contained in:
parent
94f0f3e966
commit
0d4dd385b8
@ -96,7 +96,7 @@ class PtBlock(name: String,
|
||||
}
|
||||
|
||||
|
||||
class PtInlineAssembly(val assembly: String, position: Position) : PtNode(position) {
|
||||
class PtInlineAssembly(val assembly: String, val isIR: Boolean, position: Position) : PtNode(position) {
|
||||
override fun printProperties() {}
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ class IRCodeGen(
|
||||
return chunk
|
||||
}
|
||||
is PtConditionalBranch -> translate(node)
|
||||
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.position)
|
||||
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.isIR, node.position)
|
||||
is PtIncludeBinary -> {
|
||||
val chunk = IRCodeChunk(node.position)
|
||||
val data = node.file.readBytes()
|
||||
@ -979,15 +979,18 @@ class IRCodeGen(
|
||||
vmblock += vmsub
|
||||
}
|
||||
is PtAsmSub -> {
|
||||
val assembly = if(child.children.isEmpty()) "" else (child.children.single() as PtInlineAssembly).assembly
|
||||
vmblock += IRAsmSubroutine(child.name, child.position, child.address,
|
||||
val assemblyChild = if(child.children.isEmpty()) null else (child.children.single() as PtInlineAssembly)
|
||||
vmblock += IRAsmSubroutine(
|
||||
child.name, child.position, child.address,
|
||||
child.clobbers,
|
||||
child.parameters.map { Pair(it.first.type, it.second) }, // note: the name of the asmsub param is not used anymore.
|
||||
child.returnTypes.zip(child.retvalRegisters),
|
||||
assembly)
|
||||
assemblyChild?.isIR==true,
|
||||
assemblyChild?.assembly ?: ""
|
||||
)
|
||||
}
|
||||
is PtInlineAssembly -> {
|
||||
vmblock += IRInlineAsmChunk(child.assembly, child.position)
|
||||
vmblock += IRInlineAsmChunk(child.assembly, child.isIR, child.position)
|
||||
}
|
||||
else -> TODO("BLOCK HAS WEIRD CHILD NODE $child")
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ sub str2uword(str string) -> uword {
|
||||
; -- returns the unsigned word value of the string number argument in AY
|
||||
; the number may NOT be preceded by a + sign and may NOT contain spaces
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,conv.str2uword.string
|
||||
syscall 11
|
||||
return
|
||||
@ -206,7 +206,7 @@ sub str2word(str string) -> word {
|
||||
; -- returns the signed word value of the string number argument in AY
|
||||
; the number may be preceded by a + or - sign but may NOT contain spaces
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,conv.str2word.string
|
||||
syscall 12
|
||||
return
|
||||
|
@ -9,7 +9,7 @@ floats {
|
||||
|
||||
sub print_f(float value) {
|
||||
; ---- prints the floating point value (without a newline).
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.print_f.value
|
||||
syscall 25
|
||||
return
|
||||
@ -17,7 +17,7 @@ sub print_f(float value) {
|
||||
}
|
||||
|
||||
sub pow(float value, float power) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.pow.value
|
||||
loadm.f fr1,floats.pow.power
|
||||
fpow.f fr0,fr1
|
||||
@ -26,7 +26,7 @@ sub pow(float value, float power) -> float {
|
||||
}
|
||||
|
||||
sub fabs(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.fabs.value
|
||||
fabs.f fr0,fr0
|
||||
return
|
||||
@ -34,7 +34,7 @@ sub fabs(float value) -> float {
|
||||
}
|
||||
|
||||
sub sin(float angle) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.sin.angle
|
||||
fsin.f fr0,fr0
|
||||
return
|
||||
@ -42,7 +42,7 @@ sub sin(float angle) -> float {
|
||||
}
|
||||
|
||||
sub cos(float angle) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.cos.angle
|
||||
fcos.f fr0,fr0
|
||||
return
|
||||
@ -50,7 +50,7 @@ sub cos(float angle) -> float {
|
||||
}
|
||||
|
||||
sub tan(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.tan.value
|
||||
ftan.f fr0,fr0
|
||||
return
|
||||
@ -58,7 +58,7 @@ sub tan(float value) -> float {
|
||||
}
|
||||
|
||||
sub atan(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.atan.value
|
||||
fatan.f fr0,fr0
|
||||
return
|
||||
@ -66,7 +66,7 @@ sub atan(float value) -> float {
|
||||
}
|
||||
|
||||
sub ln(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.ln.value
|
||||
fln.f fr0,fr0
|
||||
return
|
||||
@ -74,7 +74,7 @@ sub ln(float value) -> float {
|
||||
}
|
||||
|
||||
sub log2(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.log2.value
|
||||
flog.f fr0,fr0
|
||||
return
|
||||
@ -82,7 +82,7 @@ sub log2(float value) -> float {
|
||||
}
|
||||
|
||||
sub sqrt(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.sqrt.value
|
||||
sqrt.f fr0,fr0
|
||||
return
|
||||
@ -100,7 +100,7 @@ sub deg(float angle) -> float {
|
||||
}
|
||||
|
||||
sub round(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.round.value
|
||||
fround.f fr0,fr0
|
||||
return
|
||||
@ -108,7 +108,7 @@ sub round(float value) -> float {
|
||||
}
|
||||
|
||||
sub floor(float value) -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.floor.value
|
||||
ffloor.f fr0,fr0
|
||||
return
|
||||
@ -117,7 +117,7 @@ sub floor(float value) -> float {
|
||||
|
||||
sub ceil(float value) -> float {
|
||||
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.f fr0,floats.ceil.value
|
||||
fceil.f fr0,fr0
|
||||
return
|
||||
@ -125,7 +125,7 @@ sub ceil(float value) -> float {
|
||||
}
|
||||
|
||||
sub rndf() -> float {
|
||||
%asm {{
|
||||
%ir {{
|
||||
rnd.f fr0
|
||||
return
|
||||
}}
|
||||
|
@ -41,7 +41,7 @@ prog8_lib {
|
||||
; Returns -1 (255), 0 or 1 depending on wether string1 sorts before, equal or after string2.
|
||||
; Note that you can also directly compare strings and string values with eachother using
|
||||
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,prog8_lib.string_compare.st1
|
||||
loadm.w r1,prog8_lib.string_compare.st2
|
||||
syscall 29
|
||||
|
@ -7,14 +7,14 @@ sys {
|
||||
|
||||
sub reset_system() {
|
||||
; Soft-reset the system back to initial power-on Basic prompt.
|
||||
%asm {{
|
||||
%ir {{
|
||||
syscall 0
|
||||
}}
|
||||
}
|
||||
|
||||
sub wait(uword jiffies) {
|
||||
; --- wait approximately the given number of jiffies (1/60th seconds)
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,sys.wait.jiffies
|
||||
syscall 13
|
||||
}}
|
||||
@ -22,7 +22,7 @@ sys {
|
||||
|
||||
sub waitvsync() {
|
||||
; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
|
||||
%asm {{
|
||||
%ir {{
|
||||
syscall 14
|
||||
}}
|
||||
}
|
||||
@ -61,41 +61,41 @@ sys {
|
||||
|
||||
sub exit(ubyte returnvalue) {
|
||||
; -- immediately exit the program with a return code in the A register
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.b r0,sys.exit.returnvalue
|
||||
syscall 1
|
||||
}}
|
||||
}
|
||||
|
||||
sub set_carry() {
|
||||
%asm {{
|
||||
%ir {{
|
||||
sec
|
||||
}}
|
||||
}
|
||||
|
||||
sub clear_carry() {
|
||||
%asm {{
|
||||
%ir {{
|
||||
clc
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
sub gfx_enable(ubyte mode) {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.b r0,sys.gfx_enable.mode
|
||||
syscall 8
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_clear(ubyte color) {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.b r0,sys.gfx_clear.color
|
||||
syscall 9
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,sys.gfx_plot.xx
|
||||
loadm.w r1,sys.gfx_plot.yy
|
||||
loadm.b r2,sys.gfx_plot.color
|
||||
@ -104,7 +104,7 @@ sys {
|
||||
}
|
||||
|
||||
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,sys.gfx_getpixel.xx
|
||||
loadm.w r1,sys.gfx_getpixel.yy
|
||||
syscall 30
|
||||
|
@ -6,7 +6,7 @@ txt {
|
||||
|
||||
sub clear_screen() {
|
||||
str @shared sequence = "\x1b[2J\x1B[H"
|
||||
%asm {{
|
||||
%ir {{
|
||||
load.w r0,txt.clear_screen.sequence
|
||||
syscall 3
|
||||
}}
|
||||
@ -29,14 +29,14 @@ sub uppercase() {
|
||||
}
|
||||
|
||||
sub chrout(ubyte char) {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.b r0,txt.chrout.char
|
||||
syscall 2
|
||||
}}
|
||||
}
|
||||
|
||||
sub print (str text) {
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,txt.print.text
|
||||
syscall 3
|
||||
}}
|
||||
@ -113,7 +113,7 @@ sub print_w (word value) {
|
||||
sub input_chars (uword buffer) -> ubyte {
|
||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well)
|
||||
; It assumes the keyboard is selected as I/O channel!
|
||||
%asm {{
|
||||
%ir {{
|
||||
loadm.w r0,txt.input_chars.buffer
|
||||
syscall 6
|
||||
return
|
||||
|
@ -167,8 +167,10 @@ internal class BeforeAsmAstChanger(val program: Program,
|
||||
if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && !subroutine.hasRtsInAsm(options.compTarget)) {
|
||||
// make sure the NOT INLINED asm subroutine actually has a rts at the end
|
||||
// (non-asm routines get a Return statement as needed, above)
|
||||
val instruction = if(options.compTarget.name==VMTarget.NAME) " return\n" else " rts\n"
|
||||
mods += IAstModification.InsertLast(InlineAssembly(instruction, Position.DUMMY), subroutine)
|
||||
mods += if(options.compTarget.name==VMTarget.NAME)
|
||||
IAstModification.InsertLast(InlineAssembly(" return\n", true, Position.DUMMY), subroutine)
|
||||
else
|
||||
IAstModification.InsertLast(InlineAssembly(" rts\n", false, Position.DUMMY), subroutine)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ class IntermediateAstMaker(val program: Program) {
|
||||
"%asminclude" -> {
|
||||
val result = loadAsmIncludeFile(directive.args[0].str!!, directive.definingModule.source)
|
||||
val assembly = result.getOrElse { throw it }
|
||||
PtInlineAssembly(assembly, directive.position)
|
||||
PtInlineAssembly(assembly, false, directive.position)
|
||||
}
|
||||
else -> {
|
||||
// other directives don't output any code (but could end up in option flags somewhere else)
|
||||
@ -252,7 +252,7 @@ class IntermediateAstMaker(val program: Program) {
|
||||
}
|
||||
|
||||
private fun transform(srcNode: InlineAssembly): PtInlineAssembly =
|
||||
PtInlineAssembly(srcNode.assembly, srcNode.position)
|
||||
PtInlineAssembly(srcNode.assembly, srcNode.isIR, srcNode.position)
|
||||
|
||||
private fun transform(srcJump: Jump): PtJump {
|
||||
val identifier = if(srcJump.identifier!=null) transform(srcJump.identifier!!) else null
|
||||
@ -306,13 +306,22 @@ class IntermediateAstMaker(val program: Program) {
|
||||
sub.parameters.forEach { it.first.parent=sub }
|
||||
|
||||
if(srcSub.asmAddress==null) {
|
||||
var combinedAsm = ""
|
||||
for (asm in srcSub.statements)
|
||||
combinedAsm += (asm as InlineAssembly).assembly + "\n"
|
||||
if(combinedAsm.isNotEmpty())
|
||||
sub.add(PtInlineAssembly(combinedAsm, srcSub.statements[0].position))
|
||||
else
|
||||
sub.add(PtInlineAssembly("", srcSub.position))
|
||||
var combinedTrueAsm = ""
|
||||
var combinedIrAsm = ""
|
||||
for (asm in srcSub.statements) {
|
||||
asm as InlineAssembly
|
||||
if(asm.isIR)
|
||||
combinedIrAsm += asm.assembly + "\n"
|
||||
else
|
||||
combinedTrueAsm += asm.assembly + "\n"
|
||||
}
|
||||
|
||||
if(combinedTrueAsm.isNotEmpty())
|
||||
sub.add(PtInlineAssembly(combinedTrueAsm, false, srcSub.statements[0].position))
|
||||
if(combinedIrAsm.isNotEmpty())
|
||||
sub.add(PtInlineAssembly(combinedIrAsm, true, srcSub.statements[0].position))
|
||||
if(combinedIrAsm.isEmpty() && combinedTrueAsm.isEmpty())
|
||||
sub.add(PtInlineAssembly("", true, srcSub.position))
|
||||
}
|
||||
|
||||
return sub
|
||||
|
@ -17,7 +17,7 @@ class TestVarious: FunSpec({
|
||||
test("symbol names in inline assembly blocks") {
|
||||
val names1 = InlineAssembly("""
|
||||
|
||||
""", Position.DUMMY).names
|
||||
""", false, Position.DUMMY).names
|
||||
names1 shouldBe emptySet()
|
||||
|
||||
val names2 = InlineAssembly("""
|
||||
@ -29,7 +29,7 @@ label2:
|
||||
; also not these
|
||||
;; ...or these
|
||||
// valid words 123456
|
||||
""", Position.DUMMY).names
|
||||
""", false, Position.DUMMY).names
|
||||
|
||||
names2 shouldBe setOf("label", "lda", "sta", "ea", "value", "label2", "othervalue", "valid", "words")
|
||||
}
|
||||
|
@ -125,6 +125,9 @@ private fun Prog8ANTLRParser.StatementContext.toAst() : Statement {
|
||||
val asm = inlineasm()?.toAst()
|
||||
if(asm!=null) return asm
|
||||
|
||||
val ir = inlineir()?.toAst()
|
||||
if(ir!=null) return ir
|
||||
|
||||
val branchstmt = branch_stmt()?.toAst()
|
||||
if(branchstmt!=null) return branchstmt
|
||||
|
||||
@ -252,7 +255,12 @@ private fun Prog8ANTLRParser.FunctioncallContext.toAst(): FunctionCallExpression
|
||||
|
||||
private fun Prog8ANTLRParser.InlineasmContext.toAst(): InlineAssembly {
|
||||
val text = INLINEASMBLOCK().text
|
||||
return InlineAssembly(text.substring(2, text.length-2), toPosition())
|
||||
return InlineAssembly(text.substring(2, text.length-2), false, toPosition())
|
||||
}
|
||||
|
||||
private fun Prog8ANTLRParser.InlineirContext.toAst(): InlineAssembly {
|
||||
val text = INLINEASMBLOCK().text
|
||||
return InlineAssembly(text.substring(2, text.length-2), true, toPosition())
|
||||
}
|
||||
|
||||
private fun Prog8ANTLRParser.ReturnstmtContext.toAst() : Return {
|
||||
|
@ -616,14 +616,14 @@ class FunctionCallStatement(override var target: IdentifierReference,
|
||||
override fun toString() = "FunctionCallStatement(target=$target, pos=$position)"
|
||||
}
|
||||
|
||||
class InlineAssembly(val assembly: String, override val position: Position) : Statement() {
|
||||
class InlineAssembly(val assembly: String, val isIR: Boolean, override val position: Position) : Statement() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
}
|
||||
|
||||
override fun copy() = InlineAssembly(assembly, position)
|
||||
override fun copy() = InlineAssembly(assembly, isIR, position)
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
|
@ -2,6 +2,17 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
%asm {{
|
||||
lda #99
|
||||
rts
|
||||
}}
|
||||
|
||||
%ir {{
|
||||
nop
|
||||
loadr r1,r2
|
||||
return
|
||||
}}
|
||||
|
||||
ubyte @shared @zp var1 = 42
|
||||
uword @shared @zp var2 = 4242
|
||||
str @shared name = "irmen"
|
||||
|
@ -265,7 +265,7 @@ class IRFileReader {
|
||||
}
|
||||
|
||||
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>")
|
||||
private val inlineAsmPattern = Regex("<INLINEASM POS=(.+)>")
|
||||
private val inlineAsmPattern = Regex("<INLINEASM IR=(.+) POS=(.+)>")
|
||||
private val asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||
@ -299,16 +299,17 @@ class IRFileReader {
|
||||
}
|
||||
|
||||
private fun parseInlineAssembly(startline: String, lines: Iterator<String>): IRInlineAsmChunk {
|
||||
// <INLINEASM POS=[examples/test.p8: line 8 col 6-9]>
|
||||
// <INLINEASM IR=true POS=[examples/test.p8: line 8 col 6-9]>
|
||||
val match = inlineAsmPattern.matchEntire(startline) ?: throw IRParseException("invalid INLINEASM")
|
||||
val pos = parsePosition(match.groupValues[1])
|
||||
val isIr = match.groupValues[1].toBoolean()
|
||||
val pos = parsePosition(match.groupValues[2])
|
||||
val asmlines = mutableListOf<String>()
|
||||
var line = lines.next()
|
||||
while(line!="</INLINEASM>") {
|
||||
asmlines.add(line)
|
||||
line = lines.next()
|
||||
}
|
||||
return IRInlineAsmChunk(asmlines.joinToString("\n"), pos)
|
||||
return IRInlineAsmChunk(asmlines.joinToString("\n"), isIr, pos)
|
||||
}
|
||||
|
||||
private fun parseAsmSubroutine(startline: String, lines: Iterator<String>): IRAsmSubroutine {
|
||||
@ -341,12 +342,15 @@ class IRFileReader {
|
||||
val regsf = parseRegisterOrStatusflag(regstr)
|
||||
returns.add(Pair(dt, regsf))
|
||||
}
|
||||
return IRAsmSubroutine(scopedname,
|
||||
return IRAsmSubroutine(
|
||||
scopedname,
|
||||
parsePosition(pos), if(address=="null") null else address.toUInt(),
|
||||
clobberRegs.toSet(),
|
||||
params,
|
||||
returns,
|
||||
asm.assembly)
|
||||
asm.isIR,
|
||||
asm.assembly
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseSubroutine(startline: String, lines: Iterator<String>, variables: List<StStaticVariable>): IRSubroutine {
|
||||
|
@ -78,7 +78,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
out.write("${dt.toString().lowercase()} $reg\n")
|
||||
}
|
||||
out.write("</PARAMS>\n")
|
||||
out.write("<INLINEASM POS=${it.position}>\n")
|
||||
out.write("<INLINEASM IR=${it.isIR} POS=${it.position}>\n")
|
||||
out.write(it.assembly.trimStart('\r', '\n').trimEnd(' ', '\r', '\n'))
|
||||
out.write("\n</INLINEASM>\n</ASMSUB>\n")
|
||||
}
|
||||
@ -87,7 +87,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
}
|
||||
|
||||
private fun writeInlineAsm(chunk: IRInlineAsmChunk) {
|
||||
out.write("<INLINEASM POS=${chunk.position}>\n")
|
||||
out.write("<INLINEASM IR=${chunk.isIR} POS=${chunk.position}>\n")
|
||||
out.write(chunk.assembly.trimStart('\r', '\n').trimEnd(' ', '\r', '\n'))
|
||||
out.write("\n</INLINEASM>\n")
|
||||
}
|
||||
|
@ -104,13 +104,16 @@ class IRSubroutine(val name: String,
|
||||
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
|
||||
}
|
||||
|
||||
class IRAsmSubroutine(val name: String,
|
||||
val position: Position,
|
||||
val address: UInt?,
|
||||
val clobbers: Set<CpuRegister>,
|
||||
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||
val assembly: String) {
|
||||
class IRAsmSubroutine(
|
||||
val name: String,
|
||||
val position: Position,
|
||||
val address: UInt?,
|
||||
val clobbers: Set<CpuRegister>,
|
||||
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||
val isIR: Boolean,
|
||||
val assembly: String
|
||||
) {
|
||||
init {
|
||||
require('.' in name) { "subroutine name is not scoped: $name" }
|
||||
require(!name.startsWith("main.main.")) { "subroutine name invalid main prefix: $name" }
|
||||
@ -146,7 +149,7 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
|
||||
}
|
||||
}
|
||||
|
||||
class IRInlineAsmChunk(val assembly: String, position: Position): IRCodeChunkBase(position) {
|
||||
class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) {
|
||||
// note: no lines, asm is in the property
|
||||
override fun isEmpty() = assembly.isBlank()
|
||||
override fun isNotEmpty() = assembly.isNotBlank()
|
||||
|
@ -83,7 +83,7 @@ return
|
||||
<PARAMS>
|
||||
uword sys.wait.jiffies
|
||||
</PARAMS>
|
||||
<INLINEASM POS=[library:/prog8lib/virtual/syslib.p8: line 17 col 10-13]>
|
||||
<INLINEASM IR=true POS=[library:/prog8lib/virtual/syslib.p8: line 17 col 10-13]>
|
||||
loadm.w r0,sys.wait.jiffies
|
||||
syscall 13
|
||||
</INLINEASM>
|
||||
|
@ -72,6 +72,7 @@ block_statement:
|
||||
| variabledeclaration
|
||||
| subroutinedeclaration
|
||||
| inlineasm
|
||||
| inlineir
|
||||
| labeldef
|
||||
;
|
||||
|
||||
@ -88,6 +89,7 @@ statement :
|
||||
| branch_stmt
|
||||
| subroutinedeclaration
|
||||
| inlineasm
|
||||
| inlineir
|
||||
| returnstmt
|
||||
| forloop
|
||||
| whileloop
|
||||
@ -229,6 +231,8 @@ literalvalue :
|
||||
|
||||
inlineasm : '%asm' INLINEASMBLOCK;
|
||||
|
||||
inlineir: '%ir' INLINEASMBLOCK;
|
||||
|
||||
inline: 'inline';
|
||||
|
||||
subroutine :
|
||||
|
@ -12,7 +12,7 @@
|
||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||
</options>
|
||||
<keywords keywords="&;->;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" />
|
||||
<keywords2 keywords="%address;%asm;%ir;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved;iso:;petscii:;sc:" />
|
||||
<keywords3 keywords="@requirezp;@shared;@zp;byte;const;float;str;ubyte;uword;bool;void;word" />
|
||||
<keywords4 keywords="abs;all;any;avg;callfar;callrom;cmp;len;lsb;memory;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;reverse;rnd;rndw;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;sgn;sizeof;sort;sqrt16;swap;|>" />
|
||||
</highlighting>
|
||||
|
@ -25,7 +25,7 @@
|
||||
<Keywords name="Folders in comment, middle"></Keywords>
|
||||
<Keywords name="Folders in comment, close"></Keywords>
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
word uword
float
zp shared requirezp</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub romsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat
break return goto</Keywords>
|
||||
<Keywords name="Keywords4">abs all any avg callfar callrom cmp len lsb lsl lsr memory mkword msb peek peekw poke pokew push pushw pop popw rsave rsavex rrestore rrestorex reverse rnd rndw rol rol2 ror ror2 sgn sizeof sort sqrt16 swap</Keywords>
|
||||
<Keywords name="Keywords5">true false
not and or xor
as to downto |></Keywords>
|
||||
|
@ -36,7 +36,7 @@ syn keyword prog8Operator and or to downto as void
|
||||
syn match prog8Directive "\(^\|\s\)%\(output\|launcher\|zeropage\)\>"
|
||||
syn match prog8Directive "\(^\|\s\)%\(zpreserved\|address\|import\|option\)\>"
|
||||
syn match prog8Directive "\(^\|\s\)%\(asmbinary\|asminclude\|breakpoint\)\>"
|
||||
syn match prog8Directive "\(^\|\s\)%asm\>"
|
||||
syn match prog8Directive "\(^\|\s\)%\(asm\|ir\)\>"
|
||||
|
||||
syn match prog8Type "\<\%(u\?byte\|u\?word\|float\|str\|bool\)\>"
|
||||
syn region prog8ArrayType matchgroup=prog8Type
|
||||
|
@ -229,12 +229,16 @@ class VmProgramLoader {
|
||||
program: MutableList<IRInstruction>,
|
||||
symbolAddresses: MutableMap<String, Int>,
|
||||
) {
|
||||
asmChunk.assembly.lineSequence().forEach {
|
||||
val parsed = parseIRCodeLine(it.trim(), program.size, placeholders)
|
||||
if(parsed is IRInstruction)
|
||||
program += parsed
|
||||
else if(parsed is IRCodeLabel)
|
||||
symbolAddresses[parsed.name] = program.size
|
||||
if(asmChunk.isIR) {
|
||||
asmChunk.assembly.lineSequence().forEach {
|
||||
val parsed = parseIRCodeLine(it.trim(), program.size, placeholders)
|
||||
if (parsed is IRInstruction)
|
||||
program += parsed
|
||||
else if (parsed is IRCodeLabel)
|
||||
symbolAddresses[parsed.name] = program.size
|
||||
}
|
||||
} else {
|
||||
throw IRParseException("vm currently does not support real inlined assembly (only IR)': ${asmChunk.position}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,16 @@ class TestVm: FunSpec( {
|
||||
test("vm asmbinary not supported") {
|
||||
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||
val startSub = IRAsmSubroutine("main.asmstart", Position.DUMMY, 0x2000u, emptySet(), emptyList(), emptyList(), "inlined asm here")
|
||||
val startSub = IRAsmSubroutine(
|
||||
"main.asmstart",
|
||||
Position.DUMMY,
|
||||
0x2000u,
|
||||
emptySet(),
|
||||
emptyList(),
|
||||
emptyList(),
|
||||
true,
|
||||
"inlined asm here"
|
||||
)
|
||||
block += startSub
|
||||
program.addBlock(block)
|
||||
shouldThrowWithMessage<IRParseException>("vm currently does not support asmsubs: main.asmstart") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user