+++ /dev/null
-`A FUZIX target for ZX Spectrum +2A/+3`
-
-The +2A and +3 have the following choice of memory configurations on top of
-the standard 128K spectrum
-
-```
- 00 40 80 C0
-conf0 [0] [1] [2] [3]
-conf1 [4] [5] [6] [7]
-conf2 [4] [5] [6] [3]
-conf3 [4] [7] [6] [3]
-```
-
-We have an interesting limitation: unlike the 128K spectrum banks 4-7 are
-all contended (slower). In addition pointing I into those banks will crash
-the machine. Providing we keep RAM in the low 16K we can avoid IM2 however.
-
-That gives us a conventional low 0/1 and 4/5 for user space with the kernel
-using 3/6/7. Given the memory napping limits it actually probably makes
-more sense to eventually allow one 48K and one 32K mapping so most processes
-can run two at a time but one big one is allowed. That implies we get our
-chmem act together.
-
-We then map
-
-0/1/2/3 - user process 0: 48K, 16K common
-4/5/6/3 - user process 1: 32K, 16K common, 16K is kernel reserved
-4/7/6/3 - kernel: 48K minus screen, common 16K (some kernel in it)
- (conveniently the map 'BOOT' uses)
-
-As an aside this only works for the +2A/+3. The various clones even with
-lots of RAM clone the original 128K and add more pages of memory in the top
-16K bank. Some allow the low 16K to become RAM (eg for CP/M) but have
-4000-BFFF fixed.
-
-There are also various add in boards some of which can work on the +2A/+3
-that provide alternative RAM and ROM banks for the low 16K. We don't make
-use of them in this configuration althogh in future it would make sense to
-make the kernel mapping in such a case map DivMMC or similar RAM into the
-low 16K when in kernel mapping so the kernel becomes mmc/7/3 and we leave 6
-free to allow a pair of 48K processes.
+++ /dev/null
-;
-; Multiple app sizes and the fact the kernel and apps share the same banks
-; means we need to put this somewhere low
-;
- .module commonmem
- .area _COMMONDATA
-
- .include "../cpu-z80/std-commonmem.s"
+++ /dev/null
-/* Simple IDE interface */
-#define CONFIG_IDE
-#define IDE_REG_DATA 0xA3
-#define IDE_REG_ERROR 0xA7
-#define IDE_REG_FEATURES 0xA7
-#define IDE_REG_SEC_COUNT 0xAB
-#define IDE_REG_LBA_0 0xAF
-#define IDE_REG_LBA_1 0xB3
-#define IDE_REG_LBA_2 0xB7
-#define IDE_REG_LBA_3 0xBB
-#define IDE_REG_DEVHEAD 0xBB
-#define IDE_REG_STATUS 0xBF
-#define IDE_REG_COMMAND 0xBF
-
-/* 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
-/* Swap only : swap via IDE or banked low RAM or similar */
-#define CONFIG_SWAP_ONLY
-/* Banks as reported to user space */
-#define CONFIG_BANKS 1
-
-/* Keyboard contains not ascii symbols */
-#define CONFIG_UNIKEY
-
-/* Video terminal, not a serial tty */
-#define CONFIG_VT
-/* 8x8 font for the moment */
-#define CONFIG_FONT8X8
-/* Vt definitions */
-#define VT_WIDTH 32
-#define VT_HEIGHT 24
-#define VT_RIGHT 31
-#define VT_BOTTOM 23
-
-#define TICKSPERSEC 50 /* Ticks per second */
-#define PROGBASE 0x0000 /* also data base */
-#define PROGLOAD 0x0100 /* also data base */
-#define PROGTOP 0xF800 /* Top of program */
-#define PROC_SIZE 64 /* Memory needed per process */
-
-#define BOOT_TTY (513) /* 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 1
-
-#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
-
-#define SWAPDEV (swap_dev) /* Swap device (dynamic) */
-#define SWAP_SIZE 0x7C /* 64K minus the common in blocks */
-#define SWAPBASE 0x0000 /* We swap the lot in one, include the */
-#define SWAPTOP 0xF800 /* vectors so its a round number of sectors */
-#define MAX_SWAPS 64
-
-
-#define NBUFS 9 /* Number of block buffers */
-#define NMOUNTS 4 /* Number of mounts at a time */
-#define MAX_BLKDEV 2 /* 2 IDE drives, 1 SD drive */
-
-#define swap_map(x) ((uint8_t *)(x)) /* For now */
-
-#define platform_discard()
+++ /dev/null
- .module crt0
-
- .module crt0
-
- .area _CODE ; Code lives at 0000-0x3FFF in bank 4
- .area _CODE2 ; Lives at 0x5B00 onwards in bank 7/6
- .area _CODE3
- .area _CONST
- .area _VIDEO
- .area _FONT
- .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
- ;
- ; Above 0xC000 in the top of bank 3
- ;
- .area _COMMONMEM
- .area _COMMONDATA
-
- ; imported symbols
- .globl _fuzix_main
- .globl init_early
- .globl init_hardware
- .globl _sysconfig
- .globl s__INITIALIZER
- .globl s__DATA
- .globl l__DATA
- .globl s__FONT
- .globl l__FONT
- .globl s__DISCARD
- .globl l__DISCARD
- .globl s__COMMONMEM
- .globl l__COMMONMEM
-
- .globl kstack_top
-
- ; startup code
- .area _CODE
-
- .include "kernel.def"
-
-;
-; The bootloader has executed and now enters our code. HL points
-; to a table of properties extracted from the 3DOS and BASIC
-; environment. Do the memory shuffle and get going
-;
-init1:
- di
- ld sp, #kstack_top
- push hl
-
- ; Configure memory map
- call init_early
-
- ; move the common memory where it belongs
- ld hl, #s__DATA
- ld de, #s__COMMONMEM
- ld bc, #l__COMMONMEM
- ldir
- ; font
- ld de, #s__FONT
- ld bc, #l__FONT
- ldir
- ; and 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
-
- pop hl
- ld (_sysconfig), hl ; We keep this safe until we wiped data
-
- ; Hardware setup
- call init_hardware
-
- ; Call the C main routine
- call _fuzix_main
-
- ; main shouldn't return, but if it does...
- di
-stop: halt
- jr stop
-
-
- .area _DATA
-_sysconfig:
- .word 0
+++ /dev/null
-#include <kernel.h>
-#include <kdata.h>
-#include <printf.h>
-#include <devfd.h>
-#include <sysconfig.h>
-
-#define MAX_FD 2
-
-extern uint8_t fdc_user;
-extern uint16_t fdc_addr;
-extern uint8_t rwcmd[9];
-extern uint8_t seekcmd[3];
-
-extern void fdc_motoron(void);
-extern void fdc_motoroff(void);
-extern uint8_t fdc_read(void);
-extern uint8_t fdc_write(void);
-extern uint8_t fdc_recal(void);
-extern uint8_t fdc_seek(void);
-
-uint8_t track[MAX_FD] = { 0xFF, 0xFF };
-
-static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
-{
- blkno_t block;
- uint16_t dptr;
- int ct = 0;
- int tries;
- uint8_t err = 0;
- uint8_t nblock;
-
- if(rawflag == 2)
- goto bad2;
-
- if (rawflag == 0) {
- dptr = (uint16_t)udata.u_buf->bf_data;
- block = udata.u_buf->bf_blk;
- nblock = 1;
- } else {
- if (((uint16_t)udata.u_offset|udata.u_count) & BLKMASK)
- goto bad2;
- dptr = (uint16_t)udata.u_base;
- block = udata.u_offset >> 9;
- nblock = udata.u_count >> 9;
- }
-
- rwcmd[1] = 1 << minor;
- rwcmd[2] = block / 9;
- rwcmd[3] = 0; /* Single sided only for now */
- rwcmd[4] = 1 + block % 9; /* Sector */
- rwcmd[6] = rwcmd[4];
-
- fdc_user = rawflag;
-
- while (ct < nblock) {
- fdc_addr = dptr;
- if (track[minor] != rwcmd[2]) {
- seekcmd[1] = 1 << minor;
- seekcmd[2] = rwcmd[2];
- fdc_seek(); /* FIXME: error handling */
- }
- for (tries = 0; tries < 4 ; tries++) {
- /* FIXME: need to return status properly and mask it */
- if (is_read)
- err = fdc_read();
- else
- err = fdc_write();
- if (err == 0)
- break;
- }
- if (tries > 1) /* FIXME: set drive */
- fdc_recal();
- if (tries == 4)
- goto bad;
-
- dptr += 0x200; /* Move on 512 bytes in the buffer */
-
- rwcmd[4]++;
- /* Step a track */
- if (rwcmd[4] > 10) {
- rwcmd[4] = 1;
- rwcmd[2]++;
- }
- rwcmd[6] = rwcmd[4];
- ct++;
- }
- return 1;
-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;
- /* Check we have a floppy */
- if(!(sysconfig & CONF_PLUS3) || 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;
- 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 *driveptr);
-
-#endif /* __DEVFD_DOT_H__ */
+++ /dev/null
-#include <kernel.h>
-#include <version.h>
-#include <kdata.h>
-#include <tty.h>
-#include <devsys.h>
-#include <vt.h>
-#include <devfd.h>
-#include <devide.h>
-#include <blkdev.h>
-
-struct devsw dev_tab[] = /* The device driver switch table */
-{
- /* 0: /dev/fd Floppy disc block devices: disciple */
- { fd_open, no_close, fd_read, fd_write, no_ioctl },
-#ifdef CONFIG_IDE
- /* 1: /dev/hd Hard disc block devices */
- { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl },
-#else
- { no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
-#endif
- /* 2: /dev/tty TTY devices */
- { tty_open, tty_close, tty_read, tty_write, vt_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 }
-};
-
-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_IDE
- devide_init();
-#endif
-}
+++ /dev/null
-#include <kernel.h>
-#include <kdata.h>
-#include <printf.h>
-#include <stdbool.h>
-#include <devtty.h>
-#include <keycode.h>
-#include <vt.h>
-#include <tty.h>
-
-char tbuf1[TTYSIZ];
-
-uint8_t vtattr_cap;
-struct vt_repeat keyrepeat;
-static uint8_t kbd_timer;
-
-/* buffer for port scan procedure */
-uint8_t keybuf[8];
-/* Previous state */
-uint8_t keymap[8];
-
-static uint8_t keybyte, keybit;
-static uint8_t newkey;
-static int keysdown = 0;
-
-uint8_t keyboard[8][5] = {
- {' ', 0 , 'm', 'n', 'b'},
- {13 , 'l', 'k', 'j', 'h'},
- {'p', 'o', 'i', 'u', 'y'},
- {'0', '9', '8', '7', '6'},
- {'1', '2', '3', '4', '5'},
- {'q', 'w', 'e', 'r', 't'},
- {'a', 's', 'd', 'f', 'g'},
- {0 , 'z', 'x', 'c', 'v'}
-};
-
-/* SYMBOL SHIFT MODE */
-uint8_t shiftkeyboard[8][5] = {
- {' ', 0 , '.', ',', '*'},
- {13 , '=', '+', '-', '^'},
- {'"', ';', '@', ']', '['},
- {'_', ')', '(', '\'','&'},
- {'!', '@', '#', '$', '%'},
- {'`', 0 , 0 , '<', '>'},
- {'~' ,'|', '\\','{', '}'},
- {0 , ':', KEY_POUND , '?', '/'}
-};
-
-
-static uint8_t shiftmask[8] = { 0x02, 0, 0, 0, 0, 0, 0, 0x01 };
-
-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},
-};
-
-/* tty1 is the screen */
-
-/* Output for the system console (kprintf etc) */
-void kputchar(char c)
-{
- if (c == '\n')
- tty_putc(0, '\r');
- tty_putc(0, c);
-}
-
-/* Both console and debug port are always ready */
-ttyready_t tty_writeready(uint8_t minor)
-{
- minor;
- return TTY_READY_NOW;
-}
-
-void tty_putc(uint8_t minor, unsigned char c)
-{
- minor;
- vtoutput(&c, 1);
-}
-
-int tty_carrier(uint8_t minor)
-{
- minor;
- return 1;
-}
-
-void tty_setup(uint8_t minor)
-{
- minor;
-}
-
-void tty_sleeping(uint8_t minor)
-{
- minor;
-}
-
-void tty_data_consumed(uint8_t minor)
-{
-}
-
-void update_keyboard(void)
-{
- /* We need this assembler code because SDCC __sfr cannot handle 16-bit addresses. And because it is much faster, of course */
- /* TODO: make it naked? */
- __asm
- ld hl,#_keybuf
- ld c, #0xFE
- ld b, #0x7f
- ld e, #8 ; 8 keyboard ports, 7FFE, BFFE, DFFE and so on
- read_halfrow:
- in a, (c)
-; and #0
- cpl
- ld(hl), a
- rrc b
- inc hl
- dec e
- jr nz, read_halfrow
- __endasm;
-}
-
-void tty_pollirq(void)
-{
- int i;
-
- update_keyboard();
-
- newkey = 0;
-
- for (i = 0; i < 8; i++) {
- int n;
- uint8_t key = keybuf[i] ^ keymap[i];
- if (key) {
- uint8_t m = 0x10;
- for (n = 4; n >= 0; 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 >>= 1;
- }
- }
- keymap[i] = keybuf[i];
- }
- if (keysdown && keysdown < 3) {
- if (newkey) {
- keydecode();
- kbd_timer = keyrepeat.first;
- } else if (! --kbd_timer) {
- keydecode();
- kbd_timer = keyrepeat.continual;
- }
- }
-
-}
-
-static uint8_t cursor[4] = { KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT };
-
-static void keydecode(void)
-{
- uint8_t c;
-
- uint8_t ss = keymap[0] & 0x02; /* SYMBOL SHIFT */
- uint8_t cs = keymap[7] & 0x01; /* CAPS SHIFT */
-
- if (ss) {
- c = shiftkeyboard[keybyte][keybit];
- } else {
- c = keyboard[keybyte][keybit];
- if (cs) {
- if (c >= 'a' && c <= 'z')
- c -= 'a' - 'A';
- else if (c == '0') /* CS + 0 is backspace) */
- c = 0x08;
- else if (c == ' ')
- c = KEY_STOP; /* ^C map for BREAK */
- else if (c >= '5' && c <= '8')
- c = cursor[c - '5'];
- }
- }
- tty_inproc(1, c);
-}
-
-
-/* This is used by the vt asm code, but needs to live in the kernel */
-uint16_t cursorpos;
+++ /dev/null
-#ifndef __DEVTTY_DOT_H__
-#define __DEVTTY_DOT_H__
-
-void tty_pollirq(void);
-static void keydecode(void);
-
-#define KEY_ROWS 8
-#define KEY_COLS 5
-extern uint8_t keymap[8];
-extern uint8_t keyboard[8][5];
-extern uint8_t shiftkeyboard[8][5];
-
-#endif
+++ /dev/null
-;
-; ROM timings are used for the drives.
-;
-; 0x0A, motor on
-; 0x32, motor off
-; 0xAF, write off
-; 0x1E, head settle ms
-; 0x0C, step rate ms
-; 0x0F, head unload
-; 0x03, head load x 2 + 1
-;
-;
- .area _COMMONMEM
-
- .globl _fdc_motoron, _fdc_motoroff
- .globl _fdc_read, _fdc_write, _fdc_recal, _fdc_seek
- .globl _fdc_user, _fdc_addr
- .globl _fdc_statbuf
- .globl _seekcmd
- .globl _rwcmd
- .globl _recalcmd
- .globl port_map
- .globl map_kernel, map_process_always
-
-fdc_cmd:
- dec b
- jr z, fdclast
-fdc_cmdl:
- call fdc_outcmd
- inc hl
- ret c ; Error
- djnz fdc_cmdl
-fdclast:
- di
-fdc_outcmd:
- push bc
- ld bc, #0x2ffd
- ld e, (hl)
-fdc_outcmdw: ; Wait non busy
- in a, (c)
- add a, a
- jr c, fdc_outcmdw
- add a, a ; FIXME: can we use ret m or similar here ?
- ret c ; Failed
- ld b, #0x3F
- out (c), e ; Output the byte
- ex (sp), hl
- ex (sp), hl ; Nap
- pop bc
- ret ; NC
-
-fdc_cmdq: ; Quick (non data) command
- call fdc_outcmd
- djnz fdc_cmdq
- ret
-
-fdc_status:
- ld bc, #0x2ffd
- ld hl, #_fdc_statbuf
-fdc_statw:
- in a, (c)
- add a, a
- jr c, fdc_statw
- add a, a
- ret nc ; Finished copying block
- ld b, #0x3F
- ini
- ld b, #0x2F
- ex (sp), hl
- ex (sp), hl
- jr fdc_statw
-
-fdc_statusa:
- call fdc_status
- ld a, (_fdc_statbuf)
- ret
-
-fdc_read:
- ld hl, #_rwcmd
- ld (hl), #66
- ld b, #9
- call fdc_cmd ; Will return with DI
-fdc_readgo:
- ld bc, #0x2ffd
- ld d, #0x20
- jr fdc_rwait
-;
-; This would be faster using EXX. May be worth looking at depending
-; upon clock counts.
-;
-fdc_rbyte:
- ld b, #0x3F ; 3FFD
- ini
- ld b, #0x2f
-fdc_rwait: ; wait for ready
- in a, (c)
- jp p, fdc_rwait
- and d
- jp nz, fdc_rbyte
- ; now get status
- jr fdc_statusa
-
-fdc_write:
- ld hl, #_rwcmd
- ld (hl), #65
- ld b, #9
- call fdc_cmd ; Will return with DI
-fdc_writego:
- ld bc, #0x2ffd
- ld d, #0x20
- jr fdc_wwait
-fdc_wbyte:
- ld b, #0x40
- outi
- ld b, #0x2f
-fdc_wwait:
- in a, (c)
- jp p, fdc_wwait
- ; now read status
- jr fdc_statusa
-
-;
-; Seek is interesting as we have to second guess the delays
-;
-fdc_seek:
- ld (_seekcmd + 2), a ; Cylinder we want
-fdc_seek2:
- ld b, a
- ld b, #3
- call fdc_cmdq
- ld bc, (_seekcmd + 2)
- ld a, (curtrack) ; Current track FIXME
- sub c
- bit 7, a
- jr z, seekin
- neg
-seekin: ; milliseconds of time for the seek
- add a, a
- ld b, a
- add a, a
- add a, b
- add a, a ; 12ms step rate assumed
- add a, #0x1e ; head settle
- call msdelay
- ; We should now get a sense interrupt
- call fdc_sense
- ; Check if it worked
- bit 6, a
- jr nz, fdc_seekfail
- ld a, (_seekcmd + 2)
- ld (curtrack), a ; FIXME per drive
- ret ; Z
-fdc_seekfail:
- ld a, #0xFF
- ld (curtrack), a ; Mark as busted
- ret ; NZ
-
-fdc_recalibrate:
- ld hl, #_recalcmd
- ld b, #2 ; recalibrate, unit
- call fdc_cmdq
- ld a, #80 ; or 40 if 40 track !
- ld b, #12 ; 12ms
-fdc_recald:
- ld a, #80 ; or 40 if 40 track !
- call msdelay
- djnz fdc_recald
- ld a, #0x1e ; settle
- call msdelay
- call fdc_status
- bit 6, a
- jr nz, fdc_seekfail
- xor a
- ld (curtrack), a
- ret ; Z
-
-fdc_sense:
- ld hl, #sensecmd
- call fdc_outcmd
- call fdc_statusa
- bit 7, a
- jr nz, fdc_sense
- ld a, (_fdc_statbuf)
- ret
-
-fdc_cmdwait:
- call fdc_sense
- and #0xC0
- cp #0x80
- jr nz, fdc_cmdwait
- ret
-
-;fdc_getunit:
-; ld hl, #fdc_guscmd
-; ld b, #2
-; call fdc_cmdq
-; jr fdc_statusa
-
-;
-; Delay 'a' milliseconds. Trashes A, C.
-;
-msdelay: ; For uncontended RAM
- ld c, #0xDC
- dec c
- jr nz, msdelay
- dec a
- jr nz, msdelay
- ret
-
-
-;
-; Must be called with the motor timeout stopped
-;
-_fdc_motoron:
- ld a, (port_map)
- bit 3, a
- ret nz
- or #9
- ld (port_map), a
- ld bc, #0x1ffd
- out (c), a
-_fdc_mwait:
- ld bc, #0x3548
- dec bc
- ld a, b
- or c
- jr nz, _fdc_mwait
- ret
-
-_fdc_motoroff:
- ld a, (port_map)
- and #0xF7
- ld (port_map), a
- ld bc, #0x1ffd
- out (c), a
- ret
-
-_fdc_read:
- ld hl, (_fdc_addr)
- ld a, (_fdc_user)
- or a
- push af
- call nz, map_process_always
- call fdc_read
- pop af
- call nz, map_kernel
- ret
-
-_fdc_write:
- ld hl, (_fdc_addr)
- ld a, (_fdc_user)
- or a
- push af
- call nz, map_process_always
- call fdc_write
- pop af
- call nz, map_kernel
- ret
-
-_fdc_recal:
- call fdc_recalibrate
- ld l, a
- ret
-
-_fdc_seek:
- call fdc_seek2
- ret
-
- .area _COMMONDATA
-
-curtrack:
- .byte 0 ; FIXME
-
-_rwcmd:
- .byte 0x66 ; MFM read / 0x65 for write
- .byte 0 ; Drive 0, head 0 (for now)
- .byte 0 ; Track
- .byte 0 ; Head
- .byte 0 ; Sector
- .byte 2 ; 512 byte blocks
- .byte 0 ; Last sector (== sector)
- .byte 0x2A ; Gap length
- .byte 0xFF
-
-sensecmd:
- .byte 0x08
-
-_seekcmd:
- .byte 0x0F
- .byte 0x00
- .byte 0x00 ; Cylinder
-
-_recalcmd:
- .byte 0x07
- .byte 0
-
-_fdc_user:
- .byte 0x00
-_fdc_addr:
- .word 0x0000
-_fdc_statbuf:
- .word 0,0,0,0
+++ /dev/null
--mwxuy
--i fuzix.ihx
--b _COMMONDATA=0xF800
--b _COMMONMEM=0xF000
--b _CODE=0x0100
--b _CODE2=0x5B00
--b _DISCARD=0xE400
--l z80
-platform-plus3/crt0.rel
-platform-plus3/commonmem.rel
-platform-plus3/plus3.rel
-platform-plus3/zxvideo.rel
-platform-plus3/main.rel
-start.rel
-version.rel
-lowlevel-z80.rel
-usermem_std-z80.rel
-platform-plus3/tricks.rel
-timer.rel
-kdata.rel
-usermem.rel
-platform-plus3/devices.rel
-platform-plus3/devfd.rel
-platform-plus3/floppy.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
-vt.rel
-font8x8.rel
-mm.rel
-simple.rel
-swap.rel
-devsys.rel
-platform-plus3/devtty.rel
-platform-plus3/devide.rel
-platform-plus3/devide_discard.rel
-platform-plus3/mbr.rel
-platform-plus3/blkdev.rel
--e
+++ /dev/null
-; UZI mnemonics for memory addresses etc
-
-U_DATA .equ 0xF800 ; (this is struct u_data from kernel.h)
-U_DATA__TOTALSIZE .equ 0x300 ; 256+256+256 bytes.
-
-Z80_TYPE .equ 1
-
-PROGBASE .equ 0x0000
-PROGLOAD .equ 0x0100
-
-Z80_MMU_HOOKS .equ 0
+++ /dev/null
-#include <kernel.h>
-#include <timer.h>
-#include <kdata.h>
-#include <printf.h>
-#include <devtty.h>
-
-uint16_t ramtop = PROGTOP;
-uint16_t swap_dev;
-
-void platform_idle(void)
-{
- __asm
- halt
- __endasm;
-}
-
-void platform_interrupt(void)
-{
- tty_pollirq();
-//FIXME floppy_timer();
- 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
-/* Simple IDE interface */
-#define IDE_REG_DATA 0xA3
-#define IDE_REG_ERROR 0xA7
-#define IDE_REG_FEATURES 0xA7
-#define IDE_REG_SEC_COUNT 0xAB
-#define IDE_REG_LBA_0 0xAF
-#define IDE_REG_LBA_1 0xB3
-#define IDE_REG_LBA_2 0xB7
-#define IDE_REG_LBA_3 0xBB
-#define IDE_REG_DEVHEAD 0xBB
-#define IDE_REG_STATUS 0xBF
-#define IDE_REG_COMMAND 0xBF
-
-#define ide_select(x)
-#define ide_deselect()
+++ /dev/null
-;
-; ZX Spectrum Plus 2A and Plus 3 hardware support
-;
-
-;
-; For the moment we just have a single user bank and simple swap. Once
-; we have things running that will be changed and will need the map
-; handlers here to be adjusted
-;
-
- .module plus3
-
- ; exported symbols
- .globl init_early
- .globl init_hardware
- .globl _program_vectors
- .globl platform_interrupt_all
- .globl interrupt_handler
- .globl unix_syscall_entry
- .globl null_handler
- .globl nmi_handler
-
- .globl map_kernel
- .globl map_process
- .globl map_process_always
- .globl map_save
- .globl map_restore
- .globl map_process_save
- .globl map_kernel_restore
- .globl map_for_swap
-
- .globl _need_resched
- .globl _kernel_flag
- .globl port_map
-
- ; exported debugging tools
- .globl _platform_monitor
- .globl _platform_reboot
- .globl outchar
-
- ; imported symbols
- .globl _ramsize
- .globl _procmem
-
- .globl outcharhex
- .globl outhl, outde, outbc
- .globl outnewline
- .globl outstring
- .globl outstringhex
-
- .include "kernel.def"
- .include "../kernel.def"
-
-; -----------------------------------------------------------------------------
-; COMMON MEMORY BANK (above 0xC000 in page 3)
-; -----------------------------------------------------------------------------
- .area _COMMONMEM
-
-_platform_monitor:
- ;
- ; Not so much a monitor as wait for space
- ;
- ld a, #0x7F
- in a, (0xFE)
- rra
- jr c, _platform_monitor
-
-_platform_reboot:
- di
- im 1
- ld bc, #0x7ffd
- xor a ; 128K ROM, initial banks, low screen
- out (c), a
- rst 0 ; Into the ROM
-
-platform_interrupt_all:
- ret
-
-; -----------------------------------------------------------------------------
-; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped)
-; -----------------------------------------------------------------------------
- .area _CODE
-
-init_early:
- ld bc, #0x7ffd
- ld a, #3 + 8 ; Screen into page 7
- ret
-
- .area _VIDEO
-
-init_hardware:
- ; set system RAM size
- ld hl, #128
- ld (_ramsize), hl
- ld hl, #(128 - 64) ; 64K for kernel/screen/etc
- ld (_procmem), hl
-
- ; screen initialization
- ; clear
- ld hl, #0x4000
- ld de, #0x4001
- ld bc, #0x1800 ; There should be 0x17FF, but we are going
- xor a ; to copy additional byte to avoid need of
- ld (hl), a ; DE and HL increment before attribute
- ldir ; initialization (2 bytes of RAM economy)
-
- ; set color attributes
- ld a, #7 ; black paper, white ink
- ld bc, #0x300 - #1
- ld (hl), a
- ldir
-
- ret
-
-;------------------------------------------------------------------------------
-; COMMON MEMORY PROCEDURES FOLLOW
-
- .area _COMMONMEM
-
-_program_vectors:
- di
- pop de
- pop hl
- push hl
- push de
-
- call map_process
-
- ; write zeroes across all vectors
- ld hl, #0
- ld de, #1
- ld bc, #0x007f ; program first 0x80 bytes only
- ld (hl), #0x00
- ldir
-
- ; now install the interrupt vector at 0x0038
- ld a, #0xC3 ; JP instruction
- ld (0x0038), a
- ld hl, #interrupt_handler
- ld (0x0039), hl
-
- ; set restart vector for UZI system calls
- ld (0x0030), a ; (rst 30h is unix function call vector)
- ld hl, #unix_syscall_entry
- ld (0x0031), hl
-
- ; Set vector for jump to NULL
- ld (0x0000), a
- ld hl, #null_handler ; to Our Trap Handler
- ld (0x0001), hl
-
- ld (0x0066), a ; Set vector for NMI
- ld hl, #nmi_handler
- ld (0x0067), hl
- jr map_kernel
-
-switch_kernel:
- ld a, (port_map)
- or #0x07 ; Map 4,7,6,3
-switchit:
- push bc
- ld (port_map), a
- ld bc, #0x1FFD
- out (c), a
- pop bc
- ret
-
-switch_user:
- ld a, (port_map)
- and #0xF8 ; Preserve the other bits
- and #0x01 ; Map 0,1,2,3
- or #0x04
- jr switchit
-
-map_process:
- ld a, h
- or l
- jr z, map_kernel
-map_process_save:
-map_process_always:
- push af
- call switch_user
- pop af
- ret
-
-map_kernel:
-map_kernel_restore:
- push af
- call switch_kernel
- pop af
- ret
-
-map_save:
- push af
- ld a, (port_map)
- and #7
- ld (map_store), a
- pop af
- ret
-
-map_restore:
- push af
- push hl
- ld a, (port_map)
- and #0xF8
- ld hl, #map_store
- or (hl)
- call switchit
- pop hl
- pop af
- ret
-
-;
-; a is 1 for the first bank 2 for the second. Switch to that process
-; bank
-;
-map_for_swap:
- jp switch_user
-
-;
-; We have no easy serial debug output instead just breakpoint this
-; address when debugging.
-;
-outchar:
- ret
-
- .area _COMMONDATA
-_kernel_flag:
- .db 1
-_need_resched:
- .db 0
-port_map: ; place to store current map register values
- .db 0 ; because we have no ability to read 1ffd port
- ; to detect what page is mapped currently
-map_store:
- .db 0
-ksave_map:
- .db 0
+++ /dev/null
-#
-# ZXSpectrum +3 uses unbanked kernel images (for now anyway)
-#
+++ /dev/null
-#ifndef _SYSCONFIG_H
-#define _SYSCONFIG_H
-
-extern uint16_t sysconfig;
-
-#define CONF_PLUS3 0x0001 /* Plus3 (has 3DOS) */
-
-#endif
\ No newline at end of file
+++ /dev/null
-export CPU = z80
+++ /dev/null
- .module tricks
-
-;
-; Standardised implementation of tricks.s for pure swapping Z80
-; systems. Wants moving from here to lib/
-;
-; FIXME: All of this can be moved into CODE ?
-;
- .globl _ptab_alloc
- .globl _newproc
- .globl _chksigs
- .globl _getproc
- .globl _platform_monitor
- .globl trap_illegal
- .globl _inint
- .globl _platform_switchout
- .globl _switchin
- .globl _doexec
- .globl _dofork
- .globl _runticks
- .globl unix_syscall_entry
- .globl interrupt_handler
- .globl _swapper
- .globl _swapout
-
- ; imported debug symbols
- .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
-
- .include "kernel.def"
- .include "../kernel.def"
-
- .area _COMMONMEM
-
-; Switchout switches out the current process, finds another that is READY,
-; possibly the same process, and switches it in. When a process is
-; restarted after calling switchout, it thinks it has just returned
-; from switchout().
-_platform_switchout:
- di
- ; save machine state
-
- ld hl, #0 ; return code set here is ignored, but _switchin can
- ; return from either _switchout OR _dofork, so they must both write
- ; U_DATA__U_SP with the following on the stack:
- push hl ; return code
- push ix
- push iy
- ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
-
- ; set inint to false
- xor a
- ld (_inint), a
-
- ; find another process to run (may select this one again)
- call _getproc
-
- push hl
- call _switchin
-
- ; we should never get here
- call _platform_monitor
-
-badswitchmsg: .ascii "_switchin: FAIL"
- .db 13, 10, 0
-swapped: .ascii "_switchin: SWAPPED"
- .db 13, 10, 0
-
-_switchin:
- di
- pop bc ; return address
- pop de ; new process pointer
-;
-; FIXME: do we actually *need* to restore the stack !
-;
- push de ; restore stack
- push bc ; restore stack
-
- push de
- ld hl, #P_TAB__P_PAGE_OFFSET
- add hl, de ; process ptr
- pop de
-
- ld a, (hl)
-
- or a
- jr nz, not_swapped
-
- ;
- ; We are still on the departing processes stack, which is
- ; fine for now.
- ;
- ld sp, #_swapstack
- push hl
- ; We will always swap out the current process
- ld hl, (U_DATA__U_PTAB)
- push hl
- call _swapout
- pop hl
- pop hl
- push de
- call _swapper
- pop de
- pop hl
- ld a, (hl)
-
-not_swapped:
- ; check u_data->u_ptab matches what we wanted
- ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
- or a ; clear carry flag
- sbc hl, de ; subtract, result will be zero if DE==IX
- jr nz, switchinfail
-
- ; wants optimising up a bit
- ld ix, (U_DATA__U_PTAB)
- ; next_process->p_status = P_RUNNING
- ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
-
- ; Fix the moved page pointers
- ; Just do one byte as that is all we use on this platform
- ld a, P_TAB__P_PAGE_OFFSET(ix)
- ld (U_DATA__U_PAGE), a
- ; runticks = 0
- ld hl, #0
- ld (_runticks), hl
-
- ; restore machine state -- note we may be returning from either
- ; _switchout or _dofork
- ld sp, (U_DATA__U_SP)
-
- pop iy
- pop ix
- pop hl ; return code
-
- ; enable interrupts, if the ISR isn't already running
- ld a, (_inint)
- or a
- ret z ; in ISR, leave interrupts off
- ei
- ret ; return with interrupts on
-
-switchinfail:
- call outhl
- ld hl, #badswitchmsg
- call outstring
- ; something went wrong and we didn't switch in what we asked for
- jp _platform_monitor
-
-fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
-
-;
-; Called from _fork. We are in a syscall, the uarea is live as the
-; parent uarea. The kernel is the mapped object.
-;
-_dofork:
- ; always disconnect the vehicle battery before performing maintenance
- di ; should already be the case ... belt and braces.
-
- pop de ; return address
- pop hl ; new process p_tab*
- push hl
- push de
-
- ld (fork_proc_ptr), hl
-
- ; prepare return value in parent process -- HL = p->p_pid;
- ld de, #P_TAB__P_PID_OFFSET
- add hl, de
- ld a, (hl)
- inc hl
- ld h, (hl)
- ld l, a
-
- ; Save the stack pointer and critical registers.
- ; When this process (the parent) is switched back in, it will be as if
- ; it returns with the value of the child's pid.
- push hl ; HL still has p->p_pid from above, the return value in the parent
- push ix
- push iy
-
- ; save kernel stack pointer -- when it comes back in the parent we'll be in
- ; _switchin which will immediately return (appearing to be _dofork()
- ; returning) and with HL (ie return code) containing the child PID.
- ; Hurray.
- ld (U_DATA__U_SP), sp
-
- ; now we're in a safe state for _switchin to return in the parent
- ; process.
-
- ld hl, (U_DATA__U_PTAB)
- push hl
- call _swapout
- pop hl
-
- ; now the copy operation is complete we can get rid of the stuff
- ; _switchin will be expecting from our copy of the stack.
- pop bc
- pop bc
- pop bc
-
- ; Make a new process table entry, etc.
- ld hl, (fork_proc_ptr)
- push hl
- call _newproc
- pop bc
-
- ; runticks = 0;
- ld hl, #0
- ld (_runticks), hl
- ; in the child process, fork() returns zero.
- ;
- ; And we exit, with the kernel mapped, the child now being deemed
- ; to be the live uarea. The parent is frozen in time and space as
- ; if it had done a switchout().
- ret
-;
-; We can keep a stack in common because we will complete our
-; use of it before we switch common block. In this case we have
-; a true common so it's even easier.
-;
- .ds 128
-_swapstack:
+++ /dev/null
-;
-; zx128 vt primitives
-;
-; We load this high on the Plus3 so we can page in page 7 for the
-; video overlay and frame buffer space. Any font will also go in page
-; 7. These routines must not call any code outside of common and their
-; own bank.
-;
-
- .module zxvideo
-
- ; exported symbols
- .globl _plot_char
- .globl _scroll_down
- .globl _scroll_up
- .globl _cursor_on
- .globl _cursor_off
- .globl _clear_lines
- .globl _clear_across
- .globl _do_beep
- .globl _vtattr_notify
-
- .area _VIDEO
-
- ; colors are ignored everywhere for now
-
-videopos:
- ld a,e
- and #7
- rrca
- rrca
- rrca
- add a,d
- ld d,e
- ld e,a
- ld a,d
- and #0x18
- or #0x40 ; page 7 is mapped here
- ld d,a
- ret
-
-_plot_char:
- pop iy
- pop hl
- pop de ; D = x E = y
- pop bc
- push bc
- push de
- push hl
- push iy
-
- call videopos
-
- ;
- ; TODO: Map char 0x60 to a grave accent bitmap rather
- ; than fudging with a quote
- ;
-
- ld b, #0 ; calculating offset in font table
- ld a, c
- cp #0x60
- jr nz, nofiddle
- ld a, #0x27
-nofiddle:
- or a ; clear carry
- rla
- rl b
- rla
- rl b
- rla
- rl b
- ld c, a
-
- ; FIXME: Can't do this any more!
- ld hl, #0x3C00 ; ROM font
- add hl, bc ; hl points to first byte of char data
-
-
- ; printing
- ld c, #8
-plot_char_loop:
- ld a, (hl)
- ld (de), a
- inc hl ; next byte of char data
- inc d ; next screen line
- dec c
- jr nz, plot_char_loop
- ret
-
-
-_clear_lines:
- pop bc
- pop hl
- pop de ; E = line, D = count
- push de
- push hl
- push bc
-
-clear_next_line:
- push de
- ld d, #0 ; from the column #0
- ld b, d ; b = 0
- ld c, #32 ; clear 32 cols
- push bc
- push de
- call _clear_across
-
- pop hl ; clear stack
- pop hl
-
- pop de
- inc e
- dec d
- jr nz, clear_next_line
-
- ret
-
-
-_clear_across:
- pop iy
- pop hl
- pop de ; DE = coords
- pop bc ; C = count
- push bc
- push de
- push hl
- push iy
- call videopos ; first pixel line of first character in DE
- push de
- pop hl ; copy to hl
- xor a
-
- ; no boundary checks. Assuming that D + C < SCREEN_WIDTH
-
-clear_line:
- ld b, #8 ; 8 pixel lines to clear for this char
-clear_char:
- ld (de), a
- inc d
- dec b
- jr nz, clear_char
-
- ex de, hl
- inc de
- push de
- pop hl
-
- dec c
- jr nz, clear_line
- ret
-
-copy_line:
- ; HL - source, DE - destination
-
- ; convert line coordinates to screen coordinates both for DE and HL
- push de
- ex de, hl
- call videopos
- ex de, hl
- pop de
- call videopos
-
- ld c, #8
-
-copy_line_nextchar:
- push hl
- push de
-
- ld b, #32
-
-copy_pixel_line:
- ld a, (hl)
- ld (de), a
- inc e
- inc l
- dec b
- jr nz, copy_pixel_line
-
- pop de
- pop hl
- inc d
- inc h
- dec c
- jr nz, copy_line_nextchar
- ret
-
- ; TODO: the LDIR way should be much faster
-
-_scroll_down:
- ; set HL = (0,22), DE = (0, 23)
- xor a
- ld d, a
- ld h, a
- ld l, #22
- ld e, #23
- ld c, #23 ; 23 lines to move
-
-loop_scroll_down:
- push hl
- push de
- push bc
-
- call copy_line
-
- pop bc
- pop de
- pop hl
-
- dec l
- dec e
- dec c
- jr nz, loop_scroll_down
-
- ret
-
-
-_scroll_up:
- ; set HL = (0,1), DE = (0, 0)
- xor a
- ld d, a
- ld e, a
- ld h, a
- ld l, #1
- ld c, #23 ; 23 lines to move
-
-loop_scroll_up:
- push hl
- push de
- push bc
-
- call copy_line
-
- pop bc
- pop de
- pop hl
-
- inc l
- inc e
- dec c
- jr nz, loop_scroll_up
-
- ret
-
-_cursor_on:
- pop bc
- pop hl
- pop de
- push de
- push hl
- push bc
- ld (cursorpos), de
-
- call videopos
- ld a, #7
- add a, d
- ld d, a
- ld a, #0xFF
- ld (de), a
- ret
-_cursor_off:
- ld de, (cursorpos)
- call videopos
- ld a, #7
- add a, d
- ld d, a
- xor a
- ld (de), a
-_vtattr_notify:
- ret
-
- ; FIXME: now this is_do_silent_click actually
-_do_beep:
- ld e, #0xFF ; length
- ld c, #0xFE ; beeper port
- ld l, #0x10 ; beeper bit
-loop_beep:
- ld a, l
- out (c), a
- xor a
- out (c), a
- dec bc
- ld a, b
- or c
- jr nz, loop_beep
- ret
-
-;
-; Must live in video or common so we are sure we can get at it with
-; page 7 mapped
-;
-cursorpos:
- .dw 0