0000-3FFF Fuzix
4000-7FFF Fuzix
-8000-BFFF Fuzix + Bootstrap
-C000-FFFF Bootloader data
-
+8000-BFFF Fuzix
+C000-FFFF Copy of common and other areas for C000-FFFF in RAM
Running
Kernel mode
-0000-BFFF Fuzix
-C000-FFFF Kernel data + RAM helpers if needed
+0000-BFFF Fuzix(Cartridge)
+C000-FFFF Kernel common and data
User mode
-0000-BFFF Process bank
-C000-FFFF Kernel data + RAM helpers
+0000-BFFF Process bank (with stubs in spare low bytes)
+C000-FFFF Kernel common and data
Difficulties
- Have to map 0x4000-7FFF to a device for some I/O devices so we can't
always directly do I/O to user space. Kernel buffers are high so ok.
- Kernel I/O routines can live in other 16K chunks
+ Kernel I/O routines can live in other 16K chunks or common.
- We have to load the cartridge header at 0x4000 or 0x8000 - neither is at
all convenient!
limited mapping system.
Speed up all the ei/di mess by just keeping a private variable for irqoff
state
+Get common and discard and initialized in C000-FFFF of the ROM and copied
+out
In Progress
Move the switch helper into both banks so we can fix the FIXME in map_kernel
-
Work out how map/unmap an I/O device needs to work to be usable. Do we grab
the live map and just edit it for 4000-7FFF then set that map ? Do we
precompute and save kernel and user maps for the device ?
-
Sunrise IDE support
To do
some awkward corner cases (constants) going K->U. So we can spot the to user
case of a 'low' source and bounce it or similar, while just doing a user
map and ldir for the others. We badly need the cached path walk though!
-Get common and discard and initialized in C000-FFFF of the ROM
-Then on boot up move SP to BFFF, map the ROM in the top 16K, copy it into
-8000-Bxxx and then restore the RAM, and copy it up. Then do the normal maps.
-Otherwise we are going to run out of space at some point.
Remember current map for kernel/user so we can fast track map_save/restore
map_kernel etc by knowing if we are mapping k->k u->u or a transition and
we can label all other cases with a value meaning 'other' as we don't need
.globl kstack_top
;
-; We are running in an unknown subslot of an unknown bank and
-; have 4000-BFFF mapped to us, BIOS (0:0) in the low 16K and
+; We are running in an unknown subslot of an unknown slot and
+; have 4000-7FFF mapped to us, BIOS (0:0) in the low 16K and
; RAM ought to be in the top 16K because the BIOS needs it. We
; can't btw even assume that all the RAM is in the same bank - what a
; mess!
SLTTBL .equ 0xFCC5
SLTATR .equ 0xFCC9
-
pstring:
ld a,(hl)
or a
expan: .asciz 'expanded'
-wtfami: ld sp,#0xF000 ; random free space in known RAM
+wtfami: ld sp,#0xF380 ; below system variables
;
; Initialize the debug port
;
ld hl,#hello
call pstring
+ ; We'd like the use the ROM services but unfortunately they
+ ; don't actually work for the top 16K in MSX
+
+ ld ix,#0xffff ; subslot control byte
+
di
+ ld a,(ix)
+ cpl ; remember the old subslot mapping
+ ; for the RAM top 16K
+ ld e,a
+ in a,(0xA8)
+ ld d,a ; Remember the old slot mapping
+ and #0x0C ; This is the mapping for the cartridge
+ rla
+ rla
+ rla ; move it to the top 2 bits
+ rla
+ ld b,a
+ in a,(0xA8)
+ and #0x3F
+ or b
+ ld b,a
+ out (0xA8),a ; cartridge mapped in top 16K not stack
+ ld a,(ix)
+ cpl
+ and #0x0c ; cartridge subslot if any
+ rla
+ rla
+ rla
+ rla
+ ld c,a ; save the bits
+ ld a,(0xffff)
+ cpl
+ and #0x3f ; mask off top 16K map
+ or c
+ ld c,a
+
+ ; At this point D/E get us the RAM mapping
+ ; C/B the ROM mapping
+ ; We could both be in the same slot so we have to do all the
+ ; painful stupid stuff 8(
+
+ ld a,d
+ out (0xA8),a
+ ld (ix),e
+
+ ld a,d
+ call phex
+ ld a,e
+ call phex
+ ld a,b
+ call phex
+ ld a,c
+ call phex
+ exx
+
+ ld hl,#0xC000
+ ld bc,#0x3300
+
+copy_common_loop:
+ exx ; Paging values
+ ld a,b ; Map cartridge
+ out (0xA8),a
+ ld (ix),c
+ exx ; Work values
+ ld e,(hl) ; Fetch byte
+ exx ; Paging values
+ ld a,d ; Map RAM
+ out (0xA8),a
+ ld (ix),e
+ exx ; Work values
+ ld (hl),e ; Save to RAM
+ inc hl ; Move on
+ dec bc
+ ld a,b
+ or c
+ jr nz, copy_common_loop
+
+ ; RAM is what is left mapped
+
;
; Save a few things before we give the ROM the boot
; We keep them in the alt registers
; Begin by setting up our RAM as a normal ROM based SDCC
; process (for a change!)
- ld hl,#s__INITIALIZER
- ld de,#s__INITIALIZED
- ld bc,#l__INITIALIZER
- ldir
- ; Now unpack the common space
- ld de,#s__COMMONMEM
- ld bc,#l__COMMONMEM
- ldir
- ; Wipe the BSS area
- ld hl,#s__DATA
- ld d,h
- ld e,l
- ld (hl),#0
- ld bc,#l__DATA
- inc de
- dec bc
- ldir
+; ld hl,#s__INITIALIZER
+; ld de,#s__INITIALIZED
+; ld bc,#l__INITIALIZER
+; ldir
+; ; Now unpack the common space
+; ld de,#s__COMMONMEM
+; ld bc,#l__COMMONMEM
+; ldir
+; ; Wipe the BSS area
+; ld hl,#s__DATA
+; ld d,h
+; ld e,l
+; ld (hl),#0
+; ld bc,#l__DATA
+; inc de
+; dec bc
+; ldir
; Switch to the right stack
ld sp,#kstack_top
call init_early
#define BOOTDEVICENAMES "hd#,fd,,rd"
//#define CONFIG_DYNAMIC_BUFPOOL /* we expand bufpool to overwrite the _DISCARD segment at boot */
-#define NBUFS 6 /* Number of block buffers, keep in line with space reserved in zeta-v2.s */
+#define NBUFS 5 /* Number of block buffers, keep in line with space reserved in zeta-v2.s */
#define NMOUNTS 2 /* Number of mounts at a time */
#define MAX_BLKDEV 2 /* IDE or SD ?? */
.area _HOME
.area _VIDEO
.area _CONST
- .area _DISCARD
- ; ROM section must end with the initializer
- .area _INITIALIZER
- ; These are unpacked
+ ; RAM based
.area _COMMONMEM
.area _INITIALIZED
.area _GSINIT
.area _BSS
.area _HEAP
.area _DATA
+ ; Need to do dynamic buffers yet
+ .area _DISCARD
+ .area _INITIALIZER
- ; 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__COMMONMEM
- .globl l__COMMONMEM
- .globl s__INITIALIZER
- .globl kstack_top
.globl interrupt_handler
.globl null_handler
+ .globl do_set_sub_slot
+ .globl do_get_sub_slot
+
.globl rst38 ; for checking
;
; First _CODE section
;
-; We need to put the bank switch stub in here and matching in RAM
+; We put the bank switch stub in here and matching in RAM
;
.area _CODE
start: jp null_handler
.ds 0x35
rst38: jp interrupt_handler
- ; FIXME NMI etc ?
+ ; We only have 0x3B-0x4F free
+do_set_sub_slot:
+ in e,(c) ; Get bank map
+ out (c),b ; Set bank map
+ ld (hl),a ; Set slots
+ jr do_get_sub_slot_2
+do_get_sub_slot:
+ in e,(c)
+ out (c),b
+do_get_sub_slot_2: ; Get complemented slot bits
+ ld a,(hl)
+ out (c),e
+ ret
+ ; 4A-4F free
+
+; Just so we don't pack the binary
+
+ .area _PAGE0
keyrepeat.first = 2 * ticks_per_dsecond;
keyrepeat.continual = 1 * ticks_per_dsecond;
-// sunrise_probe(2,3);
+ sunrise_probe(1,0xFF);
}
uint8_t *rp;
uint8_t i;
uint8_t pp;
+ uint8_t cp;
const char *vdpname = "??";
if (vdptype < 3)
vdpname = vdpnametab[vdptype];
+ cp = bp[5] & 3;
+
kprintf("VDP %s@%x\n", vdpname, vdpport);
kprintf("Subslots %x\n", subslots);
-
- kprintf("Kernel map %x %x %x %x %x %x\n",
+ kprintf("Cartridge in slot %d", cp);
+ if (subslots & (1 << cp))
+ kprintf(".%d", bp[cp] & 3);
+ kprintf("\nKernel map %x %x %x %x %x %x\n",
*bp, bp[1], bp[2], bp[3], bp[4], bp[5]);
bp = current_map;
void platform_discard(void)
{
/* Until we tackle the buffers */
+ /* Use the old discard space to bounce the vectors to user pages */
+ copy_vectors();
}
/*
.globl init_hardware
.globl interrupt_handler
.globl _program_vectors
+ .globl _copy_vectors
.globl _set_initial_map
.globl _need_resched
.globl _platform_reboot
.globl nmi_handler
.globl null_handler
- .globl map_process
+ .globl map_process_always
.globl map_kernel
.globl _vdp_load_font
;
.globl vdpinit
+ .globl s__DISCARD
+
.include "kernel.def"
.include "../kernel-z80.def"
init_early:
ld a, #'*'
out (0x2F), a
+ ld a, #'-'
+ call outchar
; called with e'=vdp d'=machine type
; HL info bits
exx
; Program the video engine
ld bc,(_vdpport)
- ; Play with statius register 2
+ ; Play with status register 2
dec c
ld a,#0x8F
out (c),a
ret
+_program_vectors:
+ ret
;------------------------------------------------------------------------------
; COMMON MEMORY PROCEDURES FOLLOW
.area _COMMONMEM
-
-_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
-
- ; At this point the common block has already been copied
- call map_process
-
- ; write zeroes across all vectors
- ; on MSX this is probably the wrong thing to do!!! FIXME
- ld hl, #0
- ld de, #1
- ld bc, #0x007f ; program first 0x80 bytes only
- ld (hl), #0x00
- ldir
-
- ; now install the interrupt vector at 0x0038
- ld a, #0xC3 ; JP instruction
- ld (0x0038), a
- ld hl, #interrupt_handler
- ld (0x0039), hl
-
- ; set restart vector for 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 (0x0066), a ; Set vector for NMI
- ld hl, #nmi_handler
- ld (0x0067), hl
- jp map_kernel
-
; emulator debug port for now
outchar:
push af
pop af
ret
+_copy_vectors:
+ ld hl,#0
+ ld de,#s__DISCARD
+ ld bc,#256
+ ldir
+ call map_process_always
+ dec h ; pointers back
+ dec d
+ inc b ; bc = 256
+ ex de,hl ; swap so we copy back
+ ldir ; into user
+ jp map_kernel
#
-# Push the execve code high to make room
-#
export CROSS_CC_SEG1=--codeseg CODE2
-export CROSS_CC_SEG2=--codeseg CODE
+export CROSS_CC_SEG2=--codeseg CODE2
export CROSS_CC_SEG3=--codeseg CODE
-export CROSS_CC_VIDEO=--codeseg CODE
-export CROSS_CC_FONT=--codeseg CODE
+export CROSS_CC_VIDEO=--codeseg CODE2
+# We load the font at start up
+export CROSS_CC_FONT=--codeseg DISCARD --constseg DISCARD
#
export CROSS_CC_SYS1=--codeseg CODE
-export CROSS_CC_SYS2=--codeseg CODE2
+export CROSS_CC_SYS2=--codeseg CODE
export CROSS_CC_SYS3=--codeseg CODE2
export CROSS_CC_SYS4=--codeseg CODE2
-export CROSS_CC_SYS5=--codeseg COMMONMEM
+export CROSS_CC_SYS5=--codeseg CODE
export CROSS_CC_SEGDISC=--codeseg DISCARD
.globl _ramsize
.globl _procmem
.globl ___hard_di
+ .globl outcharhex
+
+;
+; Our helpers put the top bank back before returning so the rest
+; can be generalized in common space
+;
+ .area _COMMONMEM
+
+ .globl _switch_map
+ .globl _current_map
+ .globl map_kernel
+ .globl map_kernel_di
+ .globl map_process_always
+ .globl map_process_always_di
+ .globl map_process
+ .globl map_save_kernel
+ .globl map_restore
+ .globl _set_initial_map
+ .globl _map_slot1_kernel
+ .globl _map_slot1_user
+ .globl find_ram
+ .globl _ramtab
+ .globl _kernel_map
+ .globl _user_map
+ .globl _current_map
+
+ .globl _subslots
+ .globl _int_disabled
+
+ .globl do_set_sub_slot
+ .globl do_get_sub_slot
;
; Memory banking for a 'simple' MSX 1 system. We have Fuzix in a
; other non MSX2 style mappers. (For an MSX2 mapper it would I think
; be better to teach the MSX2 code about different VDP options).
;
-; This is our little helper that needs to live low down. It expects
-; interrupts to be *off*
+; Call our little helper who lives low down. It expects interrupts to be
+; *off*. The stack will be in the top 16K so care is neeed.
;
; Entry
; B = computed slot mask
; Return
; A = result of subslot set
;
-
- .area _LOW
+;
set_sub_slot:
push bc
push de
+ push hl
ld c,#0xA8
- in e,(c)
- out (c),b ; map the thing we need to set subslots for
- ; into the top 16K
- ld (0xFFFF),a ; subslot info
- ld a,(0xFFFF) ; report back the effect
- cpl ; remembering it's complemented
- out (c),e
+ ld hl,#0xffff
+ call do_set_sub_slot
+ cpl
+ pop hl
pop de
pop bc
ret
get_sub_slot:
push bc
push de
+ push hl
ld c,#0xA8
- in e,(c)
- out (c),b ; map the thing we need to set subslots for
- ; into the top 16K
- ld a,(0xFFFF) ; report back the effect
- cpl ; remembering it's complemented
- out (c),e
+ ld hl,#0xffff
+ call do_get_sub_slot
+ cpl
+ pop hl
pop de
pop bc
ret
-;
-; Our helpers put the top bank back before returning so the rest
-; can be generalized in common space
-;
- .area _COMMONMEM
-
- .globl _switch_map
- .globl _current_map
- .globl map_kernel
- .globl map_kernel_di
- .globl map_process_always
- .globl map_process_always_di
- .globl map_process
- .globl map_save_kernel
- .globl map_restore
- .globl _set_initial_map
- .globl _map_slot1_kernel
- .globl _map_slot1_user
- .globl find_ram
- .globl _ramtab
- .globl _kernel_map
- .globl _user_map
- .globl _current_map
- .globl _subslots
- .globl _int_disabled
;
; Switch to the map pointed to by HL.
push bc
push de
ld a,#'['
- out (0x2F),a
+; out (0x2F),a
in a,(0xA8)
and #0x3F ; Keep the lower selections
ld b,a ; the same
cp (hl)
jr z, subslot_done ; same subslots
ld a,b
- call phex
+; call outcharhex
ld a,(hl)
- call phex
+; call outcharhex
; Do set
call set_sub_slot
ld (de),a ; update map
ld (de),a
out (0xA8),a
ld a,#']'
- out (0x2F),a
+; out (0x2F),a
pop de
pop bc
pop af
call map_kernel_di ; FIXME: fast path this later
ret
-; This is messy because of the NMOS Z80 IRQ bug. It might be worth
-; revisiting all the logic that uses this and just keeping a software flag
-; instead.
;
; The expensive bank switching also means we need to write some custom
; usermem copiers.
map_kernel:
push af
push hl
+ di
ld a,(_int_disabled)
push af
xor a
; kernel low mapping back. FIXME: if the kernel cartridge and
; RAM are in the same subslot this will break. Need to put the flip
; code in the low 256 bytes of both.
+ ; (DONE OK now I think)
ld a,(_kernel_map+5)
out (0xA8),a
ld hl,#_kernel_map
map_process_always:
push af
push hl
+ di
ld a,(_int_disabled)
push af
ld a,#1
ld a,l
; First step: Update the slot register in the map
and #0x03 ; slot
- rlca
- rlca
+ rla
+ rla
ld e,a
- ld a, (_scratch_map + 4) ; slot register
+ ld a, (_scratch_map + 5) ; slot register
and #0xF3
or e
- ld (_scratch_map + 4),a ; slot register with us in bank 1
+ ld (_scratch_map + 5),a ; slot register with us in bank 1
ld e,a ; Save it in E
ld a,l
bit 7,a
_ramtab:
.ds 6
-
-dophex: ld c,a
- and #0xf0
- rrca
- rrca
- rrca
- rrca
- call pdigit
- ld a,c
- and #0x0f
-pdigit: cp #10
- jr c,isl
- add #7
-isl: add #'0'
- out (0x2F),a
- ret
-
-phex:
- push af
- push bc
- call dophex
- ld a,#' '
- out (0x2f),a
- pop bc
- pop af
- ret