trs80: Add serial, keyboard and interrupt handling
authorAlan Cox <alan@linux.intel.com>
Thu, 18 Dec 2014 21:34:25 +0000 (21:34 +0000)
committerAlan Cox <alan@linux.intel.com>
Thu, 18 Dec 2014 21:34:25 +0000 (21:34 +0000)
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)

Kernel/platform-trs80/devices.c
Kernel/platform-trs80/devtty.c
Kernel/platform-trs80/devtty.h
Kernel/platform-trs80/main.c
Kernel/platform-trs80/trs80.s

index 131482b..2374efa 100644 (file)
@@ -6,19 +6,20 @@
 #include <devhd.h>
 #include <devsys.h>
 #include <devlpr.h>
+#include <devtty.h>
 
 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 */
 };
 
index b5a39a4..752f6d6 100644 (file)
 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();
 }
 
index bb6f7e6..300ecd6 100644 (file)
@@ -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
index 45b6c82..74a5fa5 100644 (file)
@@ -5,12 +5,16 @@
 #include <devtty.h>
 
 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();
 }
 
index 7a89759..c1f390e 100644 (file)
@@ -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