/* curses wrappers. The original code uses curses, cc65 uses conio, so I wrote this stuff to map the curses calls to conio ones. Later on, just replaced all the curses stuff (except clrtobot() and clrtoeol()) with direct calls to conio. Keeping this around in case it's useful for porting some other curses app to cc65. */ /* original plan was to use time() or _systime(). It turns out that these are not implemented on the Atari, and always return -1. So, use the OS's countdown timer instead. Anyone porting to another cc65 platform needs to rewrite this. TODO: rewrite in terms of clock() and CLOCKS_PER_SEC. Will make it less atari-specific, plus auto-adjust for pal/ntsc. TODO: there is atari-specific stuff elsewhere in the code :( */ static unsigned int tmout_jiffies = 0; /* void timeout(unsigned int msec) { if(msec > 0) tmout_jiffies = (msec / 100) * 6; // TODO: should be 5 for PAL else tmout_jiffies = 0; } */ /* set timer with interrupts disabled, to avoid race condition where an interrupt happens between setting the high & low bytes. */ void start_timer() { __asm__("SEI"); POKE(541, tmout_jiffies / 256); POKE(540, tmout_jiffies % 256); __asm__("CLI"); } /* this getch() works like curses, except it always acts like it's in cbreak mode. */ int getch() { int ret = -1; if(tmout_jiffies == 0) return cgetc(); start_timer(); do { if(kbhit()) { ret = cgetc(); break; } } while (timer_running()); return ret; } #define timer_running() (PEEK(541) || PEEK(540)) #define timer_expired() (!timer_running()) int flushinp() { POKE(764, 255); return 0; } void clrtobot() { unsigned char rows, cols, y, oldx, oldy; oldx = wherex(); oldy = wherey(); screensize(&cols, &rows); cclear(cols - wherex()); /* leaves cursor at start of next line */ for(y = wherey(); y < rows; y++) cclearxy(0, y, cols); gotoxy(oldx, oldy); } /* TODO: rewrite in asm */ void clrtobot() { unsigned char rows, cols, y, oldx, oldy; oldx = wherex(); oldy = wherey(); screensize(&cols, &rows); cclear(cols - wherex()); /* leaves cursor at start of next line */ for(y = wherey(); y < rows; y++) cclearxy(0, y, cols); gotoxy(oldx, oldy); } /* TODO: rewrite in asm */ void clrtoeol() { unsigned char cols, rows, oldx, oldy; oldx = wherex(); oldy = wherey(); screensize(&cols, &rows); cclear(cols - wherex()); gotoxy(oldx, oldy); } /* one-to-one mapping between some of the conio API and the curses one */ #define clear() clrscr() #define printw cprintf #define curs_set(x) cursor(x) /* conio doesn't do deferred printing, refresh() is a no-op */ #define refresh() /* we don't support cooked or raw mode, cbreak() is a no-op */ #define cbreak() /* we don't support echo mode */ #define noecho() /* curses move() takes args in the opposite order to gotoxy() */ #define move(a, b) gotoxy(b, a) /* our attrset() only supports A_NORMAL and A_REVERSE, since the Atari can only print normal and reverse video. */ #define A_NORMAL 0 #define A_REVERSE 1 #define attrset(x) revers(x) /**** atari-specific stuff */ /* original plan was to use time() or _systime(). It turns out that these are not implemented on the Atari, and always return -1. So, use the OS's countdown timer instead. Anyone porting to another cc65 platform needs to rewrite this. TODO: rewrite in terms of clock() and CLOCKS_PER_SEC. Will make it less atari-specific, plus auto-adjust for pal/ntsc. TODO: there is atari-specific stuff elsewhere in the code :( */ static unsigned int tmout_jiffies = 0; void timeout(unsigned int msec) { if(msec > 0) tmout_jiffies = (msec / 100) * 6; // TODO: should be 5 for PAL else tmout_jiffies = 0; } /* set timer with interrupts disabled, to avoid race condition where an interrupt happens between setting the high & low bytes. */ void start_timer() { __asm__("SEI"); POKE(541, tmout_jiffies / 256); POKE(540, tmout_jiffies % 256); __asm__("CLI"); } #define timer_running() (PEEK(541) || PEEK(540)) #define timer_expired() (!timer_running()) int flushinp() { POKE(764, 255); return 0; }