* don't support split I/D (different code/data page) at this point.
*
* Beyond that it's a normal banked platform. The oddities are that we
- * have no common, and that we must also swap the ZP/Stack separately
+ * have no common, and that we must also swap the Stack separately
* from bank 0, as well as the program bank.
*
- * Define MAP_SIZE for the space in the 64K available to the process,
- * this needs to be no more than 63.5K (udata and kstack copies...)
+ * Note: The code assumes we have the normal user map of 0x0000-0xFBFF
+ * then 512 bytes of udata material, then a gap then stubs and that we
+ * swap the full 64K minus stubs/gap. If we extend udata then stubs will
+ * end up getting swapped in the final block but it's R/O so nobody
+ * should care.
*/
#include <kernel.h>
#include <kdata.h>
#include <printf.h>
-#ifdef CONFIG_BANK_65C812
+#ifdef CONFIG_BANK_65C816
-uint16_t pzero[NPROC];
/* Kernel is 0, apps 1,2,3 etc */
static unsigned char pfree[MAX_MAPS];
static unsigned char pfptr = 0;
if (map == 0)
return ENOMEM;
blk = map * SWAP_SIZE;
- /* Write the kstack and zero page to disk */
- swapwrite(SWAPDEV, blk, 512, pzero[p-ptab], 0);
- /* Write the app (and possibly the uarea etc..) to disk */
- swapwrite(SWAPDEV, blk, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page);
+ /* Write the user CPU stack to disk */
+ swapwrite(SWAPDEV, blk, 512, (STACK_BANKOFF+(p-ptab)) << 8, 0);
+ /* Write the process including DP and C stack, plus the udata cache */
+ swapwrite(SWAPDEV, blk + 1, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page);
pagemap_free(p);
p->p_page = 0;
p->p_page2 = map;
kprintf("%x: nopage!\n", p);
return;
}
- /* Read the kstack and zero page from disk */
- swapread(SWAPDEV, blk, 512, pzero[p-ptab], 0);
+ /* Read the user stack from disk: FIXME - this is half a block
+ so we need to make sure our disk drivers can cope with this for
+ read (write is ok) */
+ swapread(SWAPDEV, blk, 256, (STACK_BANKOFF+(p-ptab)) << 8, 0);
/* Read the process back in */
- swapread(SWAPDEV, blk, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page);
+ swapread(SWAPDEV, blk + 1, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page);
#ifdef DEBUG
kprintf("%x: swapin done %d\n", p, p->p_page);
#endif
; The 65C816 memory management and switching logic is common
; to all systems so keep it all here
;
- .include "kernel.def"
+ .include "../platform/kernel.def"
.include "../kernel816.def"
- .include "zeropage.inc"
+ .include "../platform/zeropage.inc"
.export _switchout
.export _switchin
.export _dofork
.importzp ptr1
- .import jump_monitor
+ .import _trap_monitor
.import _chksigs
.import _platform_idle
+ .import _newproc
.import _nready
.import _inint
.import _getproc
.import outcharhex
.import outstring
- .segment "COMMONMEM"
+
+ .code
.p816
.i8
.a8
lda #U_DATA__TOTALSIZE-1 ; including our live stack
phb
switch_patch_1:
- mv KERNEL_BANK:0,0 ; save stack and udata
+ mvn KERNEL_FAR,0 ; save stack and udata
plb
sep #$30
- clz _inint
+ stz _inint
jsr _getproc ; x,a holds process
jsr _switchin ; switch to process
jsr _trap_monitor ; bug out if it fails
lda #U_DATA__TOTALSIZE-1
switch_patch_2:
; FIXME check syntax required for bank value ??
- mvn 0,KERNEL_BANK:0
+ mvn 0,KERNEL_FAR
; after the MVN our data bank is KERNEL_DATA
; Our stack is now valid and we may use it again, our UDATA
; is for the new process
ldx U_DATA__U_PTAB
cpx ptr1
bne switchinfail ; wrong process !!
- clz _runticks
+ stz _runticks
sep #$20
.a8
lda #P_RUNNING
stx sp
sep #$10
.i8
- lda U_DATA__U_INTERRUPT
+ lda U_DATA__U_ININTERRUPT
beq notisr
cli ; interrupts back on
notisr:
ldx #>badswitchmsg
jsr outstring
; something went wrong and we didn't switch in what we asked for
- jmp _ trap_monitor
-badswitchmsg: .byte "_switchin: FAIL"
- .byte 13, 10, 0
+ jmp _trap_monitor
+badswitchmsg:
+ .byte "_switchin: FAIL"
+ .byte 13, 10, 0
_dofork:
sta ptr1 ; new process ptr. U_DATA gives parent
stx ptr1+1
lda U_DATA__U_PAGE
sta fork_patch+2 ; source bank (parent)
- ldy #P_TAB__P_PAGE
+ ldy #P_TAB__P_PAGE_OFFSET
lda (ptr1),y
sta fork_patch+1 ; destination bank (child)
sta fork_patch_2+1
lda #MAP_SIZE ; 64K - udata shadow
phb
fork_patch:
- mvn 0,0 ; copy the entire bank
+ mvn 0,0 ; copy the entire bank below the save
ldx #U_DATA
ldy #U_DATA_STASH
- lda #U_DATA_TOTALSIZE-1
+ lda #U_DATA__TOTALSIZE-1
fork_patch_2:
- mvn KERNEL_BANK:0,0
+ mvn KERNEL_FAR,0
plb ; back to kernel bank
; At this point we have copied the parent into the child bank
plx ; discard frame we build for child
plx
- .sep #$30 ; back to 8bit mode for C
+ sep #$30 ; back to 8bit mode for C
.a8
.i8
lda ptr1
.I8
.A8
- .export unix_syscall_entry
.export _doexec
.export interrupt_handler
.export nmi_handler
+ .export map_process_always
+ .export map_kernel
+ .export _userpage
+
+ .export sigret_irq
+ .export sigret
+ .export syscall_vector
+
+ .export illegal_inst
+ .export trap_inst
+ .export abort_inst
+ .export emulation
.export outstring
.export outstringhex
.export outcharhex
.export outxa
- .export _userpage
-
.export _need_resched
+ .import istack_top
+ .import istackc_top
+ .import istack_switched_sp
+
+ .import kstack_top
+ .import kstackc_top
+
+ .import _ssig
+
.import outchar
.import _kernel_flag
.import _unix_syscall
- .import map_restore
- .import map_save
- .import map_process_always
- .import map_kernel
.import _platform_interrupt
.import platform_doexec
.import _inint
.import _trap_monitor
+ .import push0
+ .import incaxy
+
.include "platform/zeropage.inc"
.include "platform/kernel.def"
.include "kernel816.def"
- .segment "COMMONMEM"
+ .code
;
; Unlike Z80 we need to deal with systems that have no overlapping
; memory banks. We pass the arguments is a single pointer therefore
; stubs (syscall and signal return)
; - audit and begin testing
;
+
+syscall = $fe
+
;
; This is called from a stub we put into each user process bank that
; does a jsl to the kernel entry point then an rts
php ; save cpu mode of caller on ustack
sei ; interrupts off
cld ; get into sane mode - no decimal, known state
- sep $30
+ sep #$30
.a8
.i8
stx U_DATA__U_CALLNO
dey
dey
lda (ptr1),y ; copy the arguments over
- ld
- sta KERNEL_BANK:U_DATA__U_ARGN,x
+ sta KERNEL_FAR+U_DATA__U_ARGN,x
inx
inx
cpy #0
bne copy_args
noargs:
- rep #$30
- .a16
- .i16
+ sep #$30
+ .a8
+ .i8
+
lda #KERNEL_BANK ; our direct and base bank need setting
pha
plb
+
+ rep #$30
+ .a16
+ .i16
+
lda #KERNEL_DP
tcd
+
rep #$30
- .a8
- .i8
- rep #$10
+ .a16
.i16
+
ldx sp ; save the C stack
- pshx ; on the main stack
+ phx ; on the main stack
; FIXME: how to check stack space in brk when this is not visible ?
tsx
stx U_DATA__U_SYSCALL_SP
- ldx #kstack_top
+ ldx #kstack_top-1
txs ; set our CPU stack
- ldx #kstack_c ; set our C stack
+ ldx #kstackc_top-1 ; set our C stack
stx sp ;
cli ; sane state achieved
sep #$10
.i8
+
lda #1
sta _kernel_flag ; In kernel mode
cli ; Interrupts now ok
jsr _unix_syscall ; Enter C space
sei ; Interrupts back off
stz _kernel_flag
+
rep #$10
.i16
+
ldx U_DATA__U_SYSCALL_SP
txs ; Back to the old stack
; We can't restore sp yet as we are
; in the wrong bank
- .i8
sep #$10
+ .i8
+
lda U_DATA__U_CURSIG
bne signal_out
sep #$20
+ .a8
lda U_DATA__U_PAGE
- .a16
;
; We use this trick several times. U_PAGE holds the bank
; register. As we want our DP to be bank:0000 we need to
lda #0
tcd
+ rep #$20
+ .a16
pla ; pull the saved sp off the ustack
sta sp ; and store it 16bit
- rep #$20
- .a8
- plp ; off ustack
+ sep #$20
+ .a8
+ .i8
; We may now be in decimal !
ldy U_DATA__U_RETVAL
ldx U_DATA__U_RETVAL+1
; also sets z for us
lda U_DATA__U_ERROR
+ plp
rtl
;
; rts in bank return to the interruption point
;
signal_out:
- clz U_DATA__U_CURSIG
+ stz U_DATA__U_CURSIG
rep #$10
.i16
txs
sep #$10
.i8
- tax ; Save signal code in X
; Stack the signal return (the signal itself can cause syscalls)
; Be careful here stack ops are currently going to user stack but
; data ops to kernel. Don't mix them up!
- lda #>sigret ; needs to be a fixed address in user
- pha
- lda #<sigret ; FIXME
- pha
+ pea sigret
phx ; signal number
phy ; temporarily save C sp value
- txa
asl a ; vector offset
tay
- rep #$10
+ rep #$30
+ .a16
.i16
+ lda #0
ldx U_DATA__U_SIGVEC,y ; get signal vector
- clz U_DATA__U_SIGVEC,y ; and reset it
+ sta U_DATA__U_SIGVEC,y ; and reset it
ply ; get the temporary sp save back
phx
+ sep #$20
+ .a8
; Needs to change for split I/D
lda U_DATA__U_PAGE ; target code page
pha
- pea #PROGLOAD+20 ; trap handler in user app
+ pea PROGLOAD+20 ; trap handler in user app
pha
plb ; get the right user data bank
xba ; get into ff00 format
; registers and return directly to the start of the user process
;
_doexec:
- ; FIXME how do we find the correct cpu stack for this process
- ;
- ; Would (bank + offset) << 8 work ?
- sta _tmp1
- stx _tmp1+1
+ sta tmp1
+ stx tmp1+1
sei
stz _kernel_flag
rep #$30
.i16
.a16
- ldx _tmp1 ; target address
+ ldx tmp1 ; target address
sep #$20
.a8
lda U_DATA__U_PAGE ; get our bank
clc
adc #STACK_BANKOFF
xba ; swap to xx00
- lda #FF ; stack top is xxff
+ lda #$FF ; stack top is xxff
tcs ; Set CPU stack at xxFF
; Split I/D will need to change this logic
lda U_DATA__U_PAGE ; our bank
xba ; now in the form xx00 as we need
tcd ; set the user DP
; We are now on the correct DP and CPU stack
+ ; So fix up the syscall vector
+ ldy #syscall_vector
+ sty syscall
+ ; And the C stack pointer
ldy U_DATA__U_ISP
sty sp ; sp is in DP so we write user version
sep #$30
sep #$10
.i8
rtl
+
+;
+; The basic idea of taking a trap and signalling is to make sure we
+; look like an interrupt and can re-cycle much of that code. The
+; caller already saved the CPU state. Interrupts are off at this point
+; as it we got here via a trap.
+;
+shoot_myself:
+ sep #$30
+ .a8
+ .i8
+ lda #KERNEL_BANK
+ pha
+ plb
+ rep #$30
+ .a16
+ .i16
+ lda #IRQ_DP
+ tcd
+ tsx
+ stx istack_switched_sp
+ ldx #istack_top-1
+ txs
+ ldx #istackc_top -1
+ stx sp
+
+ ;
+ ; We have now arrived in kernel mappings for an interrupt
+ ;
+
+ sep #$30
+ .a8
+ .i8
+ jsr push0
+ lda #1
+ sta _inint
+ pla ; top of stack is the saved signal number
+ ldx #0
+ jsr _ssig
+ jmp join_interrupt_path
+
;
; The C world here is fairly ugly. We have to stash various bits of
; Switch stacks
tsx
stx istack_switched_sp
- ldx #istack
+ ldx #istack_top-1
txs
- ldx #istack_c ; set up C istack (may not need eventually)
+ ldx #istackc_top-1 ; set up C istack (may not need eventually)
stx sp
sep #$30
lda #1
sta _inint
jsr _platform_interrupt
+
+ ;
+ ; A synchronously delivered signal trap joins the interrupt
+ ; return flow
+ ;
+
+join_interrupt_path:
stz _inint
; Restore the stack we arrived on
; save the bank as a task switch or swap might move the
; process
;
- lda U_DATA_U_PAGE
+ lda U_DATA__U_PAGE
sep #$30
.a8
.a8
.i16
signal_exit:
- clz U_DATA__U_CURSIG
- sta _tmp1 ; save signal 8bits (irq tmp1)
+ stz U_DATA__U_CURSIG
+ sta tmp1 ; save signal 8bits (irq tmp1)
; Move down the stack frame
; A16
; X16
; Y16
- ; error
- ; retval
; sigret_irq
; signal number
;
tcs ; stick y in s
sep #$20
- .a8
- ;
- ; Stack the signal bits
- ;
- lda U_DATA__U_ERROR
- pha
- lda U_DATA__U_RETVAL
- pha
- lda U_DATA__U_RETVAL+1
- pha
- pea #sigret_irq
- ; sig nal return
+ pea sigret_irq ; signal return
sep #$10
.i8
phy ; signal code
asl a
tay
rep #$30
- .i16
.a16
- lda U_DATA__U_SIGVEC,y
- clz U_DATA__U_SIGVEC,y
- pha
+ .i16
+ lda #0
+ ldx U_DATA__U_SIGVEC,y
+ sta U_DATA__U_SIGVEC,y
+ phx
sep #$20
.a8
lda U_DATA__U_PAGE
.i16
ldx #0
txy
- pea #PROGLOAD+20
+ pea PROGLOAD+20
sep #$30
.i8
.a8
lda #$30 ; i8a8
pha
rti
+
+;
+; Trap handlers
+;
+illegal_inst:
+ rep #$30
+ .a16
+ .i16
+ pha
+ phx
+ ply
+ cld
+ lda #4
+sync_sig:
+ sep #$30
+ .a8
+ .i8
+ pha
+ jmp shoot_myself
+
+trap_inst:
+ rep #$30
+ .a16
+ .i16
+ pha
+ phx
+ ply
+ cld
+ lda #5
+ bra sync_sig
+
+abort_inst:
+ rep #$30
+ .a16
+ .i16
+ pha
+ phx
+ ply
+ cld
+ lda #7
+ bra sync_sig
+
;
; We can make the map routines generic as all 65c816 are the same
; mapping model. We don't change anything but instead track the page
; some custom swap logic in the disk drivers which is sucky but I
; don't currently have any better idea!
;
+
+ .a8
+ .i8
+
map_process_always:
lda U_DATA__U_PAGE
sta _userpage
map_process:
cmp #0
bne map_process_2
- cmpx #0
+ cpx #0
bne map_process_2
map_kernel:
rts
nmi_trap:
.byte "NMI!", 0
+emulation:
+ ldx #>emu_trap
+ lda #<emu_trap
+ jsr outstring
+ jmp _trap_monitor
+emu_trap:
+ .byte "EM!", 0
+
outstring:
sta ptr1
stx ptr1+1
_need_resched:
.byte 0
+
+
+;
+; Stubs get propogated into each segment at FF00
+;
+ .segment "STUBS"
+
+ .a8
+ .i8
+
+sigret:
+ sep #$30
+ plx ; pull the return and error code back
+ ply
+ pla
+ plp ; recover the flags
+ rts ; back to the interrupted syscall return
+
+
+sigret_irq:
+ rep #$30
+ .a16
+ .i16
+ ply
+ plx
+ pla
+ plp ; flags and status bits (back to 8/8 usually)
+ rts
+
+ .a8
+ .i8
+
+syscall_vector:
+ jsl KERNEL_FAR+syscall_entry
+ rts
+
CSRCS = devtty.c devhd.c
CSRCS += devices.c main.c
+LSRCS = ../lib/65c816.s
+LOBJS = $(patsubst ../lib/%.s,%.o, $(LSRCS))
+
ASRCS = v65.s crt0.s
-ASRCS += tricks.s commonmem.s
+ASRCS += commonmem.s
COBJS = $(CSRCS:.c=$(BINEXT))
AOBJS = $(ASRCS:.s=$(BINEXT))
-OBJS = $(COBJS) $(AOBJS)
+OBJS = $(COBJS) $(AOBJS) $(LOBJS)
JUNK = $(CSRCS:.c=.o) $(CSRCS:.c=.s) $(ASRCS:.s=.o)
$(AOBJS): %$(BINEXT): %.s
$(CROSS_AS) $(ASOPTS) $< -o $*$(BINEXT)
+$(LOBJS): %$(BINEXT): ../lib/%.s
+ $(CROSS_AS) $(ASOPTS) $< -o $*$(BINEXT)
+
clean:
rm -f $(OBJS) $(JUNK) core *~
$(CROSS_LD) -o ../fuzix.bin --mapfile ../fuzix.map -C ld65.cfg \
crt0.o commonmem.o \
v65.o ../start.o ../version.o ../lowlevel-65c816.o \
- ../lib/65c816.o main.o ../timer.o ../kdata.o devhd.o devices.o \
+ 65c816.o main.o ../timer.o ../kdata.o devhd.o devices.o \
../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
../syscall_proc.o ../syscall_other.o ../mm.o ../bank65c816.o \
../tty.o ../devsys.o ../syscall_fs2.o ../syscall_fs3.o \
../syscall_exec16.o ../usermem.o ../usermem_std-65c816.o devtty.o
- dd if=../fuzix.bin of=fuzix.img bs=512 skip=1
+ dd if=../fuzix.bin of=fuzix.img bs=512
\ No newline at end of file
Bank 0:
0x0000 Kernel DP
- 0x0100 UData + C stack
- 0x0200 Bootcode / Replaced with C stack
- 0x0300 CPU stack (kernel mode)
- 0x0400 Kernel image
+ 0x0100 UData + C stack etc
+ 0x0300 Bootcode
+ ... Kernel image
0xF700 7 x 256 byte CPU stacks for processes
0xFE00 I/O page
0xFF00 Vectors
TODO
----
+- Sort out memory map (move udata to 0100 and boot upwards)
+- Fix fork() to copy the user C stacks in dofork()
- Debug initial sketches
-- Add stubs and correct stub copier (+ syscall vector)
-- Add vectors correctly for the 816
-- Figure out how to set stacks up nicely
-- Test signal handling paths
- Fix brk() checking [right now its busted entirely]
+- Make discard sane so we can discard for buffers
+- Test signal handling paths
- Fix execl() execle() in userspace (so init can be fully tested)
- Add pre-emption logic to the interrupt return path
-- Fix fork() to copy the user C stacks in dofork()
- Add swap logic
Optimisations We Need To Do
.export _ub
.export _udata
.export kstack_top
+ .export kstackc_top
.export istack_top
+ .export istackc_top
.export istack_switched_sp
- .export CTemp
.segment "COMMONDATA"
.include "zeropage.inc"
+ .p816
+ .a8
+ .i8
+
+;
+; The udata for 65C816 is a bit different to 6502 as we have both a C
+; stack and a small CPU stack in the banking
;
-; In 6502 land these are the C stacks, we will need to handle the
-; hardware stack separately, and also to save sp,sp+1 etc on irqs
+; Our current layout is
+; [udata][cpu stack] in 256 bytes
+; [C stack] in 256 (will it be sufficient ?)
;
-; Declared as BSS so no non zero bytes here please
+; There is a separate IRQ DP, stack and C stack.
;
_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
_udata:
kstack_base:
- .res 512,0
+ .res 256,0
kstack_top:
-FIXME: C stack of 512 - udata, 65C816 stack follows
+kstackc_base:
+ .res 256,0
+kstackc_top:
;
; We have a single istack so we can stuff that anywhere we like
.bss
istack_base:
- .res 254,0
+ .res 64,0 ; should be tons
istack_top:
-FIXME: interrupt CPU stack (64 ?)
-istack_switched_sp: .word 0
+istackc_base:
+ .res 254,0 ; overkill - tune me
+istackc_top:
+istack_switched_sp:
+ .word 0
* if we add swap.
*/
#define CONFIG_BANK_65C816
+#define KERNEL_BANK 0
#define MAX_MAPS 7
#define MAP_SIZE 0xFC00 /* 0-FBFF */
+#define STACK_BANKOFF 0xF5 /* F600-FCFF */
+
#define TICKSPERSEC 10 /* Ticks per second */
#define MAPBASE 0x0000 /* We map from 0 */
#define PROGBASE 0x0100 /* also data base */
- ; imported symbols
- .import init_early
- .import init_hardware
- .import _fuzix_main
- .import kstack_top
- .import vector
- .import nmi_handler
-
- .import __BSS_RUN__, __BSS_SIZE__
- .importzp ptr1, ptr2, tmp1
-
- ; startup code @0
- .include "zeropage.inc"
+ ; imported symbols
+ .import init_early
+ .import init_hardware
+ .import _fuzix_main
+ .import kstack_top
+ .import kstackc_top
+ .import vector
+ .import nmi_handler
+ .import interrupt_handler
+ .import emulation
+ .import illegal_inst
+ .import trap_inst
+ .import abort_inst
+
+ .import __BSS_RUN__, __BSS_SIZE__
+ .importzp ptr1, ptr2, tmp1
+
+ ; startup code @0200
+ .include "kernel.def"
+ .include "../kernel816.def"
+ .include "zeropage.inc"
;
; So we end up first in the image
;
- .segment "START"
- .byte 65
- .byte 81
+ .segment "START"
+ .byte 65
+ .byte 81
- .a8
- .i8
- .p816
+ .p816
+ .a8
+ .i8
entry:
;
; We get run from bank 0, our I/O writes would otherwise need to be
; 24bit
;
- sep #$30 ; ensure we are in 8bit mode
- lda #'F'
- sta $FE20 ; signal our arrival
+ sep #$30 ; ensure we are in 8bit mode
+ lda #'F'
+ sta $FE20 ; signal our arrival
+
+ sei ; interrupts off
+ cld ; decimal off
- sei ; interrupts off
- cld ; decimal off
+ rep #$10
+ .i16
- rep #$10
- .i16
- ldx #kstack
- txs ; Stack (6502 not C)
+ ldx #kstack_top
+ txs ; Stack (6502 not C)
- lda #'u'
- sta $FE20
+ lda #'u'
+ sta $FE20
- ldx #kstack_top ; C stack
- sta sp
+ ldx #kstackc_top ; C stack
+ sta sp
- ldx #__BSS_RUN__
+ ldx #__BSS_RUN__
- lda #'z'
- sta $FE20
+ lda #'z'
+ sta $FE20
- txy
- iny
+ txy
+ iny
- ; Wipe the BSS
+ ; Wipe the BSS
- rep #$20
- .a16
- lda #__BSS_SIZE-2 ; must be >=2 bytes or else
- clz 0,x
- mvn 0,0
+ rep #$20
+ .a16
+ lda #__BSS_SIZE__-2 ; must be >=2 bytes or else
+ stz 0,x
+ mvn 0,0
- sep #$30
- .a8
- .i8
-
- lda #'i'
- sta $FE20
-
- lda #'x'
- sta $FE20
-
- jsr init_early
- lda #'.'
- sta $FE20
- jsr init_hardware
- lda #13
- sta $FE20
- lda #10
- sta $FE20
- jmp code
+ sep #$30
+ .a8
+ .i8
+
+ lda #'i'
+ sta $FE20
+
+ lda #'x'
+ sta $FE20
+
+ jsr init_early
+ lda #'.'
+ sta $FE20
+ jsr init_hardware
+ lda #13
+ sta $FE20
+ lda #10
+ sta $FE20
+ jmp code
; The above gets blasted into udata space
- .code
+ .code
code:
- rep #$30
- .a8
- .i8
- ldx #$U_DATA
- ldy #$U_DATA+1
- lda #$UDATA_TOTALSIZE-2
- clz 0,x
- mvn 0,0
-
- sep #$30
- .a8
- .i8
-
- jsr _fuzix_main ; Should never return
- sei ; Spin
-stop: jmp stop
-
- .segment "VECTORS"
- .addr vector
- .addr $0202 ; does it matter ???
- .addr nmi_handler
+ rep #$30
+ .a16
+ .i16
+
+ ldx #U_DATA
+ ldy #U_DATA+1
+ lda #U_DATA__TOTALSIZE-2
+ stz 0,x
+ mvn 0,0
+
+ sep #$30
+ .a8
+ .i8
+
+ jsr _fuzix_main ; Should never return
+ sei ; Spin
+stop: bra stop
+
+
+;
+; Processor vector table (0xFFE0)
+;
+ .segment "VECTORS"
+
+
+ .word 0 ; unused
+ .word 0 ; unused
+ .word illegal_inst ; COP
+ .word trap_inst ; BRK
+ .word abort_inst ; ABORT
+ .word nmi_handler ; NMI
+ .word 0 ; Unused (native reset)
+ .word interrupt_handler
+
+ ;
+ ; Emulation mode vectors. If called badness occurred
+ ;
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+
+
#include <printf.h>
#include <devhd.h>
-extern uint8_t hd_map;
+extern uint8_t hd_kmap;
extern void hd_read_data(uint16_t addr);
extern void hd_write_data(uint16_t addr);
return -1;
/* For swap it'll be the swap bank passed */
- hd_map = rawflag ? udata.u_page : KERNEL_BANK;
+ hd_kmap = rawflag ? udata.u_page : KERNEL_BANK;
dptr = (uint16_t)udata.u_dptr;
nb = udata.u_nblock;
; UZI mnemonics for memory addresses etc
; (this is struct u_data from kernel.h)
-U_DATA .set $0100 ; stomps over bootstrap
+U_DATA .set $0100 ; stomps over bootstrap
; 256+256+256 bytes. (U, kstack copy, k C stack copy)
-U_DATA__TOTALSIZE .set $300
-U_DATA_STASH .set $FC00 ; leaves FFxx for vectors and stubs
+U_DATA__TOTALSIZE .set $300
+U_DATA_STASH .set $FC00 ; leaves FFxx for vectors and stubs
-PROGLOAD .set $0200
-ZPBASE .set $0
+PROGLOAD .set $0200
+ZPBASE .set $0
+
+KERNEL_BANK .set $0 ; bank number
+KERNEL_FAR .set $000000 ; 24 bit
+
+; Add this to the bank number to get the high 8bits of the 16bit CPU stack
+; for this process
+STACK_BANKOFF .set $F5 ; F600-FCFF
+; Direct page for IRQ processing (saves us saving/restoring DP registers)
+; Can probably use the same page as the IRQ CPU stack... FIXME
+IRQ_DP .set $FD ; FD00-FDFF
+KERNEL_DP .set $00 ; We use the real ZP for kernel DP
+
+MAP_SIZE .set $FC00
\ No newline at end of file
MEMORY {
RAMZ: start = $0000, size = $0100, type = rw, fill = yes;
- STACK: start = $0100, size = $0100, type = rw, fill = yes;
- BOOT: start = $0200, size = $0200, type = rw, fill = yes;
- MAIN: start = $0400, size = $F300, type = rw, fill = yes;
+ UDATA: start = $0100, size = $0200, type = rw, fill = yes;
+ MAIN: start = $0300, size = $F400, type = rw, fill = yes;
USTACKS:start = $F700, size = $0700, type = rw, fill = yes;
IO: start = $FE00, size = $0100, type = rw, fill = yes;
- VECTOR: start = $FFF0, size = $0010, type = rw, fill = yes;
+ STUB: start = $FF00, size = $00E0, type = rw, fill = yes;
+ VECTOR: start = $FFE0, size = $0020, type = rw, fill = yes;
}
SEGMENTS {
ZEROPAGE: load = RAMZ, type = zp, define = yes;
- COMMONDATA: load = MAIN, type = bss;
+ COMMONDATA: load = UDATA, type = bss;
+
+ START: load = MAIN, type = ro;
CODE: load = MAIN, type = ro, define = yes;
RODATA: load = MAIN, type = ro;
- START: load = BOOT, type = ro;
-
DATA: load = MAIN, type = rw, define = yes;
BSS: load = MAIN, type = bss, define = yes;
DISCARD: load = MAIN, type = ro;
DISCARDDATA: load = MAIN, type = ro;
+ STUBS: load = STUB, type = ro;
VECTORS: load = VECTOR, type = ro;
}
#include <devtty.h>
uint8_t kernel_flag = 1;
+uint16_t ramtop = PROGTOP;
void platform_idle(void)
{
}
/*
- * Map handling: We have flexible paging. Each map table consists of a set of pages
- * with the last page repeated to fill any holes.
+ * 7 banks, kernel in bank 0
*/
void pagemap_init(void)
{
int i;
/* Bank 0 is the kernel */
- for (i = 15 ; i > 0; i--)
- pagemap_add(i * 8);
+ for (i = 7 ; i > 0; i--)
+ pagemap_add(i);
}
void map_init(void)
-export CPU = 658C16
+export CPU = 65c816
.export ___hard_di
.export ___hard_ei
.export ___hard_irqrestore
- .export vector
.import _ramsize
.import _procmem
.import nmi_handler
- .import unix_syscall_entry
+ .import syscall_vector
.import kstack_top
.import istack_switched_sp
.import istack_top
- .import _unix_syscall
- .import _platform_interrupt
.import _kernel_flag
.import pushax
.import outxa
.import incaxy
- .import _create_init_common
-
.include "kernel.def"
.include "../kernel816.def"
.include "zeropage.inc"
+ .p816
+ .a8
+ .i8
;
; syscall is jsr [$00fe]
;
sei
rts
+;
+; This could go in discard once we make that useful FIXME
+;
init_early:
- ; copy the stubs from bank 0 to all banks so we can keep the
- jsr _create_init_common
+ lda #1
+init_loop:
+ sep #$30
+ .a8
+ .i8
+ sta common_patch+1 ; destination bank
+ phb ; save our bank (mvn will mess it)
+ pha ; and count
+
+ rep #$30
+ .a16
+ .i16
+ ldx #$FF00
+ txy
+ lda #$00FE
+common_patch:
+ mvn KERNEL_FAR,0 ; copy the block
+ pla
+ plb ; bank to kernel bank
+ dec
+ cmp #8
+ bne init_loop
rts
+ .a8
+ .i8
+
init_hardware:
; set system RAM size for test purposes
rep #$10
stx _ramsize
ldx #512-64
stx _procmem
- ; TODO - correct vectors for the 816
- ldx #vector
- stx $FFFE
- ldx #<nmi_handler
- stx $FFFA
- ldx #syscall_entry
- stx #syscall
+ ldx #syscall_vector
+ stx syscall
rep #$10
.i8
; I/O logic
;
+ .export _hd_kmap
+ .export _hd_read_data
+ .export _hd_write_data
;
; Disk copier (needs to be in common), call with ints off
lda _hd_kmap ; page number
pha
plb ; data now points into user app
- ldy #00FE
+ ldy #$00FE
phy
pld ; DP is now the I/O space
ldy #512
+hd_read:
lda $34 ; I/O data via DP
sta 0,x ; stores into data (user) bank
inx
lda _hd_kmap ; page number
pha
plb ; data now points into user app
- ldy #00FE
+ ldy #$00FE
phy
pld ; DP is now the I/O space
ldy #512
+hd_write:
lda 0,x ; load from data (user) bank
sta $34 ; I/O data via DP
inx
dey
- bne hd_read
+ bne hd_write
plb ; restore bank registers
pld
sep #$10
.bss
-_hd_map:
+_hd_kmap:
.res 1
.import outxa, popax
.importzp ptr2, tmp2
+
+ .p816
+ .a8
+ .i8
+
;
; ptr1 and tmp1 are reserved for map_* functions in 6502 but
; are actually free here. We keep the convention however in case
; of future changes
;
- .segment "COMMONMEM"
+ .code
; user, dst, count(count in ax)
;
beq ug_nomov ; 0 means 64K!
dec ; need 1 less than size
ugetpatch:
- mvn 0,KERNEL_BANK:0
+ mvn 0,KERNEL_FAR
ug_nomov:
.i8
.a8
ldy #0 ; counter
ldx tmp2+1 ; how many 256 byte blocks
- beq __uget_tail ; if none skip to the tail
+ beq __ugets_tail ; if none skip to the tail
__ugets_blk:
phb
beq up_nomov ; 0 means 64K!
dec ; need 1 less than size
uputpatch:
- mvn KERNEL_BANK:0,0
+ mvn KERNEL_FAR,0
up_nomov:
.i8
.a8
phb
pha
plb
- clz (ptr2)
+ lda #0
+ sta (ptr2)
plb
phb