atarist: filling in the blanks
authorAlan Cox <alan@linux.intel.com>
Sat, 26 Jan 2019 22:24:50 +0000 (22:24 +0000)
committerAlan Cox <alan@linux.intel.com>
Sat, 26 Jan 2019 22:24:50 +0000 (22:24 +0000)
Still a work in progress with much to complete

Kernel/platform-atarist/config.h
Kernel/platform-atarist/devtty.c
Kernel/platform-atarist/devtty.h
Kernel/platform-atarist/kernel.def
Kernel/platform-atarist/main.c
Kernel/platform-atarist/p68000.S

index 11cb001..cfec7ba 100644 (file)
 #define CMDLINE        NULL      /* Location of root dev name */
 
 /* Device parameters */
-#define NUM_DEV_TTY 2
-#define NDEVS    2        /* Devices 0..NDEVS-1 are capable of being mounted */
-                          /*  (add new mountable devices to beginning area.) */
+#define NUM_DEV_TTY 3
+
 #define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
 #define NBUFS    10       /* Number of block buffers */
 #define NMOUNTS         4        /* Number of mounts at a time */
+
+/* TODO tty scan rows/cols etc */
index 15f986e..fb0f431 100644 (file)
@@ -7,12 +7,22 @@
 #include <vt.h>
 #include <tty.h>
 
-#undef  DEBUG                  /* UNdefine to delete debug code sequences */
+/*
+ *     We have three serial links on the Atari ST. The MFP provides the serial
+ *     port (tty2 for now), and a pair of ACIA chips provide keyboard/mouse/js
+ *     and midi. We expose the midi as a tty but not the keyboard port.
+ */
+#define IKBD_STATUS 0xFFFC00
+#define IKBD_DATA   0xFFFC02
+#define MIDI_STATUS 0xFFFC04
+#define MIDI_DATA   0xFFFC06
+
+#define MFP_TSR     0xFFFA2D
+#define MFP_DATA    0xFFFA2F
+#define MFP_TCDCR   0xFFFA1D
+#define MFP_TDDR    0xFFFA25
 
-uint8_t *uart_data = (uint8_t *)0xFF04;        /* ACIA data */
-uint8_t *uart_status = (uint8_t *)0xFF05;      /* ACIA status */
-uint8_t *uart_command = (uint8_t *)0xFF06;     /* ACIA command */
-uint8_t *uart_control = (uint8_t *)0xFF07;     /* ACIA control */
+#undef  DEBUG                  /* UNdefine to delete debug code sequences */
 
 static tcflag_t console_mask[4] = {
        _ISYS,
@@ -33,22 +43,24 @@ static tcflag_t uart_mask[4] = {
 tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
        NULL,
        console_mask,
-       console_mask,
-       uart_mask
+       uart_mask,
+       console_mask
 };
 
 static unsigned char tbuf1[TTYSIZ];
 static unsigned char tbuf2[TTYSIZ];
+static unsigned char tbuf3[TTYSIZ];
 
 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},
-       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}
+       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2}
 };
 
 uint8_t vtattr_cap;
 
-/* tty1 is the screen tty2 is the serial port */
+/* tty1 is the screen tty2 is the serial port tty3 is MIDI */
 
 /* Output for the system console (kprintf etc) */
 void kputchar(char c)
@@ -63,26 +75,62 @@ ttyready_t tty_writeready(uint8_t minor)
        uint8_t c;
        if (minor == 1)
                return TTY_READY_NOW;
-       c = *uart_status;
-       return (c & 16) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */
+       if (minor == 2) {
+               /* Double check which way around */
+               c = *(volatile uint8_t *)MFP_TSR;
+               return (c & 0x80) ? TTY_READY_NOW : TTY_READY_SOON;
+       }
+       c = *(volatile uint8_t *)MIDI_STATUS;
+       if (c & 0x02)
+               return TTY_READY_NOW;
+       return TTY_READY_SOON;
 }
 
