From c3ce9d9e3f1b5a3992c4de4fa9820b0e9fc8414c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 28 Aug 2018 13:47:24 +0100 Subject: [PATCH] sbcv2: comment extensively and move driver stuff that should be shared out We now have something approaching a clean reference port, and a long list of cleanups to do the other trees ! --- Kernel/platform-sbcv2/Makefile | 6 +- Kernel/platform-sbcv2/commonmem.s | 5 +- Kernel/platform-sbcv2/discard.c | 45 +++++++++- Kernel/platform-sbcv2/ds1302-n8vem.s | 79 ----------------- Kernel/platform-sbcv2/ppide.c | 123 --------------------------- Kernel/platform-sbcv2/sbcv2.s | 95 ++++++++++++++++++--- Kernel/platform-sbcv2/tricks.s | 10 ++- 7 files changed, 138 insertions(+), 225 deletions(-) delete mode 100644 Kernel/platform-sbcv2/ds1302-n8vem.s delete mode 100644 Kernel/platform-sbcv2/ppide.c diff --git a/Kernel/platform-sbcv2/Makefile b/Kernel/platform-sbcv2/Makefile index 623ff2ed..b807b31b 100644 --- a/Kernel/platform-sbcv2/Makefile +++ b/Kernel/platform-sbcv2/Makefile @@ -1,7 +1,7 @@ CROSS_CCOPTS += -I../dev/ -CSRCS = devtty.c ppide.c +CSRCS = devtty.c CSRCS += devices.c main.c DISCSRCS = discard.c @@ -12,9 +12,9 @@ ASRCS += tricks.s commonmem.s DISCARD_DSRCS = ../dev/devide_discard.c DSRCS = ../dev/blkdev.c ../dev/devide.c ../dev/mbr.c DSRCS += ../dev/propio2.c ../dev/ds1302.c -DSRCS += ../dev/devfd.c +DSRCS += ../dev/devfd.c ../dev/ppide_rbc.c -DASRCS = ../dev/rbcfd9266_hw.s +DASRCS = ../dev/rbcfd9266_hw.s ../dev/ds1302_rbc.s NSRCS = diff --git a/Kernel/platform-sbcv2/commonmem.s b/Kernel/platform-sbcv2/commonmem.s index bafd590b..ed199180 100644 --- a/Kernel/platform-sbcv2/commonmem.s +++ b/Kernel/platform-sbcv2/commonmem.s @@ -1,6 +1,7 @@ ; -; We have no real common on the TRS80so just tuck it up at the top of -; memory leaving room for the keyboard and video (3K) +; 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 diff --git a/Kernel/platform-sbcv2/discard.c b/Kernel/platform-sbcv2/discard.c index 3703edc0..b9e6bb30 100644 --- a/Kernel/platform-sbcv2/discard.c +++ b/Kernel/platform-sbcv2/discard.c @@ -9,20 +9,50 @@ extern int strcmp(const char *, const char *); -/* Could move to discard */ +/* + * Everything in this file ends up in discard which means the moment + * we try and execute init it gets blown away. That includes any + * variables declared here so beware! + */ + +/* + * We get passed each kernel command line argument. if we return 1 then + * 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 platform_param(unsigned char *p) { used(p); - if (strcmp(p, "msr") == 0) + if (strcmp(p, "msr") == 0) { timermsr = 1; + return 1; + } return 0; } +/* + * Set up our memory mappings. This is not needed for simple banked memory + * only more complex setups such as 16K paging. + */ void map_init(void) { } -/* Kernel in bank 0, user in banks 1-14, high 32K is bank 15 */ +/* + * Add all the available pages to the list of pages we an use. If this + * is runtime dynamic check to make sure you don't add more than MAX_MAPS + * of them. On some machines with a lot of RAM the implementation turns + * the excess into a RAM disc + * + * The mapping can be logical numbers 1-n, or can be physical values to + * write into registers. Whatever works best. The 0 value is however + * reserved throughout to indicate kernel mode in calls, and also + * to mean swapped out for processes. If your bank 0 is user space you + * might need to just dec/inc before using it in an I/O port or similar + * to avoid confusion. + * + * Kernel in bank 0, user in banks 1-14, high 32K is bank 15 + */ void pagemap_init(void) { uint8_t i; @@ -30,6 +60,11 @@ void pagemap_init(void) pagemap_add(i); } +/* + * This function is called for partitioned devices if a partition is found + * and marked as swap type. The first one found will be used as swap. We + * only support one swap device. + */ void platform_swap_found(uint8_t letter, uint8_t m) { blkdev_t *blk = blk_op.blkdev; @@ -46,6 +81,10 @@ void platform_swap_found(uint8_t letter, uint8_t m) swapmap_add(n--); } +/* + * Called after interrupts are enabled in order to enumerate and set up + * any devices. In our case we simply need to probe the IDE and SD card. + */ void device_init(void) { devide_init(); diff --git a/Kernel/platform-sbcv2/ds1302-n8vem.s b/Kernel/platform-sbcv2/ds1302-n8vem.s deleted file mode 100644 index 87a95bcd..00000000 --- a/Kernel/platform-sbcv2/ds1302-n8vem.s +++ /dev/null @@ -1,79 +0,0 @@ -; 2015-02-19 Sergey Kiselev -; 2014-12-31 William R Sowerbutts -; N8VEM SBC / Zeta SBC DS1302 real time clock interface code -; -; FIXME: belongs in dev/ -; - - .module ds1302-n8vem - - ; exported symbols - .globl _ds1302_set_pin_ce - .globl _ds1302_set_pin_clk - .globl _ds1302_set_pin_data - .globl _ds1302_set_pin_data_driven - .globl _ds1302_get_pin_data - - .include "kernel.def" - .include "../kernel.def" - -; ----------------------------------------------------------------------------- -; DS1302 interface -; ----------------------------------------------------------------------------- - -N8VEM_RTC = 0x70 -PIN_CE = 0x10 -PIN_DATA_HIZ = 0x20 -PIN_CLK = 0x40 -PIN_DATA_OUT = 0x80 -PIN_DATA_IN = 0x01 - -.area _DATA - -rtc_shadow: .db 0 ; we can't read back the latch contents, so we must keep a copy - -.area _CODE - -_ds1302_get_pin_data: - in a, (N8VEM_RTC) ; read input register - and #PIN_DATA_IN ; mask off data pin - ld l, a ; return result in L - ret - -_ds1302_set_pin_data_driven: - ld hl, #2 ; get address of function argument - add hl, sp - ld b, (hl) ; load argument from stack - ld a, (rtc_shadow) - and #~PIN_DATA_HIZ ; 0 - output pin - bit 0, b ; test bit - jr nz, writereg - or #PIN_DATA_HIZ - jr writereg - -_ds1302_set_pin_data: - ld bc, #(((~PIN_DATA_OUT) << 8) | PIN_DATA_OUT) - jr setpin - -_ds1302_set_pin_ce: - ld bc, #(((~PIN_CE) << 8) | PIN_CE) - jr setpin - -_ds1302_set_pin_clk: - ld bc, #(((~PIN_CLK) << 8) | PIN_CLK) - jr setpin - -setpin: - ld a, (rtc_shadow) ; load current register contents - and b ; unset the pin - ld hl, #2 ; get address of function argument - add hl, sp - ld b, (hl) ; load argument from stack - bit 0, b ; test bit - jr z, writereg ; arg is false - or c ; arg is true -writereg: - out (N8VEM_RTC), a ; write out new register contents - ld (rtc_shadow), a ; update our shadow copy - ret - diff --git a/Kernel/platform-sbcv2/ppide.c b/Kernel/platform-sbcv2/ppide.c deleted file mode 100644 index 1d89cb79..00000000 --- a/Kernel/platform-sbcv2/ppide.c +++ /dev/null @@ -1,123 +0,0 @@ -/* 2015-04-24 WRS: devide glue functions for PPIDE */ -/* FIXME: move to dev */ - -#include -#include -#include -#include -#include -#include -#include - -__sfr __at (PPIDE_BASE + 0x00) ppi_port_a; /* IDE bus LSB */ -__sfr __at (PPIDE_BASE + 0x01) ppi_port_b; /* IDE bus MSB */ -__sfr __at (PPIDE_BASE + 0x02) ppi_port_c; /* IDE bus control signals */ -__sfr __at (PPIDE_BASE + 0x03) ppi_control; /* 8255 command register */ - -void ppide_init(void) -{ - ppi_control = PPIDE_PPI_BUS_READ; - ppi_port_c = ide_reg_status; -} - -uint8_t devide_readb(uint8_t regaddr) -{ - uint8_t r; - - /* note: ppi_control should contain PPIDE_PPI_BUS_READ already */ - ppi_port_c = regaddr; - ppi_port_c = regaddr | PPIDE_RD_LINE; /* begin /RD pulse */ - r = ppi_port_a; - ppi_port_c = regaddr; /* end /RD pulse */ - return r; -} - -void devide_writeb(uint8_t regaddr, uint8_t value) -{ - ppi_control = PPIDE_PPI_BUS_WRITE; - ppi_port_c = regaddr; - ppi_port_a = value; - ppi_port_b = 0; - ppi_port_c = regaddr | PPIDE_WR_LINE; - /* FIXME: check timing */ - ppi_port_c = regaddr; - ppi_control = PPIDE_PPI_BUS_READ; -} - -/****************************************************************************/ -/* The innermost part of the transfer routines has to live in common memory */ -/* since it must be able to bank switch to the user memory bank. */ -/****************************************************************************/ -COMMON_MEMORY - -void devide_read_data(void) __naked -{ - __asm - ld a, #ide_reg_data - ld c, #PPIDE_BASE+2 ; select control lines - out (c), a ; select IDE data register - ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr - ld d, #ide_reg_data ; register address - ld e, #ide_reg_data | PPIDE_RD_LINE ; register address with /RD asserted - ld b, #0 ; setup count - ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user - or a ; test is_user - push af ; save flags - ld a, #PPIDE_BASE+0 ; I will be needing this later - call nz, map_process_always ; map user memory first if required -goread: ; now we do the transfer - out (c), e ; assert /RD - ld c, a ; PPIDE_BASE - ini ; read byte from LSB - inc c ; up to MSB - ini ; read byte from MSB - inc c ; control lines - out (c), d ; de-assert /RD - inc b ; (delay) counteract second ini instruction - jr nz, goread ; (delay) next word - ; read completed - pop af ; recover is_user test result - ret z ; done if kernel memory transfer - jp map_kernel ; else map kernel then return - __endasm; -} - -void devide_write_data(void) __naked -{ - __asm - ld c, #PPIDE_BASE+2 ; select control lines - ld a, #ide_reg_data - out (c), a ; select data register - ld a, #PPIDE_PPI_BUS_WRITE - inc c ; up to 8255A command register - out (c), a ; 8255A ports A, B to output mode - dec c ; back down to the control lines - ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr - ld d, #ide_reg_data ; register address - ld e, #ide_reg_data | PPIDE_WR_LINE ; register address with /WR asserted - ld b, #0 ; setup count - ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user - or a ; test is_user - push af ; save flags - ld a, #PPIDE_BASE+0 ; I will be needing this later - call nz, map_process_always ; map user memory first if required -gowrite: ; now we do the transfer - out (c), d ; de-assert /WR - ld c, a ; PPIDE_BASE - outi ; write byte to LSB - inc c ; up to MSB - outi ; write byte to MSB - inc c ; up to control lines - out (c), e ; assert /WR - inc b ; (delay) offset to counteract second outi instruction - jr nz, gowrite ; (delay) next word - ; write completed - out (c), d ; de-assert /WR - ld a, #PPIDE_PPI_BUS_READ - inc c ; up to 8255A command register - out (c), a ; 8255A ports A, B to read mode - pop af ; recover is_user test result - ret z ; done if kernel memory transfer - jp map_kernel ; else map kernel then return - __endasm; -} diff --git a/Kernel/platform-sbcv2/sbcv2.s b/Kernel/platform-sbcv2/sbcv2.s index a061855b..9bdcea91 100644 --- a/Kernel/platform-sbcv2/sbcv2.s +++ b/Kernel/platform-sbcv2/sbcv2.s @@ -1,5 +1,8 @@ ; ; SBC v2 support +; +; This first chunk is mostly boilerplate to adjust for each +; system. ; .module sbcv2 @@ -50,16 +53,31 @@ _bufpool: .ds BUFSIZE * NBUFS -; + +; ----------------------------------------------------------------------------- ; COMMON MEMORY BANK (kept even when we task switch) -; +; ----------------------------------------------------------------------------- .area _COMMONMEM +; +; 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 +; platform_interrupt_all: ret -; FIXME: map ROM and jump into it +; +; If you have a ROM monitor you can get back to then do so, if not +; fall into reboot. +; _platform_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). +; _platform_reboot: di xor a @@ -72,10 +90,12 @@ _platform_reboot: ; ----------------------------------------------------------------------------- .area _CODE + .globl _ttymap ; -; We will address this one better when we do some ROMWBW integration +; 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. ; - .globl _ttymap init_early: ; FIXME: code goes here to check for PropIO v2 nicely ; Passes the minimal checking @@ -92,8 +112,20 @@ init_early: ld (_ttymap+1), hl ; set tty map to 0,2,1 for prop ret +; ----------------------------------------------------------------------------- +; DISCARD is memory that will be recycled when we exec init +; ----------------------------------------------------------------------------- .area _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,#512 ld (_ramsize), hl @@ -110,17 +142,23 @@ init_hardware: ret -;------------------------------------------------------------------------------ -; COMMON MEMORY PROCEDURES FOLLOW - +; +; Bank switching unsurprisingly must be in common memory space so it's +; always available. +; .area _COMMONMEM -mapreg: .db 0 -mapsave: .db 0 +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) _kernel_flag: .db 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 @@ -164,12 +202,20 @@ map_kernel: out (0x78), a pop af ret + ; map_process is called with HL either NULL or pointing to the + ; page mapping. Unlike the other calls it's allowed to trash AF map_process: ld a, h or l jr z, map_kernel map_process_hl: - ld a, (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_process_a: ; used by bankfork dec a ; We bias by 1 because 0 is a valid user @@ -178,6 +224,10 @@ map_process_a: ; used by bankfork 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_process_always: push af push hl @@ -187,12 +237,20 @@ map_process_always: pop af ret + ; + ; Save the existing mapping. The place you save it to needs to + ; be in common memory as you have no idea what bank is live + ; map_save: push af ld a, (mapreg) ld (mapsave), 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) @@ -201,6 +259,11 @@ map_restore: 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 twait: in a,(0x6D) @@ -213,6 +276,10 @@ twait: in a,(0x6D) ; ; PropIO v2 block transfers ; +; This is glue specific to the PropIO driver to customise it for a +; given platform. Basically it's the code in common space to do the +; data transfer into any bank. +; ; FIXME: Move these somewhere better BLKPARAM_ADDR_OFFSET .equ 0 @@ -234,7 +301,7 @@ _platform_prop_sd_read: jr nz, do_read_a ld a, (U_DATA__U_PAGE) do_read_a: call map_process_a -do_read: ld bc,#0xAB +do_read: ld bc,#0xAB inir inir jp map_kernel diff --git a/Kernel/platform-sbcv2/tricks.s b/Kernel/platform-sbcv2/tricks.s index ee50c077..1eaafcaa 100644 --- a/Kernel/platform-sbcv2/tricks.s +++ b/Kernel/platform-sbcv2/tricks.s @@ -1,4 +1,12 @@ - +; +; 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. +; +; As this is meant to be a simple reference port we use the standard +; approach. The morbidly curious can read the TRS80 model 1 bank to +; bank copier. +; .include "../kernel.def" .include "kernel.def" -- 2.34.1