Kernel: zeta-v2: Implement /dev/rd and new /dev/mem
authorWill Sowerbutts <will@sowerbutts.com>
Sun, 8 Jan 2017 23:00:43 +0000 (23:00 +0000)
committerWill Sowerbutts <will@sowerbutts.com>
Sun, 8 Jan 2017 23:05:11 +0000 (23:05 +0000)
This implements the new /dev/mem and /dev/rd drivers for the zeta-v2
platform.

Kernel/platform-zeta-v2/Makefile
Kernel/platform-zeta-v2/config.h
Kernel/platform-zeta-v2/devrd.c [deleted file]
Kernel/platform-zeta-v2/devrd.h [deleted file]
Kernel/platform-zeta-v2/devrd_hw.s [deleted file]
Kernel/platform-zeta-v2/devrd_zeta2.c [new file with mode: 0644]
Kernel/platform-zeta-v2/devrd_zeta2_hw.s [new file with mode: 0644]
Kernel/platform-zeta-v2/discard.c
Kernel/platform-zeta-v2/fuzix.lnk
Kernel/platform-zeta-v2/kernel.def
Kernel/platform-zeta-v2/zeta-v2.s

index 9d87e96..20526e1 100644 (file)
@@ -1,11 +1,11 @@
 ASRCS = crt0.s tricks.s commonmem.s zeta-v2.s monitor.s
-ASRCS += ds1302-n8vem.s devrd_hw.s
-CSRCS = devices.c main.c devtty.c devrd.c ppide.c
+ASRCS += ds1302-n8vem.s devrd_zeta2_hw.s
+CSRCS = devices.c main.c devtty.c devrd_zeta2.c ppide.c
 DISCARD_CSRCS = discard.c devtty_discard.c
 DISCARD_DSRCS = ../dev/ds1302_discard.c ../dev/devide_discard.c
 DSRCS = ../dev/devfd.c ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c
-DSRCS += ../dev/ds1302.c ../dev/devide.c
-DASRCS = ../dev/devfd_hw.s
+DSRCS += ../dev/ds1302.c ../dev/devide.c ../dev/devrd.c
+DASRCS = ../dev/devfd_hw.s ../dev/devrd_hw.s
 
 AOBJS = $(ASRCS:.s=.rel)
 COBJS = $(CSRCS:.c=.rel)
index df016d7..0e7cbeb 100644 (file)
@@ -14,8 +14,8 @@
 #define CONFIG_BANK16
 /* Permit large I/O requests to bypass cache and go direct to userspace */
 #define CONFIG_LARGE_IO_DIRECT
-/* 32 x 16K pages, 3 pages for kernel, 16 pages for RAM disk */
-#define MAX_MAPS       13
+/* 32 x 16K pages, 3 pages for kernel, whatever the RAM disk uses */
+#define MAX_MAPS       (32 - 3 - DEV_RD_RAM_PAGES)
 
 /* Banks as reported to user space */
 #define CONFIG_BANKS   4
@@ -41,7 +41,7 @@
 #define NBUFS    10       /* Number of block buffers */
 #define NMOUNTS         4        /* Number of mounts at a time */
 
-#define MAX_BLKDEV 4       /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 SD card */
+#define MAX_BLKDEV 4       /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 PPIDE */
 
 /* On-board DS1302, we can read the time of day from it */
 #define CONFIG_RTC
 //#define CONFIG_PPP           /* #define CONFIG_PPP to enable as tty3 */
 
 /* Device parameters */
+#define CONFIG_DEV_MEM          /* enable /dev/mem driver */
+
 #define CONFIG_RAMDISK          /* enable memory-backed disk driver */
-#define NUM_DEV_RD 1
-#define DEV_RD_PAGES 16                /* size of the RAM disk in pages */
-#define DEV_RD_START 48                /* first page used by the RAM disk */
+#define DEV_RD_ROM_PAGES 28     /* size of the ROM disk in 16KB pages (max 32, any unused pages are at the start of the ROM) */
+#define DEV_RD_RAM_PAGES 0      /* size of the RAM disk in 16KB pages */
+
+#define DEV_RD_ROM_START ((uint32_t)(32-DEV_RD_ROM_PAGES) << 14)        /* first byte used by the ROM disk */
+#define DEV_RD_RAM_START ((uint32_t)(64-DEV_RD_RAM_PAGES) << 14)        /* first byte used by the RAM disk */
+#define DEV_RD_ROM_SIZE  ((uint32_t)DEV_RD_ROM_PAGES << 14)             /* size of the ROM disk */
+#define DEV_RD_RAM_SIZE  ((uint32_t)DEV_RD_RAM_PAGES << 14)             /* size of the RAM disk */
 
 #ifdef CONFIG_PPP
        /* SD card in ParPortProp */
