cromemco: initial draft port
authorAlan Cox <alan@linux.intel.com>
Fri, 6 Apr 2018 18:35:48 +0000 (19:35 +0100)
committerAlan Cox <alan@linux.intel.com>
Fri, 6 Apr 2018 18:35:48 +0000 (19:35 +0100)
No floppy driver yet and boot blocks are untested

15 files changed:
Kernel/platform-cromemco/Makefile [new file with mode: 0644]
Kernel/platform-cromemco/README [new file with mode: 0644]
Kernel/platform-cromemco/cloader-16fdc.s [new file with mode: 0644]
Kernel/platform-cromemco/config.h [new file with mode: 0644]
Kernel/platform-cromemco/cromemco.s [new file with mode: 0644]
Kernel/platform-cromemco/crt0.s [new file with mode: 0644]
Kernel/platform-cromemco/devfd.c [new file with mode: 0644]
Kernel/platform-cromemco/devfd.h [new file with mode: 0644]
Kernel/platform-cromemco/devices.c [new file with mode: 0644]
Kernel/platform-cromemco/devtty.c [new file with mode: 0644]
Kernel/platform-cromemco/devtty.h [new file with mode: 0644]
Kernel/platform-cromemco/fuzix.lnk [new file with mode: 0644]
Kernel/platform-cromemco/main.c [new file with mode: 0644]
Kernel/platform-cromemco/target.mk [new file with mode: 0644]
Kernel/platform-cromemco/tricks.s [new file with mode: 0644]

