diff --git a/src/main/java/dk/camelot64/kickc/model/values/CharToAtasciiConverter.java b/src/main/java/dk/camelot64/kickc/model/values/CharToAtasciiConverter.java index e0756a383..33bdfbf60 100644 --- a/src/main/java/dk/camelot64/kickc/model/values/CharToAtasciiConverter.java +++ b/src/main/java/dk/camelot64/kickc/model/values/CharToAtasciiConverter.java @@ -16,12 +16,36 @@ public class CharToAtasciiConverter { /** Map from UNICODE char to Byte value for Atari Screencode. https://www.atariarchives.org/mapping/appendix10.php */ public static Map charToScreenCodeAtari; + /** ASCII newline encoding. */ + public static final byte NEWLINE_ASCII = 0x0a; + + /** ATASCII newline encoding. */ + public static final byte NEWLINE_ATASCII = (byte) 0x9b; + static { - charToAtascii = CharToPetsciiConverter.charToAscii; - charToScreenCodeAtari = new HashMap<>(); + charToAtascii = getCharToAtascii(); + charToScreenCodeAtari = getCharToScreenCodeAtari(); + } + + private static Map getCharToAtascii() { + Map charToAtascii = new HashMap<>(); + for(Character asciiChar : CharToPetsciiConverter.charToAscii.keySet()) { + final Byte asciiByte = CharToPetsciiConverter.charToAscii.get(asciiChar); + byte atasciiByte; + if(asciiByte == NEWLINE_ASCII) + atasciiByte = NEWLINE_ATASCII; + else + atasciiByte = asciiByte; + charToAtascii.put(asciiChar, atasciiByte); + } + return charToAtascii; + } + + private static Map getCharToScreenCodeAtari() { + Map charToScreenCodeAtari = new HashMap<>(); for(Character atasciiChar : charToAtascii.keySet()) { final Byte atasciiByte = charToAtascii.get(atasciiChar); - Byte screencodeAtariByte; + byte screencodeAtariByte; if(atasciiByte >= 0 && atasciiByte <= 31) screencodeAtariByte = (byte) (atasciiByte + 64); else if(atasciiByte >= 32 && atasciiByte <= 96) @@ -30,6 +54,7 @@ public class CharToAtasciiConverter { screencodeAtariByte = atasciiByte; charToScreenCodeAtari.put(atasciiChar, screencodeAtariByte); } + return charToScreenCodeAtari; } } diff --git a/src/main/kc/include/atari-antic.h b/src/main/kc/include/atari-antic.h index 2e5e1084f..f653982b2 100644 --- a/src/main/kc/include/atari-antic.h +++ b/src/main/kc/include/atari-antic.h @@ -110,4 +110,64 @@ struct ATARI_ANTIC { // - - 1 - - - - - DLI: Display List Interrupt char NMIST; -}; \ No newline at end of file +}; + +// ANTIC Display List Instruction Set + +// 2: High Resolution Text Mode. 8 scanlines per char, 32/40/48 chars wide. bit 7 controls inversion or blinking, based on modes in CHACTL. +const char MODE2 = 0x02; +// 3: High Resolution Text Mode. 10 scanlines per char, 32/40/48 chars wide +const char MODE3 = 0x03; +// 4: Multicolor text. 8 scanlines per char, 32/40/48 chars wide. +const char MODE4 = 0x04; +// 5: Multicolor text. 16 scanlines per char, 32/40/48 chars wide. each character is instead 4x8 with pixels twice as wide. Normally each pair of bits produces either the background color (00) or PF0-PF2 (01-11). If bit 7 is set, however, the 11 pair produces PF3 instead of PF2. +const char MODE5 = 0x05; +// 6: Single color text in five colors. 8 scanlines per char, 16/20/24 chars wide. the upper two bits are used to select the foreground color used by 1 bits, with 00-11 producing PF0-PF3. +const char MODE6 = 0x06; +// 7: Single color text in five colors. 16 scanlines per char, 16/20/24 chars wide. the upper two bits are used to select the foreground color used by 1 bits, with 00-11 producing PF0-PF3. +const char MODE7 = 0x07; +// 8: Bitmap mode with 8x8 pixels. 40 pixel screen. four-color mode. +const char MODE8 = 0x08; +// 9: Bitmap mode with 4x4 pixels. 80 pixel screen. two-color mode. +const char MODE9 = 0x09; +// A: Bitmap mode with 4x4 pixels. 80 pixel screen. four-color mode. +const char MODEA = 0x0a; +// B: Bitmap mode with 2x2 pixels. 160 pixel screen. two-color mode. +const char MODEB = 0x0b; +// C: Bitmap mode with 2x1 pixels. 160 pixel screen. two-color mode. +const char MODEC = 0x0c; +// D: Bitmap mode with 2x2 pixels. 160 pixel screen. four-color mode. +const char MODED = 0x0d; +// E: Bitmap mode with 2x1 pixels. 160 pixel screen. four-color mode. +const char MODEE = 0x0e; +// F: Bitmap mode with 1x1 pixels. 320 pixel screen. two-color mode. +const char MODEF = 0x0f; + +// Display list interrupt - Interrupt CPU at beginning of last scan line. Can be combined with mode or blank instructions by OR. +const char DLI = 0x80; +// Load memory scan counter (LMS operation) - Load memory scan counter with new 16-bit address. Can be combined with mode instructions by OR. +const char LMS = 0x40; +// Vertical scroll - Enable vertical scrolling. Can be combined with mode or blank instructions by OR. +const char VS = 0x20; +// Horizontal scroll - Enable horizontal scrolling. Can be combined with mode or blank instructions by OR. +const char HS = 0x10; +// Jump command - followed by two bytes indicating the new instruction pointer for the display list. +const char JMP = 0x01; +// Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps. This is usually used to terminate the display list and restart it for the next frame. +const char JVB = 0x41; +// Blank 1 line +const char BLANK1 = 0x00; +// Blank 2 lines +const char BLANK2 = 0x10; +// Blank 3 lines +const char BLANK3 = 0x20; +// Blank 4 lines +const char BLANK4 = 0x30; +// Blank 5 lines +const char BLANK5 = 0x40; +// Blank 6 lines +const char BLANK6 = 0x50; +// Blank 7 lines +const char BLANK7 = 0x60; +// Blank 8 lines +const char BLANK8 = 0x70; diff --git a/src/test/kc/examples/atarixl/helloxl.c b/src/test/kc/examples/atarixl/helloxl.c index 881b41c2b..ef2c154b8 100644 --- a/src/test/kc/examples/atarixl/helloxl.c +++ b/src/test/kc/examples/atarixl/helloxl.c @@ -21,12 +21,14 @@ char TEXT[] = "HELLO atari 8BIT" "Demonstrates ANTIC display list" ; + + // 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) - 0x70, // BLK 8 (0x70) 8 blank lines - 0x02, // 2, TEXT (0x02) Charmode 2 (32/40/48 chars wide, 8 lines per char) - 0x41, DISPLAY_LIST // JVB DISPLAY_LIST (0x41) jump and wait for VBLANK + BLANK8, BLANK8, BLANK8, // 3* BLK 8 (0x70) 8 blank lines + LMS|MODE7, TEXT, // LMS TEXT 7 (0x47) Load memory address and set to charmode 7 (16/20/24 chars wide, 16 lines per char) + BLANK8, // BLK 8 (0x70) 8 blank lines + MODE2, // TEXT 2 (0x02) Charmode 2 (32/40/48 chars wide, 8 lines per char) + JVB, 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 index 94023d045..f14d30de9 100644 --- a/src/test/ref/examples/atarixl/helloxl.asm +++ b/src/test/ref/examples/atarixl/helloxl.asm @@ -25,6 +25,16 @@ ProgramStart: .segment ProgramEnd ProgramEnd: + // 2: High Resolution Text Mode. 8 scanlines per char, 32/40/48 chars wide. bit 7 controls inversion or blinking, based on modes in CHACTL. + .const MODE2 = 2 + // 7: Single color text in five colors. 16 scanlines per char, 16/20/24 chars wide. the upper two bits are used to select the foreground color used by 1 bits, with 00-11 producing PF0-PF3. + .const MODE7 = 7 + // Load memory scan counter (LMS operation) - Load memory scan counter with new 16-bit address. Can be combined with mode instructions by OR. + .const LMS = $40 + // Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps. This is usually used to terminate the display list and restart it for the next frame. + .const JVB = $41 + // Blank 8 lines + .const BLANK8 = $70 // OS Shadow ANTIC Direct Memory Access Control ($D400) .label SDMCTL = $22f // OS Shadow ANTIC Display List Pointer ($D402) @@ -52,4 +62,4 @@ main: { .byte 0 // ANTIC Display List Program // https://en.wikipedia.org/wiki/ANTIC - DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $70, 2, $41, DISPLAY_LIST + DISPLAY_LIST: .byte BLANK8, BLANK8, BLANK8, LMS|MODE7, TEXT, BLANK8, MODE2, JVB, DISPLAY_LIST diff --git a/src/test/ref/examples/atarixl/helloxl.log b/src/test/ref/examples/atarixl/helloxl.log index 56a946ac8..775dfdef6 100644 --- a/src/test/ref/examples/atarixl/helloxl.log +++ b/src/test/ref/examples/atarixl/helloxl.log @@ -138,7 +138,12 @@ SYMBOL TABLE SSA (byte) ATARI_POKEY_WRITE::SKREST (byte) ATARI_POKEY_WRITE::STIMER (byte) ATARI_POKEY_WRITE::UNUSED -(const byte*) DISPLAY_LIST[] = { (byte) $70, (byte) $70, (byte) $70, (byte) $47, <(const byte*) TEXT, >(const byte*) TEXT, (byte) $70, (byte) 2, (byte) $41, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte) BLANK8 = (byte) $70 +(const byte*) DISPLAY_LIST[] = { (const nomodify byte) BLANK8, (const nomodify byte) BLANK8, (const nomodify byte) BLANK8, (const nomodify byte) LMS|(const nomodify byte) MODE7, <(const byte*) TEXT, >(const byte*) TEXT, (const nomodify byte) BLANK8, (const nomodify byte) MODE2, (const nomodify byte) JVB, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte) JVB = (byte) $41 +(const nomodify byte) LMS = (byte) $40 +(const nomodify byte) MODE2 = (byte) 2 +(const nomodify byte) MODE7 = (byte) 7 (const nomodify byte**) SDLST = (byte**)(number) $230 (const nomodify byte*) SDMCTL = (byte*)(number) $22f (const byte*) TEXT[] = (byte*) "HELLO atari 8BITDemonstrates ANTIC display list"sa @@ -331,6 +336,16 @@ ProgramStart: ProgramEnd: // Global Constants & labels + // 2: High Resolution Text Mode. 8 scanlines per char, 32/40/48 chars wide. bit 7 controls inversion or blinking, based on modes in CHACTL. + .const MODE2 = 2 + // 7: Single color text in five colors. 16 scanlines per char, 16/20/24 chars wide. the upper two bits are used to select the foreground color used by 1 bits, with 00-11 producing PF0-PF3. + .const MODE7 = 7 + // Load memory scan counter (LMS operation) - Load memory scan counter with new 16-bit address. Can be combined with mode instructions by OR. + .const LMS = $40 + // Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps. This is usually used to terminate the display list and restart it for the next frame. + .const JVB = $41 + // Blank 8 lines + .const BLANK8 = $70 // OS Shadow ANTIC Direct Memory Access Control ($D400) .label SDMCTL = $22f // OS Shadow ANTIC Display List Pointer ($D402) @@ -365,7 +380,7 @@ main: { .byte 0 // ANTIC Display List Program // https://en.wikipedia.org/wiki/ANTIC - DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $70, 2, $41, DISPLAY_LIST + DISPLAY_LIST: .byte BLANK8, BLANK8, BLANK8, LMS|MODE7, TEXT, BLANK8, MODE2, JVB, DISPLAY_LIST REGISTER UPLIFT POTENTIAL REGISTERS Statement [0] *((const nomodify byte*) SDMCTL) ← (byte) $21 [ ] ( [ ] { } ) always clobbers reg byte a @@ -419,6 +434,16 @@ ProgramStart: ProgramEnd: // Global Constants & labels + // 2: High Resolution Text Mode. 8 scanlines per char, 32/40/48 chars wide. bit 7 controls inversion or blinking, based on modes in CHACTL. + .const MODE2 = 2 + // 7: Single color text in five colors. 16 scanlines per char, 16/20/24 chars wide. the upper two bits are used to select the foreground color used by 1 bits, with 00-11 producing PF0-PF3. + .const MODE7 = 7 + // Load memory scan counter (LMS operation) - Load memory scan counter with new 16-bit address. Can be combined with mode instructions by OR. + .const LMS = $40 + // Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps. This is usually used to terminate the display list and restart it for the next frame. + .const JVB = $41 + // Blank 8 lines + .const BLANK8 = $70 // OS Shadow ANTIC Direct Memory Access Control ($D400) .label SDMCTL = $22f // OS Shadow ANTIC Display List Pointer ($D402) @@ -453,7 +478,7 @@ main: { .byte 0 // ANTIC Display List Program // https://en.wikipedia.org/wiki/ANTIC - DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $70, 2, $41, DISPLAY_LIST + DISPLAY_LIST: .byte BLANK8, BLANK8, BLANK8, LMS|MODE7, TEXT, BLANK8, MODE2, JVB, DISPLAY_LIST ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 @@ -567,7 +592,12 @@ FINAL SYMBOL TABLE (byte) ATARI_POKEY_WRITE::SKREST (byte) ATARI_POKEY_WRITE::STIMER (byte) ATARI_POKEY_WRITE::UNUSED -(const byte*) DISPLAY_LIST[] = { (byte) $70, (byte) $70, (byte) $70, (byte) $47, <(const byte*) TEXT, >(const byte*) TEXT, (byte) $70, (byte) 2, (byte) $41, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte) BLANK8 = (byte) $70 +(const byte*) DISPLAY_LIST[] = { (const nomodify byte) BLANK8, (const nomodify byte) BLANK8, (const nomodify byte) BLANK8, (const nomodify byte) LMS|(const nomodify byte) MODE7, <(const byte*) TEXT, >(const byte*) TEXT, (const nomodify byte) BLANK8, (const nomodify byte) MODE2, (const nomodify byte) JVB, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte) JVB = (byte) $41 +(const nomodify byte) LMS = (byte) $40 +(const nomodify byte) MODE2 = (byte) 2 +(const nomodify byte) MODE7 = (byte) 7 (const nomodify byte**) SDLST = (byte**) 560 (const nomodify byte*) SDMCTL = (byte*) 559 (const byte*) TEXT[] = (byte*) "HELLO atari 8BITDemonstrates ANTIC display list"sa @@ -609,6 +639,16 @@ ProgramStart: ProgramEnd: // Global Constants & labels + // 2: High Resolution Text Mode. 8 scanlines per char, 32/40/48 chars wide. bit 7 controls inversion or blinking, based on modes in CHACTL. + .const MODE2 = 2 + // 7: Single color text in five colors. 16 scanlines per char, 16/20/24 chars wide. the upper two bits are used to select the foreground color used by 1 bits, with 00-11 producing PF0-PF3. + .const MODE7 = 7 + // Load memory scan counter (LMS operation) - Load memory scan counter with new 16-bit address. Can be combined with mode instructions by OR. + .const LMS = $40 + // Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps. This is usually used to terminate the display list and restart it for the next frame. + .const JVB = $41 + // Blank 8 lines + .const BLANK8 = $70 // OS Shadow ANTIC Direct Memory Access Control ($D400) .label SDMCTL = $22f // OS Shadow ANTIC Display List Pointer ($D402) @@ -642,5 +682,5 @@ main: { .byte 0 // ANTIC Display List Program // https://en.wikipedia.org/wiki/ANTIC - DISPLAY_LIST: .byte $70, $70, $70, $47, TEXT, $70, 2, $41, DISPLAY_LIST + DISPLAY_LIST: .byte BLANK8, BLANK8, BLANK8, LMS|MODE7, TEXT, BLANK8, MODE2, JVB, DISPLAY_LIST diff --git a/src/test/ref/examples/atarixl/helloxl.sym b/src/test/ref/examples/atarixl/helloxl.sym index 7f524f179..31a09543f 100644 --- a/src/test/ref/examples/atarixl/helloxl.sym +++ b/src/test/ref/examples/atarixl/helloxl.sym @@ -99,7 +99,12 @@ (byte) ATARI_POKEY_WRITE::SKREST (byte) ATARI_POKEY_WRITE::STIMER (byte) ATARI_POKEY_WRITE::UNUSED -(const byte*) DISPLAY_LIST[] = { (byte) $70, (byte) $70, (byte) $70, (byte) $47, <(const byte*) TEXT, >(const byte*) TEXT, (byte) $70, (byte) 2, (byte) $41, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte) BLANK8 = (byte) $70 +(const byte*) DISPLAY_LIST[] = { (const nomodify byte) BLANK8, (const nomodify byte) BLANK8, (const nomodify byte) BLANK8, (const nomodify byte) LMS|(const nomodify byte) MODE7, <(const byte*) TEXT, >(const byte*) TEXT, (const nomodify byte) BLANK8, (const nomodify byte) MODE2, (const nomodify byte) JVB, <(const byte*) DISPLAY_LIST, >(const byte*) DISPLAY_LIST } +(const nomodify byte) JVB = (byte) $41 +(const nomodify byte) LMS = (byte) $40 +(const nomodify byte) MODE2 = (byte) 2 +(const nomodify byte) MODE7 = (byte) 7 (const nomodify byte**) SDLST = (byte**) 560 (const nomodify byte*) SDMCTL = (byte*) 559 (const byte*) TEXT[] = (byte*) "HELLO atari 8BITDemonstrates ANTIC display list"sa