1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-28 16:31:36 +00:00

Fixed problem with volatile booleans being allocated to registers. Closes #153

This commit is contained in:
jespergravgaard 2019-03-27 22:54:01 +01:00
parent c696d9610e
commit c81147f60f
15 changed files with 7167 additions and 1 deletions

View File

@ -54,7 +54,7 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
potentials.add(Registers.getRegisterX());
potentials.add(Registers.getRegisterY());
}
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varRefExtracted(equivalenceClass)) {
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varRefExtracted(equivalenceClass) &&!varVolatile(equivalenceClass)) {
potentials.add(Registers.getRegisterA());
}
registerPotentials.setPotentialRegisters(equivalenceClass, potentials);

View File

@ -32,6 +32,15 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testMultiplexerIrq() throws IOException, URISyntaxException {
compileAndCompare("multiplexer-irq/simple-multiplexer-irq", 10);
}
@Test
public void testIrqVolatileProblem() throws IOException, URISyntaxException {
compileAndCompare("irq-volatile-bool-problem");
}
@Test
public void testMusicIrq() throws IOException, URISyntaxException {

View File

@ -0,0 +1,43 @@
// Illustrates a problem where a volatile bool modified at the end of an IRQ is not stored properly
// because it is assigned to the A register
const void()** KERNEL_IRQ = $0314;
const byte* RASTER = $d012;
const byte* VIC_CONTROL = $d011;
const byte* IRQ_STATUS = $d019;
const byte* IRQ_ENABLE = $d01a;
const byte IRQ_RASTER = %00000001;
const byte* BGCOL = $d020;
const byte* CIA1_INTERRUPT = $dc0d;
const byte CIA_INTERRUPT_CLEAR = $7f;
void main() {
asm { sei }
// Disable CIA 1 Timer IRQ
*CIA1_INTERRUPT = CIA_INTERRUPT_CLEAR;
// Set raster line to $0fd
*VIC_CONTROL &=$7f;
*RASTER = $fd;
// Enable Raster Interrupt
*IRQ_ENABLE = IRQ_RASTER;
// Set the IRQ routine
*KERNEL_IRQ = &irq;
asm { cli }
while(true) {
if(*RASTER<20)
framedone = true;
}
}
volatile bool framedone = false;
interrupt(kernel_min) void irq() {
(*BGCOL)++;
*IRQ_STATUS = IRQ_RASTER;
if (*RASTER>50) {
framedone = false;
}
(*BGCOL)--;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

View File

@ -0,0 +1,140 @@
// A flexible sprite multiplexer routine for 32 sprites.
// Usage:
// - Once:
// - plexInit(screen): Initialize the data structures and set the screen address
// Each frame:
// - Set x-pos, y-pos and pointer in PLEX_XPOS[id], PLEX_YPOS[id], PLEX_PTR[id]
// - plexSort() Sorts the sprites according to y-positions and prepares for showing them. This uses an insertion sort that is quite fast when the relative order of the sprites does not change very much.
// - plexShowSprite() Shows the next sprite by copying values from PLEX_XXX[] to an actual sprite. Actual sprites are used round-robin. This should be called once for each of the 24 virtual sprites.
// - plexFreeNextYpos() Returns the Y-position where the next sprite is available to be shown (ie. the next pos where the next sprite is no longer in use showing something else).
// - plexShowNextYpos() Returns the Y-position of the next sprite to show.
//
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 32 sprites have been shown.
// TODO: Let the caller specify the number of sprites to use (or add PLEX_ENABLE[PLEX_COUNT])
import "c64"
// The number of sprites in the multiplexer
const byte PLEX_COUNT = 32;
// The x-positions of the multiplexer sprites ($000-$1ff)
word[PLEX_COUNT] PLEX_XPOS;
// The y-positions of the multiplexer sprites.
byte[PLEX_COUNT] PLEX_YPOS;
// The sprite pointers for the multiplexed sprites
byte[PLEX_COUNT] PLEX_PTR;
// The address of the sprite pointers on the current screen (screen+$3f8).
byte* PLEX_SCREEN_PTR = $400+$3f8;
// Indexes of the plex-sprites sorted by sprite y-position. Each call to plexSort() will fix the sorting if changes to the Y-positions have ruined it.
byte[PLEX_COUNT] PLEX_SORTED_IDX;
// Variables controlling the showing of sprites
// The index in the PLEX tables of the next sprite to show
volatile byte plex_show_idx=0;
// The index the next sprite to use for showing (sprites are used round-robin)
volatile byte plex_sprite_idx=0;
// The MSB bit of the next sprite to use for showing
volatile byte plex_sprite_msb=1;
// Initialize the multiplexer data structures
void plexInit(byte* screen) {
plexSetScreen(screen);
for(byte i: 0..PLEX_COUNT-1) {
PLEX_SORTED_IDX[i] = i;
}
}
// Set the address of the current screen used for setting sprite pointers (at screen+$3f8)
inline void plexSetScreen(byte* screen) {
PLEX_SCREEN_PTR = screen+$3f8;
}
// Ensure that the indices in PLEX_SORTED_IDX is sorted based on the y-positions in PLEX_YPOS
// Assumes that the positions are nearly sorted already (as each sprite just moves a bit)
// Uses an insertion sort:
// 1. Moves a marker (m) from the start to end of the array. Every time the marker moves forward all elements before the marker are sorted correctly.
// 2a. If the next element after the marker is larger that the current element
// the marker can be moved forwards (as the sorting is correct).
// 2b. If the next element after the marker is smaller than the current element:
// elements before the marker are shifted right one at a time until encountering one smaller than the current one.
// It is then inserted at the spot. Now the marker can move forward.
void plexSort() {
for(byte m: 0..PLEX_COUNT-2) {
byte nxt_idx = PLEX_SORTED_IDX[m+1];
byte nxt_y = PLEX_YPOS[nxt_idx];
if(nxt_y<PLEX_YPOS[PLEX_SORTED_IDX[m]]) {
// Shift values until we encounter a value smaller than nxt_y
byte s = m;
do {
PLEX_SORTED_IDX[s+1] = PLEX_SORTED_IDX[s];
s--;
} while((s!=$ff) && (nxt_y<PLEX_YPOS[PLEX_SORTED_IDX[s]]));
// store the mark at the found position
s++;
PLEX_SORTED_IDX[s] = nxt_idx;
}
}
// Prepare for showing the sprites
plex_show_idx = 0;
plex_sprite_idx = 0;
plex_sprite_msb = 1;
plexFreePrepare();
}
// Show the next sprite.
// plexSort() prepares showing the sprites
void plexShowSprite() {
byte plex_sprite_idx2 = plex_sprite_idx<<1;
byte ypos = PLEX_YPOS[PLEX_SORTED_IDX[plex_show_idx]];
SPRITES_YPOS[plex_sprite_idx2] = ypos;
plexFreeAdd(ypos);
PLEX_SCREEN_PTR[plex_sprite_idx] = PLEX_PTR[PLEX_SORTED_IDX[plex_show_idx]];
byte xpos_idx = PLEX_SORTED_IDX[plex_show_idx]<<1;
SPRITES_XPOS[plex_sprite_idx2] = <PLEX_XPOS[xpos_idx];
if(>PLEX_XPOS[xpos_idx]!=0) {
*SPRITES_XMSB |= plex_sprite_msb;
} else {
*SPRITES_XMSB &= ($ff^plex_sprite_msb);
}
plex_sprite_idx = (plex_sprite_idx+1)&7;
plex_show_idx++;
plex_sprite_msb <<=1;
if(plex_sprite_msb==0) {
plex_sprite_msb = 1;
}
}
// Get the y-position of the next sprite to show
inline byte plexShowNextYpos() {
return PLEX_YPOS[PLEX_SORTED_IDX[plex_show_idx]];
}
// Contains the Y-position where each sprite is free again. PLEX_FREE_YPOS[s] holds the Y-position where sprite s is free to use again.
byte[8] PLEX_FREE_YPOS;
// The index of the sprite that is free next. Since sprites are used round-robin this moves forward each time a sprite is shown.
volatile byte plex_free_next = 0;
// Prepare for a new frame. Initialize free to zero for all sprites.
inline void plexFreePrepare() {
for( byte s: 0..7) {
PLEX_FREE_YPOS[s] = 0;
}
plex_free_next = 0;
}
// Get the Y-position where the next sprite to be shown is free to use.
inline byte plexFreeNextYpos() {
return PLEX_FREE_YPOS[plex_free_next];
}
// Update the data structure to reflect that a sprite has been shown. This sprite will be free again after 21 lines.
inline void plexFreeAdd(byte ypos) {
PLEX_FREE_YPOS[plex_free_next] = ypos+21;
plex_free_next = (plex_free_next+1)&7;
}

View File

@ -0,0 +1,96 @@
// A simple usage of the flexible sprite multiplexer routine
import "c64"
import "multiplexer-irq"
// Location of screen & sprites
byte* SCREEN = $400;
byte* SPRITE = $2000;
byte* YSIN = $2100;
kickasm(pc YSIN) {{
.var min = 50
.var max = 250-21
.var ampl = max-min;
.for(var i=0;i<256;i++)
.byte round(min+(ampl/2)+(ampl/2)*sin(toRadians(360*i/256)))
}}
kickasm(pc SPRITE, resource "balloon.png") {{
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
void main() {
asm { sei }
init();
loop();
}
// Initialize the program
void init() {
*D011 = VIC_DEN | VIC_RSEL | 3;
// Initialize the multiplexer
plexInit(SCREEN);
// Set the x-positions & pointers
word xp = 32;
for(byte sx: 0..PLEX_COUNT-1) {
PLEX_PTR[sx] = (byte)(SPRITE/$40);
PLEX_XPOS[sx<<1] = xp;
xp += 9;
}
// Enable & initialize sprites
*SPRITES_ENABLE = $ff;
for(byte ss: 0..7) {
SPRITES_COLS[ss] = GREEN;
}
// enable the interrupt
asm { sei }
*CIA1_INTERRUPT = CIA_INTERRUPT_CLEAR;
*IRQ_ENABLE = IRQ_RASTER;
*IRQ_STATUS = IRQ_RASTER;
*KERNEL_IRQ = &plex_irq;
asm { cli }
}
volatile bool framedone = true;
interrupt(kernel_min) void plex_irq() {
byte rasterY;
*BORDERCOL = WHITE;
do {
plexShowSprite();
rasterY = plexFreeNextYpos();
} while (plex_show_idx < PLEX_COUNT && rasterY < *RASTER+2);
*IRQ_STATUS = IRQ_RASTER;
if (plex_show_idx<PLEX_COUNT) {
*RASTER = rasterY;
} else {
framedone = true;
}
*BORDERCOL = 0;
}
// The raster loop
void loop() {
// The current index into the y-sinus
volatile byte sin_idx = 0; // without volatile gives wrong asm
while(true) {
while(!framedone) { }
*BORDERCOL = RED;
// Assign sinus positions
volatile byte y_idx = sin_idx; // without volatile gives wrong asm
for(byte sy: 0..PLEX_COUNT-1) {
PLEX_YPOS[sy] = YSIN[y_idx];
y_idx += 8;
}
sin_idx +=1;
// Sort the sprites by y-position
(*BORDERCOL)++;
plexSort();
*BORDERCOL = GREEN;
framedone = false;
*VIC_CONTROL &=$7f;
*RASTER = $0;
}
}

View File

@ -0,0 +1,61 @@
// Illustrates a problem where a volatile bool modified at the end of an IRQ is not stored properly
// because it is assigned to the A register
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
.label KERNEL_IRQ = $314
.label RASTER = $d012
.label VIC_CONTROL = $d011
.label IRQ_STATUS = $d019
.label IRQ_ENABLE = $d01a
.const IRQ_RASTER = 1
.label BGCOL = $d020
.label CIA1_INTERRUPT = $dc0d
.const CIA_INTERRUPT_CLEAR = $7f
.label framedone = 2
bbegin:
lda #0
sta framedone
jsr main
main: {
sei
// Disable CIA 1 Timer IRQ
lda #CIA_INTERRUPT_CLEAR
sta CIA1_INTERRUPT
// Set raster line to $0fd
lda #$7f
and VIC_CONTROL
sta VIC_CONTROL
lda #$fd
sta RASTER
// Enable Raster Interrupt
lda #IRQ_RASTER
sta IRQ_ENABLE
// Set the IRQ routine
lda #<irq
sta KERNEL_IRQ
lda #>irq
sta KERNEL_IRQ+1
cli
b2:
lda RASTER
cmp #$14
bcs b2
lda #1
sta framedone
jmp b2
}
irq: {
inc BGCOL
lda #IRQ_RASTER
sta IRQ_STATUS
lda RASTER
cmp #$32
bcc b1
beq b1
lda #0
sta framedone
b1:
dec BGCOL
jmp $ea81
}

View File

@ -0,0 +1,41 @@
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] (bool) framedone#11 ← false
to:@2
@2: scope:[] from @1
[2] phi()
[3] call main
to:@end
@end: scope:[] from @2
[4] phi()
main: scope:[main] from @2
asm { sei }
[6] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0
[7] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f
[8] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd
[9] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0
[10] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq()
asm { cli }
to:main::@2
main::@2: scope:[main] from main main::@2 main::@7
[12] if(*((const byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@2
to:main::@7
main::@7: scope:[main] from main::@2
[13] (bool) framedone#0 ← true
to:main::@2
irq: scope:[irq] from
[14] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0)
[15] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0
[16] if(*((const byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1
to:irq::@2
irq::@2: scope:[irq] from irq
[17] (bool) framedone#3 ← false
to:irq::@1
irq::@1: scope:[irq] from irq irq::@2
[18] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0)
to:irq::@return
irq::@return: scope:[irq] from irq::@1
[19] return
to:@return

View File

@ -0,0 +1,675 @@
Resolved forward reference irq to interrupt(KERNEL_MIN)(void()) irq()
Resolved forward reference framedone to (bool) framedone
CONTROL FLOW GRAPH SSA
@begin: scope:[] from
(void()**) KERNEL_IRQ#0 ← ((void()**)) (word/signed word/dword/signed dword) $314
(byte*) RASTER#0 ← ((byte*)) (word/dword/signed dword) $d012
(byte*) VIC_CONTROL#0 ← ((byte*)) (word/dword/signed dword) $d011
(byte*) IRQ_STATUS#0 ← ((byte*)) (word/dword/signed dword) $d019
(byte*) IRQ_ENABLE#0 ← ((byte*)) (word/dword/signed dword) $d01a
(byte) IRQ_RASTER#0 ← (byte/signed byte/word/signed word/dword/signed dword) 1
(byte*) BGCOL#0 ← ((byte*)) (word/dword/signed dword) $d020
(byte*) CIA1_INTERRUPT#0 ← ((byte*)) (word/dword/signed dword) $dc0d
(byte) CIA_INTERRUPT_CLEAR#0 ← (byte/signed byte/word/signed word/dword/signed dword) $7f
to:@1
main: scope:[main] from @2
(bool) framedone#12 ← phi( @2/(bool) framedone#11 )
asm { sei }
*((byte*) CIA1_INTERRUPT#0) ← (byte) CIA_INTERRUPT_CLEAR#0
*((byte*) VIC_CONTROL#0) ← *((byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f
*((byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd
*((byte*) IRQ_ENABLE#0) ← (byte) IRQ_RASTER#0
(void()*~) main::$0 ← & interrupt(KERNEL_MIN)(void()) irq()
*((void()**) KERNEL_IRQ#0) ← (void()*~) main::$0
asm { cli }
to:main::@1
main::@1: scope:[main] from main main::@4 main::@7
(bool) framedone#9 ← phi( main/(bool) framedone#12 main::@4/(bool) framedone#13 main::@7/(bool) framedone#0 )
if(true) goto main::@2
to:main::@return
main::@2: scope:[main] from main::@1
(bool) framedone#15 ← phi( main::@1/(bool) framedone#9 )
(bool~) main::$1 ← *((byte*) RASTER#0) < (byte/signed byte/word/signed word/dword/signed dword) $14
(bool~) main::$2 ← ! (bool~) main::$1
if((bool~) main::$2) goto main::@4
to:main::@7
main::@4: scope:[main] from main::@2
(bool) framedone#13 ← phi( main::@2/(bool) framedone#15 )
to:main::@1
main::@7: scope:[main] from main::@2
(bool) framedone#0 ← true
to:main::@1
main::@return: scope:[main] from main::@1
(bool) framedone#6 ← phi( main::@1/(bool) framedone#9 )
(bool) framedone#1 ← (bool) framedone#6
return
to:@return
@1: scope:[] from @begin
(bool) framedone#2 ← false
to:@2
irq: scope:[irq] from
(bool) framedone#14 ← phi( @2/(bool) framedone#11 )
*((byte*) BGCOL#0) ← ++ *((byte*) BGCOL#0)
*((byte*) IRQ_STATUS#0) ← (byte) IRQ_RASTER#0
(bool~) irq::$0 ← *((byte*) RASTER#0) > (byte/signed byte/word/signed word/dword/signed dword) $32
(bool~) irq::$1 ← ! (bool~) irq::$0
if((bool~) irq::$1) goto irq::@1
to:irq::@2
irq::@1: scope:[irq] from irq irq::@2
(bool) framedone#10 ← phi( irq/(bool) framedone#14 irq::@2/(bool) framedone#3 )
*((byte*) BGCOL#0) ← -- *((byte*) BGCOL#0)
to:irq::@return
irq::@2: scope:[irq] from irq
(bool) framedone#3 ← false
to:irq::@1
irq::@return: scope:[irq] from irq::@1
(bool) framedone#7 ← phi( irq::@1/(bool) framedone#10 )
(bool) framedone#4 ← (bool) framedone#7
return
to:@return
@2: scope:[] from @1
(bool) framedone#11 ← phi( @1/(bool) framedone#2 )
call main
to:@3
@3: scope:[] from @2
(bool) framedone#8 ← phi( @2/(bool) framedone#1 )
(bool) framedone#5 ← (bool) framedone#8
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @1
(label) @2
(label) @3
(label) @begin
(label) @end
(byte*) BGCOL
(byte*) BGCOL#0
(byte*) CIA1_INTERRUPT
(byte*) CIA1_INTERRUPT#0
(byte) CIA_INTERRUPT_CLEAR
(byte) CIA_INTERRUPT_CLEAR#0
(byte*) IRQ_ENABLE
(byte*) IRQ_ENABLE#0
(byte) IRQ_RASTER
(byte) IRQ_RASTER#0
(byte*) IRQ_STATUS
(byte*) IRQ_STATUS#0
(void()**) KERNEL_IRQ
(void()**) KERNEL_IRQ#0
(byte*) RASTER
(byte*) RASTER#0
(byte*) VIC_CONTROL
(byte*) VIC_CONTROL#0
(bool) framedone
(bool) framedone#0
(bool) framedone#1
(bool) framedone#10
(bool) framedone#11
(bool) framedone#12
(bool) framedone#13
(bool) framedone#14
(bool) framedone#15
(bool) framedone#2
(bool) framedone#3
(bool) framedone#4
(bool) framedone#5
(bool) framedone#6
(bool) framedone#7
(bool) framedone#8
(bool) framedone#9
interrupt(KERNEL_MIN)(void()) irq()
(bool~) irq::$0
(bool~) irq::$1
(label) irq::@1
(label) irq::@2
(label) irq::@return
(void()) main()
(void()*~) main::$0
(bool~) main::$1
(bool~) main::$2
(label) main::@1
(label) main::@2
(label) main::@4
(label) main::@7
(label) main::@return
Inversing boolean not [22] (bool~) main::$2 ← *((byte*) RASTER#0) >= (byte/signed byte/word/signed word/dword/signed dword) $14 from [21] (bool~) main::$1 ← *((byte*) RASTER#0) < (byte/signed byte/word/signed word/dword/signed dword) $14
Inversing boolean not [34] (bool~) irq::$1 ← *((byte*) RASTER#0) <= (byte/signed byte/word/signed word/dword/signed dword) $32 from [33] (bool~) irq::$0 ← *((byte*) RASTER#0) > (byte/signed byte/word/signed word/dword/signed dword) $32
Successful SSA optimization Pass2UnaryNotSimplification
Alias (bool) framedone#1 = (bool) framedone#15 (bool) framedone#9 (bool) framedone#13 (bool) framedone#6
Alias (bool) framedone#10 = (bool) framedone#7 (bool) framedone#4
Alias (bool) framedone#11 = (bool) framedone#2
Alias (bool) framedone#5 = (bool) framedone#8
Successful SSA optimization Pass2AliasElimination
Self Phi Eliminated (bool) framedone#1
Successful SSA optimization Pass2SelfPhiElimination
Redundant Phi (bool) framedone#12 (bool) framedone#11
Redundant Phi (bool) framedone#14 (bool) framedone#11
Redundant Phi (bool) framedone#5 (bool) framedone#1
Successful SSA optimization Pass2RedundantPhiElimination
Simple Condition (bool~) main::$2 [23] if(*((byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@4
Simple Condition (bool~) irq::$1 [35] if(*((byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
Constant (const void()**) KERNEL_IRQ#0 = ((void()**))$314
Constant (const byte*) RASTER#0 = ((byte*))$d012
Constant (const byte*) VIC_CONTROL#0 = ((byte*))$d011
Constant (const byte*) IRQ_STATUS#0 = ((byte*))$d019
Constant (const byte*) IRQ_ENABLE#0 = ((byte*))$d01a
Constant (const byte) IRQ_RASTER#0 = 1
Constant (const byte*) BGCOL#0 = ((byte*))$d020
Constant (const byte*) CIA1_INTERRUPT#0 = ((byte*))$dc0d
Constant (const byte) CIA_INTERRUPT_CLEAR#0 = $7f
Constant (const void()*) main::$0 = &irq
Successful SSA optimization Pass2ConstantIdentification
if() condition always true - replacing block destination [8] if(true) goto main::@2
Successful SSA optimization Pass2ConstantIfs
Successful SSA optimization PassNEliminateUnusedVars
Removing unused block main::@return
Successful SSA optimization Pass2EliminateUnusedBlocks
Culled Empty Block (label) main::@4
Culled Empty Block (label) @3
Successful SSA optimization Pass2CullEmptyBlocks
Culled Empty Block (label) main::@1
Successful SSA optimization Pass2CullEmptyBlocks
Constant inlined main::$0 = &interrupt(KERNEL_MIN)(void()) irq()
Successful SSA optimization Pass2ConstantInlining
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:3
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi()
to:@1
@1: scope:[] from @begin
[1] (bool) framedone#11 ← false
to:@2
@2: scope:[] from @1
[2] phi()
[3] call main
to:@end
@end: scope:[] from @2
[4] phi()
main: scope:[main] from @2
asm { sei }
[6] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0
[7] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f
[8] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd
[9] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0
[10] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq()
asm { cli }
to:main::@2
main::@2: scope:[main] from main main::@2 main::@7
[12] if(*((const byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@2
to:main::@7
main::@7: scope:[main] from main::@2
[13] (bool) framedone#0 ← true
to:main::@2
irq: scope:[irq] from
[14] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0)
[15] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0
[16] if(*((const byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1
to:irq::@2
irq::@2: scope:[irq] from irq
[17] (bool) framedone#3 ← false
to:irq::@1
irq::@1: scope:[irq] from irq irq::@2
[18] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0)
to:irq::@return
irq::@return: scope:[irq] from irq::@1
[19] return
to:@return
VARIABLE REGISTER WEIGHTS
(byte*) BGCOL
(byte*) CIA1_INTERRUPT
(byte) CIA_INTERRUPT_CLEAR
(byte*) IRQ_ENABLE
(byte) IRQ_RASTER
(byte*) IRQ_STATUS
(void()**) KERNEL_IRQ
(byte*) RASTER
(byte*) VIC_CONTROL
(bool) framedone
(bool) framedone#0 110.0
(bool) framedone#11 20.0
(bool) framedone#3 20.0
interrupt(KERNEL_MIN)(void()) irq()
(void()) main()
Initial phi equivalence classes
Added variable framedone#11 to zero page equivalence class [ framedone#11 ]
Added variable framedone#0 to zero page equivalence class [ framedone#0 ]
Added variable framedone#3 to zero page equivalence class [ framedone#3 ]
Complete equivalence classes
[ framedone#11 ]
[ framedone#0 ]
[ framedone#3 ]
Allocated zp ZP_BOOL:2 [ framedone#11 ]
Allocated zp ZP_BOOL:3 [ framedone#0 ]
Allocated zp ZP_BOOL:4 [ framedone#3 ]
INITIAL ASM
//SEG0 File Comments
// Illustrates a problem where a volatile bool modified at the end of an IRQ is not stored properly
// because it is assigned to the A register
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label KERNEL_IRQ = $314
.label RASTER = $d012
.label VIC_CONTROL = $d011
.label IRQ_STATUS = $d019
.label IRQ_ENABLE = $d01a
.const IRQ_RASTER = 1
.label BGCOL = $d020
.label CIA1_INTERRUPT = $dc0d
.const CIA_INTERRUPT_CLEAR = $7f
.label framedone = 3
.label framedone_3 = 4
.label framedone_11 = 2
//SEG3 @begin
bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [1] (bool) framedone#11 ← false -- vboz1=vboc1
lda #0
sta framedone_11
//SEG6 [2] phi from @1 to @2 [phi:@1->@2]
b2_from_b1:
jmp b2
//SEG7 @2
b2:
//SEG8 [3] call main
jsr main
//SEG9 [4] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend
//SEG10 @end
bend:
//SEG11 main
main: {
//SEG12 asm { sei }
sei
//SEG13 [6] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 -- _deref_pbuc1=vbuc2
// Disable CIA 1 Timer IRQ
lda #CIA_INTERRUPT_CLEAR
sta CIA1_INTERRUPT
//SEG14 [7] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
// Set raster line to $0fd
lda #$7f
and VIC_CONTROL
sta VIC_CONTROL
//SEG15 [8] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd -- _deref_pbuc1=vbuc2
lda #$fd
sta RASTER
//SEG16 [9] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 -- _deref_pbuc1=vbuc2
// Enable Raster Interrupt
lda #IRQ_RASTER
sta IRQ_ENABLE
//SEG17 [10] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq() -- _deref_pptc1=pprc2
// Set the IRQ routine
lda #<irq
sta KERNEL_IRQ
lda #>irq
sta KERNEL_IRQ+1
//SEG18 asm { cli }
cli
jmp b2
//SEG19 main::@2
b2:
//SEG20 [12] if(*((const byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@2 -- _deref_pbuc1_ge_vbuc2_then_la1
lda RASTER
cmp #$14
bcs b2
jmp b7
//SEG21 main::@7
b7:
//SEG22 [13] (bool) framedone#0 ← true -- vboz1=vboc1
lda #1
sta framedone
jmp b2
}
//SEG23 irq
irq: {
//SEG24 entry interrupt(KERNEL_MIN)
//SEG25 [14] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0) -- _deref_pbuc1=_inc__deref_pbuc1
inc BGCOL
//SEG26 [15] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 -- _deref_pbuc1=vbuc2
lda #IRQ_RASTER
sta IRQ_STATUS
//SEG27 [16] if(*((const byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1 -- _deref_pbuc1_le_vbuc2_then_la1
lda RASTER
cmp #$32
bcc b1
beq b1
jmp b2
//SEG28 irq::@2
b2:
//SEG29 [17] (bool) framedone#3 ← false -- vboz1=vboc1
lda #0
sta framedone_3
jmp b1
//SEG30 irq::@1
b1:
//SEG31 [18] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0) -- _deref_pbuc1=_dec__deref_pbuc1
dec BGCOL
jmp breturn
//SEG32 irq::@return
breturn:
//SEG33 [19] return - exit interrupt(KERNEL_MIN)
jmp $ea81
}
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [1] (bool) framedone#11 ← false [ ] ( ) always clobbers reg byte a
Statement [6] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [7] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [8] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [9] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [10] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq() [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [12] if(*((const byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@2 [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [13] (bool) framedone#0 ← true [ ] ( main:3 [ ] ) always clobbers reg byte a
Statement [15] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( [ ] ) always clobbers reg byte a
Statement [16] if(*((const byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1 [ ] ( [ ] ) always clobbers reg byte a
Statement [17] (bool) framedone#3 ← false [ ] ( [ ] ) always clobbers reg byte a
Potential registers zp ZP_BOOL:2 [ framedone#11 ] : zp ZP_BOOL:2 ,
Potential registers zp ZP_BOOL:3 [ framedone#0 ] : zp ZP_BOOL:3 ,
Potential registers zp ZP_BOOL:4 [ framedone#3 ] : zp ZP_BOOL:4 ,
REGISTER UPLIFT SCOPES
Uplift Scope [] 110: zp ZP_BOOL:3 [ framedone#0 ] 20: zp ZP_BOOL:2 [ framedone#11 ] 20: zp ZP_BOOL:4 [ framedone#3 ]
Uplift Scope [main]
Uplift Scope [irq]
Uplifting [] best 1370 combination zp ZP_BOOL:3 [ framedone#0 ] zp ZP_BOOL:2 [ framedone#11 ] zp ZP_BOOL:4 [ framedone#3 ]
Uplifting [main] best 1370 combination
Uplifting [irq] best 1370 combination
Coalescing zero page register [ zp ZP_BOOL:2 [ framedone#11 ] ] with [ zp ZP_BOOL:3 [ framedone#0 ] ]
Coalescing zero page register [ zp ZP_BOOL:2 [ framedone#11 framedone#0 ] ] with [ zp ZP_BOOL:4 [ framedone#3 ] ]
ASSEMBLER BEFORE OPTIMIZATION
//SEG0 File Comments
// Illustrates a problem where a volatile bool modified at the end of an IRQ is not stored properly
// because it is assigned to the A register
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label KERNEL_IRQ = $314
.label RASTER = $d012
.label VIC_CONTROL = $d011
.label IRQ_STATUS = $d019
.label IRQ_ENABLE = $d01a
.const IRQ_RASTER = 1
.label BGCOL = $d020
.label CIA1_INTERRUPT = $dc0d
.const CIA_INTERRUPT_CLEAR = $7f
.label framedone = 2
//SEG3 @begin
bbegin:
jmp b1
//SEG4 @1
b1:
//SEG5 [1] (bool) framedone#11 ← false -- vboz1=vboc1
lda #0
sta framedone
//SEG6 [2] phi from @1 to @2 [phi:@1->@2]
b2_from_b1:
jmp b2
//SEG7 @2
b2:
//SEG8 [3] call main
jsr main
//SEG9 [4] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
jmp bend
//SEG10 @end
bend:
//SEG11 main
main: {
//SEG12 asm { sei }
sei
//SEG13 [6] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 -- _deref_pbuc1=vbuc2
// Disable CIA 1 Timer IRQ
lda #CIA_INTERRUPT_CLEAR
sta CIA1_INTERRUPT
//SEG14 [7] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
// Set raster line to $0fd
lda #$7f
and VIC_CONTROL
sta VIC_CONTROL
//SEG15 [8] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd -- _deref_pbuc1=vbuc2
lda #$fd
sta RASTER
//SEG16 [9] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 -- _deref_pbuc1=vbuc2
// Enable Raster Interrupt
lda #IRQ_RASTER
sta IRQ_ENABLE
//SEG17 [10] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq() -- _deref_pptc1=pprc2
// Set the IRQ routine
lda #<irq
sta KERNEL_IRQ
lda #>irq
sta KERNEL_IRQ+1
//SEG18 asm { cli }
cli
jmp b2
//SEG19 main::@2
b2:
//SEG20 [12] if(*((const byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@2 -- _deref_pbuc1_ge_vbuc2_then_la1
lda RASTER
cmp #$14
bcs b2
jmp b7
//SEG21 main::@7
b7:
//SEG22 [13] (bool) framedone#0 ← true -- vboz1=vboc1
lda #1
sta framedone
jmp b2
}
//SEG23 irq
irq: {
//SEG24 entry interrupt(KERNEL_MIN)
//SEG25 [14] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0) -- _deref_pbuc1=_inc__deref_pbuc1
inc BGCOL
//SEG26 [15] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 -- _deref_pbuc1=vbuc2
lda #IRQ_RASTER
sta IRQ_STATUS
//SEG27 [16] if(*((const byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1 -- _deref_pbuc1_le_vbuc2_then_la1
lda RASTER
cmp #$32
bcc b1
beq b1
jmp b2
//SEG28 irq::@2
b2:
//SEG29 [17] (bool) framedone#3 ← false -- vboz1=vboc1
lda #0
sta framedone
jmp b1
//SEG30 irq::@1
b1:
//SEG31 [18] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0) -- _deref_pbuc1=_dec__deref_pbuc1
dec BGCOL
jmp breturn
//SEG32 irq::@return
breturn:
//SEG33 [19] return - exit interrupt(KERNEL_MIN)
jmp $ea81
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b1
Removing instruction jmp b2
Removing instruction jmp bend
Removing instruction jmp b2
Removing instruction jmp b7
Removing instruction jmp b2
Removing instruction jmp b1
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction b1:
Removing instruction b2_from_b1:
Removing instruction bend_from_b2:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction b2:
Removing instruction bend:
Removing instruction b7:
Removing instruction b2:
Removing instruction breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) BGCOL
(const byte*) BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) $d020
(byte*) CIA1_INTERRUPT
(const byte*) CIA1_INTERRUPT#0 CIA1_INTERRUPT = ((byte*))(word/dword/signed dword) $dc0d
(byte) CIA_INTERRUPT_CLEAR
(const byte) CIA_INTERRUPT_CLEAR#0 CIA_INTERRUPT_CLEAR = (byte/signed byte/word/signed word/dword/signed dword) $7f
(byte*) IRQ_ENABLE
(const byte*) IRQ_ENABLE#0 IRQ_ENABLE = ((byte*))(word/dword/signed dword) $d01a
(byte) IRQ_RASTER
(const byte) IRQ_RASTER#0 IRQ_RASTER = (byte/signed byte/word/signed word/dword/signed dword) 1
(byte*) IRQ_STATUS
(const byte*) IRQ_STATUS#0 IRQ_STATUS = ((byte*))(word/dword/signed dword) $d019
(void()**) KERNEL_IRQ
(const void()**) KERNEL_IRQ#0 KERNEL_IRQ = ((void()**))(word/signed word/dword/signed dword) $314
(byte*) RASTER
(const byte*) RASTER#0 RASTER = ((byte*))(word/dword/signed dword) $d012
(byte*) VIC_CONTROL
(const byte*) VIC_CONTROL#0 VIC_CONTROL = ((byte*))(word/dword/signed dword) $d011
(bool) framedone
(bool) framedone#0 framedone zp ZP_BOOL:2 110.0
(bool) framedone#11 framedone zp ZP_BOOL:2 20.0
(bool) framedone#3 framedone zp ZP_BOOL:2 20.0
interrupt(KERNEL_MIN)(void()) irq()
(label) irq::@1
(label) irq::@2
(label) irq::@return
(void()) main()
(label) main::@2
(label) main::@7
zp ZP_BOOL:2 [ framedone#11 framedone#0 framedone#3 ]
FINAL ASSEMBLER
Score: 1022
//SEG0 File Comments
// Illustrates a problem where a volatile bool modified at the end of an IRQ is not stored properly
// because it is assigned to the A register
//SEG1 Basic Upstart
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
//SEG2 Global Constants & labels
.label KERNEL_IRQ = $314
.label RASTER = $d012
.label VIC_CONTROL = $d011
.label IRQ_STATUS = $d019
.label IRQ_ENABLE = $d01a
.const IRQ_RASTER = 1
.label BGCOL = $d020
.label CIA1_INTERRUPT = $dc0d
.const CIA_INTERRUPT_CLEAR = $7f
.label framedone = 2
//SEG3 @begin
bbegin:
//SEG4 @1
//SEG5 [1] (bool) framedone#11 ← false -- vboz1=vboc1
lda #0
sta framedone
//SEG6 [2] phi from @1 to @2 [phi:@1->@2]
//SEG7 @2
//SEG8 [3] call main
jsr main
//SEG9 [4] phi from @2 to @end [phi:@2->@end]
//SEG10 @end
//SEG11 main
main: {
//SEG12 asm { sei }
sei
//SEG13 [6] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 -- _deref_pbuc1=vbuc2
// Disable CIA 1 Timer IRQ
lda #CIA_INTERRUPT_CLEAR
sta CIA1_INTERRUPT
//SEG14 [7] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
// Set raster line to $0fd
lda #$7f
and VIC_CONTROL
sta VIC_CONTROL
//SEG15 [8] *((const byte*) RASTER#0) ← (byte/word/signed word/dword/signed dword) $fd -- _deref_pbuc1=vbuc2
lda #$fd
sta RASTER
//SEG16 [9] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 -- _deref_pbuc1=vbuc2
// Enable Raster Interrupt
lda #IRQ_RASTER
sta IRQ_ENABLE
//SEG17 [10] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) irq() -- _deref_pptc1=pprc2
// Set the IRQ routine
lda #<irq
sta KERNEL_IRQ
lda #>irq
sta KERNEL_IRQ+1
//SEG18 asm { cli }
cli
//SEG19 main::@2
b2:
//SEG20 [12] if(*((const byte*) RASTER#0)>=(byte/signed byte/word/signed word/dword/signed dword) $14) goto main::@2 -- _deref_pbuc1_ge_vbuc2_then_la1
lda RASTER
cmp #$14
bcs b2
//SEG21 main::@7
//SEG22 [13] (bool) framedone#0 ← true -- vboz1=vboc1
lda #1
sta framedone
jmp b2
}
//SEG23 irq
irq: {
//SEG24 entry interrupt(KERNEL_MIN)
//SEG25 [14] *((const byte*) BGCOL#0) ← ++ *((const byte*) BGCOL#0) -- _deref_pbuc1=_inc__deref_pbuc1
inc BGCOL
//SEG26 [15] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 -- _deref_pbuc1=vbuc2
lda #IRQ_RASTER
sta IRQ_STATUS
//SEG27 [16] if(*((const byte*) RASTER#0)<=(byte/signed byte/word/signed word/dword/signed dword) $32) goto irq::@1 -- _deref_pbuc1_le_vbuc2_then_la1
lda RASTER
cmp #$32
bcc b1
beq b1
//SEG28 irq::@2
//SEG29 [17] (bool) framedone#3 ← false -- vboz1=vboc1
lda #0
sta framedone
//SEG30 irq::@1
b1:
//SEG31 [18] *((const byte*) BGCOL#0) ← -- *((const byte*) BGCOL#0) -- _deref_pbuc1=_dec__deref_pbuc1
dec BGCOL
//SEG32 irq::@return
//SEG33 [19] return - exit interrupt(KERNEL_MIN)
jmp $ea81
}

View File

@ -0,0 +1,35 @@
(label) @1
(label) @2
(label) @begin
(label) @end
(byte*) BGCOL
(const byte*) BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) $d020
(byte*) CIA1_INTERRUPT
(const byte*) CIA1_INTERRUPT#0 CIA1_INTERRUPT = ((byte*))(word/dword/signed dword) $dc0d
(byte) CIA_INTERRUPT_CLEAR
(const byte) CIA_INTERRUPT_CLEAR#0 CIA_INTERRUPT_CLEAR = (byte/signed byte/word/signed word/dword/signed dword) $7f
(byte*) IRQ_ENABLE
(const byte*) IRQ_ENABLE#0 IRQ_ENABLE = ((byte*))(word/dword/signed dword) $d01a
(byte) IRQ_RASTER
(const byte) IRQ_RASTER#0 IRQ_RASTER = (byte/signed byte/word/signed word/dword/signed dword) 1
(byte*) IRQ_STATUS
(const byte*) IRQ_STATUS#0 IRQ_STATUS = ((byte*))(word/dword/signed dword) $d019
(void()**) KERNEL_IRQ
(const void()**) KERNEL_IRQ#0 KERNEL_IRQ = ((void()**))(word/signed word/dword/signed dword) $314
(byte*) RASTER
(const byte*) RASTER#0 RASTER = ((byte*))(word/dword/signed dword) $d012
(byte*) VIC_CONTROL
(const byte*) VIC_CONTROL#0 VIC_CONTROL = ((byte*))(word/dword/signed dword) $d011
(bool) framedone
(bool) framedone#0 framedone zp ZP_BOOL:2 110.0
(bool) framedone#11 framedone zp ZP_BOOL:2 20.0
(bool) framedone#3 framedone zp ZP_BOOL:2 20.0
interrupt(KERNEL_MIN)(void()) irq()
(label) irq::@1
(label) irq::@2
(label) irq::@return
(void()) main()
(label) main::@2
(label) main::@7
zp ZP_BOOL:2 [ framedone#11 framedone#0 framedone#3 ]

View File

@ -0,0 +1,359 @@
// A simple usage of the flexible sprite multiplexer routine
.pc = $801 "Basic"
:BasicUpstart(bbegin)
.pc = $80d "Program"
.label SPRITES_XPOS = $d000
.label SPRITES_YPOS = $d001
.label SPRITES_XMSB = $d010
.label RASTER = $d012
.label SPRITES_ENABLE = $d015
.label BORDERCOL = $d020
.label SPRITES_COLS = $d027
.label VIC_CONTROL = $d011
.label D011 = $d011
.const VIC_DEN = $10
.const VIC_RSEL = 8
// VIC II IRQ Status Register
.label IRQ_STATUS = $d019
// VIC II IRQ Enable Register
.label IRQ_ENABLE = $d01a
// Bits for the IRQ Status/Enable Registers
.const IRQ_RASTER = 1
// CIA#1 Interrupt Status & Control Register
.label CIA1_INTERRUPT = $dc0d
// Value that disables all CIA interrupts when stored to the CIA Interrupt registers
.const CIA_INTERRUPT_CLEAR = $7f
// The vector used when the KERNAL serves IRQ interrupts
.label KERNEL_IRQ = $314
.const WHITE = 1
.const RED = 2
.const GREEN = 5
// The number of sprites in the multiplexer
.const PLEX_COUNT = $20
.label SPRITE = $2000
.label YSIN = $2100
// The address of the sprite pointers on the current screen (screen+$3f8).
.label PLEX_SCREEN_PTR = $400+$3f8
.label plex_show_idx = 9
.label plex_sprite_idx = 8
.label plex_sprite_msb = $b
.label plex_sprite_idx_1 = $e
.label plex_free_next = $f
.label framedone = 2
.label plex_free_next_27 = $a
.label plex_free_next_31 = $a
bbegin:
// The index in the PLEX tables of the next sprite to show
lda #0
sta plex_show_idx
// The index the next sprite to use for showing (sprites are used round-robin)
sta plex_sprite_idx
// The MSB bit of the next sprite to use for showing
lda #1
sta plex_sprite_msb
// The index of the sprite that is free next. Since sprites are used round-robin this moves forward each time a sprite is shown.
lda #0
sta plex_free_next_31
lda #1
sta framedone
jsr main
main: {
sei
jsr init
jsr loop
rts
}
// The raster loop
loop: {
.label sin_idx = 3
.label y_idx = 4
// The current index into the y-sinus
lda #0
sta sin_idx
b1:
// without volatile gives wrong asm
b4:
lda framedone
cmp #0
bne b6
jmp b4
b6:
lda #RED
sta BORDERCOL
// Assign sinus positions
lda sin_idx
sta y_idx
ldy #0
// without volatile gives wrong asm
b7:
ldx y_idx
lda YSIN,x
sta PLEX_YPOS,y
lax y_idx
axs #-[8]
stx y_idx
iny
cpy #PLEX_COUNT-1+1
bne b7
inc sin_idx
inc BORDERCOL
jsr plexSort
lda #GREEN
sta BORDERCOL
lda #0
sta framedone
lda #$7f
and VIC_CONTROL
sta VIC_CONTROL
lda #0
sta RASTER
jmp b1
}
// Ensure that the indices in PLEX_SORTED_IDX is sorted based on the y-positions in PLEX_YPOS
// Assumes that the positions are nearly sorted already (as each sprite just moves a bit)
// Uses an insertion sort:
// 1. Moves a marker (m) from the start to end of the array. Every time the marker moves forward all elements before the marker are sorted correctly.
// 2a. If the next element after the marker is larger that the current element
// the marker can be moved forwards (as the sorting is correct).
// 2b. If the next element after the marker is smaller than the current element:
// elements before the marker are shifted right one at a time until encountering one smaller than the current one.
// It is then inserted at the spot. Now the marker can move forward.
plexSort: {
.label nxt_idx = $c
.label nxt_y = $d
.label m = 5
lda #0
sta m
b1:
ldy m
lda PLEX_SORTED_IDX+1,y
sta nxt_idx
tay
lda PLEX_YPOS,y
sta nxt_y
ldx m
ldy PLEX_SORTED_IDX,x
cmp PLEX_YPOS,y
bcs b2
b3:
lda PLEX_SORTED_IDX,x
sta PLEX_SORTED_IDX+1,x
dex
cpx #$ff
bne b8
b5:
inx
lda nxt_idx
sta PLEX_SORTED_IDX,x
b2:
inc m
lda #PLEX_COUNT-2+1
cmp m
bne b1
// Prepare for showing the sprites
lda #0
sta plex_show_idx
sta plex_sprite_idx_1
lda #1
sta plex_sprite_msb
ldx #0
plexFreePrepare1_b1:
lda #0
sta PLEX_FREE_YPOS,x
inx
cpx #8
bne plexFreePrepare1_b1
sta plex_free_next
rts
b8:
lda nxt_y
ldy PLEX_SORTED_IDX,x
cmp PLEX_YPOS,y
bcc b3
jmp b5
}
// Initialize the program
init: {
.label xp = 6
lda #VIC_DEN|VIC_RSEL|3
sta D011
jsr plexInit
lda #$20
sta xp
lda #0
sta xp+1
tax
b1:
lda #$ff&SPRITE/$40
sta PLEX_PTR,x
txa
asl
tay
lda xp
sta PLEX_XPOS,y
lda xp+1
sta PLEX_XPOS+1,y
lda #9
clc
adc xp
sta xp
bcc !+
inc xp+1
!:
inx
cpx #PLEX_COUNT-1+1
bne b1
// Enable & initialize sprites
lda #$ff
sta SPRITES_ENABLE
ldx #0
b2:
lda #GREEN
sta SPRITES_COLS,x
inx
cpx #8
bne b2
// enable the interrupt
sei
lda #CIA_INTERRUPT_CLEAR
sta CIA1_INTERRUPT
lda #IRQ_RASTER
sta IRQ_ENABLE
sta IRQ_STATUS
lda #<plex_irq
sta KERNEL_IRQ
lda #>plex_irq
sta KERNEL_IRQ+1
cli
rts
}
// Initialize the multiplexer data structures
plexInit: {
ldx #0
b1:
txa
sta PLEX_SORTED_IDX,x
inx
cpx #PLEX_COUNT-1+1
bne b1
rts
}
plex_irq: {
.label _3 = 5
lda #WHITE
sta BORDERCOL
b1:
jsr plexShowSprite
ldy plexShowSprite.plexFreeAdd1__2
ldx PLEX_FREE_YPOS,y
lda RASTER
clc
adc #2
sta _3
lda plex_show_idx
cmp #PLEX_COUNT
bcc b9
b4:
lda #IRQ_RASTER
sta IRQ_STATUS
lda plex_show_idx
cmp #PLEX_COUNT
bcc b2
lda #1
sta framedone
b3:
lda #0
sta BORDERCOL
jmp $ea81
b2:
stx RASTER
jmp b3
b9:
cpx _3
bcc b1
jmp b4
}
// Show the next sprite.
// plexSort() prepares showing the sprites
plexShowSprite: {
.label _8 = 8
.label plex_sprite_idx2 = 5
.label plexFreeAdd1__2 = $a
lda plex_sprite_idx
asl
sta plex_sprite_idx2
ldx plex_show_idx
ldy PLEX_SORTED_IDX,x
lda PLEX_YPOS,y
ldy plex_sprite_idx2
sta SPRITES_YPOS,y
clc
adc #$15
ldy plex_free_next_27
sta PLEX_FREE_YPOS,y
ldx plex_free_next_27
inx
lda #7
sax plexFreeAdd1__2
ldx plex_show_idx
ldy PLEX_SORTED_IDX,x
lda PLEX_PTR,y
ldx plex_sprite_idx
sta PLEX_SCREEN_PTR,x
ldx plex_show_idx
lda PLEX_SORTED_IDX,x
asl
tax
lda PLEX_XPOS,x
ldy plex_sprite_idx2
sta SPRITES_XPOS,y
lda PLEX_XPOS+1,x
cmp #0
bne b1
lda plex_sprite_msb
eor #$ff
and SPRITES_XMSB
sta SPRITES_XMSB
b2:
ldx plex_sprite_idx
inx
lda #7
sax _8
inc plex_show_idx
asl plex_sprite_msb
lda plex_sprite_msb
cmp #0
bne breturn
lda #1
sta plex_sprite_msb
breturn:
rts
b1:
lda SPRITES_XMSB
ora plex_sprite_msb
sta SPRITES_XMSB
jmp b2
}
// Contains the Y-position where each sprite is free again. PLEX_FREE_YPOS[s] holds the Y-position where sprite s is free to use again.
PLEX_FREE_YPOS: .fill 8, 0
// The x-positions of the multiplexer sprites ($000-$1ff)
PLEX_XPOS: .fill 2*PLEX_COUNT, 0
// The y-positions of the multiplexer sprites.
PLEX_YPOS: .fill PLEX_COUNT, 0
// The sprite pointers for the multiplexed sprites
PLEX_PTR: .fill PLEX_COUNT, 0
// Indexes of the plex-sprites sorted by sprite y-position. Each call to plexSort() will fix the sorting if changes to the Y-positions have ruined it.
PLEX_SORTED_IDX: .fill PLEX_COUNT, 0
.pc = YSIN "YSIN"
.var min = 50
.var max = 250-21
.var ampl = max-min;
.for(var i=0;i<256;i++)
.byte round(min+(ampl/2)+(ampl/2)*sin(toRadians(360*i/256)))
.pc = SPRITE "SPRITE"
.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)

View File

@ -0,0 +1,251 @@
@begin: scope:[] from
[0] phi()
to:@4
@4: scope:[] from @begin
[1] (byte) plex_show_idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
[2] (byte) plex_sprite_idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
[3] (byte) plex_sprite_msb#0 ← (byte/signed byte/word/signed word/dword/signed dword) 1
to:@9
@9: scope:[] from @4
[4] (byte) plex_free_next#31 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:@12
@12: scope:[] from @9
kickasm(location (const byte*) YSIN#0) {{ .var min = 50
.var max = 250-21
.var ampl = max-min;
.for(var i=0;i<256;i++)
.byte round(min+(ampl/2)+(ampl/2)*sin(toRadians(360*i/256)))
}}
kickasm(location (const byte*) SPRITE#0) {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff))
.for (var y=0; y<21; y++)
.for (var x=0;x<3; x++)
.byte pic.getSinglecolorByte(x,y)
}}
to:@14
@14: scope:[] from @12
[7] (bool) framedone#19 ← true
to:@16
@16: scope:[] from @14
[8] phi()
[9] call main
to:@end
@end: scope:[] from @16
[10] phi()
main: scope:[main] from @16
asm { sei }
[12] call init
to:main::@1
main::@1: scope:[main] from main
[13] phi()
[14] call loop
to:main::@return
main::@return: scope:[main] from main::@1
[15] return
to:@return
loop: scope:[loop] from main::@1
[16] (byte) loop::sin_idx#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:loop::@1
loop::@1: scope:[loop] from loop loop::@15
[17] (byte) loop::sin_idx#6 ← phi( loop/(byte) loop::sin_idx#0 loop::@15/(byte) loop::sin_idx#1 )
[17] (bool) framedone#12 ← phi( loop/(bool) framedone#19 loop::@15/(bool) framedone#5 )
to:loop::@4
loop::@4: scope:[loop] from loop::@1 loop::@4
[18] if((bool) framedone#12) goto loop::@6
to:loop::@4
loop::@6: scope:[loop] from loop::@4
[19] *((const byte*) BORDERCOL#0) ← (const byte) RED#0
[20] (byte) loop::y_idx#0 ← (byte) loop::sin_idx#6
to:loop::@7
loop::@7: scope:[loop] from loop::@6 loop::@7
[21] (byte) loop::sy#2 ← phi( loop::@6/(byte/signed byte/word/signed word/dword/signed dword) 0 loop::@7/(byte) loop::sy#1 )
[21] (byte) loop::y_idx#2 ← phi( loop::@6/(byte) loop::y_idx#0 loop::@7/(byte) loop::y_idx#1 )
[22] *((const byte[PLEX_COUNT#0]) PLEX_YPOS#0 + (byte) loop::sy#2) ← *((const byte*) YSIN#0 + (byte) loop::y_idx#2)
[23] (byte) loop::y_idx#1 ← (byte) loop::y_idx#2 + (byte/signed byte/word/signed word/dword/signed dword) 8
[24] (byte) loop::sy#1 ← ++ (byte) loop::sy#2
[25] if((byte) loop::sy#1!=(const byte) PLEX_COUNT#0-(byte/signed byte/word/signed word/dword/signed dword) 1+(byte/signed byte/word/signed word/dword/signed dword) 1) goto loop::@7
to:loop::@13
loop::@13: scope:[loop] from loop::@7
[26] (byte) loop::sin_idx#1 ← (byte) loop::sin_idx#6 + (byte/signed byte/word/signed word/dword/signed dword) 1
[27] *((const byte*) BORDERCOL#0) ← ++ *((const byte*) BORDERCOL#0)
[28] call plexSort
to:loop::@15
loop::@15: scope:[loop] from loop::@13
[29] *((const byte*) BORDERCOL#0) ← (const byte) GREEN#0
[30] (bool) framedone#5 ← false
[31] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) & (byte/signed byte/word/signed word/dword/signed dword) $7f
[32] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:loop::@1
plexSort: scope:[plexSort] from loop::@13
[33] phi()
to:plexSort::@1
plexSort::@1: scope:[plexSort] from plexSort plexSort::@2
[34] (byte) plexSort::m#2 ← phi( plexSort/(byte/signed byte/word/signed word/dword/signed dword) 0 plexSort::@2/(byte) plexSort::m#1 )
[35] (byte) plexSort::nxt_idx#0 ← *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0+(byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) plexSort::m#2)
[36] (byte) plexSort::nxt_y#0 ← *((const byte[PLEX_COUNT#0]) PLEX_YPOS#0 + (byte) plexSort::nxt_idx#0)
[37] if((byte) plexSort::nxt_y#0>=*((const byte[PLEX_COUNT#0]) PLEX_YPOS#0 + *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plexSort::m#2))) goto plexSort::@2
to:plexSort::@11
plexSort::@11: scope:[plexSort] from plexSort::@1
[38] (byte~) plexSort::s#6 ← (byte) plexSort::m#2
to:plexSort::@3
plexSort::@3: scope:[plexSort] from plexSort::@11 plexSort::@8
[39] (byte) plexSort::s#3 ← phi( plexSort::@8/(byte) plexSort::s#1 plexSort::@11/(byte~) plexSort::s#6 )
[40] *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0+(byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) plexSort::s#3) ← *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plexSort::s#3)
[41] (byte) plexSort::s#1 ← -- (byte) plexSort::s#3
[42] if((byte) plexSort::s#1!=(byte/word/signed word/dword/signed dword) $ff) goto plexSort::@8
to:plexSort::@5
plexSort::@5: scope:[plexSort] from plexSort::@3 plexSort::@8
[43] (byte) plexSort::s#2 ← ++ (byte) plexSort::s#1
[44] *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plexSort::s#2) ← (byte) plexSort::nxt_idx#0
to:plexSort::@2
plexSort::@2: scope:[plexSort] from plexSort::@1 plexSort::@5
[45] (byte) plexSort::m#1 ← ++ (byte) plexSort::m#2
[46] if((byte) plexSort::m#1!=(const byte) PLEX_COUNT#0-(byte/signed byte/word/signed word/dword/signed dword) 2+(byte/signed byte/word/signed word/dword/signed dword) 1) goto plexSort::@1
to:plexSort::@6
plexSort::@6: scope:[plexSort] from plexSort::@2
[47] (byte) plex_show_idx#1 ← (byte/signed byte/word/signed word/dword/signed dword) 0
[48] (byte) plex_sprite_idx#1 ← (byte/signed byte/word/signed word/dword/signed dword) 0
[49] (byte) plex_sprite_msb#1 ← (byte/signed byte/word/signed word/dword/signed dword) 1
to:plexSort::plexFreePrepare1
plexSort::plexFreePrepare1: scope:[plexSort] from plexSort::@6
[50] phi()
to:plexSort::plexFreePrepare1_@1
plexSort::plexFreePrepare1_@1: scope:[plexSort] from plexSort::plexFreePrepare1 plexSort::plexFreePrepare1_@1
[51] (byte) plexSort::plexFreePrepare1_s#2 ← phi( plexSort::plexFreePrepare1/(byte/signed byte/word/signed word/dword/signed dword) 0 plexSort::plexFreePrepare1_@1/(byte) plexSort::plexFreePrepare1_s#1 )
[52] *((const byte[8]) PLEX_FREE_YPOS#0 + (byte) plexSort::plexFreePrepare1_s#2) ← (byte/signed byte/word/signed word/dword/signed dword) 0
[53] (byte) plexSort::plexFreePrepare1_s#1 ← ++ (byte) plexSort::plexFreePrepare1_s#2
[54] if((byte) plexSort::plexFreePrepare1_s#1!=(byte/signed byte/word/signed word/dword/signed dword) 8) goto plexSort::plexFreePrepare1_@1
to:plexSort::plexFreePrepare1_@2
plexSort::plexFreePrepare1_@2: scope:[plexSort] from plexSort::plexFreePrepare1_@1
[55] (byte) plex_free_next#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:plexSort::@return
plexSort::@return: scope:[plexSort] from plexSort::plexFreePrepare1_@2
[56] return
to:@return
plexSort::@8: scope:[plexSort] from plexSort::@3
[57] if((byte) plexSort::nxt_y#0<*((const byte[PLEX_COUNT#0]) PLEX_YPOS#0 + *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plexSort::s#1))) goto plexSort::@3
to:plexSort::@5
init: scope:[init] from main
[58] *((const byte*) D011#0) ← (const byte) VIC_DEN#0|(const byte) VIC_RSEL#0|(byte/signed byte/word/signed word/dword/signed dword) 3
[59] call plexInit
to:init::@1
init::@1: scope:[init] from init init::@1
[60] (word) init::xp#2 ← phi( init::@1/(word) init::xp#1 init/(byte/signed byte/word/signed word/dword/signed dword) $20 )
[60] (byte) init::sx#2 ← phi( init::@1/(byte) init::sx#1 init/(byte/signed byte/word/signed word/dword/signed dword) 0 )
[61] *((const byte[PLEX_COUNT#0]) PLEX_PTR#0 + (byte) init::sx#2) ← ((byte))(const byte*) SPRITE#0/(byte/signed byte/word/signed word/dword/signed dword) $40
[62] (byte~) init::$6 ← (byte) init::sx#2 << (byte/signed byte/word/signed word/dword/signed dword) 1
[63] *((const word[PLEX_COUNT#0]) PLEX_XPOS#0 + (byte~) init::$6) ← (word) init::xp#2
[64] (word) init::xp#1 ← (word) init::xp#2 + (byte/signed byte/word/signed word/dword/signed dword) 9
[65] (byte) init::sx#1 ← ++ (byte) init::sx#2
[66] if((byte) init::sx#1!=(const byte) PLEX_COUNT#0-(byte/signed byte/word/signed word/dword/signed dword) 1+(byte/signed byte/word/signed word/dword/signed dword) 1) goto init::@1
to:init::@3
init::@3: scope:[init] from init::@1
[67] *((const byte*) SPRITES_ENABLE#0) ← (byte/word/signed word/dword/signed dword) $ff
to:init::@2
init::@2: scope:[init] from init::@2 init::@3
[68] (byte) init::ss#2 ← phi( init::@2/(byte) init::ss#1 init::@3/(byte/signed byte/word/signed word/dword/signed dword) 0 )
[69] *((const byte*) SPRITES_COLS#0 + (byte) init::ss#2) ← (const byte) GREEN#0
[70] (byte) init::ss#1 ← ++ (byte) init::ss#2
[71] if((byte) init::ss#1!=(byte/signed byte/word/signed word/dword/signed dword) 8) goto init::@2
to:init::@4
init::@4: scope:[init] from init::@2
asm { sei }
[73] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0
[74] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0
[75] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0
[76] *((const void()**) KERNEL_IRQ#0) ← &interrupt(KERNEL_MIN)(void()) plex_irq()
asm { cli }
to:init::@return
init::@return: scope:[init] from init::@4
[78] return
to:@return
plexInit: scope:[plexInit] from init
[79] phi()
to:plexInit::plexSetScreen1
plexInit::plexSetScreen1: scope:[plexInit] from plexInit
[80] phi()
to:plexInit::@1
plexInit::@1: scope:[plexInit] from plexInit::@1 plexInit::plexSetScreen1
[81] (byte) plexInit::i#2 ← phi( plexInit::@1/(byte) plexInit::i#1 plexInit::plexSetScreen1/(byte/signed byte/word/signed word/dword/signed dword) 0 )
[82] *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plexInit::i#2) ← (byte) plexInit::i#2
[83] (byte) plexInit::i#1 ← ++ (byte) plexInit::i#2
[84] if((byte) plexInit::i#1!=(const byte) PLEX_COUNT#0-(byte/signed byte/word/signed word/dword/signed dword) 1+(byte/signed byte/word/signed word/dword/signed dword) 1) goto plexInit::@1
to:plexInit::@return
plexInit::@return: scope:[plexInit] from plexInit::@1
[85] return
to:@return
plex_irq: scope:[plex_irq] from
[86] *((const byte*) BORDERCOL#0) ← (const byte) WHITE#0
to:plex_irq::@1
plex_irq::@1: scope:[plex_irq] from plex_irq plex_irq::@9
[87] (byte) plex_sprite_msb#29 ← phi( plex_irq/(byte) plex_sprite_msb#0 plex_irq::@9/(byte) plex_sprite_msb#17 )
[87] (byte) plex_free_next#27 ← phi( plex_irq/(byte) plex_free_next#31 plex_irq::@9/(byte/word/dword) plexShowSprite::plexFreeAdd1_$2#0 )
[87] (byte) plex_show_idx#27 ← phi( plex_irq/(byte) plex_show_idx#0 plex_irq::@9/(byte) plex_show_idx#16 )
[87] (byte) plex_sprite_idx#25 ← phi( plex_irq/(byte) plex_sprite_idx#0 plex_irq::@9/(byte/word/dword~) plexShowSprite::$8 )
[88] call plexShowSprite
to:plex_irq::plexFreeNextYpos1
plex_irq::plexFreeNextYpos1: scope:[plex_irq] from plex_irq::@1
[89] (byte) plex_irq::plexFreeNextYpos1_return#0 ← *((const byte[8]) PLEX_FREE_YPOS#0 + (byte/word/dword) plexShowSprite::plexFreeAdd1_$2#0)
to:plex_irq::@7
plex_irq::@7: scope:[plex_irq] from plex_irq::plexFreeNextYpos1
[90] (byte/signed word/word/dword/signed dword~) plex_irq::$3 ← *((const byte*) RASTER#0) + (byte/signed byte/word/signed word/dword/signed dword) 2
[91] if((byte) plex_show_idx#16<(const byte) PLEX_COUNT#0) goto plex_irq::@9
to:plex_irq::@4
plex_irq::@4: scope:[plex_irq] from plex_irq::@7 plex_irq::@9
[92] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0
[93] if((byte) plex_show_idx#16<(const byte) PLEX_COUNT#0) goto plex_irq::@2
to:plex_irq::@5
plex_irq::@5: scope:[plex_irq] from plex_irq::@4
[94] (bool) framedone#3 ← true
to:plex_irq::@3
plex_irq::@3: scope:[plex_irq] from plex_irq::@2 plex_irq::@5
[95] *((const byte*) BORDERCOL#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0
to:plex_irq::@return
plex_irq::@return: scope:[plex_irq] from plex_irq::@3
[96] return
to:@return
plex_irq::@2: scope:[plex_irq] from plex_irq::@4
[97] *((const byte*) RASTER#0) ← (byte) plex_irq::plexFreeNextYpos1_return#0
to:plex_irq::@3
plex_irq::@9: scope:[plex_irq] from plex_irq::@7
[98] if((byte) plex_irq::plexFreeNextYpos1_return#0<(byte/signed word/word/dword/signed dword~) plex_irq::$3) goto plex_irq::@1
to:plex_irq::@4
plexShowSprite: scope:[plexShowSprite] from plex_irq::@1
[99] (byte) plexShowSprite::plex_sprite_idx2#0 ← (byte) plex_sprite_idx#25 << (byte/signed byte/word/signed word/dword/signed dword) 1
[100] (byte) plexShowSprite::plexFreeAdd1_ypos#0 ← *((const byte[PLEX_COUNT#0]) PLEX_YPOS#0 + *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plex_show_idx#27))
[101] *((const byte*) SPRITES_YPOS#0 + (byte) plexShowSprite::plex_sprite_idx2#0) ← (byte) plexShowSprite::plexFreeAdd1_ypos#0
to:plexShowSprite::plexFreeAdd1
plexShowSprite::plexFreeAdd1: scope:[plexShowSprite] from plexShowSprite
[102] (byte/signed word/word/dword/signed dword) plexShowSprite::plexFreeAdd1_$0#0 ← (byte) plexShowSprite::plexFreeAdd1_ypos#0 + (byte/signed byte/word/signed word/dword/signed dword) $15
[103] *((const byte[8]) PLEX_FREE_YPOS#0 + (byte) plex_free_next#27) ← (byte/signed word/word/dword/signed dword) plexShowSprite::plexFreeAdd1_$0#0
[104] (byte/signed word/word/dword/signed dword) plexShowSprite::plexFreeAdd1_$1#0 ← (byte) plex_free_next#27 + (byte/signed byte/word/signed word/dword/signed dword) 1
[105] (byte/word/dword) plexShowSprite::plexFreeAdd1_$2#0 ← (byte/signed word/word/dword/signed dword) plexShowSprite::plexFreeAdd1_$1#0 & (byte/signed byte/word/signed word/dword/signed dword) 7
to:plexShowSprite::@7
plexShowSprite::@7: scope:[plexShowSprite] from plexShowSprite::plexFreeAdd1
[106] *((const byte*) PLEX_SCREEN_PTR#0 + (byte) plex_sprite_idx#25) ← *((const byte[PLEX_COUNT#0]) PLEX_PTR#0 + *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plex_show_idx#27))
[107] (byte) plexShowSprite::xpos_idx#0 ← *((const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 + (byte) plex_show_idx#27) << (byte/signed byte/word/signed word/dword/signed dword) 1
[108] (byte~) plexShowSprite::$3 ← < *((const word[PLEX_COUNT#0]) PLEX_XPOS#0 + (byte) plexShowSprite::xpos_idx#0)
[109] *((const byte*) SPRITES_XPOS#0 + (byte) plexShowSprite::plex_sprite_idx2#0) ← (byte~) plexShowSprite::$3
[110] (byte~) plexShowSprite::$4 ← > *((const word[PLEX_COUNT#0]) PLEX_XPOS#0 + (byte) plexShowSprite::xpos_idx#0)
[111] if((byte~) plexShowSprite::$4!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto plexShowSprite::@1
to:plexShowSprite::@4
plexShowSprite::@4: scope:[plexShowSprite] from plexShowSprite::@7
[112] (byte/word/dword~) plexShowSprite::$6 ← (byte/word/signed word/dword/signed dword) $ff ^ (byte) plex_sprite_msb#29
[113] *((const byte*) SPRITES_XMSB#0) ← *((const byte*) SPRITES_XMSB#0) & (byte/word/dword~) plexShowSprite::$6
to:plexShowSprite::@2
plexShowSprite::@2: scope:[plexShowSprite] from plexShowSprite::@1 plexShowSprite::@4
[114] (byte/signed word/word/dword/signed dword~) plexShowSprite::$7 ← (byte) plex_sprite_idx#25 + (byte/signed byte/word/signed word/dword/signed dword) 1
[115] (byte/word/dword~) plexShowSprite::$8 ← (byte/signed word/word/dword/signed dword~) plexShowSprite::$7 & (byte/signed byte/word/signed word/dword/signed dword) 7
[116] (byte) plex_show_idx#16 ← ++ (byte) plex_show_idx#27
[117] (byte) plex_sprite_msb#27 ← (byte) plex_sprite_msb#29 << (byte/signed byte/word/signed word/dword/signed dword) 1
[118] if((byte) plex_sprite_msb#27!=(byte/signed byte/word/signed word/dword/signed dword) 0) goto plexShowSprite::@return
to:plexShowSprite::@6
plexShowSprite::@6: scope:[plexShowSprite] from plexShowSprite::@2
[119] (byte) plex_sprite_msb#4 ← (byte/signed byte/word/signed word/dword/signed dword) 1
to:plexShowSprite::@return
plexShowSprite::@return: scope:[plexShowSprite] from plexShowSprite::@2 plexShowSprite::@6
[120] (byte) plex_sprite_msb#17 ← phi( plexShowSprite::@2/(byte) plex_sprite_msb#27 plexShowSprite::@6/(byte) plex_sprite_msb#4 )
[121] return
to:@return
plexShowSprite::@1: scope:[plexShowSprite] from plexShowSprite::@7
[122] *((const byte*) SPRITES_XMSB#0) ← *((const byte*) SPRITES_XMSB#0) | (byte) plex_sprite_msb#29
to:plexShowSprite::@2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
(label) @12
(label) @14
(label) @16
(label) @4
(label) @9
(label) @begin
(label) @end
(byte*) BGCOL
(byte*) BGCOL1
(byte*) BGCOL2
(byte*) BGCOL3
(byte*) BGCOL4
(byte) BLACK
(byte) BLUE
(byte*) BORDERCOL
(const byte*) BORDERCOL#0 BORDERCOL = ((byte*))(word/dword/signed dword) $d020
(byte) BROWN
(byte*) CHARGEN
(byte*) CIA1_INTERRUPT
(const byte*) CIA1_INTERRUPT#0 CIA1_INTERRUPT = ((byte*))(word/dword/signed dword) $dc0d
(byte*) CIA1_PORT_A
(byte*) CIA1_PORT_A_DDR
(byte*) CIA1_PORT_B
(byte*) CIA1_PORT_B_DDR
(byte*) CIA2_INTERRUPT
(byte*) CIA2_PORT_A
(byte*) CIA2_PORT_A_DDR
(byte*) CIA2_PORT_B
(byte*) CIA2_PORT_B_DDR
(byte) CIA_INTERRUPT_CLEAR
(const byte) CIA_INTERRUPT_CLEAR#0 CIA_INTERRUPT_CLEAR = (byte/signed byte/word/signed word/dword/signed dword) $7f
(byte*) COLS
(byte) CYAN
(byte*) D011
(const byte*) D011#0 D011 = ((byte*))(word/dword/signed dword) $d011
(byte*) D016
(byte*) D018
(byte) DARK_GREY
(byte) GREEN
(const byte) GREEN#0 GREEN = (byte/signed byte/word/signed word/dword/signed dword) 5
(byte) GREY
(void()**) HARDWARE_IRQ
(byte) IRQ_COLLISION_BG
(byte) IRQ_COLLISION_SPRITE
(byte*) IRQ_ENABLE
(const byte*) IRQ_ENABLE#0 IRQ_ENABLE = ((byte*))(word/dword/signed dword) $d01a
(byte) IRQ_LIGHTPEN
(byte) IRQ_RASTER
(const byte) IRQ_RASTER#0 IRQ_RASTER = (byte/signed byte/word/signed word/dword/signed dword) 1
(byte*) IRQ_STATUS
(const byte*) IRQ_STATUS#0 IRQ_STATUS = ((byte*))(word/dword/signed dword) $d019
(void()**) KERNEL_IRQ
(const void()**) KERNEL_IRQ#0 KERNEL_IRQ = ((void()**))(word/signed word/dword/signed dword) $314
(byte*) LIGHTPEN_X
(byte*) LIGHTPEN_Y
(byte) LIGHT_BLUE
(byte) LIGHT_GREEN
(byte) LIGHT_GREY
(byte) ORANGE
(byte) PINK
(byte) PLEX_COUNT
(const byte) PLEX_COUNT#0 PLEX_COUNT = (byte/signed byte/word/signed word/dword/signed dword) $20
(byte[8]) PLEX_FREE_YPOS
(const byte[8]) PLEX_FREE_YPOS#0 PLEX_FREE_YPOS = { fill( 8, 0) }
(byte[PLEX_COUNT#0]) PLEX_PTR
(const byte[PLEX_COUNT#0]) PLEX_PTR#0 PLEX_PTR = { fill( PLEX_COUNT#0, 0) }
(byte*) PLEX_SCREEN_PTR
(const byte*) PLEX_SCREEN_PTR#0 PLEX_SCREEN_PTR = ((byte*))(word/signed word/dword/signed dword) $400+(word/signed word/dword/signed dword) $3f8
(byte[PLEX_COUNT#0]) PLEX_SORTED_IDX
(const byte[PLEX_COUNT#0]) PLEX_SORTED_IDX#0 PLEX_SORTED_IDX = { fill( PLEX_COUNT#0, 0) }
(word[PLEX_COUNT#0]) PLEX_XPOS
(const word[PLEX_COUNT#0]) PLEX_XPOS#0 PLEX_XPOS = { fill( PLEX_COUNT#0, 0) }
(byte[PLEX_COUNT#0]) PLEX_YPOS
(const byte[PLEX_COUNT#0]) PLEX_YPOS#0 PLEX_YPOS = { fill( PLEX_COUNT#0, 0) }
(byte*) PROCPORT
(byte) PROCPORT_BASIC_KERNEL_IO
(byte*) PROCPORT_DDR
(byte) PROCPORT_DDR_MEMORY_MASK
(byte) PROCPORT_KERNEL_IO
(byte) PROCPORT_RAM_ALL
(byte) PROCPORT_RAM_CHARROM
(byte) PROCPORT_RAM_IO
(byte) PURPLE
(byte*) RASTER
(const byte*) RASTER#0 RASTER = ((byte*))(word/dword/signed dword) $d012
(byte) RED
(const byte) RED#0 RED = (byte/signed byte/word/signed word/dword/signed dword) 2
(byte*) SCREEN
(byte*) SPRITE
(const byte*) SPRITE#0 SPRITE = ((byte*))(word/signed word/dword/signed dword) $2000
(byte*) SPRITES_COLS
(const byte*) SPRITES_COLS#0 SPRITES_COLS = ((byte*))(word/dword/signed dword) $d027
(byte*) SPRITES_ENABLE
(const byte*) SPRITES_ENABLE#0 SPRITES_ENABLE = ((byte*))(word/dword/signed dword) $d015
(byte*) SPRITES_EXPAND_X
(byte*) SPRITES_EXPAND_Y
(byte*) SPRITES_MC
(byte*) SPRITES_MC1
(byte*) SPRITES_MC2
(byte*) SPRITES_PRIORITY
(byte*) SPRITES_XMSB
(const byte*) SPRITES_XMSB#0 SPRITES_XMSB = ((byte*))(word/dword/signed dword) $d010
(byte*) SPRITES_XPOS
(const byte*) SPRITES_XPOS#0 SPRITES_XPOS = ((byte*))(word/dword/signed dword) $d000
(byte*) SPRITES_YPOS
(const byte*) SPRITES_YPOS#0 SPRITES_YPOS = ((byte*))(word/dword/signed dword) $d001
(word) SPRITE_PTRS
(byte) VIC_BMM
(byte*) VIC_CONTROL
(const byte*) VIC_CONTROL#0 VIC_CONTROL = ((byte*))(word/dword/signed dword) $d011
(byte*) VIC_CONTROL2
(byte) VIC_CSEL
(byte) VIC_DEN
(const byte) VIC_DEN#0 VIC_DEN = (byte/signed byte/word/signed word/dword/signed dword) $10
(byte) VIC_ECM
(byte) VIC_MCM
(byte*) VIC_MEMORY
(byte) VIC_RSEL
(const byte) VIC_RSEL#0 VIC_RSEL = (byte/signed byte/word/signed word/dword/signed dword) 8
(byte) VIC_RST8
(byte) WHITE
(const byte) WHITE#0 WHITE = (byte/signed byte/word/signed word/dword/signed dword) 1
(byte) YELLOW
(byte*) YSIN
(const byte*) YSIN#0 YSIN = ((byte*))(word/signed word/dword/signed dword) $2100
(bool) framedone
(bool) framedone#12 framedone zp ZP_BOOL:2 57.0
(bool) framedone#19 framedone zp ZP_BOOL:2 0.6666666666666666
(bool) framedone#3 framedone zp ZP_BOOL:2 20.0
(bool) framedone#5 framedone zp ZP_BOOL:2 7.333333333333333
(void()) init()
(byte~) init::$6 reg byte a 22.0
(label) init::@1
(label) init::@2
(label) init::@3
(label) init::@4
(label) init::@return
(byte) init::ss
(byte) init::ss#1 reg byte x 16.5
(byte) init::ss#2 reg byte x 16.5
(byte) init::sx
(byte) init::sx#1 reg byte x 16.5
(byte) init::sx#2 reg byte x 8.8
(word) init::xp
(word) init::xp#1 xp zp ZP_WORD:6 7.333333333333333
(word) init::xp#2 xp zp ZP_WORD:6 8.25
(void()) loop()
(label) loop::@1
(label) loop::@13
(label) loop::@15
(label) loop::@4
(label) loop::@6
(label) loop::@7
(byte) loop::sin_idx
(byte) loop::sin_idx#0 sin_idx zp ZP_BYTE:3 4.0
(byte) loop::sin_idx#1 sin_idx zp ZP_BYTE:3 3.142857142857143
(byte) loop::sin_idx#6 sin_idx zp ZP_BYTE:3 3.8888888888888893
(byte) loop::sy
(byte) loop::sy#1 reg byte y 151.5
(byte) loop::sy#2 reg byte y 101.0
(byte) loop::y_idx
(byte) loop::y_idx#0 y_idx zp ZP_BYTE:4 22.0
(byte) loop::y_idx#1 y_idx zp ZP_BYTE:4 67.33333333333333
(byte) loop::y_idx#2 y_idx zp ZP_BYTE:4 157.0
(void()) main()
(label) main::@1
(label) main::@return
(void()) plexInit((byte*) plexInit::screen)
(label) plexInit::@1
(label) plexInit::@return
(byte) plexInit::i
(byte) plexInit::i#1 reg byte x 16.5
(byte) plexInit::i#2 reg byte x 22.0
(label) plexInit::plexSetScreen1
(byte*~) plexInit::plexSetScreen1_$0
(byte*) plexInit::plexSetScreen1_screen
(byte*) plexInit::screen
(void()) plexShowSprite()
(byte~) plexShowSprite::$3 reg byte a 4.0
(byte~) plexShowSprite::$4 reg byte a 4.0
(byte/word/dword~) plexShowSprite::$6 reg byte a 4.0
(byte/signed word/word/dword/signed dword~) plexShowSprite::$7 reg byte x 4.0
(byte/word/dword~) plexShowSprite::$8 $8 zp ZP_BYTE:8 1.0833333333333333
(label) plexShowSprite::@1
(label) plexShowSprite::@2
(label) plexShowSprite::@4
(label) plexShowSprite::@6
(label) plexShowSprite::@7
(label) plexShowSprite::@return
(label) plexShowSprite::plexFreeAdd1
(byte/signed word/word/dword/signed dword~) plexShowSprite::plexFreeAdd1_$0
(byte/signed word/word/dword/signed dword) plexShowSprite::plexFreeAdd1_$0#0 reg byte a 4.0
(byte/signed word/word/dword/signed dword~) plexShowSprite::plexFreeAdd1_$1
(byte/signed word/word/dword/signed dword) plexShowSprite::plexFreeAdd1_$1#0 reg byte x 4.0
(byte/word/dword~) plexShowSprite::plexFreeAdd1_$2
(byte/word/dword) plexShowSprite::plexFreeAdd1_$2#0 plexFreeAdd1_$2 zp ZP_BYTE:10 1.0434782608695652
(byte) plexShowSprite::plexFreeAdd1_ypos
(byte) plexShowSprite::plexFreeAdd1_ypos#0 reg byte a 3.0
(byte) plexShowSprite::plex_sprite_idx2
(byte) plexShowSprite::plex_sprite_idx2#0 plex_sprite_idx2 zp ZP_BYTE:5 0.6000000000000001
(byte) plexShowSprite::xpos_idx
(byte) plexShowSprite::xpos_idx#0 reg byte x 2.0
(byte) plexShowSprite::ypos
(void()) plexSort()
(label) plexSort::@1
(label) plexSort::@11
(label) plexSort::@2
(label) plexSort::@3
(label) plexSort::@5
(label) plexSort::@6
(label) plexSort::@8
(label) plexSort::@return
(byte) plexSort::m
(byte) plexSort::m#1 m zp ZP_BYTE:5 151.5
(byte) plexSort::m#2 m zp ZP_BYTE:5 42.08333333333333
(byte) plexSort::nxt_idx
(byte) plexSort::nxt_idx#0 nxt_idx zp ZP_BYTE:12 30.299999999999997
(byte) plexSort::nxt_y
(byte) plexSort::nxt_y#0 nxt_y zp ZP_BYTE:13 150.375
(label) plexSort::plexFreePrepare1
(bool~) plexSort::plexFreePrepare1_$0
(label) plexSort::plexFreePrepare1_@1
(label) plexSort::plexFreePrepare1_@2
(byte) plexSort::plexFreePrepare1_s
(byte) plexSort::plexFreePrepare1_s#1 reg byte x 151.5
(byte) plexSort::plexFreePrepare1_s#2 reg byte x 151.5
(byte) plexSort::s
(byte) plexSort::s#1 reg byte x 1368.3333333333335
(byte) plexSort::s#2 reg byte x 202.0
(byte) plexSort::s#3 reg byte x 2052.5
(byte~) plexSort::s#6 reg byte x 202.0
(byte) plex_free_next
(byte) plex_free_next#0 plex_free_next zp ZP_BYTE:15 20.0
(byte) plex_free_next#27 plex_free_next#27 zp ZP_BYTE:10 2.8333333333333335
(byte) plex_free_next#31 plex_free_next#31 zp ZP_BYTE:10 4.0
interrupt(KERNEL_MIN)(void()) plex_irq()
(byte/signed word/word/dword/signed dword~) plex_irq::$3 $3 zp ZP_BYTE:5 11.0
(label) plex_irq::@1
(label) plex_irq::@2
(label) plex_irq::@3
(label) plex_irq::@4
(label) plex_irq::@5
(label) plex_irq::@7
(label) plex_irq::@9
(label) plex_irq::@return
(label) plex_irq::plexFreeNextYpos1
(byte) plex_irq::plexFreeNextYpos1_return
(byte) plex_irq::plexFreeNextYpos1_return#0 reg byte x 4.0
(byte) plex_irq::rasterY
(byte) plex_show_idx
(byte) plex_show_idx#0 plex_show_idx zp ZP_BYTE:9 4.0
(byte) plex_show_idx#1 plex_show_idx zp ZP_BYTE:9 20.0
(byte) plex_show_idx#16 plex_show_idx zp ZP_BYTE:9 2.1666666666666665
(byte) plex_show_idx#27 plex_show_idx zp ZP_BYTE:9 1.1052631578947367
(byte) plex_sprite_idx
(byte) plex_sprite_idx#0 plex_sprite_idx zp ZP_BYTE:8 4.0
(byte) plex_sprite_idx#1 plex_sprite_idx#1 zp ZP_BYTE:14 20.0
(byte) plex_sprite_idx#25 plex_sprite_idx zp ZP_BYTE:8 1.1176470588235294
(byte) plex_sprite_msb
(byte) plex_sprite_msb#0 plex_sprite_msb zp ZP_BYTE:11 4.0
(byte) plex_sprite_msb#1 plex_sprite_msb zp ZP_BYTE:11 20.0
(byte) plex_sprite_msb#17 plex_sprite_msb zp ZP_BYTE:11 2.142857142857143
(byte) plex_sprite_msb#27 plex_sprite_msb zp ZP_BYTE:11 3.0
(byte) plex_sprite_msb#29 plex_sprite_msb zp ZP_BYTE:11 0.95
(byte) plex_sprite_msb#4 plex_sprite_msb zp ZP_BYTE:11 4.0
zp ZP_BOOL:2 [ framedone#12 framedone#19 framedone#5 framedone#3 ]
zp ZP_BYTE:3 [ loop::sin_idx#6 loop::sin_idx#0 loop::sin_idx#1 ]
zp ZP_BYTE:4 [ loop::y_idx#2 loop::y_idx#0 loop::y_idx#1 ]
reg byte y [ loop::sy#2 loop::sy#1 ]
zp ZP_BYTE:5 [ plexSort::m#2 plexSort::m#1 plex_irq::$3 plexShowSprite::plex_sprite_idx2#0 ]
reg byte x [ plexSort::s#3 plexSort::s#1 plexSort::s#6 ]
reg byte x [ plexSort::plexFreePrepare1_s#2 plexSort::plexFreePrepare1_s#1 ]
reg byte x [ init::sx#2 init::sx#1 ]
zp ZP_WORD:6 [ init::xp#2 init::xp#1 ]
reg byte x [ init::ss#2 init::ss#1 ]
reg byte x [ plexInit::i#2 plexInit::i#1 ]
zp ZP_BYTE:8 [ plex_sprite_idx#25 plex_sprite_idx#0 plexShowSprite::$8 ]
zp ZP_BYTE:9 [ plex_show_idx#27 plex_show_idx#0 plex_show_idx#16 plex_show_idx#1 ]
zp ZP_BYTE:10 [ plex_free_next#27 plex_free_next#31 plexShowSprite::plexFreeAdd1_$2#0 ]
zp ZP_BYTE:11 [ plex_sprite_msb#29 plex_sprite_msb#0 plex_sprite_msb#17 plex_sprite_msb#27 plex_sprite_msb#4 plex_sprite_msb#1 ]
zp ZP_BYTE:12 [ plexSort::nxt_idx#0 ]
zp ZP_BYTE:13 [ plexSort::nxt_y#0 ]
reg byte x [ plexSort::s#2 ]
zp ZP_BYTE:14 [ plex_sprite_idx#1 ]
zp ZP_BYTE:15 [ plex_free_next#0 ]
reg byte a [ init::$6 ]
reg byte x [ plex_irq::plexFreeNextYpos1_return#0 ]
reg byte a [ plexShowSprite::plexFreeAdd1_ypos#0 ]
reg byte a [ plexShowSprite::plexFreeAdd1_$0#0 ]
reg byte x [ plexShowSprite::plexFreeAdd1_$1#0 ]
reg byte x [ plexShowSprite::xpos_idx#0 ]
reg byte a [ plexShowSprite::$3 ]
reg byte a [ plexShowSprite::$4 ]
reg byte a [ plexShowSprite::$6 ]
reg byte x [ plexShowSprite::$7 ]