deal with 'bra' better on 65c02

This commit is contained in:
Irmen de Jong 2021-02-28 16:15:49 +01:00
parent 8e3ebc84f0
commit 7e3e18a5c7
9 changed files with 51 additions and 37 deletions

View File

@ -420,7 +420,7 @@ _print_byte_digits
jsr c64.CHROUT
pla
jsr c64.CHROUT
jmp _ones
bra _ones
+ pla
cmp #'0'
beq _ones
@ -443,7 +443,7 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
jsr c64.CHROUT
+ pla
jsr conv.byte2decimal
jmp print_ub._print_byte_digits
bra print_ub._print_byte_digits
}}
}
@ -494,7 +494,7 @@ asmsub print_uwbin (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
jsr print_ubbin
pla
clc
jmp print_ubbin
bra print_ubbin
}}
}
@ -507,7 +507,7 @@ asmsub print_uwhex (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
jsr print_ubhex
pla
clc
jmp print_ubhex
bra print_ubhex
}}
}
@ -570,7 +570,7 @@ asmsub print_w (word value @ AY) clobbers(A,Y) {
adc #1
bcc +
iny
+ jmp print_uw
+ bra print_uw
}}
}

View File

@ -218,13 +218,13 @@ internal class AstChecker(private val program: Program,
err("subroutines can only have one return value")
// subroutine must contain at least one 'return' or 'goto'
// (or if it has an asm block, that must contain a 'rts' or 'jmp')
// (or if it has an asm block, that must contain a 'rts' or 'jmp' or 'bra')
if(subroutine.statements.count { it is Return || it is Jump } == 0) {
if (subroutine.amountOfRtsInAsm() == 0) {
if (subroutine.returntypes.isNotEmpty()) {
// for asm subroutines with an address, no statement check is possible.
if (subroutine.asmAddress == null && !subroutine.inline)
err("non-inline subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
err("non-inline subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or rts/jmp/bra in case of %asm)")
}
}
}

View File

@ -1024,7 +1024,7 @@ $repeatLabel lda $counterVar
+ dec $counterVar
""")
translate(body)
out(" jmp $repeatLabel")
jmp(repeatLabel)
if(constIterations!=null && constIterations>=16 && zeropage.available() > 1) {
// allocate count var on ZP
val zpAddr = zeropage.allocate(counterVar, DataType.UWORD, body.position, errors)
@ -1378,6 +1378,13 @@ $label nop""")
return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables
}
internal fun jmp(asmLabel: String) {
if(isTargetCpu(CpuType.CPU65c02))
out(" bra $asmLabel") // note: 64tass will convert this automatically to a jmp if the relative distance is too large
else
out(" jmp $asmLabel")
}
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: Expression): Pair<Expression, Expression>? {
if(pointerOffsetExpr is BinaryExpression && pointerOffsetExpr.operator=="+") {
val leftDt = pointerOffsetExpr.left.inferType(program)

View File

@ -19,7 +19,7 @@ private val alwaysKeepSubroutines = setOf(
Pair("main", "start")
)
private val asmJumpRx = Regex("""[\-+a-zA-Z0-9_ \t]+(jmp|jsr)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE)
private val asmJumpRx = Regex("""[\-+a-zA-Z0-9_ \t]+(jmp|jsr|bra)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE)
private val asmRefRx = Regex("""[\-+a-zA-Z0-9_ \t]+(...)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE)
@ -178,7 +178,7 @@ class CallGraph(private val program: Program, private val asmFileLoader: (filena
}
override fun visit(inlineAssembly: InlineAssembly) {
// parse inline asm for subroutine calls (jmp, jsr)
// parse inline asm for subroutine calls (jmp, jsr, bra)
val scope = inlineAssembly.definingSubroutine()
scanAssemblyCode(inlineAssembly.assembly, inlineAssembly, scope)
super.visit(inlineAssembly)

View File

@ -728,7 +728,7 @@ class Subroutine(override val name: String,
.asSequence()
.filter { it is InlineAssembly }
.map { (it as InlineAssembly).assembly }
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it }
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it || " bra" in it || "\tbra" in it}
}

View File

@ -592,7 +592,7 @@ flag such as Carry (Pc).
Asmsubs can also be tagged as ``inline asmsub`` to make trivial pieces of assembly inserted
directly instead of a call to them. Note that it is literal copy-paste of code that is done,
so make sure the assembly is actually written to behave like such - which probably means you
don't want a ``rts`` or ``jmp`` in it!
don't want a ``rts`` or ``jmp`` or ``bra`` in it!
.. note::

View File

@ -2,6 +2,8 @@
TODO
====
- on 65C02 target; replace all jmp by bra (64tass will sort it out if the jump exceeds relative distance)
- optimize assigning array and struct variables (multi-element assings -> memcopy)
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
- optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2))

View File

@ -64,25 +64,25 @@ main {
asmsub print_number_gfx(ubyte num @ A) clobbers(A,Y) {
%asm {{
phx
jsr conv.ubyte2decimal
phx
pha
cpy #'0'
beq +
tya
jsr cx16.GRAPH_put_char
pla
jsr cx16.GRAPH_put_char
jmp _ones
+ pla
phx
jsr conv.ubyte2decimal
phx
pha
cpy #'0'
beq +
tya
jsr cx16.GRAPH_put_char
pla
jsr cx16.GRAPH_put_char
bra _ones
+ pla
cmp #'0'
beq _ones
jsr cx16.GRAPH_put_char
_ones pla
jsr cx16.GRAPH_put_char
plx
rts
_ones pla
jsr cx16.GRAPH_put_char
plx
rts
}}
}

View File

@ -4,15 +4,20 @@
main {
sub start() {
uword screen = 2000
ubyte i = 1
uword w = 33
str derp ="derp"
ubyte[] array = [1,2,3]
uword xx1
uword xx2
uword xx3
uword total
@(screen+i) = 128
@(i+screen) = 129
txt.print("done\n")
c64.SETTIM(0,0,0)
repeat 600 {
repeat 600 {
xx1++
xx2++
xx3++
}
}
uword time = c64.RDTIM16()
txt.print_uw(time)
}
}