From cc67d8951dfcc16ca29ae70c9152935a4eb02bb7 Mon Sep 17 00:00:00 2001 From: Brett Gordon Date: Wed, 17 Jun 2015 12:07:05 +0100 Subject: [PATCH] CoCo3 Fuzix (take two) UDATA/Banking is still non-ideal. DriveWire virtual terminal still need help. Stupid Comments fixed devlpr removed --- Kernel/platform-coco3/AUTOEXEC.BAS | 2 + Kernel/platform-coco3/Makefile | 55 +++++ Kernel/platform-coco3/README | 133 +++++++++++ Kernel/platform-coco3/boot/boot.s | 212 +++++++++++++++++ Kernel/platform-coco3/build | 43 ++++ Kernel/platform-coco3/coco3.s | 307 ++++++++++++++++++++++++ Kernel/platform-coco3/commonmem.s | 29 +++ Kernel/platform-coco3/config.h | 77 ++++++ Kernel/platform-coco3/crt0.s | 37 +++ Kernel/platform-coco3/device.h | 5 + Kernel/platform-coco3/devices.c | 44 ++++ Kernel/platform-coco3/devtty.c | 331 ++++++++++++++++++++++++++ Kernel/platform-coco3/devtty.h | 7 + Kernel/platform-coco3/drivewire.s | 169 +++++++++++++ Kernel/platform-coco3/dw.def | 70 ++++++ Kernel/platform-coco3/dwread.s | 341 +++++++++++++++++++++++++++ Kernel/platform-coco3/dwwrite.s | 196 +++++++++++++++ Kernel/platform-coco3/fuzix.link | 14 ++ Kernel/platform-coco3/kernel.def | 22 ++ Kernel/platform-coco3/libc.c | 36 +++ Kernel/platform-coco3/main.c | 37 +++ Kernel/platform-coco3/target.mk | 1 + Kernel/platform-coco3/tricks.s | 273 +++++++++++++++++++++ Kernel/platform-coco3/ttydw.c | 86 +++++++ Kernel/platform-coco3/ttydw.h | 8 + Kernel/platform-coco3/usermem_gime.s | 135 +++++++++++ 26 files changed, 2670 insertions(+) create mode 100644 Kernel/platform-coco3/AUTOEXEC.BAS create mode 100644 Kernel/platform-coco3/Makefile create mode 100644 Kernel/platform-coco3/README create mode 100644 Kernel/platform-coco3/boot/boot.s create mode 100755 Kernel/platform-coco3/build create mode 100644 Kernel/platform-coco3/coco3.s create mode 100644 Kernel/platform-coco3/commonmem.s create mode 100644 Kernel/platform-coco3/config.h create mode 100644 Kernel/platform-coco3/crt0.s create mode 100644 Kernel/platform-coco3/device.h create mode 100644 Kernel/platform-coco3/devices.c create mode 100644 Kernel/platform-coco3/devtty.c create mode 100644 Kernel/platform-coco3/devtty.h create mode 100644 Kernel/platform-coco3/drivewire.s create mode 100644 Kernel/platform-coco3/dw.def create mode 100644 Kernel/platform-coco3/dwread.s create mode 100644 Kernel/platform-coco3/dwwrite.s create mode 100644 Kernel/platform-coco3/fuzix.link create mode 100644 Kernel/platform-coco3/kernel.def create mode 100644 Kernel/platform-coco3/libc.c create mode 100644 Kernel/platform-coco3/main.c create mode 100644 Kernel/platform-coco3/target.mk create mode 100644 Kernel/platform-coco3/tricks.s create mode 100644 Kernel/platform-coco3/ttydw.c create mode 100644 Kernel/platform-coco3/ttydw.h create mode 100644 Kernel/platform-coco3/usermem_gime.s diff --git a/Kernel/platform-coco3/AUTOEXEC.BAS b/Kernel/platform-coco3/AUTOEXEC.BAS new file mode 100644 index 00000000..957b7be0 --- /dev/null +++ b/Kernel/platform-coco3/AUTOEXEC.BAS @@ -0,0 +1,2 @@ +10 RUNM"BOOT.BIN" 'DW1 + diff --git a/Kernel/platform-coco3/Makefile b/Kernel/platform-coco3/Makefile new file mode 100644 index 00000000..7b06d4ba --- /dev/null +++ b/Kernel/platform-coco3/Makefile @@ -0,0 +1,55 @@ + +CSRCS = devtty.c ttydw.c +CSRCS += devices.c main.c libc.c + +DSRCS = ../dev/devdw.c + +ASRCS = coco3.s crt0.s +ASRCS += tricks.s commonmem.s usermem_gime.s drivewire.s + +COBJS = $(CSRCS:.c=$(BINEXT)) +AOBJS = $(ASRCS:.s=$(BINEXT)) +DOBJS = devdw.o +OBJS = $(COBJS) $(AOBJS) $(DOBJS) + +CROSS_CCOPTS += -I../dev/ + +JUNK = $(CSRCS:.c=.o) $(ASRCS:.s=.o) + +all: $(OBJS) + +$(COBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DOBJS): %$(BINEXT): ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %$(BINEXT): %.s + $(CROSS_AS) $(ASOPTS) $< -o $*.o + + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: + $(CROSS_CC) $(CROSS_CCOPTS) -O0 -c -o ../bank16k.o ../bank16k.c + $(CROSS_LD) -o ../fuzix.bin --map=../fuzix.map --script=fuzix.link \ + crt0.o commonmem.o \ + coco3.o ../start.o ../version.o ../lowlevel-6809.o \ + tricks.o main.o ../timer.o ../kdata.o devices.o \ + drivewire.o devdw.o ttydw.o \ + ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \ + ../syscall_proc.o ../syscall_other.o ../mm.o ../bank16k.o ../swap.o \ + ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec16.o \ + ../usermem_std-6809.o devtty.o libc.o ../vt.o usermem_gime.o + +boot.bin: boot/boot.s + lwasm -lboot.list -oboot.bin boot/boot.s + +fuzix.dsk: boot.bin + rm -f fuzix.dsk + decb dskini fuzix.dsk + decb copy -2 -b ../fuzix.bin ./fuzix.dsk,FUZIX.BIN + decb copy -2 -b boot.bin ./fuzix.dsk,BOOT.BIN + decb copy -l -0 -a AUTOEXEC.BAS ./fuzix.dsk,AUTOEXEC.BAS + diff --git a/Kernel/platform-coco3/README b/Kernel/platform-coco3/README new file mode 100644 index 00000000..19a0f396 --- /dev/null +++ b/Kernel/platform-coco3/README @@ -0,0 +1,133 @@ +Fuzix for CoCo3 (512k) + +Copyright 2015, Brett M. Gordon, under GPL2. + + +This port is for running FUZIX on an emulated 512K Ram Color +Computer 3. This port is based heavily on the platform-6809test and +the two dragon ports by Tormod Volden. It will not, as yet, work on a +stock 128k CoCo3; No disk swapping is supported, and until then, a +128K version will be unexciting, anyway. + + +************************* +REQUIREMENTS +************************* + +A working DriveWire implementation. +A 512k CoCo3 (emulator only for now) + +and for building: + +decb from the toolshed project: http://sourceforge.net/projects/toolshed/ +lwtools from William Astle: http://lwtools.projects.l-w.ca/ +gcc6809: http://toolshed.sourceforge.net/gcc/ + + + +************************* +BOOTING +************************* + +Booting this Fuzix is accomplished via some flavor of Disk Extended +Color Basic (DECB). When building Fuzix two disk images are +produced. The first, "Kernel/platform-coco3/fuzix.dsk", is a standard +35 track DECB image. This RSDOS filesystem contains a small +bootloader, "BOOT.BIN", that does the serious work of loading the +actual kernel, "FUZIX.BIN", into memory. There is a HDBDOS/YA-DOS +style "AUTOEXEC.BAS" file included to assist in auto-booting FUZIX. + +The second disk image produced is +"Standalone/filesystem-src/fuzixfs.dsk". This is the actual Fuzix +"root" filesystem, containing the usual suspects. + +The stock build can be booted by placing "fuzix.dsk" in Drivewire as +disk 0, and "fuzixfs.dsk" as disk 1. PLEASE TURN OFF "HDBDOS +Translation" on the Drivewire Server. If not using HDBDOS/YA-DOS type +the following at the BASIC prompt: + +LOADM"BOOT.BIN":EXEC 'DW1 + +The boot loader will automatically consider anything after the BASIC +REM comment as a commandline to be sent to the kernel. In the above +example, "DW1", indicates that DriveWire Drive No. 1 should be mounted +as the root filesystem. + + +************************* +KEYBOARD +************************* + +Some work needs done on the support on the ALT key shifting. The ALT +key is hard to use with a emulators that work in Windows or X, anyway. + +The tilde, "~", character can be produced with +The pipe, "|", character can be produced with + +Pressing <1> will switch to virtual console No. 1. +Pressing <2> will switch to virtual console No. 2. + + +************************* +DEVICES (so far) +************************* + +node major minor description +/dev/tty1 2 1 console / virtual terminal No. 1. +/dev/tty2 2 2 virtual terminal No. 2. +/dev/tty3 2 3 Drivewire Virtual Window #0 +/dev/dw? 8 0-256 Drivewire Block Drives + + +************************** +BUILDING +************************** + +# 1. Build the kernel: +make -C Kernel TARGET=coco3 + +# 2. Build the boot disk: +make -C Kernel/platform-coco3 fuzix.dsk + +# 2. Build the libraries +make -C Library tools/syscall_6809 +make -C Library/libs -f Makefile.6809 TARGET=coco3 + +# 3. Build the utils +make -C Applications/util -f Makefile.6809 TARGET=coco3 + +# 4. Build disk tools +make -C Standalone + +# 5. Build boot disk image +cd Standalone/filesystem-src +./build-filesystem -X fuzix.dsk 256 65535 + + + +************************* +TO DO +************************* + +* Swapping to disk has not been implemented yet, so a standard 512k +upgrade is required. + +* IDE Drivers. + +* Better and more DriveWire Virtual Serial Ports. + +* Fix the underlying Banking layout to better handle UDATA + +* Better support of the GIME chip's video modes + +* A whole gaggle of things, to numerous to count. + + +************************* +BUGS +************************* + +* Things work better if you compile the userspace utilities (esp. "init") +with standard gcc optimizations. + + diff --git a/Kernel/platform-coco3/boot/boot.s b/Kernel/platform-coco3/boot/boot.s new file mode 100644 index 00000000..72ae5e76 --- /dev/null +++ b/Kernel/platform-coco3/boot/boot.s @@ -0,0 +1,212 @@ +;;; +;;; A Fuzix booter for the CoCo3 +;;; + +;;; This bootloader works from a DECB-like evironment, It loads +;;; FUZIX.BIN from a DECB disk and plops it in memory, starting +;;; at physical address 0x0000. + org $2600 ; where am I loaded. + +frame .dw 0 ; on entry frame pointer +npage .db 0 ; next page no. +pos .dw 0 ; buffer pos in memory +nampre fcn /"FUZIX.BIN/ ; " image to load + + ;; And the Kick-off +start + sts frame + lda #'F ; print F + jsr 0xa282 ; + ;; open kernel image file + ldb #'I ; input mode + jsr open + lbcs abort + lda #'U ; print "U" + jsr $a282 + ;; Move to task one + ldx #$ffa0 + ldu #$ffa8 + ldd ,x++ ; copy mmu regs + std ,u++ + ldd ,x++ + std ,u++ + ldd ,x++ + std ,u++ + ldd ,x++ + std ,u++ + ldb #1 + stb $ff91 ; set mmu to task 1 + ;; Load BIN file + ;; + ldb $6f ; get current file no. + pshs b ; save on stack + ldb #1 + stb $6f ; switch in/out routine to disk file #1 +c@ jsr $a176 ; get a byte in A + cmpa #$ff ; compare A to ff + beq post ; jump to post able handling + ;; preamble + jsr getw ; D = length address + tfr d,y ; U = length + jsr getw ; D = load address + jsr setload ; set load address +d@ jsr $a176 ; A = byte + jsr putb ; put into kernel memory + leay -1,y ; decrement U + bne d@ ; loop + bra c@ ; try next byte in stream + ;; postable +post jsr getw ; get zero's + cmpd #0 ; test D + lbne abort ; abort if not zero + jsr getw ; get exec address + pshs d ; save on stack + jsr close ; close DECB file + ;; report load + clr $6f ; set stream to console + lda #'L + jsr $A282 + ldd #0 ; Address = 0 + jsr setload + ldy #bounce_end-bounce + ldx #bounce +e@ lda ,x+ + jsr putb + leay -1,y + bne e@ + lda ,s+ ; get jmp address high byte + jsr putb ; put at end of bounce routine + lda ,s+ + jsr putb ; put at end of bounce routine + lda #'O + jsr $a282 ; report load + ;; find command line in input buffer + ldx #$2dc ; X = start of line +f@ lda ,x+ ; get a byte + cmpa #$83 ; is a colon token? + bne f@ + ldd #$88 ; set destination of command line + jsr setload ; +g@ lda ,x+ ; get one byte + jsr putb ; put it in memory + tsta + bne g@ ; repeat if not done + ;; map in kernel block 0 + orcc #$50 ; turn off interrupts + clr $ffa8 + jmp $0 ; and jump to bounce routine + +;;; This routine is copied down to kernel map 0 +bounce + ;; map in rest of kernel + ldx #$ffa9 + lda #1 +a@ sta ,x+ + inca + cmpa #8 + bne a@ + .db $7e ; jump +bounce_end + + +;;; Gets next word from file +;;; takes: nothing +;;; returns: D = next word +getw + jsr $a176 ; A = high byte + tfr a,b ; B = high byte + jsr $a176 ; A = low byte + exg a,b ; flip D = next word + rts + + +;;; Sets load address +;;; takes: D = Address +;;; returns: X = cpu mapped address +;;; mods: D +setload + pshs d + ;; find block number + lsra + lsra + lsra + lsra + lsra ; A= blk no + sta $ffaa ; put in mmu + puls d + anda #$1f ; D = offset + addd #$4000 ; mmu offset + std pos ; store + rts + +;;; puts a byte into kernel memory, increments position +;;; takes: A = byte to store +;;; returns: nothing +;;; mods: +putb pshs d,x +a@ ldx pos + cmpx #$6000 ; too far ? + beq inc@ + sta ,x+ + stx pos + puls d,x,pc +inc@ ldx #$4000 ; inc pos + stx pos + inc $ffaa + bra a@ + +;;; Abort! +abort + lds frame + rts + + +;;; Open a file +;;; takes: B=ascii mode (I,O,D) +;;; returns: C set on error +open pshs b ; save mode + ;; move local filename into BASIC's vars + ldx $a6 + pshs x + ldx #nampre ; pointer to our local filename + stx $a6 ; set CHARAD + jsr $c935 ; have BASIC set up DNAMBF for us + puls x + stx $a6 + ;; end of string copy - get directory info +f@ jsr $c68c ; search directory, U=ram directory image + tst $973 ; found? + bne g@ ; yes - then return + ;; not found + ldb ,s ; get mode + cmpb #'I ; is mode I? + beq err@ ; yes then error! + ldd #$00ff ; basic/ascii + bra h@ + ;; copy directory stuff +g@ ldd ,u ; D = type/ascii + ldb #$ff ; force ascii +h@ std $957 + ldd #$100 ; record length + std $976 + lda ,s ; A = Mode (I,O,D) + ldb #1 ; B = FCB #1 + jsr $c48d ; open file +out@ clra ; clear C + puls b,pc ; return +err@ coma ; set C + puls b,pc ; return + + + +;;; Close file buffer +close + ldb #1 ; set file number to 1 + stb $6f + jsr $a42d ; close file + clr $6f ; set dev to screen + rts + + + + end start \ No newline at end of file diff --git a/Kernel/platform-coco3/build b/Kernel/platform-coco3/build new file mode 100755 index 00000000..f09a45c4 --- /dev/null +++ b/Kernel/platform-coco3/build @@ -0,0 +1,43 @@ + +# remake kernel +cd .. +make TARGET=coco3 clean + +# specially make bank16.c (bug fix for compile fart?) +#m6809-unknown-gcc -c -Wall -msoft-reg-count=0 -mfar-stack-param -I cpu-6809 -I platform-coco3 -I include -o bank16k.o bank16k.c + +# make rest of kernel +make TARGET=coco3 + + +# make boot.dsk +cd platform-coco3 +rm fuzix.dsk ; make fuzix.dsk + + +# make Libs +cd ../../Library +rm tools/syscall_6809 +make tools/syscall_6809 +cd libs +make -f Makefile.6809 TARGET=coco3 clean +make -f Makefile.6809 TARGET=coco3 + +# build utils +cd ../../Applications/util +make -f Makefile.6809 TARGET=coco3 clean +make -f Makefile.6809 TARGET=coco3 + +# build sh +cd ../../Applications/V7/cmd/sh +make -f Makefile.6809 TARGET=coco3 clean +make -f Makefile.6809 TARGET=coco3 + +# build utils +cd ../../../../Standalone +make + +# build boot disk image +cd filesystem-src +./build-filesystem -X fuzixfs.dsk 256 65535 + diff --git a/Kernel/platform-coco3/coco3.s b/Kernel/platform-coco3/coco3.s new file mode 100644 index 00000000..c0127b22 --- /dev/null +++ b/Kernel/platform-coco3/coco3.s @@ -0,0 +1,307 @@ +;;; +;;; Tandy Color Computer 3 +;;; +;;; low level routines, but not the tricky ones. +;;; see tricks.s for those. + + + .module coco3 + + ; exported symbols + .globl init_early + .globl init_hardware + .globl interrupt_handler + .globl _program_vectors + .globl map_kernel + .globl map_process + .globl map_process_always + .globl map_save + .globl map_restore + .globl _need_resched + + ; exported debugging tools + .globl _trap_monitor + .globl _trap_reboot + .globl outchar + .globl _di + .globl _ei + .globl _irqrestore + + ; imported symbols + .globl _ramsize + .globl _procmem + .globl unix_syscall_entry + .globl nmi_handler + .globl null_handler + + include "kernel.def" + include "../kernel09.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK +; ----------------------------------------------------------------------------- + .area .common + + +tm_user_sp: .dw 0 + +_trap_monitor: + orcc #0x10 + bra _trap_monitor + +_trap_reboot: + orcc #0x10 ; turn off interrupts + lda #0x38 ; put RAM block in memory + sta 0xffa8 ; + ;; copy reboot bounce routine down + ldx #0 ; + ldu #bounce@ +loop@ lda ,u+ + sta ,x+ + cmpu #bounce_end@ + bne loop@ + jmp 0 ; + ;; this code is PIC and gets copied down to + ;; low memory on reboot to bounce to the reset + ;; vector. +bounce@ + lda #0x84 ; reset GIME (map in roms) + sta 0xff90 + jmp [0xfffe] ; jmp to reset vector +bounce_end@ + + + +;;; Turn off interrupts +;;; takes: nothing +;;; returns: B = original irq (cc) state +_di: + tfr cc,b ; return the old irq state + orcc #0x10 + rts + +;;; Turn on interrupts +;;; takes: nothing +;;; returns: nothing +_ei: + andcc #0xef + rts + +;;; Restore interrupts to saved setting +;;; takes: B = saved state (as returned from _di ) +;;; returns: nothing +_irqrestore: ; B holds the data + tfr b,cc + rts + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK +; ----------------------------------------------------------------------------- + .area .text + +;;; Stuff to initialize *before* hardware +;;; takes: nothing +;;; returns: nothing +init_early: + ldx #null_handler + stx 1 + lda #0x7E + sta 0 + rts + +;;; Initialize Hardware ! +;;; takes: nothing +;;; returns: nothing +init_hardware: + ;; set system RAM size + ldd #512 + std _ramsize + ldd #512-64 + std _procmem + ;; set temporary screen up + ldb #%01000100 ; coco3 mode + stb $ff90 + ldb #%00001100 ; text / 8 lines per char row + stb $ff98 + ldb #%00010100 ; 80 column mode + stb $ff99 + ldd #$b400/8 ; video at physical 0xb000 + std $ff9d + ldd #$003f ; white on black text console + sta $ffb0 + stb $ffb8 + ;; clear video memory + ldx #$ac00 + lda #$20 +a@ sta ,x+ + cmpx #$bb80 + bne a@ + ;; Our vectors are in high memory unlike Z80 but we still + ;; need vectors + ldu #0xfeee ; vector area + lda #$7e ; jump opcode + ldx #badswi_handler ; swi2 and swi3 are bad + sta ,u+ + stx ,u++ + sta ,u+ + stx ,u++ + ldx #firq_handler + sta ,u+ + stx ,u++ + ldx #my_interrupt_handler + sta ,u+ + stx ,u++ + ldx #unix_syscall_entry + sta ,u+ + stx ,u++ + ldx #nmi_handler + sta ,u+ + stx ,u + rts + + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .area .common + +;;; Setup interrupt vectors in the cpu map state +;;; CoCo3's vectors are in common, so this doesn't need to do anything +;;; takes: nothing +;;; returns: nothing +_program_vectors: + jsr map_process + ldb #0x7E + stb 0 + jsr map_kernel + rts + +;;; This clear the interrupt source before calling the +;; normal handler +;;; takes: nothing ( it is an interrupt handler) +;;; returns: nothing ( it is an interrupt handler ) +my_interrupt_handler + lda $ff02 ; clear pia irq latch by reading data port + jmp interrupt_handler ; jump to regular handler + +;;; FIXME: these interrupt handlers should prolly do something +;;; in the future. +firq_handler: +badswi_handler: + rti + + +;;; Userspace mapping pages 7+ kernel mapping pages 3-5, first common 6 +;;; All registers preserved +map_process_always: + pshs x,y,u + ldx #U_DATA__U_PAGE + jsr map_process_2 + puls x,y,u,pc + +;;; Maps a page table into cpu space +;;; takes: X - pointer page table ( ptptr ) +;;; returns: nothing +;;; modifies: nothing +map_process: + cmpx #0 ; is zero? + bne map_process_2 ; no then map process; else: map the kernel + ;; !!! fall-through to below + +;;; Maps the Kernel into CPU space +;;; takes: nothing +;;; returns: nothing +;;; modifies: nothing +;;; Map in the kernel below the current common, all registers preserved +map_kernel: + pshs a + lda #1 ; flip to mmu map 1 (kernel) + sta 0xff91 ; + sta init1_mirror ; save copy in INIT1 mirror + puls a,pc + +;;; User is in the FFA0 map with the top 8K as common +;;; As the core code currently does 16K happily but not 8 we just pair +;;; up pages + +;;; Maps a page table into the MMU +;;; takes: X = pointer to page table +;;; returns: nothing +;;; modifies: nothing +map_process_2: + pshs x,y,a + ldy #0xffa0 ; MMU user map. We can fiddle with + + ;; map in the common block + lda ,x+ ; get byte from page table + sta ,y+ ; put it in mmu + inca ; increment to get next 8k block + sta ,y+ ; put it in mmu + + ;; map the rest of the block in order +* ldy #0xffa0 ; + lda ,x+ + sta ,y+ + inca + sta ,y+ + + lda ,x+ + sta ,y+ + inca + sta ,y+ + +* lda ,x+ + lda #6 + sta ,y+ + inca + sta ,y + + lda #0 + sta 0xff91 ; new mapping goes live here + sta init1_mirror ; and save INIT1 setting in mirror + puls x,y,a,pc ; so had better include common! + + +;;; +;;; Restore a saved mapping. We are guaranteed that we won't switch +;;; common copy between save and restore. Preserve all registers +;;; +;;; We cheat somewhat. We have two mapping sets, so just remember +;;; which space we were in. Note: we could be in kernel in either +;;; space while doing user copies +;;; +map_restore: + pshs a + lda saved_map + sta init1_mirror + sta 0xff91 + puls a,pc + +;;; Save current mapping +;;; takes: nothing +;;; returns: nothing +map_save: + pshs a + lda init1_mirror + sta saved_map + puls a,pc + +saved_map: .db 0 ; which mapping state where we in? +init1_mirror: + .db 0 ; a *mirror* of gimme $ff91, which is WriteOnly +_need_resched .db 0 ; scheduler flag + + +;;; Print a character to debugging +;;; takes: A = character +;;; returns: nothing +outchar: + pshs b,x + ldx scrPos + sta ,x+ + stx scrPos + puls b,x,pc + + .area .data +scrPos .dw 0xb400 ; debugging screen buffer position + diff --git a/Kernel/platform-coco3/commonmem.s b/Kernel/platform-coco3/commonmem.s new file mode 100644 index 00000000..13050769 --- /dev/null +++ b/Kernel/platform-coco3/commonmem.s @@ -0,0 +1,29 @@ +; +; Put the udata at the start of common. We have four 16K banks so we +; keep the non .common kernel elements below C000 and then keep bank 3 as a +; true common bank +; + .module commonmem + + ; exported symbols + .globl _ub + .globl _udata + .globl kstack_top + .globl istack_top + .globl istack_switched_sp + + .area .udata + +;;; first 512 bytes: starts with struct u_block, +;;; with the kernel stack working down from above +_ub: +_udata: +kstack_base: + zmb 512 +kstack_top: + +;;; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer +istack_base: + zmb 254 +istack_top: +istack_switched_sp: .dw 0 diff --git a/Kernel/platform-coco3/config.h b/Kernel/platform-coco3/config.h new file mode 100644 index 00000000..b860fd30 --- /dev/null +++ b/Kernel/platform-coco3/config.h @@ -0,0 +1,77 @@ +/* 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) */ +#undef CONFIG_PROFIL +/* Multiple processes in memory at once */ +#define CONFIG_MULTI +/* Single tasking - for now while we get it booting */ +#undef CONFIG_SINGLETASK +/* Use C helpers for usermem */ +#undef CONFIG_USERMEM_C + +/* We use flexible 16K banks so use the helper */ +#define CONFIG_BANK16 +#define CONFIG_BANKS 4 +#define MAX_MAPS 32-3 +#define MAPBASE 0x0000 +/* And swapping */ +/* #define SWAPDEV 2051 */ +#define SWAP_SIZE 0x62 +/* FIXME */ +#define SWAPBASE 0x0000 /* We swap the lot in one, include the */ +#define SWAPTOP 0xC300 /* uarea so its a round number of sectors */ +#define UDATA_BLOCKS 0 /* We swap the uarea in the data */ +#define UDATA_SWAPSIZE 0 +#define MAX_SWAPS 32 +#define swap_map(x) ((uint8_t *)(x)) + +/* The Drivewire block dev rawmode=1 doesn't work just now + with the bank16k.c memory layout (yet), so we have to + use legacy binary loading... */ +#define CONFIG_LEGACY_EXEC + + +/* Video terminal, not a serial tty */ +#define CONFIG_VT +#define CONFIG_VT_MULTI +/* We want the 8x8 font */ +// #define CONFIG_VT_SIMPLE +/* Vt definitions */ +#define VT_BASE (uint8_t *)0xb400 +#define VT_WIDTH 80 +#define VT_HEIGHT 21 +#define VT_RIGHT 79 +#define VT_BOTTOM 20 +#define VT_INITIAL_LINE 0 + +extern unsigned char vt_map( unsigned char c ); +#define VT_MAP_CHAR(x) vt_map(x) + +#define TICKSPERSEC 60 /* Ticks per second */ +#define PROGBASE 0x0100 /* also data base */ +#define PROGTOP 0xbd00 /* Top of program, base of U_DATA */ +#define PROGLOAD 0x0100 /* ??? */ + +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + /* Temp FIXME set to serial port for debug ease */ + +/* Boot devices */ +#define BOOTDEVICENAMES ",,,,,,,,dw" + + + +/* We need a tidier way to do this from the loader */ +#define CMDLINE 0x88 /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 3 +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 6 /* Number of block buffers */ +#define NMOUNTS 2 /* Number of mounts at a time - nothing mountable! */ + +#define CONFIG_COCO_KBD /* Use CoCo key maps rather than Dragon */ + + diff --git a/Kernel/platform-coco3/crt0.s b/Kernel/platform-coco3/crt0.s new file mode 100644 index 00000000..7bb47977 --- /dev/null +++ b/Kernel/platform-coco3/crt0.s @@ -0,0 +1,37 @@ +;;; +;;; The Kernel C run-time / start routine +;;; + +;;; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl kstack_top + + + ;; exported symbols + .globl start + + ;; startup code @0 + .area .start + jmp start + + .area .text + +start: orcc #0x10 ; interrupts definitely off + lds #kstack_top + + ;; zero out kernel's bss section + ldx #__sectionbase_.bss__ + ldy #__sectionlen_.bss__ +bss_wipe: + clr ,x+ + leay -1,y + bne bss_wipe + + jsr init_early + jsr init_hardware + jsr _fuzix_main + orcc #0x10 +stop: bra stop + diff --git a/Kernel/platform-coco3/device.h b/Kernel/platform-coco3/device.h new file mode 100644 index 00000000..47575eb0 --- /dev/null +++ b/Kernel/platform-coco3/device.h @@ -0,0 +1,5 @@ +#ifndef __DEVICE_DOT_H__ +#define __DEVICE_DOT_H__ + + +#endif /* __DEVICE_DOT_H__ */ diff --git a/Kernel/platform-coco3/devices.c b/Kernel/platform-coco3/devices.c new file mode 100644 index 00000000..323ec606 --- /dev/null +++ b/Kernel/platform-coco3/devices.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/fd Floppy disc block devices */ + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 1: /dev/hd Hard disc block devices (absent) */ + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, my_tty_close, tty_read, tty_write, tty_ioctl }, + /* 3: /dev/lpr Printer devices */ + { nxio_open, no_close, no_rdwr, no_rdwr, 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 */ + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* /dev/dw Drivewire */ + { dw_open, no_close, dw_read, dw_write, no_ioctl }, +}; + +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) + 255) + return false; + else + return true; +} +void device_init(void) +{ +} + diff --git a/Kernel/platform-coco3/devtty.c b/Kernel/platform-coco3/devtty.c new file mode 100644 index 00000000..118aff2d --- /dev/null +++ b/Kernel/platform-coco3/devtty.c @@ -0,0 +1,331 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG /* UNdefine to delete debug code sequences */ + + +uint8_t vtattr_cap; + + +char tbuf1[TTYSIZ]; +char tbuf2[TTYSIZ]; +char tbuf3[TTYSIZ]; + +struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */ + {NULL, NULL, NULL, 0, 0, 0}, + {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2}, + {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}, + {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2} +}; + + + +static struct pty { + unsigned char *base; /* base of buffer in cpu space */ + unsigned char *cpos; /* current location of cursor */ + unsigned char csave; /* charactor that is under the cursor */ + struct vt_switch vt; /* the vt.o module's state */ + unsigned int scrloc; /* location to put into gimme */ +}; + +static struct pty ptytab[]={ + { (unsigned char *)0xb400, NULL, 0, {0,0,0,0}, 0xb400/8 }, + { (unsigned char *)0xac80, NULL, 0, {0,0,0,0}, 0xac80/8 } +}; + + +/* ptr to current active pty table */ +struct pty *curpty=&ptytab[0]; + +/* current minor for input */ +int curminor=1; + + +/* A wrapper for tty_close that closes the DW port properly */ +int my_tty_close( uint8_t minor ) +{ + if( minor == 3 && ttydata[3].users == 0 ) dw_vclose( minor ); + return( tty_close( minor ) ); +} + + +/* Output for the system console (kprintf etc) */ +void kputchar(char c) +{ + if (c == '\n') + tty_putc(1, '\r'); + tty_putc(1, c); +} + +ttyready_t tty_writeready(uint8_t minor) +{ + return TTY_READY_NOW; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + if( minor == 3 ){ + dw_putc( minor, c ) ; + return; + } + struct pty *t=curpty; + vt_save( &curpty->vt ); + curpty=&ptytab[minor-1]; + vt_load( &curpty->vt ); + vtoutput(&c, 1); + vt_save( &curpty->vt ); + curpty=t; + vt_load( &curpty->vt ); +} + +void tty_sleeping(uint8_t minor) +{ + used( minor); +} + + +void tty_setup(uint8_t minor) +{ + if( minor == 3 ){ + dw_vopen(minor); + return; + } +} + +/* For the moment */ +int tty_carrier(uint8_t minor) +{ + return 1; +} + +void tty_interrupt(void) +{ + +} + +uint8_t keymap[8]; +static uint8_t keyin[8]; +static uint8_t keybyte, keybit; +static uint8_t newkey; +static int keysdown = 0; +static uint8_t shiftmask[8] = { + 0, 0, 0, 0x40, 0x40, 0, 0, 0x40 +}; + +/* a lookup table to rotate a 0 bit around */ +static uint8_t rbit[8] = { + 0xFE, + 0xFD, + 0xFB, + 0xF7, + 0xEF, + 0xDF, + 0xBF, + 0x7F, +}; + +/* Row inputs: multiplexed with the joystick */ +static volatile uint8_t *pia_row = (uint8_t *)0xFF00; +/* Columns for scanning: multiplexed with the printer port */ +static volatile uint8_t *pia_col = (uint8_t *)0xFF02; + + +static void keyproc(void) +{ + int i; + uint8_t key; + + for (i = 0; i < 8; i++) { + /* We do the scan in software on the Dragon */ + *pia_col = rbit[i]; + keyin[i] = ~*pia_row; + key = keyin[i] ^ keymap[i]; + if (key) { + int n; + int m = 1; + for (n = 0; n < 7; n++) { + if ((key & m) && (keymap[i] & m)) { + if (!(shiftmask[i] & m)) + keysdown--; + } + if ((key & m) && !(keymap[i] & m)) { + if (!(shiftmask[i] & m)) { + keysdown++; + newkey = 1; + keybyte = i; + keybit = n; + } + } + m += m; + } + } + keymap[i] = keyin[i]; + } +} + +#ifdef CONFIG_COCO_KBD +uint8_t keyboard[8][7] = { + { '@', 'h', 'p', 'x', '0', '8', KEY_ENTER }, + { 'a', 'i', 'q', 'y', '1', '9', 0 /* clear - used as ctrl*/ }, + { 'b', 'j', 'r', 'z', '2', ':', KEY_ESC /* break (used for esc) */ }, + { 'c', 'k', 's', '^' /* up */, '3', ';' , 0 /* NC */ }, + { 'd', 'l', 't', '|' /* down */, '4', ',', 0 /* NC */ }, + { 'e', 'm', 'u', KEY_BS /* left */, '5', '-', '~' /* NC */ }, + { 'f', 'n', 'v', KEY_TAB /* right */, '6', '.', 0 /* NC */ }, + { 'g', 'o', 'w', ' ', '7', '/', 0 /* shift */ }, +}; + +uint8_t shiftkeyboard[8][7] = { + { '\\', 'H', 'P', 'X', '_', '(', KEY_ENTER }, + { 'A', 'I', 'Q', 'Y', '!', ')', 0 /* clear - used as ctrl */ }, + { 'B', 'J', 'R', 'Z', '"', '*', CTRL('C') /* break */ }, + { 'C', 'K', 'S', '[' /* up */, '#', '+', 0 /* NC */ }, + { 'D', 'L', 'T', ']' /* down */, '$', '<', 0 /* NC */ }, + { 'E', 'M', 'U', '{' /* left */, '%', '=', '|' /* NC */ }, + { 'F', 'N', 'V', '}' /* right */, '&', '>', 0 /* NC */ }, + { 'G', 'O', 'W', ' ', '\'', '?', 0 /* shift */ }, +}; +#else +uint8_t keyboard[8][7] = { + { '0', '8', '@', 'h', 'p', 'x', KEY_ENTER }, + { '1', '9', 'a', 'i', 'q', 'y', 0 /* clear - used as ctrl*/ }, + { '2', ':', 'b', 'j', 'r', 'z', KEY_ESC /* break (used for esc) */ }, + { '3', ';', 'c', 'k', 's', '^' /* up */, 0 /* NC */ }, + { '4', ',', 'd', 'l', 't', '|' /* down */, 0 /* NC */ }, + { '5', '-', 'e', 'm', 'u', KEY_BS /* left */, 0 /* NC */ }, + { '6', '.', 'f', 'n', 'v', KEY_TAB /* right */, 0 /* NC */ }, + { '7', '/', 'g', 'o', 'w', ' ', 0 /* shift */ }, +}; + +uint8_t shiftkeyboard[8][7] = { + { '_', '(', '\\', 'H', 'P', 'X', KEY_ENTER }, + { '!', ')', 'A', 'I', 'Q', 'Y', 0 /* clear - used as ctrl*/ }, + { '"', '*', 'B', 'J', 'R', 'Z', CTRL('C') /* break */ }, + { '#', '+', 'C', 'K', 'S', '[' /* up */, 0 /* NC */ }, + { '$', '<', 'D', 'L', 'T', ']' /* down */, 0 /* NC */ }, + { '%', '=', 'E', 'M', 'U', '{' /* left */, 0 /* NC */ }, + { '&', '>', 'F', 'N', 'V', '}' /* right */, 0 /* NC */ }, + { '\'', '?', 'G', 'O', 'W', ' ', 0 /* shift */ }, +}; +#endif /* COCO_KBD */ + + + +static void keydecode(void) +{ + uint8_t c; + + /* shift shifted handling - use alt lookup table */ + if (keymap[7] & 64) + c = shiftkeyboard[keybyte][keybit]; + else + c = keyboard[keybyte][keybit]; + /* control shifted handling - we need some refactoring here. */ + if (keymap[4] & 64) { + /* control+1 */ + if ( c == '1' ){ + vt_save( &curpty->vt ); + curpty=&ptytab[0]; + *(unsigned int *)0xff9d = curpty->scrloc ; + vt_load( &curpty->vt ); + curminor=1; + return; + } + /* control + 2 */ + if ( c == '2' ){ + vt_save( &curpty->vt ); + curpty=&ptytab[1]; + *(unsigned int *)0xff9d = curpty->scrloc ; + vt_load( &curpty->vt ); + curminor=2; + return; + } + /* control + something else */ + if (c > 32 && c < 127) + c &= 31; + } + tty_inproc(curminor, c); +} + +void platform_interrupt(void) +{ + *pia_col; + newkey = 0; + keyproc(); + if (keysdown < 3 && newkey) + keydecode(); + timer_interrupt(); + dw_vpoll(); +} + + + + +/* These are routines stolen from the stock vt.c's VT_SIMPLE code, and modified + to suite multiple vts +*/ + + +static uint8_t *char_addr(unsigned int y1, unsigned char x1) +{ + return curpty->base + VT_WIDTH * y1 + (uint16_t)x1; +} + +void cursor_off(void) +{ + if (curpty->cpos) + *curpty->cpos = curpty->csave; +} + +void cursor_on(int8_t y, int8_t x) +{ + curpty->csave = *char_addr(y, x); + curpty->cpos = char_addr(y,x); + *curpty->cpos = VT_MAP_CHAR('_'); +} + +void plot_char(int8_t y, int8_t x, uint16_t c) +{ + *char_addr(y, x) = VT_MAP_CHAR(c); +} + +void clear_lines(int8_t y, int8_t ct) +{ + unsigned char *s = char_addr(y, 0); + memset(s, ' ', ct * VT_WIDTH); +} + +void clear_across(int8_t y, int8_t x, int16_t l) +{ + unsigned char *s = char_addr(y, x); + memset(s, ' ', l); +} + +/* FIXME: these should use memmove */ + +void scroll_up(void) +{ + memcpy( curpty->base, curpty->base + VT_WIDTH, VT_WIDTH * VT_BOTTOM); +} + +void scroll_down(void) +{ + memcpy( curpty->base + VT_WIDTH, curpty->base, VT_WIDTH * VT_BOTTOM); +} + + +unsigned char vt_map( unsigned char c ) +{ + /* The CoCo3's gime has a strange code for underscore */ + if( c=='_' ) return 0x7F; + return c; +} + diff --git a/Kernel/platform-coco3/devtty.h b/Kernel/platform-coco3/devtty.h new file mode 100644 index 00000000..2ebd66d4 --- /dev/null +++ b/Kernel/platform-coco3/devtty.h @@ -0,0 +1,7 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + + +int my_tty_close( uint8_t minor ); /* wrapper call to close DW ports */ + +#endif diff --git a/Kernel/platform-coco3/drivewire.s b/Kernel/platform-coco3/drivewire.s new file mode 100644 index 00000000..c7ac5a39 --- /dev/null +++ b/Kernel/platform-coco3/drivewire.s @@ -0,0 +1,169 @@ +;; +;; DriveWire sector routines +;; +;; Copyright 2015 Tormod Volden +;; Copyright 2008 Boisy G. Pitre +;; Distributed under the GNU General Public License, version 2 or later. +;; + + ; exported + .globl _dw_operation + .globl _dw_reset + .globl _dw_transaction + + .area .common + +;;; Drivewire is really client (your retro 8 bitter) +;;; driven. Because the original CoCo hardware lacks +;;; serial IRQs, and the fact that a 6809 interrupt on a ~2Mhz +;;; machine isn't fast enough to catch the host's reply packet +;;; , the write and read functions must be "close" together. +;;; uint16_t dw_transaction( char *send, uint16_t scnt, +;;; char *recv, uint16_t rcnt ) +;;; x=send cc y ret scnt recv rcnt +;;; Brett M. Gordon +_dw_transaction: + pshs cc,y ; save caller + orcc #0x50 ; stop interrupts + ldy 5,s ; Y = number of bytes to send + beq out@ ; no byte to write - leave + jsr DWWrite ; send to DW + ldx 7,s ; X is receive buffer + ldy 9,s ; Y = number of bytes to receive + beq out@ ; no bytes to send - leave + jsr DWRead ; read in that many bytes + bcs frame@ ; C set on framing error + bne part@ ; Z zet on all bytes received +out@ ldx #0 ; no error + puls cc,y,pc ; return +frame@ ldx #-1 ; frame error + puls cc,y,pc ; return +part@ ldx #-2 ; not all bytes received! + puls cc,y,pc ; return + + +_dw_reset: + ; maybe reinitalise PIA here? + ; and send DW_INIT request to server? + rts + +_dw_operation: + pshs y + ; get parameters from C, X points to cmd packet + ldy 4,s ; driveptr + lda ,y ; for now, contains minor = drive number directly + ldb ,x ; write flag + ; buffer location into Y + ldy 3,x + ; sector number into X + ldx 1,x + tstb + bne @write + jsr dw_read_sector + bra @done +@write jsr dw_write_sector +@done bcs @err + bne @err + ldx #0 +@ret puls y,pc +@err ldx #0xFFFF + bra @ret + +; Write a sector to the DriveWire server +; Drive number in A, sector number in X, buffer location in Y +; Sets carry or non-zero flags on error +dw_write_sector: + ; header: OP, drive = A, LSN 23-16 = 0, LSN 15-8 and LSN 7-0 = X + clrb + pshs a,b,x + ldb #OP_WRITE + pshs b + ; send header + tfr s,x + pshs y ; save buffer location + ldy #5 + jsr DWWrite + ; send payload + ldx ,s + ldy #256 + jsr DWWrite + ; calculate checksum of payload, backwards + exg x,y ; Y is zero after DWWrite +@sum ldb ,-y + abx + cmpy ,s ; buffer location start + bne @sum + stx ,s ; checksum to send + tfr s,x + ldy #2 + jsr DWWrite + ; get status byte from server into following byte + ldy #1 + clra ; clear carry bit for BECKER variant + jsr DWRead + leas 7,s + bcs @ret + bne @ret + ldb -5,s ; received status byte (zero is success) +@ret rts + +; +; Based on "DoRead" by Boisy G. Pitre from DWDOS hosted on toolshed.sf.net +; Read a sector from the DriveWire server +; Drive number in A, 16-bit sector in X, buffer location in Y +; Sets carry or non-zero flags on error + +dw_read_sector: + ; header: OP, drive = A, LSN 23-16 = 0, LSN 15-8 and LSN 7-0 = X + clrb + pshs d,x,y + lda #OP_READEX +ReRead pshs a + leax ,s + ldy #$0005 + lbsr DWWrite + puls a + ldx 4,s get read buffer pointer + ldy #256 read 256 bytes + ldd #133*1 1 second timeout + bsr DWRead + bcs ReadEx + bne ReadEx +; Send 2 byte checksum + pshs y + leax ,s + ldy #2 + lbsr DWWrite + ldy #1 + ldd #133*1 + bsr DWRead + leas 2,s + bcs ReadEx + bne ReadEx +; Check received status byte + lda ,s + beq ReadEx + cmpa #E_CRC + bne ReadErr + lda #OP_REREADEX + clr ,s + bra ReRead +ReadErr comb ; set carry bit +ReadEx puls d,x,y,pc + +; Used by DWRead and DWWrite +IntMasks equ $50 +NOINTMASK equ 1 + +; Hardcode these for now so that we can use below files unmodified +H6309 equ 0 +BECKER equ 1 +ARDUINO equ 0 +JMCPBCK equ 0 +BAUD38400 equ 0 + +; These files are copied almost as-is from HDB-DOS + include "dw.def" + include "dwread.s" + include "dwwrite.s" + diff --git a/Kernel/platform-coco3/dw.def b/Kernel/platform-coco3/dw.def new file mode 100644 index 00000000..677f4c71 --- /dev/null +++ b/Kernel/platform-coco3/dw.def @@ -0,0 +1,70 @@ +******************************************************************** +* +* Copied from HDB-DOS from toolshed.sf.net +* +* dwdefs - DriveWire Definitions File +* +* $Id: dwdefs.d,v 1.10 2010/02/21 06:24:47 aaronwolfe Exp $ +* +* Ed. Comments Who YY/MM/DD +* ------------------------------------------------------------------ +* 1 Started BGP 03/04/03 +* 2 Added DWGLOBS area BGP 09/12/27 + + nam dwdefs + ttl DriveWire Definitions File + +* Addresses +BBOUT equ $FF20 +BBIN equ $FF22 + +* Opcodes +OP_NOP equ $00 No-Op +OP_RESET1 equ $FE Server Reset +OP_RESET2 equ $FF Server Reset +OP_RESET3 equ $F8 Server Reset +OP_DWINIT equ 'Z DriveWire dw3 init/OS9 boot +OP_TIME equ '# Current time requested +OP_INIT equ 'I Init routine called +OP_READ equ 'R Read one sector +OP_REREAD equ 'r Re-read one sector +OP_READEX equ 'R+128 Read one sector +OP_REREADEX equ 'r+128 Re-read one sector +OP_WRITE equ 'W Write one sector +OP_REWRIT equ 'w Re-write one sector +OP_GETSTA equ 'G GetStat routine called +OP_SETSTA equ 'S SetStat routine called +OP_TERM equ 'T Term routine called +OP_SERINIT equ 'E +OP_SERTERM equ 'E+128 + +* Printer opcodes +OP_PRINT equ 'P Print byte to the print buffer +OP_PRINTFLUSH equ 'F Flush the server print buffer + +* Serial opcodes +OP_SERREAD equ 'C +OP_SERREADM equ 'c +OP_SERWRITE equ 'C+128 +OP_SERGETSTAT equ 'D +OP_SERSETSTAT equ 'D+128 + +* for dw vfm +OP_VFM equ 'V+128 + +* WireBug opcodes (Server-initiated) +OP_WIREBUG_MODE equ 'B +* WireBug opcodes (Server-initiated) +OP_WIREBUG_READREGS equ 'R Read the CoCo's registers +OP_WIREBUG_WRITEREGS equ 'r Write the CoCo's registers +OP_WIREBUG_READMEM equ 'M Read the CoCo's memory +OP_WIREBUG_WRITEMEM equ 'm Write the CoCo's memory +OP_WIREBUG_GO equ 'G Tell CoCo to get out of WireBug mode and continue execution + +* VPort opcodes (CoCo-initiated) +OP_VPORT_READ equ 'V +OP_VPORT_WRITE equ 'v + +* Error definitions +E_CRC equ $F3 Same as NitrOS-9 E$CRC + diff --git a/Kernel/platform-coco3/dwread.s b/Kernel/platform-coco3/dwread.s new file mode 100644 index 00000000..1b4c587b --- /dev/null +++ b/Kernel/platform-coco3/dwread.s @@ -0,0 +1,341 @@ +******************************************************* +* +* Copied from HDB-DOS from toolshed.sf.net +* The original code is public domain +* +* DWRead +* Receive a response from the DriveWire server. +* Times out if serial port goes idle for more than 1.4 (0.7) seconds. +* Serial data format: 1-8-N-1 +* 4/12/2009 by Darren Atkinson +* +* Entry: +* X = starting address where data is to be stored +* Y = number of bytes expected +* +* Exit: +* CC = carry set on framing error, Z set if all bytes received +* X = starting address of data received +* Y = checksum +* U is preserved. All accumulators are clobbered +* + + IFNE ARDUINO +* Note: this is an optimistic routine. It presumes that the server will always be there, and +* has NO timeout fallback. It is also very short and quick. +DWRead clra ; clear Carry (no framing error) + pshs u,x,cc ; preserve registers + leau ,x + ldx #$0000 +loop@ tst $FF51 ; check for CA1 bit (1=Arduino has byte ready) + bpl loop@ ; loop if not set + ldb $FF50 ; clear CA1 bit in status register + stb ,u+ ; save off acquired byte + abx ; update checksum + leay ,-y + bne loop@ + + leay ,x ; return checksum in Y + puls cc,x,u,pc ; restore registers and return + + ELSE + + IFNE JMCPBCK +* NOTE: There is no timeout currently on here... +DWRead clra ; clear Carry (no framing error) + deca ; clear Z flag, A = timeout msb ($ff) + tfr cc,b + pshs u,x,dp,b,a ; preserve registers, push timeout msb + leau ,x + ldx #$0000 + IFEQ NOINTMASK + orcc #IntMasks + ENDC +loop@ ldb $FF4C + bitb #$02 + beq loop@ + ldb $FF44 + stb ,u+ + abx + leay ,-y + bne loop@ + + tfr x,y + ldb #0 + lda #3 + leas 1,s ; remove timeout msb from stack + inca ; A = status to be returned in C and Z + ora ,s ; place status information into the.. + sta ,s ; ..C and Z bits of the preserved CC + leay ,x ; return checksum in Y + puls cc,dp,x,u,pc ; restore registers and return + ELSE + IFNE BECKER + IFNDEF BCKSTAT +BCKSTAT equ $FF41 + ENDC + IFNDEF BCKPORT +BCKPORT equ $FF42 + ENDC +* NOTE: There is no timeout currently on here... +DWRead clra ; clear Carry (no framing error) + deca ; clear Z flag, A = timeout msb ($ff) + tfr cc,b + pshs u,x,dp,b,a ; preserve registers, push timeout msb + leau ,x + ldx #$0000 + IFEQ NOINTMASK + orcc #IntMasks + ENDC +loop@ ldb BCKSTAT + bitb #$02 + beq loop@ + ldb BCKPORT + stb ,u+ + abx + leay ,-y + bne loop@ + tfr x,y + ldb #0 + lda #3 +timeout leas 1,s ; remove timeout msb from stack + inca ; A = status to be returned in C and Z + ora ,s ; place status information into the.. + sta ,s ; ..C and Z bits of the preserved CC + leay ,x ; return checksum in Y + puls cc,dp,x,u,pc ; restore registers and return + ENDC + ENDC + ENDC + + IFEQ BECKER+JMCPBCK+ARDUINO + IFNE BAUD38400 +******************************************************* +* 38400 bps using 6809 code and timimg +******************************************************* + +DWRead clra ; clear Carry (no framing error) + deca ; clear Z flag, A = timeout msb ($ff) + tfr cc,b + pshs u,x,dp,b,a ; preserve registers, push timeout msb + IFEQ NOINTMASK + orcc #IntMasks ; mask interrupts + ENDC + tfr a,dp ; set direct page to $FFxx + setdp $ff + leau ,x ; U = storage ptr + ldx #0 ; initialize checksum + adda #2 ; A = $01 (serial in mask), set Carry + +* Wait for a start bit or timeout +rx0010 bcc rxExit ; exit if timeout expired + ldb #$ff ; init timeout lsb +rx0020 bita +#include +#include +#include +#include + + +void platform_idle(void) +{ +} + +void do_beep(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. + */ + +void pagemap_init(void) +{ + int i; + /* We have 64 8k pages for a CoCo3 so insert every other one + * into the kernel allocator map. + */ + for (i = 8; i < 64; i+=2) + pagemap_add(i); + /* add common page last so init gets it */ + /* pagemap_add(6); */ +} + +void map_init(void) +{ +} + + diff --git a/Kernel/platform-coco3/target.mk b/Kernel/platform-coco3/target.mk new file mode 100644 index 00000000..e9abbba1 --- /dev/null +++ b/Kernel/platform-coco3/target.mk @@ -0,0 +1 @@ +export CPU = 6809 diff --git a/Kernel/platform-coco3/tricks.s b/Kernel/platform-coco3/tricks.s new file mode 100644 index 00000000..d32c35e4 --- /dev/null +++ b/Kernel/platform-coco3/tricks.s @@ -0,0 +1,273 @@ +;;; +;;; CoCo3 ghoulish tricks (boo!) +;;; + .module tricks + + ;; imported + .globl _newproc + .globl _chksigs + .globl _getproc + .globl _trap_monitor + + ;; exported + .globl _switchout + .globl _switchin + .globl _dofork + .globl _ramtop + + include "kernel.def" + include "../kernel09.def" + + + .area .data +;;; _ramrop cannot be in common, as this memory becomes per-process +;;; when we add better udata handling. +_ramtop: + .dw 0 + + + + .area .common + +;;; Switchout switches out the current process, finds another that is READY, +;;; possibly the same process, and switches it in. When a process is +;;; restarted after calling switchout, it thinks it has just returned +;;; from switchout(). +;;; +;;; FIXME: make sure we optimise the switch to self case higher up the stack! +;;; +;;; This function can have no arguments or auto variables. +_switchout: + orcc #0x10 ; irq off + jsr _chksigs ; check for signals + + ;; save machine state + ldd #0 ; return zero + ;; return code set here is ignored, but _switchin can + ;; return from either _switchout OR _dofork, so they must both write + ;; U_DATA__U_SP with the following on the stack: + pshs d,y,u + sts U_DATA__U_SP ; save SP + + + ;; Stash the uarea into process memory bank + jsr map_process_always + ldx #U_DATA + ldy #U_DATA_STASH +stash ldd ,x++ + std ,y++ + cmpx #U_DATA+U_DATA__TOTALSIZE + bne stash + jsr map_kernel + + + jsr _getproc ; X = next process ptr + jsr _switchin ; and switch it in + ; we should never get here + jsr _trap_monitor + +_swapstack + .dw 0 + .dw 0 + + +badswitchmsg: + .ascii "_switchin: FAIL" + .db 13 + .db 10 + .db 0 + +;;; Switch in a process +;;; takes: X = process +;;; returns: shouldn't +_switchin: + orcc #0x10 ; irq off + + ;pshs x + stx _swapstack + + leax P_TAB__P_PAGE_OFFSET,x ; get address of page table + + + cmpx U_DATA__U_PAGE ; switching in ourselfs? + beq nostash ; yes then don't save UDATA + + jsr map_process ; map new process into memory + + ; fetch uarea from process memory + sty _swapstack+2 + ldx #U_DATA_STASH + ldy #U_DATA +stashb ldd ,x++ + std ,y++ + cmpx #U_DATA_STASH+U_DATA__TOTALSIZE + bne stashb + + ; we have now new stacks so get new stack pointer before any jsr + lds U_DATA__U_SP + + ; get back kernel page so that we see process table + jsr map_kernel + +nostash: + ;puls x + ldx _swapstack + ; check u_data->u_ptab matches what we wanted + cmpx U_DATA__U_PTAB + bne switchinfail + + lda #P_RUNNING + sta P_TAB__P_STATUS_OFFSET,x + + ;; fix-up page mappings (voodoo code?) + lda P_TAB__P_PAGE_OFFSET,x + sta U_DATA__U_PAGE + lda P_TAB__P_PAGE_OFFSET+1,x + sta U_DATA__U_PAGE+1 + lda P_TAB__P_PAGE_OFFSET+2,x + sta U_DATA__U_PAGE+2 + lda P_TAB__P_PAGE_OFFSET+3,x + sta U_DATA__U_PAGE+3 + + ;; clear the 16 bit tick counter + ldx #0 + stx _runticks + + ;; restore machine state -- note we may be returning from either + ;; _switchout or _dofork + lds U_DATA__U_SP + puls x,y,u ; return code and saved U and Y + + ;; enable interrupts, if the ISR isn't already running + lda U_DATA__U_ININTERRUPT + bne swtchdone + andcc #0xef +swtchdone: + rts + +switchinfail: + jsr outx + ldx #badswitchmsg + jsr outstring + ;; something went wrong and we didn't switch in what we asked for + jmp _trap_monitor + +fork_proc_ptr: + .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry + +;;; +;;; Called from _fork. We are in a syscall, the uarea is live as the +;;; parent uarea. The kernel is the mapped object. +;;; +_dofork: + ;; always disconnect the vehicle battery before performing maintenance + orcc #0x10 ; should already be the case ... belt and braces. + + ;; new process in X, get parent pid into y + stx fork_proc_ptr + ldx P_TAB__P_PID_OFFSET,x + + ;; Save the stack pointer and critical registers. + ;; When this process (the parent) is switched back in, it will be as if + ;; it returns with the value of the child's pid. + ;; Y has p->p_pid from above, the return value in the parent + pshs x,y,u + + ;; save kernel stack pointer -- when it comes back in the + ;; parent we'll be in + ;; _switchin which will immediately return (appearing to be _dofork() + ;; returning) and with HL (ie return code) containing the child PID. + ;; Hurray. + sts U_DATA__U_SP + + ;; now we're in a safe state for _switchin to return in the parent + ;; process. + + ;; --------- we switch stack copies in this call ----------- + jsr fork_copy ; copy 0x000 to udata.u_top and the + ; uarea and return on the childs + ; common + ;; We are now in the kernel child context + + ;; now the copy operation is complete we can get rid of the stuff + ;; _switchin will be expecting from our copy of the stack. + puls x + + ldx fork_proc_ptr ; get forked process + jsr _newproc ; and set it up + + ;; any calls to map process will now map the childs memory + + ldx #0 ; zero out process's tick counter + stx _runticks + ;; in the child process, fork() returns zero. + ;; + ;; And we exit, with the kernel mapped, the child now being deemed + ;; to be the live uarea. The parent is frozen in time and space as + ;; if it had done a switchout(). + puls y,u,pc + + +;;; copy the process memory to the new process +;;; and stash parent uarea to old bank +fork_copy: + ldx fork_proc_ptr + ldb P_TAB__P_PAGE_OFFSET,x ; new bank + lda U_DATA__U_PAGE ; old bank + jsr copybank + ldb P_TAB__P_PAGE_OFFSET+1,x ; new bank + lda U_DATA__U_PAGE+1 ; old bank + jsr copybank + ldb P_TAB__P_PAGE_OFFSET+2,x ; new bank + lda U_DATA__U_PAGE+2 ; old bank + jsr copybank + ;; stash parent urea (including kernel stack) + jsr map_process_always + ldx #U_DATA + ldu #U_DATA_STASH +stashf ldd ,x++ + std ,u++ + cmpx #U_DATA+U_DATA__TOTALSIZE + bne stashf + jsr map_kernel + ; --- we are now on the stack copy, parent stack is locked away --- + rts ; this stack is copied so safe to return on + +;;; Copy data from one bank to another +;;; takes: B = dest bank, A = src bank +;;; modifies: U +copybank + pshs d,x + ;; copy first block in bank + ldd 0xffa8 ; save mmu state + pshs d + ldd 0xffaa + pshs d + ;; map in src and dest + ldd 4,s ; D = banks + stb 0xffa8 + incb + stb 0xffa9 + sta 0xffaa + inca + sta 0xffab + ;; copy + ldx #0 + ldu #0x4000 +a@ ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + cmpx #0x4000 + bne a@ + ;; restore mmu + puls d + std 0xffaa + puls d + std 0xffa8 + ;; return + puls d,x,pc ; return diff --git a/Kernel/platform-coco3/ttydw.c b/Kernel/platform-coco3/ttydw.c new file mode 100644 index 00000000..710b9177 --- /dev/null +++ b/Kernel/platform-coco3/ttydw.c @@ -0,0 +1,86 @@ +/* Drivewire tty + This module needs some help to make this cross-platform. + And, it only handles one virtual Window. + */ + +#include +#include +#include +#include + +#define DW_FASTWRITE 0x80 +#define DW_SETSTAT 0xC4 +#define DW_SERREAD 0x43 + +#define DW_VOPEN 0x29 +#define DW_VCLOSE 0x2A + +/* How many vsync ticks to wait until polling again, if + DW reports no data is waiting. */ +#define MAX_WAIT TICKSPERSEC / 4 + +int wait=MAX_WAIT; + +/* Number of ports open. IF zero then polling routine + will not poll */ +int open_ports=0; + +void dw_putc( uint8_t minor, unsigned char c ){ + unsigned char buf[2]; + buf[0]=DW_FASTWRITE | (16 + minor - 3) ; + buf[1]=c; + dw_transaction( buf, 2, NULL, 0 ); + if( c == '\n' ){ + c='\r'; + dw_transaction( buf,2, NULL, 0 ); + } +} + + +void dw_vopen( uint8_t minor ){ + unsigned char buf[3]; + buf[0]=DW_SETSTAT; + buf[1]=minor-3+16; + buf[2]=DW_VOPEN; + dw_transaction( buf, 3, NULL, 0 ); + open_ports++; +} + + +void dw_vclose( uint8_t minor){ + unsigned char buf[3]; + buf[0]=DW_SETSTAT; + buf[1]=minor-3+16; + buf[2]=DW_VCLOSE; + dw_transaction( buf, 3, NULL, 0 ); + open_ports--; +} + +/* Poll and add chars (if any) to input q + no multple char reads yet + */ +void dw_vpoll( ){ + unsigned char buf[2]; + int i; + /* don't waste time polling of no port are open*/ + if( ! open_ports ) return ; + /* check ticks */ + if( --wait ) return; + for( i=0; i<4; i++){ + buf[0]=DW_SERREAD; + dw_transaction( buf, 1, buf, 2 ); + // nothing waiting ? + if( ! (buf[0] & 0x7e) ) { + wait=MAX_WAIT; + break; + } + // Window data? + if( buf[0] & 0x7e ){ + int minor=buf[0]-64+3; + if( buf[1]== '\r' ) buf[1]='\n'; + tty_inproc( minor, buf[1] ); + continue; + } + kprintf("out of band data\n"); + } +} diff --git a/Kernel/platform-coco3/ttydw.h b/Kernel/platform-coco3/ttydw.h new file mode 100644 index 00000000..d1157d29 --- /dev/null +++ b/Kernel/platform-coco3/ttydw.h @@ -0,0 +1,8 @@ +#ifndef __TTYDW_DOT_H__ +#define __TTYDW_DOT_H__ + +void dw_putc( uint8_t minor, unsigned char c ); +void dw_vopen( uint8_t minor ); +void dw_vclose( uint8_t minor ); +void dw_vpoll( ); +#endif diff --git a/Kernel/platform-coco3/usermem_gime.s b/Kernel/platform-coco3/usermem_gime.s new file mode 100644 index 00000000..a8acbe9a --- /dev/null +++ b/Kernel/platform-coco3/usermem_gime.s @@ -0,0 +1,135 @@ + .module usermem + +;;; +;;; 6809 copy to and from userspace via +;;; Color Computer 3 GIME mmu +;;; + + include "kernel.def" + include "../kernel09.def" + + ; exported + .globl __ugetc + .globl __ugetw + .globl __uget + .globl __ugets + .globl __uputc + .globl __uputw + .globl __uput + .globl __uzero + + ; imported + .globl map_process_always + .globl map_kernel + + .area .common + +__ugetc: + pshs cc ; save IRQ state + orcc #0x10 + jsr map_process_always + ldb ,x + jsr map_kernel + clra + tfr d,x + puls cc,pc ; back and return + +__ugetw: + pshs cc + orcc #0x10 + jsr map_process_always + ldx ,x + jsr map_kernel + puls cc,pc + +__uget: + pshs u,y,cc + ldu 7,s ; user address + ldy 9,s ; count + orcc #0x10 +ugetl: + jsr map_process_always + lda ,x+ + jsr map_kernel + sta ,u+ + leay -1,y + bne ugetl + ldx #0 + puls u,y,cc,pc + +__ugets: + pshs u,y,cc + ldu 7,s ; user address + ldy 9,s ; count + orcc #0x10 +ugetsl: + jsr map_process_always + lda ,x+ + beq ugetse + jsr map_kernel + sta ,u+ + leay -1,y + bne ugetsl + ldx #0xffff ; unterminated - error + lda #0 + sta -1,u ; force termination + puls u,y,cc,pc +ugetse: + jsr map_kernel + sta ,u + ldx #0 + puls u,y,cc,pc + + +__uputc: + pshs cc + orcc #0x10 + ldd 3,s + jsr map_process_always + exg d,x + stb ,x + jsr map_kernel + ldx #0 + puls cc,pc + +__uputw: + pshs cc + orcc #0x10 + ldd 3,s + jsr map_process_always + exg d,x + std ,x + jsr map_kernel + ldx #0 + puls cc,pc + +;;; X = source, user, size on stack +__uput: + pshs u,y,cc + orcc #0x10 + ldu 7,s ; user address + ldy 9,s ; count +uputl: + lda ,x+ + jsr map_process_always + sta ,u+ + jsr map_kernel + leay -1,y + bne uputl + ldx #0 + puls u,y,cc,pc + +__uzero: + pshs y,cc + lda #0 + ldy 5,s + orcc #0x10 + jsr map_process_always +uzloop: + sta ,x+ + leay -1,y + bne uzloop + jsr map_kernel + ldx #0 + puls y,cc,pc + -- 2.34.1