mirror of
https://github.com/irmen/prog8.git
synced 2024-07-10 08:28:57 +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() {}
|
override fun printProperties() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ class IRCodeGen(
|
|||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
is PtConditionalBranch -> translate(node)
|
is PtConditionalBranch -> translate(node)
|
||||||
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.position)
|
is PtInlineAssembly -> IRInlineAsmChunk(node.assembly, node.isIR, node.position)
|
||||||
is PtIncludeBinary -> {
|
is PtIncludeBinary -> {
|
||||||
val chunk = IRCodeChunk(node.position)
|
val chunk = IRCodeChunk(node.position)
|
||||||
val data = node.file.readBytes()
|
val data = node.file.readBytes()
|
||||||
@ -979,15 +979,18 @@ class IRCodeGen(
|
|||||||
vmblock += vmsub
|
vmblock += vmsub
|
||||||
}
|
}
|
||||||
is PtAsmSub -> {
|
is PtAsmSub -> {
|
||||||
val assembly = if(child.children.isEmpty()) "" else (child.children.single() as PtInlineAssembly).assembly
|
val assemblyChild = if(child.children.isEmpty()) null else (child.children.single() as PtInlineAssembly)
|
||||||
vmblock += IRAsmSubroutine(child.name, child.position, child.address,
|
vmblock += IRAsmSubroutine(
|
||||||
|
child.name, child.position, child.address,
|
||||||
child.clobbers,
|
child.clobbers,
|
||||||
child.parameters.map { Pair(it.first.type, it.second) }, // note: the name of the asmsub param is not used anymore.
|
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),
|
child.returnTypes.zip(child.retvalRegisters),
|
||||||
assembly)
|
assemblyChild?.isIR==true,
|
||||||
|
assemblyChild?.assembly ?: ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is PtInlineAssembly -> {
|
is PtInlineAssembly -> {
|
||||||
vmblock += IRInlineAsmChunk(child.assembly, child.position)
|
vmblock += IRInlineAsmChunk(child.assembly, child.isIR, child.position)
|
||||||
}
|
}
|
||||||
else -> TODO("BLOCK HAS WEIRD CHILD NODE $child")
|
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
|
; -- 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
|
; 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)
|
; (any non-digit character will terminate the number string that is parsed)
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,conv.str2uword.string
|
loadm.w r0,conv.str2uword.string
|
||||||
syscall 11
|
syscall 11
|
||||||
return
|
return
|
||||||
@ -206,7 +206,7 @@ sub str2word(str string) -> word {
|
|||||||
; -- returns the signed word value of the string number argument in AY
|
; -- 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
|
; 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)
|
; (any non-digit character will terminate the number string that is parsed)
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,conv.str2word.string
|
loadm.w r0,conv.str2word.string
|
||||||
syscall 12
|
syscall 12
|
||||||
return
|
return
|
||||||
|
@ -9,7 +9,7 @@ floats {
|
|||||||
|
|
||||||
sub print_f(float value) {
|
sub print_f(float value) {
|
||||||
; ---- prints the floating point value (without a newline).
|
; ---- prints the floating point value (without a newline).
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.print_f.value
|
loadm.f fr0,floats.print_f.value
|
||||||
syscall 25
|
syscall 25
|
||||||
return
|
return
|
||||||
@ -17,7 +17,7 @@ sub print_f(float value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub pow(float value, float power) -> float {
|
sub pow(float value, float power) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.pow.value
|
loadm.f fr0,floats.pow.value
|
||||||
loadm.f fr1,floats.pow.power
|
loadm.f fr1,floats.pow.power
|
||||||
fpow.f fr0,fr1
|
fpow.f fr0,fr1
|
||||||
@ -26,7 +26,7 @@ sub pow(float value, float power) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub fabs(float value) -> float {
|
sub fabs(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.fabs.value
|
loadm.f fr0,floats.fabs.value
|
||||||
fabs.f fr0,fr0
|
fabs.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -34,7 +34,7 @@ sub fabs(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub sin(float angle) -> float {
|
sub sin(float angle) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.sin.angle
|
loadm.f fr0,floats.sin.angle
|
||||||
fsin.f fr0,fr0
|
fsin.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -42,7 +42,7 @@ sub sin(float angle) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub cos(float angle) -> float {
|
sub cos(float angle) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.cos.angle
|
loadm.f fr0,floats.cos.angle
|
||||||
fcos.f fr0,fr0
|
fcos.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -50,7 +50,7 @@ sub cos(float angle) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub tan(float value) -> float {
|
sub tan(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.tan.value
|
loadm.f fr0,floats.tan.value
|
||||||
ftan.f fr0,fr0
|
ftan.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -58,7 +58,7 @@ sub tan(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub atan(float value) -> float {
|
sub atan(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.atan.value
|
loadm.f fr0,floats.atan.value
|
||||||
fatan.f fr0,fr0
|
fatan.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -66,7 +66,7 @@ sub atan(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub ln(float value) -> float {
|
sub ln(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.ln.value
|
loadm.f fr0,floats.ln.value
|
||||||
fln.f fr0,fr0
|
fln.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -74,7 +74,7 @@ sub ln(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub log2(float value) -> float {
|
sub log2(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.log2.value
|
loadm.f fr0,floats.log2.value
|
||||||
flog.f fr0,fr0
|
flog.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -82,7 +82,7 @@ sub log2(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub sqrt(float value) -> float {
|
sub sqrt(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.sqrt.value
|
loadm.f fr0,floats.sqrt.value
|
||||||
sqrt.f fr0,fr0
|
sqrt.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -100,7 +100,7 @@ sub deg(float angle) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub round(float value) -> float {
|
sub round(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.round.value
|
loadm.f fr0,floats.round.value
|
||||||
fround.f fr0,fr0
|
fround.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -108,7 +108,7 @@ sub round(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub floor(float value) -> float {
|
sub floor(float value) -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.floor.value
|
loadm.f fr0,floats.floor.value
|
||||||
ffloor.f fr0,fr0
|
ffloor.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -117,7 +117,7 @@ sub floor(float value) -> float {
|
|||||||
|
|
||||||
sub ceil(float value) -> float {
|
sub ceil(float value) -> float {
|
||||||
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
|
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.f fr0,floats.ceil.value
|
loadm.f fr0,floats.ceil.value
|
||||||
fceil.f fr0,fr0
|
fceil.f fr0,fr0
|
||||||
return
|
return
|
||||||
@ -125,7 +125,7 @@ sub ceil(float value) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub rndf() -> float {
|
sub rndf() -> float {
|
||||||
%asm {{
|
%ir {{
|
||||||
rnd.f fr0
|
rnd.f fr0
|
||||||
return
|
return
|
||||||
}}
|
}}
|
||||||
|
@ -41,7 +41,7 @@ prog8_lib {
|
|||||||
; Returns -1 (255), 0 or 1 depending on wether string1 sorts before, equal or after string2.
|
; 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
|
; 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).
|
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,prog8_lib.string_compare.st1
|
loadm.w r0,prog8_lib.string_compare.st1
|
||||||
loadm.w r1,prog8_lib.string_compare.st2
|
loadm.w r1,prog8_lib.string_compare.st2
|
||||||
syscall 29
|
syscall 29
|
||||||
|
@ -7,14 +7,14 @@ sys {
|
|||||||
|
|
||||||
sub reset_system() {
|
sub reset_system() {
|
||||||
; Soft-reset the system back to initial power-on Basic prompt.
|
; Soft-reset the system back to initial power-on Basic prompt.
|
||||||
%asm {{
|
%ir {{
|
||||||
syscall 0
|
syscall 0
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub wait(uword jiffies) {
|
sub wait(uword jiffies) {
|
||||||
; --- wait approximately the given number of jiffies (1/60th seconds)
|
; --- wait approximately the given number of jiffies (1/60th seconds)
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,sys.wait.jiffies
|
loadm.w r0,sys.wait.jiffies
|
||||||
syscall 13
|
syscall 13
|
||||||
}}
|
}}
|
||||||
@ -22,7 +22,7 @@ sys {
|
|||||||
|
|
||||||
sub waitvsync() {
|
sub waitvsync() {
|
||||||
; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
|
; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
|
||||||
%asm {{
|
%ir {{
|
||||||
syscall 14
|
syscall 14
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -61,41 +61,41 @@ sys {
|
|||||||
|
|
||||||
sub exit(ubyte returnvalue) {
|
sub exit(ubyte returnvalue) {
|
||||||
; -- immediately exit the program with a return code in the A register
|
; -- immediately exit the program with a return code in the A register
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.b r0,sys.exit.returnvalue
|
loadm.b r0,sys.exit.returnvalue
|
||||||
syscall 1
|
syscall 1
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_carry() {
|
sub set_carry() {
|
||||||
%asm {{
|
%ir {{
|
||||||
sec
|
sec
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub clear_carry() {
|
sub clear_carry() {
|
||||||
%asm {{
|
%ir {{
|
||||||
clc
|
clc
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub gfx_enable(ubyte mode) {
|
sub gfx_enable(ubyte mode) {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.b r0,sys.gfx_enable.mode
|
loadm.b r0,sys.gfx_enable.mode
|
||||||
syscall 8
|
syscall 8
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub gfx_clear(ubyte color) {
|
sub gfx_clear(ubyte color) {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.b r0,sys.gfx_clear.color
|
loadm.b r0,sys.gfx_clear.color
|
||||||
syscall 9
|
syscall 9
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,sys.gfx_plot.xx
|
loadm.w r0,sys.gfx_plot.xx
|
||||||
loadm.w r1,sys.gfx_plot.yy
|
loadm.w r1,sys.gfx_plot.yy
|
||||||
loadm.b r2,sys.gfx_plot.color
|
loadm.b r2,sys.gfx_plot.color
|
||||||
@ -104,7 +104,7 @@ sys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,sys.gfx_getpixel.xx
|
loadm.w r0,sys.gfx_getpixel.xx
|
||||||
loadm.w r1,sys.gfx_getpixel.yy
|
loadm.w r1,sys.gfx_getpixel.yy
|
||||||
syscall 30
|
syscall 30
|
||||||
|
@ -6,7 +6,7 @@ txt {
|
|||||||
|
|
||||||
sub clear_screen() {
|
sub clear_screen() {
|
||||||
str @shared sequence = "\x1b[2J\x1B[H"
|
str @shared sequence = "\x1b[2J\x1B[H"
|
||||||
%asm {{
|
%ir {{
|
||||||
load.w r0,txt.clear_screen.sequence
|
load.w r0,txt.clear_screen.sequence
|
||||||
syscall 3
|
syscall 3
|
||||||
}}
|
}}
|
||||||
@ -29,14 +29,14 @@ sub uppercase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub chrout(ubyte char) {
|
sub chrout(ubyte char) {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.b r0,txt.chrout.char
|
loadm.b r0,txt.chrout.char
|
||||||
syscall 2
|
syscall 2
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub print (str text) {
|
sub print (str text) {
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,txt.print.text
|
loadm.w r0,txt.print.text
|
||||||
syscall 3
|
syscall 3
|
||||||
}}
|
}}
|
||||||
@ -113,7 +113,7 @@ sub print_w (word value) {
|
|||||||
sub input_chars (uword buffer) -> ubyte {
|
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)
|
; ---- 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!
|
; It assumes the keyboard is selected as I/O channel!
|
||||||
%asm {{
|
%ir {{
|
||||||
loadm.w r0,txt.input_chars.buffer
|
loadm.w r0,txt.input_chars.buffer
|
||||||
syscall 6
|
syscall 6
|
||||||
return
|
return
|
||||||
|
@ -167,8 +167,10 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && !subroutine.hasRtsInAsm(options.compTarget)) {
|
if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && !subroutine.hasRtsInAsm(options.compTarget)) {
|
||||||
// make sure the NOT INLINED asm subroutine actually has a rts at the end
|
// make sure the NOT INLINED asm subroutine actually has a rts at the end
|
||||||
// (non-asm routines get a Return statement as needed, above)
|
// (non-asm routines get a Return statement as needed, above)
|
||||||
val instruction = if(options.compTarget.name==VMTarget.NAME) " return\n" else " rts\n"
|
mods += if(options.compTarget.name==VMTarget.NAME)
|
||||||
mods += IAstModification.InsertLast(InlineAssembly(instruction, Position.DUMMY), subroutine)
|
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" -> {
|
"%asminclude" -> {
|
||||||
val result = loadAsmIncludeFile(directive.args[0].str!!, directive.definingModule.source)
|
val result = loadAsmIncludeFile(directive.args[0].str!!, directive.definingModule.source)
|
||||||
val assembly = result.getOrElse { throw it }
|
val assembly = result.getOrElse { throw it }
|
||||||
PtInlineAssembly(assembly, directive.position)
|
PtInlineAssembly(assembly, false, directive.position)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// other directives don't output any code (but could end up in option flags somewhere 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 =
|
private fun transform(srcNode: InlineAssembly): PtInlineAssembly =
|
||||||
PtInlineAssembly(srcNode.assembly, srcNode.position)
|
PtInlineAssembly(srcNode.assembly, srcNode.isIR, srcNode.position)
|
||||||
|
|
||||||
private fun transform(srcJump: Jump): PtJump {
|
private fun transform(srcJump: Jump): PtJump {
|
||||||
val identifier = if(srcJump.identifier!=null) transform(srcJump.identifier!!) else null
|
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 }
|
sub.parameters.forEach { it.first.parent=sub }
|
||||||
|
|
||||||
if(srcSub.asmAddress==null) {
|
if(srcSub.asmAddress==null) {
|
||||||
var combinedAsm = ""
|
var combinedTrueAsm = ""
|
||||||
for (asm in srcSub.statements)
|
var combinedIrAsm = ""
|
||||||
combinedAsm += (asm as InlineAssembly).assembly + "\n"
|
for (asm in srcSub.statements) {
|
||||||
if(combinedAsm.isNotEmpty())
|
asm as InlineAssembly
|
||||||
sub.add(PtInlineAssembly(combinedAsm, srcSub.statements[0].position))
|
if(asm.isIR)
|
||||||
else
|
combinedIrAsm += asm.assembly + "\n"
|
||||||
sub.add(PtInlineAssembly("", srcSub.position))
|
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
|
return sub
|
||||||
|
@ -17,7 +17,7 @@ class TestVarious: FunSpec({
|
|||||||
test("symbol names in inline assembly blocks") {
|
test("symbol names in inline assembly blocks") {
|
||||||
val names1 = InlineAssembly("""
|
val names1 = InlineAssembly("""
|
||||||
|
|
||||||
""", Position.DUMMY).names
|
""", false, Position.DUMMY).names
|
||||||
names1 shouldBe emptySet()
|
names1 shouldBe emptySet()
|
||||||
|
|
||||||
val names2 = InlineAssembly("""
|
val names2 = InlineAssembly("""
|
||||||
@ -29,7 +29,7 @@ label2:
|
|||||||
; also not these
|
; also not these
|
||||||
;; ...or these
|
;; ...or these
|
||||||
// valid words 123456
|
// valid words 123456
|
||||||
""", Position.DUMMY).names
|
""", false, Position.DUMMY).names
|
||||||
|
|
||||||
names2 shouldBe setOf("label", "lda", "sta", "ea", "value", "label2", "othervalue", "valid", "words")
|
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()
|
val asm = inlineasm()?.toAst()
|
||||||
if(asm!=null) return asm
|
if(asm!=null) return asm
|
||||||
|
|
||||||
|
val ir = inlineir()?.toAst()
|
||||||
|
if(ir!=null) return ir
|
||||||
|
|
||||||
val branchstmt = branch_stmt()?.toAst()
|
val branchstmt = branch_stmt()?.toAst()
|
||||||
if(branchstmt!=null) return branchstmt
|
if(branchstmt!=null) return branchstmt
|
||||||
|
|
||||||
@ -252,7 +255,12 @@ private fun Prog8ANTLRParser.FunctioncallContext.toAst(): FunctionCallExpression
|
|||||||
|
|
||||||
private fun Prog8ANTLRParser.InlineasmContext.toAst(): InlineAssembly {
|
private fun Prog8ANTLRParser.InlineasmContext.toAst(): InlineAssembly {
|
||||||
val text = INLINEASMBLOCK().text
|
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 {
|
private fun Prog8ANTLRParser.ReturnstmtContext.toAst() : Return {
|
||||||
|
@ -616,14 +616,14 @@ class FunctionCallStatement(override var target: IdentifierReference,
|
|||||||
override fun toString() = "FunctionCallStatement(target=$target, pos=$position)"
|
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 lateinit var parent: Node
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
this.parent = parent
|
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 replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
|
%asm {{
|
||||||
|
lda #99
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
|
||||||
|
%ir {{
|
||||||
|
nop
|
||||||
|
loadr r1,r2
|
||||||
|
return
|
||||||
|
}}
|
||||||
|
|
||||||
ubyte @shared @zp var1 = 42
|
ubyte @shared @zp var1 = 42
|
||||||
uword @shared @zp var2 = 4242
|
uword @shared @zp var2 = 4242
|
||||||
str @shared name = "irmen"
|
str @shared name = "irmen"
|
||||||
|
@ -265,7 +265,7 @@ class IRFileReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val blockPattern = Regex("<BLOCK NAME=(.+) ADDRESS=(.+) ALIGN=(.+) POS=(.+)>")
|
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 asmsubPattern = Regex("<ASMSUB NAME=(.+) ADDRESS=(.+) CLOBBERS=(.*) RETURNS=(.*) POS=(.+)>")
|
||||||
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
private val subPattern = Regex("<SUB NAME=(.+) RETURNTYPE=(.+) POS=(.+)>")
|
||||||
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
private val posPattern = Regex("\\[(.+): line (.+) col (.+)-(.+)\\]")
|
||||||
@ -299,16 +299,17 @@ class IRFileReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseInlineAssembly(startline: String, lines: Iterator<String>): IRInlineAsmChunk {
|
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 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>()
|
val asmlines = mutableListOf<String>()
|
||||||
var line = lines.next()
|
var line = lines.next()
|
||||||
while(line!="</INLINEASM>") {
|
while(line!="</INLINEASM>") {
|
||||||
asmlines.add(line)
|
asmlines.add(line)
|
||||||
line = lines.next()
|
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 {
|
private fun parseAsmSubroutine(startline: String, lines: Iterator<String>): IRAsmSubroutine {
|
||||||
@ -341,12 +342,15 @@ class IRFileReader {
|
|||||||
val regsf = parseRegisterOrStatusflag(regstr)
|
val regsf = parseRegisterOrStatusflag(regstr)
|
||||||
returns.add(Pair(dt, regsf))
|
returns.add(Pair(dt, regsf))
|
||||||
}
|
}
|
||||||
return IRAsmSubroutine(scopedname,
|
return IRAsmSubroutine(
|
||||||
|
scopedname,
|
||||||
parsePosition(pos), if(address=="null") null else address.toUInt(),
|
parsePosition(pos), if(address=="null") null else address.toUInt(),
|
||||||
clobberRegs.toSet(),
|
clobberRegs.toSet(),
|
||||||
params,
|
params,
|
||||||
returns,
|
returns,
|
||||||
asm.assembly)
|
asm.isIR,
|
||||||
|
asm.assembly
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseSubroutine(startline: String, lines: Iterator<String>, variables: List<StStaticVariable>): IRSubroutine {
|
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("${dt.toString().lowercase()} $reg\n")
|
||||||
}
|
}
|
||||||
out.write("</PARAMS>\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(it.assembly.trimStart('\r', '\n').trimEnd(' ', '\r', '\n'))
|
||||||
out.write("\n</INLINEASM>\n</ASMSUB>\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) {
|
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(chunk.assembly.trimStart('\r', '\n').trimEnd(' ', '\r', '\n'))
|
||||||
out.write("\n</INLINEASM>\n")
|
out.write("\n</INLINEASM>\n")
|
||||||
}
|
}
|
||||||
|
@ -104,13 +104,16 @@ class IRSubroutine(val name: String,
|
|||||||
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
|
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
|
||||||
}
|
}
|
||||||
|
|
||||||
class IRAsmSubroutine(val name: String,
|
class IRAsmSubroutine(
|
||||||
val position: Position,
|
val name: String,
|
||||||
val address: UInt?,
|
val position: Position,
|
||||||
val clobbers: Set<CpuRegister>,
|
val address: UInt?,
|
||||||
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
|
val clobbers: Set<CpuRegister>,
|
||||||
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
val parameters: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||||
val assembly: String) {
|
val returns: List<Pair<DataType, RegisterOrStatusflag>>,
|
||||||
|
val isIR: Boolean,
|
||||||
|
val assembly: String
|
||||||
|
) {
|
||||||
init {
|
init {
|
||||||
require('.' in name) { "subroutine name is not scoped: $name" }
|
require('.' in name) { "subroutine name is not scoped: $name" }
|
||||||
require(!name.startsWith("main.main.")) { "subroutine name invalid main prefix: $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
|
// note: no lines, asm is in the property
|
||||||
override fun isEmpty() = assembly.isBlank()
|
override fun isEmpty() = assembly.isBlank()
|
||||||
override fun isNotEmpty() = assembly.isNotBlank()
|
override fun isNotEmpty() = assembly.isNotBlank()
|
||||||
|
@ -83,7 +83,7 @@ return
|
|||||||
<PARAMS>
|
<PARAMS>
|
||||||
uword sys.wait.jiffies
|
uword sys.wait.jiffies
|
||||||
</PARAMS>
|
</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
|
loadm.w r0,sys.wait.jiffies
|
||||||
syscall 13
|
syscall 13
|
||||||
</INLINEASM>
|
</INLINEASM>
|
||||||
|
@ -72,6 +72,7 @@ block_statement:
|
|||||||
| variabledeclaration
|
| variabledeclaration
|
||||||
| subroutinedeclaration
|
| subroutinedeclaration
|
||||||
| inlineasm
|
| inlineasm
|
||||||
|
| inlineir
|
||||||
| labeldef
|
| labeldef
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ statement :
|
|||||||
| branch_stmt
|
| branch_stmt
|
||||||
| subroutinedeclaration
|
| subroutinedeclaration
|
||||||
| inlineasm
|
| inlineasm
|
||||||
|
| inlineir
|
||||||
| returnstmt
|
| returnstmt
|
||||||
| forloop
|
| forloop
|
||||||
| whileloop
|
| whileloop
|
||||||
@ -229,6 +231,8 @@ literalvalue :
|
|||||||
|
|
||||||
inlineasm : '%asm' INLINEASMBLOCK;
|
inlineasm : '%asm' INLINEASMBLOCK;
|
||||||
|
|
||||||
|
inlineir: '%ir' INLINEASMBLOCK;
|
||||||
|
|
||||||
inline: 'inline';
|
inline: 'inline';
|
||||||
|
|
||||||
subroutine :
|
subroutine :
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||||
</options>
|
</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" />
|
<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" />
|
<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;|>" />
|
<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>
|
</highlighting>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<Keywords name="Folders in comment, middle"></Keywords>
|
<Keywords name="Folders in comment, middle"></Keywords>
|
||||||
<Keywords name="Folders in comment, close"></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="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="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="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>
|
<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\)%\(output\|launcher\|zeropage\)\>"
|
||||||
syn match prog8Directive "\(^\|\s\)%\(zpreserved\|address\|import\|option\)\>"
|
syn match prog8Directive "\(^\|\s\)%\(zpreserved\|address\|import\|option\)\>"
|
||||||
syn match prog8Directive "\(^\|\s\)%\(asmbinary\|asminclude\|breakpoint\)\>"
|
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 match prog8Type "\<\%(u\?byte\|u\?word\|float\|str\|bool\)\>"
|
||||||
syn region prog8ArrayType matchgroup=prog8Type
|
syn region prog8ArrayType matchgroup=prog8Type
|
||||||
|
@ -229,12 +229,16 @@ class VmProgramLoader {
|
|||||||
program: MutableList<IRInstruction>,
|
program: MutableList<IRInstruction>,
|
||||||
symbolAddresses: MutableMap<String, Int>,
|
symbolAddresses: MutableMap<String, Int>,
|
||||||
) {
|
) {
|
||||||
asmChunk.assembly.lineSequence().forEach {
|
if(asmChunk.isIR) {
|
||||||
val parsed = parseIRCodeLine(it.trim(), program.size, placeholders)
|
asmChunk.assembly.lineSequence().forEach {
|
||||||
if(parsed is IRInstruction)
|
val parsed = parseIRCodeLine(it.trim(), program.size, placeholders)
|
||||||
program += parsed
|
if (parsed is IRInstruction)
|
||||||
else if(parsed is IRCodeLabel)
|
program += parsed
|
||||||
symbolAddresses[parsed.name] = program.size
|
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") {
|
test("vm asmbinary not supported") {
|
||||||
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
|
||||||
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
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
|
block += startSub
|
||||||
program.addBlock(block)
|
program.addBlock(block)
|
||||||
shouldThrowWithMessage<IRParseException>("vm currently does not support asmsubs: main.asmstart") {
|
shouldThrowWithMessage<IRParseException>("vm currently does not support asmsubs: main.asmstart") {
|
||||||
|
Loading…
Reference in New Issue
Block a user