CoCo3 Fuzix (take two)
authorBrett Gordon <beretta42@gmail.com>
Wed, 17 Jun 2015 11:07:05 +0000 (12:07 +0100)
committerAlan Cox <alan@linux.intel.com>
Wed, 17 Jun 2015 11:07:05 +0000 (12:07 +0100)
UDATA/Banking is still non-ideal.
DriveWire virtual terminal still need help.
Stupid Comments fixed
devlpr removed

26 files changed:
Kernel/platform-coco3/AUTOEXEC.BAS [new file with mode: 0644]
Kernel/platform-coco3/Makefile [new file with mode: 0644]
Kernel/platform-coco3/README [new file with mode: 0644]
Kernel/platform-coco3/boot/boot.s [new file with mode: 0644]
Kernel/platform-coco3/build [new file with mode: 0755]
Kernel/platform-coco3/coco3.s [new file with mode: 0644]
Kernel/platform-coco3/commonmem.s [new file with mode: 0644]
Kernel/platform-coco3/config.h [new file with mode: 0644]
Kernel/platform-coco3/crt0.s [new file with mode: 0644]
Kernel/platform-coco3/device.h [new file with mode: 0644]
Kernel/platform-coco3/devices.c [new file with mode: 0644]
Kernel/platform-coco3/devtty.c [new file with mode: 0644]
Kernel/platform-coco3/devtty.h [new file with mode: 0644]
Kernel/platform-coco3/drivewire.s [new file with mode: 0644]
Kernel/platform-coco3/dw.def [new file with mode: 0644]
Kernel/platform-coco3/dwread.s [new file with mode: 0644]
Kernel/platform-coco3/dwwrite.s [new file with mode: 0644]
Kernel/platform-coco3/fuzix.link [new file with mode: 0644]
Kernel/platform-coco3/kernel.def [new file with mode: 0644]
Kernel/platform-coco3/libc.c [new file with mode: 0644]
Kernel/platform-coco3/main.c [new file with mode: 0644]
Kernel/platform-coco3/target.mk [new file with mode: 0644]
Kernel/platform-coco3/tricks.s [new file with mode: 0644]
Kernel/platform-coco3/ttydw.c [new file with mode: 0644]
Kernel/platform-coco3/ttydw.h [new file with mode: 0644]
Kernel/platform-coco3/usermem_gime.s [new file with mode: 0644]

