--- /dev/null
+ASRCS = crt0.s tricks.s commonmem.s rabbit.s
+CSRCS = devices.c main.c devtty.c
+DISCARD_CSRCS =
+DISCARD_DSRCS = ../dev/devsd_discard.c
+DSRCS = ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+DAOBJS = $(patsubst ../dev/%.s,%.rel, $(DASRCS))
+
+OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(DAOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS)
+
+CROSS_CCOPTS += -I../dev/
+
+JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin
+
+all: $(OBJS)
+
+$(AOBJS): %.rel: %.s
+ $(CROSS_AS) $(ASOPTS) $<
+
+$(COBJS): %.rel: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) --codeseg COMMONMEM -c $<
+
+$(DOBJS): %.rel: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DAOBJS): %.rel: ../dev/%.s
+ $(CROSS_AS) $(ASOPTS) $@ $<
+
+$(DISCARD_COBJS): %.rel: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~ fuzix.com
+
+#
+# Compile up the boot block
+#
+image:
+
--- /dev/null
+First sketches for the Rabbit 2000
+
+Hardware BL18x0 'Jackrabbit' boards
+
+ Rabbit 2000 @29.5 or 14.74MHz
+ 128K or 256K flash (256K on the 1800 only)
+ 128K SRAM (factory option for 512K)
+
+ Serial A: control cable
+ Serial B: (we use for SPI instead) RS232
+ Serial C: RS232
+ Serial D: RS485
+
+ RTC and SRAM have battery backup
+
+PA0-PA7 Parallel I/O (Free unless doing slave stuff)
+PB0/PB1 Serial clock (CLKA is connected to programming port)
+ CLKB is needed for SPI
+PB2-7 Free if not using slave
+PC0-PC7 Serial port outputs
+ 0-1 D to RS485
+ 2-5 B and C to RS232
+ 6-7 A to programming port
+PD0-PD7
+ 1-2 Control DA0
+ 4 Control D1 (alt port B TX)
+ 5 RS485 data enable (alt port B RX)
+ 6-7 (Alt port A)
+PE0-PE7
+ 0 HV0 output control
+ 1 HV1 output control
+ 2 HV2 output control
+ 3 HV3 output control
+ 4-5 (INT0B/INT1B)
+ 6 A/D comparator output
+ 7 A/D comparator output
+
+
+
+
+
+The memory map of the R2K is fairly similar to the Z180 but not quite
+
+0000 Base segment
+x000 Data segment
+y000 Stack segment
+E000 XPC
+
+The stack and data segment boundaries can be adjusted and the root segment
+can even be vanished entirely as can stack or data. The E000-FFFF window
+is however fixed and controlled by its own register (XPC)
+
+For simplicity try and get running with E000-FFFF as common. There are better
+layouts but they are more complex.
+
+There are two further complications however
+
+1. The 20bit physical address gets fed into a memory interface unit which
+in theory just sets the wait states and chip selects. However once you get
+more than 1MB it starts getting used for other games as you can route all the
+address lines to each RAM and use the chip selects as a kind of A20/A21
+address line and do further banking this way from software. For now we will
+ignore this as it's usually on Rabbbit 3000 stuff that hits this.
+
+2. All but the early Rabbit 2000 chips support split I/D. In split I/D mode
+the physical address can have either bit 16 or bit 19 inverted when accessing
+data. bit 16 effectively requires a 128K chunk of memory suitably aligned. Bit
+19 is intended for code from flash and data from RAM so is not of interest.
+
+
+Rabbit 2000 CPU bugs/differences
+
+2000 No split ID, no 9bit serial helper
+ Must nop after some I/O operations
+ Cannot start tx/rx together for SPI
+ Wait state bugs (notably in LDxR)
+
+2000A Split I/D supported, 9bit serial added
+ Most instruction bugs fixed
+ Can start tx/rx together for SPI
+ LDIR broken differently (do not use with split I/D)
+
+2000B Rare special run. Differently buggy LDIR
+
+2000C Later edition. Adds early I/O enable
+ Fixes LDIR split I/D and breaks it differently
+
+In general then
+- nop after I/O operations using ioo foo (HL) - all the logic ops and LD
+- don't use LDxR
+
+
+
+Badly Documented Stuff
+
+GCSR register
+
+(0x10->0x9 is done going from 32Khz to main clock)
+Write 0x10 to turn on the main oscillator 00010000
+Write 0x09 to switch the CPU onto it 00001001
+Write 0x05 to switch on /8 clock divider 00000101
+Write 0x14 to switch to 32Khz osc and disable 2Khz tick
+ 00011000
+
+So my guess is
+
+bit 0 - set enabbles the tick
+bit 4 - set enables the CPU to run on 32Khz
+bit 3-2 control the clock
+
+
+Serial oddity
+
+- to send a break switch the tty port off (disconnect from the port C/D) and
+use the I/O bit interface to set/lower the bit!
--- /dev/null
+;
+; Common on z80pack is at 0xF000 as defined by hardware.
+;
+
+ .module commonmem
+
+ .area _COMMONMEM
+
+ .include "../cpu-r2k/std-commonmem.s"
--- /dev/null
+/* We have an RTC */
+#undef CONFIG_RTC
+/* And we can read ToD from it */
+#undef CONFIG_RTC_FULL
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#undef CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 2 32K banks, + 64K is kernel */
+/* When we run from flash we'll fix this to 2 x 64K */
+#define MAX_MAPS 2
+#define MAP_SIZE 0x8000U
+
+#define CONFIG_SD
+#define SD_DRIVE_COUNT 1
+#define MAX_BLKDEV 1
+
+/* Read processes and big I/O direct into process space */
+#define CONFIG_LARGE_IO_DIRECT(x) 1
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS 1
+
+#define TICKSPERSEC 200 /* Ticks per second */
+#define PROGBASE 0x0000 /* also data base */
+#define PROGLOAD 0x0100 /* also data base */
+#define PROGTOP 0x7E00 /* Top of program, base of U_DATA copy */
+#define PROC_SIZE 40 /* Memory needed per process */
+
+#define SWAP_SIZE 0x40 /* 48K in blocks (we actually don't need the low 256) */
+#define SWAPBASE 0x0000 /* We swap the lot in one, include the */
+#define SWAPTOP 0x8000 /* vectors so its a round number of sectors */
+#define MAX_SWAPS 16 /* The full drive would actually be 85! */
+
+#define swap_map(x) ((uint8_t *)(x)) /* Simple zero based mapping */
+
+#define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
+ /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE NULL /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+
+#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV (256 + 1) /* Device for swapping. (FIXME) */
+#define NBUFS 8 /* Number of block buffers */
+#define NMOUNTS 4 /* Number of mounts at a time */
+
+#define platform_discard()
+#define platform_copyright()
--- /dev/null
+ .module crt0
+
+ ; Segment order
+ ; Note: the code segments may be in flash
+ .area _CODE
+ .area _CODE2
+ .area _CONST
+ .area _INITIALIZED
+ .area _DATA
+ .area _BSEG
+ .area _BSS
+ .area _HEAP
+ ; note that areas below here may be overwritten by the heap at runtime, so
+ ; put initialisation stuff in here
+ .area _INITIALIZER
+ .area _GSINIT
+ .area _GSFINAL
+ .area _DISCARD
+ .area _COMMONMEM
+
+ ; imported symbols
+ .globl _fuzix_main
+ .globl init_early
+ .globl init_hardware
+ .globl s__INITIALIZER
+ .globl s__COMMONMEM
+ .globl l__COMMONMEM
+ .globl s__DISCARD
+ .globl l__DISCARD
+ .globl s__DATA
+ .globl l__DATA
+ .globl kstack_top
+ .globl _kdataseg
+
+ ; startup code
+ .area _CODE
+
+ .include "kernel.def"
+ .include "../kernel-rabbit.def"
+;
+; For a RAM startup our configuration is
+;
+; Interrupts off
+; Stack undefined
+;
+; DATASEG set from 0-DFFF
+; XPC segment undefined but will be somewhere in the bootstrap
+; as it will jump to 0
+;
+; Physically mapped so that the kernel starts at ram address 0x0000
+;
+; Serial console is configured, wait states and cs are set up validly
+;
+init:
+ ld sp, #kstack_top
+
+ ; Learn our banks
+
+ ; Will need extending when we start to run from flash
+ ioi
+ ld a,(DATASEG)
+ ld (_kdataseg),a
+ add a,#14 ; 56K on (our E000)
+ ld xpc,a ; We now have 64K linear physical
+ ; space
+ ; For now we don't move XPC, that will change eventually
+
+ ;
+ ; our stack pointer is now valid (we can't do the above in
+ ; init_early as we have no sane stack)
+ ;
+
+ ; Configure memory map
+ call init_early
+
+ ; move the common memory where it belongs (our XPC is now valid)
+ ld hl, #s__DATA
+ ld de, #s__COMMONMEM
+ ld bc, #l__COMMONMEM
+ call doldir
+ ; and the discard
+ ld de, #s__DISCARD
+ ld bc, #l__DISCARD
+ call doldir
+ ; then zero the data area
+ ld hl, #s__DATA
+ ld de, #s__DATA + 1
+ ld bc, #l__DATA - 1
+ ld (hl), #0
+ call doldir
+
+ ; Hardware setup
+ call init_hardware
+
+ ; Call the C main routine
+ call _fuzix_main
+
+ ; main shouldn't return, but if it does...
+stop: jr stop
+
+doldir:
+ ; the ldir instruction is broken in Rabbit 2000 series CPU
+ ; in differing ways depending upon the chip version. So just
+ ; skip using it.
+ ldi
+ jp lo,doldir
+ ret
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devtty.h>
+#include <blkdev.h>
+#include <devsd.h>
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+ /* 0: /dev/hd Hard disc block devices */
+ { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl },
+ /* 1: /dev/fd Floppy disc block devices: nope */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
+ /* 3: /dev/lpr Printer devices */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 4: /dev/mem etc System devices (one offs) */
+ { no_open, no_close, sys_read, sys_write, sys_ioctl },
+ /* 5: Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+ /* This is a bit uglier than needed but the right hand side is
+ a constant this way */
+ if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1)
+ return false;
+ else
+ return true;
+}
+
+void device_init(void)
+{
+#ifdef CONFIG_SD
+ devsd_init();
+#endif
+}
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+#include "rabbit.h"
+
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+static 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 },
+ { tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ/2 },
+};
+
+static tcflag_t console_mask[4] = {
+ _ISYS,
+ _OSYS,
+ _CSYS,
+ _LSYS
+};
+
+/* Port B is owned by our SPI code */
+static uint8_t serial_map[4] = { 0, SADR-SADR, SCDR-SADR, SDDR-SADR };
+
+/* TODO: stty support for the r2k ports */
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+ NULL,
+ console_mask,
+ console_mask,
+};
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+ minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+ minor;
+ return 1;
+}
+
+/*
+ * Drain the interrupt queue
+ */
+void tty_pollirq(void)
+{
+ uint16_t c;
+ while((c = sera_get()) != 0xFF)
+ tty_inproc(1, c);
+ while((c = serc_get()) != 0xFF)
+ tty_inproc(2, c);
+ while((c = serd_get()) != 0xFF)
+ tty_inproc(3, c);
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ out(SADR + serial_map[minor], c);
+}
+
+void tty_sleeping(uint8_t minor)
+{
+ minor;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+ uint8_t r = in(SASR + serial_map[minor]);
+ /* FIXME: should go IRQ driven */
+ if (r & 4)
+ return TTY_READY_SOON;
+ else
+ return TTY_READY_NOW;
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+ while(tty_writeready(TTYDEV) != TTY_READY_NOW);
+ tty_putc(TTYDEV & 0xFF, c);
+ if(c == '\n') {
+ while(tty_writeready(TTYDEV) != TTY_READY_NOW);
+ tty_putc(TTYDEV & 0xFF, '\r');
+ }
+}
--- /dev/null
+extern void tty_pollirq(void);
+
+extern uint16_t sera_get(void);
+extern void sera_setup(uint8_t set) __z88dk_fastcall;
+
+extern uint16_t serc_get(void);
+extern void serc_setup(uint8_t set) __z88dk_fastcall;
+
+extern uint16_t serd_get(void);
+extern void serd_setup(uint8_t set) __z88dk_fastcall;
--- /dev/null
+-mwxuy
+-i fuzix.ihx
+-l r2k
+-b _CODE=0x0100
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xD800
+platform-rabbit2000/crt0.rel
+platform-rabbit2000/commonmem.rel
+platform-rabbit2000/rabbit.rel
+platform-rabbit2000/main.rel
+start.rel
+version.rel
+lowlevel-r2k.rel
+usermem_std-r2k.rel
+platform-rabbit2000/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-rabbit2000/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+bankfixed.rel
+swap.rel
+devsys.rel
+platform-rabbit2000/devtty.rel
+platform-rabbit2000/devsd.rel
+platform-rabbit2000/devsd_discard.rel
+platform-rabbit2000/mbr.rel
+platform-rabbit2000/blkdev.rel
+-e
--- /dev/null
+;
+; The interrupt page. We fold IIR and EIR together
+;
+; For interrupts we should never get we do the required
+; irq clearing reads.
+;
+ .module iir
+
+ .area _IIR
+
+ .globl unix_syscall_entry
+ .globl ticktock
+
+periodic:
+eir0: ; If we use both we'll need to do some
+ ; thinking and maybe split this
+ jp ticktock
+
+ .bndry 16
+eir1:
+ ipres
+ ret
+
+ .bndry 16
+
+rst10:
+ ret
+
+ .bndry 16
+
+rst18:
+ ret
+
+ .bndry 16
+
+rst20:
+ ret
+
+ .bndry 16
+
+rst28:
+ jp unix_syscall_entry
+
+ .bndry 16
+
+spare:
+ ret
+ .bindry 16
+
+rst38:
+ ret
+
+ .bndry 16
+
+slave:
+ ipres
+ ret
+
+ .bndry 16
+
+spare2:
+ ret
+
+ .bndry 16
+
+timera:
+ push af
+ ioi ld a,(TACSR)
+ pop af
+ ipres
+ ret
+
+ .bndry 16
+
+timerb:
+ push af
+ ioi ld a,(TBCSR)
+ pop af
+ ipres
+ ret
+
+ .bndry 16
+
+seriala:
+ push af
+ ioi ld a,(SASR)
+ or a
+ jp m,sera_rx
+ jp sera_tx
+
+ .bndry 16
+
+;
+; B is our SPI
+;
+serialb:
+ ipres
+ ret
+
+ .bndry 16
+
+serialc:
+ push af
+ ioi ld a,(SCSR)
+ or a
+ jp m,serc_rx
+ jp serc_tx
+
+
+ .bndry 16
+
+seriald:
+ push af
+ ioi ld a,(SDSR)
+ or a
+ jp m,serd_rx
+ jp serd_tx
+
+
+ .bndry 16
--- /dev/null
+; UZI mnemonics for memory addresses etc
+
+U_DATA .equ 0xE000 ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes.
+
+U_DATA_STASH .equ 0xBE00 ; BE00-BFFF
+
+PROGBASE .equ 0x0000
+PROGLOAD .equ 0x0100
+
+CONFIG_SWAP .equ 1
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <rabbit.h>
+
+uaddr_t ramtop = PROGTOP;
+
+void pagemap_init(void)
+{
+ int i;
+ for (i = 0; i < 2; i++)
+ pagemap_add(kdataseg + 16 + i << 3); /* In 32K chunks to get us going */
+}
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+ for the polled ports */
+void platform_idle(void)
+{
+ /* We don't want an idle poll and IRQ driven tty poll at the same moment */
+ irqflags_t irq = di();
+ tty_pollirq();
+ irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+ tty_pollirq();
+ timer_interrupt();
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
+
+uint8_t platform_param(char *p)
+{
+ used(p);
+ return 0;
+}
+
--- /dev/null
+extern uint8_t kdataseg;
+
+extern void rabbit_spi_tx(uint8_t c) __z88dk_fastcall;
+extern uint8_t rabbit_spi_rx(void);
+extern void rabbit_spi_slow(void);
+extern void rabbit_spi_fast(void);
+extern void rabbit_read_rtc(uint8_t *ptr) __z88dk_fastcall;
+extern void rabbit_bop_watchdog(uint8_t code) __z88dk_fastcall;
+
+#define GCSR 0x00
+#define RTCCR 0x01
+#define RTC0R 0x02
+#define RTC1R 0x03
+#define RTC2R 0x04
+#define RTC3R 0x05
+#define RTC4R 0x06
+#define RTC5R 0x07
+#define WDTCR 0x08
+#define WDTTR 0x09
+#define GCM0R 0x0A
+#define GCM1R 0x0B
+#define GOCR 0x0E
+#define GCDR 0x0F
+#define MMIDR 0x10
+#define STACKSEG 0x11
+#define DATASEG 0x12
+#define SEGSIZE 0x13
+#define MB0CR 0x14
+#define MB1CR 0x15
+#define MB2CR 0x16
+#define MB3CR 0x17
+#define SPD0R 0x20
+#define SPD1R 0x21
+#define SPD2R 0x22
+#define SPSR 0x23
+#define SPCR 0x24
+#define GCPU 0x2E
+#define GREV 0x2F
+#define PADR 0x30
+#define PBDR 0x40
+#define PCDR 0x50
+#define PCFR 0x55
+#define PDDR 0x60
+#define PDCR 0x64
+#define PDFR 0x65
+#define PDDCR 0x66
+#define PDDDR 0x67
+#define PDB0R 0x68
+#define PDB1R 0x69
+#define PDB2R 0x6A
+#define PDB3R 0x6B
+#define PDB4R 0x6C
+#define PDB5R 0x6D
+#define PDB6R 0x6E
+#define PDB7R 0x6F
+#define PEDR 0x70
+#define PECR 0x74
+#define PEFR 0x75
+#define PEDDR 0x77
+#define PEB0R 0x78
+#define PEB1R 0x79
+#define PEB2R 0x7A
+#define PEB3R 0x7B
+#define PEB4R 0x7C
+#define PEB5R 0x7D
+#define PEB6R 0x7E
+#define PEB7R 0x7F
+#define IB0CR 0x80
+#define IB1CR 0x81
+#define IB2CR 0x82
+#define IB3CR 0x83
+#define IB4CR 0x84
+#define IB5CR 0x85
+#define IB6CR 0x86
+#define IB7CR 0x87
+#define I0CR 0x98
+#define I1CR 0x99
+#define TACSR 0xA0
+#define TACR 0xA2
+#define TAT1R 0xA3
+#define TAT4R 0xA9
+#define TAT5R 0xAB
+#define TAT6R 0xAD
+#define TAT7R 0xAF
+#define TBCSR 0xB0
+#define TBCR 0xB1
+#define TBM1R 0xB2
+#define TBL1R 0xB3
+#define TBM2R 0xB4
+#define TBL2R 0xB5
+#define TBCMR 0xBE
+#define TBCLR 0xBF
+#define SADR 0xC0
+#define SAAR 0xC1
+#define SALR 0xC2
+#define SASR 0xC3
+#define SACR 0xC4
+#define SBDR 0xD0
+#define SBAR 0xD1
+#define SBLR 0xD2
+#define SBSR 0xD3
+#define SBCR 0xD4
+#define SCDR 0xE0
+#define SCAR 0xE1
+#define SCLR 0xE2
+#define SCSR 0xE3
+#define SCCR 0xE4
+#define SDDR 0xF0
+#define SDAR 0xF1
+#define SDLR 0xF2
+#define SDSR 0xF3
+#define SDCR 0xF4
+
+#define GREV_R2000 0x00
+#define GREV_R2000A 0x01
+#define GREV_R2000B 0x02
+#define GREV_R2000C 0x03
+
+#define GCPU_R2000 0x01
--- /dev/null
+;
+; Skeleton for Rabbit 2000
+;
+ .module rabbit
+
+ .area _COMMONMEM
+
+ .globl _platform_reboot
+ .globl _platform_monitor
+
+ .include 'kernel.def'
+ .include '../kernel-rabbit.def'
+
+_platform_reboot:
+_platform_monitor:
+ ; Force a hardware level reset using the watchdog
+ ld a,#0x53
+ ioi
+ ld (WDTCR),a
+ jr _platform_monitor
+
+ .globl platform_interrupt_all
+
+platform_interrupt_all:
+ ret
+
+ .area _COMMONDATA
+
+ .globl _int_disabled
+
+_int_disabled:
+ .db 1
+
+
+ .area _CODE
+
+ .globl init_early
+ .globl init_hardware
+
+ .globl _ramsize
+ .globl _procmem
+
+init_early:
+ ret
+
+init_hardware:
+ ; FIXME: should get this from firmware
+ ld hl,#128
+ ld (_ramsize),hl
+ ld de,#64
+ or a,a
+ sbc hl,de
+ ld (_procmem),hl
+ ret
+
+ .area _COMMONMEM
+
+ .globl _program_vectors
+
+_program_vectors:
+ ret
+
+
+ .globl map_process
+ .globl map_process_always
+ .globl map_process_always_di
+ .globl map_process_a
+ .globl map_kernel
+ .globl map_kernel_di
+ .globl map_save_kernel
+ .globl map_restore
+
+ .globl _kdataseg
+
+map_kernel:
+map_kernel_di:
+ push af
+ ld a,(_kdataseg)
+ ioi
+ ld (DATASEG),a
+ pop af
+ ret
+
+map_process:
+map_process_di:
+ ld a,h
+ or a,l
+ jr z, map_kernel
+ ld a,(hl)
+map_process_a:
+ ioi
+ ld (DATASEG),a
+ ret
+map_process_always:
+map_process_always_di:
+ push af
+ ld a,(U_DATA__U_PAGE)
+ ioi
+ ld (DATASEG),a
+ pop af
+ ret
+map_save_kernel:
+ push af
+ ioi
+ ld a, (DATASEG)
+ ld (map_store),a
+ ld a,(_kdataseg)
+ ioi
+ ld (DATASEG),a ; Must match map_kernel
+ pop af
+ ret
+map_restore:
+ push af
+ ld a,(map_store)
+ ioi
+ ld (DATASEG),a
+ pop af
+ ret
+map_store:
+ .db 0
+_kdataseg:
+ .db 0
+
+ .globl outchar
+
+outchar:
+ push af
+outwait:
+ ioi
+ ld a, (SASR)
+ bit 2,a
+ jr nz,outwait
+ pop af
+ ioi
+ ld (SADR),a
+ ret
+
+ .globl _spi_tx
+;
+; Low level Rabbit 2000 primitives to use Port B for SPI.
+;
+; Assumptions: The port is configured and the clock is set up
+; properly. That is you have the serial pins enabled and you have
+; timer A5 programmed and running.
+;
+; We don't support simultaneous rx/tx although the R2000 can do it
+; at lower speeds with some mucking about. SD doesn't need the full
+; duplex behaviour.
+;
+; Remember the bit ordering !
+
+
+ .area _CODE
+
+ .globl _rabbit_spi_tx
+ .globl _rabbit_spi_rx
+ .globl _rabbit_spi_slow
+ .globl _rabbit_spi_fast
+;
+_rabbit_spi_tx:
+ ; Finish any previous transaction activity
+ ioi
+ ld a,(SBSR)
+ bit 7,a
+ jr nz,_rabbit_spi_tx
+ ld a,l
+ ioi
+ ld (SBDR),a
+ ld a, #0x8C ; send, our clock (ie master)
+ ioi
+ ld (SBCR),a
+txwait: ioi
+ ld a,(SBSR)
+ bit 3,a
+ jr nz,txwait
+txwait2: ioi
+ ld a,(SBSR)
+ bit 2,a
+ jr nz,txwait2
+ ret
+
+_rabbit_spi_rx:
+ ; Fire up the receiver and clock
+ ld a,#0x4C ; receive (using PC4, 0x5C is PD4)
+ ioi
+ ld (SBCR),a
+ ; Wait for the data byte to appear
+ ; This is bounded by the synchronous clock
+rxwait:
+ ioi
+ ld a,(SBSR)
+ and a,#0x80
+ jr z,rxwait
+ ioi
+ ld a,(SBDR)
+ ld l,a
+ ret
+
+
+;
+; Slow speed for probing
+;
+_rabbit_spi_slow:
+ ld a,#30 ; about 25KHz with a 29.5MHz clock
+ ioi
+ ld (TAT5R),a
+ ret
+
+;
+; Set the timer for fast SPI.
+;
+; We are limited to about 7.5MHz
+;
+_rabbit_spi_fast:
+ xor a,a
+ ioi
+ ld(TAT5R),a
+ ret
+
+;
+; Real time clock interface. This is a 48bit counter running at 32KHz
+;
+; Convention is that clock 0 is Jan 1 1980
+;
+; The caller needs to ensure that they get two identical copies
+;
+
+ .globl _rabbit_read_rtc
+
+_rabbit_read_rtc:
+ ex de,hl ; C argument is the buffer
+ ld hl,#RTC0R
+ ioi
+ ld (hl),#0
+ nop ; R2000 erratum
+ ipset3
+ ioi
+ ldi
+ ioi
+ ldi
+ ioi
+ ldi
+ ioi
+ ldi
+ ioi
+ ldi
+ ioi
+ ldi
+ ipres
+ ret
+
+;
+; Watchdog timer
+;
+; 0x5A = 2 second, 0x57 = 1 second, 0x59 = 500m, 0x53 = 250ms
+;
+ .globl _rabbit_bop_watchdog
+
+_rabbit_bop_watchdog:
+ ld a,l
+ ioi
+ ld (WDTCR),a
+ ret
+;
+; Periodic interrupt. Annoyingly fixed at 2KHz it seems
+; This is the same for all rabbit 2k so maybe it belongs in the
+; lowlevel-rabbit code ?
+;
+ .globl ticktock
+
+ .globl _ticker
+ .globl interrupt_handler
+ticktock:
+ push af
+ ioi
+ ld a,(GCSR)
+ push hl
+ ld hl,#_ticker
+ inc (hl)
+ jr z,tickwrap
+ pop hl
+ pop af
+ ipres
+ ret
+tickwrap: ld (hl),#11 ; slightly off for 200/second but the rtc
+ ; will compensate just fine. We need the
+ ; speed for the serial queues
+ jp interrupt_handler
+
+;
+; Serial queues. The basic logic for them is given in the manual
+; We do a simple optimization - our queues never cross a page. With
+; the free d we then read the char early
+;
+; Our platform interrupt will pick up the queue each timer tick
+;
+
+.macro serial X Y
+
+ .area _COMMONMEM
+
+ .globl _ser'X'_q
+ .globl _ser'X'_rxbuf
+
+ser'X'_rx:
+ push hl
+ push de
+ ioi
+ ld a,(S'Y'DR)
+ ld d,a
+ ld hl,#_ser'X'_q
+ ld a,(hl)
+ ld e,a
+ inc hl
+ cp a,(hl)
+ jr z,ser'X'_rx_over
+ inc a
+ and a, #63
+ dec hl
+ ld (hl),a
+ ipres
+ ; work around stupid linker bug
+ ld hl, #_ser'X'_rxbuf
+ ld l,e
+ ld (hl),d
+ser'X'_rx_over: ; for now do nothing clever
+ pop de
+ pop hl
+ pop af
+ ret
+
+ser'X'_tx: ; really 'transmit and other...'
+ ; we don't do transmit interrupts yet but we
+ ; can't turn them off alone 8(
+ ioi
+ ld (S'Y'SR),a
+ pop af
+ ipres
+ ret
+
+ .globl _ser'X'_setup
+ .globl _ser'X'_get
+
+;
+; 00PPMMII
+;
+; PP 00 port C 01 port D 1X off
+; MM 00 8bit 01 7bit 10 clocked ext, 11 clocked int
+; II 00 no int 01 pri 1 10 pri 2 11 pri 3
+;
+_ser'X'_setup:
+ ld a,l
+ ioi
+ ld (S'Y'CR),a
+ ret
+
+_ser'X'_get:
+ ld hl,#_ser'X'_q
+ ld a,(hl) ; out ptr
+ ld e,a
+ inc hl
+ inc a
+ cp a,(hl) ; in ptr
+ jr nz, ser'X'_empty
+ dec hl
+ ipset3
+ ld (hl),a
+ ld hl,#_ser'X'_rxbuf ; work around dumb linker limit
+ ld l,e
+ ld l,(hl)
+ ld h,#0
+ ipres
+ ret
+ser'X'_empty:
+ ld hl,#0xffff
+ ret
+_ser'X'_q:
+ .db 0
+ .db 1
+
+ .area _SERIALBUF
+
+_ser'X'_rxbuf: .ds 64
+
+ .area _COMMONMEM
+.endm
+
+serial a A
+serial c C
+serial d D
--- /dev/null
+export CPU = r2k
+
--- /dev/null
+
+ .include "../kernel.def"
+ .include "kernel.def"
+
+ .include "../lib/r2kfixedbank.s"