#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,
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)
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;
}
}
{
}
-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;
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
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