diff --git a/Kernel/platform/platform-sbc2g/Makefile b/Kernel/platform/platform-sbc2g/Makefile index a6d378c167..c82cfbe535 100644 --- a/Kernel/platform/platform-sbc2g/Makefile +++ b/Kernel/platform/platform-sbc2g/Makefile @@ -6,8 +6,8 @@ CSRCS += devices.c main.c DISCSRCS = discard.c -ASRCS = sbc2g.s crt0.s -ASRCS += tricks.s commonmem.s +ASRCS = sbc2g.S crt0.S +ASRCS += tricks.S commonmem.S ide.S DISCARD_DSRCS = ../../dev/tinydisk_discard.c ../../dev/tinyide_discard.c DSRCS = ../../dev/tinydisk.c ../../dev/tinyide.c @@ -15,49 +15,65 @@ NSRCS = DASRCS = -COBJS = $(CSRCS:.c=.rel) -AOBJS = $(ASRCS:.s=.rel) -NOBJS = $(patsubst ../../dev/net/%.c,%.rel, $(NSRCS)) -DISCOBJS = $(DISCSRCS:.c=.rel) -DISCARD_DOBJS = $(patsubst ../../dev/%.c,%.rel, $(DISCARD_DSRCS)) -DOBJS = $(patsubst ../../dev/%.c,%.rel, $(DSRCS)) -DAOBJS = $(patsubst ../../dev/%.s,%.rel, $(DASRCS)) +COBJS = $(CSRCS:.c=.o) +AOBJS = $(ASRCS:.S=.o) +NOBJS = $(patsubst ../../dev/net/%.c,%.o, $(NSRCS)) +DISCOBJS = $(DISCSRCS:.c=.o) +DISCARD_DOBJS = $(patsubst ../../dev/%.c,%.o, $(DISCARD_DSRCS)) +DOBJS = $(patsubst ../../dev/%.c,%.o, $(DSRCS)) +DAOBJS = $(patsubst ../../dev/%.S,%.o, $(DASRCS)) OBJS = $(COBJS) $(AOBJS) $(NOBJS) $(DISCOBJS) $(DOBJS) $(DISCARD_DOBJS) $(DAOBJS) -JUNK = *.lst *.asm *.sym *.rst *.lst *.ihx *.tmp *.rel +JUNK = *.tmp *.o all: $(OBJS) -$(COBJS): %.rel: %.c +$(COBJS): %.o: %.c $(CROSS_CC) $(CROSS_CCOPTS) -c $< -$(DISCOBJS): %.rel: %.c +$(DISCOBJS): %.o: %.c $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< -$(DOBJS): %.rel: ../../dev/%.c +$(DOBJS): %.o: ../../dev/%.c $(CROSS_CC) $(CROSS_CCOPTS) -c $< -$(DISCARD_DOBJS): %.rel: ../../dev/%.c +$(DISCARD_DOBJS): %.o: ../../dev/%.c $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< -$(NOBJS): %.rel: ../../dev/net/%.c +$(NOBJS): %.o: ../../dev/net/%.c $(CROSS_CC) $(CROSS_CCOPTS) -c $< -$(AOBJS): %.rel: %.s +$(AOBJS): %.o: %.S $(CROSS_AS) $(ASOPTS) $< -$(DAOBJS): %.rel: ../../dev/%.s +$(DAOBJS): %.o: ../../dev/%.S $(CROSS_AS) $(ASOPTS) $@ $< clean: rm -f $(JUNK) core *~ loader.bin image: loader.bin - -loader.bin: loader.s - sdasz80 -o loader.s - sdldz80 -i loader.rel + $(CROSS_LD) -b -C 0x0100 -S 0xF600 -f CLDBbXSs -o fuzix.bin \ + crt0.o commonmem.o sbc2g.o ../../start.o \ + ../../version.o ../../cpu-z80u/lowlevel-z80u.o \ + ../../usermem.o tricks.o main.o discard.o \ + ../../timer.o ../../kdata.o devices.o ../../devio.o \ + ../../filesys.o ../../blk512.o ../../process.o \ + ../../inode.o ../../syscall_exec.o ../../syscall_exec16.o \ + ../../syscall_fs.o ../../syscall_fs2.o ../../syscall_fs3.o \ + ../../syscall_proc.o ../../syscall_other.o ../../syscall_net.o \ + ../../network.o ../../tty.o ../../mm.o ../../mm/memalloc_none.o \ + ../../swap.o ../../mm/bankfixed.o ../../devsys.o \ + devtty.o ../../dev/tinydisk.o ../../dev/tinydisk_discard.o \ + ../../dev/tinyide.o ../../dev/tinyide_discard.o ide.o \ + /opt/ccz80/lib/libz80.a -m fuzix.tmpmap + perl -lpe '$$_=hex' fuzix.tmpmap | paste -d" " - fuzix.tmpmap | sort -n | cut -d" " -f 2- >../../fuzix.map + ../../tools/pack85 <../../fuzix.map fuzix.bin ../../fuzix.bin + +loader.bin: loader.S + asz80 loader.S + ldz80 -b loader.o -o loader.tmp makebin -s 65536 loader.ihx loader.tmp dd if=loader.tmp bs=256 skip=192 of=loader.bin diff --git a/Kernel/platform/platform-sbc2g/commonmem.S b/Kernel/platform/platform-sbc2g/commonmem.S new file mode 100644 index 0000000000..184e6d8e3e --- /dev/null +++ b/Kernel/platform/platform-sbc2g/commonmem.S @@ -0,0 +1,9 @@ +; +; The common memory area traditionally starts with the udata and the +; interrupt stacks. As this is standard in almost all cases you can +; just include the standard implementation. +; + .common + +#include "../../cpu-z80u/std-commonmem.S" + diff --git a/Kernel/platform/platform-sbc2g/commonmem.s b/Kernel/platform/platform-sbc2g/commonmem.s index 67d41c5007..e8fc35de68 100644 --- a/Kernel/platform/platform-sbc2g/commonmem.s +++ b/Kernel/platform/platform-sbc2g/commonmem.s @@ -1,11 +1,60 @@ +# 0 "commonmem.S" +# 0 "" +# 0 "" +# 1 "commonmem.S" ; -; The common memory area traditionally starts with the udata and the -; interrupt stacks. As this is standard in almost all cases you can -; just include the standard implementation. +; The common memory area traditionally starts with the udata and the +; interrupt stacks. As this is standard in almost all cases you can +; just include the standard implementation. ; - .module commonmem + .common + +# 1 "../../cpu-z80u/std-commonmem.S" 1 +; +; +; Standard Z80 common memory area blocks. +; +; Must remain a multiple of 256 bytes +; + ; exported symbols + .export _ub + .export _udata + .export kstack_top + .export istack_top + .export istack_switched_sp - .area _COMMONMEM - .include "../../cpu-z80/std-commonmem.s" +_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above +_udata: +kstack_base: + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +kstack_top: + ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer +istack_base: + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +istack_top: +istack_switched_sp: .word 0 +# 9 "commonmem.S" 2 diff --git a/Kernel/platform/platform-sbc2g/config.h b/Kernel/platform/platform-sbc2g/config.h index 2a9bc6f012..aed447c37c 100644 --- a/Kernel/platform/platform-sbc2g/config.h +++ b/Kernel/platform/platform-sbc2g/config.h @@ -48,7 +48,7 @@ extern uint16_t swap_dev; #define CONFIG_TD #define CONFIG_TD_NUM 2 #define CONFIG_TD_IDE -#define CONFIG_TINYIDE_SDCCPIO +#define CONFIG_TINYIDE_INDIRECT #define CONFIG_TINYIDE_8BIT #define IDE_IS_8BIT(x) 1 diff --git a/Kernel/platform/platform-sbc2g/crt0.S b/Kernel/platform/platform-sbc2g/crt0.S new file mode 100644 index 0000000000..e78dc937e0 --- /dev/null +++ b/Kernel/platform/platform-sbc2g/crt0.S @@ -0,0 +1,40 @@ + ; startup code + .code + + ; Load at 0x0100 + ; We are executed from ROMWBW so we live in bank 14/15 + ; with the HBIOS proxy at FE00 +start: + di + ld sp, kstack_top + ; move the common memory where it belongs + ld hl, __bss + ld de, __common + ld bc, __common_size + ldir + ld de, __commondata + ld bc, __commondata_size + ldir + ; then the discard + ; Discard can just be linked in but is next to the buffers + ld de, __discard + ld bc, __discard_size + ldir + ; then zero the data area + ld hl, __bss + ld de, __bss + 1 + ld bc, __bss_size - 1 + ld (hl), 0 + ldir +; Zero buffers area + ld hl, __buffers + ld de, __buffers + 1 + ld bc, __buffers_size - 1 + ld (hl), 0 + ldir + call init_early + call init_hardware + call _fuzix_main + di +stop: halt + jr stop diff --git a/Kernel/platform/platform-sbc2g/crt0.s b/Kernel/platform/platform-sbc2g/crt0.s index f177ef2b39..46eb581929 100644 --- a/Kernel/platform/platform-sbc2g/crt0.s +++ b/Kernel/platform/platform-sbc2g/crt0.s @@ -1,76 +1,44 @@ - ; Ordering of segments for the linker. - .area _CODE - .area _CODE2 - .area _HOME - .area _CONST - .area _INITIALIZED - .area _DATA - .area _BSEG - .area _BSS - .area _HEAP - .area _GSINIT - .area _GSFINAL - .area _BUFFERS - .area _INITIALIZER - .area _DISCARD - .area _COMMONMEM - .area _COMMONDATA +# 0 "crt0.S" +# 0 "" +# 0 "" +# 1 "crt0.S" + ; startup code + .code - ; 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__BUFFERS - .globl l__BUFFERS - .globl s__COMMONMEM - .globl l__COMMONMEM - .globl s__COMMONDATA - .globl l__COMMONDATA - .globl s__INITIALIZER - .globl kstack_top - .globl map_kernel - - ; startup code - .area _CODE - - ; Load at 0x0100 - ; We are executed from ROMWBW so we live in bank 14/15 - ; with the HBIOS proxy at FE00 + ; Load at 0x0100 + ; We are executed from ROMWBW so we live in bank 14/15 + ; with the HBIOS proxy at FE00 start: - di - ld sp, #kstack_top - ; move the common memory where it belongs - ld hl, #s__DATA - ld de, #s__COMMONMEM - ld bc, #l__COMMONMEM - ldir - ld de, #s__COMMONDATA - ld bc, #l__COMMONDATA - ldir - ; then the discard - ; Discard can just be linked in but is next to the buffers - 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 -; Zero buffers area - ld hl, #s__BUFFERS - ld de, #s__BUFFERS + 1 - ld bc, #l__BUFFERS - 1 - ld (hl), #0 - ldir - call init_early - call init_hardware - call _fuzix_main - di -stop: halt - jr stop + di + ld sp, kstack_top + ; move the common memory where it belongs + ld hl, __bss + ld de, __common + ld bc, __common_size + ldir + ld de, __commondata + ld bc, __commondata_size + ldir + ; then the discard + ; Discard can just be linked in but is next to the buffers + ld de, __discard + ld bc, __discard_size + ldir + ; then zero the data area + ld hl, __bss + ld de, __bss + 1 + ld bc, __bss_size - 1 + ld (hl), 0 + ldir +; Zero buffers area + ld hl, __buffers + ld de, __buffers + 1 + ld bc, __buffers_size - 1 + ld (hl), 0 + ldir + call init_early + call init_hardware + call _fuzix_main + di +stop: halt + jr stop diff --git a/Kernel/platform/platform-sbc2g/devtty.c b/Kernel/platform/platform-sbc2g/devtty.c index 6725774549..01592d08d2 100644 --- a/Kernel/platform/platform-sbc2g/devtty.c +++ b/Kernel/platform/platform-sbc2g/devtty.c @@ -85,24 +85,24 @@ void tty_poll(void) uint8_t progress; /* Check for an interrupt */ - SIOA_C = 0; - if (!(SIOA_C & 2)) + out(SIOA_C, 0); + if (!(in(SIOA_C) & 2)) return; do { progress = 0; - SIOA_C = 0; // read register 0 - ca = SIOA_C; + out(SIOA_C, 0); // read register 0 + ca = in(SIOA_C); /* Input pending */ if (ca & 1) { progress = 1; - tty_inproc(1, SIOA_D); + tty_inproc(1, in(SIOA_D)); } /* Output pending */ if ((ca & 4) && (sleeping & 2)) { tty_outproc(2); sleeping &= ~2; - SIOA_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending + out(SIOA_C, 5 << 3); // reg 0 CMD 5 - reset transmit interrupt pending } /* Carrier changed on A: this is a timer interrupt from the external square wave generator */ @@ -111,22 +111,22 @@ void tty_poll(void) timer_tick(); } /* ACK any break or error events */ - SIOA_C = 2 << 3; + out(SIOA_C, 2 << 3); - SIOB_C = 0; // read register 0 - cb = SIOB_C; + out(SIOB_C, 0); // read register 0 + cb = in(SIOB_C); if (cb & 1) { - tty_inproc(2, SIOB_D); + tty_inproc(2, in(SIOB_D)); progress = 1; } if ((cb & 4) && (sleeping & 8)) { tty_outproc(3); sleeping &= ~8; - SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending + out(SIOB_C, 5 << 3); // reg 0 CMD 5 - reset transmit interrupt pending } /* ACK any break or error events */ - SIOB_C = 2 << 3; + out(SIOB_C, 2 << 3); } while(progress); } @@ -175,9 +175,9 @@ void tty_data_consumed(uint_fast8_t minor) /* kernel writes to system console -- never sleep! */ void kputchar(uint_fast8_t c) { - while(tty_writeready(TTYDEV - 512) != TTY_READY_NOW); + while(tty_writeready(TTYDEV & 0xFF) != TTY_READY_NOW); if (c == '\n') - tty_putc(TTYDEV - 512, '\r'); - while(tty_writeready(TTYDEV - 512) != TTY_READY_NOW); - tty_putc(TTYDEV - 512, c); + tty_putc(TTYDEV & 0xFF, '\r'); + while(tty_writeready(TTYDEV & 0xFF) != TTY_READY_NOW); + tty_putc(TTYDEV & 0xFF, c); } diff --git a/Kernel/platform/platform-sbc2g/devtty.h b/Kernel/platform/platform-sbc2g/devtty.h index 20bf3bdcbf..3b4faa1468 100644 --- a/Kernel/platform/platform-sbc2g/devtty.h +++ b/Kernel/platform/platform-sbc2g/devtty.h @@ -4,14 +4,14 @@ /* SIO 2 ports */ #define SIO0_BASE 0x00 -__sfr __at (SIO0_BASE + 0) SIOA_D; -__sfr __at (SIO0_BASE + 1) SIOB_D; -__sfr __at (SIO0_BASE + 2) SIOA_C; -__sfr __at (SIO0_BASE + 3) SIOB_C; +#define SIOA_D (SIO0_BASE + 0) +#define SIOB_D (SIO0_BASE + 1) +#define SIOA_C (SIO0_BASE + 2) +#define SIOB_C (SIO0_BASE + 3) -extern void sio2_otir(uint8_t port) __z88dk_fastcall; +extern void sio2_otir(uint8_t port); -void tty_putc(uint8_t minor, uint_fast8_t c); +void tty_putc(uint_fast8_t minor, uint_fast8_t c); void tty_poll(void); #endif diff --git a/Kernel/platform/platform-sbc2g/discard.c b/Kernel/platform/platform-sbc2g/discard.c index df899a7941..b7e9047c9c 100644 --- a/Kernel/platform/platform-sbc2g/discard.c +++ b/Kernel/platform/platform-sbc2g/discard.c @@ -16,7 +16,7 @@ * we claim it, if not it gets passed to init. It's perfectly acceptable * to act on a match and return to also pass it to init if you need to. */ -uint8_t plt_param(unsigned char *p) +uint_fast8_t plt_param(unsigned char *p) { } diff --git a/Kernel/platform/platform-sbc2g/ide.S b/Kernel/platform/platform-sbc2g/ide.S new file mode 100644 index 0000000000..489e5e0c36 --- /dev/null +++ b/Kernel/platform/platform-sbc2g/ide.S @@ -0,0 +1,38 @@ + + .export _devide_read_data + .export _devide_write_data + + .common + +#define IDE_REG_DATA 0x0010 + +ide_setup: + ld bc, IDE_REG_DATA ; port and count + ld a, (_td_raw) + jp z, map_buffers + dec a + jp z, map_proc_always + ld a,(_td_page) + jp map_for_swap + +_devide_read_data: + pop de + pop hl + push hl + push de + push bc + call ide_setup + inir ; transfer first 256 bytes + inir ; transfer second 256 bytes + jp map_kernel + +_devide_write_data: + pop de + pop hl + push hl + push de + push bc + call ide_setup + otir ; transfer first 256 bytes + otir ; transfer second 256 bytes + jp map_kernel diff --git a/Kernel/platform/platform-sbc2g/kernel.def b/Kernel/platform/platform-sbc2g/kernelu.def similarity index 100% rename from Kernel/platform/platform-sbc2g/kernel.def rename to Kernel/platform/platform-sbc2g/kernelu.def diff --git a/Kernel/platform/platform-sbc2g/loader.s b/Kernel/platform/platform-sbc2g/loader.S similarity index 91% rename from Kernel/platform/platform-sbc2g/loader.s rename to Kernel/platform/platform-sbc2g/loader.S index ce35444a38..1e4e053364 100644 --- a/Kernel/platform/platform-sbc2g/loader.s +++ b/Kernel/platform/platform-sbc2g/loader.S @@ -8,13 +8,7 @@ ; bootstrap goes for a bizarre wander. ; - .area VECTOR(ABS) - - .org 0xFFFE - .word start - - .area LOADER(ABS) - + .abs ; ; Occupies the entire 'boot track' (16K/32 sectors) ; Just use the top bit so we can load the image easily @@ -63,7 +57,7 @@ high: out (LBA_2),a out (LBA_1),a - ld de,#0x7C02 ; sectors 2 to 126 + ld de,#0x7B02 ; sectors 2 to 126 ld hl,#0x0100 ; load address load_loop: call ide_ready @@ -124,6 +118,13 @@ serstr: jr serstr hello: - .asciz '\r\n\r\nSBC2G FUZIX LOADER 0.1\r\n\r\n' + .byte 13,10,13,10 + .ascii 'SBC2G FUZIX LOADER 0.1' + .byte 13,10,13,10,0 gogogo: - .asciz '\r\nExecuting FUZIX...\r\n' + .byte 13,10 + .ascii 'Executing FUZIX...' + .byte 13,10,0 + + .org 0xFFFE + .word start diff --git a/Kernel/platform/platform-sbc2g/main.c b/Kernel/platform/platform-sbc2g/main.c index dcd5917c06..5d90aa7c8e 100644 --- a/Kernel/platform/platform-sbc2g/main.c +++ b/Kernel/platform/platform-sbc2g/main.c @@ -15,10 +15,6 @@ uint8_t timermsr = 0; * it needs to execute. On a machine with entirely interrupt driven * hardware this could just halt for interrupt. */ -void plt_idle(void) -{ - __asm halt __endasm; -} /* * This routine is called from the interrupt handler code to process @@ -46,7 +42,7 @@ struct blkbuf *bufpool_end = bufpool + NBUFS; */ void plt_discard(void) { - uint16_t discard_size = (uint16_t)udata - (uint16_t)bufpool_end; + uint16_t discard_size = (uint16_t)&udata - (uint16_t)bufpool_end; bufptr bp = bufpool_end; discard_size /= sizeof(struct blkbuf); diff --git a/Kernel/platform/platform-sbc2g/plt_ide.h b/Kernel/platform/platform-sbc2g/plt_ide.h index 1929bb367e..7ebe619cbe 100644 --- a/Kernel/platform/platform-sbc2g/plt_ide.h +++ b/Kernel/platform/platform-sbc2g/plt_ide.h @@ -1,11 +1,14 @@ -__sfr __at 0x10 data; -__sfr __at 0x11 error; -__sfr __at 0x12 count; -__sfr __at 0x13 sec; -__sfr __at 0x14 cyll; -__sfr __at 0x15 cylh; -__sfr __at 0x16 devh; -__sfr __at 0x17 cmd; -__sfr __at 0x17 status; +#define data 0x10 +#define error 0x11 +#define count 0x12 +#define sec 0x13 +#define cyll 0x14 +#define cylh 0x15 +#define devh 0x16 +#define cmd 0x17 +#define status 0x17 -#define IDE_REG_DATA 0x0010 +#define IDE_REG_DATA 0x10 + +#define ide_read(x) in(x) +#define ide_write(x,y) out(x,y) diff --git a/Kernel/platform/platform-sbc2g/rules.mk b/Kernel/platform/platform-sbc2g/rules.mk index 8b4e83cb4f..ee57e356bc 100644 --- a/Kernel/platform/platform-sbc2g/rules.mk +++ b/Kernel/platform/platform-sbc2g/rules.mk @@ -1 +1 @@ -CROSS_CCOPTS += --peep-file $(FUZIX_ROOT)/Kernel/cpu-z80/rst.peep +#CROSS_CCOPTS += --peep-file $(FUZIX_ROOT)/Kernel/cpu-z80/rst.peep diff --git a/Kernel/platform/platform-sbc2g/sbc2g.S b/Kernel/platform/platform-sbc2g/sbc2g.S new file mode 100644 index 0000000000..365f61b31e --- /dev/null +++ b/Kernel/platform/platform-sbc2g/sbc2g.S @@ -0,0 +1,346 @@ +; +; SBC2G support +; +; This first chunk is mostly boilerplate to adjust for each +; system. +; + ; exported symbols + .export init_early + .export init_hardware + .export _program_vectors + .export map_buffers + .export map_kernel + .export map_kernel_di + .export map_kernel_restore + .export map_proc + .export map_proc_a + .export map_proc_always + .export map_proc_always_di + .export map_save_kernel + .export map_restore + .export map_for_swap + .export plt_interrupt_all + .export _kernel_flag + .export _int_disabled + + ; exported debugging tools + .export _plt_monitor + .export _plt_reboot + .export _plt_idle + .export outchar + +#include "kernelu.def" +#include "../../cpu-z80u/kernel-z80.def" + +; Base address of SIO/2 chip 0x00 + +SIOA_D .equ 0x00 +SIOB_D .equ 0x01 +SIOA_C .equ 0x02 +SIOB_C .equ 0x03 + +; +; Buffers (we use asm to set this up as we need them in a special segment +; so we can recover the discard memory into the buffer pool +; + + .export _bufpool + + .buffers +_bufpool: + .ds BUFSIZE * NBUFS + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (kept even when we task switch) +; ----------------------------------------------------------------------------- + .common +; +; Interrupt flag. This needs to be in common memory for most memory +; models. It starts as 1 as interrupts start off. +; +_int_disabled: + .byte 1 +; +; This method is invoked early in interrupt handling before any +; complex handling is done. It's useful on a few platforms but +; generally a ret is all that is needed +; +plt_interrupt_all: + ret + +; +; If you have a ROM monitor you can get back to then do so, if not +; fall into reboot. +; +_plt_monitor: +; +; Reboot the system if possible, halt if not. On a system where the +; ROM promptly wipes the display you may want to delay or wait for +; a keypress here (just remember you may be interrupts off, no kernel +; mapped so hit the hardware). +; +; ROM is long gone. Could look at reloading boot sector ? +; +_plt_reboot: + di + jr _plt_reboot + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK (may be below 0x8000, only accessible when the kernel is +; mapped) +; ----------------------------------------------------------------------------- + .code +; +; This routine is called very early, before the boot code shuffles +; things into place. We do the ttymap here mostly as an example but +; even that really ought to be in init_hardware. +; +init_early: + ret + +_plt_idle: + halt + ret + +; ----------------------------------------------------------------------------- +; DISCARD is memory that will be recycled when we exec init +; ----------------------------------------------------------------------------- + .discard +; +; After the kernel has shuffled things into place this code is run. +; It's the best place to breakpoint or trace if you are not sure your +; kernel is loading and putting itself into place properly. +; +; It's required jobs are to set up the vectors, ramsize (total RAM), +; and procmem (total memory free to processs), as well as setting the +; interrupt mode but *not* enabling interrupts. Many platforms also +; program up support hardware like PIO and CTC devices here. +; +init_hardware: + ld hl, sio_setup + ld bc, 0x0A00 + SIOA_C ; 10 bytes to SIOA_C + otir + + ld hl, sio_setup + ld bc, 0x0A00 + SIOB_C ; and to SIOB_C + otir + + ld hl, 512 + ld (_ramsize), hl + ld hl, 448 + 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 + + ; Compiler helper vectors - in kernel bank only + + ld hl, rstblock + ld de, 8 + ld bc, 32 + ldir + + im 1 ; set CPU interrupt mode + + ret + +RTS_LOW .equ 0xEA + +sio_setup: + .byte 0x00 + .byte 0x18 ; Reset + .byte 0x04 + .byte 0xC4 + .byte 0x01 + .byte 0x19 ; We want carrier events + .byte 0x03 + .byte 0xE1 + .byte 0x05 + .byte RTS_LOW + + +; +; Bank switching unsurprisingly must be in common memory space so it's +; always available. +; + .commondata + +mapreg: + .byte 0 ; Our map register is write only so keep a copy +mapsave: + .byte 0 ; Saved copy of the previous map (see map_save) + +_kernel_flag: + .byte 1 ; We start in kernel mode + +; +; This is invoked with a NULL argument at boot to set the kernel +; vectors and then elsewhere in the kernel when the kernel knows +; a bank may need vectors writing to it. +; +_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 + + call map_proc + + ; 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 FUZIX system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, unix_syscall_entry + ld (0x0031), hl + + ld (0x0000), a + ld hl, null_handler ; to Our Trap Handler + ld (0x0001), hl + + ; and fall into map_kernel + +; +; Mapping set up for the SBCv2 +; +; The top 32K bank holds kernel code and pieces of common memory +; The lower 32K is switched between the various user banks. +; +; We know the ROM mapping is already off +; +; The _di versions of the functions are called when we know interrupts +; are definitely off. In our case it's not useful information so both +; symbols end up at the same code. +; +map_buffers: + ; for us no difference. We could potentially use a low 32K bank + ; for buffers but it's not clear it would gain us much value +map_kernel_restore: +map_kernel_di: +map_kernel: + push af + xor a + ld (mapreg),a + out (0x30), a + pop af + ret + ; map_proc is called with HL either NULL or pointing to the + ; page mapping. Unlike the other calls it's allowed to trash AF +map_proc: + ld a, h + or l + jr z, map_kernel +map_proc_hl: + ld a, (hl) ; and fall through + ; + ; With a simple bank switching system you need to provide a + ; method to switch to the bank in A without corrupting any + ; other registers. The stack is safe in common memory. + ; For swap you need to provide what for simple banking is an + ; identical routine. +map_for_swap: +map_proc_a: ; used by bankfork + ld (mapreg), a ; bank + out (0x30), a + inc a ; cheaper than push/pop + ret + + ; + ; Map the current process into memory. We do this by extracting + ; the bank value from u_page. + ; +map_proc_always_di: +map_proc_always: + push af + push hl + ld hl, _udata + U_DATA__U_PAGE + call map_proc_hl + pop hl + pop af + ret + + ; + ; Save the existing mapping and switch to the kernel. + ; The place you save it to needs to be in common memory as you + ; have no idea what bank is live. Alternatively defer the save + ; until you switch to the kernel mapping + ; +map_save_kernel: push af + ld a, (mapreg) + ld (mapsave), a + xor a + ld (mapreg),a + out (0x30),a + pop af + ret + ; + ; Restore the saved bank. Note that you don't need to deal with + ; stacking of banks (we never recursively use save/restore), and + ; that we may well call save and decide not to call restore. + ; +map_restore: + push af + ld a, (mapsave) + ld (mapreg), a + out (0x30), a + pop af + ret + + ; + ; Used for low level debug. Output the character in A without + ; corrupting other registers. May block. Interrupts and memory + ; state are undefined + ; +outchar: + push af +ocloop_sio: + xor a ; read register 0 + out (SIOA_C), a + in a,(SIOA_C) ; read Line Status Register + and #0x04 ; get THRE bit + jr z,ocloop_sio + ; now output the char to serial port + pop af + out (SIOA_D),a + ret + + .code +; +; A little SIO helper +; + .export _sio2_otir + +_sio2_otir: + pop de + pop hl + push hl + push de + push bc + ld b, 0x06 + ld c,l + ld hl, _sio_r + otir + pop bc + ret + +; +; Stub helpers for code compactness. TODO +; + .discard +; +; The first two use an rst as a jump. In the reload sp case we don't +; have to care. In the pop ix case for the function end we need to +; drop the spare frame first, but we know that af contents don't +; matter +; + +rstblock: diff --git a/Kernel/platform/platform-sbc2g/sbc2g.s b/Kernel/platform/platform-sbc2g/sbc2g.s index 98cbe16c46..cda2870bbe 100644 --- a/Kernel/platform/platform-sbc2g/sbc2g.s +++ b/Kernel/platform/platform-sbc2g/sbc2g.s @@ -1,373 +1,395 @@ +# 0 "sbc2g.S" +# 0 "" +# 0 "" +# 1 "sbc2g.S" ; -; SBC2G support -; -; This first chunk is mostly boilerplate to adjust for each -; system. -; - - .module sbcv2 - - ; exported symbols - .globl init_early - .globl init_hardware - .globl interrupt_handler - .globl _program_vectors - .globl map_buffers - .globl map_kernel - .globl map_kernel_di - .globl map_kernel_restore - .globl map_proc - .globl map_proc_a - .globl map_proc_always - .globl map_proc_always_di - .globl map_save_kernel - .globl map_restore - .globl map_for_swap - .globl plt_interrupt_all - .globl _kernel_flag - .globl _int_disabled - - ; exported debugging tools - .globl _plt_monitor - .globl _plt_reboot - .globl outchar - - ; imported symbols - .globl _ramsize - .globl _procmem - .globl istack_top - .globl istack_switched_sp - .globl unix_syscall_entry - .globl outcharhex - .globl null_handler - .globl ___sdcc_enter_ix - - .globl s__COMMONMEM - .globl l__COMMONMEM - - .include "kernel.def" - .include "../../cpu-z80/kernel-z80.def" +; SBC2G support +; +; This first chunk is mostly boilerplate to adjust for each +; system. +; + ; exported symbols + .export init_early + .export init_hardware + .export _program_vectors + .export map_buffers + .export map_kernel + .export map_kernel_di + .export map_kernel_restore + .export map_proc + .export map_proc_a + .export map_proc_always + .export map_proc_always_di + .export map_save_kernel + .export map_restore + .export map_for_swap + .export plt_interrupt_all + .export _kernel_flag + .export _int_disabled + + ; exported debugging tools + .export _plt_monitor + .export _plt_reboot + .export _plt_idle + .export outchar + +# 1 "kernelu.def" 1 +; FUZIX mnemonics for memory addresses etc +; +; +; The U_DATA address. If we are doing a normal build this is the start +; of common memory. We do actually have a symbol for udata so +; eventually this needs to go away +; +U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes @ F000 +; +; Space for the udata of a switched out process within the bank of +; memory that it uses. Normally placed at the very top +; +U_DATA_STASH .equ 0x7E00 ; 7E00-7FFF +; +; Z80 systems start program space at 0, and load at 0x100 so that the +; low 256 bytes are free for syscall vectors and the like, with some +; also used as a special case by the CP/M emulator. +; +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 +; +; CPU type +; 0 = CMOS Z80 +; 1 = NMOS Z80 (also works with CMOS) +; 2 = Z180 +; +; If either NMOS or CMOS may be present pick NMOS as the NMOS build +; contains extra code to work around an erratum n the NUMS Z80 +; +Z80_TYPE .equ 1 ; NMOS (IRQ bugs) Z80 +; +; For special platforms that have external memory protection hardware +; Just say 0. +; +Z80_MMU_HOOKS .equ 0 +; +; Set this if the platform has swap enabled in config.h +; +CONFIG_SWAP .equ 1 +; +; The number of disk buffers. Must match config.h +; +NBUFS .equ 5 +# 33 "sbc2g.S" 2 +# 1 "../../cpu-z80u/kernel-z80.def" 1 +# 34 "sbc2g.S" 2 ; Base address of SIO/2 chip 0x00 -SIOA_D .EQU 0x00 -SIOB_D .EQU 0x01 -SIOA_C .EQU 0x02 -SIOB_C .EQU 0x03 +SIOA_D .equ 0x00 +SIOB_D .equ 0x01 +SIOA_C .equ 0x02 +SIOB_C .equ 0x03 ; ; Buffers (we use asm to set this up as we need them in a special segment ; so we can recover the discard memory into the buffer pool ; - .globl _bufpool - .area _BUFFERS + .export _bufpool + .buffers _bufpool: - .ds BUFSIZE * NBUFS + .ds 520 * NBUFS ; ----------------------------------------------------------------------------- ; COMMON MEMORY BANK (kept even when we task switch) ; ----------------------------------------------------------------------------- - .area _COMMONMEM - + .common ; -; Interrupt flag. This needs to be in common memory for most memory -; models. It starts as 1 as interrupts start off. +; Interrupt flag. This needs to be in common memory for most memory +; models. It starts as 1 as interrupts start off. ; _int_disabled: - .db 1 + .byte 1 ; -; This method is invoked early in interrupt handling before any -; complex handling is done. It's useful on a few platforms but -; generally a ret is all that is needed +; This method is invoked early in interrupt handling before any +; complex handling is done. It's useful on a few platforms but +; generally a ret is all that is needed ; plt_interrupt_all: - ret + ret ; -; If you have a ROM monitor you can get back to then do so, if not -; fall into reboot. +; If you have a ROM monitor you can get back to then do so, if not +; fall into reboot. ; _plt_monitor: ; -; Reboot the system if possible, halt if not. On a system where the -; ROM promptly wipes the display you may want to delay or wait for -; a keypress here (just remember you may be interrupts off, no kernel -; mapped so hit the hardware). +; Reboot the system if possible, halt if not. On a system where the +; ROM promptly wipes the display you may want to delay or wait for +; a keypress here (just remember you may be interrupts off, no kernel +; mapped so hit the hardware). ; -; ROM is long gone. Could look at reloading boot sector ? +; ROM is long gone. Could look at reloading boot sector ? ; _plt_reboot: - di - jr _plt_reboot + di + jr _plt_reboot ; ----------------------------------------------------------------------------- ; KERNEL MEMORY BANK (may be below 0x8000, only accessible when the kernel is ; mapped) ; ----------------------------------------------------------------------------- - .area _CODE - + .code ; -; This routine is called very early, before the boot code shuffles -; things into place. We do the ttymap here mostly as an example but -; even that really ought to be in init_hardware. +; This routine is called very early, before the boot code shuffles +; things into place. We do the ttymap here mostly as an example but +; even that really ought to be in init_hardware. ; init_early: - ret + ret + +_plt_idle: + halt + ret ; ----------------------------------------------------------------------------- ; DISCARD is memory that will be recycled when we exec init ; ----------------------------------------------------------------------------- - .area _DISCARD + .discard ; -; After the kernel has shuffled things into place this code is run. -; It's the best place to breakpoint or trace if you are not sure your -; kernel is loading and putting itself into place properly. +; After the kernel has shuffled things into place this code is run. +; It's the best place to breakpoint or trace if you are not sure your +; kernel is loading and putting itself into place properly. ; -; It's required jobs are to set up the vectors, ramsize (total RAM), -; and procmem (total memory free to processs), as well as setting the -; interrupt mode but *not* enabling interrupts. Many platforms also -; program up support hardware like PIO and CTC devices here. +; It's required jobs are to set up the vectors, ramsize (total RAM), +; and procmem (total memory free to processs), as well as setting the +; interrupt mode but *not* enabling interrupts. Many platforms also +; program up support hardware like PIO and CTC devices here. ; init_hardware: - ld hl,#sio_setup - ld bc,#0x0A00 + SIOA_C ; 10 bytes to SIOA_C - otir + ld hl, sio_setup + ld bc, 0x0A00 + SIOA_C ; 10 bytes to SIOA_C + otir - ld hl,#sio_setup - ld bc,#0x0A00 + SIOB_C ; and to SIOB_C - otir + ld hl, sio_setup + ld bc, 0x0A00 + SIOB_C ; and to SIOB_C + otir - ld hl,#512 - ld (_ramsize), hl - ld hl,#448 - ld (_procmem), hl + ld hl, 512 + ld (_ramsize), hl + ld hl, 448 + 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 + ; 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 - ; Compiler helper vectors - in kernel bank only + ; Compiler helper vectors - in kernel bank only - ld hl,#rstblock - ld de,#8 - ld bc,#32 - ldir + ld hl, rstblock + ld de, 8 + ld bc, 32 + ldir - im 1 ; set CPU interrupt mode + im 1 ; set CPU interrupt mode - ret + ret -RTS_LOW .EQU 0xEA +RTS_LOW .equ 0xEA sio_setup: - .byte 0x00 - .byte 0x18 ; Reset - .byte 0x04 - .byte 0xC4 - .byte 0x01 - .byte 0x19 ; We want carrier events - .byte 0x03 - .byte 0xE1 - .byte 0x05 - .byte RTS_LOW + .byte 0x00 + .byte 0x18 ; Reset + .byte 0x04 + .byte 0xC4 + .byte 0x01 + .byte 0x19 ; We want carrier events + .byte 0x03 + .byte 0xE1 + .byte 0x05 + .byte RTS_LOW ; -; Bank switching unsurprisingly must be in common memory space so it's -; always available. +; Bank switching unsurprisingly must be in common memory space so it's +; always available. ; - .area _COMMONMEM + .commondata -mapreg: .db 0 ; Our map register is write only so keep a copy -mapsave: .db 0 ; Saved copy of the previous map (see map_save) +mapreg: + .byte 0 ; Our map register is write only so keep a copy +mapsave: + .byte 0 ; Saved copy of the previous map (see map_save) _kernel_flag: - .db 1 ; We start in kernel mode + .byte 1 ; We start in kernel mode ; -; This is invoked with a NULL argument at boot to set the kernel -; vectors and then elsewhere in the kernel when the kernel knows -; a bank may need vectors writing to it. +; This is invoked with a NULL argument at boot to set the kernel +; vectors and then elsewhere in the kernel when the kernel knows +; a bank may need vectors writing to it. ; _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 + ; 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 - call map_proc + call map_proc - ; now install the interrupt vector at 0x0038 - ld a, #0xC3 ; JP instruction - ld (0x0038), a - ld hl, #interrupt_handler - ld (0x0039), hl + ; 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 FUZIX system calls - ld (0x0030), a ; (rst 30h is unix function call vector) - ld hl, #unix_syscall_entry - ld (0x0031), hl + ; set restart vector for FUZIX system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, unix_syscall_entry + ld (0x0031), hl - ld (0x0000), a - ld hl, #null_handler ; to Our Trap Handler - ld (0x0001), hl + ld (0x0000), a + ld hl, null_handler ; to Our Trap Handler + ld (0x0001), hl - ; and fall into map_kernel + ; and fall into map_kernel ; -; Mapping set up for the SBCv2 +; Mapping set up for the SBCv2 ; -; The top 32K bank holds kernel code and pieces of common memory -; The lower 32K is switched between the various user banks. +; The top 32K bank holds kernel code and pieces of common memory +; The lower 32K is switched between the various user banks. ; -; We know the ROM mapping is already off +; We know the ROM mapping is already off ; -; The _di versions of the functions are called when we know interrupts -; are definitely off. In our case it's not useful information so both -; symbols end up at the same code. +; The _di versions of the functions are called when we know interrupts +; are definitely off. In our case it's not useful information so both +; symbols end up at the same code. ; map_buffers: - ; for us no difference. We could potentially use a low 32K bank - ; for buffers but it's not clear it would gain us much value + ; for us no difference. We could potentially use a low 32K bank + ; for buffers but it's not clear it would gain us much value map_kernel_restore: map_kernel_di: map_kernel: - push af - xor a - ld (mapreg),a - out (0x30), a - pop af - ret - ; map_proc is called with HL either NULL or pointing to the - ; page mapping. Unlike the other calls it's allowed to trash AF + push af + xor a + ld (mapreg),a + out (0x30), a + pop af + ret + ; map_proc is called with HL either NULL or pointing to the + ; page mapping. Unlike the other calls it's allowed to trash AF map_proc: - ld a, h - or l - jr z, map_kernel + ld a, h + or l + jr z, map_kernel map_proc_hl: - ld a, (hl) ; and fall through - ; - ; With a simple bank switching system you need to provide a - ; method to switch to the bank in A without corrupting any - ; other registers. The stack is safe in common memory. - ; For swap you need to provide what for simple banking is an - ; identical routine. + ld a, (hl) ; and fall through + ; + ; With a simple bank switching system you need to provide a + ; method to switch to the bank in A without corrupting any + ; other registers. The stack is safe in common memory. + ; For swap you need to provide what for simple banking is an + ; identical routine. map_for_swap: -map_proc_a: ; used by bankfork - ld (mapreg), a ; bank - out (0x30), a - inc a ; cheaper than push/pop - ret - - ; - ; Map the current process into memory. We do this by extracting - ; the bank value from u_page. - ; +map_proc_a: ; used by bankfork + ld (mapreg), a ; bank + out (0x30), a + inc a ; cheaper than push/pop + ret + + ; + ; Map the current process into memory. We do this by extracting + ; the bank value from u_page. + ; map_proc_always_di: map_proc_always: - push af - push hl - ld hl, #_udata + U_DATA__U_PAGE - call map_proc_hl - pop hl - pop af - ret - - ; - ; Save the existing mapping and switch to the kernel. - ; The place you save it to needs to be in common memory as you - ; have no idea what bank is live. Alternatively defer the save - ; until you switch to the kernel mapping - ; -map_save_kernel: push af - ld a, (mapreg) - ld (mapsave), a - xor a - ld (mapreg),a - out (0x30),a - pop af - ret - ; - ; Restore the saved bank. Note that you don't need to deal with - ; stacking of banks (we never recursively use save/restore), and - ; that we may well call save and decide not to call restore. - ; + push af + push hl + ld hl, _udata + 2 + call map_proc_hl + pop hl + pop af + ret + + ; + ; Save the existing mapping and switch to the kernel. + ; The place you save it to needs to be in common memory as you + ; have no idea what bank is live. Alternatively defer the save + ; until you switch to the kernel mapping + ; +map_save_kernel: push af + ld a, (mapreg) + ld (mapsave), a + xor a + ld (mapreg),a + out (0x30),a + pop af + ret + ; + ; Restore the saved bank. Note that you don't need to deal with + ; stacking of banks (we never recursively use save/restore), and + ; that we may well call save and decide not to call restore. + ; map_restore: - push af - ld a, (mapsave) - ld (mapreg), a - out (0x30), a - pop af - ret - - ; - ; Used for low level debug. Output the character in A without - ; corrupting other registers. May block. Interrupts and memory - ; state are undefined - ; + push af + ld a, (mapsave) + ld (mapreg), a + out (0x30), a + pop af + ret + + ; + ; Used for low level debug. Output the character in A without + ; corrupting other registers. May block. Interrupts and memory + ; state are undefined + ; outchar: - push af + push af ocloop_sio: - xor a ; read register 0 - out (SIOA_C), a - in a,(SIOA_C) ; read Line Status Register - and #0x04 ; get THRE bit - jr z,ocloop_sio - ; now output the char to serial port - pop af - out (SIOA_D),a - ret + xor a ; read register 0 + out (SIOA_C), a + in a,(SIOA_C) ; read Line Status Register + and #0x04 ; get THRE bit + jr z,ocloop_sio + ; now output the char to serial port + pop af + out (SIOA_D),a + ret - .area _CODE + .code ; -; A little SIO helper +; A little SIO helper ; - .globl _sio_r - .globl _sio2_otir + .export _sio2_otir _sio2_otir: - ld b,#0x06 - ld c,l - ld hl,#_sio_r - otir - ret + pop de + pop hl + push hl + push de + push bc + ld b, 0x06 + ld c,l + ld hl, _sio_r + otir + pop bc + ret ; -; Stub helpers for code compactness. Note that -; sdcc_enter_ix is in the standard compiler support already +; Stub helpers for code compactness. TODO ; - .area _DISCARD - + .discard ; -; The first two use an rst as a jump. In the reload sp case we don't -; have to care. In the pop ix case for the function end we need to -; drop the spare frame first, but we know that af contents don't -; matter +; The first two use an rst as a jump. In the reload sp case we don't +; have to care. In the pop ix case for the function end we need to +; drop the spare frame first, but we know that af contents don't +; matter ; rstblock: - jp ___sdcc_enter_ix - .ds 5 -___spixret: - ld sp,ix - pop ix - ret - .ds 3 -___ixret: - pop af - pop ix - ret - .ds 4 -___ldhlhl: - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - ret diff --git a/Kernel/platform/platform-sbc2g/target.mk b/Kernel/platform/platform-sbc2g/target.mk index 4f5b92693b..1cf94007a6 100644 --- a/Kernel/platform/platform-sbc2g/target.mk +++ b/Kernel/platform/platform-sbc2g/target.mk @@ -1,4 +1,5 @@ # # Tell the build system what processor type we are using # -export CPU = z80 +export CPU = z80u +export USERCPU = z80 diff --git a/Kernel/platform/platform-sbc2g/tricks.S b/Kernel/platform/platform-sbc2g/tricks.S new file mode 100644 index 0000000000..e9f777d7bf --- /dev/null +++ b/Kernel/platform/platform-sbc2g/tricks.S @@ -0,0 +1,123 @@ +; +; For simple banked systems there is a standard implementation. The +; only reason to do otherwise is for speed. A custom bank logic aware +; bank to bank copier will give vastly better fork() performance. +; +#include "kernelu.def" +#include "../../cpu-z80u/kernel-z80.def" + +; +; All of the fixed bank support is available as a library routine, +; however it is a performance sensitive area. Start with +; +; .include "../lib/z80fixedbank.s" +; +; As well as using "usermem_std-z80.rel" in your link file for the +; userspace access operations. +; +; We can use the fast Z80 copiers in this case +; +#include "../../lib/z80uuser1.s" +; +; The when it all works you can consider following this example and +; optimizing it hard. +; +; Firstly we still want the core of the fixed bank support +; +#include "../../lib/z80ufixedbank-core.s" + +; +; We want to provide our own optimized direct 32K bank to bank +; copy. This is slightly crazy stuff. The fastest Z80 copy is to use +; the stack. In the case of banked copies even more so. This can't be +; a library routine as we have to inline the memory mapping as we have +; no valid stack. +; +; Copy the process memory for a fork. +; +; A is the page base of the parent +; C of the child +; +; We violate all the rules of good programming for speed here. +; +; Interrupts are off so the stack pointer is spare (Watch out for NMI +; if your platform has an NMI to handle. +; +bankfork: + push ix + ld (cpatch0 + 1),a ; patch parent into loop + ld a,c + ld (cpatch1 + 1),a ; patch child into loop + ; + ; Set up ready for the copy + ; + ld (spcache),sp + ; 32256 bytes to copy. + ; Stack pointer at the target buffer + ld sp,#PROGBASE ; Base of memory to fork + ; 8 outer loops + ld a,#8 + ld (copyct),a + xor a ; 256 inner loops of 16 (total 32k) +copyloop: + ex af,af' ; Save A as we need an A for ioports +cpatch0: + ld a,#0 ; parent bank (patched in for speed) +bankpatch1: + out (0x30),a + pop bc ; copy 16 bytes out of parent + pop de + pop hl + exx + pop bc + pop de + pop hl + pop ix + pop iy + ld (sp_patch+1),sp +cpatch1: + ld a,#0 ; child bank (also patched in for speed) +bankpatch2: + out (0x30),a + push iy ; and put them back into the child + push ix + push hl + push de + push bc + exx + push hl + push de + push bc + ex af,af' ; Get counter back + dec a + jr z, setdone ; 252 loops ? +copy_cont: +sp_patch: + ld sp,#0 + jp copyloop +; +; This outer loop only runs 8 times so isn't quite so performance +; critical +; +setdone: + ld hl,#copyct + dec (hl) + jr z, copy_over + ld a,#252 + jr copy_cont +copy_over: + ; + ; Get the stack back + ; + ld sp,(spcache) + ; + ; And the correct kernel bank. + ; + pop ix + jp map_kernel + +spcache: + .word 0 +copyct: + .byte 0 + diff --git a/Kernel/platform/platform-sbc2g/tricks.s b/Kernel/platform/platform-sbc2g/tricks.s index ab42c25048..cef1006eda 100644 --- a/Kernel/platform/platform-sbc2g/tricks.s +++ b/Kernel/platform/platform-sbc2g/tricks.s @@ -1,123 +1,613 @@ +# 0 "tricks.S" +# 0 "" +# 0 "" +# 1 "tricks.S" ; -; For simple banked systems there is a standard implementation. The -; only reason to do otherwise is for speed. A custom bank logic aware -; bank to bank copier will give vastly better fork() performance. +; For simple banked systems there is a standard implementation. The +; only reason to do otherwise is for speed. A custom bank logic aware +; bank to bank copier will give vastly better fork() performance. ; - .include "kernel.def" - .include "../../cpu-z80/kernel-z80.def" +# 1 "kernelu.def" 1 +; FUZIX mnemonics for memory addresses etc +; +; +; The U_DATA address. If we are doing a normal build this is the start +; of common memory. We do actually have a symbol for udata so +; eventually this needs to go away +; +U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes @ F000 +; +; Space for the udata of a switched out process within the bank of +; memory that it uses. Normally placed at the very top +; +U_DATA_STASH .equ 0x7E00 ; 7E00-7FFF +; +; Z80 systems start program space at 0, and load at 0x100 so that the +; low 256 bytes are free for syscall vectors and the like, with some +; also used as a special case by the CP/M emulator. +; +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 +; +; CPU type +; 0 = CMOS Z80 +; 1 = NMOS Z80 (also works with CMOS) +; 2 = Z180 +; +; If either NMOS or CMOS may be present pick NMOS as the NMOS build +; contains extra code to work around an erratum n the NUMS Z80 +; +Z80_TYPE .equ 1 ; NMOS (IRQ bugs) Z80 +; +; For special platforms that have external memory protection hardware +; Just say 0. +; +Z80_MMU_HOOKS .equ 0 +; +; Set this if the platform has swap enabled in config.h +; +CONFIG_SWAP .equ 1 +; +; The number of disk buffers. Must match config.h +; +NBUFS .equ 5 +# 7 "tricks.S" 2 +# 1 "../../cpu-z80u/kernel-z80.def" 1 +# 8 "tricks.S" 2 ; -; All of the fixed bank support is available as a library routine, -; however it is a performance sensitive area. Start with +; All of the fixed bank support is available as a library routine, +; however it is a performance sensitive area. Start with +; +; .include "../lib/z80fixedbank.s" +; +; As well as using "usermem_std-z80.rel" in your link file for the +; userspace access operations. ; -; .include "../lib/z80fixedbank.s" +; We can use the fast Z80 copiers in this case ; -; As well as using "usermem_std-z80.rel" in your link file for the -; userspace access operations. +# 1 "../../lib/z80uuser1.s" 1 ; -; We can use the fast Z80 copiers in this case +; Alternative user memory copiers for systems where all the kernel +; data that is ever moved from user space is visible in the user +; mapping. ; - .include "../../lib/z80user1.s" + + ; exported symbols + .export __uget + .export __ugetc + .export __ugetw + + .export __uput + .export __uputc + .export __uputw + + .export __uzero + +; +; We need these in common as they bank switch ; -; The when it all works you can consider following this example and -; optimizing it hard. + .common ; -; Firstly we still want the core of the fixed bank support +; The basic operations are copied from the standard one. Only the +; blk transfers are different. uputget is a bit different as we are +; not doing 8bit loop pairs. ; - .include "../../lib/z80fixedbank-core.s" +uputget: + ; load DE with the byte count + ld c, (ix + 8) ; byte count + ld b, (ix + 9) + ld a, b + or c + ret z ; no work + ; load HL with the source address + ld l, (ix + 4) ; src address + ld h, (ix + 5) + ; load DE with destination address (in userspace) + ld e, (ix + 6) + ld d, (ix + 7) + ret ; Z is still false + +__uputc: + pop bc ; return + pop de ; char + pop hl ; dest + push hl + push de + push bc + call map_proc_always + ld (hl), e +uputc_out: + jp map_kernel ; map the kernel back below common +__uputw: + pop bc ; return + pop de ; word + pop hl ; dest + push hl + push de + push bc + call map_proc_always + ld (hl), e + inc hl + ld (hl), d + jp map_kernel + +; +; ugetc and ugetw are fastcall so the address we need is already in +; HL +; +__ugetc: + call map_proc_always + ld l, (hl) + ld h, 0 + jp map_kernel + +__ugetw: + call map_proc_always + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + jp map_kernel + +__uput: + push ix + ld ix, 0 + add ix, sp + call uputget ; source in HL dest in DE, count in BC + jr z, uput_out ; but count is at this point magic + call map_proc_always + ldir +uput_out: + call map_kernel + pop ix + ld hl, 0 + ret + +__uget: + push ix + ld ix, 0 + add ix, sp + call uputget ; source in HL dest in DE, count in BC + jr z, uput_out ; but count is at this point magic + call map_proc_always + ldir + jr uput_out + +; +__uzero: + pop de ; return + pop hl ; address + pop bc ; size + push bc + push hl + push de + ld a, b ; check for 0 copy + or c + ret z + call map_proc_always + ld (hl), 0 + dec bc + ld a, b + or c + jp z, uputc_out + ld e, l + ld d, h + inc de + ldir + jp uputc_out +# 21 "tricks.S" 2 +; +; The when it all works you can consider following this example and +; optimizing it hard. ; -; We want to provide our own optimized direct 32K bank to bank -; copy. This is slightly crazy stuff. The fastest Z80 copy is to use -; the stack. In the case of banked copies even more so. This can't be -; a library routine as we have to inline the memory mapping as we have -; no valid stack. +; Firstly we still want the core of the fixed bank support ; -; Copy the process memory for a fork. +# 1 "../../lib/z80ufixedbank-core.s" 1 ; -; A is the page base of the parent -; C of the child +; For a purely bank based architecture this code is common and can be +; used by most platforms ; -; We violate all the rules of good programming for speed here. +; The caller needs to provide the standard map routines along with +; map_kernel_a which maps in the kernel bank in a. This code assumes +; that the bank can be encoded in 8bits. ; -; Interrupts are off so the stack pointer is spare (Watch out for NMI -; if your platform has an NMI to handle. + .export _plt_switchout + .export _switchin + .export _dofork + + .export _need_resched + + .common + +; __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(). +; +; This function can have no arguments or auto variables. +; +_plt_switchout: + ld hl, #0 ; return code set here is ignored, but _switchin can + ; return from either _switchout OR _dofork, so they must both write + ; 14 with the following on the stack: + push hl ; return code + push bc ; register variable + push ix + push iy + ld hl,(__tmp) + push hl + ld hl,(__hireg) + push hl + ld hl,(__tmp2) + push hl + ld hl,(__tmp2+2) + push hl + ld hl,(__tmp3) + push hl + ld hl,(__tmp3+2) + push hl + ld hl,(__retaddr) + push hl + ld (_udata + 14), sp ; this is where the SP is restored in _switchin + + ; Stash the uarea back into process memory + call map_proc_always + ld hl, #_udata + ld de, #U_DATA_STASH + ld bc, #U_DATA__TOTALSIZE + ldir + call map_kernel + + ; find another process to run (may select this one again) + call _getproc + + push hl + call _switchin + + ; we should never get here + call _plt_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .byte 13, 10, 0 +swapped: .ascii "_switchin: SWAPPED" + .byte 13, 10, 0 + +_switchin: + di + pop bc ; return address (we can trash bc here - we will restore one) + pop de ; new process pointer +; +; FIXME: do we actually *need* to restore the stack ! +; + push de ; restore stack + push bc ; restore stack + + ld a,#1 + ld (_int_disabled),a + +; +; FIXME: map_kernel_di ? +; + call map_kernel + + ld hl, #15 + add hl, de ; process ptr +# 129 "../../lib/z80ufixedbank-core.s" + ld a, (hl) +not_swapped: + push hl + ld hl, (_udata + 0) + or a + sbc hl, de + pop hl + jr z, skip_copyback ; Tormod's optimisation: don't copy the + ; the stash back if we are the task who + ; last owned the real udata + ld a,(hl) + ; Pages please ! + call map_proc_a + + ; bear in mind that the stack will be switched now, so we can't use it + ; to carry values over this point + + exx ; thank goodness for exx 8) + ld hl, #U_DATA_STASH + ld de, #_udata + ld bc, #U_DATA__TOTALSIZE + ldir + exx + + ; In the non swap case we must set so before we use the stack + ; otherwise we risk corrupting the restored stack frame + ld sp, (_udata + 14) + call map_kernel + + ; check u_data->u_ptab matches what we wanted + ld hl, (_udata + 0) ; u_data->u_ptab + or a ; clear carry flag + sbc hl, de ; subtract, result will be zero if DE==HL + jr nz, switchinfail + +skip_copyback: + ; wants optimising up a bit + ld ix, (_udata + 0) + ; next_process->p_status = 1 + ld (ix + 0), #1 + + ; Fix the moved page pointers + ; Just do one byte as that is all we use on this platform + ld a, (ix + 15) + ld (_udata + 2), a + ; runticks = 0 + ld hl, #0 + ld (_runticks), hl + + ; restore machine state -- note we may be returning from either + ; _switchout or _dofork + ld sp, (_udata + 14) + + pop hl + ld (__retaddr),hl + pop hl + ld (__tmp3+2),hl + pop hl + ld (__tmp3),hl + pop hl + ld (__tmp2+2),hl + pop hl + ld (__tmp2),hl + pop hl + ld (__hireg),hl + pop hl + ld (__tmp),hl + pop iy ; register variables + pop ix + pop bc + pop hl ; return code + + ; enable interrupts, if we didn't pre-empt in an ISR + ld a, (_udata + 16) + ld (_int_disabled),a + or a + ret nz ; Not an 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 _plt_monitor + + +; +; 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. + + ; + ; FIXME: we should no longer need interrupts off for most of a + ; fork() call. + ; + 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, #3 + 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 bc + push ix + push iy + ld hl,(__tmp) + push hl + ld hl,(__hireg) + push hl + ld hl,(__tmp2) + push hl + ld hl,(__tmp2+2) + push hl + ld hl,(__tmp3) + push hl + ld hl,(__tmp3+2) + push hl + ld hl,(__retaddr) + push hl + + ; 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 (_udata + 14), sp + + ; now we're in a safe state for _switchin to return in the parent + ; process. + + ; --------- copy process --------- + + ld hl, (fork_proc_ptr) + ld de, #15 + add hl, de + ; load p_page + ld c, (hl) + ; load existing page ptr + ld a, (_udata + 2) + + ; FIXME: We will redefine this to expect udata as parent and (hl) + ; as child so it's also clean for multibank. For now just make + ; sure HL happens to be right + call bankfork ; do the bank to bank copy + + ; Copy done + + call map_proc_always + + ; We are going to copy the uarea into the parents uarea stash + ; we must not touch the parent uarea after this point, any + ; changes only affect the child + ld hl, #_udata ; copy the udata from common into the + ld de, #U_DATA_STASH ; target process + ld bc, #U_DATA__TOTALSIZE + ldir + ; Return to the kernel mapping + call map_kernel + + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. + ; ix/iy are untouched so don't need a restore BC is not so does + ld hl,18 + add hl,sp + ld sp,hl + pop bc + pop af ; and the pid + + ; Make a new process table entry, etc. + ld hl,#_udata + push hl + ld hl, (fork_proc_ptr) + push hl + call _makeproc + pop af + pop af + + ; 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 + + .commondata +; +; For the moment +; +bouncebuffer: + .ds 256 +; +; 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. This can share with the bounce +; buffer used by bankfork as we won't switchin mid way through the +; banked fork() call. +; +_swapstack: +_need_resched: .byte 0 +fork_proc_ptr: .word 0 ; (C type is struct p_tab *) -- address of child process p_tab entry +# 28 "tricks.S" 2 + +; +; We want to provide our own optimized direct 32K bank to bank +; copy. This is slightly crazy stuff. The fastest Z80 copy is to use +; the stack. In the case of banked copies even more so. This can't be +; a library routine as we have to inline the memory mapping as we have +; no valid stack. +; +; Copy the process memory for a fork. +; +; A is the page base of the parent +; C of the child +; +; We violate all the rules of good programming for speed here. +; +; Interrupts are off so the stack pointer is spare (Watch out for NMI +; if your platform has an NMI to handle. ; bankfork: - push ix - ld (cpatch0 + 1),a ; patch parent into loop - ld a,c - ld (cpatch1 + 1),a ; patch child into loop - ; - ; Set up ready for the copy - ; - ld (spcache),sp - ; 32256 bytes to copy. - ; Stack pointer at the target buffer - ld sp,#PROGBASE ; Base of memory to fork - ; 8 outer loops - ld a,#8 - ld (copyct),a - xor a ; 256 inner loops of 16 (total 32k) + push ix + ld (cpatch0 + 1),a ; patch parent into loop + ld a,c + ld (cpatch1 + 1),a ; patch child into loop + ; + ; Set up ready for the copy + ; + ld (spcache),sp + ; 32256 bytes to copy. + ; Stack pointer at the target buffer + ld sp,#PROGBASE ; Base of memory to fork + ; 8 outer loops + ld a,#8 + ld (copyct),a + xor a ; 256 inner loops of 16 (total 32k) copyloop: - ex af,af' ; Save A as we need an A for ioports + ex af,af' ; Save A as we need an A for ioports cpatch0: - ld a,#0 ; parent bank (patched in for speed) + ld a,#0 ; parent bank (patched in for speed) bankpatch1: - out (0x30),a - pop bc ; copy 16 bytes out of parent - pop de - pop hl - exx - pop bc - pop de - pop hl - pop ix - pop iy - ld (sp_patch+1),sp + out (0x30),a + pop bc ; copy 16 bytes out of parent + pop de + pop hl + exx + pop bc + pop de + pop hl + pop ix + pop iy + ld (sp_patch+1),sp cpatch1: - ld a,#0 ; child bank (also patched in for speed) + ld a,#0 ; child bank (also patched in for speed) bankpatch2: - out (0x30),a - push iy ; and put them back into the child - push ix - push hl - push de - push bc - exx - push hl - push de - push bc - ex af,af' ; Get counter back - dec a - jr z, setdone ; 252 loops ? + out (0x30),a + push iy ; and put them back into the child + push ix + push hl + push de + push bc + exx + push hl + push de + push bc + ex af,af' ; Get counter back + dec a + jr z, setdone ; 252 loops ? copy_cont: sp_patch: - ld sp,#0 - jp copyloop + ld sp,#0 + jp copyloop ; -; This outer loop only runs 8 times so isn't quite so performance -; critical +; This outer loop only runs 8 times so isn't quite so performance +; critical ; setdone: - ld hl,#copyct - dec (hl) - jr z, copy_over - ld a,#252 - jr copy_cont + ld hl,#copyct + dec (hl) + jr z, copy_over + ld a,#252 + jr copy_cont copy_over: - ; - ; Get the stack back - ; - ld sp,(spcache) - ; - ; And the correct kernel bank. - ; - pop ix - jp map_kernel + ; + ; Get the stack back + ; + ld sp,(spcache) + ; + ; And the correct kernel bank. + ; + pop ix + jp map_kernel spcache: - .word 0 + .word 0 copyct: - .byte 0 - + .byte 0