--- /dev/null
+
+CSRCS = devlpr.c devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = sam.s crt0.s sam_vt.s floppy.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all: $(OBJS)
+
+$(COBJS): %.rel: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+ $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~
+
+image:
--- /dev/null
+Sam Coupe prototyping and 32K/32K split development work
+
+Proposed memory layout
+
+Kernel mode
+
+0-7FFF Kernel in bank 2/3
+8000-FFFF Kernel in bank 0/1
+
+Video
+
+0-5FFF Frame buffer (mode 3) bank 4/5
+6000-6FFF Font
+7000-7FFF Free
+8000-FFFF Kernel in bank 0/1
+
+User Space
+
+0000-00FF Thunking code
+0100-7FFF User page
+8000-FCFFF User page
+FD00-FEFF UDATA stash
+FF00-FFFF Thunking code
+
+Probably will move the thunking code mostly into FFxx somewhere so we
+can do CP/M emulation still
+
+Extmem support would require extra work and separate high/low pools for
+the bank allocator
+
+User Copies
+
+0000-7FFF User bank for copy
+8000-FFFF Kernel in bank 0/1
+
+Forking
+
+0000-00FF Parent low stubs
+0100-7FFF Parent low bank
+8000-80FF Child low stubs (not yet set)
+8100-FFFF Child low bank
+
+then
+
+0000-7EFF Parent high bank
+7F00-7FFF Parent high stubs
+8000-FEFF Child high bank
+FF00-FFFF Child stubs (not yet set)
+
+Stub code is in the low parts of the low banks and the top of the high banks
+so we have two copier routines one for each half.
+
+
+To Do:
+
+- Keyboard map
+- Interrupt logic
+- Boot loader
+
+Then once we can get to the point of being able to see and type
+
+- Move fonts to video bank after frame buffer
+- Floppy driver (at least for read)
+- Get to init
+- Debug all the new banking code and stubs
+- Atom and Atom-lite IDE driver
+- Look at how to preserve high colour bits
+
+- RTC driver
+- Serial driver
+- Mouse/Joystick/Input
+
+- Mode setting/graphics mode support
+- Video ioctls
+- UDG ioctls
+- Is there any way to do video mapping into user process sanely
+ (probably not)
+
+- Sound
+
+- MegaRAM
+
+- Maybe look at a 16K boundary aware allocator to get better memory
+ packing - but it's really hairy.
+
+- Less interrupt masking (but the banking logic makes it really foul
+ especially as we don't have proper IM2 support)
+
+- Maybe look at the modern add ons (SD card, network etc)
+
--- /dev/null
+;
+; Boot block, loaded at 0x4000
+;
+; Banks and SP we need to double check are ROM0/1/2/3 and valid
+;
+; The boot block is trivial but it gets a bit fun once we've loaded
+; our 14 tracks
+;
+; We load
+; 32K into bank 2/3
+; 32K into bank 4/5
+; 5.5K into bank 6/7
+;
+; by loading 14 tracks off side 0 skipping track 0 sector 1 which is
+; the boot block itself.
+;
+; We then run from 0x8000 in bank 6, which will untangle everything
+; for us shuffling the kernel so that 0/1 is the low kernel in RAM
+; 2/3 is the high kernel in RAM and 4/5 is the video
+; (or maybe it'll be saner to use 4/5 for kernel 2/3 video..)
+;
+boot:
+ di
+ ld de,#2 ; track 0 sector 2 (we are sector 0)
+ ld a,e ; Start in bank 2
+ ld hl,#0x8000 ; Which we map high
+ out (HIMEM),a
+ ex af,af'
+next_sec:
+ bit 7,h ; If the last read went to 0000
+ jr nz, still_good
+ set 7,h ; Go back to 8000 and move on 32K
+ ex af,af'
+ inc a
+ inc a
+ out (HIMEM),a ; switch bank
+ ex af,af'
+still_good:
+ ld a,e ; update the sector register
+ ld (SECTOR),a
+dread: ld a,#CMD_READ ; Ask for data from the FDC
+ out (CMD),a
+ ld b,#20 ; Wait for FDC
+nap: djnz nap
+ ld bc,DATA ; Begin reading from data port
+ jr waitbyte
+byte: ini
+wait: in a,(STATUS) ; Wait for DRQ
+ bit 1,a
+ jr nz,byte ; When we get a DRQ read a byte
+ rrca ; Check for end/error
+ jr c,wait
+ ; and with 0d to check error FIXME
+ ;
+ ; Sector done. Move on a sector
+ ;
+ inc e
+ ld a,#11
+ cp e
+ jr nz, next_sec
+ ;
+ ; Move on a track - do a step in command
+ ;
+ ld e,#1
+ inc d
+ ;
+ ; We read 14 tracks minus 1 sector which loads us
+ ;
+ ;
+ ld a,#14
+ cp d
+ ; Jump to the start of the last bank loaded. This is actually
+ ; packed up boot stuff and font. We loaded 5.5K here, of which 4K
+ ; was font, leaving a spacious 1.5K to untangle all the banks and
+ ; boot up.
+ jp z, 0x8000
+ ld a,#CMD_STEPIN
+ out (CMD),a
+nap2: ld b,#20
+ djnz nap2
+wait2: in a,(STATUS)
+ bit 0,a
+ jr nz,wait2
+ jr next_sec
--- /dev/null
+;
+; We have no real common on the TRS80so just tuck it up at the top of
+; memory leaving room for the keyboard and video (3K)
+;
+ .module commonmem
+
+ .area _COMMONMEM
+
+ .include "../cpu-z80/std-commonmem.s"
+
--- /dev/null
+/* Set if you want RTC support and have an RTC on ports 0xB0-0xBC */
+#undef CONFIG_RTC
+
+/* 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) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* Fonts are pre-expanded as we have reasonable amounts of memory and
+ need to deal with a 2bit deep bitmap display */
+#define CONFIG_FONT_8X8_EXP2
+
+/* Banked memory set up */
+/* FIXME */
+#define CONFIG_BANK_FIXED
+#define MAX_MAPS 16
+#define MAP_SIZE 0xFD00
+
+#define CONFIG_BANKS 2 /* 2 x 32K */
+
+/* Vt definitions */
+#define VT_WIDTH 80
+#define VT_HEIGHT 24
+#define VT_RIGHT 79
+#define VT_BOTTOM 23
+
+#define TICKSPERSEC 50 /* Ticks per second */
+#define PROGBASE 0x0000 /* Base of user */
+#define PROGLOAD 0x0100 /* Load and run here */
+#define PROGTOP 0xFD00 /* Top of program, base of U_DATA stash */
+#define PROC_SIZE 64 /* Memory needed per process */
+
+#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 2
+#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 */
--- /dev/null
+ ; For 32K banking we need to keep anything that is common
+ ; and anything that might be copied to or from user space
+ ; in the top 32K. So fill the bottom with code
+ .area _CODE
+ .area _CODE2
+ .area _HOME
+ ; Must be above the 32K boundary
+ ; FIXME: we really want to bank the fonts in the video area
+ .area _VIDEO
+ .area _HIGH
+ .area _FONT
+ .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 _GSINIT
+ .area _GSFINAL
+ .area _DISCARD
+ .area _INITIALIZER
+ .area _COMMONMEM
+
+ .area _PAGE0
+ .area _PAGEH
+
+ ; imported symbols
+ .globl _fuzix_main
+ .globl init_early
+ .globl init_hardware
+ .globl s__DATA
+ .globl l__DATA
+ .globl s__DISCARD
+ .globl l__DISCARD
+ .globl s__COMMONMEM
+ .globl l__COMMONMEM
+ .globl s__INITIALIZER
+ .globl kstack_top
+
+ ; startup code
+ .area _CODE
+
+;
+; Once the loader completes it jumps here
+;
+start:
+ ld sp, #kstack_top
+ ; move the common memory where it belongs
+ ld hl, #s__DATA
+ ld de, #s__COMMONMEM
+ ld bc, #l__COMMONMEM
+ ldir
+ ; then the discard
+ ld de, #s__DISCARD
+ ld bc, #l__DISCARD
+ ldir
+ ; then zero the data area
+ ld hl, #s__DATA
+ ld de, #s__DATA + 1
+ ld bc, #l__DATA - 1
+ ld (hl), #0
+ ldir
+ call init_early
+ call init_hardware
+ call _fuzix_main
+ di
+stop: halt
+ jr stop
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+#define MAX_FD 4
+
+#define OPDIR_NONE 0
+#define OPDIR_READ 1
+#define OPDIR_WRITE 2
+
+#define FD_READ 0x80 /* 2797 needs 0x88, 1797 needs 0x80 */
+#define FD_WRITE 0xA0 /* Likewise A8 v A0 */
+
+static uint8_t motorct;
+static uint8_t fd_selected = 0xFF;
+static uint8_t fd_tab[MAX_FD] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*
+ * We only support normal block I/O for the moment. We do need to
+ * add swapping!
+ */
+
+static uint8_t selmap[4] = { 0x01, 0x02, 0x04, 0x08 };
+
+static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+ int ct = 0;
+ int tries;
+ uint8_t err = 0;
+ uint8_t *driveptr = fd_tab + minor;
+ uint8_t cmd[6];
+
+ if(rawflag == 2)
+ goto bad2;
+
+ if (fd_selected != minor) {
+ uint8_t err;
+ /* FIXME: We force DD for now */
+ err = fd_motor_on(selmap[minor]|0x80);
+ if (err)
+ goto bad;
+ }
+
+ if (*driveptr == 0xFF)
+ fd_reset(driveptr);
+
+ if (rawflag && d_blkoff(BLKSHIFT))
+ return -1;
+
+ cmd[0] = is_read ? FD_READ : FD_WRITE;
+ cmd[1] = udata.u_block / 9; /* 2 sectors per block */
+ cmd[2] = ((udata.u_block % 9) << 1) + 1; /*eww.. */
+ cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE;
+ cmd[4] = ((uint16_t)udata.u_dptr) & 0xFF;
+ cmd[5] = ((uint16_t)udata.u_dptr) >> 8;
+
+ while (ct < 2) {
+ for (tries = 0; tries < 4 ; tries++) {
+ err = fd_operation(cmd, driveptr);
+ if (err == 0)
+ break;
+ if (tries > 1)
+ fd_reset(driveptr);
+ }
+ /* FIXME: should we try the other half and then bale out ? */
+ if (tries == 4)
+ goto bad;
+ cmd[5]++; /* Move on 256 bytes in the buffer */
+ cmd[2]++; /* Next sector for 2nd block */
+ ct++;
+ }
+ return udata.u_nblock << 8;
+bad:
+ kprintf("fd%d: error %x\n", minor, err);
+bad2:
+ udata.u_error = EIO;
+ return -1;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+ flag;
+ if(minor >= MAX_FD) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;
+ return fd_transfer(minor, true, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;rawflag;minor;
+// return 0;
+ return fd_transfer(minor, false, rawflag);
+}
--- /dev/null
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+
+/* low level interface */
+uint16_t fd_reset(uint8_t *driveptr);
+uint16_t fd_operation(uint8_t *cmd, uint8_t *driveptr);
+uint16_t fd_motor_on(uint16_t drivesel);
+uint16_t fd_motor_off(uint16_t driveptr);
+
+#endif /* __DEVFD_DOT_H__ */
--- /dev/null
+#include <kernel.h>
+#include <tty.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+ /* 0: FIXME IDE */
+ { fd_open, no_close, fd_read, fd_write, no_ioctl },
+ /* 1: /dev/dd Hard disc block devices */
+ { fd_open, no_close, fd_read, fd_write, no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
+ /* 3: /dev/lpr Printer devices */
+ { 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 },
+ /* 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)
+{
+ int i;
+#ifdef CONFIG_RTC
+ /* Time of day clock */
+ inittod();
+#endif
+}
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat; /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+ minor; flag; // shut up compiler
+ return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+ minor; // shut up compiler
+ return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ int c = udata.u_count;
+ char *p = udata.u_base;
+ minor; rawflag; flag; // shut up compiler
+
+ while(c) {
+ /* Note; on real hardware it might well be necessary to
+ busy wait a bit just to get acceptable performance */
+ while (lpstat != 0xFF) {
+// if (psleep_flags(&clocktick, flag))
+// return -1;
+ }
+ /* FIXME: tidy up ugetc and sysio checks globally */
+ lpdata = ugetc(p++);
+ }
+ return (-1);
+}
--- /dev/null
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <vt.h>
+#include <devtty.h>
+#include <stdarg.h>
+
+char tbuf1[TTYSIZ];
+char tbuf2[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 }
+};
+
+/* Write to system console */
+void kputchar(char c)
+{
+ if(c=='\n')
+ tty_putc(1, '\r');
+ tty_putc(1, c);
+}
+
+uint8_t tty_writeready(uint8_t minor)
+{
+ return TTY_READY_NOW;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ if (minor == 1)
+ vtoutput(&c, 1);
+}
+
+void tty_interrupt(void)
+{
+}
+
+void tty_setup(uint8_t minor)
+{
+}
+
+int tty_carrier(uint8_t minor)
+{
+ return 1;
+}
+
+void tty_sleeping(uint8_t minor)
+{
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+static uint8_t keymap[9];
+uint8_t keyin[9];
+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;
+
+ /* Call asm keyin here FIXME */
+ 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 */
+ 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();
+}
+
--- /dev/null
+#ifndef _DEVTTY_H
+#define _DEVTTY_H
+
+extern void tty_interrupt(void);
+extern void kbd_interrupt(void);
+
+#endif
--- /dev/null
+;
+; TODO
+;
+
+ .module floppy
+
+ .area _HIGH
+
+ .globl _fd_motor_on
+ .globl _fd_operation
+ .globl _fd_reset
+
+_fd_operation:
+_fd_reset:
+_fd_motor_on:
+ ret
--- /dev/null
+-mwxuy
+-i fuzix.ihx
+-b _PAGE0=0x0001
+-b _CODE=0x0100
+-b _COMMONMEM=0xF800
+-b _PAGEH=0xFF00
+-l z80
+platform-sam/crt0.rel
+platform-sam/commonmem.rel
+start.rel
+version.rel
+lowlevel-z80-thunked.rel
+usermem.rel
+usermem_std-z80-thunked.rel
+timer.rel
+kdata.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
+swap.rel
+bankfixed.rel
+vt.rel
+font8x8_exp2.rel
+devsys.rel
+platform-sam/devfd.rel
+platform-sam/devices.rel
+platform-sam/devlpr.rel
+platform-sam/devtty.rel
+platform-sam/floppy.rel
+platform-sam/main.rel
+platform-sam/sam.rel
+platform-sam/tricks.rel
+platform-sam/sam_vt.rel
+-e
--- /dev/null
+; UZI mnemonics for memory addresses etc
+
+U_DATA .equ 0x010 ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE .equ 0x200 ; 512 bytes.
+
+U_DATA_STASH .equ 0xFD00 ; FD00-FEFF
+ ; FF00-FFFF is the high stubs
+
+
+PROGBASE .equ 0x0000
+PROGLOAD .equ 0x0100
+
+Z80_TYPE .equ 1
+
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint16_t ramtop = PROGTOP;
+uint8_t need_resched;
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+ for the polled ports */
+void platform_idle(void)
+{
+ __asm
+ halt
+ __endasm;
+}
+
+void do_beep(void)
+{
+}
+
+void platform_interrupt(void)
+{
+ tty_interrupt();
+ kbd_interrupt();
+ timer_interrupt();
+}
+
+void map_init(void)
+{
+}
+
+void platform_discard(void)
+{
+}
+
+void pagemap_init(void)
+{
+ pagemap_add(0x63); /* Mode 3, U64K low 32K mapped as low 32K */
+ pagemap_add(0x73); /* Mode 3, U64K high 32K mapped as low 32K */
+}
+
+
+uint8_t platform_param(char *p)
+{
+ used(p);
+ return 0;
+}
+
--- /dev/null
+export BANKED=-thunked
--- /dev/null
+;
+; SAM Coupe initial hardware support
+;
+
+ .module sam
+
+ ; exported symbols
+ .globl init_early
+ .globl init_hardware
+ .globl interrupt_handler
+ .globl _program_vectors
+ .globl _kernel_flag
+ .globl map_page_low
+ .globl map_kernel_low
+ .globl map_user_low
+ .globl map_save_low
+ .globl map_restore_low
+ .globl map_video
+ .globl unmap_video
+ .globl _platform_doexec
+ .globl _platform_reboot
+ .globl _platform_copier_l
+ .globl _platform_copier_h
+
+ ; exported debugging tools
+ .globl _platform_monitor
+ .globl outchar
+
+ ; imported symbols
+ .globl _ramsize
+ .globl _procmem
+ .globl istack_top
+ .globl istack_switched_sp
+ .globl kstack_top
+ .globl unix_syscall_entry
+ .globl outcharhex
+ .globl _keyin
+
+ .globl s__COMMONMEM
+ .globl l__COMMONMEM
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+KERNEL_HIGH .equ 0
+KERNEL_LOW .equ 2 ; 0/1 high 2/3 low
+VIDEO_LOW .equ 4
+
+; -----------------------------------------------------------------------------
+;
+; Because of the 32K split our memory model is a bit different to the
+; usual Z80 setup.
+;
+; -----------------------------------------------------------------------------
+ .area _COMMONMEM
+
+_platform_monitor:
+ di
+ halt ; NMI button will cause a reboot..
+_platform_reboot:
+ xor a
+ out (250), a ; ROM appears low
+ rst 0 ; bang
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below common, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+ .area _DISCARD
+
+; colours - FIXME correct these
+ .db 0,32,64,120
+clutmap:
+init_early:
+ ld a, #0x44 ; Kernel is in 0/1 2/3, so video goes above it
+ ; Video mode 3 (with luck)
+ out (252), a
+ ld a, #0x10 ; black border, mic 1
+ out (254), a
+ in a, (251)
+ and #0x9F ; low palette colours
+ ld hl, #clutmap
+ ld bc, #4*256 + 248 ; 4 colours, port 248
+ otdr
+ ret
+
+init_hardware:
+ ; set system RAM size (FIXME - check for 512/1M)
+ ld hl, #256
+ ld (_ramsize), hl
+ ld hl, #(256-64) ; 64K for kernel
+ ld (_procmem), hl
+
+ ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+ ld hl, #0
+ push hl
+ call _program_vectors
+ pop hl
+
+ im 1 ; set CPU interrupt mode
+
+ ; interrupt mask
+ ; 60Hz timer on
+
+ ret
+
+ .area _HIGH
+
+_kernel_flag:
+ .db 1 ; We start in kernel mode
+low_map:
+ .db KERNEL_LOW
+low_save:
+ .db 0
+video_save:
+ .db 0
+
+map_save_low:
+ push af
+ ld a,(low_map)
+ ld (low_save),a
+ pop af
+ ; Fall through as we also map the kernel
+map_kernel_low:
+ push af
+ ld a,#KERNEL_LOW
+ ld (low_map),a
+ out (250),a
+ pop af
+ ret
+map_restore_low:
+ ld a, (low_save)
+ jr map_page_low
+map_user_low:
+ ld a,(U_DATA__U_PAGE)
+map_page_low:
+ ld (low_map),a
+ out (250),a
+ ret
+map_video:
+ ld a,(low_map)
+ ld (video_save),a
+ ld a,#VIDEO_LOW
+ jr map_page_low
+unmap_video:
+ ld a,(video_save)
+ jr map_page_low
+
+_program_vectors:
+ ; we are called, with interrupts disabled, by both newproc() and crt0
+ ; will exit with interrupts off
+ di ; just to be sure
+ pop de ; temporarily store return address
+ pop hl ; function argument -- base page number
+ push hl ; put stack back as it was
+ push de
+
+ ld a,(hl) ; get the low page
+ call map_page_low
+
+ ; Copy the stub page into place
+ ld hl, #stub_page
+ ld de, #0x0000
+ ld bc, #0x0100
+ ldir
+ jp map_kernel_low
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+;
+; We use the MIDI port for debug - it's not useful for much else after all.
+;
+outchar:
+ push af
+outcw: in a,(248)
+ bit 1,a
+ jr nz, outcw
+ pop af
+ out (253),a
+ ret
+;
+; Keyboard scanner. This is easiest kept in asm space
+; (reference code from the technical manual)
+;
+_keyscan:
+ ld hl, #_keyin
+ ld b, #0xFE
+keyscl: ld c, #249 ; need BC out to get address lines
+ in a, (c)
+ and #0xE0 ; top 3 bits valid
+ ld d, a
+ ld c, #254
+ in a, (c)
+ and #0x1F ; low 5 bits
+ or d
+ ld (hl), a
+ inc hl
+ scf
+ rlc b
+ jr c, keyscl
+ in a, (c)
+ and #0x1F
+ ld (hl), a
+ ret
+
+ .area _PAGE0
+;
+; Loaded into 00-FF in the bottom of the kernel and then into other
+; pages. There is an argument for putting most of this at the top of
+; the high page of everything. That might allow us to run CP/M
+; emulation
+;
+; Move what we can into PAGEH and high kernel code
+;
+; We'd still need some low space but we have 0A-3A/3B-4F/57-5B
+;
+; We can't deal with NMI in the CP/M case though.
+;
+; Starts at address 1 to avoid an SDCC flaw
+;
+stub_page:
+
+stub0: .word 0 ; cp/m emu changes this
+ .byte 0 ; cp/m emu I/O byte
+ .byte 0 ; cp/m emu drive and user
+ jp 0 ; cp/m emu bdos entry point
+rst8:
+_platform_copier_l:
+ ld a,(hl)
+ out (251),a
+ exx
+ ldir
+ exx
+ nop ; fall through
+rst10: ld a,#KERNEL_HIGH
+ out (251),a
+ ret
+ nop
+ nop
+ nop
+rst18:
+_platform_doexec:
+ out (251),a ; FIXME: trashing of clut high bits
+ ei
+ jp (hl)
+ nop
+rst20: nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+rst28: jp syscall_path
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+rst30: nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+rst38: ; Interrupt handling stub
+ push af
+ push de
+ push hl
+ ; FIXME: this trashes any clut overrides
+ ld a,#KERNEL_HIGH
+ out (251),a
+ ; Kernel is now the high map. Our stack may be invalid
+ ; so be careful
+ ld (istack_switched_sp),sp
+ ld sp,#istack_top
+ call interrupt_handler
+ ; On return HL = signal vector E= signal (if any) A = page for
+ ; high
+ ; FIXME 0 = kernel do we need to xlate ?
+ out (251),a
+ ; stack is invalid again now
+ ld sp,(istack_switched_sp)
+ ; back on user stack
+ xor a
+ cp e
+ call nz, sigpath
+ pop hl
+ pop de
+ pop af
+ ei
+ ret
+ nop
+ nop
+ nop
+nmi_handler: ; FIXME: check ends up at 0066
+ retn
+sigpath:
+ push de ; signal number
+ ld de,#irqsigret
+ push de ; clean up
+ jp (hl)
+irqsigret:
+ inc sp ; drop signal number
+ inc sp
+ ret
+
+syscall_path:
+ push ix
+ ;TODO : BC/DE/HL/IX off stack
+ ; FIXME trashes the clut bits
+ ld a,#KERNEL_HIGH
+ di
+ out (251),a
+ ; Stack now invalid
+ ld (U_DATA__U_SYSCALL_SP),sp
+ ld sp,#kstack_top
+ call unix_syscall_entry
+ ; FIXME check di rules
+ ; On return A is the page (0 means kernel),
+ ; FIXME: do we need to xlate
+ out (251),a
+ ; stack now invalid
+ ld sp,(U_DATA__U_SYSCALL_SP)
+ xor a
+ cp h
+ call nz, syscall_sigret
+ ; FIXME for now do the grungy C flag HL DE stuff from
+ ; lowlevel-z80 until we fix the ABI
+ ld bc,#0
+ pop ix
+ ret
+syscall_sigret:
+ push hl ; save errno
+ push de ; save retval
+ ld l,h
+ ld h,#0
+ push hl ; signal
+ ld hl,#syscall_sighelp
+ push bc ; vector
+ ret
+syscall_sighelp:
+ pop de ; discard signal
+ pop de ; recover error info
+ pop hl
+ ld h,#0 ; clear signal bit
+ ret
+
+ .area _PAGEH
+;
+; High stubs. Present in each bank
+;
+_platform_copier_h:
+ ld a,(hl)
+ out (251),a
+ exx
+ ldir
+ exx
+ ld a,#KERNEL_HIGH
+ out (251),a
+ ret
--- /dev/null
+;
+; Video layer for the SAM. For the moment we use a fairly primitve
+; set up. We'd really like a mono hi-res mode but you don't get one
+;
+; Our display consists of 192 lines of 128 bytes (24K) and is page
+; aligned.
+;
+; We really want to do 80 column 6bit chars but start simple
+;
+; Our video is 0 based so we don't add an offset
+; Must preserve BC
+;
+
+ .module sam_vt
+
+ .area _VIDEO
+
+ .globl _scroll_up
+ .globl _scroll_down
+ .globl _plot_char
+ .globl _clear_lines
+ .globl _clear_across
+
+ .globl _cursor_on
+ .globl _cursor_off
+ .globl _cursor_disable
+
+ .globl _vtattr_notify
+ .globl _vtattr_cap
+
+ .globl map_video
+ .globl unmap_video
+ .globl ___hard_di
+ .globl _fontdata_8x8_exp2
+
+VIDEO_PAGE .equ 4
+
+_vtattr_cap:
+ .byte 0 ; for now- we can add funky effects later
+
+base_addr:
+ ld a,d ; save X
+ ld d,e ; 256 * Y
+ ld e,#0
+ srl d
+ srl e ; this is DE = E * 128
+ ; A is a char 0-63 - need a byte 0-126
+ ; Aligned so no carry issues
+ add a
+ add e
+ ld e,a
+ ret
+
+;
+; This is awkward. We can't map the video in 0000-7FFF without
+; interrupts off, and we can't map it high without confusing the
+; hell out of everything else. For now just di. 32K/32K splits suck
+;
+_scroll_up:
+ call ___hard_di
+ push af
+ call map_video
+ ld hl,#128
+ ld de,#0
+ ld bc,#24576-128
+ldir_pop:
+ ldir
+pop_unmap:
+ call unmap_video
+ pop af
+ ret c
+ ei
+ ret
+
+_scroll_down:
+ call ___hard_di
+ push af
+ call map_video
+ ld hl,#24576
+ ld de,#24576-128
+ ld b,d
+ ld c,e
+ lddr
+ jr pop_unmap
+
+_plot_char:
+ pop hl ; return
+ pop de ; H = X L = Y
+ pop bc ; C = char
+ push bc
+ push de
+ push hl
+ call ___hard_di
+ push af
+ call base_addr
+ ld h,#0
+ ld l,c
+ add hl,hl ; char * 16 (expanded 8 x 8)
+ add hl,hl
+ add hl,hl
+ add hl,hl
+ ld bc,#_fontdata_8x8_exp2 ; plus font base
+ add hl,bc
+ call map_video
+ ld b,#20 ; it gets decremented by 4 by the ldi's
+ ; and once by djnz, and we need to do it
+ ; four times
+plot_loop:
+ ldi ; copy expanded char
+ ldi
+ dec e
+ dec e
+ set 7,e ; de += 126
+ ldi ; copy second char row
+ ldi
+ dec e ; Similar idea
+ dec e ; toggle the bit back and gives us
+ res 7,e
+ inc d ; de += 126
+ djnz plot_loop
+ jr pop_unmap
+
+_clear_lines:
+ pop hl
+ pop de
+ push de
+ push hl
+ call ___hard_di
+ push af
+ ld a,d ; count (0-23)
+ ld d,#0
+ ; Now how much to copy ?
+ ; 128 bytes per scan line, 8 scan lines per char = 1024
+ add a,a ; x 2
+ add a,a ; x 4
+ ld b,a ; x 1024
+ ld c,d ; d is 0
+ call base_addr
+ call map_video
+ ld h,d
+ ld e,l
+ inc de
+ dec bc
+ ld (hl),#0
+ jr ldir_pop
+
+_clear_across:
+ pop hl
+ pop de ; DE = X/Y
+ pop bc ; C = count
+ push bc
+ push de
+ push hl
+
+ call ___hard_di
+ push af
+
+ call base_addr
+ call map_video
+
+ xor a
+ ld l,#4 ; 4 line pairs
+ ld h,e ; save offset start
+wipe_line:
+ ld b,c
+wipe_rowpair:
+ ld (de),a
+ set 7,e
+ ld (de),a
+ res 7,e
+ inc de
+ djnz wipe_rowpair
+ ld e,h ; restore offset. As we are 256 byte aligned we don't need
+ inc d ; to worry about carries just restore low, inc high
+ dec l
+ jr nz, wipe_line
+ jp pop_unmap
+
+;
+; TODO
+;
+_cursor_on:
+_cursor_off:
+_cursor_disable:
+_vtattr_notify:
+ ret
--- /dev/null
+export CPU = z80
--- /dev/null
+
+ .include "../kernel.def"
+ .include "kernel.def"
+
+;FIXME .include "../lib/z80fixedbank.s"
+
+ .module tricks32
+
+ .globl _ptab_alloc
+ .globl _newproc
+ .globl _chksigs
+ .globl _getproc
+ .globl _runticks
+ .globl _platform_monitor
+
+ .globl _platform_switchout
+ .globl _switchin
+ .globl _dofork
+
+ .globl map_page_low
+ .globl map_kernel_low
+
+ .globl outhl
+ .globl outstring
+
+ .globl _platform_copier_l
+ .globl _platform_copier_h
+
+ .area _HIGH
+
+;
+; Switch out this process for another task. All the optimisation
+; tricks have been done by switchout, so when we are called we
+; really need to switch.
+;
+_platform_switchout:
+ di
+ ld hl,#0
+ push hl ; stack a retcode of 0 (see fork)
+ push ix ; save registers
+ push iy
+ ld (U_DATA__U_SP), sp
+
+ ; Map the to
+ ld a,(U_DATA__U_PAGE2)
+ call map_page_low
+ ld hl,#U_DATA
+ ld de,#U_DATA_STASH-0x8000
+ ld bc,#U_DATA__TOTALSIZE
+ ldir
+ call map_kernel_low
+ ; switch the new process in
+ call _getproc
+ push hl
+ call _switchin
+ ; Should never be hit
+ call _platform_monitor
+
+_switchin:
+ di
+ pop bc ; return address (we never do)
+ pop de ; new process pointer
+
+ ld hl,#P_TAB__P_PAGE2_OFFSET
+ add hl,de
+ ld a,(hl) ; our high page
+
+ ; FIXME: add swap support
+
+ ld hl,(U_DATA__U_PTAB)
+ or a
+ sbc hl,de
+ jr z, skip_copyback
+
+ call map_page_low
+
+ ; We are going to write our stack directly under us. No calls for
+ ; a moment
+ exx
+ ld hl,#U_DATA_STASH
+ ld de,#U_DATA
+ ld bc,#U_DATA__TOTALSIZE
+ ldir
+ exx
+ ld sp, (U_DATA__U_SP)
+
+ ; Ok our stack is now valid
+
+ call map_kernel_low
+ ld hl, (U_DATA__U_PTAB)
+ or a
+ sbc hl,de
+ jr nz, switchin_failed ; invalid u_data
+
+skip_copyback:
+ ld sp, (U_DATA__U_SP)
+ ld ix, (U_DATA__U_PTAB)
+ ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+ ld a, P_TAB__P_PAGE_OFFSET(ix)
+ ld (U_DATA__U_PAGE),a
+ ld a, P_TAB__P_PAGE2_OFFSET(ix)
+ ld (U_DATA__U_PAGE2),a
+ ld hl,#0
+ ld (_runticks), hl
+ ; Recover IX and IY, return value
+ pop ix
+ pop iy
+ pop hl
+
+ ; if we pre-empted in an ISR IRQ's stay off, if not they get enabled
+ ld a, (U_DATA__U_ININTERRUPT)
+ or a
+ ret nz
+ ei
+ ret
+
+switchin_failed:
+ call outhl
+ ld hl, #bad_switch
+ call outstring
+ jp _platform_monitor
+
+fork_proc_ptr:
+ .dw 0
+
+bad_switch:
+ .asciz '!SWITCH'
+
+_dofork:
+ di
+ pop de
+ pop hl ; HL is the new process ptab pointer
+ push hl
+ push de
+
+ ld (fork_proc_ptr),hl
+
+ ld de,#P_TAB__P_PID_OFFSET
+ add hl,de
+ ld a,(hl)
+ inc hl
+ ld h,(hl)
+ ld l,a
+
+ ; Build a parent frame for switchin that has the child pid
+ ; on it
+ push hl
+ push ix
+ push iy
+
+ ld (U_DATA__U_SP), sp
+
+ ; Parent state built and in u_data
+
+ call copy_process
+
+ ; Low page is undefined at this point which is ok as we are
+ ; about to change it again
+
+ ; Now put the u_data into the stash for the parent, then we can
+ ; modify it for the child
+
+ ; Map parent
+ ld a,(U_DATA__U_PAGE)
+ call map_page_low
+ ; Copy udata
+ ld hl, #U_DATA
+ ld de, #U_DATA_STASH - 0x8000
+ ld bc, #U_DATA__TOTALSIZE
+ ldir
+ ; Kernel back
+ call map_kernel_low
+
+ pop bc ; discard stack frame we built
+ pop bc
+ pop bc
+
+ ; Back into the kernel to finish the process creation
+
+ ld hl,(fork_proc_ptr)
+ push hl
+ call _newproc
+ pop bc
+
+ ; Clear runticks, and return 0
+ ld hl,#0
+ ld (_runticks),hl
+ ret
+
+;
+; Process copying is tricky. We want to do a direct copy for speed
+; but that requires mapping both banks and means
+; 1. We can't put all of this routine in a common helper when we make one
+; 2. We need interrupts off for now
+; 3. We need a magic helper in the low page
+;
+; HL is the child ptab, udata is the parent
+;
+; The platform needs to provide a platform_copier method for each
+; bank that copies low to high of all process, stubs and user data
+; in that bank (basically a straight 32K copy)
+;
+; typically that would be
+;
+; ld a,(hl)
+; out (whatever),a
+; exx
+; ldir
+; exx
+; ld a,#kernel
+; out (whatever),a
+; ret
+;
+; There have to be two of these - one in high stubs one in low because
+; the high banks will both be mapped so the low one isn't available
+;
+copy_process:
+ ld de,#P_TAB__P_PAGE2_OFFSET
+ add hl,de
+ ld a,(U_DATA__U_PAGE)
+ call map_page_low
+ call setup_platform_copier
+ call _platform_copier_l
+ inc hl
+ inc hl
+ ld a,(U_DATA__U_PAGE2)
+ call map_page_low
+ call setup_platform_copier
+ call _platform_copier_h
+ ret
+
+setup_platform_copier:
+ exx
+ ld hl,#0
+ ld de,#0x8000
+ ld b,d
+ ld c,e
+ exx
+ ret
\ No newline at end of file