From: Alan Cox Date: Thu, 18 Dec 2014 21:34:25 +0000 (+0000) Subject: trs80: Add serial, keyboard and interrupt handling X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=4f420e6276e91b0c31c7a638b83fc7c0fa2fe710;p=FUZIX.git trs80: Add serial, keyboard and interrupt handling This gives a console you can type into and which is at least good enough to set the root fs. It follows the standard TRS80 layout but with some extra ctrl and ctrl-shift hooks for useful keys Tandy forgot to include ({} etc) --- diff --git a/Kernel/platform-trs80/devices.c b/Kernel/platform-trs80/devices.c index 131482b9..2374efa3 100644 --- a/Kernel/platform-trs80/devices.c +++ b/Kernel/platform-trs80/devices.c @@ -6,19 +6,20 @@ #include #include #include +#include struct devsw dev_tab[] = /* The device driver switch table */ { /* 0: /dev/fd Floppy disc block devices */ - { fd_open, no_close, fd_read, fd_write, no_ioctl }, + { fd_open, no_close, fd_read, fd_write, no_ioctl }, /* 1: /dev/hd Hard disc block devices */ - { hd_open, no_close, hd_read, hd_write, no_ioctl }, + { hd_open, no_close, hd_read, hd_write, no_ioctl }, /* 2: /dev/tty TTY devices */ - { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + { tty_open, trstty_close, tty_read, tty_write, tty_ioctl }, /* 3: /dev/lpr Printer devices */ - { lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl }, + { lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl }, /* 4: /dev/mem etc System devices (one offs) */ - { no_open, no_close, sys_read, sys_write, sys_ioctl }, + { no_open, no_close, sys_read, sys_write, sys_ioctl }, /* Pack to 7 with nxio if adding private devices and start at 8 */ }; diff --git a/Kernel/platform-trs80/devtty.c b/Kernel/platform-trs80/devtty.c index b5a39a47..752f6d68 100644 --- a/Kernel/platform-trs80/devtty.c +++ b/Kernel/platform-trs80/devtty.c @@ -10,6 +10,11 @@ char tbuf1[TTYSIZ]; char tbuf2[TTYSIZ]; +__sfr __at 0xE8 tr1865_ctrl; +__sfr __at 0xE9 tr1865_baud; +__sfr __at 0xEA tr1865_status; +__sfr __at 0xEB tr1865_rxtx; + struct s_queue ttyinq[NUM_DEV_TTY+1] = { /* ttyinq[0] is never used */ { NULL, NULL, NULL, 0, 0, 0 }, { tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ/2 }, @@ -26,31 +31,198 @@ void kputchar(char c) static bool tty_writeready(uint8_t minor) { - minor; - return 1; /* FIXME !! */ + uint8_t reg; + if (minor == 1) + return 1; + reg = tr1865_status; + if (reg & 0x40) + return 1; + return 0; } void tty_putc(uint8_t minor, unsigned char c) { if (minor == 1) vtoutput(&c, 1); + if (minor == 2) + tr1865_rxtx = c; } -void tty_pollirq(void) +void tty_interrupt(void) { - /* Keyboard scanner */ + uint8_t reg = tr1865_status; + if (reg & 0x80) { + reg = tr1865_rxtx; + tty_inproc(2, reg); + } } /* Called to set baud rate etc */ +static const uint8_t trsbaud[] = { + 0,0,1,2, 3,4,5,6, 7,10,14, 15 +}; + +static const uint8_t trssize[4] = { + 0x00, 0x40, 0x20, 0x60 +}; + void tty_setup(uint8_t minor) { - minor; + uint8_t baud; + uint8_t ctrl; + if (minor == 1) + return; + baud = ttydata[2].termios.c_cflag & CBAUD; + if (baud > B19200) { + ttydata[2].termios.c_cflag &= ~CBAUD; + ttydata[2].termios.c_cflag |= B19200; + baud = B19200; + } + tr1865_baud = baud | (baud << 4); + + ctrl = 3; + if (ttydata[2].termios.c_cflag & PARENB) { + if (ttydata[2].termios.c_cflag & PARODD) + ctrl |= 0x80; + } else + ctrl |= 0x8; /* No parity */ + ctrl |= trssize[(ttydata[2].termios.c_cflag & CSIZE) >> 4]; + tr1865_ctrl = ctrl; +} + +int trstty_close(uint8_t minor) +{ + if (minor == 2) + tr1865_ctrl = 0; /* Drop carrier */ + return tty_close(minor); } -/* For the moment */ int tty_carrier(uint8_t minor) { - minor; - return 1; + if (minor == 1) + return 1; + if (tr1865_ctrl & 0x80) + return 1; + return 0; +} + + +static uint8_t keymap[8]; +static uint8_t keyin[8]; +static uint8_t keybyte, keybit; +static uint8_t newkey; +static int keysdown = 0; +static uint8_t shiftmask[8] = { + 0, 0, 0, 0, 0, 0, 0, 7 +}; + +static void keyproc(void) +{ + int i; + uint8_t key; + + for (i = 0; i < 8; i++) { + /* Set one of A0 to A7, and read the byte we get back. + Invert that to get a mask of pressed buttons */ + keyin[i] = *(uint8_t *)(0xF400 | (1 << i)); + key = keyin[i] ^ keymap[i]; + if (key) { + int n; + int m = 1; + for (n = 0; n < 8; n++) { + if ((key & m) && (keymap[i] & m)) { + if (!(shiftmask[i] & m)) + keysdown--; + } + if ((key & m) && !(keymap[i] & m)) { + if (!(shiftmask[i] & m)) + keysdown++; + keybyte = i; + keybit = n; + newkey = 1; + } + m += m; + + } + } + keymap[i] = keyin[i]; + } +} + +static uint8_t keyboard[8][8] = { + {'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g' }, + {'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' }, + {'p', 'q', 'r', 's', 't', 'u', 'v', 'w' }, + {'x', 'y', 'z', '[', '\\', ']', '^', '_' }, + {'0', '1', '2', '3', '4', '5', '6', '7' }, + {'8', '9', ':', ';', ',', '-', '.', '/' }, + {13, 12, 3, 0/*up*/, 0/*down*/, 8/* left */, 0/*right*/, ' '}, + { 0, 0, 0, 0, 0xF1, 0xF2, 0xF3, 0 } +}; + +static uint8_t shiftkeyboard[8][10] = { + {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G' }, + {'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' }, + {'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W' }, + {'X', 'Y', 'Z', '{', '|', '}', '^', '_' }, + {'0', '!', '"', '#', '$', '%', '&', '\'' }, + {'(', ')', '*', '+', '<', '=', '>', '?' }, + {13, 12, 3, 0/*up*/, 0/*down*/, 8/* left */, 0/*right*/, ' '}, + { 0, 0, 0, 0, 0xF1, 0xF2, 0xF3, 0 } +}; + +static uint8_t capslock = 0; + +static void keydecode(void) +{ + uint8_t c; + + if (keybyte == 7 && keybit == 3) { + capslock = 1 - capslock; + return; + } + + if (keymap[7] & 3) /* shift */ + c = shiftkeyboard[keybyte][keybit]; + else + c = keyboard[keybyte][keybit]; + + /* The keyboard lacks some rather important symbols so remap them + with control */ + if (keymap[7] & 4) { /* control */ + if (c > 31 && c < 96) + c &= 31; + if (keymap[7] & 3) { + if (c == '(') + c = '{'; + if (c == ')') + c = '}'; + if (c == '-') + c = '_'; + if (c == '/') + c = '``'; + if (c == '<') + c = '^'; + } else { + if (c == '(') + c = '['; + if (c == ')') + c = ']'; + if (c == '-') + c = '|'; + } + } + if (capslock && c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + if (c) + tty_inproc(1, c); +} + +void kbd_interrupt(void) +{ + newkey = 0; + keyproc(); + if (keysdown < 3 && newkey) + keydecode(); } diff --git a/Kernel/platform-trs80/devtty.h b/Kernel/platform-trs80/devtty.h index bb6f7e69..300ecd62 100644 --- a/Kernel/platform-trs80/devtty.h +++ b/Kernel/platform-trs80/devtty.h @@ -1,6 +1,8 @@ #ifndef _DEVTTY_H #define _DEVTTY_H -extern void tty_pollirq(void); +extern void tty_interrupt(void); +extern void kbd_interrupt(void); +extern int trstty_close(uint8_t minor); #endif diff --git a/Kernel/platform-trs80/main.c b/Kernel/platform-trs80/main.c index 45b6c821..74a5fa5f 100644 --- a/Kernel/platform-trs80/main.c +++ b/Kernel/platform-trs80/main.c @@ -5,12 +5,16 @@ #include uint16_t ramtop = PROGTOP; +__sfr __at 0xE0 irqstat; +__sfr __at 0xEF irqack; /* On idle we spin checking for the terminals. Gives us more responsiveness for the polled ports */ void platform_idle(void) { - tty_pollirq(); + __asm + halt + __endasm; } void do_beep(void) @@ -19,6 +23,12 @@ void do_beep(void) void platform_interrupt(void) { + uint8_t irq = irqstat; + if (irq & 0x20) + tty_interrupt(); + if (!(irq & 0x80)) + return; + kbd_interrupt(); timer_interrupt(); } diff --git a/Kernel/platform-trs80/trs80.s b/Kernel/platform-trs80/trs80.s index 7a897594..c1f390e7 100644 --- a/Kernel/platform-trs80/trs80.s +++ b/Kernel/platform-trs80/trs80.s @@ -55,15 +55,19 @@ tm_stack: .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 tm_stack_top: +; +; Can't di halt as it breaks sdltrs 8( +; _trap_monitor: - ld a, #128 - out (0x28), a + jr _trap_monitor + platform_interrupt_all: + in a,(0xef) ret _trap_reboot: - ld a, #1 - out (0x28), a + di + halt ; ----------------------------------------------------------------------------- ; KERNEL MEMORY BANK (below 0xEA00, only accessible when the kernel is mapped) @@ -104,8 +108,6 @@ init_hardware: ld hl, #(128-64) ; 64K for kernel ld (_procmem), hl - ; 100Hz timer on - ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused) ld hl, #0 push hl @@ -113,6 +115,12 @@ init_hardware: pop hl im 1 ; set CPU interrupt mode + + ; interrupt mask + ; 60Hz timer on + + ld a, #0x24 ; 0x20 for serial + out (0xe0), a ret @@ -211,8 +219,10 @@ map_process_a: ; used by bankfork map_process_always: push af + push hl ld hl, #U_DATA__U_PAGE call map_process_hl + pop hl pop af ret