CROSS_CCOPTS += -I../dev/
-CSRCS = devtty.c ppide.c
+CSRCS = devtty.c
CSRCS += devices.c main.c
DISCSRCS = discard.c
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 =
;
-; 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
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;
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;
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();
+++ /dev/null
-; 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
-
+++ /dev/null
-/* 2015-04-24 WRS: devide glue functions for PPIDE */
-/* FIXME: move to dev */
-
-#include <kernel.h>
-#include <kdata.h>
-#include <printf.h>
-#include <stdbool.h>
-#include <timer.h>
-#include <devide.h>
-#include <blkdev.h>
-
-__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;
-}
;
; SBC v2 support
+;
+; This first chunk is mostly boilerplate to adjust for each
+; system.
;
.module sbcv2
_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
; -----------------------------------------------------------------------------
.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
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
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
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
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
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)
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)
;
; 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
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
-
+;
+; 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"