From: Aaron Taylor Date: Mon, 11 Jan 2021 06:22:01 +0000 (-0800) Subject: Imported slu/mmu/interrupt/register code from WIP memtester program into C template. X-Git-Url: http://git.subgeniuskitty.com/pdp11-modern-c/.git/commitdiff_plain/202004d54803c861f7fbaa9169eaad750c63f7cf Imported slu/mmu/interrupt/register code from WIP memtester program into C template. --- diff --git a/Makefile b/Makefile index 51c8869..f4a8632 100644 --- a/Makefile +++ b/Makefile @@ -33,9 +33,6 @@ PDP_LOAD = bin2pdp SIMH_CMD = pdp11 SIMH_CFG = simh.conf -# List of all source files in PDP-11 library. -PDPLIB_SRC != ls pdp11/*.c - #################################################################################################### # Targets @@ -44,14 +41,19 @@ all: aout aout: $(AS) $(AS_FLAGS) -o init.o init.s - $(CC) $(CC_FLAGS) -o pdp11.o $(PDPLIB_SRC) + $(AS) $(AS_FLAGS) -o pdp11_inthandler.o pdp11/interrupt_handler.s + $(CC) $(CC_FLAGS) -o pdp11_interrupt.o pdp11/pdp11_interrupt.c + $(CC) $(CC_FLAGS) -o pdp11_slu.o pdp11/pdp11_slu.c + $(CC) $(CC_FLAGS) -o pdp11_mmu.o pdp11/pdp11_mmu.c + $(CC) $(CC_FLAGS) -o pdp11.o pdp11/pdp11.c ############################################## # Insert your program's build commands here. # $(CC) $(CC_FLAGS) -o hello.o hello.c ############################################## - $(LD) $(LD_FLAGS) init.o pdp11.o hello.o -o program.out + $(LD) $(LD_FLAGS) init.o pdp11_inthandler.o pdp11_interrupt.o pdp11_slu.o pdp11_mmu.o pdp11.o \ + hello.o -o program.out clean: @rm -rf *.o *.out *.pdp11 *.bin *.core diff --git a/pdp11/interrupt_handler.s b/pdp11/interrupt_handler.s new file mode 100644 index 0000000..970363b --- /dev/null +++ b/pdp11/interrupt_handler.s @@ -0,0 +1,24 @@ +# (c) 2020 Aaron Taylor +# See License.txt file for copyright and license details. + +.globl _int4_asm_handler +.globl _int4_c_handler + +_int4_asm_handler: + # GCC appears to be using the same calling convention documented in the + # original UNIX manuals. Most of these register saves are probably + # unnecessary. + mov r0,-(sp) + mov r1,-(sp) + mov r2,-(sp) + mov r3,-(sp) + mov r4,-(sp) + mov r5,-(sp) + jsr pc, _int4_c_handler + mov (sp)+,r5 + mov (sp)+,r4 + mov (sp)+,r3 + mov (sp)+,r2 + mov (sp)+,r1 + mov (sp)+,r0 + rti diff --git a/pdp11/pdp11.c b/pdp11/pdp11.c index f92bad5..edfd4fa 100644 --- a/pdp11/pdp11.c +++ b/pdp11/pdp11.c @@ -3,33 +3,6 @@ #include -/* - * Polled console I/O - */ - -#define RCSR (*((volatile uint16_t *)0177560)) -#define RBUF (*((volatile uint16_t *)0177562)) -#define XCSR (*((volatile uint16_t *)0177564)) -#define XBUF (*((volatile uint16_t *)0177566)) - -void -putch(uint16_t c) -{ - while((XCSR && 0200) == 0) continue; - XBUF = c; -} - -uint16_t -getch(void) -{ - while((RCSR && 0200) == 0) continue; - return RBUF; -} - -/* - * Busy-loop - */ - void wait(uint16_t count) { diff --git a/pdp11/pdp11.h b/pdp11/pdp11.h index 2aff814..f8bb40c 100644 --- a/pdp11/pdp11.h +++ b/pdp11/pdp11.h @@ -5,9 +5,10 @@ #define SGK_PDP11_H #include +#include "./pdp11_register.h" +#include "./pdp11_mmu.h" +#include "./pdp11_slu.h" -void putch(uint16_t); -uint16_t getch(void); void wait(uint16_t); #endif /* SGK_PDP11_H */ diff --git a/pdp11/pdp11_interrupt.c b/pdp11/pdp11_interrupt.c new file mode 100644 index 0000000..5d563aa --- /dev/null +++ b/pdp11/pdp11_interrupt.c @@ -0,0 +1,10 @@ +// (c) 2020 Aaron Taylor +// See License.txt file for copyright and license details. + +#include "pdp11.h" + +void +int4_c_handler(void) +{ + printf("\nHandling interrupt 4\n"); +} diff --git a/pdp11/pdp11_mmu.c b/pdp11/pdp11_mmu.c new file mode 100644 index 0000000..32d5d27 --- /dev/null +++ b/pdp11/pdp11_mmu.c @@ -0,0 +1,53 @@ +// (c) 2020 Aaron Taylor +// See License.txt file for copyright and license details. + +#include +#include "pdp11_register.h" +#include "pdp11_slu.h" + +void +init_mmu(void) +{ + + /* + * First populate the relocation registers, all zero since we want an + * identity mapping, except the highest page that we remap to the physical MMIO + * range. + */ + SET(KISAR0,PAR_PAF,0000000); + SET(KISAR1,PAR_PAF,0000000); + SET(KISAR2,PAR_PAF,0000000); + SET(KISAR3,PAR_PAF,0000000); + SET(KISAR4,PAR_PAF,0000000); + SET(KISAR5,PAR_PAF,0000000); + SET(KISAR6,PAR_PAF,0000000); + SET(KISAR7,PAR_PAF,0177600); + + /* + * Now populate the page descriptor registers. See EK-KDJ1B-UG page 1-19 + * for details of each field. + */ + uint16_t data = 0; + SET(data,PDR_BYPASCACHE,0); + SET(data,PDR_PAGELEN,0177); + SET(data,PDR_PAGEWRITEN,0); + SET(data,PDR_EXPANDDIR,0); + SET(data,PDR_ACCESSCTRL,03); + + KISDR0 = data; + KISDR1 = data; + KISDR2 = data; + KISDR3 = data; + KISDR4 = data; + KISDR5 = data; + KISDR6 = data; + KISDR7 = data; + + /* + * Enable the MMU with a 22-bit mapping. + */ + SET(MMR3,MMR3_KRNSPLTID,0); + SET(MMR3,MMR3_EN_22BIT,1); + SET(MMR0,MMR0_EN_MMU,1); +} + diff --git a/pdp11/pdp11_mmu.h b/pdp11/pdp11_mmu.h new file mode 100644 index 0000000..9280850 --- /dev/null +++ b/pdp11/pdp11_mmu.h @@ -0,0 +1,15 @@ +// (c) 2020 Aaron Taylor +// See License.txt file for copyright and license details. + +#ifndef SGK_PDP11_MMU_H +#define SGK_PDP11_MMU_H + +/* + * Initializes the MMU with a 22-bit kernel-mode I-space map that relocates the + * MMIO page to the physical MMIO region at the top of the physical address + * space while leaving the lower 56kB identity mapped. Assumes the CPU is + * already running in kernel mode with MMU hardware disabled. + */ +void init_mmu(void); + +#endif // SGK_PDP11_MMU_H diff --git a/pdp11/pdp11_register.h b/pdp11/pdp11_register.h new file mode 100644 index 0000000..c3f0ce6 --- /dev/null +++ b/pdp11/pdp11_register.h @@ -0,0 +1,253 @@ +// (c) 2020 Aaron Taylor +// See LICENSE.txt file for copyright and license details. + +#ifndef SGK_PDP11_REGISTER_H +#define SGK_PDP11_REGISTER_H + + +/* + * ============================================================================= + * Register Access Macros + * ============================================================================= + */ + +/* + * Use these macros along with the register address/field definitions in this + * file to get/set memory mapped registers. + * + * For example: + * SET(KISDR2,PDR_PAGELEN,0100); + * SET(MMR3,MMR3_EN_22BIT,1); + * uint16_t value = GET(PSW,PSW_REGSET); + */ + +#define GET(reg,regspec) GET_EXPANDED(reg,regspec) +#define GET_EXPANDED(reg,mask,offset) ((reg & (mask << offset)) >> offset) + +#define SET(reg,regspec,value) SET_EXPANDED(reg,regspec,value) +#define SET_EXPANDED(reg,mask,offset,value) (reg = ((reg & (~(mask << offset))) | (value << offset))) + + +/* + * ============================================================================= + * Register Address Definitions + * ============================================================================= + */ + +// Register names correspond to KDJ11-B User Guide (EK-KDJ1B-UG). +// http://bitsavers.org/pdf/dec/pdp11/1173/EK-KDJ1B-UG_KDJ11-B_Nov86.pdf + +/* CPU */ + +#define PSW (*((volatile uint16_t *)0177776)) +#define PIRQ (*((volatile uint16_t *)0177772)) +#define CPUERR (*((volatile uint16_t *)0177766)) + +/* MMU */ + +#define MMR0 (*((volatile uint16_t *)0177572)) +#define MMR1 (*((volatile uint16_t *)0177574)) +#define MMR2 (*((volatile uint16_t *)0177576)) +#define MMR3 (*((volatile uint16_t *)0172516)) + +#define UISDR0 (*((volatile uint16_t *)0177600)) +#define UISDR1 (*((volatile uint16_t *)0177602)) +#define UISDR2 (*((volatile uint16_t *)0177604)) +#define UISDR3 (*((volatile uint16_t *)0177606)) +#define UISDR4 (*((volatile uint16_t *)0177610)) +#define UISDR5 (*((volatile uint16_t *)0177612)) +#define UISDR6 (*((volatile uint16_t *)0177614)) +#define UISDR7 (*((volatile uint16_t *)0177616)) + +#define UDSDR0 (*((volatile uint16_t *)0177620)) +#define UDSDR1 (*((volatile uint16_t *)0177622)) +#define UDSDR2 (*((volatile uint16_t *)0177624)) +#define UDSDR3 (*((volatile uint16_t *)0177626)) +#define UDSDR4 (*((volatile uint16_t *)0177630)) +#define UDSDR5 (*((volatile uint16_t *)0177632)) +#define UDSDR6 (*((volatile uint16_t *)0177634)) +#define UDSDR7 (*((volatile uint16_t *)0177636)) + +#define UISAR0 (*((volatile uint16_t *)0177640)) +#define UISAR1 (*((volatile uint16_t *)0177642)) +#define UISAR2 (*((volatile uint16_t *)0177644)) +#define UISAR3 (*((volatile uint16_t *)0177646)) +#define UISAR4 (*((volatile uint16_t *)0177650)) +#define UISAR5 (*((volatile uint16_t *)0177652)) +#define UISAR6 (*((volatile uint16_t *)0177654)) +#define UISAR7 (*((volatile uint16_t *)0177656)) + +#define UDSAR0 (*((volatile uint16_t *)0177660)) +#define UDSAR1 (*((volatile uint16_t *)0177662)) +#define UDSAR2 (*((volatile uint16_t *)0177664)) +#define UDSAR3 (*((volatile uint16_t *)0177666)) +#define UDSAR4 (*((volatile uint16_t *)0177670)) +#define UDSAR5 (*((volatile uint16_t *)0177672)) +#define UDSAR6 (*((volatile uint16_t *)0177674)) +#define UDSAR7 (*((volatile uint16_t *)0177676)) + +#define SISDR0 (*((volatile uint16_t *)0172200)) +#define SISDR1 (*((volatile uint16_t *)0172202)) +#define SISDR2 (*((volatile uint16_t *)0172204)) +#define SISDR3 (*((volatile uint16_t *)0172206)) +#define SISDR4 (*((volatile uint16_t *)0172210)) +#define SISDR5 (*((volatile uint16_t *)0172212)) +#define SISDR6 (*((volatile uint16_t *)0172214)) +#define SISDR7 (*((volatile uint16_t *)0172216)) + +#define SDSDR0 (*((volatile uint16_t *)0172220)) +#define SDSDR1 (*((volatile uint16_t *)0172222)) +#define SDSDR2 (*((volatile uint16_t *)0172224)) +#define SDSDR3 (*((volatile uint16_t *)0172226)) +#define SDSDR4 (*((volatile uint16_t *)0172230)) +#define SDSDR5 (*((volatile uint16_t *)0172232)) +#define SDSDR6 (*((volatile uint16_t *)0172234)) +#define SDSDR7 (*((volatile uint16_t *)0172236)) + +#define SISAR0 (*((volatile uint16_t *)0172240)) +#define SISAR1 (*((volatile uint16_t *)0172242)) +#define SISAR2 (*((volatile uint16_t *)0172244)) +#define SISAR3 (*((volatile uint16_t *)0172246)) +#define SISAR4 (*((volatile uint16_t *)0172250)) +#define SISAR5 (*((volatile uint16_t *)0172252)) +#define SISAR6 (*((volatile uint16_t *)0172254)) +#define SISAR7 (*((volatile uint16_t *)0172256)) + +#define SDSAR0 (*((volatile uint16_t *)0172260)) +#define SDSAR1 (*((volatile uint16_t *)0172262)) +#define SDSAR2 (*((volatile uint16_t *)0172264)) +#define SDSAR3 (*((volatile uint16_t *)0172266)) +#define SDSAR4 (*((volatile uint16_t *)0172270)) +#define SDSAR5 (*((volatile uint16_t *)0172272)) +#define SDSAR6 (*((volatile uint16_t *)0172274)) +#define SDSAR7 (*((volatile uint16_t *)0172276)) + +#define KISDR0 (*((volatile uint16_t *)0172300)) +#define KISDR1 (*((volatile uint16_t *)0172302)) +#define KISDR2 (*((volatile uint16_t *)0172304)) +#define KISDR3 (*((volatile uint16_t *)0172306)) +#define KISDR4 (*((volatile uint16_t *)0172310)) +#define KISDR5 (*((volatile uint16_t *)0172312)) +#define KISDR6 (*((volatile uint16_t *)0172314)) +#define KISDR7 (*((volatile uint16_t *)0172316)) + +#define KDSDR0 (*((volatile uint16_t *)0172320)) +#define KDSDR1 (*((volatile uint16_t *)0172322)) +#define KDSDR2 (*((volatile uint16_t *)0172324)) +#define KDSDR3 (*((volatile uint16_t *)0172326)) +#define KDSDR4 (*((volatile uint16_t *)0172330)) +#define KDSDR5 (*((volatile uint16_t *)0172332)) +#define KDSDR6 (*((volatile uint16_t *)0172334)) +#define KDSDR7 (*((volatile uint16_t *)0172336)) + +#define KISAR0 (*((volatile uint16_t *)0172340)) +#define KISAR1 (*((volatile uint16_t *)0172342)) +#define KISAR2 (*((volatile uint16_t *)0172344)) +#define KISAR3 (*((volatile uint16_t *)0172346)) +#define KISAR4 (*((volatile uint16_t *)0172350)) +#define KISAR5 (*((volatile uint16_t *)0172352)) +#define KISAR6 (*((volatile uint16_t *)0172354)) +#define KISAR7 (*((volatile uint16_t *)0172356)) + +#define KDSAR0 (*((volatile uint16_t *)0172360)) +#define KDSAR1 (*((volatile uint16_t *)0172362)) +#define KDSAR2 (*((volatile uint16_t *)0172364)) +#define KDSAR3 (*((volatile uint16_t *)0172366)) +#define KDSAR4 (*((volatile uint16_t *)0172370)) +#define KDSAR5 (*((volatile uint16_t *)0172372)) +#define KDSAR6 (*((volatile uint16_t *)0172374)) +#define KDSAR7 (*((volatile uint16_t *)0172376)) + +/* SLU */ + +#define CONSRCSR (*((volatile uint16_t *)0177560)) +#define CONSRBUF (*((volatile uint16_t *)0177562)) +#define CONSXCSR (*((volatile uint16_t *)0177564)) +#define CONSXBUF (*((volatile uint16_t *)0177566)) + +#define SLU0RCSR (*((volatile uint16_t *)0176500)) +#define SLU0RBUF (*((volatile uint16_t *)0176502)) +#define SLU0XCSR (*((volatile uint16_t *)0176504)) +#define SLU0XBUF (*((volatile uint16_t *)0176506)) + +#define SLU1RCSR (*((volatile uint16_t *)0176510)) +#define SLU1RBUF (*((volatile uint16_t *)0176512)) +#define SLU1XCSR (*((volatile uint16_t *)0176514)) +#define SLU1XBUF (*((volatile uint16_t *)0176516)) + +#define SLU2RCSR (*((volatile uint16_t *)0176520)) +#define SLU2RBUF (*((volatile uint16_t *)0176522)) +#define SLU2XCSR (*((volatile uint16_t *)0176524)) +#define SLU2XBUF (*((volatile uint16_t *)0176524)) + +#define SLU3RCSR (*((volatile uint16_t *)0176530)) +#define SLU3RBUF (*((volatile uint16_t *)0176532)) +#define SLU3XCSR (*((volatile uint16_t *)0176534)) +#define SLU3XBUF (*((volatile uint16_t *)0176536)) + + +/* + * ============================================================================= + * Register Field Definitions + * ============================================================================= + */ + +/* + * These take the form of "(width),(offset)". For example, if a field is + * 4-bits wide and occupies bits 2-5 (starting from 0), then it would be + * defined as "(017),(2)". + */ + +/* CPU */ + + +/* MMU */ +#define MMR0_AB_NONRES (01),(15) +#define MMR0_AB_PAGLEN (01),(14) +#define MMR0_AB_RO (01),(13) +#define MMR0_PG_MODE (03),(5) +#define MMR0_PG_SPLTID (01),(4) +#define MMR0_PG_NUMBER (07),(1) +#define MMR0_EN_MMU (01),(0) + +#define MMR1_A_CHANGE (037),(11) +#define MMR1_A_REGSTR (07),(8) +#define MMR1_B_CHANGE (037),(3) +#define MMR1_B_REGSTR (07),(0) + +#define MMR2_PC (0177777),(0) + +#define MMR3_EN_22BIT (01),(4) +#define MMR3_EN_CSMINS (01),(3) +#define MMR3_KRNSPLTID (01),(2) +#define MMR3_SUPSPLTID (01),(1) +#define MMR3_USRSPLTID (01),(0) + +#define PAR_PAF (0177777),(0) + +#define PDR_BYPASCACHE (01),(15) +#define PDR_PAGELEN (0177),(8) +#define PDR_PAGEWRITEN (01),(6) +#define PDR_EXPANDDIR (01),(3) +#define PDR_ACCESSCTRL (03),(1) + +/* SLU */ + +#define SLURCSR_RCVRDY (01),(7) +#define SLURCSR_RCVINT (01),(6) +#define SLURCSR_RCVEN (01),(0) + +#define SLURBUF_ERROR (01),(15) +#define SLURBUF_EOVRUN (01),(14) +#define SLURBUF_EFRAME (01),(13) +#define SLURBUF_EPARIT (01),(12) +#define SLURBUF_BUFFER (0377),(0) + +#define SLUXCSR_XMTBRK (01),(0) +#define SLUXCSR_XMTINT (01),(6) +#define SLUXCSR_XMTRDY (01),(7) + +#define SLUXBUF_BUFFER (0377),(0) + + +#endif // SGK_PDP11_REGISTER_H diff --git a/pdp11/pdp11_slu.c b/pdp11/pdp11_slu.c new file mode 100644 index 0000000..1d4667c --- /dev/null +++ b/pdp11/pdp11_slu.c @@ -0,0 +1,132 @@ +// (c) 2020 Aaron Taylor +// See License.txt file for copyright and license details. + +#include +#include +#include "pdp11.h" + +/* + * Polled console I/O + */ + +void +putch(uint16_t c) +{ + while(!(GET(CONSXCSR,SLUXCSR_XMTRDY))) continue; + CONSXBUF = c; +} + +uint16_t +getch(void) +{ + while(!(GET(CONSRCSR,SLURCSR_RCVRDY))) continue; + return CONSRBUF; +} + + +/* + * Helper functions for use with console IO + */ + +void +print_string(const char * string) +{ + while (*string != '\0') { + putch(*string); + string++; + } +} + +char +digit_to_ascii(uint16_t digit) +{ + if (digit > 15) { + print_string("ERROR: Out of range in digit_to_ascii()\r\n"); + // TODO: How do I want to handle runtime errors? + return 0; + } else if (digit > 9) { + digit -= 10; + digit += 'a'; + return digit; + } else { + digit += '0'; + return digit; + } +} + +void +print_uint16_in_octal(uint16_t number) +{ + char output[7]; // +6 for digits; +1 for null-term + for (int i = 5; i >= 0; i--) { + output[i] = digit_to_ascii(number % 8); + number = number / 8; + } + output[6] = '\0'; + putch('0'); + print_string(output); +} + +void +printf(const char * format, ...) +{ + va_list ap; + va_start(ap, format); + while (*format) { + switch (*format) { + case '%': + format++; + switch (*format) { + case 's': + { + char * s = va_arg(ap, char *); + print_string(s); + break; + } + case 'o': + { + uint16_t u = va_arg(ap, unsigned int); + print_uint16_in_octal(u); + break; + } + default: + /* Put it back and look innocent. */ + putch('%'); + putch(*format); + break; + } + break; + case '\\': + format++; + switch (*format) { + case 'n': + print_string("\r\n"); + break; + case 't': + putch('\t'); + break; + case '%': + putch('%'); + break; + case '\\': + putch('\\'); + break; + default: + /* Maybe this escape wasn't meant for us. */ + putch('\\'); + putch(*format); + break; + } + break; + case '\n': + print_string("\r\n"); + break; + default: + putch(*format); + break; + } + format++; + } + va_end(ap); +} + diff --git a/pdp11/pdp11_slu.h b/pdp11/pdp11_slu.h new file mode 100644 index 0000000..9949360 --- /dev/null +++ b/pdp11/pdp11_slu.h @@ -0,0 +1,27 @@ +// (c) 2020 Aaron Taylor +// See License.txt file for copyright and license details. + +#ifndef SGK_PDP11_SLU_H +#define SGK_PDP11_SLU_H + +#include +#include "pdp11.h" + +/* + * Polled IO functions for default console port. + */ +void putch(uint16_t c); +uint16_t getch(void); + +/* + * Simple printf function. Replaces: + * %s - Print a string + * %o - Print a uint16 in octal + * \n - Print a newline suitable for this system ('\r\n') + * \t - Print a tab + * \% - Print a '%' + * Also converts existing newlines in the 'format' string to '\r\n'. + */ +void printf(const char * format, ...); + +#endif // SGK_PDP11_SLU_H