diff --git a/Kernel/platform-cromemco/Makefile b/Kernel/platform-cromemco/Makefile
new file mode 100644 (file)
index 0000000..2e8ab09
--- /dev/null
@@ -0,0 +1,31 @@
+
+CSRCS = devtty.c devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = crt0.s cromemco.s
+ASRCS += tricks.s commonmem.s
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+
+OBJS  = $(AOBJS) $(COBJS)
+
+JUNK = *.rel *.lst *.asm *.sym *.rst
+
+all:   $(OBJS)
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
+       sdasz80 -o cloader-16fdc.s
+       sdldz80 -m -i cloader-16fdc.rel
+       makebin -s 256 cloader-16fdc.ihx > cloader-16fdc.tmp
+       dd if=cloader-16fdc.tmp of=cloader-16fdc.bin bs=1 skip=128
+
diff --git a/Kernel/platform-cromemco/README b/Kernel/platform-cromemco/README
new file mode 100644 (file)
index 0000000..7be076f
--- /dev/null
@@ -0,0 +1,179 @@
+FUZIX on a Cromenco (no hard disk support right now - need docs for that and
+suitable emulation!)
+
+We expect
+
+0              tuart / 4 FDC
+4              fdc aux
+5-9            times
+32             tuart / parallel 36
+48             fdc
+64             mmu
+80             tuart / parallel 84
+255            front panel
+
+
+
+
+The MMU settings we use are
+
+1 << n         That bank 0-6
+
+0x80           Turn on comon writing (write to all banks)
+
+
+UARTs: TMS 5501 x 2 per board. These can do Z80 IM2 where the vector is
+determined by A7-A5 of the IRQ (used as D7-D5 of the vector)
+
+R 0            Status
+
+7: set if tx buffer empty
+6: set if rx data available
+5: irq pending
+4: start bit detected
+3: full bit detected
+2: serial receive line state
+1: overrun (clear on read)
+0: frame error (clear on valid rx)
+
+W 0
+7: 1 for one stop 0 for 2
+0-6 set baud rate (all 0 off)
+0: 110
+1: 150
+2: 300
+3: 1200
+4: 2400
+5: 4800
+6: 9600
+(but see later)
+
+R 1            Data received
+
+W 1            Load tx
+
+W 2            cmd
+
+0:             reset (self clears)
+1:             break send
+2:             IRQ on parallel msb
+3:             May respond to an IRQ by gating an RST
+               Low prevents gating instructions
+4:             Baud rate x8
+5:             Test
+
+
+R 3:           Interrupt address (gives service priority order for events)
+               Each read clears a priority
+
+               C7 timer 1
+               CF timer 2
+               D7 !sens
+               DF timer 3
+               E7 rx data
+               EF tx data
+               F7 timer 4
+               FF timer 5 (or none)
+
+W 3:           Interrupt mask
+
+7: timer 5
+6: timer 4
+5: tx buffer empty
+4: rx data ready
+3: timer 3
+2: !sens
+1: timer 2
+0: timer 1
+
+R 4:
+       Read parallel input data captured after strobe
+W 4:
+       Write parallel
+
+       (Parallel will halt the CPU for the other end to respond .. !)
+
+W 5:   timer 1 (decremented ever 64uS - longest interval 16.32ms)
+
+W 6:   timer 2 (ditto)
+
+W 7:   timer 3 (ditto)
+
+W 8:   timer 4 (ditto)
+
+W 9:   timer 5 (ditto)
+
+
+
+
+The 4FDC has a uart at 0 (parallel out is used for disk control)
+Disk (FD1771).  16FDC is same ports but a 1793
+
+Parallel in is wired so that (16FDC)
+       D7 = DRQ/RTC (Jumper sets it to 512ms clock used with 5501 int)
+       D6 = Seek in progress
+       D3 = Switch 5
+       D2 = Switch 6
+       D1 = Switch 7
+       D0 = Switch 8
+
+4FDC has only D7 (DRQ) optional - default off, D6 seek in progress
+
+64FDC
+       D7 = DRQ/RTC
+       D6 = 1
+       D5 = ?
+       D4-D0 Switch 5/1-4
+
+
+16FDC out
+       D6 clear to eject (not always supported)
+       D5 set to disconnect drive select (shared disk configurations)
+       D4 clear for fast  step mode (8" drives), set once seek complete sent
+       D3 clear to force drive to track 0 (restore)
+       D2 clear activates control OUT (test pin)
+       D1 side select (0 for second side of 2 sided media)
+
+4FDC out
+       D6: eject left
+       D5: eject right
+       D4: clear for fast seek
+       D3:  cler for restore
+       D2: clear activates daisy chain
+
+64FDC out
+       D5: drive select override (as 16FDC)
+       D2: control out (as 16FDC)
+       D1: side select (as 16FDC)
+       
+(hex)
+R 30   status 
+W 30   command
+R 31   track
+W 31   track
+R 32   sector
+W 32   sector
+R 33   data
+W 33   data
+R 34   flags
+       D7: !DRQ
+       D6: !BOOT (0 SW3 set to boot)
+       D5  HEADLOAD    (Drive sect if high on 64FDC)
+       D4  Zero mean switch inhibit init is on (16FDC)
+       D3  motor is on (16FDC) on = 1
+       D2  motor timeout (16FDC) timedout = 1
+       D1 autowait timeout if 1
+       D0: End of Job
+W 34   control
+       D7: autowait - 34H will hold CPU in wait until DRQ or EOJ or RESET
+       D6: double density (4FDC not ??)
+       D5: motor on
+       D4: 1 = 8" (fast step) 0 = 5.25 (slow step)
+       D3-D0 - drive select (only one at a time)
+
+W 40   Disables boot rom as a side effect
+
+
+W 40   bank select
+
+
diff --git a/Kernel/platform-cromemco/cloader-16fdc.s b/Kernel/platform-cromemco/cloader-16fdc.s
new file mode 100644 (file)
index 0000000..285e5d5
--- /dev/null
@@ -0,0 +1,116 @@
+               .area ASEG(ABS)
+               .org  0x80
+;
+;      Loader for Fuzix on a Cromenco 16FDC
+;
+;      The kernel is written in blocks 1+ SS/SD with no magic
+;      involved. We have 128 bytes, but fortunately a ROM helper
+;
+;
+;      Memory map
+;      0x0000-0x002E   Stack
+;      0x0060-0x007F   Used by the boot ROM
+;      0x0080-0x00FF   This boot block
+;      0x0100-0xBFFF   Free RAM
+;      0xC000-0xCFFF   Boot ROM (until we out to 0x40)
+;      0xD000-0xFFFF   May be RAM but may also be ROM shadows
+;
+
+set_side       .equ    0xC003
+set_track      .equ    0xC006
+set_sector     .equ    0xC009
+set_buffer     .equ    0xC00C
+disk_restore   .equ    0xC00F
+disk_seek      .equ    0xC012
+disk_read      .equ    0xC015
+disk_write     .equ    0xC018
+setup_uart     .equ    0xC01B
+char_input     .equ    0xC01E
+char_ready     .equ    0xC021
+line_input     .equ    0xC024
+char_output    .equ    0xC027
+newline_output .equ    0xC02A
+
+       .globl start
+       .globl endc
+       .globl end
+       .globl msg
+;      Carry set, drive in A
+start:
+       push af
+       ld hl,#boot
+       call tout
+       ld hl,#0xFC
+       pop af
+       ld (hl),a       ; boot drive
+       inc hl
+       ld a,#16
+       ld (hl),a       ; controller type (16FDC)
+       inc hl
+       ld bc,(0x7E)    ; features and feature save for boot disk
+       ld (hl),c
+       inc hl
+       ld (hl),b
+       inc hl          ; now 0x100
+       xor a
+       ld b,a
+       call set_side
+       ld a,(0x6E)     ; sectors per track
+       inc a
+       ld c,a
+       ld a,#1         ; sector 2
+       ld de,#128
+trackloop:
+       push af
+       ld a,b
+       call set_track
+       pop af
+secloop:
+       inc a
+       call set_sector
+       call set_buffer
+       ex af,af'       ; shorter than pushing them
+       exx
+       call disk_seek
+       call disk_read
+       jr c, crap
+       exx
+       add hl,de
+       ld a,h
+       cp #0xC0
+       jr z,go
+       ex af,af'
+       cp c
+       jr nz, secloop
+       inc b
+       xor a
+       jr trackloop
+go:
+       ld a,(0x100)
+       cp #0xC3
+       jr z, 0x100
+crap:
+       ld hl, #fail
+       call tout
+       jp 0xC000
+
+tout:
+       ld a,(hl)
+       inc hl
+       or a
+       ret z
+       push hl
+       call char_output
+       pop hl
+       jr tout
+
+msg:
+boot:  .asciz 'Boot'
+fail:  .ascii ' failed'
+       .byte 13,10,0
+
+endc:
+       .org 0xF8
+
+       .ascii 'FZSSSD'
+end:
diff --git a/Kernel/platform-cromemco/config.h b/Kernel/platform-cromemco/config.h
new file mode 100644 (file)
index 0000000..fe8ec2d
--- /dev/null
@@ -0,0 +1,39 @@
+/* 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 */
+#undef CONFIG_SINGLETASK
+/* Fixed banking */
+#define CONFIG_BANK_FIXED
+/* 7 64K banks, 1 is kernel */
+#define MAX_MAPS       6
+#define MAP_SIZE       0xF000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   1
+
+#define TICKSPERSEC 10      /* Ticks per second */
+#define PROGBASE    0x0000  /* also data base */
+#define PROGLOAD    0x0100  /* also data base */
+#define PROGTOP     0xED00  /* Top of program, base of U_DATA copy */
+#define PROC_SIZE   60   /* Memory needed per process */
+
+#define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* 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 3
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    8       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
+#define platform_discard()
diff --git a/Kernel/platform-cromemco/cromemco.s b/Kernel/platform-cromemco/cromemco.s
new file mode 100644 (file)
index 0000000..25bb675
--- /dev/null
@@ -0,0 +1,224 @@
+;
+;      Cromemco hardware support
+;
+
+            .module cromemco
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl _program_vectors
+           .globl platform_interrupt_all
+
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_process_a
+           .globl map_save
+           .globl map_restore
+
+           .globl _platform_reboot
+
+            ; exported debugging tools
+            .globl _platform_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+
+           .globl unix_syscall_entry
+            .globl null_handler
+           .globl nmi_handler
+            .globl interrupt_handler
+           .globl _doexit
+           .globl _inint
+           .globl kstack_top
+           .globl _panic
+           .globl _need_resched
+           .globl _ssig
+
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_platform_reboot:
+_platform_monitor:
+           jr _platform_monitor
+platform_interrupt_all:
+           ret
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+           ld a,#0x81                  ; Every memory is in bank 7
+           out (0x40),a                ; MMU set
+           ld hl,#0xF000               ; Copy 4K to itself loading
+           ld d,h                      ; into into the other banks
+           ld e,l
+           ld b,#0x10
+           ld c,l
+           ldir
+           ld a,#0x01                  ; bank to the kernel bank
+           out (0x40),a
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #448
+            ld (_ramsize), hl
+            ld hl, #(448-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ld a, #156                  ; ticks for 10Hz (9984uS per tick)
+           out (8), a                  ; 10Hz timer on
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+;          ld a, #0xfe                 ; Use FEFF (currently free)
+;          ld i, a
+;            im 2 ; set CPU interrupt mode
+           im 1                        ; really should use a page and im2?
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x38
+            ld hl, #interrupt_handler
+            ld (0x39), hl
+
+           ld a,#0xC3          ; JP
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+           ld (0x0038), a   ;  (rst 38h)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ; now install the interrupt vector at 0x38
+            ld hl, #interrupt_handler
+            ld (0x39), hl
+
+            ; Set vector for jump to NULL
+            ld (0x0000), a   
+            ld hl, #null_handler  ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+           ; falls through
+
+            ; put the paging back as it was -- we're in kernel mode so this is predictable
+map_kernel:
+           push af
+           ld a,#1
+           out (0x40), a
+           ld (map_page), a    ; map_page lives in kernel so be careful
+           pop af              ; our common is r/o common so writes won't
+            ret                        ; cross a bank
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+           ld a, (hl)
+map_process_a:
+           ld (map_page),a     ; save before we map out kernel
+           out (0x40), a
+            ret
+map_process_always:
+           push af
+           ld a, (U_DATA__U_PAGE)
+           ld (map_page),a     ; save before we map out kernel
+           out (0x40), a
+           pop af
+           ret
+map_save:                      ; this is a bit naughty, but we know
+           push af             ; map_save will always be followed by
+           ld a, #1            ; map_kernel so we do the map_kernel
+           out (0x40), a       ; a shade early.
+           ld a, (map_page)    ; then we can get the vars
+           ld (map_store), a
+           pop af
+           ret     
+map_restore:                   ; called in kernel map
+           push af
+           ld a, (map_store)
+           ld (map_page),a
+           out (0x40), a
+           pop af
+           ret     
+map_store:
+           .db 0
+map_page:
+           .db 0
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           push af
+outcharl:
+           in a, (0x00)
+           bit 7,a
+           jr z, outcharl
+           pop af
+           out (0x01), a
+            ret
+
+;
+;      Low level pieces for floppy driver
+;
+               .globl _fd_reset
+               .globl _fd_operation
+               .globl _fd_map
+               .globl _fd_cmd
+
+_fd_reset:
+               ret
+_fd_operation:
+               ret
+_fd_map:
+               .byte 0
+_fd_cmd:
+               .byte 0, 0, 0, 0, 0, 0, 0
+
diff --git a/Kernel/platform-cromemco/crt0.s b/Kernel/platform-cromemco/crt0.s
new file mode 100644 (file)
index 0000000..027a303
--- /dev/null
@@ -0,0 +1,73 @@
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        ; WRS: Note we list all our segments here, even though
+        ; we don't use them all, because their ordering is set
+        ; when they are first seen.
+        .area _CODE
+        .area _CODE2
+        .area _CONST
+        .area _INITIALIZED
+        .area _DATA
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        ; note that areas below here may be overwritten by the heap at runtime, so
+        ; put initialisation stuff in here
+        .area _INITIALIZER
+        .area _GSINIT
+        .area _GSFINAL
+       .area _DISCARD
+        .area _COMMONMEM
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .globl init_hardware
+        .globl s__INITIALIZER
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+        .globl s__DISCARD
+        .globl l__DISCARD
+        .globl s__DATA
+        .globl l__DATA
+        .globl kstack_top
+
+        ; startup code
+        .area _CODE
+init:
+        di
+        ld sp, #kstack_top
+
+        ; Configure memory map
+        call init_early
+
+       ; move the common memory where it belongs    
+       ld hl, #s__DATA
+       ld de, #s__COMMONMEM
+       ld bc, #l__COMMONMEM
+       ldir
+       ; and the discard
+       ld de, #s__DISCARD
+       ld bc, #l__DISCARD
+       ldir
+       ; then zero the data area
+       ld hl, #s__DATA
+       ld de, #s__DATA + 1
+       ld bc, #l__DATA - 1
+       ld (hl), #0
+       ldir
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
diff --git a/Kernel/platform-cromemco/devfd.c b/Kernel/platform-cromemco/devfd.c
new file mode 100644 (file)
index 0000000..04efa5d
--- /dev/null
@@ -0,0 +1,176 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+#define MAX_DRIVE      4
+
+#define OPDIR_NONE     0
+#define OPDIR_READ     1
+#define OPDIR_WRITE    2
+
+#define FD_READ                0x80    /* 2797 needs 0x88, 1797 needs 0x80 */
+#define FD_WRITE       0xA0    /* Likewise A8 v A0 */
+
+/* Extern as they live in common */
+extern uint8_t fd_map;
+extern uint8_t fd_selected;
+extern uint8_t fd_cmd[7];
+
+static uint8_t fd_tab[MAX_DRIVE];
+
+__sfr __at 0x04        fd_aux;
+__sfr __at 0x30 fd_stcmd;
+__sfr __at 0x31 fd_track;
+__sfr __at 0x32 fd_sector;
+__sfr __at 0x33 fd_data;
+__sfr __at 0x34 fd_ctrlflag;
+
+/* 4 large disks (0 5" 1 8" 255 none */
+
+uint8_t drivetype[4] = { 1, 1, 1, 1 };
+
+/*
+ *     We only support normal block I/O for the moment.
+ */
+
+static uint8_t selmap[4] = { 0x01, 0x02, 0x04, 0x08 };
+
+static const uint8_t skewtab[2][18] = {
+    /* Matches CDOS 5" skew for DSDD */
+    { 1, 5, 9, 3, 7, 2, 6, 10, 4, 9 },
+    /* No idea what CDOS uses for 8" DSDD right now */
+    { 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 },
+};
+
+static uint8_t live[4];
+
+/*
+ *     A note on disk formats and the Cromenco (and also emulator limits)
+ *
+ *     Classic 8" SS/SD        26 sectors, 128 bytes/sector, 77 track
+ *                             software skewed
+ *     Classic 5" SS/SD        18 sectors, 40 tracks otherwise as before
+ *
+ *     Double sided use the same formats for SD but with two sides
+ *
+ *     When we go to DD 8" goes to 16 512 byte sectors/track and
+ *     5" goes to 10 512 byte sectors/track
+ *
+ *     The controller can do a lot more but the emulators don't always
+ *     cope. In particular a 'correct' bootable disk is supposed to be
+ *     SD on track 0 side 0 and can be DS/DD on the rest.
+ *
+ *     Likewise the hardware can write PC format media in theory and
+ *     do format level skewing at least for 5.25" disks
+ *
+ *     Just to get us going - only do DSDD.
+ */
+static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    int tries;
+    uint8_t err = 0;
+    uint8_t drive = minor & 3;
+    uint8_t *driveptr = fd_tab + drive;
+    uint8_t large = !(minor & 0x10);
+    const uint8_t *skew = skewtab[large];              /* skew table */
+
+    if(rawflag == 2)
+        goto bad2;
+
+    fd_map = rawflag;
+    if (rawflag && d_blkoff(BLKSHIFT))
+            return -1;
+
+    /* Command to go to the controller after any seek is done */
+    fd_cmd[0] = is_read ? FD_READ : FD_WRITE;
+    if (large) {
+        /* Track */
+        fd_cmd[1] = udata.u_block / 16;
+        /* Sector */
+        fd_cmd[2] = skew[udata.u_block % 16];  /* 1..n skewed */
+        /* control */
+        fd_cmd[6] = 0xF0;
+    } else {
+        fd_cmd[1] = udata.u_block / 10;
+        fd_cmd[2] = skew[udata.u_block % 10];
+        fd_cmd[6] = 0xA0;
+    }
+    fd_cmd[6] |= (1 << drive);
+    /* Directon of xfer */
+    fd_cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE;
+    /* Buffer */
+    fd_cmd[4] = ((uint16_t)udata.u_dptr) & 0xFF;
+    fd_cmd[5] = ((uint16_t)udata.u_dptr) >> 8;
+    
+    /* FIXME: Sides. Really 32 sectors/track 16 each side */
+
+    while (udata.u_done < udata.u_nblock) {
+        if (large) {
+            fd_cmd[1] = udata.u_block / 16;
+            fd_cmd[2] = (udata.u_block % 16) + 1;
+        } else {
+            fd_cmd[1] = udata.u_block / 10;
+            fd_cmd[2] = (udata.u_block % 10) + 1;
+        }
+        for (tries = 0; tries < 4 ; tries++) {
+            err = fd_operation(driveptr);
+            if (err == 0)
+                break;
+            if (tries > 1)
+                fd_reset(driveptr);
+        }
+        if (tries == 4)
+            goto bad;
+        udata.u_block++;
+        udata.u_done++;
+    }
+    return udata.u_done << 9;
+bad:
+    kprintf("fd%d: error %x\n", minor, err);
+bad2:
+    udata.u_error = EIO;
+    return -1;
+}
+
+/* We encode the minor has
+        000[8/5][sd/dd][ss/ds][disk.2] */
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    uint8_t *dp = live + (minor & 3);
+
+    flag;
+    if ((minor & 0xE0) || drivetype[minor] == 255) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    /* Ensure we can't open the same physical disk in two modes at once */
+    if (*dp != 0xFF) {
+        udata.u_error = EBUSY;
+        return -1;
+    }
+    *dp = minor;
+    return 0;
+}
+
+int fd_close(uint8_t minor)
+{
+    live[minor & 3] = 0xFF;
+    return 0;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(minor, true, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;rawflag;minor;
+    return fd_transfer(minor, false, rawflag);
+}
+
+    
\ No newline at end of file
diff --git a/Kernel/platform-cromemco/devfd.h b/Kernel/platform-cromemco/devfd.h
new file mode 100644 (file)
index 0000000..22ad8c4
--- /dev/null
@@ -0,0 +1,7 @@
+extern int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int fd_close(uint8_t minor);
+extern int fd_open(uint8_t minor, uint16_t flag);
+
+extern void fd_reset(uint8_t *ptr);
+extern int fd_operation(uint8_t *ptr);
diff --git a/Kernel/platform-cromemco/devices.c b/Kernel/platform-cromemco/devices.c
new file mode 100644 (file)
index 0000000..4b869a7
--- /dev/null
@@ -0,0 +1,39 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devfd.h>
+#include <devsys.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  */
+  /* TODO: add fd_ioctl and eject etc */
+  {  fd_open,     fd_close,    fd_read,   fd_write,   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,    tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices: none for now */
+  {  nxio_open,   no_close,   no_rdwr,   no_rdwr,  no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,     sys_close,   sys_read, sys_write, sys_ioctl  },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+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) - 1)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+}
diff --git a/Kernel/platform-cromemco/devtty.c b/Kernel/platform-cromemco/devtty.c
new file mode 100644 (file)
index 0000000..d62c586
--- /dev/null
@@ -0,0 +1,118 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+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 uint8_t ttybase[NUM_DEV_TTY+1] = {
+ 0, 0, 32, 80
+};
+
+static uint8_t ttypoll;
+
+/* Write to system console */
+void kputchar(char c)
+{
+    /* handle CRLF */
+    if(c=='\n')
+        tty_putc(1, '\r');
+    tty_putc(1, c);
+}
+
+char tty_writeready(uint8_t minor)
+{
+    uint8_t r = ttybase[minor];
+    r = in(r);
+    if (r & 0x80)
+        return 1;
+    return 0;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+    uint8_t r = ttybase[minor];
+    out(r + 1, c);
+}
+
+void tty_sleeping(uint8_t minor)
+{
+    ttypoll |= 1 << minor;
+}
+
+__sfr __at 0x08 timer4;
+
+void tty_irq(uint8_t minor)
+{
+    uint8_t r = ttybase[minor];
+    uint8_t op;
+    while((op = in(r + 3)) != 0xFF) {
+        switch(op) {
+        case 0xE7:
+            /* should check in(r) for error bits */
+            tty_inproc(minor, in(r + 1 ));
+        case 0xEF:
+            ttypoll &= ~(1 << minor);
+            wakeup(&ttydata[minor]);
+        case 0xF7:
+            if (minor == 1) {
+                timer_interrupt();
+                timer4 = 156;
+            }
+        }
+    }
+}    
+
+static uint8_t baudbits[] = {
+    1,
+    1,
+    1,
+    1, /* 110 */
+    1,
+    2, /* 150 */
+    4, /* 300 */
+    4,
+    8, /* 1200 */
+    16,        /* 2400 */
+    32,        /* 4800 */
+    64,        /* 9600 */
+    /* x8 modes */
+    8, /* 19200 */
+    16,        /* 38400 */
+    16,
+    16
+};
+
+void tty_setup(uint8_t minor)
+{
+    struct termios *t = &ttydata[minor].termios;
+    uint8_t baud = t->c_cflag & CBAUD;
+    uint8_t r = ttybase[minor];
+    out(r, baudbits[baud] | (t->c_cflag & CSTOPB) ? 0 : 0x80);
+    /* Assume we keep to IM1 */
+    if (baud <= B9600)
+        out(r + 2, 0x8);
+    else
+        out(r + 2, 0x18);
+    t->c_cflag |= CS8;
+    t->c_cflag &= ~PARENB;
+    /* Ok we could do sw parity .. */
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+    used(minor);
+    return 1;
+}
diff --git a/Kernel/platform-cromemco/devtty.h b/Kernel/platform-cromemco/devtty.h
new file mode 100644 (file)
index 0000000..ddb0f42
--- /dev/null
@@ -0,0 +1 @@
+extern void tty_irq(uint8_t minor);
diff --git a/Kernel/platform-cromemco/fuzix.lnk b/Kernel/platform-cromemco/fuzix.lnk
new file mode 100644 (file)
index 0000000..886a5e1
--- /dev/null
@@ -0,0 +1,36 @@
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x0100
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xE000
+-l z80
+platform-cromemco/crt0.rel
+platform-cromemco/commonmem.rel
+platform-cromemco/cromemco.rel
+platform-cromemco/main.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem_std-z80.rel
+platform-cromemco/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-cromemco/devfd.rel
+platform-cromemco/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+bankfixed.rel
+devsys.rel
+platform-cromemco/devtty.rel
+-e
diff --git a/Kernel/platform-cromemco/main.c b/Kernel/platform-cromemco/main.c
new file mode 100644 (file)
index 0000000..8f83fac
--- /dev/null
@@ -0,0 +1,34 @@
+#include <kernel.h>
+#include <devtty.h>
+
+uaddr_t ramtop = PROGTOP;
+
+void pagemap_init(void)
+{
+ int i;
+ for (i = 1; i < 7; i++)
+  pagemap_add(1 << i);
+}
+
+void platform_idle(void)
+{
+  /* halt ?? */
+}
+
+void platform_interrupt(void)
+{
+ tty_irq(1);
+ tty_irq(2);
+ tty_irq(3);
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
+
+uint8_t platform_param(char *p)
+{
+ used(p);
+ return 0;
+}
diff --git a/Kernel/platform-cromemco/target.mk b/Kernel/platform-cromemco/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-cromemco/tricks.s b/Kernel/platform-cromemco/tricks.s
new file mode 100644 (file)
index 0000000..ee50c07
--- /dev/null
@@ -0,0 +1,5 @@
+
+       .include "../kernel.def"
+       .include "kernel.def"
+
+       .include "../lib/z80fixedbank.s"