diff --git a/Kernel/platform-zeta-v2/devrd.c b/Kernel/platform-zeta-v2/devrd.c
deleted file mode 100644 (file)
index d6a76e5..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/* Zeta SBC V2 RAM disk driver 
- *
- * Implements a single RAM disk DEV_RD_PAGES size and
- * starting from DEV_RD_START page
- *
- * */
-
-#include <kernel.h>
-#include <kdata.h>
-#include <printf.h>
-
-extern uint8_t src_page;       /* source page number */
-extern uint8_t dst_page;       /* destination page number */
-extern uint16_t src_offset;    /* offset of the data in the source page */
-extern uint16_t dst_offset;    /* offset of the data in the destination page */
-extern uint16_t cpy_count;     /* data transfer length */
-extern uint8_t kernel_pages[]; /* kernel's page table */
-
-int ramdisk_transfer(bool is_read, uint8_t minor, uint8_t rawflag);
-int page_copy(void);           /* assembler code */
-
-int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
-{
-    flag;
-    return ramdisk_transfer(true, minor, rawflag);
-}
-
-int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
-{
-    flag;
-    return ramdisk_transfer(false, minor, rawflag);
-}
-
-int ramdisk_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
-{
-       blkno_t block;
-       int block_xfer;     /* r/w return value (number of 512 byte blocks transferred) */
-       uint32_t rd_addr;
-       uint16_t buffer_addr;
-       usize_t xfer_count;
-
-       if (minor >= NUM_DEV_RD) {
-               udata.u_error = ENXIO;
-               return -1;
-       }
-
-       if (rawflag) { /* rawflag == 1, read to or write from user space */
-               xfer_count = udata.u_count;
-               buffer_addr = (uint16_t) udata.u_base;
-               block = udata.u_offset >> 9;
-               block_xfer = xfer_count >> 9;
-       } else { /* rawflag == 0, read to or write from kernel space */
-               xfer_count = 512;
-               buffer_addr = (uint16_t) udata.u_buf->bf_data;
-               block = udata.u_buf->bf_blk;
-               block_xfer = 1;
-       }
-
-       if (block > (DEV_RD_PAGES * 16 * 2)) { /* block beyond RAM disk end? */
-               udata.u_error = EIO;
-               return -1;
-       }
-
-       /* calculate physical address of the RAM drive data */
-       /* rd_addr = block * 512 + DEV_RD_START * 16K; */
-       rd_addr = ((unsigned long) block << 9) + DEV_RD_START * 16384UL;
-       while (xfer_count > 0) {
-               if (is_read) {
-                       /* RAM disk page number = rd_addr / 16K */
-                       src_page = rd_addr >> 14;
-                       /* offset within RAM disk page */
-                       src_offset = rd_addr & 0x3FFF;
-                       /* destination page number */
-                       if (rawflag)
-                               dst_page = ((uint8_t *) &udata.u_page)[buffer_addr >> 14];
-                       else
-                               dst_page = kernel_pages[buffer_addr >> 14];
-                       /* offset in the destination page */
-                       dst_offset = buffer_addr & 0x3FFF;
-               } else {
-                       /* source page number */
-                       if (rawflag)
-                               src_page = ((uint8_t *) &udata.u_page)[buffer_addr >> 14];
-                       else
-                               src_page = kernel_pages[buffer_addr >> 14];
-                       /* offset in the source page */
-                       src_offset = buffer_addr & 0x3FFF;
-                       /* RAM disk page number = rd_addr / 16K */
-                       dst_page = rd_addr >> 14;
-                       /* offset within RAM disk page */
-                       dst_offset = rd_addr & 0x3FFF;
-               }
-               cpy_count = xfer_count;
-               if (cpy_count > 16384 - src_offset)
-                       cpy_count = 16384 - src_offset;
-               if (cpy_count > 16384 - dst_offset)
-                       cpy_count = 16384 - dst_offset;
-#ifdef DEBUG
-               kprintf("page_cpy(src_page=%x, src_offset=%x, dst_page=%x, dst_offset=%x, cpy_count=%x)\n", src_page, src_offset, dst_page, dst_offset, cpy_count);
-#endif
-               page_copy();
-               xfer_count -= cpy_count;
-               buffer_addr += cpy_count;
-               rd_addr += cpy_count;
-       }
-
-       return block_xfer;
-}
-
-
-int rd_open(uint8_t minor)
-{
-    if(minor < NUM_DEV_RD){
-        return 0;
-    } else {
-        udata.u_error = EIO;
-        return -1;
-    }
-}
diff --git a/Kernel/platform-zeta-v2/devrd.h b/Kernel/platform-zeta-v2/devrd.h
deleted file mode 100644 (file)
index e54a154..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __DEVRD_DOT_H__
-#define __DEVRD_DOT_H__
-
-/* public interface */
-int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
-int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
-int rd_init(void);
-int rd_open(uint8_t minor, uint16_t flag);
-
-#endif /* __DEVRD_DOT_H__ */
diff --git a/Kernel/platform-zeta-v2/devrd_hw.s b/Kernel/platform-zeta-v2/devrd_hw.s
deleted file mode 100644 (file)
index 750ce9e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-       .module devrd_hw
-
-       ; imported symbols - from zeta-v2.s
-       .globl map_kernel,mpgsel_cache
-
-       ; exported symbols (used by devrd.c)
-       .globl _page_copy
-       .globl _src_page, _src_offset, _dst_page, _dst_offset, _cpy_count
-
-       .include "kernel.def"
-
-       .area _COMMONMEM
-
-;=========================================================================
-; _page_copy - Copy data from one physical page to another
-; Inputs:
-;   _src_page - page number of the source page (uint8_t)
-;   _src_offset - offset in the source page (uint16_t)
-;   _dst_page - page number of the destination page (uint8_t)
-;   _dst_offset - offset in the destination page (uint16_t)
-;   _cpy_count - number of bytes to copy (uint16_t)
-; Outputs:
-;   Data copied
-;   Destroys AF, BC, DE, HL
-;=========================================================================
-_page_copy:
-       ld a,(_src_page)
-       ld (mpgsel_cache+1),a           ; save the mapping
-       out (MPGSEL_1),a                ; map source page to bank #1
-       ld a,(_dst_page)
-       ld (mpgsel_cache+2),a           ; save the mapping
-       out (MPGSEL_2),a                ; map destination page to bank #2
-       ld hl,(_src_offset)             ; load offset in source page
-       ld a,#0x40                      ; add bank #1 offset - 0x4000
-       add h                           ; to the source offset
-       ld h,a
-       ld de,(_dst_offset)
-       ld a,#0x80                      ; add bank #2 offset - 0x8000
-       add d                           ; to the destination offset
-       ld d,a
-       ld bc,(_cpy_count)              ; bytes to copy
-       ldir                            ; do the copy
-       call map_kernel                 ; map the kernel
-       ret
-
-; variables
-_src_page:
-       .db     0
-_dst_page:
-       .db     0
-_src_offset:
-       .dw     0
-_dst_offset:
-       .dw     0
-_cpy_count:
-       .dw     0
-;=========================================================================
diff --git a/Kernel/platform-zeta-v2/devrd_zeta2.c b/Kernel/platform-zeta-v2/devrd_zeta2.c
new file mode 100644 (file)
index 0000000..2dd5e9e
--- /dev/null
@@ -0,0 +1,47 @@
+/* Zeta SBC V2  memory driver
+ *
+ * 2017-01-03 William R Sowerbutts, based on RAM disk code by Sergey Kiselev
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#define DEVRD_PRIVATE
+#include "devrd.h"
+
+void rd_page_copy(void); // devrd_zeta2_hw.s
+
+void rd_platform_copy(void)
+{
+    uint16_t ocount, count, maxcpy;
+
+    ocount = count = rd_cpy_count;
+
+    while(true){
+        /* ensure transfer will not span a 16KB bank boundary */
+        if(count > 1){
+            maxcpy = ((uint16_t)rd_src_address) & 0x3FFF;
+            if((rd_dst_address & 0x3FFF) > maxcpy)
+                maxcpy = rd_dst_address & 0x3FFF;
+            maxcpy = 0x4000 - maxcpy;
+            if(rd_cpy_count > maxcpy)
+                rd_cpy_count = maxcpy;
+        }
+#ifdef DEBUG
+        kprintf("rd_transfer: src=0x%lx, dst=0x%x(%s) reverse=%d count=%d\n",
+                rd_src_address, rd_dst_address, rd_dst_userspace?"user":"kern",
+                rd_reverse, rd_cpy_count);
+#endif
+        rd_page_copy();
+
+        count -= rd_cpy_count;
+        if(!count)
+            break;
+
+        rd_dst_address += rd_cpy_count;
+        rd_src_address += rd_cpy_count;
+        rd_cpy_count = count;
+    }
+
+    rd_cpy_count = ocount;
+}
diff --git a/Kernel/platform-zeta-v2/devrd_zeta2_hw.s b/Kernel/platform-zeta-v2/devrd_zeta2_hw.s
new file mode 100644 (file)
index 0000000..05b2f86
--- /dev/null
@@ -0,0 +1,141 @@
+        .module devrd_hw
+
+        ; imported symbols
+        .globl map_kernel, mpgsel_cache, _kernel_pages
+        .globl _rd_platform_copy
+
+        ; exported symbols
+        .globl _rd_page_copy
+        .globl _rd_cpy_count
+        .globl _rd_reverse
+        .globl _rd_dst_userspace
+        .globl _rd_dst_address
+        .globl _rd_src_address
+        .globl _devmem_read
+        .globl _devmem_write
+
+        .include "../kernel.def"
+        .include "kernel.def"
+
+        .area _CODE
+_devmem_write:
+        ld a, #1
+        ld (_rd_reverse), a             ; 1 = write
+        jr _devmem_go
+
+_devmem_read:
+        xor a
+        ld (_rd_reverse), a             ; 0 = read
+        inc a
+_devmem_go:
+        ld (_rd_dst_userspace), a       ; 1 = userspace
+        ; load the other parameters
+        ld hl, (U_DATA__U_BASE)
+        ld (_rd_dst_address), hl
+        ld hl, (U_DATA__U_OFFSET)
+        ld (_rd_src_address), hl
+        ld hl, (U_DATA__U_OFFSET+2)
+        ld (_rd_src_address+2), hl
+        ld hl, (U_DATA__U_COUNT)
+        ld (_rd_cpy_count), hl
+        ; for single byte transfers we can optimise away the outer loop
+        dec l                           ; test for HL=1
+        ld a, h
+        or l
+        jp nz, _rd_platform_copy        ; > 1 byte, do it the hard way
+        call _rd_page_copy              ; transfer single byte
+        ld hl, #1                       ; return with HL set appropriately
+        ret
+
+        .area _COMMONMEM
+;=========================================================================
+; _rd_page_copy - Copy data from one physical page to another
+; See notes in devrd.h for input parameters
+;=========================================================================
+_rd_page_copy:
+        ; split rd_src_address into page and offset -- it's limited to 20 bits (max 0xFFFFF)
+        ; example address 0x000ABCDE 
+        ; in memory it is stored: DE BC 0A 00
+        ; offset would be 0x0ABCDE & 0x3FFF = 0x3CDE
+        ; page would be   0x0ABCDE >> 14    = 0x2A
+
+        ; compute source page number
+        ld a,(_rd_src_address+1)        ; load 0xBC -> B
+        ld b, a
+        ld a,(_rd_src_address+2)        ; load 0x0A -> A
+        rl b                            ; grab the top bit into carry
+        rla                             ; shift accumulator left, load carry bit at the bottom 
+        rl b                            ; and again
+        rla                             ; now A is the page number (0x2A)
+
+        ; map source page
+        ld (mpgsel_cache+1),a           ; save the mapping
+        out (MPGSEL_1),a                ; map source page to bank #1
+
+        ; compute source page offset, store in DE
+        ld a,(_rd_src_address+1)
+        and #0x3F                       ; mask to 16KB
+        or #0x40                        ; add offset for bank 1
+        ld d, a
+        ld a,(_rd_src_address+0)
+        ld e, a                         ; now offset is in DE
+
+        ; compute destination page index (addr 0xABCD >> 14 = 0x02)
+        ld a,(_rd_dst_address+1)        ; load top 8 bits
+        and #0xc0                       ; mask off top 2 bits
+        rlca                            ; rotate into lower 2 bits
+        rlca
+        ld b, #0
+        ld c, a                         ; store in l
+
+        ; look up page number
+        ld a,(_rd_dst_userspace)        ; are we loading into userspace memory?
+        or a
+        jr nz, rd_translate_userspace
+        ld hl, #_kernel_pages           ; get kernel page table
+        jr rd_do_translate
+rd_translate_userspace:
+        ld hl, #U_DATA__U_PAGE          ; get user process page table
+rd_do_translate:
+        add hl, bc                      ; add index to base ptr (uint8_t *)
+        ld a, (hl)                      ; load the page number from the page table
+
+        ; map destination page
+        ld (mpgsel_cache+2),a           ; save the mapping
+        out (MPGSEL_2),a                ; map destination page to bank #2
+
+        ; compute destination page offset, store in HL
+        ld a,(_rd_dst_address+1)
+        and #0x3F                       ; mask to 16KB
+        or #0x80                        ; add offset for bank #2
+        ld h, a
+        ld a, (_rd_dst_address+0)
+        ld l, a                         ; now offset is in HL
+
+        ; load byte count
+        ld bc,(_rd_cpy_count)           ; bytes to copy
+
+        ; check if reversed
+        ld a, (_rd_reverse)
+        or a
+        jr nz, go
+        ex de,hl                        ; reverse if necessary
+go:
+        ldir                            ; do the copy
+        jp map_kernel                   ; map back the kernel
+
+; variables
+_rd_cpy_count:
+        .dw     0                       ; uint16_t
+_rd_reverse:
+        .db     0                       ; bool
+_rd_dst_userspace:
+        .db     0                       ; bool
+_rd_dst_address:
+        .dw     0                       ; uint16_t
+_rd_src_address:
+        .db     0                       ; uint32_t
+        .db     0
+        .db     0
+        .db     0
+;=========================================================================
index 4081d80..ce78eff 100644 (file)
@@ -4,13 +4,21 @@
 #include <devtty.h>
 #include <ds1302.h>
 #include "config.h"
