CSRCS = devlpr.c devtty.c devfd.c
CSRCS += devices.c main.c
-ASRCS = sam.s crt0.s sam_vt.s floppy.s
+DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/devide_discard.c
+
+ASRCS = sam.s crt0.s sam_vt.s floppy.s atom.s
ASRCS += tricks.s commonmem.s
-COBJS = $(CSRCS:.c=.rel)
AOBJS = $(ASRCS:.s=.rel)
-OBJS = $(COBJS) $(AOBJS)
+COBJS = $(CSRCS:.c=.rel)
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+OBJS = $(COBJS) $(AOBJS) $(DOBJS) $(DISCARD_COBJS) $(DISCARD_DOBJS)
-JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+CROSS_CCOPTS += -I../dev/
+
+JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin
all: $(OBJS)
$(AOBJS): %.rel: %.s
$(CROSS_AS) $(ASOPTS) $<
+$(DOBJS): %.rel: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DISCARD_COBJS): %.rel: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
clean:
rm -f $(OBJS) $(JUNK) core *~
-image:
+image: boot setup
+
+boot:
+ sdasz80 -o boot.s
+ sdldz80 -i boot.rel
+ # 512 bytes at 4K
+ makebin -s 16896 -p boot.ihx > boot.bin
+
+setup:
+ sdasz80 -o setup.s
+ sdldz80 -n -f setup.lnk
+ # 5.5K at 32K
+ makebin -s 38400 -p setup.ihx > setup.bin
--- /dev/null
+;
+; Support for the Atomlite IDE/CF interface
+;
+; To support the Atom as well we need to make the 8bit selection in
+; devide_discard.c dynamic and we also have to address some corner
+; cases here because it's possible to get a word transfer across the
+; 32K boundary when doing user space transfers. That means we need
+; to be able to start half a word in. A transfer could also exceed
+; 16K so clever alignment won't help us that much!
+;
+; The other fun problem is that the atom expects correctly paired
+; transfers while atomlite just maps both data ports to the same
+; address. As we need to write latch,data and read data,latch we have
+; to worry about byteswapping.
+;
+ .module atom
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+
+ .globl _devide_read_data
+ .globl _devide_write_data
+
+ ; imports
+ .globl user_mapping
+ .globl _blk_op
+ .globl map_kernel_low
+
+
+ .area _COMMONMEM
+
+; FIXME: Move these somewhere better
+BLKPARAM_ADDR_OFFSET .equ 0
+BLKPARAM_IS_USER_OFFSET .equ 2
+BLKPARAM_SWAP_PAGE .equ 3
+
+IDE_DATA_R .equ 0x00F6
+IDE_DATA_W .equ 0x00F7
+
+_devide_read_data:
+ ld a, (_blk_op + BLKPARAM_IS_USER_OFFSET)
+ ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET)
+ or a
+ jr z, atomlite_read
+ dec a
+ jr z, atomlite_read_user
+; SWAP to enable yet
+; ld a, (blk_op + BLKPARAM_SWAP_PAGE)
+; call map_for_swap
+atomlite_read:
+ call atomlite_reader
+ jp map_kernel_low
+atomlite_read_user:
+ ; HL is the user buffer, BC length
+ call user_mapping
+ jr z,ide_r2
+ call atomlite_reader
+ exx
+ call user_mapping
+ide_r2:
+ call atomlite_reader
+ jp map_kernel_low
+
+_devide_write_data:
+ ld a, (_blk_op + BLKPARAM_IS_USER_OFFSET)
+ ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET)
+ or a
+ jr z, atomlite_read
+ dec a
+ jr z, atomlite_read_user
+; SWAP to enable yet
+; ld a, (blk_op + BLKPARAM_SWAP_PAGE)
+; call map_for_swap
+atomlite_write:
+ call atomlite_writer
+ jp map_kernel_low
+atomlite_write_user:
+ ; HL is the user buffer, BC length
+ call user_mapping
+ jr z,ide_w2
+ call atomlite_writer
+ exx
+ call user_mapping
+ide_w2:
+ call atomlite_writer
+ jp map_kernel_low
+;
+; This needs optimizing to use as we know C = 0 - but think about
+; the hard case with atom and split transfers. Probably need to
+; unroll the loop into two halves, check termination on each and also
+; somehow indicate partial transfers. We do know the transfer will be
+; a total of 512 bytes so the rule I think is
+; if bit 0,c on 1st transfer - it's split word
+;
+atomlite_reader:
+ ld d,b
+ ld e,c
+ ld bc,#IDE_DATA_R
+ide_r_loop:
+ in a,(c)
+ ld (hl),a
+ inc hl
+ dec bc
+ ld a,b
+ or c
+ jr nz,ide_r_loop
+ ret
+;
+; The non split case 512 bytes as fast as we can given the interface
+; design
+;
+atomlite_reader_fast:
+ ld bc,#IDE_DATA_R
+atomlite_rf_loop:
+ ini ; Read from F6 for the data high
+ inc b
+ inc b ; up to F7 for the data low
+ ini
+ dec a
+ jr nz, atomlite_rf_loop
+ ret
+;
+; This needs optimizing to use as we know C = 0
+;
+atomlite_writer:
+ ld d,b
+ ld e,c
+ ld bc,#IDE_DATA_W
+ide_w_loop:
+ ld a,(hl)
+ out (c),a
+ inc hl
+ dec bc
+ ld a,b
+ or c
+ jr nz,ide_w_loop
+ ret
+;
+; The non split case 512 bytes as fast as we can given the interface
+; design
+;
+atomlite_writer_fast:
+ ld bc,#IDE_DATA_W
+atomlite_wf_loop:
+ ini ; Read from F7 for the data high
+ ini ; F6 for the data low
+ inc b
+ inc b ; back to F7
+ dec a
+ jr nz, atomlite_rf_loop
+ ret
; for us shuffling the kernel so that 0/1 is the low kernel in RAM
; 2/3 is the high kernel in RAM and 4/5 is the video
; (or maybe it'll be saner to use 4/5 for kernel 2/3 video..)
-;
+;
+ .area BOOT(ABS)
+ .org 0x4000
+
+HIMEM .equ 251
+
+STATUS .equ 224
+CMD .equ 224
+TRACK .equ 225
+SECTOR .equ 226
+DATA .equ 227
+
+CMD_READ .equ 0x80
+CMD_STEPIN .equ 0x58
+
+ .db 0,0,0,0,0,0,0,0 ; need to work out what goes here
boot:
di
ld de,#2 ; track 0 sector 2 (we are sector 0)
out (CMD),a
ld b,#20 ; Wait for FDC
nap: djnz nap
- ld bc,DATA ; Begin reading from data port
- jr waitbyte
+ ld bc,#DATA ; Begin reading from data port
+ jr wait
byte: ini
wait: in a,(STATUS) ; Wait for DRQ
bit 1,a
bit 0,a
jr nz,wait2
jr next_sec
+
+ .org 0x4100
+ .ascii 'BOO'
+ .byte 'T'+0x80
-/* Set if you want RTC support and have an RTC on ports 0xB0-0xBC */
+/* RTC support is to do */
#undef CONFIG_RTC
-
/* Enable to make ^Z dump the inode table for debug */
#undef CONFIG_IDUMP
/* Enable to make ^A drop back into the monitor */
#undef CONFIG_MONITOR
/* Profil syscall support (not yet complete) */
-#define CONFIG_PROFIL
+#undef CONFIG_PROFIL
/* Multiple processes in memory at once */
#define CONFIG_MULTI
/* Single tasking */
#undef CONFIG_SINGLETASK
+/* Banked memory set up: 32K banks */
+#define CONFIG_BANK32
+#define MAX_MAPS 16
+
+#define CONFIG_BANKS 2 /* 2 x 32K */
+
/* Video terminal, not a serial tty */
#define CONFIG_VT
/* Fonts are pre-expanded as we have reasonable amounts of memory and
need to deal with a 2bit deep bitmap display */
#define CONFIG_FONT_8X8_EXP2
-/* Banked memory set up */
-/* FIXME */
-#define CONFIG_BANK_FIXED
-#define MAX_MAPS 16
-#define MAP_SIZE 0xFD00
-
-#define CONFIG_BANKS 2 /* 2 x 32K */
-
/* Vt definitions */
-#define VT_WIDTH 80
+#define VT_WIDTH 64
#define VT_HEIGHT 24
-#define VT_RIGHT 79
+#define VT_RIGHT 63
#define VT_BOTTOM 23
#define TICKSPERSEC 50 /* Ticks per second */
/* We need a tidier way to do this from the loader */
#define CMDLINE NULL /* Location of root dev name */
+#define BOOTDEVICENAMES "hd#,fd,,rd"
+
+/* Block devices */
+#define CONFIG_IDE /* Atom / Atomlite */
+#define MAX_BLKDEV 4 /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 IDE */
/* Device parameters */
#define NUM_DEV_TTY 2
#include <tty.h>
#include <version.h>
#include <kdata.h>
+#include <blkdev.h>
#include <devfd.h>
#include <devsys.h>
#include <devlpr.h>
struct devsw dev_tab[] = /* The device driver switch table */
{
- /* 0: FIXME IDE */
- { fd_open, no_close, fd_read, fd_write, no_ioctl },
- /* 1: /dev/dd Hard disc block devices */
- { fd_open, no_close, fd_read, fd_write, no_ioctl },
- /* 2: /dev/tty TTY devices */
- { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
- /* 3: /dev/lpr Printer devices */
- { lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl },
- /* 4: /dev/mem etc System devices (one offs) */
- { no_open, no_close, sys_read, sys_write, sys_ioctl },
- /* Pack to 7 with nxio if adding private devices and start at 8 */
+ /* 0: /dev/hd Block device interface */
+ { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl}, /* 1: /dev/dd Hard disc block devices */
+ /* 1: /dev/fd Floppy disk block devices */
+ { fd_open, no_close, fd_read, fd_write, no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
+ /* 3: /dev/lpr Printer devices */
+ { lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl },
+ /* 4: /dev/mem etc System devices (one offs) */
+ { no_open, no_close, sys_read, sys_write, sys_ioctl },
+ /* Pack to 7 with nxio if adding private devices and start at 8 */
};
bool validdev(uint16_t dev)
{
- /* This is a bit uglier than needed but the right hand side is
- a constant this way */
- if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1)
- return false;
- else
- return true;
-}
-
-void device_init(void)
-{
- int i;
-#ifdef CONFIG_RTC
- /* Time of day clock */
- inittod();
-#endif
+ /* This is a bit uglier than needed but the right hand side is
+ a constant this way */
+ if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1)
+ return false;
+ else
+ return true;
}
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+void map_init(void)
+{
+}
+
+uint8_t maxpages = 16; /* 256K */
+/* Pages 0/1/2/3 are the kernel 4/5 are display and fonts */
+void pagemap_init(void)
+{
+ uint8_t i;
+ for (i = 6; i < maxpages; i += 2)
+ pagemap_add(i);
+}
+
+uint8_t platform_param(char *p)
+{
+ used(p);
+ return 0;
+}
+
+void device_init(void)
+{
+#ifdef CONFIG_RTC
+ /* Time of day clock */
+ inittod();
+#endif
+ devide_init();
+}
tty.rel
mm.rel
swap.rel
-bankfixed.rel
+bank32k.rel
vt.rel
font8x8_exp2.rel
devsys.rel
+platform-sam/atom.rel
+platform-sam/blkdev.rel
platform-sam/devfd.rel
platform-sam/devices.rel
+platform-sam/devide.rel
+platform-sam/devide_discard.rel
platform-sam/devlpr.rel
platform-sam/devtty.rel
+platform-sam/discard.rel
platform-sam/floppy.rel
platform-sam/main.rel
+platform-sam/mbr.rel
platform-sam/sam.rel
-platform-sam/tricks.rel
platform-sam/sam_vt.rel
+platform-sam/tricks.rel
-e
uint16_t ramtop = PROGTOP;
uint8_t need_resched;
-/* On idle we spin checking for the terminals. Gives us more responsiveness
- for the polled ports */
void platform_idle(void)
{
- __asm
- halt
- __endasm;
+ __asm
+ halt
+ __endasm;
}
void do_beep(void)
{
}
-void platform_interrupt(void)
-{
- tty_interrupt();
- kbd_interrupt();
- timer_interrupt();
-}
+__sfr __at 249 status;
-void map_init(void)
+void platform_interrupt(void)
{
+#if 0
+ if (status & 1)
+ line_interrupt();
+ if (status & 2)
+ mouse_interrupt();
+#endif
+ if (status & 4) {
+ timer_interrupt();
+ kbd_interrupt();
+ }
+ /* FIXME: figure out how tty interrupt needs to be handled */
+ tty_interrupt();
}
void platform_discard(void)
{
-}
-
-void pagemap_init(void)
-{
- pagemap_add(0x63); /* Mode 3, U64K low 32K mapped as low 32K */
- pagemap_add(0x73); /* Mode 3, U64K high 32K mapped as low 32K */
-}
-
-
-uint8_t platform_param(char *p)
-{
- used(p);
- return 0;
+ /* Buffer handling can happen here */
}
; -----------------------------------------------------------------------------
.area _DISCARD
-; colours - FIXME correct these
- .db 0,32,64,120
+ ; Mode 3 colour set we use
+ .byte 0x00 ; Black
+ .byte 0x40 ; Green
+ .byte 0x20 ; Red
+ .byte 0x70 ; White
clutmap:
+
init_early:
ld a, #0x44 ; Kernel is in 0/1 2/3, so video goes above it
; Video mode 3 (with luck)
_kernel_flag:
.db 1 ; We start in kernel mode
-low_map:
- .db KERNEL_LOW
low_save:
.db 0
video_save:
map_save_low:
push af
- ld a,(low_map)
+ in a,(250)
ld (low_save),a
pop af
; Fall through as we also map the kernel
map_kernel_low:
push af
ld a,#KERNEL_LOW
- ld (low_map),a
out (250),a
pop af
ret
map_user_low:
ld a,(U_DATA__U_PAGE)
map_page_low:
- ld (low_map),a
+ or #0x20 ; force ROM off
out (250),a
ret
map_video:
- ld a,(low_map)
+ in a,(250)
ld (video_save),a
ld a,#VIDEO_LOW
jr map_page_low
ld a,(hl) ; get the low page
call map_page_low
+ exx
; Copy the stub page into place
- ld hl, #stub_page
+ ld hl, #stub_page_1 - 1
ld de, #0x0000
ld bc, #0x0100
ldir
- jp map_kernel_low
+ exx
+ ; And then the high stubs from the kernel
+ inc hl
+ inc hl
+ ld a,(hl)
+ call map_page_low
+ ld hl,#stubs_high
+ ld de,#stubs_high-0x8000
+ ld bc,#0x0100
+ ldir
+
+ ; FIXME: we need to do the high stubs somewhere too
+ jp map_kernel_low
+;
; outchar: Wait for UART TX idle, then print the char in A
; destroys: AF
;
.area _PAGE0
;
-; Loaded into 00-FF in the bottom of the kernel and then into other
-; pages. There is an argument for putting most of this at the top of
-; the high page of everything. That might allow us to run CP/M
-; emulation
-;
-; Move what we can into PAGEH and high kernel code
-;
-; We'd still need some low space but we have 0A-3A/3B-4F/57-5B
-;
-; We can't deal with NMI in the CP/M case though.
+; This exists at the bottom of each process mapping we are using
;
; Starts at address 1 to avoid an SDCC flaw
;
-stub_page:
+stub_page_1:
stub0: .word 0 ; cp/m emu changes this
.byte 0 ; cp/m emu I/O byte
.byte 0 ; cp/m emu drive and user
jp 0 ; cp/m emu bdos entry point
rst8:
-_platform_copier_l:
+_platform_copier_l: ; Must be low
ld a,(hl)
out (251),a
exx
ldir
exx
- nop ; fall through
-rst10: ld a,#KERNEL_HIGH
+ and #0x60 ; preserve the colour bits
+ or #KERNEL_HIGH
out (251),a
ret
- nop
- nop
+syscall_stash:
+ .byte 0 ; must be low
nop
rst18:
_platform_doexec:
- out (251),a ; FIXME: trashing of clut high bits
+ out (251),a ; caller needs to handle CLUT bits
ei
jp (hl)
nop
nop
nop
nop
-rst28: jp syscall_path
+rst28: nop
nop
nop
nop
nop
nop
nop
-rst30: nop
nop
nop
+rst30: jp syscall_high
nop
nop
nop
nop
nop
-rst38: ; Interrupt handling stub
+;
+; We only have 38-4F available for this in low space
+;
+rst38: jp interrupt_high ; Interrupt handling stub
+ nop
+ nop
+ nop
+ nop
+ nop
+ ; 40
+ .ds 0x26
+nmi_handler: ; FIXME: check ends up at 0066
+ retn
+
+ .area _PAGEH
+
+stubs_high:
+;
+; High stubs. Present in each bank in the top 256 bytes
+;
+_platform_copier_h:
+ ld a,(hl)
+ out (251),a
+ exx
+ ldir
+ exx
+ and #0x60
+ or #KERNEL_HIGH
+ out (251),a
+ ret
+interrupt_high:
push af
push de
push hl
- ; FIXME: this trashes any clut overrides
- ld a,#KERNEL_HIGH
+ in a,(251)
+ and #0x60
+ or #KERNEL_HIGH
out (251),a
; Kernel is now the high map. Our stack may be invalid
; so be careful
call interrupt_handler
; On return HL = signal vector E= signal (if any) A = page for
; high
- ; FIXME 0 = kernel do we need to xlate ?
+ or a
+ jr nz, touser
+ ld a,#KERNEL_HIGH
+touser:
+ ld d,a
+ in a,(251)
+ and #0x60
+ or d
out (251),a
; stack is invalid again now
ld sp,(istack_switched_sp)
pop af
ei
ret
- nop
- nop
- nop
-nmi_handler: ; FIXME: check ends up at 0066
- retn
sigpath:
push de ; signal number
ld de,#irqsigret
inc sp
ret
-syscall_path:
+syscall_high:
push ix
- ;TODO : BC/DE/HL/IX off stack
- ; FIXME trashes the clut bits
- ld a,#KERNEL_HIGH
+ ld ix,#0
+ add ix,sp
+ ld a,4(ix)
+ ld b,6(ix)
+ ld c,7(ix)
+ ld d,8(ix)
+ ld e,9(ix)
+ ld h,10(ix)
+ ld l,11(ix)
+ push hl
+ ld h,12(ix)
+ ld l,13(ix)
+ pop ix
di
+ ld (syscall_stash),a
+ in a,(251)
+ and #0x60
+ or #KERNEL_HIGH
out (251),a
; Stack now invalid
ld (U_DATA__U_SYSCALL_SP),sp
ld sp,#kstack_top
call unix_syscall_entry
; FIXME check di rules
- ; On return A is the page (0 means kernel),
- ; FIXME: do we need to xlate
+ push bc
+ ld b,a
+ in a,(251)
+ and #0x60
+ or b
+ pop bc
out (251),a
; stack now invalid
ld sp,(U_DATA__U_SYSCALL_SP)
; FIXME for now do the grungy C flag HL DE stuff from
; lowlevel-z80 until we fix the ABI
ld bc,#0
+ ld a,h
+ or l
+ jr nz, error
+ ex de,hl
pop ix
+ ei
+ ret
+error: scf
+ pop ix
+ ei
ret
syscall_sigret:
push hl ; save errno
pop hl
ld h,#0 ; clear signal bit
ret
-
- .area _PAGEH
-;
-; High stubs. Present in each bank
-;
-_platform_copier_h:
- ld a,(hl)
- out (251),a
- exx
- ldir
- exx
- ld a,#KERNEL_HIGH
- out (251),a
- ret
.globl map_video
.globl unmap_video
.globl ___hard_di
- .globl _fontdata_8x8_exp2
+
+_fontdata_8x8_exp2 .equ 0xE000 ; in video bank
VIDEO_PAGE .equ 4
--- /dev/null
+-m
+-i setup.ihx
+setup.rel
+../font8x8_exp2.rel
+-e
+
--- /dev/null
+;
+; This block is loaded over the start of the video space we
+; will use and moves everything into the right places
+;
+; On entry our mapping is going to be
+; ROM 1 6 7
+;
+; Our kernel is in 2/3/4/5 and other bits in the start of 6 (ie us)
+; We use 7 as a buffer
+;
+;
+ .globl _fontdata_8x8_exp2
+
+ .area _BOOTSTRAP
+
+MODE3 .equ 0x40 ; I think ?
+
+bootstrap:
+ ; Blue border for debugging
+ ld a,#1
+ out (254),a
+;
+; The kernel low 32K is currently sitting in 4/5 not 0/1 so
+; move it. The upper 32K is already in 2/3
+;
+ ld de,#0x2420
+ call copy16k
+ ld de,#0x2521
+ call copy16k
+;
+; The font follows us and is 4K long but belongs in 4/5 after
+; the mode 3 screen
+;
+ ; Map bank 4/5 low
+ ld a,#0x24
+ out (250),a
+ ; Put the font data where it belongs
+ ld hl,#_fontdata_8x8_exp2
+ ld de,#0xE000-0x8000
+ ld bc,#0x1000
+ ldir
+;
+; In theory we are now ready to actually go live
+;
+ ; Put the video in the right place and set the mode
+ ld a,#4 + MODE3
+ out (252),a
+ xor a
+ ; Map the kernel low
+ out (250),a
+ ; Black border to hint where we got to
+ out (254),a
+ jp 0x100
+;
+; Move 16K via a bounce buffer
+;
+copy16k:
+ ld a,d ; soure bank
+ out (250),a
+ ld a,e
+ ld hl,#0x0000
+ ld de,#0xC000 ; buffer via bank 7
+ ld bc,#0x4000
+ ldir
+ out (250),a ; dest bank
+ ld hl,#0xC000
+ ld de,#0x0000
+ ld bc,#0x4000
+ ldir
+ ret