diff --git a/Kernel/platform-coco3/AUTOEXEC.BAS b/Kernel/platform-coco3/AUTOEXEC.BAS
new file mode 100644 (file)
index 0000000..957b7be
--- /dev/null
@@ -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 (file)
index 0000000..7b06d4b
--- /dev/null
@@ -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 (file)
index 0000000..19a0f39
--- /dev/null
@@ -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 <F1>
+The pipe, "|", character can be produced with <SHIFT><F1>
+
+Pressing <CTRL><1> will switch to virtual console No. 1.
+Pressing <CTRL><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 (file)
index 0000000..72ae5e7
--- /dev/null
@@ -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 (executable)
index 0000000..f09a45c
--- /dev/null
@@ -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 (file)
index 0000000..c0127b2
--- /dev/null
@@ -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 (file)
index 0000000..1305076
--- /dev/null
@@ -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 (file)
index 0000000..b860fd3
--- /dev/null
@@ -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 (file)
index 0000000..7bb4797
--- /dev/null
@@ -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 (file)
index 0000000..47575eb
--- /dev/null
@@ -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 (file)
index 0000000..323ec60
--- /dev/null
@@ -0,0 +1,44 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devdw.h>
+#include <devsys.h>
+#include <tty.h>
+#include <vt.h>
+#include <devtty.h>
+
+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 (file)
index 0000000..118aff2
--- /dev/null
@@ -0,0 +1,331 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <vt.h>
+#include <tty.h>
+#include <devdw.h>
+#include <ttydw.h>
+
+#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 (file)
index 0000000..2ebd66d
--- /dev/null
@@ -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 (file)
index 0000000..c7ac5a3
--- /dev/null
@@ -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 (file)
index 0000000..677f4c7
--- /dev/null
@@ -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 (file)
index 0000000..1b4c587
--- /dev/null
@@ -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      <BBIN               ; check for start bit
+          beq       rxByte              ; branch if start bit detected
+          subb      #1                  ; decrement timeout lsb
+          bita      <BBIN
+          beq       rxByte
+          bcc       rx0020              ; loop until timeout lsb rolls under
+          bita      <BBIN
+          beq       rxByte
+          addb      ,s                  ; B = timeout msb - 1
+          bita      <BBIN
+          beq       rxByte
+          stb       ,s                  ; store decremented timeout msb
+          bita      <BBIN
+          bne       rx0010              ; loop if still no start bit
+
+* Read a byte
+rxByte    leay      ,-y                 ; decrement request count
+          ldd       #$ff80              ; A = timeout msb, B = shift counter
+          sta       ,s                  ; reset timeout msb for next byte
+rx0030    exg       a,a
+          nop
+          lda       <BBIN               ; read data bit
+          lsra                          ; shift into carry
+          rorb                          ; rotate into byte accumulator
+          lda       #$01                ; prep stop bit mask
+          bcc       rx0030              ; loop until all 8 bits read
+
+          stb       ,u+                 ; store received byte to memory
+          abx                           ; update checksum
+          ldb       #$ff                ; set timeout lsb for next byte
+          anda      <BBIN               ; read stop bit
+          beq       rxExit              ; exit if framing error
+          leay      ,y                  ; test request count
+          bne       rx0020              ; loop if another byte wanted
+          lda       #$03                ; setup to return SUCCESS
+
+* Clean up, set status and return
+rxExit    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
+          setdp     $00
+
+
+          ELSE
+          IFNE H6309
+*******************************************************
+* 57600 (115200) bps using 6309 native mode
+*******************************************************
+
+DWRead    clrb                          ; clear Carry (no framing error)
+          decb                          ; clear Z flag, B = $FF
+          pshs      u,x,dp,cc           ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+*         ldmd      #1                  ; requires 6309 native mode
+          tfr       b,dp                ; set direct page to $FFxx
+          setdp     $ff
+          leay      -1,y                ; adjust request count
+          leau      ,x                  ; U = storage ptr
+          tfr       0,x                 ; initialize checksum
+          lda       #$01                ; A = serial in mask
+          bra       rx0030              ; go wait for start bit
+
+* Read a byte
+rxByte    sexw                          ; 4 cycle delay
+          ldw       #$006a              ; shift counter and timing flags
+          clra                          ; clear carry so next will branch
+rx0010    bcc       rx0020              ; branch if even bit number (15 cycles)
+          nop                           ; extra (16th) cycle
+rx0020    lda       <BBIN               ; read bit
+          lsra                          ; move bit into carry
+          rorb                          ; rotate bit into byte accumulator
+          lda       #0                  ; prep A for 8th data bit
+          lsrw                          ; bump shift count, timing bit to carry
+          bne       rx0010              ; loop until 7th data bit has been read
+          incw                          ; W = 1 for subtraction from Y
+          inca                          ; A = 1 for reading bit 7
+          anda      <BBIN               ; read bit 7
+          lsra                          ; move bit 7 into carry, A = 0
+          rorb                          ; byte is now complete
+          stb       ,u+                 ; store received byte to memory
+          abx                           ; update checksum
+          subr      w,y                 ; decrement request count
+          inca                          ; A = 1 for reading stop bit
+          anda      <BBIN               ; read stop bit
+          bls       rxExit              ; exit if completed or framing error
+
+* Wait for a start bit or timeout
+rx0030    clrw                          ; initialize timeout counter
+rx0040    bita      <BBIN               ; check for start bit
+          beq       rxByte              ; branch if start bit detected
+          addw      #1                  ; bump timeout counter
+          bita      <BBIN
+          beq       rxByte
+          bcc       rx0040              ; loop until timeout rolls over
+          lda       #$03                ; setup to return TIMEOUT status
+
+* Clean up, set status and return
+rxExit    beq       rx0050              ; branch if framing error
+          eora      #$02                ; toggle SUCCESS flag
+rx0050    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
+          setdp     $00
+
+
+          ELSE
+*******************************************************
+* 57600 (115200) 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
+          lda       #$01                ; A = serial in mask
+          bra       rx0030              ; go wait for start bit
+
+* Read a byte
+rxByte    leau      1,u                 ; bump storage ptr
+          leay      ,-y                 ; decrement request count
+          lda       <BBIN               ; read bit 0
+          lsra                          ; move bit 0 into Carry
+          ldd       #$ff20              ; A = timeout msb, B = shift counter
+          sta       ,s                  ; reset timeout msb for next byte
+          rorb                          ; rotate bit 0 into byte accumulator
+rx0010    lda       <BBIN               ; read bit (d1, d3, d5)
+          lsra
+          rorb
+          bita      1,s                 ; 5 cycle delay
+          bcs       rx0020              ; exit loop after reading bit 5
+          lda       <BBIN               ; read bit (d2, d4)
+          lsra
+          rorb
+          leau      ,u
+          bra       rx0010
+
+rx0020    lda       <BBIN               ; read bit 6
+          lsra
+          rorb
+          leay      ,y                  ; test request count
+          beq       rx0050              ; branch if final byte of request
+          lda       <BBIN               ; read bit 7
+          lsra
+          rorb                          ; byte is now complete
+          stb       -1,u                ; store received byte to memory
+          abx                           ; update checksum
+          lda       <BBIN               ; read stop bit
+          anda      #$01                ; mask out other bits
+          beq       rxExit              ; exit if framing error
+
+* Wait for a start bit or timeout
+rx0030    bita      <BBIN               ; check for start bit
+          beq       rxByte              ; branch if start bit detected
+          bita      <BBIN               ; again
+          beq       rxByte
+          ldb       #$ff                ; init timeout lsb
+rx0040    bita      <BBIN
+          beq       rxByte
+          subb      #1                  ; decrement timeout lsb
+          bita      <BBIN
+          beq       rxByte
+          bcc       rx0040              ; loop until timeout lsb rolls under
+          bita      <BBIN
+          beq       rxByte
+          addb      ,s                  ; B = timeout msb - 1
+          bita      <BBIN
+          beq       rxByte
+          stb       ,s                  ; store decremented timeout msb
+          bita      <BBIN
+          beq       rxByte
+          bcs       rx0030              ; loop if timeout hasn't expired
+          bra       rxExit              ; exit due to timeout
+
+rx0050    lda       <BBIN               ; read bit 7 of final byte
+          lsra
+          rorb                          ; byte is now complete
+          stb       -1,u                ; store received byte to memory
+          abx                           ; calculate final checksum
+          lda       <BBIN               ; read stop bit
+          anda      #$01                ; mask out other bits
+          ora       #$02                ; return SUCCESS if no framing error
+
+* Clean up, set status and return
+rxExit    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
+          ;setdp     $00
+
+          ENDC
+          ENDC
+          ENDC
+
diff --git a/Kernel/platform-coco3/dwwrite.s b/Kernel/platform-coco3/dwwrite.s
new file mode 100644 (file)
index 0000000..d262968
--- /dev/null
@@ -0,0 +1,196 @@
+*******************************************************
+*
+* Copied from HDB-DOS from toolshed.sf.net
+* The original code is public domain
+*
+* DWWrite
+*    Send a packet to the DriveWire server.
+*    Serial data format:  1-8-N-1
+*    4/12/2009 by Darren Atkinson
+*
+* Entry:
+*    X  = starting address of data to send
+*    Y  = number of bytes to send
+*
+* Exit:
+*    X  = address of last byte sent + 1
+*    Y  = 0
+*    All others preserved
+*
+
+
+          IFNE ARDUINO
+DWWrite   pshs      a                  ; preserve registers
+txByte
+          lda       ,x+                ; get byte from buffer
+          sta       $FF52              ; put it to PIA
+loop@     tst       $FF53              ; check status register
+          bpl       loop@              ; until CB1 is set by Arduino, continue looping
+          tst       $FF52              ; clear CB1 in status register
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          puls      a,pc                ; restore registers and return
+
+          ELSE
+
+          IFNE JMCPBCK
+DWWrite   pshs      d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+txByte
+          lda       ,x+
+          sta       $FF44
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          puls      cc,d,pc           ; restore registers and return
+
+          ELSE
+          IFNE BECKER
+          IFNDEF BCKPORT
+BCKPORT   equ   $FF42
+          ENDC
+DWWrite   pshs      d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+;          ldu       #BBOUT              ; point U to bit banger out register
+;          lda       3,u                 ; read PIA 1-B control register
+;          anda      #$f7                ; clear sound enable bit
+;          sta       3,u                 ; disable sound output
+;          fcb       $8c                 ; skip next instruction
+
+txByte
+          lda       ,x+
+          sta       BCKPORT
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          puls      cc,d,pc           ; restore registers and return
+          ENDC
+          ENDC
+          ENDC
+
+          IFEQ BECKER+JMCPBCK+ARDUINO
+          IFNE BAUD38400
+*******************************************************
+* 38400 bps using 6809 code and timimg
+*******************************************************
+
+DWWrite   pshs      u,d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+          ldu       #BBOUT              ; point U to bit banger out register
+          lda       3,u                 ; read PIA 1-B control register
+          anda      #$f7                ; clear sound enable bit
+          sta       3,u                 ; disable sound output
+          fcb       $8c                 ; skip next instruction
+
+txByte    stb       ,--u                ; send stop bit
+          leau      ,u+
+          lda       #8                  ; counter for start bit and 7 data bits
+          ldb       ,x+                 ; get a byte to transmit
+          lslb                          ; left rotate the byte two positions..
+          rolb                          ; ..placing a zero (start bit) in bit 1
+tx0010    stb       ,u++                ; send bit
+          tst       ,--u
+          rorb                          ; move next bit into position
+          deca                          ; decrement loop counter
+          bne       tx0010              ; loop until 7th data bit has been sent
+          leau      ,u
+          stb       ,u                  ; send bit 7
+          lda       ,u++
+          ldb       #$02                ; value for stop bit (MARK)
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          stb       ,--u                ; leave bit banger output at MARK
+          puls      cc,d,u,pc           ; restore registers and return
+
+          ELSE
+
+          IFNE H6309
+*******************************************************
+* 57600 (115200) bps using 6309 native mode
+*******************************************************
+
+DWWrite   pshs      u,d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+*         ldmd      #1                  ; requires 6309 native mode
+          ldu       #BBOUT+1            ; point U to bit banger out register +1
+          aim       #$f7,2,u            ; disable sound output
+          lda       #8                  ; counter for start bit and 7 data bits
+          fcb       $8c                 ; skip next instruction
+
+txByte    stb       -1,u                ; send stop bit
+tx0010    ldb       ,x+                 ; get a byte to transmit
+          lslb                          ; left rotate the byte two positions..
+          rolb                          ; ..placing a zero (start bit) in bit 1
+          bra       tx0030
+
+tx0020    bita      #1                  ; even or odd bit number ?
+          beq       tx0040              ; branch if even (15 cycles)
+tx0030    nop                           ; extra (16th) cycle
+tx0040    stb       -1,u                ; send bit
+          rorb                          ; move next bit into position
+          deca                          ; decrement loop counter
+          bne       tx0020              ; loop until 7th data bit has been sent
+          leau      ,u+
+          stb       -1,u                ; send bit 7
+          ldd       #$0802              ; A = loop counter, B = MARK value
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          stb       -1,u                ; final stop bit
+          puls      cc,d,u,pc           ; restore registers and return
+
+          ELSE
+*******************************************************
+* 57600 (115200) bps using 6809 code and timimg
+*******************************************************
+
+DWWrite   pshs      dp,d,cc             ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+          ldd       #$04ff              ; A = loop counter, B = $ff
+          tfr       b,dp                ; set direct page to $FFxx
+          ;setdp     $ff
+          ldb       <$ff23              ; read PIA 1-B control register
+          andb      #$f7                ; clear sound enable bit
+          stb       <$ff23              ; disable sound output
+          fcb       $8c                 ; skip next instruction
+
+txByte    stb       <BBOUT              ; send stop bit
+          ldb       ,x+                 ; get a byte to transmit
+          nop
+          lslb                          ; left rotate the byte two positions..
+          rolb                          ; ..placing a zero (start bit) in bit 1
+tx0020    stb       <BBOUT              ; send bit (start bit, d1, d3, d5)
+          rorb                          ; move next bit into position
+          exg       a,a
+          nop
+          stb       <BBOUT              ; send bit (d0, d2, d4, d6)
+          rorb                          ; move next bit into position
+          leau      ,u
+          deca                          ; decrement loop counter
+          bne       tx0020              ; loop until 7th data bit has been sent
+
+          stb       <BBOUT              ; send bit 7
+          ldd       #$0402              ; A = loop counter, B = MARK value
+          leay      ,-y                 ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          stb       <BBOUT              ; leave bit banger output at MARK
+          puls      cc,d,dp,pc          ; restore registers and return
+          ;setdp     $00
+
+          ENDC
+          ENDC
+          ENDC
+
diff --git a/Kernel/platform-coco3/fuzix.link b/Kernel/platform-coco3/fuzix.link
new file mode 100644 (file)
index 0000000..bbe1824
--- /dev/null
@@ -0,0 +1,14 @@
+define basesympat __sectionbase_%s__
+define lensympat __sectionlen_%s__
+section .start load 0x0200
+section .text2
+section .text
+section .text.hot
+section .test.unlikely
+section .discard
+section .data
+section        .bss
+section .video load 0xa880
+section .udata load 0xc000
+section .common
+entry start
diff --git a/Kernel/platform-coco3/kernel.def b/Kernel/platform-coco3/kernel.def
new file mode 100644 (file)
index 0000000..c061112
--- /dev/null
@@ -0,0 +1,22 @@
+;;; UZI mnemonics for memory addresses etc
+
+U_DATA                      equ 0xc000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           equ 0x200        ; 256+256 bytes.
+
+U_DATA_STASH               equ 0xBd00       ; FC00-FEFF
+
+
+;;; We don't need these macros for we have no 
+;;; SAM shenanigans on a CoCo3
+
+SAM_USER macro
+       endm
+
+SAM_KERNEL macro
+       endm
+
+SAM_SAVE macro
+       endm
+
+SAM_RESTORE macro
+       endm
diff --git a/Kernel/platform-coco3/libc.c b/Kernel/platform-coco3/libc.c
new file mode 100644 (file)
index 0000000..55d3d7f
--- /dev/null
@@ -0,0 +1,36 @@
+#include "cpu.h"
+
+void *memcpy(void *d, const void *s, size_t sz)
+{
+  unsigned char *dp = d;
+  const unsigned char *sp = s;
+  while(sz--)
+    *dp++=*sp++;
+  return d;
+}
+
+void *memset(void *d, int c, size_t sz)
+{
+  unsigned char *p = d;
+  while(sz--)
+    *p++ = c;
+  return d;
+}
+
+size_t strlen(const char *p)
+{
+  const char *e = p;
+  while(*e++);
+  return e-p-1;
+}
+
+/* Until we pull out the bits of libgcc that are useful instead */
+void abort(void)
+{
+  while(1);
+}
+
+void *malloc(size_t size)
+{
+  return 0;
+}
diff --git a/Kernel/platform-coco3/main.c b/Kernel/platform-coco3/main.c
new file mode 100644 (file)
index 0000000..ff18e6e
--- /dev/null
@@ -0,0 +1,37 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+
+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 (file)
index 0000000..e9abbba
--- /dev/null
@@ -0,0 +1 @@
+export CPU = 6809
diff --git a/Kernel/platform-coco3/tricks.s b/Kernel/platform-coco3/tricks.s
new file mode 100644 (file)
index 0000000..d32c35e
--- /dev/null
@@ -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 (file)
index 0000000..710b917
--- /dev/null
@@ -0,0 +1,86 @@
+/* Drivewire tty
+        This module needs some help to make this cross-platform.
+       And, it only handles one virtual Window.
+ */
+
+#include <kernel.h>
+#include <printf.h>
+#include <tty.h>
+#include <devdw.h>
+
+#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 (file)
index 0000000..d1157d2
--- /dev/null
@@ -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 (file)
index 0000000..a8acbe9
--- /dev/null
@@ -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
+