From b11fbf6cd44b95e9632f56550656cb954e478e18 Mon Sep 17 00:00:00 2001 From: Phil Budne Date: Sat, 17 Feb 2018 01:17:58 -0500 Subject: [PATCH] DISPLAY: Update display code to support DEC Type 340, and 36 switches Only interface code to Type 340 is for Richard Cornwell's KA10 (but could be used on PDP-1/4/7/9 as well) --- PDP1/pdp1_cpu.c | 11 +- PDP11/pdp11_vt.c | 11 +- TX-0/tx0_cpu.c | 14 +- display/Makefile.340 | 13 + display/display.c | 99 ++++---- display/display.h | 86 ++++++- display/tst340.c | 368 +++++++++++++++++++++++++++ display/type340.c | 583 ++++++++++++++++++++++++++++++------------- display/type340.h | 60 +++++ display/type340cmd.h | 177 +++++++++++++ display/vttest.c | 8 +- display/x11.c | 90 +++++-- 12 files changed, 1260 insertions(+), 260 deletions(-) create mode 100644 display/Makefile.340 create mode 100644 display/tst340.c create mode 100644 display/type340.h create mode 100644 display/type340cmd.h diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index a4fc917a..7d76931d 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -1704,15 +1704,16 @@ return SCPE_OK; #ifdef USE_DISPLAY /* set "test switches"; from display code */ +#include "display/display.h" /* prototypes */ -void cpu_set_switches(unsigned long bits) +void cpu_set_switches(unsigned long v1, unsigned long v2) { -/* just what we want; smaller CPUs might want to shift down? */ -TW = bits; +TW = v1 ^ v2; } -unsigned long cpu_get_switches(void) +void cpu_get_switches(unsigned long *p1, unsigned long *p2) { -return TW; +*p1 = TW; +*p2 = 0; } #endif diff --git a/PDP11/pdp11_vt.c b/PDP11/pdp11_vt.c index 920dd996..18e7e2a6 100644 --- a/PDP11/pdp11_vt.c +++ b/PDP11/pdp11_vt.c @@ -545,15 +545,16 @@ int32 SR; /* switch register */ #endif void -cpu_set_switches(unsigned long val) +cpu_set_switches(unsigned long v1, unsigned long v2) { - SR = val; + SR = v1 ^ v2; } -unsigned long -cpu_get_switches(void) +void +cpu_get_switches(unsigned long *p1, unsigned long *p2) { - return SR; + *p1 = SR; + *p2 = 0; } #else /* USE_DISPLAY not defined */ char pdp11_vt_unused; /* sometimes empty object modules cause problems */ diff --git a/TX-0/tx0_cpu.c b/TX-0/tx0_cpu.c index 869b5b31..264adc20 100644 --- a/TX-0/tx0_cpu.c +++ b/TX-0/tx0_cpu.c @@ -1193,18 +1193,22 @@ for (k = 0; k < lnt; k++) { /* print specified */ return SCPE_OK; } +#ifdef USE_DISPLAY +#include "display/display.h" /* prototypes */ + /* set "test switches"; from display code */ void -cpu_set_switches(unsigned long bits) +cpu_set_switches(unsigned long v1, unsigned long v2) { /* just what we want; smaller CPUs might want to shift down? */ - TAC = bits; + TAC = v1 ^ v2; } -unsigned long -cpu_get_switches(void) +void +cpu_get_switches(unsigned long *p1, unsigned long *p2) { - return TAC; + *p1 = TAC; + *p2 = 0; } t_stat sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) { diff --git a/display/Makefile.340 b/display/Makefile.340 new file mode 100644 index 00000000..79941a5d --- /dev/null +++ b/display/Makefile.340 @@ -0,0 +1,13 @@ +# Makefile for type340 test/debug + +ALL=tdbg tx +all: $(ALL) + +tdbg: tst340.c type340.c Makefile.340 type340.h type340cmd.h + cc -g -o tdbg tst340.c type340.c -DTY340_NODISPLAY -DDEBUG_TY340 -DDUMP + +tx: tst340.c type340.c display.c x11.c Makefile.340 ws.h type340.h type340cmd.h display.h + cc -g -o tx tst340.c type340.c display.c x11.c -lm -lX11 -lXt -DDUMP + +clean: + rm -f $(ALL) diff --git a/display/display.c b/display/display.c index 714fd802..dcc0b825 100644 --- a/display/display.c +++ b/display/display.c @@ -13,7 +13,7 @@ */ /* - * Copyright (c) 2003-2004, Philip L. Budne + * Copyright (c) 2003-2018 Philip L. Budne * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -131,7 +131,6 @@ static struct color color_red = { pred, ELEMENTS(pred), 100000 }; static struct display displays[] = { /* * TX-0 - * * * Unknown manufacturer * @@ -140,8 +139,6 @@ static struct display displays[] = { * 50us point plot time (20,000 points/sec) * P17 Phosphor??? Two phosphor layers: * fast blue (.05s half life), and slow green (.2s half life) - * - * */ { DIS_TX0, "MIT TX-0", &color_p17, NULL, 512, 512 }, @@ -216,8 +213,9 @@ static struct display displays[] = { /* * Type 340 Display system - * on PDP-4/6/7/9/10 + * on PDP-1/4/6/7/9/10 * + * Raytheon 16ADP7A CRT, same as Type 30 * 1024x1024 * 9 3/8" raster (.01" dot pitch) * 0,0 at lower left @@ -989,16 +987,13 @@ display_scale(void) /* * handle keyboard events * - * data switches; 18 -- enough for PDP-1/4/7/9/15 (for munching squares!) + * data switches: bit toggled on key up, all cleared on space + * enough for PDP-1/4/7/9/15 (for munching squares!): * 123 456 789 qwe rty uio - * bit toggled on key up - * all cleared on space * - * spacewar switches; bit high as long as key down - * asdf kl;' - * just where PDP-1 spacewar expects them! - * key mappings same as MIT Media Lab Java PDP-1 simulator - * + * second set of 18 for PDP-6/10, IBM7xxx (shifted versions of above): + * !@# $%^ &*( QWE RTY UIO + * */ unsigned long spacewar_switches = 0; @@ -1006,15 +1001,13 @@ unsigned long spacewar_switches = 0; void display_keydown(int k) { + /*printf("down '%c'\r\n", k); /**/ switch (k) { - case 'f': case 'F': spacewar_switches |= 01; break; /* torpedos */ - case 'd': case 'D': spacewar_switches |= 02; break; /* engines */ - case 'a': case 'A': spacewar_switches |= 04; break; /* rotate R */ - case 's': case 'S': spacewar_switches |= 010; break; /* rotate L */ - case '\'': case '"': spacewar_switches |= 040000; break; /* torpedos */ - case ';': case ':': spacewar_switches |= 0100000; break; /* engines */ - case 'k': case 'K': spacewar_switches |= 0200000; break; /* rotate R */ - case 'l': case 'L': spacewar_switches |= 0400000; break; /* rotate L */ +/* handle spacewar switches: see display.h for copious commentary */ +#define SWSW(LC,UC,BIT,POS36,FUNC36) \ + case LC: case UC: spacewar_switches |= BIT; return; + SPACEWAR_SWITCHES +#undef SWSW default: return; } } @@ -1023,19 +1016,16 @@ display_keydown(int k) void display_keyup(int k) { - unsigned long test_switches = cpu_get_switches(); + unsigned long test_switches, test_switches2; - /* fetch console switches from simulator? */ + cpu_get_switches(&test_switches, &test_switches2); switch (k) { - case 'f': case 'F': spacewar_switches &= ~01; return; - case 'd': case 'D': spacewar_switches &= ~02; return; - case 'a': case 'A': spacewar_switches &= ~04; return; - case 's': case 'S': spacewar_switches &= ~010; return; +/* handle spacewar switches: see display.h for copious commentary */ +#define SWSW(LC,UC,BIT,POS36,NAME36) \ + case LC: case UC: spacewar_switches &= ~BIT; return; - case '\'': case '"': spacewar_switches &= ~040000; return; - case ';': case ':': spacewar_switches &= ~0100000; return; - case 'k': case 'K': spacewar_switches &= ~0200000; return; - case 'l': case 'L': spacewar_switches &= ~0400000; return; + SPACEWAR_SWITCHES +#undef SWSW case '1': test_switches ^= 1<<17; break; case '2': test_switches ^= 1<<16; break; @@ -1049,20 +1039,45 @@ display_keyup(int k) case '8': test_switches ^= 1<<10; break; case '9': test_switches ^= 1<<9; break; - case 'q': case 'Q': test_switches ^= 1<<8; break; - case 'w': case 'W': test_switches ^= 1<<7; break; - case 'e': case 'E': test_switches ^= 1<<6; break; + case 'q': test_switches ^= 1<<8; break; + case 'w': test_switches ^= 1<<7; break; + case 'e': test_switches ^= 1<<6; break; - case 'r': case 'R': test_switches ^= 1<<5; break; - case 't': case 'T': test_switches ^= 1<<4; break; - case 'y': case 'Y': test_switches ^= 1<<3; break; + case 'r': test_switches ^= 1<<5; break; + case 't': test_switches ^= 1<<4; break; + case 'y': test_switches ^= 1<<3; break; - case 'u': case 'U': test_switches ^= 1<<2; break; - case 'i': case 'I': test_switches ^= 1<<1; break; - case 'o': case 'O': test_switches ^= 1; break; + case 'u': test_switches ^= 1<<2; break; + case 'i': test_switches ^= 1<<1; break; + case 'o': test_switches ^= 1; break; - case ' ': test_switches = 0; break; + /* second set of 18 switches */ + case '!': test_switches2 ^= 1<<17; break; + case '@': test_switches2 ^= 1<<16; break; + case '#': test_switches2 ^= 1<<15; break; + + case '$': test_switches2 ^= 1<<14; break; + case '%': test_switches2 ^= 1<<13; break; + case '^': test_switches2 ^= 1<<12; break; + + case '&': test_switches2 ^= 1<<11; break; + case '*': test_switches2 ^= 1<<10; break; + case '(': test_switches2 ^= 1<<9; break; + + case 'Q': test_switches2 ^= 1<<8; break; + case 'W': test_switches2 ^= 1<<7; break; + case 'E': test_switches2 ^= 1<<6; break; + + case 'R': test_switches2 ^= 1<<5; break; + case 'T': test_switches2 ^= 1<<4; break; + case 'Y': test_switches2 ^= 1<<3; break; + + case 'U': test_switches2 ^= 1<<2; break; + case 'I': test_switches2 ^= 1<<1; break; + case 'O': test_switches2 ^= 1; break; + + case ' ': test_switches = test_switches2 = 0; break; default: return; } - cpu_set_switches(test_switches); + cpu_set_switches(test_switches, test_switches2); } diff --git a/display/display.h b/display/display.h index 96bcc07b..c8b6af85 100644 --- a/display/display.h +++ b/display/display.h @@ -8,7 +8,7 @@ */ /* - * Copyright (c) 2003-2004, Philip L. Budne + * Copyright (c) 2003-2018, Philip L. Budne * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -37,11 +37,15 @@ * known display types */ enum display_type { + /* + * Give TX-0 the rightful spot as the progenitor + * of the PDP-1, and thus all DEC machines. + */ + DIS_TX0 = 0, DIS_VR14 = 14, DIS_VR17 = 17, DIS_VR20 = 20, DIS_TYPE30 = 30, - DIS_TX0 = 33, DIS_VR48 = 48, DIS_TYPE340 = 340 }; @@ -86,7 +90,7 @@ extern int display_age(int,int); #define DISPLAY_INT_MIN 0 /* lowest "on" level */ /* - * plot a point; argumen ts are x, y, intensity, color (0/1) + * plot a point; arguments are x, y, intensity, color (0/1) * returns true if light pen active (mouse button down) * at (or very near) this location. * @@ -119,10 +123,78 @@ extern void display_lp_radius(int); /* * set by simulated spacewar switch box switches - * 18 bits (only high 4 and low 4 used) + * bits high as long as key down + * + * asdf kl;' + * bits just where PDP-1 spacewar expects them! + * key mappings same as MIT Media Lab Java PDP-1 simulator + * + * PDP-6/10 SPCWAR adds hyperspace button, two more players. + * All additional bits above PDP-1 18-bit word. */ extern unsigned long spacewar_switches; +/* + * spacewar_switches fruit salad: + * + * the low 18 bits spacewar_swiches (a 32-bit int) + * are the switches for PDP-1 spacewar (four at either end) + * where the game expects them. + * + * Additional bits for the PDP-6/10 game are in the upper 14 bits: + * existing (top player) hyperspace buttons in the top two bits, + * and bottom players in two 6-bit bytes + * + * Too much mess to have in three places (display.c key up/down and + * the PDP-10 interface code), so I'm using a common idiom from the PDP-10 + * world: define a macro that expands to multiple macro invocations + * and redefine the inner macro as needed before expanding the outer macro. + * + * I have little/no expectation that this is actually playable, but + * you could rig up an AVR (or other USB MCU) with switch boxes to + * look like a USB HID keyboard. For full historical accuracy, please + * use wooden controllers! + * + * Phil Budne Feb 2018 + */ + +/* SWSW (SpaceWar SWitch) macro args: + * LC: lower case key + * UC: upper case key + * BIT: bit in spacewar_switches (1 means switch on) + * yes, 32-bit int bits expressed in octal + * (which is just like decimal, if you're missing two fingers) + * POS: user in PDP-6/10 parlance Upper/Lower Left/Right + * FUNC: function name in PDP-6/10 parlance (FIRE means beam or torpedo) + * comment is meaning in PDP-1 parlance + * + * entries in order of PDP-1 function bit order + */ +#define SPACEWAR_SWITCHES \ + SWSW('f', 'F', 01, UL, FIRE) /* torpedos */ \ + SWSW('d', 'D', 02, UL, THRUST) /* engines */ \ + SWSW('a', 'A', 04, UL, CW) /* rotate R */ \ + SWSW('s', 'S', 010, UL, CCW) /* rotate L */ \ + SWSW('g', 'G', 010000000000, UL, HYPER) /* PDP-6/10 hyperspace */ \ + \ + SWSW('\'', '"', 040000, UR, FIRE) /* torpedos */ \ + SWSW(';', ':', 0100000, UR, THRUST) /* engines */ \ + SWSW('k', 'K', 0200000, UR, CW) /* rotate R */ \ + SWSW('l', 'L', 0400000, UR, CCW) /* rotate L */ \ + SWSW('\r','\n',020000000000, UR, HYPER) /* PDP-6/10 hyperspace */ \ + \ + SWSW('v', 'V', 01000000, LL, FIRE) /* torpedos */ \ + SWSW('c', 'C', 02000000, LL, THRUST) /* engines */ \ + SWSW('z', 'Z', 04000000, LL, CW) /* rotate R */ \ + SWSW('x', 'X', 010000000, LL, CCW) /* rotate L */ \ + SWSW('b', 'B', 020000000, LL, HYPER) /* hyperspace */ \ + \ + SWSW('.', '>', 0100000000, LR, FIRE) /* torpedos */ \ + SWSW(',', '<', 0200000000, LR, THRUST) /* engines */ \ + SWSW('n', 'N', 0400000000, LR, CW) /* rotate R */ \ + SWSW('m', 'M', 01000000000, LR, CCW) /* rotate L */ \ + SWSW('/', '?', 02000000000, LR, HYPER) /* hyperspace */ + /* * light pen "tip switch" activated (for VS60 emulation etc.) * should only be set from "driver" (window system layer) @@ -138,7 +210,7 @@ extern unsigned char display_tablet; /* * users of this library are expected to provide these calls. - * simulator will set 18 simulated switches. + * simulator will set up to 36 simulated switches. */ -extern unsigned long cpu_get_switches(void); /* get current switch state */ -extern void cpu_set_switches(unsigned long); /* set switches */ +extern void cpu_get_switches(unsigned long *p1, unsigned long *p2); +extern void cpu_set_switches(unsigned long, unsigned long); diff --git a/display/tst340.c b/display/tst340.c new file mode 100644 index 00000000..1cae5d75 --- /dev/null +++ b/display/tst340.c @@ -0,0 +1,368 @@ +/* + * debug output, no display: + * cc -g -o tst340 tst340.c type340.c -DTY340_NODISPLAY -DDEBUG_TY340 + * + * w/ display: + * cc -g -o tst340 tst340.c type340.c display.c x11.c -lm -lX11 -lXt + */ + +// possible source of test code +// light pen diag: +// http://bitsavers.informatik.uni-stuttgart.de/pdf/dec/pdp7/DIGITAL-7-78-M_370LightPenDiag_Apr64.pdf + +#include +#include + +#include "display.h" +#include "type340.h" +#include "type340cmd.h" + +void dump(int *ip); + +int words[] = { +#if 0 + // 11sim! + 020154, + 0221000, + 0120000, + 0600001, + 020000, + 0220000, + 0121000, + 0600400, + 03000 +#elif 1 + // p budne: character test + MPT, /* param: point mode */ + MPT|H|0, /* point: h=0; point mode */ + MPAR|V|512, /* point: v=64; par mode */ + MCHR|S3|IN7, /* param: chr mode, size 3, intensity 7 */ + CHAR('H'-'@', 'E'-'@', 'L'-'@'), + CHAR('L'-'@', 'O'-'@', ' '), + CHAR('W'-'@', 'O'-'@', 'R'-'@'), + CHAR('L'-'@', 'D'-'@', '!'), + CHAR(' ', 0, 037), + MCHR|S2|IN7, /* param: chr mode, size 2, intensity 7 */ + CHAR(CHRCR, CHRLF, 'H'-'@'), + CHAR('E'-'@', 'L'-'@', 'L'-'@'), + CHAR('O'-'@', ' ', 'W'-'@'), + CHAR('O'-'@', 'R'-'@', 'L'-'@'), + CHAR('D'-'@', '!', CHRESC), + MCHR|S1|IN7, /* param: chr mode, size 1, intensity 7 */ + CHAR(CHRCR, CHRLF, 'H'-'@'), + CHAR('E'-'@', 'L'-'@', 'L'-'@'), + CHAR('O'-'@', ' ', 'W'-'@'), + CHAR('O'-'@', 'R'-'@', 'L'-'@'), + CHAR('D'-'@', '!', CHRESC), + + MCHR|S0|IN2, /* param: chr mode, size 0, intensity 2 */ + CHAR(CHRUC, CHRCR, CHRLF), + CHAR(000, 001, 002), CHAR(003, 004, 005), CHAR(006, 007, ' '), + CHAR(010, 011, 012), CHAR(013, 014, 015), CHAR(016, 017, ' '), + CHAR(020, 021, 022), CHAR(023, 024, 025), CHAR(026, 027, ' '), + CHAR(030, 031, 032), /* 33-37 are control codes */ + CHAR(040, 041, 042), CHAR(043, 044, 045), CHAR(046, 047, ' '), + CHAR(050, 051, 052), CHAR(053, 054, 055), CHAR(056, 057, ' '), + CHAR(060, 061, 062), CHAR(063, 064, 065), CHAR(066, 067, ' '), + CHAR(070, 071, 072), CHAR(073, 074, 075), CHAR(076, 077, ' '), + + CHAR(CHRLC, CHRCR, CHRLF), + CHAR(000, 001, 002), CHAR(003, 004, 005), CHAR(006, 007, ' '), + CHAR(010, 011, 012), CHAR(013, 014, 015), CHAR(016, 017, ' '), + CHAR(020, 021, 022), CHAR(023, 024, 025), CHAR(026, 027, ' '), + CHAR(030, 031, 032), /* 33-37 are control codes */ + CHAR(040, 041, 042), CHAR(043, 044, 045), CHAR(046, 047, ' '), + CHAR(050, 051, 052), CHAR(053, 054, 055), CHAR(056, 057, ' '), + CHAR(060, 061, 062), CHAR(063, 064, 065), CHAR(066, 067, ' '), + CHAR(070, 071, 072), CHAR(073, 074, 075), CHAR(076, 077, ' '), + CHAR(CHRESC, 0, 0), + STP +#elif 1 + /* +030153: PT LPOFF S2 IN3 +221000: PT V 512. +103000: VCT IP H 512. +703100: ESCP INSFY DN YP4 YP2 RT XP64 +140000: INCR +304210: INSFY INCRPT( PR, PR, PR, PR) +325063: INSFY INCRPT( PUR, PUR, PD, PD) +631777: ESCP INSFY INCRPT( PD, PD, PDL, PDL) +100000: VCT +600210: ESCP INSFY LT XP8 +140000: INCR +237463: INSFY INCRPT( PD, PDL, PD, PD) +231673: INSFY INCRPT( PD, PD, PDR, PDR) +704210: ESCP INSFY INCRPT( PR, PR, PR, PR) +100000: VCT +203400: INSFY UP YP4 YP2 YP1 +600203: ESCP INSFY LT XP2 XP1 +140000: INCR +377463: INSFY INCRPT( PDL, PDL, PD, PD) +631273: ESCP INSFY INCRPT( PD, PU, PDR, PDR) +002000: PAR STOP + */ + // H-340_Type_340_Precision_Incremental_CRT_System_Nov64.pdf + MPT|LPON|S2|IN3, // 0030133, /* set params */ + MPT|V|512, // 0220000, /* y axis */ + MVCT|H|IP|512, // 0103760, /* x axis, draw line */ + ESCP|INSFY|DN|YP4|YP2|XP64, // 0703100, /* draw curve */ + MINCR, // 0140000, /* set mode */ + INSFY|INCRPT(PR,PR,PR,PR), // 0304210, /* draw curve */ + INSFY|INCRPT(PUR,PUR,PD,PD), // 0325063, /* draw curve */ + ESCP|INSFY|INCRPT(PD,PD,PDL,PDL), // 0631777, + MVCT, // 0100000, /* set mode */ + ESCP|INSFY|LT|XP8, // 0600210, /* draw line */ + MINCR, // 0140000, /* set mode */ + 0237463, /* draw curve */ + 0231673, /* draw curve */ + 0704210, /* draw curve */ + 0100000, /* set mode */ + 0203400, /* draw line */ + 0600203, /* draw line */ + 0140000, /* set mode */ + 0377463, /* draw curve */ + 0631273, /* draw curve */ +#if 0 +#endif + 0002000, /* stop, set done, send data interrupt */ +#else + // ITS SYSTEM;DDT > @ RECYC + 0020157, + 0261777 +#endif +}; + +int +main() { +#ifdef DUMP + dump(words); +#endif + for (;;) { + ty340_reset(); + for (unsigned i = 0; i < sizeof(words)/sizeof(words[0]); i++) { +#ifdef TY340_NODISPLAY + putchar('\n'); +#endif + int s = ty340_instruction(words[i]); +#ifdef TY340_NODISPLAY + printf(" status %#o\n", s); +#endif + if (s & ST340_STOPPED) + break; + /* XXX check for LPHIT? fetch coordinates */ + } +#ifdef TY340_NODISPLAY + break; +#else + display_age(1000, 1); + display_sync(); +#endif + } +} + +ty340word +ty340_fetch(ty340word addr) { + printf("ty340_fetch %#o\n", addr); + return 0; +} + +void +ty340_store(ty340word addr, ty340word value) { + printf("ty340_store %#o %#o\n", addr, value); +} + +void +ty340_cond_int(ty340word status) { + /*printf("ty340_stop_int\n");*/ +} + +void +ty340_lp_int(ty340word x, ty340word y) { + printf("ty340_lp_int %d. %d.\n", x, y); +} + +void +ty340_rfd(void) { /* request for data */ +#ifdef TY340_NODISPLAY + puts("ty340_rfd"); +#endif +} + +void +cpu_get_switches(unsigned long *p1, unsigned long *p2) { +} + +void +cpu_set_switches(unsigned long sw1, unsigned long sw2) { +} + +/**************************************************************** + * dump display list using symbols from type340cmd.h + */ + +#ifdef DUMP +// Vector & incremental modes +static int +escpinsfy(int word) +{ + int ret = 0; + if (word & ESCP) { + printf(" ESCP"); + ret = 1; + } + if (word & INSFY) + printf(" INSFY"); + return ret; +} + +static void +incr(int pt) +{ + pt &= 017; + //printf(" %#o", pt); + switch (pt) { +#define P(X) case X: printf(" " #X); return + P(PR); + P(PL); + P(PU); + P(PD); + P(PUL); + P(PUR); + P(PDL); + P(PDR); + } + printf(" ???"); +} + +// PAR, SLV, POINT +static int +xmode(int word) +{ + int m = word & MODEMASK; + switch (m) { +#define M(MODE) case MODE: printf(#MODE); break + M(MPAR); + M(MPT); + M(MSLV); + M(MCHR); + M(MVCT); + M(MVCTC); + M(MINCR); + M(MSUBR); + default: printf("M??"); break; /* SNH */ + } + return m; +} + +/* returns 1 if not stopped */ +int +dump1(int *mp, int word) +{ + int run = 1; + printf("%06o: ", word); + switch (*mp) { + case MPAR: + *mp = xmode(word); + // XXX look at reserved bits: 0300600?? + if (word & LPOFF) { + if ((word & LPON) == LPON) + printf(" LPON"); + else + printf(" LPOFF"); + } + if (word & STP) { + if ((word & STP) == STP) + printf(" STP"); + else + printf(" STOP"); + run = 0; + } + switch (word & S3) { + case S0: printf(" S0"); break; + case S1: printf(" S1"); break; + case S2: printf(" S2"); break; + case S3: printf(" S3"); break; + } + switch (word & IN7) { + case IN0: printf(" IN0"); break; + case IN1: printf(" IN1"); break; + case IN2: printf(" IN2"); break; + case IN3: printf(" IN3"); break; + case IN4: printf(" IN4"); break; + case IN5: printf(" IN5"); break; + case IN6: printf(" IN6"); break; + case IN7: printf(" IN7"); break; + } + break; + case MPT: + // 0400000 reserved + *mp = xmode(word); + if (word & IP) printf(" IP"); + if (word & V) printf(" V"); + else printf(" H"); + printf(" %d.", word & 01777); + break; + case MSLV: + *mp = xmode(word); + // reserved: 010000 + printf(" XXX SLAVE"); + break; + case MCHR: + printf(" XXX CHR"); + if ((word>>12)&077 == 037 || + (word>>6)&077 == 037 || + (word&077) == 037) + *mp = 0; + case MVCT: + case MVCTC: + if (escpinsfy(word)) *mp = 0; + if (word & 077400) { + if (word & DN) printf(" DN"); + else printf(" UP"); + if (word & YP64) printf(" YP64"); + if (word & YP32) printf(" YP32"); + if (word & YP16) printf(" YP16"); + if (word & YP8) printf(" YP8"); + if (word & YP4) printf(" YP4"); + if (word & YP2) printf(" YP2"); + if (word & YP1) printf(" YP1"); + } + if (word & 0377) { + if (word & LT) printf(" LT"); + else printf(" RT"); + if (word & XP64) printf(" XP64"); + if (word & XP32) printf(" XP32"); + if (word & XP16) printf(" XP16"); + if (word & XP8) printf(" XP8"); + if (word & XP4) printf(" XP4"); + if (word & XP2) printf(" XP2"); + if (word & XP1) printf(" XP1"); + } + break; + case MINCR: + if (escpinsfy(word)) *mp = 0; + printf(" INCRPT("); + incr(word >> 12); putchar(','); + incr(word >> 8); putchar(','); + incr(word >> 4); putchar(','); + incr(word); putchar(')'); + break; + case MSUBR: + puts("XXX SUBR: quitting"); + run = 0; + break; + } + putchar('\n'); + return run; +} + +void +dump(int *ip) +{ + int mode = 0; + puts(" === DUMP ==="); + while (dump1(&mode, *ip++)) + ; + puts("=== END DUMP ==="); +} +#endif diff --git a/display/type340.c b/display/type340.c index df9750a3..d3c22560 100644 --- a/display/type340.c +++ b/display/type340.c @@ -1,3 +1,8 @@ +/* + * wrap, or clip? + * finish lc bitmaps + */ + /* * $Id: type340.c,v 1.6 2005/01/14 18:58:00 phil Exp $ * Simulator Independent DEC Type 340 Graphic Display Processor Simulation @@ -5,12 +10,33 @@ * September 20, 2003 * from vt11.c * - * Information from DECUS 7-13 + * First displayed PDP-6/10 SPCWAR Feb 2018! + * + * The Type 340 was used on the PDP-{4,6,7,9,10} + * and used 18-bit words, with bits numbered 0 thru 17 + * (most significant to least) + * + * This file simulates ONLY the 340 proper + * and not CPU specific interfacing details + * + * see: + * http://www.bitsavers.org/pdf/dec/graphics/H-340_Type_340_Precision_Incremental_CRT_System_Nov64.pdf + * + * Initial information from DECUS 7-13: + * http://www.bitsavers.org/pdf/dec/graphics/7-13_340_Display_Programming_Manual.pdf + * pre-bitsavers location(!!): * http://www.spies.com/~aek/pdf/dec/pdp7/7-13_340displayProgMan.pdf + * + * NOTE!!! The 340 is an async processor, with multiple control signals + * running in parallel. No attempt has been made to simulate this. + * And while it might be fun to try to implement it as a bit vector + * of signals, and run code triggered by those signals in the next + * service interval, BUT unless/until this is proven necessary, I'm + * resisting that impulse (pun not intended). */ /* - * Copyright (c) 2003-2004, Philip L. Budne + * Copyright (c) 2003-2018, Philip L. Budne * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,13 +62,21 @@ */ #include "display.h" /* XY plot interface */ +#include "type340.h" /* interface definitions */ +#include "type340cmd.h" /* 340 command definitions */ /* - * The Type 340 was used on the PDP-{4,6,7,9,10} - * and used 18-bit words, with bits numbered 0 thru 17 - * (most significant to least) + * sub-options, under "#if" + * (make runtime selectable????!) + * TYPE342 character generator + * TYPE343 slave display control + * TYPE347 subroutine facility */ +#ifndef TYPE342 +#define TYPE342 1 /* default to character generation */ +#endif + #define BITMASK(N) (1<<(17-(N))) /* mask for a field */ @@ -55,91 +89,126 @@ #define TESTBIT(W,B) (((W) & BITMASK(B)) != 0) #ifdef DEBUG_TY340 +#include #define DEBUGF(X) printf X #else #define DEBUGF(X) #endif - -typedef long ty340word; - -static ty340word DAC; /* Display Address Counter */ -static unsigned char shift; /* 1 bit */ -static enum mode mode; /* 3 bits */ -static int scale; /* 2 bits */ - enum mode { PARAM=0, POINT, SLAVE, CHAR, VECTOR, VCONT, INCR, SUBR }; -enum jump_type { DJP=2, DJS=3, DDS=1 }; -static ty340word ASR; /* Address Save Register */ -static unsigned char save_ff; /* "save" flip-flop */ +#define TY340_UNITS 1 -static unsigned char intensity; /* 3 bits */ -static unsigned char lp_ena; /* 1 bit */ +enum jump_type { DJP=2, DJS=3, DDS=1 }; /* type 347 */ -/* kept signed for raster violation checking */ -static short xpos, ypos; /* 10 bits, signed */ -static unsigned char sequence; /* 2 bits */ +/* put all the state in a struct "just in case" */ +static struct type340 { +/* ty340word DAC; /* Display Address Counter */ + ty340word status; /* see ST340_XXX in type340.h */ + signed short xpos, ypos; /* 10 bits, signed (for OOB checks) */ + char initialized; /* 0 before display_init */ + /* only using (evil) bitfield syntax to limit enum size */ + enum mode mode : 8; /* 3 bits */ + unsigned char lp_ena; /* 1 bit */ + unsigned char scale; /* multiplier: 1,2,4,8 */ + unsigned char intensity; /* 3 bits */ +#if TYPE342 + unsigned char shift; /* 1 bit */ +#endif +#if TYPE347 + ty340word ASR; /* Address Save Register */ + unsigned char SAVE_FF; /* "save" flip-flop */ +#endif +} u340[TY340_UNITS]; -/* XXX make defines public for 340_cycle return */ -#define STOPPED 01 -#define LPHIT 02 -#define VEDGE 04 -#define HEDGE 010 -static unsigned char status = STOPPED; - -/* - * callbacks into PDP-6/10 simulator - */ -extern ty340word ty340_fetch(ty340word); -extern void ty340_store(ty340word, ty340word); -extern void ty340_stop_int(void); -extern void ty340_lp_int(void); +#if TY340_UNITS == 1 +#define UNIT(N) u340 +#else +#define UNIT(N) (u340+(N)) +#endif +#if 0 +/* NOT USED WITH PDP-6 Type 344 Interface!! */ void ty340_set_dac(ty340word addr) { - DAC = addr; - mode = 0; - DEBUGF(("set DAC %06\r\n", DAC)); - status = 0; /* XXX just clear stopped? */ - /* XXX clear other stuff? save_ff? */ -} + struct type340 *u = UNIT(0); + u->DAC = addr; + DEBUGF(("set DAC %06o\r\n", u->DAC)); -void + /* XXX only when reset? */ + u->mode = 0; + u->status = 0; /* XXX just clear stopped? */ + ty340_rfd(); /* ready for data */ +} +#endif + +ty340word ty340_reset(void) { - /* XXX call display layer? destroy window? */ - xpos = ypos = 0; - status = STOPPED; + struct type340 *u = UNIT(0); +#ifndef TY340_NODISPLAY + if (!u->initialized) { + display_init(DIS_TYPE340, 1, u); /* XXX check return? */ + u->initialized = 1; + } +#endif + u->xpos = u->ypos = 0; + u->mode = 0; + u->status = 0; /* set ST340_DONE? */ + u->scale = 1; +#if TYPE347 + u->SAVE_FF = 0; +#endif + ty340_rfd(); /* ready for data */ + return u->status; } static int point(int x, int y, int seq) { + struct type340 *u = UNIT(0); int i; - /* XXX apply scale? */ +#ifdef TYPE340_POINT + DEBUGF(("type340 point %d %d %d\r\n", x, y, seq)); +#endif - i = DISPLAY_INT_MAX-7+intensity; + i = DISPLAY_INT_MAX-7+u->intensity; if (i <= 0) i = 1; if (x < 0 || x > 1023) { - status |= VEDGE; + /* XXX clip? wrap?? */ + u->status |= ST340_VEDGE; return 0; } if (y < 0 || y > 1023) { - status |= HEDGE; + /* XXX clip? wrap?? */ + u->status |= ST340_HEDGE; return 0; } +#ifndef TY340_NODISPLAY if (display_point(x, y, i, 0)) { - if (lp_ena) { - /* XXX save location? */ - status |= LPHIT; - sequence = seq; - } + /* + * in real life: type340 pauses + * until CPU reads coordinates + */ + u->status |= ST340_LPHIT; + if (u->lp_ena) + ty340_lp_int(x, y); } +#endif + return 1; +} + +void +lpoint(int x, int y) +{ +#ifdef TYPE340_LPOINT + DEBUGF(("type340 lpoint %d %d\r\n", x, y)); +#endif + point(x, y, 0); } /* @@ -374,92 +443,125 @@ lineTwoStep(int x0, int y0, int x1, int y1) } } /* lineTwoStep */ -static int -vector(int i, int sx, int dx, int sy, int dy) +/* here in VECTOR & VCONT modes */ +int +vector(int i, int sy, int dy, int sx, int dx) { + struct type340 *u = UNIT(0); int x0, y0, x1, y1; + int flags; - x0 = xpos; - y0 = ypos; + DEBUGF(("v i%d y%c%d x%c%d\r\n", i, + (sy ? '-' : '+'), dy, + (sx ? '-' : '+'), dx)); + x0 = u->xpos; + y0 = u->ypos; if (sx) { - x1 = x0 - dx; - if (x1 < 0) /* XXX TEMP? */ + x1 = x0 - dx * u->scale; + if (x1 < 0) { x1 = 0; + flags = ST340_HEDGE; + } } else { - x1 = x0 + dx; - if (x1 > 1023) /* XXX TEMP? */ + x1 = x0 + dx * u->scale; + if (x1 > 1023) { x1 = 1023; + flags = ST340_HEDGE; + } } if (sy) { - y1 = y0 - dy; - if (y1 < 0) /* XXX TEMP? */ + y1 = y0 - dy * u->scale; + if (y1 < 0) { y1 = 0; + flags |= ST340_VEDGE; + } } else { - y1 = y0 + dy; /* XXX TEMP? */ - if (y1 > 1023) + y1 = y0 + dy * u->scale; + if (y1 > 1023) { y1 = 1023; + flags |= ST340_VEDGE; + } } DEBUGF(("vector i%d (%d,%d) to (%d,%d)\r\n", i, x0, y0, x1, y1)); - if (i) + if (i) /* XXX need OLD value??? */ lineTwoStep(x0, y0, x1, y1); - xpos = x1; - ypos = y1; - return 0; + u->xpos = x1; + u->ypos = y1; + u->status |= flags; /* ?? */ + return flags; } -/* return true on raster violation */ +/* + * incremental vector + * return true on raster violation + * + * i is intensify + * n is subvector number + * byte is 4 bits + */ int ipoint(int i, int n, unsigned char byte) { + struct type340 *u = UNIT(0); + DEBUGF(("type340 ipoint i%d n%d %#o\r\n", i, n, byte)); if (byte & 010) { /* left/right */ - if (byte & 04) { - if (xpos == 0) { - status |= VEDGE; - return 1; + if (byte & 04) { /* left */ + u->xpos -= u->scale; + if (u->xpos < 0) { + u->xpos = 0; /* XXX wrap? */ + u->status |= ST340_VEDGE; /* save flags & continue?? */ + return 1; /* escape */ } - xpos--; } - else { - if (xpos == 1023) { - status |= VEDGE; + else { /* right */ + u->xpos += u->scale; + if (u->xpos > 1023) { + u->xpos = 1023; /* XXX wrap? */ + u->status |= ST340_VEDGE; return 1; } - xpos++; } } if (byte & 02) { /* up/down */ - if (byte & 04) { - if (ypos == 0) { - status |= HEDGE; + if (byte & 01) { /* down */ + u->ypos -= u->scale; + if (u->ypos < 0) { + u->ypos = 0; /* XXX wrap? */ + u->status |= ST340_HEDGE; return 1; } - ypos--; } else { - if (ypos == 1023) { - status |= HEDGE; + u->ypos += u->scale; + if (u->ypos > 1023) { + u->ypos = 1023; /* XXX wrap? */ + u->status |= ST340_HEDGE; return 1; } - ypos++; } } if (i) - point(xpos, ypos, n); + point(u->xpos, u->ypos, n); - return 0; + return 0; /* no escape */ } +#if TYPE342 /* - * 342 character generator - first 64 characters (from manual) + * 342 character generator - first 64 characters + * 7-13_340_Display_Programming_Manual.pdf p.24 + * each char contains a vertical stripe of the matrix. + * lowest bit is bottom + * first char is leftmost */ -static const unsigned char chars[64][5] = { - { 0070, 0124, 0154, 0124, 0070 }, /* 00 */ +static const unsigned char chars[128][5] = { + { 0070, 0124, 0154, 0124, 0070 }, /* 00 blob */ { 0174, 0240, 0240, 0240, 0174 }, /* 01 A */ { 0376, 0222, 0222, 0222, 0154 }, /* 02 B */ { 0174, 0202, 0202, 0202, 0104 }, /* 03 C */ @@ -522,6 +624,76 @@ static const unsigned char chars[64][5] = { { 0020, 0050, 0104, 0202, 0000 }, /* 74 < */ { 0050, 0050, 0050, 0050, 0050 }, /* 75 = */ { 0000, 0202, 0104, 0050, 0020 }, /* 76 > */ + { 0100, 0200, 0236, 0220, 0140 }, /* 77 ? */ +/* + * NOT YET COMPLETE!!! + * original letterforms not available, using + * https://fontstruct.com/fontstructions/show/357807/5x7_monospaced_pixel_font + * PLB: I wonder if VT52 was 5x7???? + */ + { 0070, 0124, 0154, 0124, 0070 }, /* 00 blob */ + { 0070, 0204, 0204, 0050, 0274 }, /* 01 a needs fixing! */ + { 0377, 0050, 0204, 0204, 0070 }, /* 02 b needs fixing! */ + { 0070, 0204, 0204, 0204, 0050 }, /* 03 c needs fixing! */ + { 0376, 0202, 0202, 0202, 0174 }, /* 04 D */ + { 0376, 0222, 0222, 0222, 0222 }, /* 05 E */ + { 0376, 0220, 0220, 0220, 0220 }, /* 06 F */ + { 0174, 0202, 0222, 0222, 0134 }, /* 07 G */ + { 0376, 0020, 0020, 0020, 0376 }, /* 10 H */ + { 0000, 0202, 0376, 0202, 0000 }, /* 11 I */ + { 0004, 0002, 0002, 0002, 0374 }, /* 12 J */ + { 0376, 0020, 0050, 0104, 0202 }, /* 13 K */ + { 0376, 0002, 0002, 0002, 0002 }, /* 14 K */ + { 0376, 0100, 0040, 0100, 0376 }, /* 15 M */ + { 0376, 0100, 0040, 0020, 0376 }, /* 16 N */ + { 0174, 0202, 0202, 0202, 0174 }, /* 17 O */ + { 0376, 0220, 0220, 0220, 0140 }, /* 20 P */ + { 0174, 0202, 0212, 0206, 0176 }, /* 21 Q */ + { 0376, 0220, 0230, 0224, 0142 }, /* 22 R */ + { 0144, 0222, 0222, 0222, 0114 }, /* 23 S */ + { 0200, 0200, 0376, 0200, 0200 }, /* 24 T */ + { 0374, 0002, 0002, 0002, 0374 }, /* 25 U */ + { 0370, 0004, 0002, 0004, 0370 }, /* 26 V */ + { 0376, 0004, 0010, 0004, 0376 }, /* 27 W */ + { 0202, 0104, 0070, 0104, 0202 }, /* 30 X */ + { 0200, 0100, 0076, 0100, 0200 }, /* 31 Y */ + { 0226, 0232, 0222, 0262, 0322 }, /* 32 Z */ + { 0000, 0000, 0000, 0000, 0000 }, /* 33 LF */ + { 0000, 0000, 0000, 0000, 0000 }, /* 34 CR */ + { 0000, 0000, 0000, 0000, 0000 }, /* 35 HORIZ */ + { 0000, 0000, 0000, 0000, 0000 }, /* 36 VERT */ + { 0000, 0000, 0000, 0000, 0000 }, /* 37 ESC */ + { 0000, 0000, 0000, 0000, 0000 }, /* 40 space */ + { 0000, 0000, 0372, 0000, 0000 }, /* 41 ! */ + { 0000, 0340, 0000, 0340, 0000 }, /* 42 " */ + { 0050, 0376, 0050, 0376, 0050 }, /* 43 # */ + { 0144, 0222, 0376, 0222, 0114 }, /* 44 $ */ + { 0306, 0310, 0220, 0246, 0306 }, /* 45 % */ + { 0154, 0222, 0156, 0004, 0012 }, /* 46 & */ + { 0000, 0000, 0300, 0340, 0000 }, /* 47 ' */ + { 0070, 0104, 0202, 0000, 0000 }, /* 50 ( */ + { 0000, 0000, 0202, 0104, 0070 }, /* 51 ) */ + { 0124, 0070, 0174, 0070, 0124 }, /* 52 * */ + { 0020, 0020, 0174, 0020, 0020 }, /* 53 + */ + { 0000, 0014, 0016, 0000, 0000 }, /* 54 , */ + { 0020, 0020, 0020, 0020, 0020 }, /* 55 - */ + { 0000, 0006, 0006, 0000, 0000 }, /* 56 . */ + { 0004, 0010, 0020, 0040, 0100 }, /* 57 / */ + { 0174, 0212, 0222, 0242, 0174 }, /* 60 0 */ + { 0000, 0102, 0376, 0002, 0000 }, /* 61 1 */ + { 0116, 0222, 0222, 0222, 0142 }, /* 62 2 */ + { 0104, 0202, 0222, 0222, 0154 }, /* 63 3 */ + { 0020, 0060, 0120, 0376, 0020 }, /* 64 4 */ + { 0344, 0222, 0222, 0222, 0214 }, /* 65 5 */ + { 0174, 0222, 0222, 0222, 0114 }, /* 66 6 */ + { 0306, 0210, 0220, 0240, 0300 }, /* 67 7 */ + { 0154, 0222, 0222, 0222, 0154 }, /* 70 8 */ + { 0144, 0222, 0222, 0222, 0174 }, /* 71 9 */ + { 0000, 0066, 0066, 0000, 0000 }, /* 72 : */ + { 0000, 0154, 0156, 0000, 0000 }, /* 73 ; */ + { 0020, 0050, 0104, 0202, 0000 }, /* 74 < */ + { 0050, 0050, 0050, 0050, 0050 }, /* 75 = */ + { 0000, 0202, 0104, 0050, 0020 }, /* 76 > */ { 0100, 0200, 0236, 0220, 0140 } /* 77 ? */ }; @@ -529,178 +701,233 @@ static const unsigned char chars[64][5] = { * type 342 Character/Symbol generator for type 340 display * return true if ESCaped */ -static int -character(int n, char c) +int +character(int n, unsigned char c) { + struct type340 *u = UNIT(0); int x, y; + unsigned char s = u->scale; switch (c) { - case 033: /* LF */ - if (ypos < 12) { - status |= HEDGE; - ypos = 0; + case CHRLF: /* LF */ + u->ypos -= 12*s; + if (u->ypos < 0) { + u->status |= ST340_HEDGE; + u->ypos = 0; } - else - ypos -= 12; /* XXX scale? */ - return 0; - case 034: /* CR */ - xpos = 0; + case CHRCR: /* CR */ + u->xpos = 0; return 0; - case 035: /* shift in */ - shift = 1; + case CHRUC: /* "SHIFT IN (HORIZ)" */ + u->shift = 0; /* upper case in spcwac.163 */ return 0; - case 036: /* shift out */ - shift = 0; + case CHRLC: /* "SHIFT OUT (VERT)" */ + u->shift = 0100; /* lower case in spcwar.163 */ return 0; - case 037: /* escape */ - sequence = n; + case CHRESC: /* escape */ return 1; } - /* XXX plot character from character set selected by "shift" - * (offset index by 64?) - */ + /* plot character from character set selected by "shift" */ for (x = 0; x < 5; x++) { - for (y = 0; y < 7; y++) { - if (chars[c][x] & (1<shift][x] & (1<xpos+x*s, u->ypos+y*s, n); } } } - xpos += 7; /* XXX scale? */ - if (xpos > 1023) { - xpos = 1023; - status |= VEDGE; + u->xpos += 7*s; + if (u->xpos > 1023) { + u->xpos = 1023; + u->status |= ST340_VEDGE; } return 0; } +#endif -int -ty340_cycle(int us, int slowdown) +/* + * execute one type340 instruction + * returns status word + * (could return number of microseconds) + */ +ty340word +ty340_instruction(ty340word inst) { - ty340word inst, addr; - int i, escape, stopped; + struct type340 *u = UNIT(0); + int i, escape; +#ifdef TYPE347 + ty340word addr; +#endif - if (status & STOPPED) - return 0; /* XXX age display? */ + /* cleared by RFD */ + u->status &= ~(ST340_HEDGE|ST340_VEDGE); - inst = ty340_fetch(DAC); - DEBUGF(("%06o: %06o\r\n", DAC, inst)); - DAC++; + DEBUGF(("type340 mode %#o status %#o\r\n", u->mode, u->status)); + if (u->status & ST340_STOPPED) /* XXX LPINT as well??? */ + return u->status; escape = 0; - switch (mode) { + switch (u->mode) { case PARAM: - mode = GETFIELD(inst, 2, 4); + if (inst & 0600600) { /* curious to see if MIT hacked theirs */ + DEBUGF(("type340 reserved param bits set %#o\r\n", inst)); + } + /* READ TO MODE: */ + u->mode = GETFIELD(inst, 2, 4); if (TESTBIT(inst, 5)) { /* load l.p. enable */ - lp_ena = TESTBIT(inst,6); - DEBUGF(("lp_ena %d\r\n", lp_ena)); + u->lp_ena = TESTBIT(inst,6); + DEBUGF(("type340 lp_ena %d\r\n", u->lp_ena)); } + /* PM PULSE: */ + if (TESTBIT(inst, 14)) { + /* STORE INTENSITY: */ + u->intensity = GETFIELD(inst, 15, 17); + DEBUGF(("type340 set intensity %d\r\n", u->intensity)); + } + if (TESTBIT(inst, 11)) { + /* STORE SCALE: */ + u->scale = 1<scale)); + } if (TESTBIT(inst, 7)) { - status |= STOPPED; - if (TESTBIT(inst, 8)) - ty340_stop_int(); /* set stop_int_end? */ + u->status |= ST340_STOPPED; + DEBUGF(("type340 stop\r\n")); + if (TESTBIT(inst, 8)) { + DEBUGF(("type340 stop int\r\n")); + u->status |= ST340_STOP_INT; + } } - - if (TESTBIT(inst, 11)) - scale = GETFIELD(inst, 12, 13); - - if (TESTBIT(inst, 14)) - intensity = GETFIELD(inst, 15, 17); - break; case POINT: - mode = GETFIELD(inst, 2, 4); + u->mode = GETFIELD(inst, 2, 4); - if (TESTBIT(inst, 5)) /* load l.p. enable */ - lp_ena = TESTBIT(inst,6); + if (TESTBIT(inst, 5)) { /* load l.p. enable */ + u->lp_ena = TESTBIT(inst,6); + DEBUGF(("type340 lp_ena %d\r\n", u->lp_ena)); + } - if (TESTBIT(inst, 1)) - ypos = GETFIELD(inst, 8, 17); - else - xpos = GETFIELD(inst, 8, 17); - - if (TESTBIT(inst, 7)) - point(xpos, ypos, 0); + if (TESTBIT(inst, 1)) { + u->ypos = GETFIELD(inst, 8, 17); + DEBUGF(("type340 set u->ypos %d\r\n", u->ypos)); + } + else { + u->xpos = GETFIELD(inst, 8, 17); + DEBUGF(("type340 set xpos %d\r\n", u->xpos)); + } + if (TESTBIT(inst, 7)) { /* intensify */ + DEBUGF(("type340 point (%d,%d)\r\n", u->ypos, u->xpos)); + point(u->xpos, u->ypos, 0); + } break; case SLAVE: - mode = GETFIELD(inst, 2, 4); + DEBUGF(("type340 slave %06o\r\n", inst)); + u->mode = GETFIELD(inst, 2, 4); +#if TYPE343 + /* control multiple windows???? */ +#else + /* ..set the mode register and halt without requesting a new data word */ + u->status |= ST340_STOPPED; +#endif break; case CHAR: + DEBUGF(("type340 char %06o\r\n", inst)); +#if TYPE342 escape = (character(0, GETFIELD(inst, 0, 5)) || character(1, GETFIELD(inst, 6, 11)) || character(2, GETFIELD(inst, 12, 17))); +#else + /* what other missing options do: */ + u->status |= ST340_STOPPED; +#endif break; case VECTOR: + DEBUGF(("type340 vector %06o\r\n", inst)); escape = TESTBIT(inst, 0); if (vector(TESTBIT(inst, 1), TESTBIT(inst, 2), GETFIELD(inst, 3, 9), TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) { /* XXX interrupt? */ + escape = 1; } break; case VCONT: - escape = TESTBIT(inst, 0); - if (vector(TESTBIT(inst, 1), - TESTBIT(inst, 2), GETFIELD(inst, 3, 9), - TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) { - /* XXX set escape? */ - mode = PARAM; /* raster violation */ - } + DEBUGF(("type340 vcont %06o\r\n", inst)); + while (!vector(TESTBIT(inst, 1), + TESTBIT(inst, 2), GETFIELD(inst, 3, 9), + TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) + ; + escape = 1; /* XXX always???? */ + /* NOTE: NO INTERRUPT!! Clear conditions???? */ break; case INCR: - escape = TESTBIT(inst, 0); /* escape bit */ - i = TESTBIT(inst, 1); - + DEBUGF(("type340 incr %06o\r\n", inst)); + i = TESTBIT(inst, 1); /* intensify bit */ if (ipoint(i, 0, GETFIELD(inst, 2, 5)) || ipoint(i, 1, GETFIELD(inst, 6, 9)) || ipoint(i, 2, GETFIELD(inst, 10, 13)) || ipoint(i, 3, GETFIELD(inst, 14, 17))) - /* XXX set escape? */ - mode = PARAM; /* raster violation */ + escape = 1; + else if (TESTBIT(inst, 0)) /* escape bit */ + escape = 1; break; case SUBR: + DEBUGF(("type340 subr %06o\r\n", inst)); +#if TYPE347 /* type 347 Display Subroutine Option? */ - mode = GETFIELD(inst, 2, 4); - /* XXX take high bits of current DAC? */ + u->mode = GETFIELD(inst, 2, 4); addr = GETFIELD(inst, 5, 17); switch (GETFIELD(inst, 0, 1)) { case DJS: /* display jump and save */ - ASR = DAC; - save_ff = 1; /* set "save" flip-flop */ + u->ASR = u->DAC; + u->SAVE_FF = 1; /* set "save" flip-flop */ /* FALL */ case DJP: /* display jump */ - DAC = addr; + u->DAC = addr; break; case DDS: /* display deposit save register */ - ty340_deposit(addr, (DJP<<16) | ASR); - save_ff = 0; /* ?? */ + ty340_store(addr, (DJP<<16) | u->ASR); + /* clear SAVE_FF? */ break; default: /* XXX ??? */ break; } +#else /* no 347 */ + /* "halts without generating request for data or interrupt" */ + u->status |= ST340_STOPPED; +#endif break; } if (escape) { - mode = PARAM; - if (save_ff) { + u->mode = PARAM; +#if TYPE347 + if (u->SAVE_FF) { /* return from subroutine */ - DAC = ASR; - save_ff = 0; + u->DAC = u->ASR; + u->SAVE_FF = 0; } +#endif } - return status; -} /* ty340_cycle */ + if (!(u->status & ST340_STOPPED)) /* XXX LPINT as well??? */ + ty340_rfd(); /* ready for data */ + return u->status; +} /* ty340_instruction */ + +ty340word +ty340_status(void) +{ + struct type340 *u = UNIT(0); + return u->status; +} diff --git a/display/type340.h b/display/type340.h new file mode 100644 index 00000000..48291973 --- /dev/null +++ b/display/type340.h @@ -0,0 +1,60 @@ +/* + * external interface for type340.c + * Simulator Independent DEC Type 340 Graphic Display Processor Simulation + */ + +/* + * Copyright (c) 2018, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the author shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + +typedef unsigned int ty340word; + +/* + * Type340 status bits + * MUST BE EXACT SAME VALUES AS USED IN PDP-10 CONI!!! + */ +#define ST340_VEDGE 04000 +#define ST340_LPHIT 02000 +#define ST340_HEDGE 01000 +#define ST340_STOP_INT 00400 + +/* NOT same as PDP-10 CONI */ +#define ST340_STOPPED 0400000 + +/* + * calls from host into type340.c + */ +ty340word ty340_reset(void); +ty340word ty340_status(void); +ty340word ty340_instruction(ty340word inst); +void ty340_set_dac(ty340word addr); + +/* + * calls from type340.c into host simulator + */ +extern ty340word ty340_fetch(ty340word); +extern void ty340_store(ty340word, ty340word); +extern void ty340_lp_int(ty340word x, ty340word y); +extern void ty340_rfd(void); diff --git a/display/type340cmd.h b/display/type340cmd.h new file mode 100644 index 00000000..a9ee9ff5 --- /dev/null +++ b/display/type340cmd.h @@ -0,0 +1,177 @@ +/* + * constants for type 340 words + * (use for writing test programs) + */ + +/* + * Copyright (c) 2018, Philip L. Budne + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the author shall + * not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization + * from the authors. + */ + + +#define CHAR(C1,C2,C3) \ + (((C1)<<12)|((C2)<<6)|(C3)) + +#define INCRPT(P1,P2,P3,P4) (((P1)<<12)|((P2)<<8)|((P3)<<4)|(P4)) + +/* + * adapted from + * 7-13_340_Display_Programming_Manual.pdf + * Appendix 1: Mnemonics + * + * tst340.c dump() routine uses/prints these + */ + +/* modes: */ +#define MPAR 0000000 /* parameter */ +#define MPT 0020000 /* point */ +#define MSLV 0040000 /* slave */ +#define MCHR 0060000 /* character */ +#define MVCT 0100000 /* Vector */ +#define MVCTC 0120000 /* Vector continue */ +#define MINCR 0140000 /* Increment */ +#define MSUBR 0160000 /* Subroutine */ + +#define MODEMASK 0160000 + +/**************** + * Parameter Mode Words + */ + +#define LPON 014000 +#define LPOFF 010000 + +#define STP 0003000 /* stop & interrupt */ +#define STOP 0001000 /* just stop: not in display manual */ + +/* scale settings */ +#define S0 0000100 +#define S1 0000120 +#define S2 0000140 +#define S3 0000160 + +/* intensity settings */ +#define IN0 0000010 +#define IN1 0000011 +#define IN2 0000012 +#define IN3 0000013 +#define IN4 0000014 +#define IN5 0000015 +#define IN6 0000016 +#define IN7 0000017 + +/**************** + * Point Mode Words + */ + +#define V 0200000 /* Vertical word */ +#define H 0000000 /* Horizontal word */ +#define IP 0002000 /* Intensify point */ + +/**************** + * Slave Mode Words + */ + +#define S1ON 05000 +#define S1OFF 04000 +#define LP1ON 02000 + +#define S2ON 0500 +#define S2OFF 0400 +#define LP2ON 0200 + +#define S3ON 050 +#define S3OFF 040 +#define LP3ON 020 + +#define S4ON 05 +#define S4OFF 04 +#define LP4ON 02 + +// for use in XXX macro: +#define SXON 05 +#define SXOFF 04 +#define LPXON 02 + +/**************** + * Character mode + */ + +/* defines from ITS: 340def 4 */ +#define CHRESC 037 /* escape from character mode */ +#define CHRUC 035 /* shift to upper-case */ +#define CHRLC 036 /* " " lower-case */ +#define CHRLF 033 /* line-feed */ +#define CHRCR 034 /* carriage-return */ +#define CHRSP 040 /* space (identity!) */ + +/**************** + * Vector and Vector Continue Words + */ + +#define ESCP 0400000 /* Escape */ +#define INSFY 0200000 /* Intensify */ + +/** y position */ + +#define DN 0100000 /* Down */ +#define UP 0000000 /* Up */ + +/* number of points moved */ +#define YP64 0040000 +#define YP32 0020000 +#define YP16 0010000 +#define YP8 0004000 +#define YP4 0002000 +#define YP2 0001000 +#define YP1 0000400 + +/** x position */ +#define LT 0000200 /* Left */ +#define RT 0000000 /* Right */ + +#define XP64 0000100 +#define XP32 0000040 +#define XP16 0000020 +#define XP8 0000010 +#define XP4 0000004 +#define XP2 0000002 +#define XP1 0000001 + +/**************** + * increment + */ + +#define PR 010 +#define PL 014 +#define PU 002 +#define PD 003 + +#define PUL (PU|PL) +#define PUR (PU|PR) + +#define PDL (PD|PL) +#define PDR (PD|PR) + +/* INSFY and ESCP from vector modes */ diff --git a/display/vttest.c b/display/vttest.c index 2deb2ace..4922693d 100644 --- a/display/vttest.c +++ b/display/vttest.c @@ -1295,7 +1295,7 @@ main(void) { puts("initial tests work for both VT11 and VS60"); for (df = VT, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ + vt11_reset(NULL, 0); /* reset everything */ vt11_set_dpc(start); /* start section */ c = 0; while (vt11_cycle(USEC, 1)) { @@ -1315,7 +1315,7 @@ main(void) { puts("move the light pen through the tracking object"); fflush(stdout); for (df = LP, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ + vt11_reset(NULL, 0); /* reset everything */ vt11_set_dpc(start); /* start section */ c = 0; while (vt11_cycle(USEC, 1)) { @@ -1335,7 +1335,7 @@ main(void) { ws_beep(); puts("following tests require VS60"); for (df = VS, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ + vt11_reset(NULL, 0); /* reset everything */ vt11_set_str((uint16)(0200 | '~')); /* set terminating char. */ vt11_set_anr((uint16)(040000 | (2<<12) | 04000 | 01234)); /* set associative name 0123x */ @@ -1358,7 +1358,7 @@ main(void) { fflush(stdout); wf_update(1); /* do first-time init */ for (df = WF, start = 0, more = 1; more; ) { - vt11_reset(); /* reset everything */ + vt11_reset(NULL, 0); /* reset everything */ vt11_set_dpc(start); /* start section */ c = 0; while (vt11_cycle(USEC, 1)) { diff --git a/display/x11.c b/display/x11.c index 1a09d552..7d83c437 100644 --- a/display/x11.c +++ b/display/x11.c @@ -13,7 +13,7 @@ */ /* - * Copyright (c) 2003-2004, Philip L. Budne + * Copyright (c) 2003-2018, Philip L. Budne * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -38,6 +38,10 @@ * from the authors. */ +#ifndef USE_XKB +#define USE_XKB 1 +#endif + #include #include #include @@ -51,6 +55,9 @@ #include #include #include +#ifdef USE_XKB +#include +#endif #include #include @@ -155,6 +162,55 @@ handle_button_release(w, d, e, b) *b = TRUE; } +/* + * map keyboard XEvent to 8 bit char or -1 + */ +static int +mapkey(e) + XEvent *e; +{ + int shift = (ShiftMask & e->xkey.state) != 0; + KeySym key; + +#ifdef USE_XKB + /* + * X Keyboard Extension + * described in + * https://www.x.org/releases/X11R7.7/doc/libX11/XKB/xkblib.html#Xkb_Keyboard_Extension_Support_for_Keyboards + * copyright 1995, 1996 + * + * use XkbLibraryVersion and/or XkbQueryExtension + * to determine if available??? + */ + key = XkbKeycodeToKeysym(dpy, e->xkey.keycode, 0, shift); +#elif 1 + /* + * documented in + * Xlib: C Language X Interface (X Version 11, Release 4) + * copyright 1989 + */ + int keysyms_per_keycode_return; + KeySym *keysyms = XGetKeyboardMapping(dpy, + e->xkey.keycode, + 1, + &keysyms_per_keycode_return); + key = keysyms[0]; + XFree(keysyms); +#else /* just in case... */ + /* XKeycodeToKeysym deprecated */ + key = XKeycodeToKeysym(dpy, e->xkey.keycode, shift); +#endif + + if ((key & 0xff00) == 0) + return key & 0xff; + + switch (key) { + case XK_Return: return '\r'; + } + /* printf("ignoring keycode %#x\r\n", key); /**/ + return -1; +} + static void handle_key_press(w, d, e, b) Widget w; @@ -162,12 +218,9 @@ handle_key_press(w, d, e, b) XEvent *e; Boolean *b; { - int shift = (ShiftMask & e->xkey.state) != 0; - KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift ); - - /*printf("key %d down\n", key); fflush(stdout);*/ - if ((key & 0xff00) == 0) - display_keydown(key); + int k = mapkey(e); + if (k >= 0) + display_keydown(k); if (b) *b = TRUE; @@ -180,12 +233,9 @@ handle_key_release(w, d, e, b) XEvent *e; Boolean *b; { - int shift = (ShiftMask & e->xkey.state) != 0; - KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift ); - - /*printf("key %d up\n", key); fflush(stdout);*/ - if ((key & 0xff00) == 0) - display_keyup(key); + int k = mapkey(e); + if (k >= 0) + display_keyup(k); if (b) *b = TRUE; @@ -216,7 +266,9 @@ ws_init(const char *crtname, /* crt type name */ int argc; char *argv[1]; int height, width; - +#ifdef USE_XKB + Bool supported; +#endif xpixels = xp; /* save screen size */ ypixels = yp; @@ -227,6 +279,16 @@ ws_init(const char *crtname, /* crt type name */ dpy = XtOpenDisplay( app_context, NULL, NULL, crtname, NULL, 0, &argc, argv); +#ifdef USE_XKB + /* + * suppress synthetic key up events from autorepeat + * (will still see repeated down events) + * see keymap function for XKb history + */ + supported = False; + (void) XkbSetDetectableAutoRepeat(dpy, True, &supported); +#endif + scr = DefaultScreen(dpy); crtshell = XtAppCreateShell( crtname, /* app name */