--- /dev/null
+
+CSRCS = devices.c main.c
+
+# Code that must be present for the bootstrap
+CISRCS = mini_ide.c
+
+C3SRCS = libc.c devtty.c
+
+CDSRCS = discard.c mini_ide_discard.c
+
+DSRCS = ../dev/devdw.c
+
+ASRCS = crt0.s coco2.s ide.s usermem.s bootstrap.s
+ASRCS += tricks.s commonmem.s drivewire.s video.s
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+CIOBJS = $(CISRCS:.c=$(BINEXT))
+C3OBJS = $(C3SRCS:.c=$(BINEXT))
+CDOBJS = $(CDSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.s=$(BINEXT))
+DOBJS = $(patsubst ../dev/%.c,%.o, $(DSRCS))
+OBJS = $(COBJS) $(C3OBJS) $(CDOBJS) $(AOBJS) $(DOBJS) $(CIOBJS)
+
+CROSS_CCOPTS += -I../dev/
+
+all: $(OBJS)
+
+export CROSS_CC_SEGD=-mcode-section=.text3
+
+$(COBJS): %$(BINEXT): %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) -c $<
+
+$(CIOBJS): %$(BINEXT): %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG1) -c $<
+
+$(C3OBJS): %$(BINEXT): %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGD) -c $<
+
+$(CDOBJS): %$(BINEXT): %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DOBJS): %$(BINEXT): ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGD) -c $<
+
+$(DDOBJS): %$(BINEXT): ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(AOBJS): %$(BINEXT): %.s
+ $(CROSS_AS) $(ASOPTS) $< -o $*.o
+
+clean:
+ rm -f *.o *~
+
+image: bootfuz.bin
+ $(CROSS_LD) -o ../fuzix.bin --map=../fuzix.map --script=fuzix.link \
+ crt0.o bootstrap.o commonmem.o coco2.o discard.o ../simple.o \
+ ../start.o ../version.o ../lowlevel-6809.o \
+ tricks.o main.o ../timer.o ../kdata.o devices.o \
+ drivewire.o devdw.o mini_ide.o mini_ide_discard.o \
+ ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+ ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o \
+ ../tty.o ../devsys.o ../usermem.o usermem.o ../syscall_fs2.o \
+ ../syscall_exec16.o devtty.o libc.o ../vt.o video.o ../syscall_fs3.o \
+ ../font8x8.o
+ ../tools/decb-image <../fuzix.bin fuzix.img
+
+bootfuz.bin: bootloader.s
+ lwasm -r -b -obootfuz.bin bootloader.s
+
--- /dev/null
+COCO2
+=====
+
+COCO or Dragon 64 with an IDE port, cartridge and 64K of RAM
+
+Supported hardware:
+ IDE (Glenside or compatible)
+
+Memory Map
+==========
+0000-00FF Interrupt stack
+0100-01FF Vectors (then wasted - could hide libc.o in there ?)
+0200-19FF Display
+1A00-1BFF udata/stack
+1C00-7FFF Code/Data for common plus some kernel
+8000-FEFF User space
+FF00-FFFF I/O etc
+
+Cartridge
+C000-FEFF Kernel
+
+
+Emulating in XRoar
+==================
+
+Needs the IDE patches
+
+TODO
+====
+
+Loader code
+Set the display up correctly
+Support for a real time clock and clock locking
+Review irq disabling. We shouldn't need much of this at all as we don't have
+floppy hell to contend with, but the switchin/switchout logic needs to be
+reviewed for interrupt safety and the IRQs re-enabled during swap in and
+out. We should also be totally clean now on FIR blocking, so audio might
+actually be doable!
+
+MPI switching
+
+Could we do a cartridge version
+- Re-order so common is in low memory
+- Support map_kernel/map_process flipping
+- Add asm helpers for user mode copying (trivial - and since we never copy
+ into kernel ROM we can optimise them a lot - one map switch only)
+- Fix IDE to support the map flip on transfers (needs little asm code
+ adding)
+- How to do discard, can we just take the hit or do we need to copy the
+ entire cartridge into high RAM, run in high RAM with discard at say
+ 0xA000 and then in platform_discard switch on map_kernel cartridge
+ selection so we can let userspace blow away the upper 32K of the RAM
+ mapping.
+
+16K Cartridge version would give us space for
+- Proper video (costs us about 8K)
+- Nice loader (just 'EXEC $C000' and go) < 1K
+- Probably all of sound/joysticks/printer/floppy and a few more buffers
+- Full size user memory bank (so can run full v7 shell) 4K
+
+
+Write a loader into the cartridge start so it bootstraps off disk and runs
+nicely
+
+6847T1 lower case ?
+
--- /dev/null
+;
+; Bootstrap for cartridge start up. For now load from block 1 (second
+; block). We can refine this later. We do 51 block loads from block 1
+; for 1A00 to 7FFF and then copy 1A00 to 0100 for vectors
+;
+; Needs some kind of global timeout -> error handling
+;
+;
+; Load block b
+;
+ .module bootstrap
+
+ .globl load_image
+
+ .area .text
+
+load_block:
+ lda #$FF
+ tfr a,dp
+load_block_1:
+ lda #$80
+ bita <$FF57 ; busy
+ bne load_block_1
+ lda #$40
+ sta <$FF56
+load_block_2:
+ lda #$80
+ bita <$FF57 ; busy
+ bne load_block_2
+ clr <$FF55
+ clr <$FF54
+ stb <$FF53 ; block number to fetch
+ lda #1
+ sta <$FF52
+
+
+ lda #$40
+wait_drdy:
+ bita <$FF57
+ beq wait_drdy
+ lda #$20 ; read command
+ sta <$FF57
+ clrb
+ lda #$08
+wait_drq:
+ bita <$FF57 ; DRQ
+ beq wait_drq
+copyloop:
+ lda <$FF50 ; read word and latch
+ sta ,x+
+ lda <$FF58 ; latched byte
+ sta ,x+
+ decb
+ bne copyloop
+ lda #$80
+wait_bsy:
+ bita <$FF57
+ bne wait_bsy
+ lda #$01
+ bita <$FF57
+ bne load_error
+ rts
+
+
+load_image:
+ ldy #$0400 ; display at this point
+ lda #'G'
+ sta ,y+
+ ldb #1
+ lda #51
+ ldx #$1A00
+load_loop:
+ pshs a,b
+ bsr load_block
+ lda #'*'
+ sta ,y+
+ puls a,b
+ incb
+ deca
+ bne load_loop
+ ldx #$1A00
+ ldu #$0100
+vec_copy:
+ ldd ,x++
+ std ,u++
+ cmpu #$0200
+ bne vec_copy
+
+ ldx #$1A00
+ clra
+ clrb
+ud_wipe:
+ std ,x++
+ cmpx #$1C00
+ bne ud_wipe
+endstr: rts
+
+load_error:
+ ldu #fail
+copy_str:
+ lda ,u+
+ beq endstr
+ sta ,y+
+ bra copy_str
+fail:
+ .ascii "Fail"
+ .db 0
--- /dev/null
+#define CART_DRAGONDOS 1 /* DragonDOS floppy */
+#define CART_DELTADOS 2 /* DeltaDOS floppy */
+#define CART_RSDOS 3 /* RSDOS Cartridge */
+#define CART_ORCH90 4 /* Orchestra Sound */
+
+extern int cart_find(int id);
+extern uint8_t carttype[4];
+extern uint8_t cartslots;
+extern uint8_t bootslot;
+extern uint8_t system_id;
--- /dev/null
+ ;
+ ; COCO2 platform
+ ;
+
+ .module coco2
+
+ ; exported
+ .globl _mpi_present
+ .globl _mpi_set_slot
+ .globl _cart_hash
+ .globl map_kernel
+ .globl map_process
+ .globl map_process_a
+ .globl map_process_always
+ .globl map_save
+ .globl map_restore
+ .globl init_early
+ .globl init_hardware
+ .globl _program_vectors
+ .globl _need_resched
+
+ .globl _ramsize
+ .globl _procmem
+
+ ; imported
+ .globl unix_syscall_entry
+;FIX .globl fd_nmi_handler
+ .globl null_handler
+ .globl _vtoutput
+
+ ; exported debugging tools
+ .globl _trap_monitor
+ .globl _trap_reboot
+ .globl outchar
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
+
+ include "kernel.def"
+ include "../kernel09.def"
+
+
+ .area .vectors
+ ;
+ ; At 0x100 as required by the COCO ROM
+ ;
+ jmp badswi_handler ; 0x100
+ jmp badswi_handler ; 0x103
+ jmp unix_syscall_entry ; 0x106
+ ; FIXME: 109 needs to handle bad NMI!
+ jmp badswi_handler ; 0x109
+ jmp interrupt_handler ; 0x10C
+ jmp firq_handler ; 0x10F
+
+ .area .text
+
+init_early:
+ ldx #null_handler
+ stx 1
+ lda #0x7E
+ sta 0
+ sta 0x0071 ; BASIC cold boot flag (will get trashed by
+ ; irq stack but hopefully still look bad)
+ ;
+ ; Move the display
+ ;
+ ldx #0xFFC7
+ clr ,x+ ; Set F0
+ clr ,x++ ; Clear F1-F6
+ clr ,x++
+ clr ,x++
+ clr ,x++
+ clr ,x++
+ clr ,x++
+ rts
+
+init_hardware:
+ ldd #64
+ std _ramsize
+ ldd #32
+ std _procmem
+
+ ; Turn on PIA CB1 (50Hz interrupt)
+ lda 0xFF03
+ ora #1
+ sta 0xFF03
+ jsr _vtinit
+ rts
+
+ .area .common
+
+_trap_reboot:
+ orcc #0x10
+ clr 0xFFBE
+ lda #0x7e
+ sta 0x0071 ; in case IRQ left it looking valid
+ jmp [0xFFFE]
+
+_trap_monitor:
+ orcc #0x10
+ bra _trap_monitor
+
+___hard_di:
+ tfr cc,b ; return the old irq state
+ orcc #0x10
+ rts
+___hard_ei:
+ andcc #0xef
+ rts
+
+___hard_irqrestore: ; B holds the data
+ tfr b,cc
+ rts
+
+;
+; COMMON MEMORY PROCEDURES FOLLOW
+;
+
+ .area .common
+;
+; Our vectors live in a fixed block and are not banked out. Likewise
+; No memory management for now
+;
+_program_vectors:
+map_kernel:
+ pshs a
+ clr $ffdf ; ROM in
+ lda #1
+map_kr:
+ sta romin
+ puls a,pc
+
+map_process:
+map_process_always:
+map_process_a:
+ clr $ffde ; ROM out
+ clr romin
+ rts
+
+map_restore:
+ pshs a
+ lda romsave
+ sta romin
+ bne map_kr
+ clr $ffde
+ puls a,pc
+
+map_save:
+ pshs a
+ lda romin
+ sta romsave
+ puls a,pc
+;
+; Helpers for the MPI and Cartridge Detect
+;
+
+;
+; oldslot = mpi_set_slot(uint8_t newslot)
+;
+_mpi_set_slot:
+ tfr b,a
+ ldb 0xff7f
+ sta 0xff7f
+ rts
+;
+; int8_t mpi_present(void)
+;
+_mpi_present:
+ lda 0xff7f ; Save bits
+ ldb #0xff ; Will get back 33 from an MPI cartridge
+ stb 0xff7f ; if the emulator is right on this
+ ldb 0xff7f
+ cmpb #0x33
+ bne nompi
+ clr 0xff7f ; Switch to slot 0
+ ldb 0xff7f
+ bne nompi
+ incb
+ sta 0xff7f ; Our becker port for debug will be on the default
+ ; slot so put it back for now
+ rts ; B = 0
+nompi: ldb #0
+ sta 0xff7f ; Restore bits just in case
+ rts
+
+ .area .text ; Must be clear of cartridge mapping areas
+;
+; uint16_t cart_hash(void)
+;
+_cart_hash:
+ pshs cc
+ orcc #0x10
+ ldx #0xC000
+ ldd #0
+ clr $FFBE ; Map cartridge
+hashl:
+ addd ,x++
+ cmpx #0xC200
+ bne hashl
+ tfr d,x
+ clr $FFBF ; Return to normality
+ puls cc,pc
+
+
+ .area .common
+;
+; FIXME:
+;
+firq_handler:
+badswi_handler:
+ rti
+
+;
+; debug via printer port
+;
+outchar:
+ sta 0xFF02
+ lda 0xFF20
+ ora #0x02
+ sta 0xFF20
+ anda #0xFD
+ sta 0xFF20
+ rts
+
+ .area .common
+
+_need_resched:
+ .db 0
+romin:
+ .db 0
+romsave:
+ .db 0
--- /dev/null
+;
+ .module commonmem
+
+ ; exported symbols
+ .globl _ub
+ .globl _udata
+ .globl kstack_top
+ .globl istack_top
+ .globl istack_switched_sp
+
+ .area .udata
+
+_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+ zmb 512
+kstack_top:
+
+ .area .istack
+
+ ; 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 */
+#undef CONFIG_MULTI
+/* Single tasking - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+/* Pure swap */
+#define CONFIG_SWAP_ONLY
+#define CONFIG_SPLIT_UDATA
+#define UDATA_BLKS 1
+
+#define CONFIG_BANKS 1
+/* And swapping */
+#define SWAPDEV 0x0 /* Uses part of IDE slice 0 */
+#define SWAP_SIZE 0x40 /* 32K in 512 byte blocks */
+#define SWAPBASE 0x8000 /* We swap the lot, including stashed uarea */
+#define SWAPTOP 0xFE00 /* so it's a round number of 512 byte sectors */
+#define UDATA_SIZE 0x0200 /* one block */
+#define MAX_SWAPS 32
+
+/* Permit large I/O requests to bypass cache and go direct to userspace */
+#define CONFIG_LARGE_IO_DIRECT
+
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+#define CONFIG_FONT8X8
+#define CONFIG_FONT8X8SMALL
+
+extern unsigned char vt_mangle_6847(unsigned char c);
+#define VT_MAP_CHAR(x) vt_mangle_6847(x)
+
+/* Vt definitions */
+#define VT_WIDTH 32
+#define VT_HEIGHT 24
+#define VT_RIGHT 31
+#define VT_BOTTOM 23
+#define VT_INITIAL_LINE 0
+
+#define VIDEO_BASE 0x0200
+
+#define TICKSPERSEC 50 /* Ticks per second */
+#define PROGBASE 0x8000 /* also data base */
+#define PROGLOAD 0x8000 /* also data base */
+#define PROGTOP 0xF000 /* Top of program */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE NULL /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+#define NDEVS 2 /* Devices 0..NDEVS-1 are capable of being mounted */
+ /* (add new mountable devices to beginning area.) */
+#define TTYDEV 513 /* Device used by kernel for messages, panics */
+#define NBUFS 6 /* Number of block buffers */
+#define NMOUNTS 2 /* Number of mounts at a time */
+#define swap_map(x) ((uint8_t *)(x))
+
--- /dev/null
+ ; exported
+ .globl start
+
+ ; imported symbols
+ .globl _fuzix_main
+ .globl init_early
+ .globl init_hardware
+ .globl kstack_top
+ .globl _system_id
+
+ ; startup code
+ .area .start
+
+;
+; Entry - cartridge mapped at C000, system ROM at 8000, RAM at low 32K
+;
+
+start:
+ orcc #0x10 ; interrupts definitely off
+ lds #$0100 ; not written by loader
+ jsr load_image ; load the rest of the OS from disk
+ jmp main
+
+ .area .text
+
+main:
+ lds #kstack_top
+ ldx #__sectionbase_.bss__
+ ldy #__sectionlen_.bss__
+ clra
+bss_wipe: sta ,x+
+ leay -1,y
+ bne bss_wipe
+ ; This might be in BSS so don't save until we've wiped!
+ lda #0
+ ldb $80FD ; save from ROM space
+ cmpb #0x49 ; Dragon32
+ beq identified
+ inca
+ cmpb #0x31 ; COCO1/2
+ beq identified
+ inca
+ cmpb #0x32 ; COCO3
+ beq identified
+ inca ; Beats me
+identified:
+ sta _system_id ; what sort of a box are we ?
+ jsr init_early
+ jsr init_hardware
+ jsr _fuzix_main
+ orcc #0x10
+stop: bra stop
+
--- /dev/null
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flag);
+void fd_timer_tick(void);
+
+/* low level interface */
+uint8_t fd_reset(uint8_t *drive);
+uint8_t fd_operation(uint8_t *cmd, uint8_t *drive);
+uint8_t fd_motor_on(uint8_t drive);
+uint8_t fd_motor_off(void);
+
+#endif /* __DEVFD_DOT_H__ */
+
--- /dev/null
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern uint8_t system_id;
+extern uint8_t mpi_present(void);
+extern uint8_t mpi_set_slot(uint8_t slot);
+extern uint16_t cart_hash(void);
+
+extern uint8_t spi_setup(void);
+
+#endif /* __DEVICE_DOT_H__ */
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devdw.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <tty.h>
+#include <vt.h>
+#include <devtty.h>
+#include <mini_ide.h>
+#include <device.h>
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+// minor open close read write ioctl
+// -----------------------------------------------------------------
+ /* 0: /dev/hd Hard disc block devices (IDE) */
+ { ide_open, no_close, ide_read, ide_write, ide_ioctl },
+ /* 1: /dev/fd Floppy disc block devices */
+ { no_open, no_close, no_rdwr, no_rdwr , no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, vt_ioctl },
+ /* 3: /dev/lpr Printer devices */
+ { no_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 },
+ /* 8: /dev/dw DriveWire remote disk images */
+ { 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)
+{
+ ide_probe();
+}
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <device.h>
+#include <devlpr.h>
+
+volatile uint8_t * const pia0b = (uint8_t *)0xFF02;
+volatile uint8_t * const pia1a = (uint8_t *)0xFF20;
+volatile uint8_t * const pia1b = (uint8_t *)0xFF22;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+ if (minor < 2)
+ return 0;
+ udata.u_error = ENODEV;
+ return -1;
+}
+
+int lpr_close(uint8_t minor)
+{
+ if (minor == 1)
+ dw_lpr_close();
+ return 0;
+}
+
+static int iopoll(int sofar)
+{
+ /* Ought to be a core helper for this lot ? */
+ if (need_resched())
+ _sched_yield();
+ if (udata.u_cursig || udata.u_ptab->p_pending) {
+ if (sofar)
+ return sofar;
+ udata.u_error = EINTR;
+ return -1;
+ }
+ return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ uint8_t *p = udata.u_base;
+ uint8_t *pe = p + udata.u_count;
+ int n;
+ irqflags_t irq;
+
+ if (minor == 1) {
+ while (p < pe) {
+ if ((n = iopoll(pe - p)) != 0)
+ return n;
+ dw_lpr(ugetc(p++));
+ }
+ } else {
+ while (p < pe) {
+ /* Printer busy ? */
+ while (*pia1b & 1) {
+ if ((n = iopoll(pe - p)) != 0)
+ return n;
+ }
+ /* The Dragon shares the printer and keyboard scan
+ lines. Make sure we don't collide */
+ irq = di();
+ *pia0b = ugetc(p++);
+ *pia1a |= 0x02; /* Strobe */
+ *pia1a &= ~0x02;
+ irqrestore(irq);
+ }
+ }
+ return pe - p;
+}
--- /dev/null
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+extern int lpr_open(uint8_t minor, uint16_t flag);
+extern int lpr_close(uint8_t minor);
+extern int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+extern void dw_lpr(uint8_t c);
+extern void dw_lpr_close(void);
+
+#endif
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <devfd.h>
+#include <vt.h>
+#include <tty.h>
+#include <graphics.h>
+
+#undef DEBUG /* UNdefine to delete debug code sequences */
+
+uint8_t *uart_data = (uint8_t *)0xFF04; /* ACIA data */
+uint8_t *uart_status = (uint8_t *)0xFF05; /* ACIA status */
+uint8_t *uart_command = (uint8_t *)0xFF06; /* ACIA command */
+uint8_t *uart_control = (uint8_t *)0xFF07; /* ACIA control */
+
+unsigned char tbuf1[TTYSIZ];
+unsigned char tbuf2[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}
+};
+
+uint8_t vtattr_cap = 0;
+struct vt_repeat keyrepeat;
+static uint8_t kbd_timer;
+
+/* tty1 is the screen tty2 is the serial port */
+
+/* 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)
+{
+ uint8_t c;
+ if (minor == 1)
+ return TTY_READY_NOW;
+ c = *uart_status;
+ return (c & 16) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */
+}
+
+/* For DragonPlus we should perhaps support both monitors 8) */
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ if (minor == 1)
+ vtoutput(&c, 1);
+ else
+ *uart_data = c; /* Data */
+}
+
+void tty_sleeping(uint8_t minor)
+{
+ used(minor);
+}
+
+void tty_setup(uint8_t minor)
+{
+ if (minor == 2) {
+ /* FIXME: do proper mode setting */
+ *uart_command = 0x01; /* DTR high, IRQ enabled, TX irq disabled 8N1 */
+ *uart_control = 0x1E; /* 9600 baud */
+ }
+}
+
+int tty_carrier(uint8_t minor)
+{
+ /* The serial DCD is status bit 5 but not wired */
+ return 1;
+}
+
+void tty_interrupt(void)
+{
+ uint8_t r = *uart_status;
+ if (r & 0x8) {
+ r = *uart_data;
+ tty_inproc(2,r);
+ }
+}
+
+uint8_t keymap[8];
+static uint8_t keyin[8];
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+/* FIXME: shouldn't COCO shiftmask also differ ??? 0x02 not 0x40 ?? */
+static uint8_t shiftmask[8] = {
+ 0, 0x40, 0, 0, 0, 0, 0, 0x40
+};
+
+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;
+/* Control */
+static volatile uint8_t *pia_ctrl = (uint8_t *)0xFF03;
+
+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];
+ }
+ if (system_id) { /* COCO series */
+ keybit += 2;
+ if (keybit > 5)
+ keybit -= 6;
+ }
+}
+
+#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', '-', 0 /* 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 */, '%', '=', 0 /* 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;
+
+ if (keymap[7] & 64) /* shift */
+ c = shiftkeyboard[keybyte][keybit];
+ else
+ c = keyboard[keybyte][keybit];
+ if (keymap[1] & 64) { /* control */
+ if (c > 31 && c < 127)
+ c &= 31;
+ }
+ tty_inproc(1, c);
+}
+
+void platform_interrupt(void)
+{
+ uint8_t i = *pia_ctrl;
+ if (i & 0x80) {
+ *pia_col;
+ newkey = 0;
+ keyproc();
+ if (keysdown && keysdown < 3) {
+ if (newkey) {
+ keydecode();
+ kbd_timer = keyrepeat.first;
+ } else if (! --kbd_timer) {
+ keydecode();
+ kbd_timer = keyrepeat.continual;
+ }
+ }
+// fd_timer_tick();
+ timer_interrupt();
+ }
+}
+
+/* This is used by the vt asm code, but needs to live at the top of the kernel */
+uint16_t cursorpos;
+
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#define KEY_ROWS 8
+#define KEY_COLS 7
+extern uint8_t keymap[8];
+extern uint8_t keyboard[8][7];
+extern uint8_t shiftkeyboard[8][7];
+
+extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr);
+
+#endif
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <device.h>
+#include <devtty.h>
+#include <carts.h>
+#include <blkdev.h>
+
+static const char *sysname[] = {"Dragon", "COCO", "COCO3", "Unknown"};
+
+struct cart_rom_id {
+ uint16_t hash;
+ uint8_t id;
+ const char *name;
+};
+
+static const char empty[] = "(empty)";
+
+struct cart_rom_id carts[] = {
+ { 0x72B0, CART_DRAGONDOS, "DragonDOS" },
+ { 0x9063, CART_DELTADOS, "DeltaDOS" },
+ { 0xB400, 0, empty },
+ { 0xC248, CART_RSDOS, "RS-DOS" },
+ { 0xE1BA, CART_ORCH90, "Orchestra-90 CC" },
+ { 0x0000, 0, "No ROM" }
+};
+
+static struct cart_rom_id *cart_lookup(uint16_t hash)
+{
+ struct cart_rom_id *cart = carts;
+ do {
+ if (cart->hash == hash)
+ return cart;
+ } while(cart++->hash);
+ return NULL;
+}
+
+void map_init(void)
+{
+ uint8_t i;
+ uint8_t bslot = 0;
+ uint16_t hash;
+ struct cart_rom_id *rom;
+
+ kprintf("%s system.\n", sysname[system_id]);
+ if (mpi_present()) {
+ kputs("MPI cartridge detected.\n");
+ cartslots = 4;
+ bootslot = mpi_set_slot(0);
+ bslot = bootslot & 3;
+ }
+ for (i = 0; i < cartslots; i++) {
+ mpi_set_slot((i << 4) | i);
+ hash = cart_hash();
+ rom = cart_lookup(hash);
+ if (rom) {
+ kprintf("%d: %s %c\n",
+ i, rom->name,
+ i == bootslot ? '*':' ');
+ carttype[i] = rom->id;
+ }
+ else
+ kprintf("%d: Unknown(%x) %c\n",
+ i, hash,
+ i == bslot ? '*':' ');
+ }
+ mpi_set_slot(bootslot);
+ /* We put swap on the start of slice 0, but with the first 64K free
+ so we can keep the OS image linearly there */
+ for (i = 0; i < MAX_SWAPS; i++)
+ swapmap_add(i + 128);
+}
--- /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
+
+ .globl _dw_lpr
+ .globl _dw_lpr_close
+ .globl _dw_rtc_read
+
+
+ ; imported
+ .globl map_process_a
+ .globl map_kernel
+
+ .area .common
+
+_dw_transaction:
+ pshs cc,y ; save caller
+ orcc #0x50 ; stop interrupts
+ tstb ; rawflag?
+ beq skip@ ; nope - then skip switching to process map
+ jsr map_process_always
+skip@ ldy 5,s ; Y = number of bytes to send
+ beq ok@ ; no bytes 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 ok@ ; 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
+ok@ ldx #0 ; no error
+out@ jsr map_kernel
+ puls cc,y,pc ; return
+frame@ ldx #-1 ; frame error
+ bra out@
+part@ ldx #-2 ; not all bytes received!
+ bra out@
+
+_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
+ lda 7,x ; page map LSB
+ jsr map_process_a ; same as map_process on nx32
+ lda 5,x ; minor = drive number
+ 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
+@fin jsr map_kernel
+@ret puls y,pc
+@err ldx #0xFFFF
+ bra @fin
+
+; 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
+
+ .area .text
+;
+; Virtual devices on DriveWire
+;
+; Line printer
+; RTC
+; Virtual serial ???
+;
+;
+; dw_lpr(uint8_t c)
+;
+; Print a byte to drive wire printers
+;
+; B holds the byte. Call with interrupts off
+;
+_dw_lpr:
+ pshs y
+ stb lprb2
+ ldx #lprb
+ ldy #2
+dwop:
+ jsr DWWrite
+ puls y,pc
+
+;
+; dw_lpr_close(void)
+;
+; Close the printer device
+;
+_dw_lpr_close:
+ pshs y
+ ldx #lprb3
+ ldy #1
+ bra dwop
+
+;
+; uint8_t dw_rtc_read(uint8_t *p)
+;
+_dw_rtc_read:
+ pshs y
+ ldy #2
+ pshs x
+ ldx #lprrtw
+ jsr DWWrite
+ puls x
+ ldy #6
+ clra
+ jsr DWRead
+ clrb
+ sbcb #0
+ bra dwop
+
+ .area .data
+
+lprb: .db 0x50 ; print char
+lprb2: .db 0x00 ; filled in with byte to send
+lprb3: .db 0x46 ; printer flush
+lprrtw: .db 0x23 ; request for time
+
+ .area .common
+
+
+; 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
+ *PRAGMA nonewsource
+ include "dw.def"
+ include "dwread.s"
+ include "dwwrite.s"
+
--- /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
+;
+; Glenside style IDE block transfer logic
+;
+
+ .module dragonide
+
+ .globl _devide_read_data
+ .globl _devide_write_data
+
+ .globl _blk_op
+
+ include "kernel.def"
+ include "../kernel09.def"
+
+ .area .common
+
+;
+; Standard mapping for Glenside style IDE
+;
+; We don't really support swap properly but what we do is sufficient
+; for a simple memory mapping.
+;
+_devide_read_data:
+ pshs y,dp
+ lda #0xFF
+ tfr a,dp
+ ldx _blk_op
+ leay 512,x
+ sty endp
+ tst _blk_op+2
+ beq readword
+ jsr map_process_always
+readword:
+ lda <IDEDATA
+ ldb <IDEDATA_L ; latched
+ std ,x++
+ cmpx endp
+ bne readword
+ jsr map_kernel
+ puls y,dp,pc
+
+_devide_write_data:
+ pshs y,dp
+ lda #0xFF
+ tfr a,dp
+ ldx _blk_op
+ leay 512,x
+ sty endp
+ tst _blk_op+2
+ beq writeword
+ jsr map_process_always
+writeword:
+ ldd ,x++
+ stb <IDEDATA_L
+ sta <IDEDATA
+ cmpx endp
+ bne writeword
+ jsr map_kernel
+ puls y,dp,pc
+
+endp: .dw 0
+
--- /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;
+}
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <device.h>
+#include <devtty.h>
+#include <carts.h>
+#include <blkdev.h>
+
+uint8_t membanks;
+uint8_t system_id;
+uint8_t cartslots = 1;
+uint8_t carttype[4];
+uint8_t bootslot = 0;
+uint16_t swap_dev;
+
+void platform_idle(void)
+{
+}
+
+uint8_t platform_param(char *p)
+{
+ return 0;
+}
+
+void do_beep(void)
+{
+}
+
+void platform_discard(void)
+{
+}
+
+/* Find a cartridge or it's slot */
+int cart_find(int id)
+{
+ int i;
+ for (i = 0; i < id; i++) {
+ if (carttype[i] == id)
+ return i;
+ }
+ return -1;
+}
+
+unsigned char vt_mangle_6847(unsigned char c)
+{
+ if (c >= 96)
+ c -= 32;
+ c &= 0x3F;
+ return c;
+}
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include "mini_ide.h"
+
+#define MAX_HD 2
+
+uint8_t ide_present = 1;
+
+#define data ((volatile uint8_t *)0xFF50)
+#define error ((volatile uint8_t *)0xFF51)
+#define count ((volatile uint8_t *)0xFF52)
+#define sec ((volatile uint8_t *)0xFF53)
+#define cyll ((volatile uint8_t *)0xFF54)
+#define cylh ((volatile uint8_t *)0xFF55)
+#define devh ((volatile uint8_t *)0xFF56)
+#define status ((volatile uint8_t *)0xFF57)
+#define cmd ((volatile uint8_t *)0xFF57)
+#define datal ((volatile uint8_t *)0xFF58)
+
+/* FIXME: switch to the correct mpi slot on entry */
+static int ide_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+ uint16_t nb = udata.u_nblock;
+ uint8_t *dptr = udata.u_dptr;
+
+ if (rawflag == 1 && d_blkoff(9))
+ return -1;
+
+ while(*status & 0x80); /* Wait !BUSY */
+ *devh = (minor & 0x80) ? 0x50 : 0x40 ; /* LBA, device */
+ while(*status & 0x80); /* Wait !BUSY */
+ /* FIXME - slices of about 4MB might be saner! */
+ *cylh = minor & 0x7F; /* Slice number */
+ *cyll = udata.u_block >> 8; /* Each slice is 32MB */
+ *sec = udata.u_block & 0xFF;
+ *count = udata.u_nblock;
+ while(!(*status & 0x40)); /* Wait DRDY */
+ *cmd = is_read ? 0x20 : 0x30;
+ while(*status & 0x08); /* Wait DRQ */
+ while(udata.u_nblock--) {
+ unsigned int i;
+ while(!(*status & 0x08)); /* Wait DRQ */
+ if (is_read) {
+ for (i = 0; i < 256; i++) {
+ *dptr++ = *data;
+ *dptr++ = *datal;
+ }
+ } else {
+ for (i = 0; i < 256; i++) {
+ *datal = dptr[1];
+ *data = *dptr++;
+ dptr++;
+ }
+ }
+ }
+ while(*status & 0x80); /* Wait !BUSY */
+ if (*status & 0x01) { /* Error */
+ kprintf("ide%d: error %x\n", *error);
+ udata.u_error = EIO;
+ return -1;
+ }
+ return nb;
+
+}
+
+int ide_open(uint8_t minor, uint16_t flag)
+{
+ if(minor > 1 || !(ide_present & (1 << minor))) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int ide_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return ide_transfer(minor, true, rawflag);
+}
+
+int ide_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return ide_transfer(minor, false, rawflag);
+}
+
+int ide_ioctl(uint8_t minor, uarg_t request, char *unused)
+{
+ if (request != BLKFLSBUF)
+ return -1;
+ while(*status & 0x80); /* Wait !BUSY */
+ *devh = (minor & 0x80) ? 0x10 : 0x40 ; /* LBA, device */
+ while(*status & 0x80); /* Wait !BUSY */
+ while(!(*status & 0x40)); /* Wait DRDY */
+ *cmd = 0xE7;
+ while(*status & 0x80); /* Wait !BUSY */
+ return 0;
+}
+
+/* TODO: probe the devices more carefully and do EDD and LBA checks in discard
+ code */
--- /dev/null
+extern int ide_open(uint8_t minor, uint16_t flag);
+extern int ide_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int ide_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int ide_ioctl(uint8_t minor, uarg_t request, char *data);
+
+extern uint8_t ide_present;
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include "mini_ide.h"
+
+#define data ((volatile uint8_t *)0xFF50)
+#define error ((volatile uint8_t *)0xFF51)
+#define count ((volatile uint8_t *)0xFF52)
+#define sec ((volatile uint8_t *)0xFF53)
+#define cyll ((volatile uint8_t *)0xFF54)
+#define cylh ((volatile uint8_t *)0xFF55)
+#define devh ((volatile uint8_t *)0xFF56)
+#define status ((volatile uint8_t *)0xFF57)
+#define cmd ((volatile uint8_t *)0xFF57)
+#define datal ((volatile uint8_t *)0xFF58)
+
+static timer_t giveup;
+
+static int ide_wait_op(uint8_t mask, uint8_t val)
+{
+ while((*status & mask) != val) {
+ if (timer_expired(giveup)) {
+ kputs(" - no response\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int ide_wait_nbusy(void)
+{
+ return ide_wait_op(0x80, 0x00);
+}
+
+static int ide_wait_drdy(void)
+{
+ return ide_wait_op(0x40, 0x40);
+}
+
+static int ide_wait_drq(void)
+{
+ return ide_wait_op(0x08, 0x08);
+}
+
+
+static void ide_identify(int dev, uint8_t *buf)
+{
+ uint8_t *dptr = buf;
+ int i;
+
+ giveup = set_timer_ms(2000);
+
+ if (ide_wait_nbusy() == -1)
+ return;
+ *devh = dev << 4; /* Select */
+ if (ide_wait_nbusy() == -1)
+ return;
+ if (ide_wait_drdy() == -1)
+ return;
+ *cmd = 0xEC; /* Identify */
+ if (ide_wait_drq() == -1)
+ return;
+ for (i = 0; i < 256; i++) {
+ *dptr++ = *data;
+ *dptr++ = *datal;
+ }
+ if (ide_wait_nbusy() == -1)
+ return;
+ if (*status & 1)
+ return;
+ if (ide_wait_drdy() == -1)
+ return;
+ kprintf("%x : ", dev);
+ /* Check the LBA bit is set, and print the name */
+ dptr = buf + 54; /* Name info */
+ if (*dptr)
+ for (i = 0; i < 40; i++)
+ kputchar(*dptr++);
+ if (!(buf[99] & 0x02)) { /* No LBA ? */
+ kputs(" - non-LBA\n");
+ return;
+ }
+ kputs(" - OK\n");
+ ide_present |= (1 << dev);
+}
+
+int ide_probe(void)
+{
+ uint8_t *buf = (uint8_t *)tmpbuf();
+ /* Issue an EDD if we can - timeout -> no drives */
+ /* Now issue an identify for each drive */
+ ide_identify(0, buf);
+ if (ide_present)
+ ide_identify(1, buf);
+ brelse((bufptr) buf);
+}
--- /dev/null
+export CPU = 6809
--- /dev/null
+;
+; TODO: udata needs to be in common space so swap needs to be smarter
+; about split udata
+;
+ .module tricks
+
+ # imported
+ .globl _newproc
+ .globl _chksigs
+ .globl _getproc
+ .globl _trap_monitor
+ .globl _inint
+ .globl map_kernel
+ .globl map_process
+ .globl map_process_a
+ .globl map_process_always
+ .globl copybank
+ .globl _nready
+ .globl _platform_idle
+
+ # exported
+ .globl _switchout
+ .globl _switchin
+ .globl _dofork
+ .globl _ramtop
+
+ include "kernel.def"
+ include "../kernel09.def"
+
+ .area .common
+
+ ; ramtop must be in common although not used here
+_ramtop:
+ .dw 0
+
+; 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().
+;
+;
+; This function can have no arguments or auto variables.
+_switchout:
+ orcc #0x10 ; irq off
+ jsr _chksigs
+
+ ; save machine state, including Y and U used by our C code
+ ldd #0 ; 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 ; this is where the SP is restored in _switchin
+
+ ; find another (or same) process to run, returned in X
+ jsr _getproc
+ jsr _switchin
+ ; we should never get here
+ jsr _trap_monitor
+
+badswitchmsg:
+ .ascii "_switchin: FAIL"
+ .db 13
+ .db 10
+ .db 0
+
+newpp .dw 0
+
+; new process pointer is in X
+_switchin:
+ orcc #0x10 ; irq off
+
+ stx newpp
+ ; get process table
+ lda P_TAB__P_PAGE_OFFSET+1,x ; LSB of 16-bit page no
+
+ cmpa #0
+ bne not_swapped
+ jsr _swapper ; void swapper(ptptr p)
+ ldx newpp
+ lda P_TAB__P_PAGE_OFFSET+1,x
+
+not_swapped:
+ ; 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
+
+ ldx newpp
+ ; 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 any moved page pointers
+ lda P_TAB__P_PAGE_OFFSET+1,x
+ sta U_DATA__U_PAGE+1
+
+ 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 ; in ISR, leave interrupts off
+ 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
+
+ .area .data
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+ .area .common
+;
+; 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 (Y and U used by C).
+ ; When this process (the parent) is switched back in, it will be as if
+ ; it returns with the value of the child's pid.
+ pshs x,y,u ; x has p->p_pid from above, the return value in the parent
+
+ ; 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 X (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.
+
+ ldx U_DATA__U_PTAB
+ jsr _swapout
+ cmpd #0
+ bne forked_up
+
+ ; 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
+ jsr _newproc
+
+ ; any calls to map process will now map the childs memory
+
+ ; in the child process, fork() returns zero.
+ ldx #0
+ ; runticks = 0;
+ stx _runticks
+ ;
+ ; 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
+
+forked_up: ; d is already -1
+ puls y,u,pc
+ rts
\ No newline at end of file
--- /dev/null
+ .module usermem
+
+;
+; 6809 + Cartridge copy to and from userspace
+; Assumes the irq handler saves/restores cartridge/ram correctly
+; Assumes we never copy to/from ROM space
+;
+
+ include "kernel.def"
+ include "../kernel09.def"
+
+ ; exported
+ .globl __ugetc
+ .globl __ugetw
+ .globl __uget
+ .globl __ugets
+ .globl __uputc
+ .globl __uputw
+ .globl __uput
+ .globl __uzero
+
+ .area .common
+
+__ugetc:
+ jsr map_process_always
+ ldb ,x
+ clra
+ tfr d,x
+ jmp map_kernel
+
+__ugetw:
+ jsr map_process_always
+ ldx ,x
+ jmp map_kernel
+
+__uget:
+ pshs u,y
+ ldu 6,s ; user address
+ ldy 8,s ; count
+ jsr map_process_always
+ugetl:
+ lda ,x+
+ sta ,u+
+ leay -1,y
+ bne ugetl
+ ldx #0
+ jsr map_kernel
+ puls u,y,pc
+
+__ugets:
+ pshs u,y
+ ldu 6,s ; user address
+ ldy 8,s ; count
+ jsr map_process_always
+ugetsl:
+ lda ,x+
+ beq ugetse
+ sta ,u+
+ leay -1,y
+ bne ugetsl
+ jsr map_kernel
+ ldx #0xffff ; unterminated - error
+ lda #0
+ sta -1,u ; force termination
+ puls u,y,pc
+ugetse:
+ sta ,u
+ ldx #0
+ puls u,y,pc
+
+
+__uputc:
+ ldd 2,s
+ jsr map_process_always
+ exg d,x
+ stb ,x
+ ldx #0
+ jmp map_kernel
+
+__uputw:
+ ldd 2,s
+ jsr map_process_always
+ exg d,x
+ std ,x
+ ldx #0
+ jmp map_kernel
+
+; X = source, user, size on stack
+__uput:
+ pshs u,y
+ ldu 6,s ; user address
+ ldy 8,s ; count
+ jsr map_process_always
+uputl:
+ lda ,x+
+ sta ,u+
+ leay -1,y
+ bne uputl
+ ldx #0
+ jsr map_kernel
+ puls u,y,pc
+
+__uzero:
+ pshs y
+ lda #0
+ ldy 4,s
+ jsr map_process_always
+uzloop:
+ sta ,x+
+ leay -1,y
+ bne uzloop
+ jsr map_kernel
+ ldx #0
+ puls y,pc
--- /dev/null
+ .module dragonvideo
+
+ ; Methods provided
+ .globl _vid256x192
+ .globl _plot_char
+ .globl _scroll_up
+ .globl _scroll_down
+ .globl _clear_across
+ .globl _clear_lines
+ .globl _cursor_on
+ .globl _cursor_off
+ .globl _vtattr_notify
+
+ .globl _video_read
+ .globl _video_write
+ .globl _video_cmd
+
+ ;
+ ; Imports
+ ;
+ .globl _fontdata_8x8
+ .globl _vidattr
+
+ include "kernel.def"
+ include "../kernel09.def"
+
+ .area .text
+
+;
+; Dragon video drivers
+;
+; SAM V2=1 V1=1 V0=-
+; 6847 A/G=1 GM2=1 GM1=1 GM0=1
+;
+_vid256x192:
+ sta $ffc0
+ sta $ffc3
+ sta $ffc5
+ lda $ff22
+ anda #$07
+ ora #$f0
+ sta $ff22
+ rts
+
+;
+; Compute the video base address
+; A = X, B = Y
+;
+vidaddr:
+ ldy #VIDEO_BASE
+ exg a,b
+ leay d,y ; 256 x Y + X
+ rts
+;
+; plot_char(int8_t y, int8_t x, uint16_t c)
+;
+_plot_char:
+ pshs y
+ lda 4,s
+ bsr vidaddr ; preserves X (holding the char)
+ tfr x,d
+ anda $7F ; no high font bits
+ suba $20 ; skip control symbols
+ rolb ; multiply by 8
+ rola
+ rolb
+ rola
+ rolb
+ rola
+ tfr d,x
+ leax _fontdata_8x8,x ; relative to font
+ ldb _vtattr
+ andb #0x3F ; drop the bits that don't affect our video
+ beq plot_fast
+
+ ;
+ ; General purpose plot with attributes, we only fastpath
+ ; the simple case
+ ;
+ clra
+plot_loop:
+ sta _vtrow
+ ldb _vtattr
+ cmpa #7 ; Underline only applies on the bottom row
+ beq ul_this
+ andb #0xFD
+ul_this:
+ cmpa #3 ; italic shift right for < 3
+ blt ital_1
+ andb #0xFB
+ bra maskdone
+ital_1:
+ cmpa #5 ; italic shift right for >= 5
+ blt maskdone
+ bitb #0x04
+ bne maskdone
+ orb #0x40 ; spare bit borrow for bottom of italic
+ andb #0xFB
+maskdone:
+ lda ,x+ ; now throw the row away for a bit
+ bitb #0x10
+ bne notbold
+ lsra
+ ora -1,x ; shift and or to make it bold
+notbold:
+ bitb #0x04 ; italic by shifting top and bottom
+ beq notital1
+ lsra
+notital1:
+ bitb #0x40
+ beq notital2
+ lsla
+notital2:
+ bitb #0x02
+ beq notuline
+ lda #0xff ; underline by setting bottom row
+notuline:
+ bitb #0x01 ; inverse or not: we are really in inverse
+ bne plot_inv ; by default so we complement except if
+ coma ; inverted
+plot_inv:
+ bitb #0x20 ; overstrike or plot ?
+ bne overstrike
+ sta ,y
+ bra plotnext
+overstrike:
+ anda ,y
+ sta ,y
+plotnext:
+ leay 32,y
+ lda _vtrow
+ inca
+ cmpa #8
+ bne plot_loop
+ puls y,pc
+;
+; Fast path for normal attributes
+;
+plot_fast:
+ lda ,x+ ; simple 8x8 renderer for now
+ coma
+ sta 0,y
+ lda ,x+
+ coma
+ sta 32,y
+ lda ,x+
+ coma
+ sta 64,y
+ lda ,x+
+ coma
+ sta 96,y
+ lda ,x+
+ coma
+ sta 128,y
+ lda ,x+
+ coma
+ sta 160,y
+ lda ,x+
+ coma
+ sta 192,y
+ lda ,x+
+ coma
+ sta 224,y
+ puls y,pc
+
+;
+; void scroll_up(void)
+;
+_scroll_up:
+ pshs y
+ ldy #VIDEO_BASE
+ leax 256,y
+vscrolln:
+ ; Unrolled line by line copy
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ ldd ,x++
+ std ,y++
+ cmpx video_endptr
+ bne vscrolln
+ puls y,pc
+
+;
+; void scroll_down(void)
+;
+_scroll_down:
+ pshs y
+ ldy #VIDEO_END
+ leax -256,y
+vscrolld:
+ ; Unrolled line by line loop
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ ldd ,--x
+ std ,--y
+ cmpx video_startptr
+ bne vscrolld
+ puls y,pc
+
+video_startptr:
+ .dw VIDEO_BASE
+video_endptr:
+ .dw VIDEO_END
+
+;
+; clear_across(int8_t y, int8_t x, uint16_t l)
+;
+_clear_across:
+ pshs y
+ lda 4,s ; x into A, B already has y
+ jsr vidaddr ; Y now holds the address
+ tfr x,d ; Shuffle so we are writng to X and the counter
+ tfr y,x ; l is in d
+ lda #$ff
+clearnext:
+ sta ,x
+ sta 32,x
+ sta 64,x
+ sta 96,x
+ sta 128,x
+ sta 160,x
+ sta 192,x
+ sta 224,x
+ leax 1,x
+ decb
+ bne clearnext
+ puls y,pc
+;
+; clear_lines(int8_t y, int8_t ct)
+;
+_clear_lines:
+ pshs y
+ clra ; b holds Y pos already
+ jsr vidaddr ; y now holds ptr to line start
+ tfr y,x
+ ldd #$ffff
+ lsl 4,s
+ lsl 4,s
+ lsl 4,s
+wipel:
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ std ,x++
+ dec 4,s ; count of lines
+ bne wipel
+ puls y,pc
+
+_cursor_on:
+ pshs y
+ lda 4,s
+ jsr vidaddr
+ tfr y,x
+ puls y
+ stx cursor_save
+ ; Fall through
+_cursor_off:
+ ldb _vtattr
+ bitb #0x80
+ bne nocursor
+ ldx cursor_save
+ com ,x
+ com 32,x
+ com 64,x
+ com 96,x
+ com 128,x
+ com 160,x
+ com 192,x
+ com 224,x
+nocursor:
+_vtattr_notify:
+ rts
+;
+; These routines wortk in both 256x192x2 and 128x192x4 modes
+; because everything in the X plane is bytewide.
+;
+_video_write:
+ clra ; clr C
+ bra tfr_cmd
+_video_read:
+ coma ; set C
+ bra tfr_cmd ; go
+
+;;; This does the job of READ & WRITE
+;;; takes: C = direction 0=write, 1=read
+;;; takes: X = transfer buffer ptr + 2
+tfr_cmd:
+ pshs u,y ; save regs
+ orcc #$10 ; turn off interrupt - int might remap kernel
+ ldd #$80c0 ; this is writing
+ bcc c@ ; if carry clear then keep D write
+ exg a,b ; else flip D: now is reading
+c@ sta b@+1 ; !!! self modify inner loop
+ stb b@+3 ; !!!
+ bsr vidptr ; U = screen addr
+ tfr x,y ; Y = ptr to Height, width
+ leax 4,x ; X = pixel data
+ ;; outter loop: iterate over pixel rows
+a@ lda 3,y ; count = width
+ pshs u ; save screen ptr
+ ;; inner loop: iterate over columns
+ ;; modify mod+1 and mod+3 to switch directions
+b@ ldb ,x+ ; get a byte from src
+ stb ,u+ ; save byte to dest
+ deca ; bump counter
+ bne b@ ; loop
+ ;; increment outer loop
+ puls u ; restore original screen ptr
+ leau 32,u ; add byte span of screen (goto next line)
+ dec 1,y ; bump row counter
+ bne a@ ; loop
+ puls u,y,pc ; restore regs, return
+
+
+;
+; Find the address we need on a pixel row basis
+;
+vidptr:
+ ldu #VIDEO_BASE
+ ldd ,x++ ; Y into B
+ lda #32
+ mul
+ leau d,u
+ ldd ,x++ ; X
+ leau d,u
+ rts
+
+_video_cmd:
+ pshs u
+ bsr vidptr ; u now points to the screen
+nextline:
+ pshs u ; save it for the next line
+nextop:
+ ldb ,x+ ; op code, 0 = end of line
+ beq endline
+oploop:
+ lda ,u ; do one screen byte
+ anda ,x
+ eora 1,x
+ sta ,u+
+ decb
+ bne oploop ; keep going for run
+ leax 2,x
+ bra nextop ; next triplet
+endline:
+ puls u ; get position back
+ leau 32,u ; down one scan line
+ ldb ,x+ ; get next op - 0,0 means end and done
+ bne oploop
+ puls u,pc
+
+ .area .data
+cursor_save:
+ .dw 0
+_vtrow:
+ .db 0