From 720a7d177dcccb9acdb18e9c3d5df42cc49a3deb Mon Sep 17 00:00:00 2001 From: Warren Toomey Date: Thu, 6 Feb 2025 10:19:23 +1000 Subject: [PATCH] Kernel/platform/platform-rosco-r2: A port of FUZIX to the Rosco r2 m68k SBC. --- Kernel/platform/platform-rosco-r2/Makefile | 70 +++ Kernel/platform/platform-rosco-r2/README.md | 151 +++++ Kernel/platform/platform-rosco-r2/config.h | 63 ++ Kernel/platform/platform-rosco-r2/crt0.S | 51 ++ Kernel/platform/platform-rosco-r2/devch375.c | 41 ++ Kernel/platform/platform-rosco-r2/devch375.h | 20 + .../platform-rosco-r2/devch375_discard.c | 105 ++++ Kernel/platform/platform-rosco-r2/devices.c | 40 ++ Kernel/platform/platform-rosco-r2/devtty.c | 315 ++++++++++ Kernel/platform/platform-rosco-r2/devtty.h | 10 + .../platform/platform-rosco-r2/fuzix.export | 0 Kernel/platform/platform-rosco-r2/fuzix.ld | 87 +++ Kernel/platform/platform-rosco-r2/kernel.def | 3 + Kernel/platform/platform-rosco-r2/libc.c | 52 ++ Kernel/platform/platform-rosco-r2/main.c | 80 +++ Kernel/platform/platform-rosco-r2/mk_fs_img | 34 + Kernel/platform/platform-rosco-r2/p68000.S | 582 ++++++++++++++++++ Kernel/platform/platform-rosco-r2/target.mk | 2 + Kernel/platform/platform-rosco-r2/tricks.S | 3 + 19 files changed, 1709 insertions(+) create mode 100644 Kernel/platform/platform-rosco-r2/Makefile create mode 100644 Kernel/platform/platform-rosco-r2/README.md create mode 100644 Kernel/platform/platform-rosco-r2/config.h create mode 100644 Kernel/platform/platform-rosco-r2/crt0.S create mode 100644 Kernel/platform/platform-rosco-r2/devch375.c create mode 100644 Kernel/platform/platform-rosco-r2/devch375.h create mode 100644 Kernel/platform/platform-rosco-r2/devch375_discard.c create mode 100644 Kernel/platform/platform-rosco-r2/devices.c create mode 100644 Kernel/platform/platform-rosco-r2/devtty.c create mode 100644 Kernel/platform/platform-rosco-r2/devtty.h create mode 100644 Kernel/platform/platform-rosco-r2/fuzix.export create mode 100644 Kernel/platform/platform-rosco-r2/fuzix.ld create mode 100644 Kernel/platform/platform-rosco-r2/kernel.def create mode 100644 Kernel/platform/platform-rosco-r2/libc.c create mode 100644 Kernel/platform/platform-rosco-r2/main.c create mode 100755 Kernel/platform/platform-rosco-r2/mk_fs_img create mode 100644 Kernel/platform/platform-rosco-r2/p68000.S create mode 100644 Kernel/platform/platform-rosco-r2/target.mk create mode 100644 Kernel/platform/platform-rosco-r2/tricks.S diff --git a/Kernel/platform/platform-rosco-r2/Makefile b/Kernel/platform/platform-rosco-r2/Makefile new file mode 100644 index 0000000000..2b2b627ee7 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/Makefile @@ -0,0 +1,70 @@ + +CSRCS = devtty.c +CSRCS += devices.c main.c libc.c +CSRCS += devch375.c devch375_discard.c + +ASRCS = p68000.S crt0.S +ASRCS += tricks.S + +DSRCS = ../../dev/mbr.c ../../dev/blkdev.c +DSRCS += ../../dev/devsd.c ../../dev/devsd_discard.c +DOBJS = $(patsubst ../../dev/%.c,%.o, $(DSRCS)) + +LSRCS = ../../lib/68000exception.c ../../lib/68000usercopy.c +LSRCS += ../../lib/68000relocate.c +LOBJS = $(patsubst ../../lib/%.c,%.o, $(LSRCS)) + +COBJS = $(CSRCS:.c=$(BINEXT)) +AOBJS = $(ASRCS:.S=.o) +OBJS = $(COBJS) $(AOBJS) $(DOBJS) $(LOBJS) + +CROSS_CCOPTS += -I../../dev/ + +all: $(OBJS) + +$(COBJS): %.o: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %.o: %.S + $(CROSS_AS) $(ASOPTS) $< -o $*.o + +$(DOBJS): %.o: ../../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(LOBJS): %.o: ../../lib/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +tricks.S: ../../lib/68000flat.S + +clean: + rm -f *.o fuzix.elf core *~ fuzix.dis + +image: + $(CROSS_LD) -M -o fuzix.elf -T fuzix.ld p68000.o ../../start.o \ + ../../version.o ../../cpu-68000/lowlevel-68000.o tricks.o \ + main.o ../../timer.o ../../kdata.o 68000exception.o \ + devices.o ../../devio.o ../../filesys.o ../../process.o \ + ../../inode.o ../../syscall_fs.o ../../syscall_proc.o \ + ../../syscall_other.o ../../mm.o ../../flat.o ../../blk512.o \ + ../../tty.o ../../devsys.o ../../usermem.o ../../syscall_fs2.o \ + ../../syscall_fs3.o ../../syscall_exec32.o ../../syscall_exec.o \ + blkdev.o mbr.o 68000relocate.o \ + devsd.o devsd_discard.o \ + devch375.o devch375_discard.o \ + 68000usercopy.o ../../cpu-68000/usermem_std-68000.o devtty.o \ + libc.o ../../malloc.o ../../level2.o ../../syscall_level2.o \ + ../../select.o > ../../fuzix.map + $(CROSS_COMPILE)objcopy fuzix.elf -O binary ../../fuzix.bin + m68k-elf-objdump --disassemble -S fuzix.elf > fuzix.dis + +IMAGES = $(FUZIX_ROOT)/Images/$(TARGET) + +diskimage: + # Make a blank disk image with partition + dd if=$(FUZIX_ROOT)/Standalone/filesystem-src/parttab.40M of=$(IMAGES)/disk.img bs=40017920 conv=sync,swab + # Add the file system + dd if=$(IMAGES)/filesys.img of=$(IMAGES)/disk.img bs=512 seek=2048 conv=notrunc,swab + # Add the kernel + dd if=../../fuzix.bin of=$(IMAGES)/disk.img bs=512 seek=2 conv=notrunc,swab + # Make an emulator image of it + cat $(FUZIX_ROOT)/Standalone/filesystem-src/idehdr.40M $(IMAGES)/disk.img > $(IMAGES)/emu-ide.img diff --git a/Kernel/platform/platform-rosco-r2/README.md b/Kernel/platform/platform-rosco-r2/README.md new file mode 100644 index 0000000000..9e429bb519 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/README.md @@ -0,0 +1,151 @@ +# FUZIX Port to the Rosco r2 SBC + +Warren Toomey - 2025/02/05 + +## Introduction + +This is the port of FUZIX to the Rosco r2 m68k SBC: +https://github.com/rosco-m68k/rosco_m68k + +It's a work in progress and some things don't work well yet. + +## Building FUZIX + +You will need the toolchain described in +https://github.com/rosco-m68k/rosco_m68k/blob/develop/code/Toolchain.md + +At the top-level FUZIX directory, you can do: + +``` +make TARGET=rosco-r2 kernel # Build the kernel, which creates + # the file Kernel/fuzix.bin +make TARGET=rosco-r2 diskimage # Builds the libraries and applications, + # and then creates the filesystem image + # Images/rosco-r2/filesys.img +make TARGET=rosco-r2 kclean # Clean up the kernel build. Do this if + # you make any kernel config changes +make TARGET=rosco-r2 clean # Clean up everything +``` + +There is a shell script here called `mk_fs_img`. Once you have +`Kernel/fuzix.bin` and `Images/rosco-r2/filesys.img` you can run +this script to make the SD card image `sdcard.img` which has the +bootable kernel in partition 1 and the populated FUZIX filesystem +in partition 2. + +## Booting with an SD Card + +Copy the card image `sdcard.img` to your SD card. Under Linux I do: + +``` +cat sdcard.img > /dev/sdc; sync; sync +``` + +At boot time, the SD card should appear as `hda` with two partitions. +Use the boot device `hda2` and login as `root` with no password: + +``` +FUZIX version 0.5 +Copyright (c) 1988-2002 by H.F.Bower, D.Braun, S.Nitschke, H.Peraza +Copyright (c) 1997-2001 by Arcady Schekochikhin, Adriano C. R. da Cunha +Copyright (c) 2013-2015 Will Sowerbutts +Copyright (c) 2014-2025 Alan Cox +Devboot +Motorola 68010 processor detected. +1024KiB total RAM, 917KiB available to processes (125 processes max) +Enabling interrupts ... ok. +SD drive 0: hda: hda1 hda2 +CH375 device: not found +bootdev: hda2 +... +login: root +``` + +## Booting with the CH375 Device and a USB Drive + +If you have built the CH375 daughter board as described +[here](https://github.com/DoctorWkt/xv6-rosco-r2/tree/ch375/hardware) +then you can copy the FUZIX filesystem to a USB drive and mount it +as the root device. + +However, as the Rosco r2 SBC boots from the SD card, you need to copy +the SD card image `sdcard.img` to both your SD card and your USB drive. + +At boot time, the SD card should appear as `hdb` with two partitions. +Use the boot device `hdb2` and login as `root` with no password. + +If you have installed 1M of expansion RAM on the daughter board and closed +jumper JP4, then the kernel will see the extra RAM and report that you have +2M of RAM. + +``` +FUZIX version 0.5 +Copyright (c) 1988-2002 by H.F.Bower, D.Braun, S.Nitschke, H.Peraza +Copyright (c) 1997-2001 by Arcady Schekochikhin, Adriano C. R. da Cunha +Copyright (c) 2013-2015 Will Sowerbutts +Copyright (c) 2014-2025 Alan Cox +Devboot +Motorola 68010 processor detected. +2048KiB total RAM, 1941KiB available to processes (125 processes max) +Enabling interrupts ... ok. +SD drive 0: hda: hda1 hda2 +CH375 device: hdb: hdb1 hdb2 +bootdev: hdb2 +... +login: root +``` + +## Configuration + +Look in `config.h` for compile-time configuration defines. +`TTY_INIT_BAUD` is set for 115200 baud. `CONFIG_FLAT` means we have no MMU. +`CONFIG_SD` and `SD_DRIVE_COUNT` sets us up for one SD card. +`CONFIG_USB` supports my USB expansion board: +https://github.com/DoctorWkt/xv6-rosco-r2/tree/ch375/hardware + +This line in `fuzix.ld`: + +``` +ram (rwx) : ORIGIN = 0x2000, LENGTH = 0x100000-0x2000 +``` + +says that the kernel starts at $2000 and we have $100000 (1 Meg) of RAM. + +## Booting + +The Rosco ROM loads the kernel at address $40000. The code in `crt0.S` +copies the kernel down to $2000. Then, interrupts are enabled and the +BSS gets cleared. These functions are then called: `init_early()`, +`init_hardware()` and `fuzix_main()`. + +## Devices + +`devices.c` holds a tables of devices and associated functions. The +main ones are the block devices (0) and the tty device (2). +`device_init()` is called to probe devices and initialise them. + +## The DUART + +The code to use the XR68C681 DUART is in `devtty.c`. I have made the +`tty_setup()` function do essentially nothing. The Rosco ROM sets the +DUART up for 115200 baud. The Fuzix code then does something which +scrambles the 115200 baud setting. Until I can figure it out, I've +just disabled it. + +## The SD Card + +The kernel is configured to have SD card support. The file `p68000.S` has +assembly functions to bit-bang the SD card using the DUART: + +``` + .globl sd_spi_clock + .globl sd_spi_raise_cs + .globl sd_spi_lower_cs + .globl sd_spi_transmit_byte + .globl sd_spi_receive_byte + .globl sd_spi_transmit_sector + .globl sd_spi_receive_sector +``` + +and the high-level SD card code is in `Kernel/dev/devsd.c` and +`Kernel/dev/devsd_discard.c`. diff --git a/Kernel/platform/platform-rosco-r2/config.h b/Kernel/platform/platform-rosco-r2/config.h new file mode 100644 index 0000000000..94a454d844 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/config.h @@ -0,0 +1,63 @@ +/* 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 + +#define CONFIG_32BIT +#define CONFIG_LEVEL_2 + +#define CONFIG_MULTI +#define CONFIG_FLAT +#define CONFIG_SPLIT_ID +#define CONFIG_PARENT_FIRST +/* It's not that meaningful but we currently chunk to 512 bytes */ +#define CONFIG_BANKS (65536/512) + +#define CONFIG_LARGE_IO_DIRECT(x) 1 + +#define CONFIG_SPLIT_UDATA +#define UDATA_SIZE 1024 +#define UDATA_BLKS 2 + +#define TICKSPERSEC 100 /* Ticks per second */ + +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + /* Temp FIXME set to serial port for debug ease */ + +/* 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 TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ + +/* Could be bigger but we need to add hashing first and it's not clearly + a win with a CF card anyway */ +#define NBUFS 16 /* Number of block buffers */ +#define NMOUNTS 8 /* Number of mounts at a time */ + +#define MAX_BLKDEV 2 + +/* Block dvices */ +#define CONFIG_IDE +#define CONFIG_SD +#define SD_DRIVE_COUNT 1 +#define CONFIG_CH375 + +#define plt_copyright() + +/* Note: select() in the level 2 code will not work on this configuration + at the moment as select is limited to 16 processes. FIXME - support a + hash ELKS style for bigger systems where wakeup aliasing is cheaper */ + +#define PTABSIZE 125 +#define UFTSIZE 16 +#define OFTSIZE 160 +#define ITABSIZE 176 + +#define BOOTDEVICENAMES "hd#" + +#define TTY_INIT_BAUD B115200 diff --git a/Kernel/platform/platform-rosco-r2/crt0.S b/Kernel/platform/platform-rosco-r2/crt0.S new file mode 100644 index 0000000000..5388b32912 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/crt0.S @@ -0,0 +1,51 @@ +/* + * Need to wipe BSS etc once we figure out our preferred boot method + * + * On entry we are loaded at $40000. We copy ourselves down to $400. + * We are in supervisor mode and the rest is our problem. + */ + #include "../../cpu-68000/kernel-68000.def" + + .globl start + .globl start2 + .globl __end + .globl __bss_start + +.mri 1 + +start: + /* Position-independent code to copy from start to + * __bss_start down to $400. Code borrowed from the + * Rosco loader code. + */ +RELOC: /* position-independent load addr */ + lea.l RELOC(PC),A0 /* PC-rel source addr (load addr) */ + move.l #start,A1 /* absolute dest addr (run addr) */ + move.l #__bss_start,D0 /* init section absolute end addr */ + sub.l A1,D0 /* subtract dest addr for init length */ + lsr.l #2,D0 /* convert to long words */ + subq.l #1,D0 /* subtract 1 for dbra */ +.INIT_LOOP: + move.l (A0)+,(A1)+ /* copy long word from source to dest */ + dbra D0,.INIT_LOOP /* loop until __bss_start */ + + move.l #start2,A0 /* Use A0, otherwise the generated code */ + /* is PC-relative which we don't want. */ + jmp (A0) /* Jump to the copied start2 code */ + +start2: + or #$0700,sr + move.l #__bss_start,a0 + move.l #__end,d0 + sub.l a0,d0 + lsr.l #2,d0 +wipebss: + clr.l (a0)+ + dbra d0,wipebss + + lea udata_block0+UBLOCK_SIZE,a7 + bsr init_early + bsr init_hardware + bsr fuzix_main + or #$0700,sr +stop: bra stop diff --git a/Kernel/platform/platform-rosco-r2/devch375.c b/Kernel/platform/platform-rosco-r2/devch375.c new file mode 100644 index 0000000000..03424e99ee --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/devch375.c @@ -0,0 +1,41 @@ +/*-----------------------------------------------------------------------*/ +/* Fuzix CH375 USB block device driver */ +/* 2025 Warren Toomey */ +/* */ +/* This one is different from the one in Kernel/dev as it assumes that */ +/* the CH375 device will send interrupts. */ +/*-----------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_CH375 + +extern uint32_t ch375_read_block(uint8_t *buf, uint32_t lba); +extern uint32_t ch375_write_block(uint8_t *buf, uint32_t lba); + +uint_fast8_t devch375_transfer_sector(void) +{ + bool success; + uint32_t lba= blk_op.lba; + + /* Disable interrupts while we do the transfer */ + /* but keep IRQ5 enabled as we use it */ + irqflags_t irq = di(); + irqrestore(4); /* IRQ4 is ignored, 5 is OK */ + + if (blk_op.is_read) { + success= ch375_read_block(blk_op.addr, lba); + } else { + success= ch375_write_block(blk_op.addr, lba); + } + irqrestore(irq); + return(success); +} + +#endif diff --git a/Kernel/platform/platform-rosco-r2/devch375.h b/Kernel/platform/platform-rosco-r2/devch375.h new file mode 100644 index 0000000000..8239bee740 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/devch375.h @@ -0,0 +1,20 @@ +/* CH375 Commands */ +#define CMD_RESET_ALL 0x05 +#define CMD_SET_USB_MODE 0x15 +#define CMD_GET_STATUS 0x22 +#define CMD_RD_USB_DATA 0x28 +#define CMD_WR_USB_DATA 0x2B +#define CMD_DISK_INIT 0x51 +#define CMD_DISK_SIZE 0x53 +#define CMD_DISK_READ 0x54 +#define CMD_DISK_RD_GO 0x55 +#define CMD_DISK_WRITE 0x56 +#define CMD_DISK_WR_GO 0x57 +#define CMD_DISK_READY 0x59 + +/* CH375 Status Results */ +#define USB_INT_SUCCESS 0x14 +#define USB_INT_CONNECT 0x15 +#define USB_INT_DISCONNECT 0x16 +#define USB_INT_DISK_READ 0x1D +#define USB_INT_DISK_WRITE 0x1E diff --git a/Kernel/platform/platform-rosco-r2/devch375_discard.c b/Kernel/platform/platform-rosco-r2/devch375_discard.c new file mode 100644 index 0000000000..c881ee3124 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/devch375_discard.c @@ -0,0 +1,105 @@ +/*-----------------------------------------------------------------------*/ +/* Fuzix CH375 USB block device driver */ +/* 2025 Warren Toomey */ +/* */ +/* This one is different from the one in Kernel/dev as it assumes that */ +/* the CH375 device will send interrupts. */ +/*-----------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#define CHDATARD 0xFFF001 /* One of the CH375 registers */ + +#ifdef CONFIG_CH375 + +/****************************************************************************/ +/* Code in this file is used only once, at startup, so we want it to live */ +/* in the DISCARD segment. sdcc only allows us to specify one segment for */ +/* each source file. */ +/****************************************************************************/ + +extern uint_fast8_t devch375_transfer_sector(void); +extern int check_read_byte(void * ptr); + +void devch375_init(void) +{ + blkdev_t *blk; + uint8_t status; + uint8_t buf[8]; + int i; + + kprintf("CH375 device: "); + + /* See if there is a CH375 device attached by trying */ + /* to read from one of the registers */ + if (check_read_byte((void *)CHDATARD) == 0) { + kprintf("not found (no register)\n"); + return; + } + + /* See if the device exists */ + /* Send the reset command and wait 50mS */ + ch375_send_cmd(CMD_RESET_ALL); + cpu_delay(50); + + /* Now set the USB mode to 6. This should */ + /* cause a level 5 interrupt which will */ + /* update the CH375 status in memory. */ + ch375_send_cmd(CMD_SET_USB_MODE); + ch375_send_data(6); + + /* Get the CH375 status after a short delay. */ + /* We expect to get USB_INT_CONNECT */ + cpu_delay(50); + status= ch375_get_status_now(); + if (status != USB_INT_CONNECT) { + kprintf("not found\n"); + return; + } + + /* Allocate and set up a blk struct */ + blk = blkdev_alloc(); + if(!blk) + return; + + blk->transfer = devch375_transfer_sector; + blk->driver_data = 0; /* Unused */ + + /* Now initialise the disk. In the real world, this */ + /* might return USB_INT_DISCONNECT. In this case, */ + /* the code should prompt the user to attach a USB key */ + /* and try again. TO ADD!! */ + ch375_send_cmd(CMD_DISK_INIT); + status= ch375_get_status(); + if (status != USB_INT_SUCCESS) { + kprintf("ch375 initialisation failed!\n"); + return; + } + + /* Get the size of the attached block device */ + blk->drive_lba_count = 0; + ch375_send_cmd(CMD_DISK_SIZE); + status= ch375_get_status(); + if (status != USB_INT_SUCCESS) { + kprintf("ch375 initialisation failed!\n"); + return; + } + + /* Read eight bytes back from the CH375 */ + for (i=0; i<8; i++) + buf[i]= ch375_read_data(); + blk->drive_lba_count = (buf[0] << 24) + (buf[1] << 16) + + (buf[2] << 8) + buf[3]; + + /* Bytes 4,5,6,7 should be 0,0,2,0 indicating a block */ + /* size of 0x200 (512) */ + + blkdev_scan(blk, 0); +} + +#endif diff --git a/Kernel/platform/platform-rosco-r2/devices.c b/Kernel/platform/platform-rosco-r2/devices.c new file mode 100644 index 0000000000..4201aaa861 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/devices.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/hd Disc block devices */ + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, + /* 1: /dev/fd 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 */ + { 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 */ +}; + +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) +{ + devsd_init(); + devch375_init(); +} diff --git a/Kernel/platform/platform-rosco-r2/devtty.c b/Kernel/platform/platform-rosco-r2/devtty.c new file mode 100644 index 0000000000..23ea0605e8 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/devtty.c @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include +#include + +/* NOTE NOTE: This file comes from the Tiny68K port of + * FUZIX. I've made tty_setup() essentially empty as + * the Rosco ROM already sets up the baud rate and + * as yet I don't know why the code here misconfigures + * the UART - Warren + */ + +static unsigned char tbuf1[TTYSIZ]; +static unsigned char tbuf2[TTYSIZ]; + +#define UART_MRA 0x01 +#define UART_SRA 0x03 +#define UART_CSRA 0x03 +#define UART_CRA 0x05 +#define UART_RHRA 0x07 +#define UART_THRA 0x07 +#define UART_IPCR 0x09 +#define UART_ACR 0x09 +#define UART_ISR 0x0B +#define UART_IMR 0x0B +#define UART_CTU 0x0D +#define UART_CTUR 0x0D +#define UART_CTL 0x0F +#define UART_CTLR 0x0F +#define UART_MRB 0x11 +#define UART_SRB 0x13 +#define UART_CSRB 0x13 +#define UART_CRB 0x15 +#define UART_RHRB 0x17 +#define UART_THRB 0x17 +#define UART_IVR 0x19 +#define UART_OPCR 0x1B +#define UART_STARTCTR 0x1D +#define UART_SETOPR 0x1D +#define UART_STOPCTR 0x1F +#define UART_CLROPR 0x1F + +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}, +}; + +static uint8_t sleeping; + +tcflag_t termios_mask[NUM_DEV_TTY + 1] = { + 0, + _CSYS|CBAUD|PARENB|PARODD|CSTOPB|CSIZE|CRTSCTS, + _CSYS|CBAUD|PARENB|PARODD|CSTOPB|CSIZE|CRTSCTS, +}; + +static volatile uint8_t *uart_base = (volatile uint8_t *)0x00f00000; + +#define GETB(x) (uart_base[(x)]) +#define PUTB(x,y) uart_base[(x)] = (y) + +/* Output for the system console (kprintf etc). Polled. */ +void kputchar(uint8_t c) +{ + if (c == '\n') { + while(!(GETB(UART_SRA) & 4)); + PUTB(UART_THRA, '\r'); + } + while(!(GETB(UART_SRA) & 4)); + PUTB(UART_THRA, c); +} + +ttyready_t tty_writeready(uint8_t minor) +{ + uint8_t c = GETB(0x10 * (minor - 1) + UART_SRA); + return (c & 4) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */ +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + PUTB(0x10 * (minor - 1) + UART_THRA, c); +} + +/* We have four BRG set ups but they affect both ports together so this + is tricky stuff to do right as we need to check if we can do the wanted + rates on both ports if both open. + + The and of baudsrc of eac valid port tells us which table and BRG settings + to use. We must track the BRG as we can only toggle it not read it */ + +/* Which baud generators can generate each rate ?: + bit 0 Normal BRG ACR:7 0 + bit 1 Normal BRG ACR:7 1 + bit 2 BRG Test ACR:7 0 + (No useful extra rates on ACR:7 1 with BRG test + + If we can't achieve a rate without breaking another open port we keep the + old rate */ + +static const uint8_t baudsrc[] = { + 0x07, /* 0 is special */ + 0x01, /* 50 baud is BRG1 ACR 0 */ + 0x03, /* 70 baud is BRG1 ACR 1 */ + 0x03, /* 110 is BRG1 ACR 0 or ACR 1 */ + 0x03, /* 134 likewise */ + 0x02, /* 150 BRG1 ACR 1 only */ + 0x03, /* 300 BRG1 ACR 0 or ACR 1 */ + 0x03, /* 600 ditto */ + 0x03, /* 1200 ditto */ + 0x03, /* 2400 ditto */ + 0x07, /* 4800 is available on all */ + 0x07, /* 9600 is available on all */ + 0x06, /* 19200 is available on all but BRG1 ACR 0 */ + 0x05, /* 38400 requires ACR 0 */ + 0x04, /* 57600 requires BRG 2 */ + 0x04, /* 115200 requires BRG 2 */ +}; +/* BRG values per speed for each table */ +static const uint8_t baudset[3][16] = { + { + /* Normal BRG ACR:7 = 0 */ + 0xDD, /* 0 is special */ + 0x00, /* 50 */ + 0x00, /* Can't do 75 on the standard BRG */ + 0x11, /* 110 */ + 0x22, /* 134 */ + 0x22, /* No 150 on the standard BRG */ + 0x44, /* 300 */ + 0x55, /* 600 */ + 0x66, /* 1200 */ + 0x88, /* 2400 */ + 0x99, /* 4800 */ + 0xBB, /* 9600 */ + 0xBB, /* Can't do 19200 */ + 0xCC, /* 38400 */ + 0xCC, /* No 57600 */ + 0xCC, /* No 115200 */ + },{ + /* Normal BRG ACR:7 = 1 */ + 0xDD, /* 0 is special */ + 0x00, /* No 50 */ + 0x00, /* 75 */ + 0x11, /* 110 */ + 0x22, /* 134 */ + 0x33, /* 150 */ + 0x44, /* 300 */ + 0x55, /* 600 */ + 0x66, /* 1200 */ + 0x88, /* 2400 */ + 0x99, /* 4800 */ + 0xBB, /* 9600 */ + 0xCC, /* 19200 */ + 0xCC, /* No 38400 */ + 0xCC, /* No 57600 */ + 0xCC, /* No 115200 */ + },{ + /* BRG Test ACR:7 = 0 */ + 0xDD, /* 0 is special */ + 0x00, /* No 50 */ + 0x00, /* No 75 */ + 0x00, /* No 110 */ + 0x00, /* No 134 */ + 0x00, /* No 150 */ + 0x00, /* No 300 */ + 0x00, /* No 600 */ + 0x00, /* No 1200 */ + 0x00, /* No 2400 */ + 0x00, /* 4800 */ + 0xBB, /* 9600 */ + 0x33, /* 19200 */ + 0xCC, /* 38400 */ + 0x55, /* 57600 */ + 0x66, /* 115200 */ + } +}; + +/* FIXME: if we got to IRQ based transmit we need to lock against this + FIXME: need to drain both tx FIFOs if switching BRG ? + */ + +void tty_setup(uint8_t minor, uint8_t flags) +{ + uint8_t other = 2 - minor; + + struct termios *t = &ttydata[minor].termios; + struct tty *to = &ttydata[other]; + + uint8_t baud = t->c_cflag & CBAUD; + uint8_t r = 0; + uint8_t base = (minor - 1) * 0x10; + uint8_t table = baudsrc[baud]; + + static uint8_t oldbaud[3] = {0., B115200, B115200 }; + static uint8_t oldbrg; + + return; /* NOTE: for now. See note at the top - WKT */ + + /* If both ports are open we need to check the baud rate pair is + achievable */ + if (to->users) + table &= baudsrc[to->termios.c_cflag & CBAUD]; + + /* Clashing rates - use the old rate for this port */ + if (table == 0) { + baud = oldbaud[minor]; + table = baudsrc[baud]; + goto out; + } + + /* Favour the standard BRG set up, don't mix and match */ + if (table != 4) { + if (table & 2) { + PUTB(UART_ACR, 0xF0); + table = 2; + } else { + PUTB(UART_ACR, 0x70); + table = 1; + } + } + + + if ((table & 4) != oldbrg) { + GETB(UART_CRA); /* Toggle BRG to use */ + oldbrg = table & 4; + } + + /* Turn the mask into an actual table */ + if (table & 4) + table = 2; + else + table = (table & 2) ? 1 : 0; + + if (!(t->c_cflag & PARENB)) + r = 0x08; /* No parity */ + if (t->c_cflag & PARODD) + r |= 0x04; + /* 5-8 bits */ + r |= (t->c_cflag & CSIZE) >> 4; + if (t->c_cflag & CRTSCTS) + r |= 0x80; /* RTS control on receive */ + + /* Set pointer to MR1x */ + PUTB(base + UART_CRA, 0x10); + PUTB(base + UART_MRA, r); + + if ((t->c_cflag & CSIZE) == CS5) + r = 0x0; /* One stop for 5 bit */ + else + r = 0x07; /* One stop bit */ + if (t->c_cflag & CRTSCTS) + r |= 0x10; /* CTS check on transmit */ + if (t->c_cflag & CSTOPB) + r |= 0x08; /* Two stop bits */ + PUTB(base + UART_MRA, r); + + /* Work out the CSR for the baud: ACR is already set to 0x70 */ + oldbaud[minor] = baud; + PUTB(base + UART_CSRA, baudset[table][baud]); +out: + t->c_cflag &= ~CBAUD; + t->c_cflag |= baud; +} + +/* Not wired on this board */ +int tty_carrier(uint8_t minor) +{ + return 1; +} + +void tty_sleeping(uint8_t minor) +{ + sleeping |= 1 << minor; +} + +void tty_data_consumed(uint8_t minor) +{ +} + +static void tty_interrupt(uint8_t r) +{ + if (r & 0x02) { + r = GETB(UART_RHRA); + tty_inproc(1,r); + } + if (r & 0x01) { + if (sleeping & 2) + tty_outproc(1); + } + if (r & 0x04) + PUTB(UART_CRA, 0x50); + if (r & 0x20) { + r = GETB(UART_RHRB); + tty_inproc(2,r); + } + if (r & 0x10) { + if (sleeping & 4) + tty_outproc(2); + } + if (r & 0x40) + PUTB(UART_CRB, 0x50); +} + +void plt_interrupt(void) +{ + uint8_t r = GETB(UART_ISR); + tty_interrupt(r); + if (r & 0x08) { + /* Ack the interrupt */ + GETB(UART_STOPCTR); + timer_interrupt(); + } + /* and 0x80 is the GPIO */ +} diff --git a/Kernel/platform/platform-rosco-r2/devtty.h b/Kernel/platform/platform-rosco-r2/devtty.h new file mode 100644 index 0000000000..14c28c3172 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/devtty.h @@ -0,0 +1,10 @@ +#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]; + +#endif diff --git a/Kernel/platform/platform-rosco-r2/fuzix.export b/Kernel/platform/platform-rosco-r2/fuzix.export new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Kernel/platform/platform-rosco-r2/fuzix.ld b/Kernel/platform/platform-rosco-r2/fuzix.ld new file mode 100644 index 0000000000..890a57d9b6 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/fuzix.ld @@ -0,0 +1,87 @@ +STARTUP(crt0.o) +OUTPUT_ARCH(m68k) + +SEARCH_DIR(.) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x2000, LENGTH = 0x100000-0x2000 +} + +/* + * stick everything in ram (of course) + */ +SECTIONS +{ + .text : + { + CREATE_OBJECT_SYMBOLS + *(.text .text.*) + + . = ALIGN(0x4); + /* These are for running static constructors and destructors under ELF. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + + *(.rodata .rodata.*) + + . = ALIGN(0x4); + *(.gcc_except_table) + + . = ALIGN(0x4); + *(.eh_frame) + + . = ALIGN(0x4); + __INIT_SECTION__ = . ; + LONG (0x4e560000) /* linkw %fp,#0 */ + *(.init) + SHORT (0x4e5e) /* unlk %fp */ + SHORT (0x4e75) /* rts */ + + . = ALIGN(0x4); + __FINI_SECTION__ = . ; + LONG (0x4e560000) /* linkw %fp,#0 */ + *(.fini) + SHORT (0x4e5e) /* unlk %fp */ + SHORT (0x4e75) /* rts */ + + . = ALIGN(0x4); + _etext = .; + *(.lit) + } > ram + + .data : + { + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.*) + _edata = .; + } > ram + + .bss : + { + . = ALIGN(0x4); + __bss_start = . ; + *(.shbss) + *(.bss .bss.*) + *(COMMON) + _end = ALIGN (0x8); + __end = _end; + } > ram + + .stab 0 (NOLOAD) : + { + *(.stab) + } + + .stabstr 0 (NOLOAD) : + { + *(.stabstr) + } +} diff --git a/Kernel/platform/platform-rosco-r2/kernel.def b/Kernel/platform/platform-rosco-r2/kernel.def new file mode 100644 index 0000000000..8dc92fbcea --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/kernel.def @@ -0,0 +1,3 @@ +/* Masks for enabling and disabling interrupts */ +#define DI_MASK $700 /* or bits for DI */ +#define EI_MASK $000 /* or bits for EI */ diff --git a/Kernel/platform/platform-rosco-r2/libc.c b/Kernel/platform/platform-rosco-r2/libc.c new file mode 100644 index 0000000000..b53392c664 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/libc.c @@ -0,0 +1,52 @@ +#include + +/* FIXME: use proper fast methods */ + +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 *memcpy32(void *d, const void *s, size_t sz) +{ + uint32_t *dp = d; + const uint32_t *sp = s; + sz >>= 2; + 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; +} + +int memcmp(const void *a, const void *b, size_t n) +{ + const uint8_t *ap = a; + const uint8_t *bp = b; + while(n--) { + if (*ap < *bp) + return -1; + if (*ap != *bp) + return 1; + ap++; + bp++; + } + return 0; +} diff --git a/Kernel/platform/platform-rosco-r2/main.c b/Kernel/platform/platform-rosco-r2/main.c new file mode 100644 index 0000000000..adbf75e85e --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +uint16_t swap_dev = 0xFFFF; +uint8_t CH375_STATUS= 0; + +void do_beep(void) +{ +} + +/* + * MMU initialize + */ + +void map_init(void) +{ +} + +uaddr_t ramtop; +uint8_t need_resched; + +uint8_t plt_param(char *p) +{ + return 0; +} + +void plt_discard(void) +{ +} + +void memzero(void *p, usize_t len) +{ + memset(p, 0, len); +} + +void pagemap_init(void) +{ + /* Linker provided end of kernel */ + /* TODO: create a discard area at the end of the image and start + there */ + extern uint8_t _end; + uint32_t e = (uint32_t)&_end; + /* Allocate the rest of memory to the userspace */ + kmemaddblk((void *)e, 0xFF8000 - e); + + kprintf("Motorola 680%s%d processor detected.\n", + sysinfo.cpu[1]?"":"0",sysinfo.cpu[1]); + enable_icache(); +} + +/* Udata and kernel stacks */ +/* We need an initial kernel stack and udata so the slot for init is + set up at compile time */ +u_block udata_block0; +static u_block *udata_block[PTABSIZE] = {&udata_block0,}; + +/* This will belong in the core 68K code once finalized */ + +void install_vdso(void) +{ + extern uint8_t vdso[]; + /* Should be uput etc */ + memcpy((void *)udata.u_codebase, &vdso, 0x20); +} + +uint8_t plt_udata_set(ptptr p) +{ + u_block **up = &udata_block[p - ptab]; + if (*up == NULL) { + *up = kmalloc(sizeof(struct u_block), 0); + if (*up == NULL) + return ENOMEM; + } + p->p_udata = &(*up)->u_d; + return 0; +} diff --git a/Kernel/platform/platform-rosco-r2/mk_fs_img b/Kernel/platform/platform-rosco-r2/mk_fs_img new file mode 100755 index 0000000000..118299466e --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/mk_fs_img @@ -0,0 +1,34 @@ +#!/bin/sh +image=sdcard.img +size=36 # in Megabytes + +# Input files +kernel=../../fuzix.bin +filesys=../../../Images/rosco-r2/filesys.img + +# Make a 36M image to start with +dd if=/dev/zero of=$image bs=1M count=$size + +# Put in a partition table with an 18M FAT32 +# partition and an 18M UDF partition which +# xv6 will use. +/sbin/parted $image mklabel msdos +/sbin/parted $image mkpart primary fat32 1MB 50% +/sbin/parted $image mkpart primary udf 50% 100% +/sbin/parted $image print + +# Make the FAT32 filesystem +/sbin/mkfs.vfat -F 32 --offset=2048 $image + +# Copy the FUZIX kernel to the FAT32 partition +mcopy -i "$image"@@1M $kernel ::RosCode1.bin + +# Print out the FAT32 contents +mdir -i "$image"@@1M + +# Now copy the FAT32 filesystem to a temp file and +# append the FUZIX filesystem +dd if=$image of=temp.img bs=1M count=18 +cat $filesys >> temp.img +mv temp.img $image +echo Result is file $image diff --git a/Kernel/platform/platform-rosco-r2/p68000.S b/Kernel/platform/platform-rosco-r2/p68000.S new file mode 100644 index 0000000000..130104ab42 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/p68000.S @@ -0,0 +1,582 @@ + +#include "../../cpu-68000/kernel-68000.def" + + .globl plt_reboot + .globl init_early + .globl init_hardware + .globl program_vectors + .globl plt_idle + .globl outchar + .globl plt_monitor + .globl udata_block0 + .globl sd_spi_clock + .globl sd_spi_raise_cs + .globl sd_spi_lower_cs + .globl sd_spi_transmit_byte + .globl sd_spi_receive_byte + .globl sd_spi_transmit_sector + .globl sd_spi_receive_sector + .globl ch375_irq5_handler + .globl ch375_send_cmd + .globl ch375_send_data + .globl ch375_read_data + .globl ch375_get_status + .globl ch375_get_status_now + .globl ch375_read_block + .globl ch375_write_block + .globl cpu_delay + .globl check_read_byte + +/* Bit values for output port positions */ +SPI_CS = (1<<2) /* OP2, chip select */ +SPI_SCK = (1<<4) /* OP4, clock */ +SPI_COPI = (1<<6) /* OP6, MOSI */ + +SPI_CIPO_B = 2 /* IP2, MISO */ +SPI_CIPO = (1<<2) + +/* XR68C681 DUART registers */ +SRA = 0xF00003 /* Status register chan A, in */ +THRA = 0xF00007 /* Tx holding register A, out */ +CTUR = 0xF0000D /* Timer upper byte register, out */ +CTLR = 0xF0000F /* Timer lower byte register, out */ +IMR = 0xF0000B /* Interrupt mask register, out */ +IVR = 0xF00019 /* Interrupt vector register, out */ +IP = 0xF0001B /* Input port register */ +SOPR = 0xF0001D /* Set output port register */ +COPR = 0xF0001F /* Clear output port register */ +OUT_LO_OFFSET = SOPR - IP /* Used to keep timing correct */ +OUT_HI_OFFSET = COPR - SOPR /* Used to keep timing correct */ + +/* CH375 I/O addresses */ +CHDATARD = 0xFFF001 /* Read data byte */ +CHDATAWR = 0xFFF001 /* Write data byte */ +CHCMDWR = 0xFFF003 /* Write command byte */ + +/* CH375 Commands */ +CMD_RESET_ALL = 0x05 +CMD_SET_USB_MODE = 0x15 +CMD_GET_STATUS = 0x22 +CMD_RD_USB_DATA = 0x28 +CMD_WR_USB_DATA = 0x2B +CMD_DISK_INIT = 0x51 +CMD_DISK_SIZE = 0x53 +CMD_DISK_READ = 0x54 +CMD_DISK_RD_GO = 0x55 +CMD_DISK_WRITE = 0x56 +CMD_DISK_WR_GO = 0x57 +CMD_DISK_READY = 0x59 + +/* CH375 Status Results */ +USB_INT_SUCCESS = 0x14 +USB_INT_CONNECT = 0x15 +USB_INT_DISCONNECT = 0x16 +USB_INT_DISK_READ = 0x1D +USB_INT_DISK_WRITE = 0x1E + +/* Address of the IRQ5 and clock tick vector */ +IRQ5_VECTOR = 0x74 +TICK_VECTOR = 0x114 + +.mri 1 +plt_monitor: +plt_reboot: + or #$0700,sr ; Disable interrupts + bra plt_monitor ; and loop infinitely + +init_early: + lea.l udata_block0,a5 ; udata ptr + move.l a5,udata_shadow ; shadow copy for entry/exit + rts + +plt_idle: + stop #($2000+EI_MASK) + rts + +init_hardware: + ; See if there is any RAM above 1M + move.l #$100000,sp@- + bsr check_read_byte + addq.l #4,sp + tst.l d0 + beq .only1M + move.w #2048,d0 ; Yes, assume 2M of RAM + bra kernelmem +.only1M: move.w #1024,d0 ; No, only 1M of RAM + +kernelmem: + move.w d0,ramsize + move.l #_end+512,d1 + + lsr.l #8,d1 + lsr.l #2,d1 + sub.w d1,d0 ; Guess for kernel + move.w d0,procmem ; guesses for now + + bsr install_vectors + + /* Connect the timer and CH375 interrupt handlers */ + move.l #timer_irq,TICK_VECTOR + move.l #ch375_irq5_handler,IRQ5_VECTOR + + move.b #$80,CTLR + move.b #$4,CTUR + move.b #$45,IVR + move.b #$2A,IMR + rts + +timer_irq: + ; C will save and restore a2+/d2+ + movem.l a0-a1/a5/d0-d1,-(sp) + move.l udata_shadow,a5 ; set up the register global + move.b #1,U_DATA__U_ININTERRUPT(a5) + jsr plt_interrupt + clr.b U_DATA__U_ININTERRUPT(a5) + + tst.b U_DATA__U_INSYS(a5) + bne no_preempt + tst.b need_resched + beq no_preempt + ; + ; Vanish into the scheduler. Some other task will pop back out + ; and eventually we'll re-appear here and continue. + ; + ; FIXME: check IRQ masking + ; + move.l U_DATA__U_PTAB(a5),a0 + ; We might be in STOPPED state in which case do not go back + ; to ready ! + cmp.b #P_RUNNING,P_TAB__P_STATUS_OFFSET(a0) + bne no_ready + move.b #P_READY,P_TAB__P_STATUS_OFFSET(a0) + ori.b #PFL_BATCH,P_TAB__P_FLAGS_OFFSET(a0) +no_ready: + bsr switchout +no_preempt: + tst.b U_DATA__U_CURSIG(a5) + beq no_signal + ; FIXME: this is ugly + movem.l (sp)+,a0-a1/a5/d0-d1 + move.w sr,-(sp) + move.w #0,-(sp) + movem.l a0-a6/d0-d7,-(sp) + move.l (sp),-(sp) + bsr exception + addq #4,sp + movem.l (sp)+,a0-a6/d0-d7 + addq #4,sp + rte +no_signal: + movem.l (sp)+,a0-a1/a5/d0-d1 + rte + +; +; Nothing to do in 68000 - all set up once at boot +; +program_vectors: + rts + +; +; We do no banking so we need to do nothing here. +; +map_process_always: +map_process: +map_kernel: +map_restore: +map_save: + rts + +; outchar: Wait for UART TX idle, then print the char in d0 + +outchar: +outcharw: + btst #2,SRA + beq outcharw + move.b d0,THRA + rts + +; +; SD via SPI +; +sd_spi_clock: + rts +sd_spi_raise_cs: + move.b #SPI_CS,COPR + rts +sd_spi_lower_cs: + move.b #SPI_CS,SOPR + rts + +/* This code borrowed from Rosco r2 blockdev/dua_spi_asm.asm */ +sd_spi_transmit_byte: + move.b 4+3(sp),d0 /* 12 d0 = send byte */ + movem.l d2-d5,-(a7) /* 12+32 save regs */ + move.l #SOPR,a0 /* 12 a0 = output LO */ + lea.l OUT_HI_OFFSET(a0),a1 /* 8 a1 = output HI */ + moveq.l #SPI_SCK,d1 /* 4 d1 = SCK bit mask */ + moveq.l #SPI_COPI,d2 /* 4 d2 = COPI bit mask */ + moveq.l #SPI_SCK,d3 /* 4 d3 = SCK|COPI bit mask */ + or.l #SPI_COPI,d3 + /* d4 = temp (COPI LO) */ + /* d5 = temp (COPI HI) */ + rept 8 +/* send bits 7...0 */ + add.b d0,d0 /* 4 shift MSB to carry */ + scs d5 /* 4/6 temp set to 0 or 0xff based on carry */ + and.b d2,d5 /* 4 isolate COPI HI bit to output */ + move.b d5,d4 /* 4 copy COPI HI bit */ + eor.b d3,d4 /* 4 set SCK LO and invert COPI for LO bit */ + move.b d4,(a0) /* 8 output SCK LO and COPI LO (if send bit LO) */ + move.b d5,(a1) /* 8 output COPI HI (if send bit HI) */ + move.b d1,(a1) /* 8 output SCK HI */ + endr + + movem.l (a7)+,d2-d5 /* 12+32 restore regs */ +spi_sb_rts: rts + +sd_spi_receive_byte: + movem.l d2-d3/a2,-(a7) /* 12+24 save regs */ + move.l #IP,a0 /* 12 a0 = input */ + lea.l OUT_LO_OFFSET(a0),a1 /* 8 a1 = output LO */ + lea.l OUT_HI_OFFSET(a1),a2 /* 8 a2 = output HI */ + moveq.l #SPI_SCK,d1 /* 4 d1 = SCK bit mask */ + moveq.l #SPI_CIPO_B,d2 /* 4 d2 = CIPO bit number */ + /* d3 = temp */ + +/* read bit 7 */ + moveq.l #0,d0 /* 4 clear read byte */ + move.b d1,(a1) /* 8 output SCK LO */ + btst.b d2,(a0) /* 8 test input CIPO bit */ + sne d3 /* 4/6 temp set to 0 or 0xff based on CIPO bit */ + sub.b d3,d0 /* 4 set low bit of read byte by subtracting 0 or -1 */ + move.b d1,(a2) /* 8 output SCK HI */ + + rept 7 +/* read bits 6...0 */ + add.b d0,d0 /* 4 shift read byte left */ + move.b d1,(a1) /* 8 output SCK LO */ + btst.b d2,(a0) /* 8 test input CIPO bit */ + sne d3 /* 4/6 temp set to 0 or 0xff based on CIPO bit */ + sub.b d3,d0 /* 4 set low bit of read byte by subtracting 0 or -1 */ + move.b d1,(a2) /* 8 output SCK HI */ + endr + movem.l (a7)+,d2-d3/a2 /* 12+24 restore regs */ + /* d0 = result read byte */ +spi_rb_rts: rts + +sd_spi_receive_sector: + move.w #512,d0 + /* Get the argument - address of buffer */ + /* As we are a flat system we don't have to worry about */ + /* kernel v user etc */ + move.l blk_op,a0 /* 12 load data buffer */ + movem.l d2-d4/a2-a3,-(a7) /*12+40 save regs */ + move.l #IP,a1 /* 12 a1 = input */ + lea.l OUT_LO_OFFSET(a1),a2 /* 8 a2 = output LO */ + lea.l OUT_HI_OFFSET(a2),a3 /* 8 a3 = output HI */ + moveq.l #SPI_SCK,d1 /* 4 d1 = SCK bit mask */ + moveq.l #SPI_CIPO_B,d2 /* 4 d2 = CIPO bit num */ + /* d3 = temp bit */ + /* d4 = temp byte */ + +.spi_rb_loop: + rept 8 +/* read bits 7...0 */ + add.b d4,d4 /* 4 shift read byte left */ + move.b d1,(a2) /* 8 set SCK LO */ + btst.b d2,(a1) /* 8 read input CIPO bit */ + sne d3 /* 4/6 d3 = 0 or -1 */ + sub.b d3,d4 /* 4 set low bit of read byte */ + move.b d1,(a3) /* 8 set SCK HI */ + endr + + move.b d4,(a0)+ /* 8 save read byte */ + subq.l #1,d0 /* 8 decrement count */ + bne.s .spi_rb_loop /* 8/10 loop if not zero */ + +.spi_rb_done: + movem.l (a7)+,d2-d4/a2-a3 /* 12+40 restore regs */ + rts + +sd_spi_transmit_sector: + move.w #512,d0 + move.l blk_op,a0 /* 12 load data buffer */ + movem.l d2-d6/a2,-(a7) /* 12+48 save regs */ + move.l #SOPR,a1 /* 12 a1 = output LO */ + lea.l OUT_HI_OFFSET(a1),a2 /* 8 a2 = output HI */ + moveq.l #SPI_SCK,d2 /* 4 d2 = SCK bit mask */ + moveq.l #SPI_COPI,d3 /* 4 d3 = COPI bit mask */ + moveq.l #SPI_SCK,d4 /* 4 d4 = SCK|COPI bit mask */ + or.l #SPI_COPI,d4 + /* d5 = temp COPI LO */ + /* d6 = temp COPI HI */ + +.spi_sb_loop: + move.b (a0)+,d1 /* 8 load send byte */ + + rept 8 +/* send bits 7...0 */ + add.b d1,d1 /* 4 shift MSB to carry */ + scs d6 /* 4/6 temp set to 0 or 0xff based on carry */ + and.b d3,d6 /* 4 isolate COPI HI bit to output */ + move.b d6,d5 /* 4 copy COPI HI bit */ + eor.b d4,d5 /* 4 set SCK LO and invert COPI for LO bit */ + move.b d5,(a1) /* 8 output SCK LO and COPI LO (if send bit LO) */ + move.b d6,(a2) /* 8 output COPI HI (if send bit HI) */ + move.b d2,(a2) /* 8 output SCK HI */ + endr + + subq.l #1,d0 + bne .spi_sb_loop + +.spi_sb_done: + movem.l (a7)+,d2-d6/a2 /* 12+48 restore regs */ + rts + +/* CH375 code */ + +/* + * This is the interrupt handler for the CH375. + * Send a CMD_GET_STATUS to the device, + * read a byte of data and save it in the + * CH375_STATUS location. + */ +ch375_irq5_handler: + move.b #CMD_GET_STATUS,CHCMDWR + move.b CHDATARD,CH375_STATUS + rte + +/* + * Write the given command to the CH375. + * Clear the CH375_STATUS beforehand by + * putting a dummy value there. + */ +ch375_send_cmd: + move.b #$FF,CH375_STATUS + move.b 7(A7),D0 + move.b D0,CHCMDWR + rts + +/* Write the given data to the CH375. */ +ch375_send_data: + move.b 7(A7),D0 + move.b D0,CHDATAWR + rts + +/* Read data from the CH375 */ +ch375_read_data: + move.b CHDATARD,D0 + rts + +/* + * Get the CH375 status from the + * CH375_STATUS memory location. + * Loop until it is not $FF + */ +ch375_get_status: + move.b CH375_STATUS,D0 + cmpi.b #$FF,D0 + beq ch375_get_status + rts + +/* As above but don't loop */ +ch375_get_status_now: + move.b CH375_STATUS,D0 + rts + +/* + * Given a pointer to a 512-byte buffer and an + * LBA number, read the block from the CH375 into + * the buffer. Return 1 on success, 0 otherwise. + * + * uint32_t ch375_read_block(uint8_t *buf, uint32_t lba) + */ +ch375_read_block: + + /* Check that buf isn't NULL */ + movea.l 4(SP),A0 + cmp.l #0,4(SP) + beq.w ch375_readfail + + /* Send the disk read command followed by the LBA */ + /* in little-endian format, then ask for one block. */ + move.b #$FF,CH375_STATUS + move.b #CMD_DISK_READ,CHCMDWR + move.b 11(SP),CHDATAWR + move.b 10(SP),CHDATAWR + move.b 9(SP),CHDATAWR + move.b 8(SP),CHDATAWR + move.b #1,CHDATAWR + + /* Loop eight times reading in */ + /* 64 bytes of data each time. */ + moveq.l #8,D1 +CH375_READL1: + + /* Get the status, ensure that */ + /* it is USB_INT_DISK_READ */ + jsr ch375_get_status + cmpi.b #USB_INT_DISK_READ,D0 + bne.s ch375_readfail + + /* Send the command to read the data, */ + /* get back the number of bytes to read. */ + /* Divide it by eight to match the loop */ + /* unrolling below (this assumes the count */ + /* is a multiple of eight). */ + move.b #$FF,CH375_STATUS + move.b #CMD_RD_USB_DATA,CHCMDWR + clr.l D0 + move.b CHDATARD,D0 + lsr.l #3,D0 + + /* Loop cnt times reading data */ +CH375_READL2: + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + move.b CHDATARD,(A0)+ + subi.l #1,D0 + bne.s CH375_READL2 + + /* After cnt bytes, tell the CH375 */ + /* to get the next set of data */ + /* and loop back */ + move.b #$FF,CH375_STATUS + move.b #CMD_DISK_RD_GO,CHCMDWR + subi.l #1,D1 + bne.s CH375_READL1 + + /* Get the status after reading the block */ + jsr ch375_get_status + cmpi.b #USB_INT_SUCCESS,D0 + bne.s ch375_readfail + + /* Return 1 on success, 0 on failure */ +ch375_readok: + moveq.l #1,d0 + rts + +ch375_readfail: + moveq.l #0,d0 + rts + +/* + * Given a pointer to a 512-byte buffer and an + * LBA number, write the block from the buffer + * to the CH375. Return 1 on success, 0 otherwise. + * + * uint32_t ch375_write_block(uint8_t *buf, uint32_t lba) + */ +ch375_write_block: + + /* Check that buf isn't NULL */ + movea.l 4(SP),A0 + cmp.l #0,4(SP) + beq.w ch375_writefail + + /* Send the disk write command followed by the LBA in */ + /* little-endian format, then ask to send one block. */ + move.b #$FF,CH375_STATUS + move.b #CMD_DISK_WRITE,CHCMDWR + move.b 11(SP),CHDATAWR + move.b 10(SP),CHDATAWR + move.b 9(SP),CHDATAWR + move.b 8(SP),CHDATAWR + move.b #1,CHDATAWR + + /* Loop eight times writing out */ + /* 64 bytes of data each time. */ + moveq.l #8,D1 +CH375_WRITEL1: + + /* Get the status, ensure that */ + /* it is USB_INT_DISK_WRITE */ + jsr ch375_get_status + cmpi.b #USB_INT_DISK_WRITE,D0 + bne.s ch375_writefail + + /* Send the command to write the data */ + /* along with the count. Then set D0 */ + /* to 8 for the loop: it really is 64 */ + /* but we do loop unrolling. */ + move.b #$FF,CH375_STATUS + move.b #CMD_WR_USB_DATA,CHCMDWR + move.b #64,CHDATAWR + moveq.l #8,D0 + + /* Loop 8 times writing data */ +CH375_WRITEL2: + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + move.b (A0)+,CHDATAWR + subi.l #1,D0 + bne.s CH375_WRITEL2 + + /* After 64 bytes, tell the CH375 to */ + /* get ready for the next set of data */ + /* and loop back */ + move.b #$FF,CH375_STATUS + move.b #CMD_DISK_WR_GO,CHCMDWR + subi.l #1,D1 + bne.s CH375_WRITEL1 + + /* Get the status after writing the block */ + jsr ch375_get_status + cmpi.b #USB_INT_SUCCESS,D0 + bne.s ch375_writefail + + /* Return 1 on success, 0 on failure */ +ch375_writeok: + moveq.l #1,d0 + rts + +ch375_writefail: + moveq.l #0,d0 + rts + +/* This comes from xosera_m68k_api.c. */ +/* Delay for D0 milliseconds */ +/* Assumes CPU running at 10MHz */ +cpu_delay: + move.l 4(A7),D0 + lsl.l #8,D0 + add.l D0,D0 +L1: subq.l #1,D0 + tst.l D0 + bne.s L1 + rts + +/* This comes from EmuTOS */ +/* check_read_byte: verify access to memory */ +/* pointed to by the given ptr. Callable from C: */ +/* int check_read_byte(void *ptr) */ +check_read_byte: + move.l sp,d1 + move.l (8),a1 /* Get the current bus error vector */ + lea berr(pc),a0 /* Replace it with berr */ + move.l a0,(8) + moveq #0,d0 /* Assume we will fail */ + nop + + move.l 4(sp),a0 /* Get the address to test */ + tst.b (a0) /* Try to access it - this may cause */ + /* a bus error and we would jump to berr */ + nop /* Flush the CPU's pipeline */ + + moveq #1,d0 /* We passed with no bus error */ + +berr: + move.l a1,(8) /* Restore the bus error vector */ + move.l d1,sp /* Reset the stack pointer */ + nop + rts /* and return from the bus error */ diff --git a/Kernel/platform/platform-rosco-r2/target.mk b/Kernel/platform/platform-rosco-r2/target.mk new file mode 100644 index 0000000000..8ed8052528 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/target.mk @@ -0,0 +1,2 @@ +export CPU = 68000 +export ENDIANFLAG = "-X" diff --git a/Kernel/platform/platform-rosco-r2/tricks.S b/Kernel/platform/platform-rosco-r2/tricks.S new file mode 100644 index 0000000000..db81fc5512 --- /dev/null +++ b/Kernel/platform/platform-rosco-r2/tricks.S @@ -0,0 +1,3 @@ +#include "../../cpu-68000/kernel-68000.def" + +#include "../../lib/68000flat.S"