-/* For DragonPlus we should perhaps support both monitors 8) */
-
 void tty_putc(uint8_t minor, unsigned char c)
 {
        if (minor == 1) {
                vtoutput(&c, 1);
-       } else
-               *uart_data = c; /* Data */
+       } else if (minor == 2)
+               *(volatile uint8_t *)MFP_DATA = c;
+       else
+               *(volatile uint8_t *)MIDI_DATA = c;
 }
 
+static const uint16_t mfp_baud[] = {
+       0x0104, /* B0 */
+       0x0260, /* B50 */
+       0x0240, /* B75 */
+       0x01AF, /* B110 */
+       0x018F, /* B134 */
+       0x0180, /* B150 */
+       0x0140, /* B300 */
+       0x0120, /* B600 */
+       0x0110, /* B1200 */
+       0x0108, /* B2400 */
+       0x0104, /* B4800 */
+       0x0102, /* B9600 */
+       0x0101  /* B19200 */
+       /* Hardware cannot support 38400 or higher */
+};
+
 void tty_setup(uint8_t minor, uint8_t flags)
 {
+       if (minor == 1)
+               return;
+       /* Mostly TOOD */
+       if (minor == 3) {
+               return;
+       }
        if (minor == 2) {
-               /* FIXME: do proper mode setting */
-               *uart_command = 0x01;   /* DTR high, IRQ enabled, TX irq disabled 8N1 */
-               *uart_control = 0x1E;   /* 9600 baud */
+               uint8_t speed = ttydata[2].termios.c_cflag & CBAUD;
+               if (speed > B19200) {
+                       speed = B19200;
+                       ttydata[2].termios.c_cflag &= ~CBAUD;
+                       ttydata[2].termios.c_cflag |= B19200;
+               }
+               *(volatile uint8_t *)MFP_TCDCR &= 0xF0;
+               *(volatile uint8_t *)MFP_TDDR = mfp_baud[speed];
+               *(volatile uint8_t *)MFP_TCDCR |= mfp_baud[speed] >> 8;
        }
 }
 
@@ -101,127 +149,219 @@ void tty_data_consumed(uint8_t minor)
 {
 }
 
-void tty_interrupt(void)
+void ser_cts(void)
 {
-       uint8_t r = *uart_status;
-       if (r & 0x8) {
-               r = *uart_data;
-               tty_inproc(2,r);
-       }       
 }
 
+void ser_dcd(void)
+{
+}
+
+void ser_ri(void)
+{
+}
 
 struct vt_repeat keyrepeat;
 
-uint8_t keymap[8];
-static uint8_t keyin[8];
-static uint8_t keybyte, keybit;
-static uint8_t newkey;
+uint8_t keymap[16];
+static uint8_t lastkey;
 static int keysdown = 0;
-static uint8_t shiftmask[8] = {
-       0, 0x40, 0, 0, 0, 0, 0, 0x40
-};
 
-static uint8_t rbit[8] = {
-       0xFE,
-       0xFD,
-       0xFB,
-       0xF7,
-       0xEF,
-       0xDF,
-       0xBF,
-       0x7F,
-};
+uint8_t keyboard[1][128] = { {
+       0, KEY_ESC,
+       '1','2','3','4','5','6','7','8','9',
+       '-','=', KEY_BS, KEY_TAB,
+       'q','w','e','r','t','y','u','i','o','p',
+       '[',']',KEY_ENTER,
+       0, 'a','s','d','f','g','h','j','k','l',':',';',
+       0,'\\','z','x','c','v','b','n','m','.',',','/',0,
+       0,0,' ',0, /* caps lock */
+       KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,
+       0,0,
+       KEY_HOME,KEY_UP,0,'-',KEY_LEFT,0,KEY_RIGHT,'+',0,KEY_DOWN,
+       0, KEY_INSERT,KEY_DEL,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,/* ISO ?? */
+       KEY_UNDO, KEY_HELP,
+       '(','/','*',')',        /* FIXME */
+       '7','8','9',
+       '4','5','6',
+       '1','2','3',
+       '0','.', KEY_ENTER,
+} };
 