+#include "devrd.h"
+
+/* Everything in here is discarded after init starts */
 
 #ifdef CONFIG_PPIDE
 #include <devide.h>
-
 void ppide_init(void);
 #endif
 
+void init_hardware_c(void)
+{
+    ramsize = 512;
+    procmem = 512 - 64 - (DEV_RD_RAM_PAGES<<4);
+}
+
 void pagemap_init(void)
 {
        int i;
@@ -21,7 +29,7 @@ void pagemap_init(void)
         * Page 35 is the common area
         * Pages starting from DEV_RD_START are used by RAM disk
         */
-       for (i = 32 + 4; i < DEV_RD_START; i++)
+       for (i = 32 + 4; i < (DEV_RD_RAM_START >> 14); i++)
                pagemap_add(i);
 
        /* finally add the common area */
@@ -32,7 +40,6 @@ void map_init(void)
 {
 }
 
-
 void device_init(void)
 {
        ds1302_init();
index 0762842..02a9689 100644 (file)
@@ -18,6 +18,8 @@ platform-zeta-v2/devfd.rel
 platform-zeta-v2/devfd_hw.rel
 platform-zeta-v2/devrd.rel
 platform-zeta-v2/devrd_hw.rel
+platform-zeta-v2/devrd_zeta2.rel
+platform-zeta-v2/devrd_zeta2_hw.rel
 platform-zeta-v2/devices.rel
 devio.rel
 filesys.rel
index ae762f1..c1ac107 100644 (file)
@@ -3,8 +3,6 @@
 U_DATA                 .equ    0xF000  ; (this is struct u_data from kernel.h)
 U_DATA__TOTALSIZE      .equ    0x300   ; 256+256+256 bytes.
 Z80_TYPE               .equ    0       ; just an old good Z80
-;RAM_KB                        .equ    512
-RAM_KB                 .equ    256
 USE_FANCY_MONITOR      .equ    1       ; disabling this saves around approx 0.5KB
 
 PROGBASE               .equ    0x0000
index 6fdce98..03ba17f 100644 (file)
@@ -21,6 +21,7 @@
         ; imported symbols
         .globl _ramsize
         .globl _procmem
+        .globl _init_hardware_c
         .globl outhl
         .globl outnewline
        .globl interrupt_handler
@@ -130,11 +131,6 @@ foundpage:
        ret
 
 init_hardware:
-        ld hl, #RAM_KB                 ; set system RAM size
-        ld (_ramsize), hl
-        ld hl,#(RAM_KB-64)             ; 64K for kernel
-        ld (_procmem), hl
-
         ; program vectors for the kernel
         ld hl, #0
         push hl
@@ -186,8 +182,7 @@ init_partial_uart:
        ld a,h                          ; get bits 15-8 of int. vectors table
        ld i,a                          ; load to I register
        im 2                            ; set Z80 CPU interrupt mode 2
-
-       ret
+        jp _init_hardware_c             ; pass control to C, which returns for us
 
 ;=========================================================================
 ; Kernel code