#export TARGET = bbcmicro
#export TARGET = dragon
#export TARGET = coco2
-#export TARGET = coco2cart
+export TARGET = coco2cart
#export TARGET = coco3
#export TARGET = dragon-nx32
#export TARGET = multicomp09
#export TARGET = v65
#export TARGET = v68
#export TARGET = v68-banked
-export TARGET = z80pack
+#export TARGET = z80pack
#export TARGET = z80pack-lite
#export TARGET = zeta-v2
#export TARGET = zx128
CSRCS = devices.c main.c
# Code that must be present for the bootstrap
-CISRCS = mini_ide.c
+CISRCS = mini_ide.c devsdc.c
C3SRCS = libc.c devtty.c
DSRCS = ../dev/devdw.c
-ASRCS = crt0.s coco2.s ide.s usermem.s bootstrap.s
+ASRCS = crt0.s coco2.s ide.s usermem.s sdc.s
+ASRCS += bootstrap.s bootstrap_sdc.s bootstrap_dw.s
ASRCS += tricks.s commonmem.s drivewire.s video.s
COBJS = $(CSRCS:.c=$(BINEXT))
image:
$(CROSS_LD) -o ../fuzix.bin -Map=../fuzix.map --script=fuzix.link \
--oformat=decb \
- crt0.o bootstrap.o commonmem.o coco2.o discard.o ../simple.o \
+ crt0.o bootstrap_sdc.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 ide.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
+ ../font8x8.o devsdc.o sdc.o
../tools/decb-image <../fuzix.bin fuzix.img
dd if=fuzix.img of=fuzix.rom bs=1024 skip=48 count=16
dd if=fuzix.img of=fuzix.ide bs=256 skip=26 count=102
Supported hardware:
IDE (Cloud9 or compatible set at FF50) with either built in
cartridge RAM or separate cartridge
+ COCO SDC (in progress)
Disk Layout
===========
TODO
====
+Fix use of CONFIG_LEGACY_EXEC in the devsdc driver
+
Make the boot loader robust (timeout handling)
Add hash of code not just simple magic - so we know bits match
+Merge coco and IDE boot code so it works out which is present
Support for a real time clock and clock locking
enough to add support for very minimal MBR parsing and offsets. That would
be a big improvement.
+Automatically pick swap according to whether IDE or SDC is present.
+
To Test
=======
--- /dev/null
+;;; The ROM-resident fuzix loader for the CoCoSDC drive. Mostly copied from
+;;; Alan's IDE booter.
+
+;
+; 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 a sector from SDC
+;;; takes: B - sector number, X = dest address
+;;; returns: nothing
+load_block:
+ clr <$ff49 ; put lba to sdc
+ clr <$ff4a ;
+ stb <$ff4b ;
+ ldb #$80 ; read sector op
+ stb <$ff48 ;
+ exg x,x ; wait a few cycles for sdc status reg
+ exg x,x ; to be valid. - 2 long noops
+ ldb #$2 ; wait till sdc is ready
+ ;; FIXME: test for failure in this loop
+a@ bitb <$ff48 ;
+ beq a@ ;
+ ;; tranfer data
+ lda #128 ; 128 x 16 bits = 256 byte sectors
+ pshs a ; push count on stack
+c@ ldd <$ff4a ; get 16bit data from drive
+ std ,x++ ; stick it in memory
+ dec ,s ; bump counter
+ bne c@ ; repeat
+ leas 1,s ; drop counter
+ ;; wait for return value
+ ldb #$1
+ ;; FIXME: test for failure in the loop, also.
+b@ bitb <$ff48 ;
+ bne b@ ; wait for busy
+ ;; FIXME: get return status here and test?
+ puls pc ; return
+
+
+
+load_image:
+ orcc #$50
+ ldy #$0400 ; display at this point
+ lda #'G' ;
+ sta ,y+ ;
+ ldd #$ff43 ; set DP to io page
+ tfr a,dp ; good for size + speed
+ stb <$ff40 ; turn on SDC's LBA mode
+ ;; we have to wait maybe 12us before doing anything
+ ;; with the SDC now, but the code below should
+ ;; delay SDC access enough.
+ ;; load kernel
+ ldb #0 ; start block no (* 2 for 256 byte sectors)
+ lda #102 ; number of blocks (* 2 for 256 bytes sectors)
+ ldx #$1A00 ; dest address
+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
+ lda ,x+
+ cmpa #$15
+ bne wrong_err
+ lda ,x+
+ cmpa #$C0
+ bne wrong_err
+ rts
+
+wrong_err:
+ ldu #wrong
+ bra l2
+load_error:
+ ldu #fail
+l2: bsr copy_str
+l1: bra l1
+
+copy_str:
+ lda ,u+
+ beq endstr
+ sta ,y+
+ bra copy_str
+endstr: rts
+fail:
+ .ascii "Fail"
+ .db 0
+wrong:
+ .ascii "Wrong image"
+ .db 0
#define CONFIG_BANKS 1
/* And swapping */
-#define SWAPDEV 0x0 /* Uses part of IDE slice 0 */
+#define SWAPDEV 0x900 /* Uses part of IDE slice 0 */
#define SWAP_SIZE 0x40 /* 32K in 512 byte blocks */
#define SWAPBASE 0x8000 /* We swap the lot */
#define SWAPTOP 0xFE00 /* so it's a round number of 512 byte sectors */
/* Permit large I/O requests to bypass cache and go direct to userspace */
#define CONFIG_LARGE_IO_DIRECT
+#define CONFIG_LEGACY_EXEC
/* Video terminal, not a serial tty */
#define CONFIG_VT
#include <vt.h>
#include <devtty.h>
#include <mini_ide.h>
+#include <devsdc.h>
#include <device.h>
struct devsw dev_tab[] = /* The device driver switch table */
{ 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 },
+ { no_open, no_close, sdc_read, sdc_write, no_ioctl },
};
bool validdev(uint16_t dev)
void device_init(void)
{
ide_probe();
+ devsdc_init();
}
--- /dev/null
+/*
+
+ CoCoSDC driver
+ (c)2015 Brett M. Gordon GPL2
+
+ * Needs work on extended SDC API stuff.
+ * init / mounting stuff really needs to set/update blkdev structure for size
+ * need to get rawmode=1 and 2 working.
+
+*/
+
+#include <kernel.h>
+#include <kdata.h>
+#include <blkdev.h>
+#include <mbr.h>
+#include <devsdc.h>
+#include <printf.h>
+
+
+#define SDC_REG_BASE 0xff40
+#define SDC_REG_CTL (SDC_REG_BASE+0x00 )
+#define SDC_REG_DATA (SDC_REG_BASE+0x02 )
+#define SDC_REG_FCTL (SDC_REG_BASE+0x03 )
+#define SDC_REG_CMD (SDC_REG_BASE+0x08 )
+#define SDC_REG_STAT (SDC_REG_BASE+0x08 )
+#define SDC_REG_PARAM1 (SDC_REG_BASE+0x09 )
+#define SDC_REG_PARAM2 (SDC_REG_BASE+0x0a )
+#define SDC_REG_PARAM3 (SDC_REG_BASE+0x0b )
+
+#define SDC_BUSY 0x01
+#define SDC_READY 0x02
+#define SDC_FAIL 0x80
+
+
+
+#define sdc_reg_ctl *((volatile uint8_t *)SDC_REG_CTL)
+#define sdc_reg_data *((volatile uint8_t *)SDC_REG_DATA)
+#define sdc_reg_fctl *((volatile uint8_t *)SDC_REG_FCTL)
+#define sdc_reg_cmd *((volatile uint8_t *)SDC_REG_CMD)
+#define sdc_reg_stat *((volatile uint8_t *)SDC_REG_STAT)
+#define sdc_reg_param1 *((volatile uint8_t *)SDC_REG_PARAM1)
+#define sdc_reg_param2 *((volatile uint8_t *)SDC_REG_PARAM2)
+#define sdc_reg_param3 *((volatile uint8_t *)SDC_REG_PARAM3)
+
+
+/* Assembler glue */
+
+extern void sdc_read_data(uint8_t *p);
+extern void sdc_write_data(uint8_t *p);
+extern uint8_t sdcpage;
+
+/* a "simple" internal function pointer to which transfer
+ routine to use. The is_read var might be better stored
+ in a way that the asm helpers could do self modifying.
+*/
+typedef void (*sdc_transfer_function_t)( unsigned char *addr);
+
+
+
+/* blkdev method: transfer sectors */
+static uint8_t sdc_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+ uint8_t nb = udata.u_nblock; /* our return value, preset to failure */
+ uint32_t lba; /* holds 32 bit lsn */
+ uint8_t *ptr = ((uint8_t *)&lba)+1; /* points to 24 bit lba in blk op */
+ uint8_t t; /* temporarory sdc status holder */
+ uint8_t cmd; /* holds SDC command value */
+ sdc_transfer_function_t fptr; /* holds which xfer routine we want */
+
+ if (rawflag == 1 && d_blkoff(9) )
+ return -1;
+
+ /* pass rawflag to assembler */
+ sdcpage = rawflag;
+
+
+ /* we get 256 bytes per lba in SDC so convert */
+ udata.u_nblock *= 2;
+ lba = udata.u_block * 2;
+ ptr[0] |= (minor & 0x7f) << 1;
+
+ /* setup cmd pointer and command value from blk_op */
+ if( is_read ){
+ cmd = 0x80;
+ fptr = sdc_read_data;
+ }
+ else{
+ cmd = 0xa0;
+ fptr = sdc_write_data;
+ }
+
+ /* apply our drive value 0 or 1*/
+ if( minor & 0x80 )
+ cmd++;
+
+ while(udata.u_nblock--){
+ /* load up registers */
+ sdc_reg_param1 = ptr[0];
+ sdc_reg_param2 = ptr[1];
+ sdc_reg_param3 = ptr[2];
+ sdc_reg_cmd= cmd;
+ asm("\texg x,x\n"); /* delay 16us minimum */
+ asm("\texg x,x\n");
+ /* wait till SDC is ready */
+ do{
+ t=sdc_reg_stat;
+ if( t & SDC_FAIL ) goto fail;
+ } while( ! (t & SDC_READY) );
+ /* do our low-level xfer function */
+ fptr( udata.u_dptr );
+ /* and wait will ready again, and test for failure */
+ do{
+ t=sdc_reg_stat;
+ if( t & SDC_FAIL ) goto fail;
+ }while ( t & SDC_BUSY );
+ /* increment our blk_op values for next 256 bytes sector */
+ udata.u_dptr += 256;
+ lba++;
+ }
+ /* Huzzah! success! */
+ return nb;
+ /* Boo! failure */
+ fail: sdc_reg_ctl = 0x00;
+ udata.u_error = EIO;
+ return -1;
+}
+
+
+int sdc_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return sdc_transfer(minor, true, rawflag);
+}
+
+int sdc_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ return sdc_transfer(minor, false, rawflag);
+}
+
+
+
+
+
+__attribute__((section(".discard")))
+/* Returns true if SDC hardware seems to exist */
+bool devsdc_exist()
+{
+ uint8_t t;
+ sdc_reg_data=0x64;
+ t=sdc_reg_fctl;
+ sdc_reg_data=0x00;
+ if( (sdc_reg_fctl ^ t) == 0x60 ) return -1;
+ else return 0;
+}
+
+__attribute__((section(".discard")))
+/* Call this to initialize SDC/blkdev interface */
+void devsdc_init()
+{
+ kputs("SDC: ");
+ if( devsdc_exist() ){
+ /* turn on uber-secret SDC LBA mode*/
+ sdc_reg_ctl = 0x43;
+ kputs("Ok.\n");
+ }
+ else kprintf("Not Found.\n");
+}
+
--- /dev/null
+
+
+extern int sdc_open(uint8_t minor, uint16_t flag);
+extern int sdc_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int sdc_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int sdc_ioctl(uint8_t minor, uarg_t request, char *data);
+
+extern uint8_t sdc_present;
; Used by DWRead and DWWrite
IntMasks equ $50
-NOINTMASK equ 1
+NOINTMASK equ 0
; Hardcode these for now so that we can use below files unmodified
H6309 equ 0
-BECKER equ 1
+BECKER equ 0
ARDUINO equ 0
JMCPBCK equ 0
BAUD38400 equ 0