diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java index a5e10d7bc..d32a07d80 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentTemplateSynthesisRule.java @@ -766,12 +766,6 @@ class AsmFragmentTemplateSynthesisRule { // Rewrite (Z1),x to save Y to $FF and reload it into YY synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)z1_derefidx_vbuxx=(.*)", twoZM1, "stx $ff" , "vb$1aa=$2", "ldz $ff\nsta ({z1}),z", mapZM1)); - // TODO: Rewrite (Z1),y assignment to use A - //synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)z1_derefidx_vbuyy=(.*)", twoZM1+"|"+rvalYy, null , "vb$1aa=$2", "sta ({z1}),y", null, "yy")); - //if(targetCpu.getCpu65xx().hasRegisterZ()) - // Rewrite (Z1),z assignment to use A - // synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)z1_derefidx_vbuzz=(.*)", twoZM1+"|"+rvalZz, null , "vb$1aa=$2", "sta ({z1}),z", null, "zz")); - // Rewrite (Z1),a to use TAY prefix synths.add(new AsmFragmentTemplateSynthesisRule("pb(.)z1_derefidx_vbuaa=(.*)", twoZM1+"|"+rvalYy, "tay" , "vb$1aa=$2", "sta ({z1}),y", mapZM1, "yy")); if(targetCpu.getCpu65xx().hasRegisterZ()) diff --git a/src/main/kc/target/atarixl.ld b/src/main/kc/target/atarixl.ld new file mode 100644 index 000000000..7c773d0a0 --- /dev/null +++ b/src/main/kc/target/atarixl.ld @@ -0,0 +1,22 @@ +// Atari XL/XE XEX file minimal file +// https://www.atarimax.com/jindroush.atari.org/afmtexe.html +.file [name="%O", type="bin", segments="XexFile"] +.segmentdef Program [segments="ProgramStart, Code, Data, ProgramEnd"] +.segmentdef ProgramStart [start=$2000] +.segmentdef Code [startAfter="ProgramStart"] +.segmentdef Data [startAfter="Code"] +.segmentdef ProgramEnd [startAfter="Data"] +.segment ProgramStart +ProgramStart: +.segment ProgramEnd +ProgramEnd: +.segmentdef XexFile +.segment XexFile +// Binary File Header +.byte $ff, $ff +// Program segment [start address, end address, data] +.word ProgramStart, ProgramEnd +.segmentout [ segments="Program" ] +// RunAd - Run Address Segment [start address, end address, data] +.word $02e0, $02e1 +.word %E \ No newline at end of file diff --git a/src/main/kc/target/atarixl.tgt b/src/main/kc/target/atarixl.tgt new file mode 100644 index 000000000..6ee8bbf3b --- /dev/null +++ b/src/main/kc/target/atarixl.tgt @@ -0,0 +1,9 @@ +{ + "extension": "xex", + "link": "atarixl.ld", + "cpu": "MOS6502X", + "emulator": "65XEDebugger", + "defines": { + "__ATARIXL__": 1 + } +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 6625aee98..1291e1025 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -192,6 +192,11 @@ public class TestPrograms { compileAndCompare("examples/nes-demo/nes-demo.c"); } + @Test + public void testAtariXlHello() throws IOException, URISyntaxException { + compileAndCompare("examples/atarixl/helloxl.c"); + } + @Test public void testAtari2600Sprites() throws IOException, URISyntaxException { compileAndCompare("examples/atari2600/atari2600-sprites.c"); diff --git a/src/test/kc/examples/atarixl/helloxl.c b/src/test/kc/examples/atarixl/helloxl.c new file mode 100644 index 000000000..8e3fd91eb --- /dev/null +++ b/src/test/kc/examples/atarixl/helloxl.c @@ -0,0 +1,64 @@ +// Hello World for Atari XL / XE +// XEX file format https://www.atarimax.com/jindroush.atari.org/afmtexe.html +// Minimal Hello World https://atariage.com/forums/topic/229742-help-with-hello-world-in-mads/ +// Display Lists atariarchives.org/mapping/appendix8.php + +#pragma target(atarixl) + +// Direct Memory Access Control +// 7 6 5 4 3 2 1 0 +// - - - - - - 0 0 No playfield +// - - - - - - 0 1 Narrow playfield (128 color clocks 32 characters) +// - - - - - - 1 0 Standard playfield (160 color clocks 40 characters) (default) +// - - - - - - 1 1 Wide playfield (192 color clocks 48 characters) +// - - - - - 1 - - Enable missle DMA +// - - - - 1 - - - Enable player DMA +// - - - 1 - - - - One line player resolution +// - - - 0 - - - - Two-line player resolution (default) +// - - 1 - - - - - Enable DMA for fetching the display list instructions (default) +// SHADOW: SDMCTL $022F +char * const ANTIC_DMACTL = 0xd400; + +// OS Shadow ANTIC Direct Memory Access Control +char * const SDMCTL = 0x022f; + +// Character Control +// 7 6 5 4 3 2 1 0 +// - - - - - - - 1 Video Blank. Inverse video characters display as blanks spaces. +// - - - - - - 1 - Video Inverse. Inverse video characters appear as inverse video. (default) +// - - - - - 1 - - Video Reflect. All characters are displayed vertically mirrored. +// SHADOW: CHART $02F3 +char * const ANTIC_CHACTL = 0xd401; + +// OS Shadow ANTIC Character Control +char * const CHART = 0x02f3; + +// Display List Pointer +// ANTIC begins executing the Display List pointed to by the 16-bit address in registers DLISTL/DLISTH +// SHADOW: SDLSTL/SDLSTH $0230/$0231 +char ** const ANTIC_DLIST = 0xd402; + +// OS Shadow ANTIC Display List Pointer +char ** const SDLST = 0x0230; + +void main() { + // Enable DMA, Narrow Playfield into Shadow ANTIC Direct Memory Access Control + *SDMCTL = 0x21; + // Set Shadow ANTIC Display List Pointer + *SDLST = DISPLAY_LIST; + // Loop forever + while (1) ; +} + +// Message to show +// Encoding: atari_internal +char TEXT[] = {'h'|0x20,'e'|0x20,'l'|0x20,'l'|0x20,'o'|0x20,0x0,'x'|0x60,'t'|0x60,0x0,'w'|0x20,'o'|0x20,'r'|0x20,'l'|0x20,'d'|0x20,0x41,0x0,0x0,0x0,0x0}; + +// ANTIC Display List Program +// https://en.wikipedia.org/wiki/ANTIC +char DISPLAY_LIST[] = { + 0x70, 0x70, 0x70, // 3* BLK 8 (0x70) 8 blank lines + 0x47, TEXT, // LMS 7, TEXT (0x47) Load memory address and set to charmode 7 (16/20/24 chars wide, 16 lines per char) + 0x41, DISPLAY_LIST // JVB DISPLAY_LIST (0x41) jump and wait for VBLANK +}; + diff --git a/src/test/ref/examples/atarixl/helloxl.asm b/src/test/ref/examples/atarixl/helloxl.asm new file mode 100644 index 000000000..26bb98578 --- /dev/null +++ b/src/test/ref/examples/atarixl/helloxl.asm @@ -0,0 +1,53 @@ +// Hello World for Atari XL / XE +// XEX file format https://www.atarimax.com/jindroush.atari.org/afmtexe.html +// Minimal Hello World https://atariage.com/forums/topic/229742-help-with-hello-world-in-mads/ +// Display Lists atariarchives.org/mapping/appendix8.php + // Atari XL/XE minimal XEX file +// https://www.atarimax.com/jindroush.atari.org/afmtexe.html +.file [name="helloxl.xex", type="bin", segments="XexFile"] +.segmentdef Program [segments="ProgramStart, Code, Data, ProgramEnd"] +.segmentdef ProgramStart [start=$2000] +.segmentdef Code [startAfter="ProgramStart"] +.segmentdef Data [startAfter="Code"] +.segmentdef ProgramEnd [startAfter="Data"] +.segment ProgramStart +ProgramStart: +.segment ProgramEnd +ProgramEnd: +.segmentdef XexFile +.segment XexFile +// Binary File Header +.byte $ff, $ff +// Program segment [start address, end address, data] +.word ProgramStart, ProgramEnd +.segmentout [ segments="Program" ] +// RunAd - Run Address Segment [start address, end address, data] +.word $02e0, $02e1 +.word main + // OS Shadow ANTIC Direct Memory Access Control + .label SDMCTL = $22f + // OS Shadow ANTIC Display List Pointer + .label SDLST = $230 +.segment Code +main: { + // *SDMCTL = 0x21 + // Enable DMA, Narrow Playfield into Shadow ANTIC Direct Memory Access Control + lda #$21 + sta SDMCTL + // *SDLST = DISPLAY_LIST + // Set Shadow ANTIC Display List Pointer + lda #DISPLAY_LIST + sta SDLST+1 + __b1: + // Loop forever + jmp __b1 +} +.segment Data + // Message to show + // Encoding: atari_internal + TEXT: .byte 'h'|$20, 'e'|$20, 'l'|$20, 'l'|$20, 'o'|$20, 0, 'x'|$60, 't'|$60, 0, 'w'|$20, 'o'|$20, 'r'|$20, 'l'|$20, 'd'|$20, $41, 0, 0, 0, 0 + // ANTIC Display List Program + // https://en.wikipedia.org/wiki/ANTIC + DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $41, DISPLAY_LIST diff --git a/src/test/ref/examples/atarixl/helloxl.cfg b/src/test/ref/examples/atarixl/helloxl.cfg new file mode 100644 index 000000000..cba3e286c --- /dev/null +++ b/src/test/ref/examples/atarixl/helloxl.cfg @@ -0,0 +1,9 @@ + +(void()) main() +main: scope:[main] from + [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 + [1] *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST + to:main::@1 +main::@1: scope:[main] from main main::@1 + [2] phi() + to:main::@1 diff --git a/src/test/ref/examples/atarixl/helloxl.log b/src/test/ref/examples/atarixl/helloxl.log new file mode 100644 index 000000000..0305f2a1e --- /dev/null +++ b/src/test/ref/examples/atarixl/helloxl.log @@ -0,0 +1,363 @@ +Resolved forward reference DISPLAY_LIST to (const byte*) DISPLAY_LIST + +CONTROL FLOW GRAPH SSA + +(void()) main() +main: scope:[main] from __start + *((const nomodify byte*) SDMCTL) ← (number) $21 + *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST + to:main::@1 +main::@1: scope:[main] from main main::@1 + (bool~) main::$0 ← (number) 0 != (number) 1 + if((bool~) main::$0) goto main::@1 + to:main::@return +main::@return: scope:[main] from main::@1 + return + to:@return + +(void()) __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +(const byte*) DISPLAY_LIST[] = { (byte) $70, (byte) $70, (byte) $70, (byte) $47, <(const byte*) TEXT, >(const byte*) TEXT, (byte) $41, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte**) SDLST = (byte**)(number) $230 +(const nomodify byte*) SDMCTL = (byte*)(number) $22f +(const byte*) TEXT[] = { (byte)(byte) 'h'|(number) $20, (byte)(byte) 'e'|(number) $20, (byte)(byte) 'l'|(number) $20, (byte)(byte) 'l'|(number) $20, (byte)(byte) 'o'|(number) $20, (byte) 0, (byte)(byte) 'x'|(number) $60, (byte)(byte) 't'|(number) $60, (byte) 0, (byte)(byte) 'w'|(number) $20, (byte)(byte) 'o'|(number) $20, (byte)(byte) 'r'|(number) $20, (byte)(byte) 'l'|(number) $20, (byte)(byte) 'd'|(number) $20, (byte) $41, (byte) 0, (byte) 0, (byte) 0, (byte) 0 } +(void()) __start() +(label) __start::@1 +(label) __start::@return +(void()) main() +(bool~) main::$0 +(label) main::@1 +(label) main::@return + +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $60 in +Adding number conversion cast (unumber) $60 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $20 in +Adding number conversion cast (unumber) $21 in *((const nomodify byte*) SDMCTL) ← (number) $21 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *((const nomodify byte*) SDMCTL) ← (unumber)(number) $21 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 559 +Simplifying constant pointer cast (byte**) 560 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $60 +Simplifying constant integer cast $60 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $20 +Simplifying constant integer cast $21 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $60 +Finalized unsigned number type (byte) $60 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $20 +Finalized unsigned number type (byte) $21 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Simple Condition (bool~) main::$0 [3] if((number) 0!=(number) 1) goto main::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +if() condition always true - replacing block destination [3] if((number) 0!=(number) 1) goto main::@1 +Successful SSA optimization Pass2ConstantIfs +Removing unused block main::@return +Successful SSA optimization Pass2EliminateUnusedBlocks +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Simplifying constant integer cast (byte) 'h'|(byte) $20 +Simplifying constant integer cast (byte) 'e'|(byte) $20 +Simplifying constant integer cast (byte) 'l'|(byte) $20 +Simplifying constant integer cast (byte) 'l'|(byte) $20 +Simplifying constant integer cast (byte) 'o'|(byte) $20 +Simplifying constant integer cast (byte) 'x'|(byte) $60 +Simplifying constant integer cast (byte) 't'|(byte) $60 +Simplifying constant integer cast (byte) 'w'|(byte) $20 +Simplifying constant integer cast (byte) 'o'|(byte) $20 +Simplifying constant integer cast (byte) 'r'|(byte) $20 +Simplifying constant integer cast (byte) 'l'|(byte) $20 +Simplifying constant integer cast (byte) 'd'|(byte) $20 +Successful SSA optimization PassNCastSimplification +Adding NOP phi() at start of main::@1 +CALL GRAPH + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Adding NOP phi() at start of main::@1 + +FINAL CONTROL FLOW GRAPH + +(void()) main() +main: scope:[main] from + [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 + [1] *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST + to:main::@1 +main::@1: scope:[main] from main main::@1 + [2] phi() + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +(void()) main() + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +Target platform is atarixl / MOS6502X + // File Comments +// Hello World for Atari XL / XE +// XEX file format https://www.atarimax.com/jindroush.atari.org/afmtexe.html +// Minimal Hello World https://atariage.com/forums/topic/229742-help-with-hello-world-in-mads/ +// Display Lists atariarchives.org/mapping/appendix8.php + // Upstart + // Atari XL/XE minimal XEX file +// https://www.atarimax.com/jindroush.atari.org/afmtexe.html +.file [name="helloxl.xex", type="bin", segments="XexFile"] +.segmentdef Program [segments="ProgramStart, Code, Data, ProgramEnd"] +.segmentdef ProgramStart [start=$2000] +.segmentdef Code [startAfter="ProgramStart"] +.segmentdef Data [startAfter="Code"] +.segmentdef ProgramEnd [startAfter="Data"] +.segment ProgramStart +ProgramStart: +.segment ProgramEnd +ProgramEnd: +.segmentdef XexFile +.segment XexFile +// Binary File Header +.byte $ff, $ff +// Program segment [start address, end address, data] +.word ProgramStart, ProgramEnd +.segmentout [ segments="Program" ] +// RunAd - Run Address Segment [start address, end address, data] +.word $02e0, $02e1 +.word main + // Global Constants & labels + // OS Shadow ANTIC Direct Memory Access Control + .label SDMCTL = $22f + // OS Shadow ANTIC Display List Pointer + .label SDLST = $230 +.segment Code + // main +main: { + // [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 -- _deref_pbuc1=vbuc2 + // Enable DMA, Narrow Playfield into Shadow ANTIC Direct Memory Access Control + lda #$21 + sta SDMCTL + // [1] *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST -- _deref_qbuc1=pbuc2 + // Set Shadow ANTIC Display List Pointer + lda #DISPLAY_LIST + sta SDLST+1 + // [2] phi from main main::@1 to main::@1 [phi:main/main::@1->main::@1] + __b1_from_main: + __b1_from___b1: + jmp __b1 + // Loop forever + // main::@1 + __b1: + jmp __b1_from___b1 +} + // File Data +.segment Data + // Message to show + // Encoding: atari_internal + TEXT: .byte 'h'|$20, 'e'|$20, 'l'|$20, 'l'|$20, 'o'|$20, 0, 'x'|$60, 't'|$60, 0, 'w'|$20, 'o'|$20, 'r'|$20, 'l'|$20, 'd'|$20, $41, 0, 0, 0, 0 + // ANTIC Display List Program + // https://en.wikipedia.org/wiki/ANTIC + DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $41, DISPLAY_LIST + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 [ ] ( [ ] { } ) always clobbers reg byte a +Statement [1] *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST [ ] ( [ ] { } ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 78 combination +Uplifting [] best 78 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Hello World for Atari XL / XE +// XEX file format https://www.atarimax.com/jindroush.atari.org/afmtexe.html +// Minimal Hello World https://atariage.com/forums/topic/229742-help-with-hello-world-in-mads/ +// Display Lists atariarchives.org/mapping/appendix8.php + // Upstart + // Atari XL/XE minimal XEX file +// https://www.atarimax.com/jindroush.atari.org/afmtexe.html +.file [name="helloxl.xex", type="bin", segments="XexFile"] +.segmentdef Program [segments="ProgramStart, Code, Data, ProgramEnd"] +.segmentdef ProgramStart [start=$2000] +.segmentdef Code [startAfter="ProgramStart"] +.segmentdef Data [startAfter="Code"] +.segmentdef ProgramEnd [startAfter="Data"] +.segment ProgramStart +ProgramStart: +.segment ProgramEnd +ProgramEnd: +.segmentdef XexFile +.segment XexFile +// Binary File Header +.byte $ff, $ff +// Program segment [start address, end address, data] +.word ProgramStart, ProgramEnd +.segmentout [ segments="Program" ] +// RunAd - Run Address Segment [start address, end address, data] +.word $02e0, $02e1 +.word main + // Global Constants & labels + // OS Shadow ANTIC Direct Memory Access Control + .label SDMCTL = $22f + // OS Shadow ANTIC Display List Pointer + .label SDLST = $230 +.segment Code + // main +main: { + // [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 -- _deref_pbuc1=vbuc2 + // Enable DMA, Narrow Playfield into Shadow ANTIC Direct Memory Access Control + lda #$21 + sta SDMCTL + // [1] *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST -- _deref_qbuc1=pbuc2 + // Set Shadow ANTIC Display List Pointer + lda #DISPLAY_LIST + sta SDLST+1 + // [2] phi from main main::@1 to main::@1 [phi:main/main::@1->main::@1] + __b1_from_main: + __b1_from___b1: + jmp __b1 + // Loop forever + // main::@1 + __b1: + jmp __b1_from___b1 +} + // File Data +.segment Data + // Message to show + // Encoding: atari_internal + TEXT: .byte 'h'|$20, 'e'|$20, 'l'|$20, 'l'|$20, 'o'|$20, 0, 'x'|$60, 't'|$60, 0, 'w'|$20, 'o'|$20, 'r'|$20, 'l'|$20, 'd'|$20, $41, 0, 0, 0, 0 + // ANTIC Display List Program + // https://en.wikipedia.org/wiki/ANTIC + DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $41, DISPLAY_LIST + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction __b1_from_main: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __b1: +Succesful ASM optimization Pass5UnusedLabelElimination +Relabelling long label __b1_from___b1 to __b1 +Succesful ASM optimization Pass5RelabelLongLabels + +FINAL SYMBOL TABLE +(const byte*) DISPLAY_LIST[] = { (byte) $70, (byte) $70, (byte) $70, (byte) $47, <(const byte*) TEXT, >(const byte*) TEXT, (byte) $41, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte**) SDLST = (byte**) 560 +(const nomodify byte*) SDMCTL = (byte*) 559 +(const byte*) TEXT[] = { (byte) 'h'|(byte) $20, (byte) 'e'|(byte) $20, (byte) 'l'|(byte) $20, (byte) 'l'|(byte) $20, (byte) 'o'|(byte) $20, (byte) 0, (byte) 'x'|(byte) $60, (byte) 't'|(byte) $60, (byte) 0, (byte) 'w'|(byte) $20, (byte) 'o'|(byte) $20, (byte) 'r'|(byte) $20, (byte) 'l'|(byte) $20, (byte) 'd'|(byte) $20, (byte) $41, (byte) 0, (byte) 0, (byte) 0, (byte) 0 } +(void()) main() +(label) main::@1 + + + +FINAL ASSEMBLER +Score: 48 + + // File Comments +// Hello World for Atari XL / XE +// XEX file format https://www.atarimax.com/jindroush.atari.org/afmtexe.html +// Minimal Hello World https://atariage.com/forums/topic/229742-help-with-hello-world-in-mads/ +// Display Lists atariarchives.org/mapping/appendix8.php + // Upstart + // Atari XL/XE minimal XEX file +// https://www.atarimax.com/jindroush.atari.org/afmtexe.html +.file [name="helloxl.xex", type="bin", segments="XexFile"] +.segmentdef Program [segments="ProgramStart, Code, Data, ProgramEnd"] +.segmentdef ProgramStart [start=$2000] +.segmentdef Code [startAfter="ProgramStart"] +.segmentdef Data [startAfter="Code"] +.segmentdef ProgramEnd [startAfter="Data"] +.segment ProgramStart +ProgramStart: +.segment ProgramEnd +ProgramEnd: +.segmentdef XexFile +.segment XexFile +// Binary File Header +.byte $ff, $ff +// Program segment [start address, end address, data] +.word ProgramStart, ProgramEnd +.segmentout [ segments="Program" ] +// RunAd - Run Address Segment [start address, end address, data] +.word $02e0, $02e1 +.word main + // Global Constants & labels + // OS Shadow ANTIC Direct Memory Access Control + .label SDMCTL = $22f + // OS Shadow ANTIC Display List Pointer + .label SDLST = $230 +.segment Code + // main +main: { + // *SDMCTL = 0x21 + // [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 -- _deref_pbuc1=vbuc2 + // Enable DMA, Narrow Playfield into Shadow ANTIC Direct Memory Access Control + lda #$21 + sta SDMCTL + // *SDLST = DISPLAY_LIST + // [1] *((const nomodify byte**) SDLST) ← (const byte*) DISPLAY_LIST -- _deref_qbuc1=pbuc2 + // Set Shadow ANTIC Display List Pointer + lda #DISPLAY_LIST + sta SDLST+1 + // [2] phi from main main::@1 to main::@1 [phi:main/main::@1->main::@1] + __b1: + // Loop forever + // main::@1 + jmp __b1 +} + // File Data +.segment Data + // Message to show + // Encoding: atari_internal + TEXT: .byte 'h'|$20, 'e'|$20, 'l'|$20, 'l'|$20, 'o'|$20, 0, 'x'|$60, 't'|$60, 0, 'w'|$20, 'o'|$20, 'r'|$20, 'l'|$20, 'd'|$20, $41, 0, 0, 0, 0 + // ANTIC Display List Program + // https://en.wikipedia.org/wiki/ANTIC + DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $41, DISPLAY_LIST + diff --git a/src/test/ref/examples/atarixl/helloxl.sym b/src/test/ref/examples/atarixl/helloxl.sym new file mode 100644 index 000000000..faf09cc6f --- /dev/null +++ b/src/test/ref/examples/atarixl/helloxl.sym @@ -0,0 +1,7 @@ +(const byte*) DISPLAY_LIST[] = { (byte) $70, (byte) $70, (byte) $70, (byte) $47, <(const byte*) TEXT, >(const byte*) TEXT, (byte) $41, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte**) SDLST = (byte**) 560 +(const nomodify byte*) SDMCTL = (byte*) 559 +(const byte*) TEXT[] = { (byte) 'h'|(byte) $20, (byte) 'e'|(byte) $20, (byte) 'l'|(byte) $20, (byte) 'l'|(byte) $20, (byte) 'o'|(byte) $20, (byte) 0, (byte) 'x'|(byte) $60, (byte) 't'|(byte) $60, (byte) 0, (byte) 'w'|(byte) $20, (byte) 'o'|(byte) $20, (byte) 'r'|(byte) $20, (byte) 'l'|(byte) $20, (byte) 'd'|(byte) $20, (byte) $41, (byte) 0, (byte) 0, (byte) 0, (byte) 0 } +(void()) main() +(label) main::@1 +