mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-23 13:31:12 +00:00
Add conio implementation for Atari XL target
This commit is contained in:
parent
e3662e22d6
commit
b38626f018
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,4 +6,6 @@
|
||||
*/bin/
|
||||
*/workspace.xml
|
||||
./target/
|
||||
target/
|
||||
**/.DS_Store
|
||||
.project
|
||||
|
@ -0,0 +1,8 @@
|
||||
ldy {c1}
|
||||
sty $fe
|
||||
ldy {c1}+1
|
||||
sty $ff
|
||||
ldy #0
|
||||
lda ($fe),y
|
||||
eor #{c2}
|
||||
sta ($fe),y
|
@ -0,0 +1,3 @@
|
||||
lda {z1}
|
||||
ldy #0
|
||||
sta ({z2}),y
|
@ -0,0 +1,8 @@
|
||||
ldy #1
|
||||
lda ({c1}),y
|
||||
bne !+
|
||||
dey
|
||||
lda ({c1}),y
|
||||
cmp #{c2}
|
||||
beq {la1}
|
||||
!:
|
@ -0,0 +1,7 @@
|
||||
ldy #1
|
||||
lda ({c1}),y
|
||||
bne {la1}
|
||||
dey
|
||||
lda ({c1}),y
|
||||
cmp #{c2}
|
||||
bne {la1}
|
@ -0,0 +1,7 @@
|
||||
ldy {c1}
|
||||
sty $fe
|
||||
ldy {c1}+1
|
||||
sty $ff
|
||||
ldy #0
|
||||
lda ($fe),y
|
||||
eor #{c2}
|
@ -0,0 +1,2 @@
|
||||
lda {c1}
|
||||
and #{c2}
|
@ -0,0 +1,8 @@
|
||||
ldy {c1}
|
||||
sty $fe
|
||||
ldy {c1}+1
|
||||
sty $ff
|
||||
ldy #0
|
||||
lda ($fe),y
|
||||
eor #{c2}
|
||||
sta {z1}
|
@ -0,0 +1,3 @@
|
||||
lda {c1}
|
||||
and #{c2}
|
||||
sta {z1}
|
@ -5,6 +5,30 @@
|
||||
#include <atari-gtia.h>
|
||||
#include <atari-pokey.h>
|
||||
|
||||
// Atari ZP registers
|
||||
|
||||
// 1-byte cursor row
|
||||
char * ROWCRS = 0x54;
|
||||
|
||||
// 2-byte cursor column
|
||||
word * COLCRS = 0x55;
|
||||
|
||||
// 2-byte saved memory scan counter
|
||||
char ** const SAVMSC = 0x58;
|
||||
|
||||
// data under cursor
|
||||
char * const OLDCHR = 0x5D;
|
||||
|
||||
// 2-byte saved cursor memory address
|
||||
char ** const OLDADR = 0x5E;
|
||||
|
||||
// Cursor inhibit flag, 0 turns on, any other number turns off. Cursor doesn't change until it moves next.
|
||||
char * const CRSINH = 0x2F0;
|
||||
|
||||
// Internal hardware value for the last key pressed. Set to 0xFF to clear.
|
||||
char * const CH = 0x2FC;
|
||||
|
||||
|
||||
// Atari GTIA write registers
|
||||
struct ATARI_GTIA_WRITE * const GTIA = 0xd000;
|
||||
|
||||
@ -40,3 +64,38 @@ char * LPENH = 0x234;
|
||||
// OS Shadow ANTIC Light Pen Vertical Position ($D40D)
|
||||
char * LPENV = 0x235;
|
||||
|
||||
// Color register zero, color of playfield zero. Shadow for 53270 ($D016)
|
||||
char * const COLOR0 = 0x2C4;
|
||||
|
||||
// Shadow for 53271 ($D017). Text color in Gr.0
|
||||
char * const COLOR1 = 0x2C5;
|
||||
|
||||
// Shadow for 53272 ($D018). Background color in GR.0
|
||||
char * const COLOR2 = 0x2C6;
|
||||
|
||||
// Shadow for 53273 ($D019)
|
||||
char * const COLOR3 = 0x2C7;
|
||||
|
||||
// Shadow for 53274 ($D01A). Border color in GR.0
|
||||
char * const COLOR4 = 0x2C8;
|
||||
|
||||
// Atari colours - names from Mapping the Atari.
|
||||
// Add luminance values 0-14 (even only) to increase brightness
|
||||
const char BLACK = 0x00;
|
||||
const char RUST = 0x10;
|
||||
const char RED_ORANGE = 0x20;
|
||||
const char DARK_ORANGE = 0x30;
|
||||
const char RED = 0x40;
|
||||
const char DARK_LAVENDER = 0x50;
|
||||
const char COBALT_BLUE = 0x60;
|
||||
const char ULTRAMARINE = 0x70;
|
||||
const char MEDIUM_BLUE = 0x80;
|
||||
const char DARK_BLUE = 0x90;
|
||||
const char BLUE_GREY = 0xA0;
|
||||
const char OLIVE_GREEN = 0xB0;
|
||||
const char MEDIUM_GREEN = 0xC0;
|
||||
const char DARK_GREEN = 0xD0;
|
||||
const char ORANGE_GREEN = 0xE0;
|
||||
const char ORANGE = 0xF0;
|
||||
|
||||
const char WHITE = 0xFE;
|
||||
|
239
src/main/kc/lib/conio-atarixl.c
Normal file
239
src/main/kc/lib/conio-atarixl.c
Normal file
@ -0,0 +1,239 @@
|
||||
// Atari XL conio.h implementation
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <atari-xl.h>
|
||||
|
||||
// The screen width
|
||||
#define CONIO_WIDTH 40
|
||||
// The screen height
|
||||
#define CONIO_HEIGHT 24
|
||||
|
||||
// The current reverse value indicator. Values 0 or 0x80 for reverse text
|
||||
__ma char conio_reverse_value = 0;
|
||||
|
||||
// The current cursor enable flag. 1 = on, 0 = off.
|
||||
__ma char conio_display_cursor = 1;
|
||||
|
||||
// The current scroll enable flag. 1 = on, 0 = off.
|
||||
__ma char conio_scroll_enable = 1;
|
||||
|
||||
// Move cursor and output one character
|
||||
// Same as "gotoxy (x, y); cputc (c);"
|
||||
void cputcxy(unsigned char x, unsigned char y, char c) {
|
||||
gotoxy(x, y);
|
||||
cputc(c);
|
||||
}
|
||||
|
||||
// Output one character at the current cursor position
|
||||
// Moves the cursor forward. Scrolls the entire screen if needed
|
||||
void cputc(char c) {
|
||||
char screenCode;
|
||||
if (c == '\r') { // 0x0d, CR = just set the cursor x value to 0
|
||||
*COLCRS = 0;
|
||||
setcursor();
|
||||
} else if(c == '\n' || c == 0x9b) { // 0x0a LF, or atascii EOL
|
||||
*COLCRS = 0;
|
||||
newline();
|
||||
} else {
|
||||
putchar(convertToScreenCode(&c));
|
||||
(*COLCRS)++;
|
||||
if (*COLCRS == CONIO_WIDTH) {
|
||||
*COLCRS = 0;
|
||||
newline();
|
||||
} else {
|
||||
setcursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Puts a character to the screen a the current location. Uses internal screencode. Deals with storing the old cursor value
|
||||
void putchar(unsigned char code) {
|
||||
**OLDADR = *OLDCHR;
|
||||
char * loc = cursorLocation();
|
||||
char newChar = code | conio_reverse_value;
|
||||
*loc = newChar;
|
||||
*OLDCHR = newChar;
|
||||
setcursor();
|
||||
}
|
||||
|
||||
// Output a NUL-terminated string at the current cursor position
|
||||
void cputs(const char* s) {
|
||||
char c;
|
||||
while (c = *s++) {
|
||||
cputc(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Move cursor and output a NUL-terminated string
|
||||
// Same as "gotoxy (x, y); puts (s);"
|
||||
void cputsxy(unsigned char x, unsigned char y, const char* s) {
|
||||
gotoxy(x, y);
|
||||
cputs(s);
|
||||
}
|
||||
|
||||
// Return a pointer to the location of the cursor
|
||||
char * cursorLocation() {
|
||||
return *SAVMSC + (word)(*ROWCRS)*CONIO_WIDTH + *COLCRS;
|
||||
}
|
||||
|
||||
void newline() {
|
||||
if ((*ROWCRS)++ == CONIO_HEIGHT) {
|
||||
if (conio_scroll_enable == 1) {
|
||||
// first hide the current screen cursor, so it doesn't scroll, but only if it is on
|
||||
if (conio_display_cursor == 1) {
|
||||
**OLDADR ^= 0x80;
|
||||
}
|
||||
// move screen up 1 line
|
||||
char * start = *SAVMSC;
|
||||
memcpy(start, start + CONIO_WIDTH, CONIO_WIDTH * 23);
|
||||
memset(start + CONIO_WIDTH * 23, 0x00, CONIO_WIDTH);
|
||||
*ROWCRS = CONIO_HEIGHT - 1;
|
||||
} else {
|
||||
gotoxy(0, 0);
|
||||
}
|
||||
}
|
||||
setcursor();
|
||||
}
|
||||
|
||||
// Handles cursor movement, displaying it if required, and inverting character it is over if there is one (and enabled)
|
||||
void setcursor() {
|
||||
// save the current oldchr into oldadr
|
||||
**OLDADR = *OLDCHR;
|
||||
// work out the new location for oldadr based on new column/row
|
||||
char * loc = cursorLocation();
|
||||
char c = *loc;
|
||||
*OLDCHR = c;
|
||||
*OLDADR = loc;
|
||||
if (conio_display_cursor == 0) {
|
||||
// cursor is off, don't affect the character at all, but do turn off cursor
|
||||
*CRSINH = 1;
|
||||
} else {
|
||||
// cursor is on, so invert the inverse bit and turn cursor on
|
||||
*CRSINH = 0;
|
||||
c = c ^ 0x80;
|
||||
}
|
||||
**OLDADR = c;
|
||||
}
|
||||
|
||||
// Print a newline
|
||||
void cputln() {
|
||||
*COLCRS = 0;
|
||||
newline();
|
||||
}
|
||||
|
||||
// Set the cursor to the specified position
|
||||
void gotoxy(unsigned char x, unsigned char y) {
|
||||
*COLCRS = x;
|
||||
*ROWCRS = y;
|
||||
setcursor();
|
||||
}
|
||||
|
||||
// Sets reverse mode for text. 1 enables reverse, 0 disables. Returns the old value.
|
||||
unsigned char revers(unsigned char onoff) {
|
||||
char old = conio_reverse_value;
|
||||
if (onoff == 0) conio_reverse_value = 0; else conio_reverse_value = 0x80;
|
||||
return old;
|
||||
}
|
||||
|
||||
// If onoff is 1, scrolling is enabled when outputting past the end of the screen
|
||||
// If onoff is 0, scrolling is disabled and the cursor instead moves to (0,0)
|
||||
// The function returns the old scroll setting.
|
||||
unsigned char scroll(unsigned char onoff) {
|
||||
char old = conio_scroll_enable;
|
||||
conio_scroll_enable = onoff;
|
||||
return old;
|
||||
}
|
||||
|
||||
// clears the screen and moves the cursor to the upper left-hand corner of the screen.
|
||||
void clrscr() {
|
||||
// Fill entire screen with spaces
|
||||
memset(*SAVMSC, 0x00, CONIO_WIDTH * CONIO_HEIGHT); // 0x00 is screencode for space character
|
||||
// set the old character to a space so the cursor doesn't reappear at the last position it was at
|
||||
*OLDCHR = 0x00;
|
||||
gotoxy(0,0);
|
||||
}
|
||||
|
||||
// If onoff is 1, a cursor is displayed when any text is output.
|
||||
// If onoff is 0, the cursor is hidden instead.
|
||||
unsigned char cursor(unsigned char onoff) {
|
||||
// this just updates internal cursor flag value, doesn't update CRSINH
|
||||
// onoff: 0 => cursor off, 1 => cursor on
|
||||
// CRSINH is opposite to this, 0 == ON, 1 == OFF
|
||||
char oldValue = conio_display_cursor;
|
||||
conio_display_cursor = onoff;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
// Return the X position of the cursor
|
||||
unsigned char wherex() {
|
||||
return (*COLCRS & 0xff);
|
||||
}
|
||||
|
||||
// Return the Y position of the cursor
|
||||
unsigned char wherey() {
|
||||
return *ROWCRS;
|
||||
}
|
||||
|
||||
// Return the current screen size.
|
||||
void screensize(unsigned char *x, unsigned char *y) {
|
||||
*x = CONIO_WIDTH;
|
||||
*y = CONIO_HEIGHT;
|
||||
}
|
||||
|
||||
// Return the current screen size X width.
|
||||
char screensizex() {
|
||||
return CONIO_WIDTH;
|
||||
}
|
||||
|
||||
// Return the current screen size Y height.
|
||||
char screensizey() {
|
||||
return CONIO_HEIGHT;
|
||||
}
|
||||
|
||||
// Return 1 if there's a key waiting, return 0 if not
|
||||
unsigned char kbhit() {
|
||||
if (*CH == 0xff) return 0; else return 1;
|
||||
}
|
||||
|
||||
// Clears the key waiting buffer.
|
||||
inline void clrkb() {
|
||||
*CH = 0xff;
|
||||
}
|
||||
|
||||
// Set the color for the text. The old color setting is returned.
|
||||
unsigned char textcolor(unsigned char color) {
|
||||
char old = *COLOR1;
|
||||
*COLOR1 = color;
|
||||
return old;
|
||||
}
|
||||
|
||||
// Set the color for the background. The old color setting is returned.
|
||||
unsigned char bgcolor(unsigned char color) {
|
||||
char old = *COLOR2;
|
||||
*COLOR2 = color;
|
||||
return old;
|
||||
}
|
||||
|
||||
// Set the color for the border. The old color setting is returned.
|
||||
unsigned char bordercolor(unsigned char color) {
|
||||
char old = *COLOR4;
|
||||
*COLOR4 = color;
|
||||
return old;
|
||||
}
|
||||
|
||||
// Convert an atascii character to its screen code representation. Requires 1 page lookup table generated below.
|
||||
inline unsigned char convertToScreenCode(unsigned char* v) {
|
||||
return rawmap[*v];
|
||||
}
|
||||
|
||||
// create a static table to map char value to screen value
|
||||
// use KickAsm functions to create a table of code -> screen code values, using cc65 algorithm
|
||||
char rawmap[0x100] = kickasm {{
|
||||
.var ht = Hashtable().put(0,64, 1,0, 2,32, 3,96) // the table for converting bit 6,7 into ora value
|
||||
.for(var i=0; i<256; i++) {
|
||||
.var idx = (i & $60) / 32
|
||||
.var mask = i & $9f
|
||||
.byte mask | ht.get(idx)
|
||||
}
|
||||
}};
|
||||
|
@ -160,7 +160,7 @@ unsigned char cursor(unsigned char onoff) {
|
||||
}
|
||||
|
||||
// If onoff is 1, scrolling is enabled when outputting past the end of the screen
|
||||
// If onoff is 1, scrolling is disabled and the cursor instead moves to (0,0)
|
||||
// If onoff is 0, scrolling is disabled and the cursor instead moves to (0,0)
|
||||
// The function returns the old scroll setting.
|
||||
unsigned char scroll(unsigned char onoff) {
|
||||
char old = conio_scroll_enable;
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "conio-mega65.c"
|
||||
#elif defined(__NES__)
|
||||
#include "conio-nes.c"
|
||||
#elif defined(__ATARIXL__)
|
||||
#include "conio-atarixl.c"
|
||||
#else
|
||||
#error "Target platform does not support conio.h"
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user