UDATA/Banking is still non-ideal.
DriveWire virtual terminal still need help.
Stupid Comments fixed
devlpr removed
--- /dev/null
+10 RUNM"BOOT.BIN" 'DW1
+
--- /dev/null
+
+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
+
--- /dev/null
+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.
+
+
--- /dev/null
+;;;
+;;; 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
--- /dev/null
+
+# 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
+
--- /dev/null
+;;;
+;;; 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
+
--- /dev/null
+;
+; 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
--- /dev/null
+/* 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 */
+
+
--- /dev/null
+;;;
+;;; 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
+
--- /dev/null
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+
+#endif /* __DEVICE_DOT_H__ */
--- /dev/null
+#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)
+{
+}
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+
+int my_tty_close( uint8_t minor ); /* wrapper call to close DW ports */
+
+#endif
--- /dev/null
+;;
+;; 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"
+
--- /dev/null
+********************************************************************
+*
+* 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
+
--- /dev/null
+*******************************************************
+*
+* 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
+
--- /dev/null
+*******************************************************
+*
+* 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
+
--- /dev/null
+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
--- /dev/null
+;;; 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
--- /dev/null
+#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;
+}
--- /dev/null
+#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)
+{
+}
+
+
--- /dev/null
+export CPU = 6809
--- /dev/null
+;;;
+;;; 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
--- /dev/null
+/* 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");
+ }
+}
--- /dev/null
+#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
--- /dev/null
+ .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
+