-/* Row inputs: multiplexed with the joystick */
-static volatile uint8_t *pia_row = (uint8_t *)0xFF00;
-/* Columns for scanning: multiplexed with the printer port */
-static volatile uint8_t *pia_col = (uint8_t *)0xFF02;
-/* Control */
-static volatile uint8_t *pia_ctrl = (uint8_t *)0xFF03;
-
-static void keyproc(void)
-{
-       int i;
-       uint8_t key;
-
-       for (i = 0; i < 8; i++) {
-               /* We do the scan in software on the Dragon */
-               *pia_col = rbit[i];
-               keyin[i] = ~*pia_row;
-               key = keyin[i] ^ keymap[i];
-               if (key) {
-                       int n;
-                       int m = 1;
-                       for (n = 0; n < 7; n++) {
-                               if ((key & m) && (keymap[i] & m)) {
-                                       if (!(shiftmask[i] & m))
-                                               keysdown--;
-                               }
-                               if ((key & m) && !(keymap[i] & m)) {
-                                       if (!(shiftmask[i] & m)) {
-                                               keysdown++;
-                                               newkey = 1;
-                                               keybyte = i;
-                                               keybit = n;
-                                       }
-                               }
-                               m += m;
-                       }
-               }
-               keymap[i] = keyin[i];
+/* TODO */
+uint8_t shiftkeyboard[1][128] = { {
+       0, KEY_ESC,
+       '1','2','3','4','5','6','7','8','9',
+       '-','=', KEY_BS, KEY_TAB,
+       'q','w','e','r','t','y','u','i','o','p',
+       '[',']',KEY_ENTER,
+       0, 'a','s','d','f','g','h','j','k','l',':',';',
+       0,'\\','z','x','c','v','b','n','m','.',',','/',0,
+       0,0,' ',0/* caps lock */,
+       KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,
+       0,0,
+       KEY_HOME,KEY_UP,0,'-',KEY_LEFT,0,KEY_RIGHT,'+',0,KEY_DOWN,
+       0, KEY_INSERT,KEY_DEL,
+       0,0,0,0,0,0,0,0,0,0,0,0,
+       0,/* ISO ?? */
+       KEY_UNDO, KEY_HELP,
+       '(','/','*',')',        /* FIXME */
+       '7','8','9',
+       '4','5','6',
+       '1','2','3',
+       '0','.', KEY_ENTER,
+} };
+
+static void keydecode(void)
+{
+       uint8_t c = lastkey;
+
+       if (c == 0 || !keysdown)
+               return;
+       /* FIXME: wire up input layer */
+       if ((keymap[5] & 0x02) || (keymap[6] & 0x40))   /* shifts */
+               c = shiftkeyboard[0][c];
+       else if (keymap[7] & 0x02) {    /* Caps lock */
+               if (c >= 'a' && c <= 'z')
+                       c -= 32;
        }
+       if (keymap[2] & 0x10)   /* Control */
+               c &= 31;
+       else
+               c = keyboard[0][c];
+       /* What should we do with alt (0x38) */
+       /* FIXME: unicode */
+       vt_inproc(1, c);
 }
 
-uint8_t keyboard[8][7] = {
-       { '0', '8', '@', 'h', 'p', 'x', 10 },
-       { '1', '9', 'a', 'i', 'q', 'y', 0 /* clear - used as ctrl*/ },
-       { '2', ':', 'b', 'j', 'r', 'z', 27 /* break (used for esc) */ },
-       { '3', ';', 'c', 'k', 's', '^' /* up */, 0 /* NC */ },
-       { '4', ',', 'd', 'l', 't', '|' /* down */, 0 /* NC */ },
-       { '5', '-', 'e', 'm', 'u', 8 /* left */, 0 /* NC */ },
-       { '6', '.', 'f', 'n', 'v', '\t' /* right */, 0 /* NC */ },
-       { '7', '/', 'g', 'o', 'w', ' ', 0 /* shift */ },
-};
+/* It's not really a grid but we need to expose it as that */
+/* FIXME: direct 37/5e/5f/59-59 to mouse */
 
-uint8_t shiftkeyboard[8][7] = {
-       { '_', '(', '\\', 'H', 'P', 'X', 10 },
-       { '!', ')', 'A', 'I', 'Q', 'Y', 0 /* clear */ },
-       { '"', '*', 'B', 'J', 'R', 'Z', 3 /* break */ },
-       { '#', '+', 'C', 'K', 'S', '[' /* up */, 0 /* NC */ },
-       { '$', '<', 'D', 'L', 'T', ']' /* down */, 0 /* NC */ },
-       { '%', '=', 'E', 'M', 'U', '{' /* left */, 0 /* NC */ },
-       { '&', '>', 'F', 'N', 'V', '}' /* right */, 0 /* NC */ },
-       { '\'', '?', 'G', 'O', 'W', ' ', 0 /* shift */ },
+static void keybop(uint8_t c)
+{
+       uint8_t i = c >> 3;
+       uint8_t b = c & 7;
+       uint8_t nonshift = 1;
+
+       if (c == 0x2A || c ==0x36 || c == 0x14 || c== 0x38 || c == 0x3A)
+               nonshift = 0;
+
+       if (c & 0x80) {
+               keymap[i] &= ~ (1 << b);
+               keysdown -= nonshift;
+               if (c == (lastkey | 0x8))
+                       lastkey = 0;
+               return;
+       }
+       keymap[i] |= (1 << b);
+       lastkey = c;
+       keysdown += nonshift;
+       /* FIXME: autorepeat */
+       if (keysdown && lastkey && keysdown < 3)
+               keydecode();
+}
+
+static uint8_t ikbd_buf[8];
+static uint8_t ikbd_ct;
+static uint8_t ikbd_len = 1;
+static uint8_t ikbd_busy;
+
+static const uint8_t msg_len[10] = {
+       8, 6, 3, 3, 3, 3, 7, 3, 2, 2
 };
 
-static void keydecode(void)
+static void ikbd_message(void)
 {
-       uint8_t c;
-
-       if (keymap[7] & 64)     /* shift */
-               c = shiftkeyboard[keybyte][keybit];
-       else
-               c = keyboard[keybyte][keybit];
-       if (keymap[1] & 64) {   /* control */
-               if (c > 31 && c < 127)
-                       c &= 31;
+       uint8_t c = ikbd_buf[0];
+       if (ikbd_ct == 1) {
+               if (c < 0xF6) {
+                       ikbd_ct = 0;
+                       ikbd_len = 1;
+                       keybop(c);
+               } else
+                       ikbd_len = msg_len[c - 0xF6];
+               return;
+       }
+       /* A message completed */
+       ikbd_ct = 0;
+       ikbd_len = 1;
+       switch(c) {
+       case 0xF6:      /* Query reply */
+               ikbd_busy = 0;
+               wakeup(&ikbd_busy);
+               return;
+       case 0xF7:      /* Abs mouse */
+               return;
+       case 0xF8:      /* Rel mouse (used) */
+       case 0xF9:
+       case 0xFA:
+       case 0xFB:
+               return;
+       case 0xFC:      /* rtc */
+               ikbd_busy = 0;
+               wakeup(&ikbd_busy);
+               /*
+               memcpy(ikbd_rtc, ikbd_buf + 1, 6);
+               ikbd_rtc_ready = 1;
+               wakeup(&ikbd_rtc_ready); */
+               return;
+       case 0xFD:      /* sticks both */
+       case 0xFE:      /* stick 0 */
+       case 0xFF:      /* stick 1 */
+               return;
        }
-       tty_inproc(1, c);
 }
 
-void platform_interrupt(void)
+static void acia_key_event(uint8_t c)
 {
-       uint8_t i = *pia_ctrl;
-       if (i & 0x80) {
-               *pia_col;
-               newkey = 0;
-               keyproc();
-               if (keysdown < 3 && newkey)
-                       keydecode();
-               timer_interrupt();
+       ikbd_buf[ikbd_ct++] = c;
+       if (ikbd_ct == ikbd_len)
+               ikbd_message();
+}
+
+/* Someting happened on one of our ACIA chips - or both. We poll them on
+   the transmit side for now */
+void acia_interrupt(void)
+{
+       uint8_t st = *(volatile uint8_t *)IKBD_STATUS;
+       if (st & 0x80)
+               acia_key_event(*(volatile uint8_t *)IKBD_DATA);
+       st = *(uint8_t *)MIDI_STATUS;
+       if (st & 0x80)
+               tty_inproc(3, *(volatile uint8_t *)MIDI_DATA);
+}
+
+/*
+ *     Send a message to the keyboard controller
+ *
+ *     FIXME: timeouts
+ */
+void ikbd_send(uint8_t *msg, uint8_t len)
+{
+       irqflags_t irq = di();
+       while(1) {
+               if (ikbd_busy == 0) {
+                       ikbd_busy = 1;
+                       while(len) {
+                               while(*(volatile uint8_t *)IKBD_STATUS & 2);
+                               *(volatile uint8_t *)IKBD_DATA = *msg++;
+                       }
+                       irqrestore(irq);
+                       return;
+               }
+               psleep_nosig(&ikbd_busy);
+               di();
        }
 }
 
 /* This is used by the vt asm code, but needs to live at the top of the kernel */
 uint16_t cursorpos;
+
+
+/*
+ *     Graphics and vblank
+ */
+
+uint32_t vblankct;
index 14c28c3..86d9807 100644 (file)
@@ -1,10 +1,10 @@
 #ifndef __DEVTTY_DOT_H__
 #define __DEVTTY_DOT_H__
 
-#define KEY_ROWS 8
-#define KEY_COLS 7
-extern uint8_t keymap[8];
-extern uint8_t keyboard[8][7];
-extern uint8_t shiftkeyboard[8][7];
+#define KEY_ROWS 1
+#define KEY_COLS 128
+extern uint8_t keymap[16];
+extern uint8_t keyboard[1][128];
+extern uint8_t shiftkeyboard[1][128];
 
 #endif
index 3f24f44..42ab1a4 100644 (file)
@@ -1,4 +1,2 @@
-; UZI mnemonics for memory addresses etc
-
-U_DATA                      equ 0x7D00       ; (this is struct u_data from kernel.h)
-U_DATA__TOTALSIZE           equ 0x300        ; 256+256+256 bytes.
+#define DI_MASK                $700            /* or bits for DI */
+#define EI_MASK                $300            /* or bits for EI : block hblank */
index 878c73b..7fe922d 100644 (file)
@@ -26,6 +26,7 @@ void memzero(void *p, usize_t len)
 
 void platform_copyright(void)
 {
+
 }
 
 void do_beep(void)
@@ -38,17 +39,32 @@ void map_init(void)
 
 u_block uarea_block[PTABSIZE];
 
-void *screenbase;
+uint8_t hzticks;
+uint32_t memtop;
+uint16_t fdseek;
+uint16_t cputype;
+uint32_t screenbase;
+
 
 void pagemap_init(void)
 {
+       hzticks = *(uint16_t *)0x448 ? 60 : 50;
+       memtop = *(uint32_t *)0x42E;
+       fdseek = *(uint16_t *)0x440;
+       cputype = *(uint16_t *)0x59E;
+
+       kprintf("System Memory: %dK\n", memtop >> 10);
+       if (hzticks == 60)
+               kputs("NTSC System\n");
+       if (cputype)
+               kputs("Not a 68000\n");
        /* FIXME: 512K hackish setup to get going */
        /* Linker provided end of kernel */
        extern uint8_t _end;
        uint32_t e = (uint32_t)&_end;
        kprintf("Kernel end %p\n", e);
        /* Allocate the rest of memory to the userspace */
-       kmemaddblk((void *)e, 0x78000 - e);
+       kmemaddblk((void *)e, screenbase - e);
 }
 
 /* Udata and kernel stacks */
index 511d14d..dbea7b1 100644 (file)
@@ -26,21 +26,75 @@ init_early:
             rts
 
 init_hardware:
-            ; set system RAM size
-           move.l $42E,d0              ; TOS phystop
-           lsr.l #8,d0                 ; into KBytes
-           lsr.l #2,d0
-           move.w d0,ramsize
-           sub.w  #64,d0               ; Guess for kernel
-           move.w d0,procmem           ; guesses for now
-           bsr install_vectors
-            rts
+       ;
+       ;       We use the ROM to do the initial set up. We must do this
+       ;   before we steal all the vectors
+       ;
+       move.w #4,-(sp)
+       trap #14
+       and #3,d0
+       move.b d0,videomode
+       move.b #50,videorows    ; 640x400 is special
+       move.b #49,videobot
+       cmpb #2,d0
+       beq mode_ok                     ; different monitor so leave it alone
+       move.b #25,videorows    ; 640x200 mode
+       move.b #24,videobot
+
+       ; Set our palette
+       pea palette
+       move.w #6,-(sp)
+       trap #14
+       addq #6,sp
+
+       move.b #1,d0
+mode_ok:
+       move.w d0,-(sp)         ; Stack resolution wanted
+
+       move.w $42E,d0          ; Top of RAM
+       sub.l #32000,d0         ; Frame buffer space
+       move.l d0,screenbase    ; Save our video base
+
+       move.l d0,-(sp)         ; physical base
+       move.l d0,-(sp)         ; logicalbase
+       move.w #5,-(sp)         ; setScreen
+       trap #14
+       lea 12(sp),sp
+
+        ; set system RAM size
+       move.l $42E,d0          ; TOS phystop
+       lsr.l #8,d0                     ; into KBytes
+       lsr.l #2,d0
+       move.w d0,ramsize
+       sub.w  #64,d0           ; Guess for kernel
+       sub.w  #32,d0           ; Video memory
+       move.w d0,procmem               ; guesses for now
+       bsr install_vectors
+       move.w #0,a0
+       move.l #int2,$68(a0)            ; hblank autvector
+       move.l #int4,$70(a0)            ; vblank autovector
+       move.l #int_mfp1,$104(a0)       ; DCD
+       move.l #int_mfp2,$108(a0)       ; CTS
+       move.l #int_mfp5,$114(a0)       ; 200Hz
+       move.l #int_mfp6,$118(a0)       ; IKBD/Midi
+       move.l #int_mfp9,$124(a0)       ; Tx Error
+       move.l #int_mfp10,$128(a0)      ; Tx Done
+       move.l #int_mfp11,$12c(a0)      ; RX Error
+       move.l #int_mfp12,$130(a0)      ; RX Data
+       move.l #int_mfp14,$138(a0)      ; RI
+        rts
+palette:
+       word $0000                      ; black
+       word $0F00                      ; red
+       word $00F0                      ; green
+       word $0FFF                      ; white
+       ; We let the others go to trash
 
 
 ;      Nothing to do in 68000 - all set up once at boot
 ;
 program_vectors:
-           rts
+       rts
 
 ;
 ;      All mapped all the time
@@ -50,49 +104,262 @@ map_process:
 map_kernel:
 map_restore:
 map_save:
-           rts
+       rts
+
+;
+;      Interrupt vectors
+;
+
+; Hblank
+int2:
+       ori.w #0300,sr          ; Fix up if something messes with sr
+       rte
+; Vblank
+;      Trigger a wakeup if anyone is waiting on blanking events
+;
+int4:
+       add.w #1,vblankct
+       tst.b vblankw
+       beq int4_out
+       movem.l a0/a1/d0/d1,-(sp)
+       pea vblankct
+       bsr wakeup
+       addq #4,sp
+       movem.l (sp)+,a0/a1/d0/d1
+int4_out:
+       rte
+;
+;      The level 6 handlers are autovectored
+;
+int_mfp1:      ; DCD on the serial
+       movem.l a0/a1/d0/d1,-(sp)
+       bsr ser_dcd
+       movem.l (sp)+,a0/a1/d0/d1
+       rte
+int_mfp2:      ; CTS on the seriall
+       movem.l a0/a1/d0/d1,-(sp)
+       bsr ser_cts
+       movem.l (sp)+,a0/a1/d0/d1
+       rte
+int_mfp5:      ; 200Hz timer
+       movem.l a0/a1/d0/d1,-(sp)
+       bsr timer_interrupt
+       movem.l (sp)+,a0/a1/d0/d1
+       rte
+int_mfp6:      ; ACIA interrupts
+       movem.l a0/a1/d0/d1,-(sp)
+       bsr acia_interrupt
+       movem.l (sp)+,a0/a1/d0/d1
+       rte
+int_mfp9:      ; MFP serial transmit error
+       ; FIXME what do we need to do to clear down ?
+       rte
+int_mfp10:     ; MFP tx complete
+       ; FIXME: blocked for now using polling
+       rte
+int_mfp11:     ; MFP rx error
+       ; FIXME: how to clear
+       rte
+int_mfp12:     ; MFP receive
+       movem.l a0/a1/d0/d1,-(sp)
+       move.b $FFFA2D,d0
+       move.l d0,-(sp)
+       pea.l 2
+       bsr tty_inproc
+       addq #8,sp
+       movem.l (sp)+,a0/a1/d0/d1
+       rte
+int_mfp14:     ; MFP ring indicate
+       movem.l a0/a1/d0/d1,-(sp)
+       bsr ser_ri
+       movem.l (sp)+,a0/a1/d0/d1
+       rte
 
 ; outchar: Wait for UART TX idle, then print the char in d0
 
 outchar:
-           move.w d0,-(sp)
+       move.w d0,-(sp)
 outcharw:
-           move.b $FFFFFA13,d0
-           btst #2,d0
-           beq outcharw
-           move.w (sp)+,d0
-           move.b d0,$FFFFFA2D
+       move.b $FFFA13,d0
+       btst #2,d0
+       beq outcharw
+       move.w (sp)+,d0
+       move.b d0,$FFFA2D
+       rts
+
+;
+;      There are 3 possible modes that we care about
+;      We number then by planes-1 so the mode is our counter for dbra
+;      0       640x400x1 planar
+;      1       320x200x4 planar
+;      3       640x200x2 planar
+;
+vaddr:
+           ; X in D1 Y in D0
+           ; returns address in A1, mode in D1
+
+           mulu.w vwidth,d0
+           mulu.w vshift,d2
+           move.b d1,d3
+           and.w #1,d3
+           and.w #$fffe,d1
+           lsl.w d2,d1
+           add.w d1,d0
+           add.w d3,d0
+           move.l screenbase,a0
+           add.w d0,a0
+           move.w videomode,d2
+           move.w vlen,d3              ; bytes per scan line minus
+                                       ; those we write
            rts
+aligned:
 
+;
+;      FIXME: check how gcc pushes uint8_t's in this case and set offsets
+;      properly
+;
 plot_char:
-           ; y, x, c
-           move.l screenbase,a0        ; Screen base from TOS
            move.w 4(sp),d0
-           mulu.w #640,d0              ; Always under 64K
-           adda.l d0,a0
-           adda.w 6(sp),a0             ; do is now our offset
+           move.w 6(sp),d1
+           move.l d2,-(sp)
+           move.l d3,-(sp)
+
+plot_char_1:
+           ; Save Regs
 
-           move.w 8(sp),d0             ; character
+           bsr vaddr
+
+           move.w 16(sp),d0            ; character
            lsl.w #3,d0                 ; into font position
            lea fontdata_8x8,a1 ; font
            adda.w d0,a1
-           moveq #7,d1
+           moveq #7,d0
+;
+;      Really we need to expand this per mode and to do colour
+;
 plotit:
-           move.b (a1)+,(a0)
-           add.l #80,a0
-           dbra d1,plotit
+           move.w d2,d1                ; count by mode
+plotrow:
+           move.b (a1),(a0)
+           add.w #2,a0
+           dbra d1,plotrow
+           add.w d3,a0                 ; line length for mode
+           dbra d0,plotit
+           ; Restore regs
+           move.l (sp)+,d3
+           move.l (sp)+,d2
            rts
 
-scroll_down:
+;
+;      640x400 is our special case - the bytes per line is half the other
+;      modes
+;
 scroll_up:
+           move.l screenbase,a0
+           move.w #640,d0
+           move.w #32000-640-1,d1
+           tst.w videomode
+           beq hires
+           move.w #1280,d0
+           move.w #32000-1280-1,d1
+hires:
+           move.l a0,a1
+           add.w d0,a1
+scrollu:    move.l (a1)+,(a0)+
+           dbra d1,scrollu
+           rts
+
+scroll_down:
+           move.l screenbase+32000,a0
+           move.w #640,d0
+           move.w #32000-640-1,d1
+           tst.w videomode
+           beq hiresd
+           move.w #1280,d0
+           move.w #32000-1280-1,d1
+hiresd:
+           move.l a0,a1
+           sub.w d0,a1
+scrolld:    move.l -(a1),-(a0)
+           dbra d1,scrolld
+           rts
+
 clear_lines:
+           move.l 4(sp),d0
+           move.l d2,-(sp)
+           move.l d3,-(sp)
+           move.w #0,a1
+           bsr vaddr
+           ; d2 is mode count, d3 is extra words/line, a0 is address
+            move.l 6(sp),d0
+           bra wipen
+wipe:
+           move.w d2,d1
+wipe1:     clr.w (a0)+
+           dbra d2,wipe1
+           add.w d3,a0
+wipen:
+           dbra d0,wipe
+           move.l (sp)+,d3
+           move.l (sp)+,d2
+           rts
+
 clear_across:
+           rts     
+
 cursor_on:
-cursor_off:
+           move.w 4(sp),d0             ; check stacking
+           move.w 6(sp),d1
+           move.l d2,-(sp)
+           move.l d3,-(sp)
+           bsr vaddr
+           moveq #7,d0
+           lea.l cursordata,a1
+           movem.l a0/d2/d3,(a1)
+;
+;      Really we need to expand this per mode and to do colour
+;
+xorit:
+           move.w d2,d1                ; count by mode
+xorrow:
+           eor.b #255,(a0)
+           add.w #2,a0
+           dbra d1,xorrow
+           add.w d3,a0                 ; line length for mode
+           dbra d0,xorit
+           move.l (sp)+,d3
+           move.l (sp)+,d2
+           rts
 cursor_disable:
+cursor_off:
+           move.l d2,-(sp)
+           move.l d3,-(sp)
+           lea.l cursordata,a1
+           movem.l (a1),a0/d2/d3
+           bra xorit
+
 vtattr_notify:
            rts 
 
 .section data
 
 kernel_flag: byte 1
+
+cursordata:  word 0
+            word 0
+            word 0
+            word 0
+videorows:
+            byte 0
+videobot:
+            byte 0
+vwidth:
+            byte 640
+vshift:
+            byte 0
+vlen:
+            byte 638
+videomode:
+            byte 1
+vblankw:
+            byte 1