From: Alan Cox Date: Sat, 17 Feb 2018 22:39:13 +0000 (+0000) Subject: pdp11: more platform updating X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=890a869722fadad993aa8d46f1a9412d2da186c4;p=FUZIX.git pdp11: more platform updating Not yet a complete usable machine --- diff --git a/Kernel/platform-pdp11/Makefile b/Kernel/platform-pdp11/Makefile index 40344ae8..b4d1d83a 100644 --- a/Kernel/platform-pdp11/Makefile +++ b/Kernel/platform-pdp11/Makefile @@ -39,3 +39,7 @@ image: tricks.o ../syscall_fs3.o \ ../usermem_std-pdp11.o devtty.o libc.o > ../fuzix.map pdp11-aout-objcopy fuzix.aout -O binary ../fuzix.bin + + pdp11-aout-as boot-rx0.s -o boot-rx0.o + pdp11-aout-ld boot-rx0.o -o boot-rx0.aout + pdp11-aout-objcopy boot-rx0.aout -O binary boot-rx0 diff --git a/Kernel/platform-pdp11/README b/Kernel/platform-pdp11/README index f5149803..9ee34d56 100644 --- a/Kernel/platform-pdp11/README +++ b/Kernel/platform-pdp11/README @@ -4,3 +4,15 @@ breaks. Once it all builds and the syscall and some minimal driver code is filled in it ought to come in at about 20KW for a pure swap based system so probably not useful on an MMUless /11 except for testing. + +Boot notes: + start block with nop apparently sometimes needed + Generally first block, but on rx appears to be first sector of track 1 + (not 0 as expected) + +Boot logic: + Load inode 1 (hardcoded offset) + Walk direct link blocks looking for /bootstrap + Load only direct blocks of the referenced inode + + Run /bootstrap diff --git a/Kernel/platform-pdp11/boot-rx0.s b/Kernel/platform-pdp11/boot-rx0.s new file mode 100644 index 00000000..1d4256d3 --- /dev/null +++ b/Kernel/platform-pdp11/boot-rx0.s @@ -0,0 +1,61 @@ +/* + * Boot off an RX0. + */ + +start: + nop + mov $hello,r0 +loop: + movb 0177564,r2 + bpl loop + movb (r0)+,r1 + beq done + movb r1,0177566 + br loop +done: + jsr pc, donereq + mov $0x200,r0 + movb $111, r1 // 111 blocks is our 56K + mov $0177170,r2 // controller base + movb $1,r3 // sector + movb $2,r4 // track +next: + movb $0x07,(r2) + jsr pc, txwait + movb r3,2(r2) + jsr pc, txwait + movb r4,2(r2) + jsr pc, donereq + + movb $0x80,r5 + movb $0x03,(r2) +load: + tstb (r2) + bpl load + movb 2(r2),(r0)+ + dec r5 + bne load + + dec r1 + beq _finished + inc r3 + cmp $27,r3 + bne next + movb $1,r3 + inc r4 + br done + +donereq: + bis $0x20,(r2) + beq donereq + rts pc + +txwait: + tstb (r2) + bpl txwait + rts pc + +_finished: + jmp 0x200 + +hello: .asciz "Loading Fuzix..." diff --git a/Kernel/platform-pdp11/config.h b/Kernel/platform-pdp11/config.h index 10e8889c..9ffee1ab 100644 --- a/Kernel/platform-pdp11/config.h +++ b/Kernel/platform-pdp11/config.h @@ -38,5 +38,5 @@ /* Device parameters */ #define NUM_DEV_TTY 1 #define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ -#define NBUFS 6 /* Number of block buffers */ +#define NBUFS 5 /* Number of block buffers */ #define NMOUNTS 2 /* Number of mounts at a time */ diff --git a/Kernel/platform-pdp11/dev_rk.c b/Kernel/platform-pdp11/dev_rk.c new file mode 100644 index 00000000..cdb11d62 --- /dev/null +++ b/Kernel/platform-pdp11/dev_rk.c @@ -0,0 +1,139 @@ +/* + * PDP/11 RK05 cartridge driver + * We assume RK05 packs for PDP/11 the moment (2/202/12 geometry) + * + * Also assumed is one unit. But that's easily fixed + */ + +#include +#include +#include +#include + +static uint16_t *rkds = (uint16_t *)0177400; +static uint16_t *rker = (uint16_t *)0177402; +static uint16_t *rkcs = (uint16_t *)0177404; +static uint16_t *rkwc = (uint16_t *)0177406; +static uint16_t *rkba = (uint16_t *)0177410; +static uint16_t *rkda = (uint16_t *)0177412; + +static int rk_probe(uint8_t minor) +{ + /* FIXME: timeout ?? */ + while(!(*rkcs & 0x80)); + *rkda = minor << 12; + *rkcs = 0x0B; /* Drive reset, go */ + while(!(*rkcs & 0x80)); + /* Now check the drive status */ + if (!(*rkds & 0x80)) + return 0; + if (*rkds & 0x20) + return 3; + return 1; +} + +static int rk_transfer(bool is_read, uint8_t minor, uint8_t rawflag) +{ + uint16_t ct = 0; + uint16_t st; + uint16_t *page = NULL; + uint8_t cmd = is_read ? 4 : 2; + + if (rk_offline & (1 << minor)) { + udata.u_error = EIO; + return -1; + } + if(rawflag == 1) { + if (d_blkoff(9)) + return -1; + page = &udata.u_page; +#ifdef SWAPDEV + } else if (rawflag == 2) { /* Swap device special */ + page = &swappage; /* Acting on this page */ +#endif + } else { /* rawflag == 0 */ + } + + + /* We don't try and merge linearly sequential writes but these are so rare + (mkfs basically) even without vm.. We may want to reconsider for swap + however */ + /* Overlapped seek is also supported but we can't really use it */ + + while (ct < udata.u_nblock) { + /* It's not quite as simple as it seems because while there is a single + disk address register it's up to use to set the bits properly for + sectors, suface, cylinder, drive */ + uint16_t darv = minor << 13; + uint8_t sector; + uint8_t surface = 0x00; + uint16_t cylinder; + + /* Assume a PDP/11 catridge not a PDP/8 one */ + sector = udata.u_block % 12; + cylinder = udata.u_block /12; + /* Check this logic: there are spare tracks but are they hard/soft + spared ? */ + if (cylinder > 202) { + cylinder -= 202; + surface = 0x10; + } + darv |= sector | surface + darv |= (cylinder << 5); + + /* Wait until ready */ + while(!(*rkcd & 0x80)); + + /* Load the target, addresses and command */ + *rkda = darv; + *rkwc = -256; /* 512 bytes for now */ + *rkba = udata.u_dptr; + *rkcs = cmd | 1; /* Needs top bits of VA when we do virtual */ + + while(!(*rkcd & 0x80)); + + st = *rker; + if (st) { + kprintf("fd%d: block %d, error %x/%x\n", minor, udata.u_block, st, + *rkds); + if (st & 0xFFF0) + rk_offline |= (1 << minor); + break; + } + udata.u_block++; + ct++; + udata.u_dptr += 512; + } + return ct << 9; +} + +/* For now assume a single controller, max 8 packs, no partitioning support */ + +int rk_open(uint8_t minor, uint16_t flag) +{ + flag; + uint8_t r; + /* No such drive or drive not loaded */ + if(minor >= 8 || !(r = rk_probe(minor))) { + udata.u_error = ENODEV; + return -1; + } + /* Read only media */ + if ((r & 2) && O_ACCMODE(flag)) { + udata.u_error = EROFS; + return -1; + } + return 0; +} + +int rk_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return rk_transfer(true, minor + 8, rawflag); +} + +int rk_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return rk_transfer(false, minor + 8, rawflag); +} diff --git a/Kernel/platform-pdp11/dev_rx.c b/Kernel/platform-pdp11/dev_rx.c new file mode 100644 index 00000000..577e5529 --- /dev/null +++ b/Kernel/platform-pdp11/dev_rx.c @@ -0,0 +1,178 @@ +/* + * Driver for an RX floppy disk controller + * + * 77 track, 26 sector per track, 128 byte per sector floppy + * + * Usually lives at 17170/2 (command/status at 0 data at 2) + * + * See "RX8/RX11 Floppy Disk System User's Manual EK-RX01-OP-001" + */ + +#include +#include +#include + +#define GO 0x01 + +#define CMD_FILL 0x00 +#define CMD_EMPTY 0x02 +#define CMD_WRITE 0x04 +#define CMD_READ 0x06 +#define CMD_READSTAT 0x08 +#define CMD_FORMAT 0x0A /* Set density (later models only) */ +#define CMD_WRITEDEL 0x0C +#define CMD_READERROR 0x0E + +#define DRIVE_B 0x10 +#define DONE 0x20 +#define INTEN 0x40 +#define XFERRQ 0x80 +#define INTIALIZE 0x4000 +#define ERROR 0x8000 + +static uint16_t *dev = (uint16_t *)0177170; +static uint8_t drive; +static uint8_t track; +static uint8_t sector; + +static void issue_read(void) +{ + uint8_t x; + uint8_t ct = 0; + /* Might want timeouts here */ + + /* Wait for it to stop being busy */ + while(!(*dev & DONE)); + *dev = CMD_READ|GO|drive; /* READ|GO|DRIVE_B etc */ + while(!(*dev & XFERRQ)); + dev[1] = sector; /* When ready send the sector */ + while(!(*dev & XFERRQ)); + dev[1] = track; /* And the track */ + + /* The controller will no go off and get the sector */ + while(!(*dev & DONE)); + + /* Now read the buffer */ + *dev = CMD_EMPTY|GO; /* Ready for xfer */ + while(ct < 128) { + x = *dev; + if (x & XFERRQ) { + *udata.u_dptr++ = dev[1]; /* Store byte */ + ct++: + } + /* An early done means an error */ + if (x & DONE) + break; /* Error */ + } + return dev[1]; /* Error bits */ +} + +static void issue_write(void) +{ + uint8_t x; + uint8_t ct = 0; + while(!(*dev & DONE)); /* Make sure we are not busy */ + + /* We need to fill the buffer */ + *dev = CMD_FILL|GO; /* Ready for xfer */ + while(ct < 128) { + x = *dev; + if (x & 0x80) { /* Failure */ + dev[1] = *udata.u_dptr+; /* Store byte */ + ct++: + } + if (x & DONE) + break; /* Error */ + } + /* Error in xfer ? */ + if (dev[0] & (1 << 15))) + return dev[1]; + /* Now we have copied the buffer into the controller we issue an I/O */ + *dev = CMD_WRITE|GO|drive; /* READ|GO|DRIVE_B etc */ + while(!(*dev & XFERRQ)); + dev[1] = sector; + while(!(*dev & XFERRQ)); + dev[1] = track; + + /* Wait for the write to complete or error */ + while(!(*dev & DONE)); + return dev[1]; /* Error bits */ +} + +static int probe_drive(void) +{ + while(!(*dev & DONE)); + *dev = CMD_READSTAT|GO|drive; + while(!(*dev & DONE)); + return (*dev & 0x80); +} + +static int rx_transfer(uint8_t minor, bool is_read, uint8_t rawflag) +{ + int ct = 0; + int tries; + uint8_t err = 0; + uint16_t ptr; + + if(rawflag == 2) + goto bad2; + + rx_map = rawflag; + if (rawflag && d_blkoff(BLKSHIFT)) + return -1; + + /* In 128's */ + udata.u_nblock *= 4; + udata.u_block *= 4; + + drive = (minor & 1) ? DRIVE_B : 0; + + while (ct < udata.u_nblock) { + track = udata.u_block /26; + sector = (udata.u_block % 26) + 1; + for (tries = 0; tries < 4 ; tries++) { + ptr = udata.u_dptr; + err = (is_read ? issue_read : issue_write)(dev)) + if (err == 0) + break; + udata.u_dptr = ptr; + if (tries > 1) + rx_reset(driveptr); + } + /* FIXME: should we try the other half and then bale out ? */ + if (tries == 4) + goto bad; + ct++; + udata.u_block++; + } + return ct << 7; +bad: + kprintf("rx%d: error %x\n", minor, err); +bad2: + udata.u_error = EIO; + return -1; +} + +int rx_open(uint8_t minor, uint16_t flag) +{ + flag; + drive = (minor & 1) ? DRIVE_B : 0; + if(minor >= MAX_FD || !probe_drive()) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} + +int rx_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return rx_transfer(minor, true, rawflag); +} + +int rx_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag;rawflag;minor; + return rx_transfer(minor, false, rawflag); +} + \ No newline at end of file diff --git a/Kernel/platform-pdp11/devtty.c b/Kernel/platform-pdp11/devtty.c index 3954fa8c..eb00d3aa 100644 --- a/Kernel/platform-pdp11/devtty.c +++ b/Kernel/platform-pdp11/devtty.c @@ -6,8 +6,10 @@ #include #include -volatile uint8_t *uart_data = (volatile uint8_t *)0xF03000; /* UART data */ -volatile uint8_t *uart_status = (volatile uint8_t *)0xF03010; /* UART status */ +volatile uint16_t *uart_rxstatus = (volatile uint16_t *)0177560; +volatile uint8_t *uart_rxdata = (volatile uint8_t *)0177562; +volatile uint8_t *uart_txstatus = (volatile uint8_t *)0177564; +volatile uint8_t *uart_txdata = (volatile uint8_t *)0177566; unsigned char tbuf1[TTYSIZ]; @@ -26,13 +28,14 @@ void kputchar(char c) ttyready_t tty_writeready(uint8_t minor) { - uint8_t c = *uart_status; - return (c & 2) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */ + uint8_t c = *uart_txstatus; + return (c & 0x80) ? TTY_READY_NOW : TTY_READY_SOON; } void tty_putc(uint8_t minor, unsigned char c) { - *uart_data = c; /* Data */ + /* Just the console for now */ + *uart_txdata = c; } void tty_setup(uint8_t minor) @@ -51,9 +54,9 @@ void tty_sleeping(uint8_t minor) /* Currently run off the timer */ void tty_interrupt(void) { - uint8_t r = *uart_status; - if (r & 1) { - r = *uart_data; + uint8_t r = *uart_rxstatus; + if (r & 0x80) { + r = *uart_rxdata; tty_inproc(1,r); } }