fix double %option merge problem where it deleted all of the blocks

This commit is contained in:
Irmen de Jong 2024-11-03 13:26:28 +01:00
parent 66fc109ce5
commit 9f84aa5fb2
6 changed files with 75 additions and 68 deletions

View File

@ -734,8 +734,9 @@ asmsub vpeek(ubyte bank @A, uword address @XY) -> ubyte @A {
}
asmsub vaddr(ubyte bank @A, uword address @R0, ubyte addrsel @R1, byte autoIncrOrDecrByOne @Y) clobbers(A) {
; -- setup the VERA's data address register 0 or 1
; with optional auto increment or decrement of 1.
; -- setup the VERA's data address register 0 or 1 with optional auto increment or decrement of 1.
; This is a convenience routine, and not very efficient if you call it often;
; it's usually better to write a tailor made version of it that accounts for the repeated values.
; Note that the vaddr_autoincr() and vaddr_autodecr() routines allow to set all possible strides, not just 1.
; Note also that Vera's addrset is reset to 0 on exit, even if you set port #1's address.
%asm {{
@ -764,6 +765,8 @@ asmsub vaddr(ubyte bank @A, uword address @R0, ubyte addrsel @R1, byte autoIncrO
asmsub vaddr_clone(ubyte port @A) clobbers (A,X,Y) {
; -- clones Vera addresses from the given source port to the other one.
; This is a convenience routine, and not very efficient if you call it often;
; it's usually better to write a tailor made version of it that accounts for the repeated values.
%asm {{
sta VERA_CTRL
ldx VERA_ADDR_L
@ -783,9 +786,10 @@ asmsub vaddr_clone(ubyte port @A) clobbers (A,X,Y) {
}
asmsub vaddr_autoincr(ubyte bank @A, uword address @R0, ubyte addrsel @R1, uword autoIncrAmount @R2) clobbers(A,Y) {
; -- setup the VERA's data address register 0 or 1
; including setting up optional auto increment amount.
; -- setup the VERA's data address register 0 or 1, including setting up optional auto increment amount.
; Specifiying an unsupported amount results in amount of zero. See the Vera docs about what amounts are possible.
; This is a convenience routine, and not very efficient if you call it often;
; it's usually better to write a tailor made version of it that accounts for the repeated values.
%asm {{
jsr _setup
lda cx16.r2H
@ -847,9 +851,10 @@ _strides_lsb .byte 0,1,2,4,8,16,32,64,128,255,255,40,80,160,255,255
}
asmsub vaddr_autodecr(ubyte bank @A, uword address @R0, ubyte addrsel @R1, uword autoDecrAmount @R2) clobbers(A,Y) {
; -- setup the VERA's data address register 0 or 1
; including setting up optional auto decrement amount.
; -- setup the VERA's data address register 0 or 1 including setting up optional auto decrement amount.
; Specifiying an unsupported amount results in amount of zero. See the Vera docs about what amounts are possible.
; This is a convenience routine, and not very efficient if you call it often;
; it's usually better to write a tailor made version of it that accounts for the repeated values.
%asm {{
jsr vaddr_autoincr._setup
lda cx16.r2H

View File

@ -11,6 +11,8 @@ class BlockMerger(val errors: IErrorReporter) {
// will be joined into a block with the same name, coming from a library.
// (or a normal block if no library block with that name was found)
private val mergedBlocks = mutableSetOf<Block>() // to make sure blocks aren't merged more than once
fun visit(program: Program) {
val allBlocks = program.allBlocks
for(block in allBlocks) {
@ -31,6 +33,9 @@ class BlockMerger(val errors: IErrorReporter) {
}
private fun merge(block: Block, target: Block) {
if(block===target || block in mergedBlocks || target in mergedBlocks)
return
val named = target.statements.filterIsInstance<Subroutine>().associateBy { it.name }
for(stmt in block.statements.filter { it !is Directive }) {
@ -47,7 +52,9 @@ class BlockMerger(val errors: IErrorReporter) {
target.statements.add(stmt)
stmt.parent = target
}
block.statements.clear()
block.definingScope.remove(block)
mergedBlocks.add(block)
}
}

View File

@ -135,5 +135,34 @@ main {
compileText(VMTarget(), optimize = false, src) shouldNotBe null
}
test("double merge works") {
val src="""
main {
sub start() {
block1.sub1()
block1.sub2()
}
}
block1 {
%option merge
sub sub1() {
cx16.r1++
}
}
block1 {
%option merge
sub sub2() {
cx16.r2++
}
}"""
compileText(VMTarget(), optimize = false, src) shouldNotBe null
}
})

View File

@ -724,7 +724,7 @@ Multiple return values
^^^^^^^^^^^^^^^^^^^^^^
Normal subroutines can only return zero or one return values.
However, the special ``asmsub`` routines (implemented in assembly code) or ``romsub`` routines
(referencing an external routine in ROM or elsewhere in memory) can return more than one return value.
(referencing an external routine in ROM or elsewhere in RAM) can return more than one return value.
For example a status in the carry bit and a number in A, or a 16-bit value in A/Y registers and some more values in R0 and R1.
In all of these cases, you have to "multi assign" all return values of the subroutine call to something.
You simply write the assignment targets as a comma separated list,
@ -784,14 +784,19 @@ The return type has to be specified if the subroutine returns a value.
Assembly / ROM subroutines
^^^^^^^^^^^^^^^^^^^^^^^^^^^
External subroutines implemented in ROM (or elsewhere in memory) are usually defined by compiler library files, with the following syntax::
External subroutines implemented in ROM are usually defined by compiler library files, with the following syntax::
romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> clobbers() -> bool @Pc, ubyte @ A, ubyte @ X, ubyte @ Y
romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) clobbers()
-> bool @Pc, ubyte @ A, ubyte @ X, ubyte @ Y
This defines the ``LOAD`` subroutine at memory address $FFD5, taking arguments in all three registers A, X and Y,
and returning stuff in several registers as well. The ``clobbers`` clause is used to signify to the compiler
what CPU registers are clobbered by the call instead of being unchanged or returning a meaningful result value.
.. note::
Unlike what it's name may suggest, ``romsub`` can also define an external subroutine elsewhere in normal RAM.
It's just that you explicitly define the memory address where it is located and it doesn't matter if that is in ROM or in RAM.
User-written subroutines in the program source code itself, implemented purely in assembly and which have an assembly calling convention (i.e.
the parameters are strictly passed via cpu registers), are defined with ``asmsub`` like this::

View File

@ -1,8 +1,6 @@
TODO
====
merge problem: if 2 library modules both have merge, stuff breaks (math & prog8_math where prog8_math used to have math block.... didn't work)
for releasenotes: gfx2.width and gfx2.height got renamed as gfx_lores.WIDTH/HEIGHT or gfx_hires4.WIDTH/HEIGTH constants. Screen mode routines also renamed.
regenerate symbol dump files

View File

@ -5,62 +5,25 @@
main {
sub start() {
cx16.r0=0
if cx16.r0==0
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0==0 42 else 99
if cx16.r0==33
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0==33 42 else 99
if cx16.r0!=3333
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=3333 42 else 99
if cx16.r0!=0
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=0 42 else 99
if cx16.r0!=33
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=0 42 else 99
if cx16.r0==cx16.r9
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0==cx16.r9 42 else 99
if cx16.r0!=cx16.r9
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=cx16.r9 42 else 99
if cx16.r0>cx16.r1
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0>cx16.r1 42 else 99
block1.sub1()
block1.sub2()
}
}
block1 {
%option merge
sub sub1() {
txt.print("sub1")
}
}
block1 {
%option merge
sub sub2() {
txt.print("sub2")
}
}