mirror of
https://github.com/open-simh/simh.git
synced 2026-01-11 23:53:30 +00:00
1035 lines
36 KiB
C
1035 lines
36 KiB
C
/*
|
||
* wrap, or clip?
|
||
* skip vector points when scaling?
|
||
* are scaled character sizes right??
|
||
*/
|
||
|
||
/*
|
||
* $Id: type340.c,v 1.6 2005/01/14 18:58:00 phil Exp $
|
||
* Simulator Independent DEC Type 340 Graphic Display Processor Simulation
|
||
* Phil Budne <phil@ultimate.com>
|
||
* September 20, 2003
|
||
* from vt11.c
|
||
*
|
||
* 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-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.
|
||
*/
|
||
|
||
#include "display.h" /* XY plot interface */
|
||
#include "type340.h" /* interface definitions */
|
||
#include "type340cmd.h" /* 340 command definitions */
|
||
|
||
/*
|
||
* 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 */
|
||
#define FIELDMASK(START,END) ((1<<((END)-(START)+1))-1)
|
||
|
||
/* extract a field */
|
||
#define GETFIELD(W,START,END) (((W)>>(17-(END)))&FIELDMASK(START,END))
|
||
|
||
/* extract a 1-bit field */
|
||
#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0)
|
||
|
||
#ifdef DEBUG_TY340
|
||
#include <stdio.h>
|
||
#define DEBUGF(X) printf X
|
||
#else
|
||
#define DEBUGF(X)
|
||
#endif
|
||
enum mode { PARAM=0, POINT, SLAVE, CHAR, VECTOR, VCONT, INCR, SUBR };
|
||
|
||
#define TY340_UNITS 1
|
||
|
||
enum jump_type { DJP=2, DJS=3, DDS=1 }; /* type 347 */
|
||
|
||
/* Codes for special characters. */
|
||
#define CH_LF 0001 /* Line feed. */
|
||
#define CH_CR 0002 /* Carriage return. */
|
||
#define CH_UC 0003 /* Shift in. */
|
||
#define CH_LC 0004 /* Shift out. */
|
||
#define CH_ESC 0005 /* Escape to parameter mode. */
|
||
#define CH_NSPC 0006 /* Non spacing. */
|
||
#define CH_D 0007 /* Descender. */
|
||
#define CH_BS 0010 /* Backspace. */
|
||
#define CH_SUB 0011 /* Subscript. */
|
||
#define CH_SUP 0012 /* Superscript. */
|
||
|
||
/* 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 */
|
||
unsigned char width; /* character grid width */
|
||
unsigned char height; /* character grid height */
|
||
#endif
|
||
#if TYPE347
|
||
ty340word ASR; /* Address Save Register */
|
||
unsigned char SAVE_FF; /* "save" flip-flop */
|
||
#endif
|
||
} u340[TY340_UNITS];
|
||
|
||
#if TY340_UNITS == 1
|
||
#define UNIT(N) u340
|
||
#else
|
||
#define UNIT(N) (u340+(N))
|
||
#endif
|
||
|
||
/* NOT USED WITH PDP-6 Type 344 Interface!! */
|
||
void
|
||
ty340_set_dac(ty340word addr)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
u->DAC = addr;
|
||
DEBUGF(("set DAC %06o\r\n", u->DAC));
|
||
|
||
/* XXX only when reset? */
|
||
u->mode = PARAM;
|
||
u->status = 0; /* XXX just clear stopped? */
|
||
ty340_rfd(); /* ready for data */
|
||
}
|
||
|
||
void
|
||
ty340_cycle(void)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
|
||
if (u->status == 0) {
|
||
ty340word insn = ty340_fetch(u->DAC);
|
||
u->status = ty340_instruction (insn);
|
||
u->DAC = (u->DAC + 1) & 07777;
|
||
}
|
||
}
|
||
|
||
ty340word
|
||
ty340_get_dac(void)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
return u->DAC;
|
||
}
|
||
|
||
ty340word
|
||
ty340_get_asr(void)
|
||
{
|
||
#if TYPE347
|
||
struct type340 *u = UNIT(0);
|
||
return u->ASR;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
ty340word
|
||
ty340_sense(ty340word flags)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
return u->status & flags;
|
||
}
|
||
|
||
void
|
||
ty340_clear(ty340word flags)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
u->status &= ~flags;
|
||
}
|
||
|
||
ty340word
|
||
ty340_reset(void *dptr)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
#ifndef TY340_NODISPLAY
|
||
if (!u->initialized) {
|
||
display_init(DIS_TYPE340, 1, dptr); /* XXX check return? */
|
||
u->initialized = 1;
|
||
}
|
||
#endif
|
||
u->xpos = u->ypos = 0;
|
||
u->mode = PARAM;
|
||
u->status = 0;
|
||
u->scale = 1;
|
||
#if TYPE342
|
||
u->shift = 0;
|
||
u->width = 6;
|
||
u->height = 11;
|
||
#endif
|
||
#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;
|
||
|
||
#ifdef TYPE340_POINT
|
||
DEBUGF(("type340 point %d %d %d\r\n", x, y, seq));
|
||
#endif
|
||
|
||
i = DISPLAY_INT_MAX-7+u->intensity;
|
||
if (i <= 0)
|
||
i = 1;
|
||
|
||
if (x < 0 || x > 1023) {
|
||
/* XXX clip? wrap?? */
|
||
u->status |= ST340_VEDGE;
|
||
return 0;
|
||
}
|
||
if (y < 0 || y > 1023) {
|
||
/* XXX clip? wrap?? */
|
||
u->status |= ST340_HEDGE;
|
||
return 0;
|
||
}
|
||
|
||
#ifndef TY340_NODISPLAY
|
||
if (display_point(x, y, i, 0)) {
|
||
/*
|
||
* 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);
|
||
}
|
||
|
||
/*
|
||
* two-step algorithm, developed by Xiaolin Wu
|
||
* from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html
|
||
*/
|
||
|
||
/*
|
||
* The two-step algorithm takes the interesting approach of treating
|
||
* line drawing as a automaton, or finite state machine. If one looks
|
||
* at the possible configurations for the next two pixels of a line,
|
||
* it is easy to see that only a finite set of possibilities exist.
|
||
* The two-step algorithm shown here also exploits the symmetry of
|
||
* line-drawing by simultaneously drawn from both ends towards the
|
||
* midpoint.
|
||
*/
|
||
|
||
static void
|
||
lineTwoStep(int x0, int y0, int x1, int y1)
|
||
{
|
||
int dy = y1 - y0;
|
||
int dx = x1 - x0;
|
||
int stepx, stepy;
|
||
|
||
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
|
||
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
|
||
|
||
lpoint(x0,y0);
|
||
if (dx == 0 && dy == 0) /* following algorithm won't work */
|
||
return; /* just the one dot */
|
||
lpoint(x1, y1);
|
||
if (dx > dy) {
|
||
int length = (dx - 1) >> 2;
|
||
int extras = (dx - 1) & 3;
|
||
int incr2 = (dy << 2) - (dx << 1);
|
||
if (incr2 < 0) {
|
||
int c = dy << 1;
|
||
int incr1 = c << 1;
|
||
int d = incr1 - dx;
|
||
int i;
|
||
|
||
for (i = 0; i < length; i++) {
|
||
x0 += stepx;
|
||
x1 -= stepx;
|
||
if (d < 0) { /* Pattern: */
|
||
lpoint(x0, y0);
|
||
lpoint(x0 += stepx, y0); /* x o o */
|
||
lpoint(x1, y1);
|
||
lpoint(x1 -= stepx, y1);
|
||
d += incr1;
|
||
}
|
||
else {
|
||
if (d < c) { /* Pattern: */
|
||
lpoint(x0, y0); /* o */
|
||
lpoint(x0 += stepx, y0 += stepy); /* x o */
|
||
lpoint(x1, y1);
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
} else {
|
||
lpoint(x0, y0 += stepy); /* Pattern: */
|
||
lpoint(x0 += stepx, y0); /* o o */
|
||
lpoint(x1, y1 -= stepy); /* x */
|
||
lpoint(x1 -= stepx, y1);
|
||
}
|
||
d += incr2;
|
||
}
|
||
}
|
||
if (extras > 0) {
|
||
if (d < 0) {
|
||
lpoint(x0 += stepx, y0);
|
||
if (extras > 1) lpoint(x0 += stepx, y0);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1);
|
||
} else
|
||
if (d < c) {
|
||
lpoint(x0 += stepx, y0);
|
||
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1);
|
||
} else {
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 1) lpoint(x0 += stepx, y0);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
|
||
}
|
||
}
|
||
} else {
|
||
int c = (dy - dx) << 1;
|
||
int incr1 = c << 1;
|
||
int d = incr1 + dx;
|
||
int i;
|
||
for (i = 0; i < length; i++) {
|
||
x0 += stepx;
|
||
x1 -= stepx;
|
||
if (d > 0) {
|
||
lpoint(x0, y0 += stepy); /* Pattern: */
|
||
lpoint(x0 += stepx, y0 += stepy); /* o */
|
||
lpoint(x1, y1 -= stepy); /* o */
|
||
lpoint(x1 -= stepx, y1 -= stepy); /* x */
|
||
d += incr1;
|
||
} else {
|
||
if (d < c) {
|
||
lpoint(x0, y0); /* Pattern: */
|
||
lpoint(x0 += stepx, y0 += stepy); /* o */
|
||
lpoint(x1, y1); /* x o */
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
} else {
|
||
lpoint(x0, y0 += stepy); /* Pattern: */
|
||
lpoint(x0 += stepx, y0); /* o o */
|
||
lpoint(x1, y1 -= stepy); /* x */
|
||
lpoint(x1 -= stepx, y1);
|
||
}
|
||
d += incr2;
|
||
}
|
||
}
|
||
if (extras > 0) {
|
||
if (d > 0) {
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
|
||
} else if (d < c) {
|
||
lpoint(x0 += stepx, y0);
|
||
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1);
|
||
} else {
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 1) lpoint(x0 += stepx, y0);
|
||
if (extras > 2) {
|
||
if (d > c)
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
else
|
||
lpoint(x1 -= stepx, y1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
int length = (dy - 1) >> 2;
|
||
int extras = (dy - 1) & 3;
|
||
int incr2 = (dx << 2) - (dy << 1);
|
||
if (incr2 < 0) {
|
||
int c = dx << 1;
|
||
int incr1 = c << 1;
|
||
int d = incr1 - dy;
|
||
int i;
|
||
for (i = 0; i < length; i++) {
|
||
y0 += stepy;
|
||
y1 -= stepy;
|
||
if (d < 0) {
|
||
lpoint(x0, y0);
|
||
lpoint(x0, y0 += stepy);
|
||
lpoint(x1, y1);
|
||
lpoint(x1, y1 -= stepy);
|
||
d += incr1;
|
||
} else {
|
||
if (d < c) {
|
||
lpoint(x0, y0);
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
lpoint(x1, y1);
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
} else {
|
||
lpoint(x0 += stepx, y0);
|
||
lpoint(x0, y0 += stepy);
|
||
lpoint(x1 -= stepx, y1);
|
||
lpoint(x1, y1 -= stepy);
|
||
}
|
||
d += incr2;
|
||
}
|
||
}
|
||
if (extras > 0) {
|
||
if (d < 0) {
|
||
lpoint(x0, y0 += stepy);
|
||
if (extras > 1) lpoint(x0, y0 += stepy);
|
||
if (extras > 2) lpoint(x1, y1 -= stepy);
|
||
} else
|
||
if (d < c) {
|
||
lpoint(x0, y0 += stepy);
|
||
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 2) lpoint(x1, y1 -= stepy);
|
||
} else {
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 1) lpoint(x0, y0 += stepy);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
|
||
}
|
||
}
|
||
} else {
|
||
int c = (dx - dy) << 1;
|
||
int incr1 = c << 1;
|
||
int d = incr1 + dy;
|
||
int i;
|
||
for (i = 0; i < length; i++) {
|
||
y0 += stepy;
|
||
y1 -= stepy;
|
||
if (d > 0) {
|
||
lpoint(x0 += stepx, y0);
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
lpoint(x1 -= stepx, y1);
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
d += incr1;
|
||
} else {
|
||
if (d < c) {
|
||
lpoint(x0, y0);
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
lpoint(x1, y1);
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
} else {
|
||
lpoint(x0 += stepx, y0);
|
||
lpoint(x0, y0 += stepy);
|
||
lpoint(x1 -= stepx, y1);
|
||
lpoint(x1, y1 -= stepy);
|
||
}
|
||
d += incr2;
|
||
}
|
||
}
|
||
if (extras > 0) {
|
||
if (d > 0) {
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
|
||
} else if (d < c) {
|
||
lpoint(x0, y0 += stepy);
|
||
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 2) lpoint(x1, y1 -= stepy);
|
||
} else {
|
||
lpoint(x0 += stepx, y0 += stepy);
|
||
if (extras > 1) lpoint(x0, y0 += stepy);
|
||
if (extras > 2) {
|
||
if (d > c)
|
||
lpoint(x1 -= stepx, y1 -= stepy);
|
||
else
|
||
lpoint(x1, y1 -= stepy);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} /* lineTwoStep */
|
||
|
||
/* 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 = 0;
|
||
|
||
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 * u->scale;
|
||
if (x1 < 0) {
|
||
x1 = 0;
|
||
flags = ST340_HEDGE;
|
||
}
|
||
}
|
||
else {
|
||
x1 = x0 + dx * u->scale;
|
||
if (x1 > 1023) {
|
||
x1 = 1023;
|
||
flags = ST340_HEDGE;
|
||
}
|
||
}
|
||
|
||
if (sy) {
|
||
y1 = y0 - dy * u->scale;
|
||
if (y1 < 0) {
|
||
y1 = 0;
|
||
flags |= ST340_VEDGE;
|
||
}
|
||
}
|
||
else {
|
||
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) /* XXX need OLD value??? */
|
||
lineTwoStep(x0, y0, x1, y1);
|
||
|
||
u->xpos = x1;
|
||
u->ypos = y1;
|
||
u->status |= flags; /* ?? */
|
||
return flags;
|
||
}
|
||
|
||
/*
|
||
* 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) { /* left */
|
||
u->xpos -= u->scale;
|
||
if (u->xpos < 0) {
|
||
u->xpos = 0; /* XXX wrap? */
|
||
u->status |= ST340_VEDGE; /* save flags & continue?? */
|
||
return 1; /* escape */
|
||
}
|
||
}
|
||
else { /* right */
|
||
u->xpos += u->scale;
|
||
if (u->xpos > 1023) {
|
||
u->xpos = 1023; /* XXX wrap? */
|
||
u->status |= ST340_VEDGE;
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
if (byte & 02) { /* up/down */
|
||
if (byte & 01) { /* down */
|
||
u->ypos -= u->scale;
|
||
if (u->ypos < 0) {
|
||
u->ypos = 0; /* XXX wrap? */
|
||
u->status |= ST340_HEDGE;
|
||
return 1;
|
||
}
|
||
}
|
||
else {
|
||
u->ypos += u->scale;
|
||
if (u->ypos > 1023) {
|
||
u->ypos = 1023; /* XXX wrap? */
|
||
u->status |= ST340_HEDGE;
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
if (i)
|
||
point(u->xpos, u->ypos, n);
|
||
|
||
return 0; /* no escape */
|
||
}
|
||
|
||
#if TYPE342
|
||
/*
|
||
* 342 character generator - first 64 characters
|
||
* 7-13_340_Display_Programming_Manual.pdf p.24
|
||
* each char contains a vertical stripe of the matrix.
|
||
* highest bit is top, lowest bit is unused (what was I drinking? -PLB)
|
||
* first char is leftmost
|
||
*/
|
||
static const unsigned char chars[128][6] = {
|
||
{ 0070, 0124, 0154, 0124, 0070, 0 }, /* 00 blob */
|
||
{ 0176, 0220, 0220, 0220, 0176, 0 }, /* 01 A */
|
||
{ 0376, 0222, 0222, 0222, 0154, 0 }, /* 02 B */
|
||
{ 0174, 0202, 0202, 0202, 0104, 0 }, /* 03 C */
|
||
{ 0376, 0202, 0202, 0202, 0174, 0 }, /* 04 D */
|
||
{ 0376, 0222, 0222, 0222, 0222, 0 }, /* 05 E */
|
||
{ 0376, 0220, 0220, 0220, 0220, 0 }, /* 06 F */
|
||
{ 0174, 0202, 0222, 0222, 0134, 0 }, /* 07 G */
|
||
{ 0376, 0020, 0020, 0020, 0376, 0 }, /* 10 H */
|
||
{ 0000, 0202, 0376, 0202, 0000, 0 }, /* 11 I */
|
||
{ 0004, 0002, 0002, 0002, 0374, 0 }, /* 12 J */
|
||
{ 0376, 0020, 0050, 0104, 0202, 0 }, /* 13 K */
|
||
{ 0376, 0002, 0002, 0002, 0002, 0 }, /* 14 L */
|
||
{ 0376, 0100, 0040, 0100, 0376, 0 }, /* 15 M */
|
||
{ 0376, 0100, 0040, 0020, 0376, 0 }, /* 16 N */
|
||
{ 0174, 0202, 0202, 0202, 0174, 0 }, /* 17 O */
|
||
{ 0376, 0220, 0220, 0220, 0140, 0 }, /* 20 P */
|
||
{ 0174, 0202, 0212, 0206, 0176, 0 }, /* 21 Q */
|
||
{ 0376, 0220, 0230, 0224, 0142, 0 }, /* 22 R */
|
||
{ 0144, 0222, 0222, 0222, 0114, 0 }, /* 23 S */
|
||
{ 0200, 0200, 0376, 0200, 0200, 0 }, /* 24 T */
|
||
{ 0374, 0002, 0002, 0002, 0374, 0 }, /* 25 U */
|
||
{ 0370, 0004, 0002, 0004, 0370, 0 }, /* 26 V */
|
||
{ 0376, 0004, 0010, 0004, 0376, 0 }, /* 27 W */
|
||
{ 0202, 0104, 0070, 0104, 0202, 0 }, /* 30 X */
|
||
{ 0200, 0100, 0076, 0100, 0200, 0 }, /* 31 Y */
|
||
{ 0226, 0232, 0222, 0262, 0322, 0 }, /* 32 Z */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_LF }, /* 33 LF */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_CR }, /* 34 CR */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_UC }, /* 35 HORIZ */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_LC }, /* 36 VERT */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_ESC }, /* 37 ESC */
|
||
{ 0000, 0000, 0000, 0000, 0000, 0 }, /* 40 space */
|
||
{ 0000, 0000, 0372, 0000, 0000, 0 }, /* 41 ! */
|
||
{ 0000, 0340, 0000, 0340, 0000, 0 }, /* 42 " */
|
||
{ 0050, 0376, 0050, 0376, 0050, 0 }, /* 43 # */
|
||
{ 0144, 0222, 0376, 0222, 0114, 0 }, /* 44 $ */
|
||
{ 0306, 0310, 0220, 0246, 0306, 0 }, /* 45 % */
|
||
{ 0154, 0222, 0156, 0004, 0012, 0 }, /* 46 & */
|
||
{ 0000, 0000, 0300, 0340, 0000, 0 }, /* 47 ' */
|
||
{ 0000, 0070, 0104, 0202, 0000, 0 }, /* 50 ( Source: AI film 104 */
|
||
{ 0000, 0202, 0104, 0070, 0000, 0 }, /* 51 ) Source: AI film 104 */
|
||
{ 0104, 0050, 0174, 0050, 0104, 0 }, /* 52 * Source: AI film */
|
||
{ 0020, 0020, 0174, 0020, 0020, 0 }, /* 53 + */
|
||
{ 0000, 0032, 0034, 0000, 0000, 0 }, /* 54 , Source: AI film 104 */
|
||
{ 0020, 0020, 0020, 0020, 0020, 0 }, /* 55 - */
|
||
{ 0000, 0006, 0006, 0000, 0000, 0 }, /* 56 . */
|
||
{ 0004, 0010, 0020, 0040, 0100, 0 }, /* 57 / */
|
||
{ 0174, 0212, 0222, 0242, 0174, 0 }, /* 60 0 */
|
||
{ 0000, 0102, 0376, 0002, 0000, 0 }, /* 61 1 */
|
||
{ 0116, 0222, 0222, 0222, 0142, 0 }, /* 62 2 */
|
||
{ 0104, 0202, 0222, 0222, 0154, 0 }, /* 63 3 */
|
||
{ 0020, 0060, 0120, 0376, 0020, 0 }, /* 64 4 */
|
||
{ 0344, 0222, 0222, 0222, 0214, 0 }, /* 65 5 */
|
||
{ 0174, 0222, 0222, 0222, 0114, 0 }, /* 66 6 */
|
||
{ 0306, 0210, 0220, 0240, 0300, 0 }, /* 67 7 */
|
||
{ 0154, 0222, 0222, 0222, 0154, 0 }, /* 70 8 */
|
||
{ 0144, 0222, 0222, 0222, 0174, 0 }, /* 71 9 */
|
||
{ 0000, 0066, 0066, 0000, 0000, 0 }, /* 72 : */
|
||
{ 0000, 0332, 0334, 0000, 0000, 0 }, /* 73 ; Source: consistent with , */
|
||
{ 0020, 0050, 0104, 0202, 0000, 0 }, /* 74 < */
|
||
{ 0050, 0050, 0050, 0050, 0050, 0 }, /* 75 = */
|
||
{ 0000, 0202, 0104, 0050, 0020, 0 }, /* 76 > */
|
||
{ 0100, 0200, 0236, 0220, 0140, 0 }, /* 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????
|
||
*
|
||
* Lars Brinkhoff: I added new shapes from AI lab film footage, and
|
||
* from the Knight TV font.
|
||
*/
|
||
{ 0070, 0124, 0154, 0124, 0070, 0 }, /* 00 blob */
|
||
{ 0034, 0042, 0042, 0074, 0002, 0 }, /* 01 a Source: AI film 75 */
|
||
{ 0376, 0042, 0042, 0042, 0034, 0 }, /* 02 b Source: AI film 75 */
|
||
{ 0034, 0042, 0042, 0042, 0024, 0 }, /* 03 c */
|
||
{ 0034, 0042, 0042, 0042, 0376, 0 }, /* 04 d Source: AI film 75 */
|
||
{ 0034, 0052, 0052, 0052, 0030, 0 }, /* 05 e Source: AI film 75 */
|
||
{ 0020, 0176, 0220, 0200, 0100, 0 }, /* 06 f Source: Knight TV */
|
||
{ 0160, 0212, 0212, 0212, 0174, CH_D },/* 07 g Source: AI film 75 */
|
||
{ 0376, 0040, 0040, 0040, 0036, 0 }, /* 10 h Source: AI film 75 */
|
||
{ 0000, 0042, 0276, 0002, 0000, 0 }, /* 11 i Source: AI film 75 */
|
||
{ 0000, 0004, 0042, 0274, 0000, 0 }, /* 12 j */
|
||
{ 0376, 0010, 0030, 0044, 0002, 0 }, /* 13 k Source: AI film 75 */
|
||
{ 0000, 0202, 0376, 0002, 0000, 0 }, /* 14 l Source: AI film 75 */
|
||
{ 0076, 0040, 0036, 0040, 0036, 0 }, /* 15 m */
|
||
{ 0076, 0020, 0040, 0040, 0036, 0 }, /* 16 n Source: AI film 75 */
|
||
{ 0034, 0042, 0042, 0042, 0034, 0 }, /* 17 o Source: AI film 75 */
|
||
{ 0376, 0210, 0210, 0210, 0160, CH_D },/* 20 p Source: Knight TV */
|
||
{ 0160, 0210, 0210, 0210, 0376, CH_D },/* 21 q Source: Knight TV */
|
||
{ 0076, 0020, 0040, 0040, 0020, 0 }, /* 22 r Source: AI film 75 */
|
||
{ 0022, 0052, 0052, 0052, 0044, 0 }, /* 23 s */
|
||
{ 0040, 0374, 0042, 0002, 0004, 0 }, /* 24 t Source: AI film 75 */
|
||
{ 0074, 0002, 0002, 0004, 0076, 0 }, /* 25 u Source: AI film 75 */
|
||
{ 0070, 0004, 0002, 0004, 0070, 0 }, /* 26 v Source: Knight TV */
|
||
{ 0074, 0002, 0034, 0002, 0074, 0 }, /* 27 w Source: AI film 75 */
|
||
{ 0042, 0024, 0010, 0024, 0042, 0 }, /* 30 x */
|
||
{ 0360, 0012, 0012, 0012, 0374, CH_D },/* 31 y Source: AI film 75 */
|
||
{ 0042, 0056, 0052, 0072, 0042, 0 }, /* 32 z Source: Knight TV */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_LF }, /* 33 LF */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_CR }, /* 34 CR */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_UC }, /* 35 HORIZ */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_LC }, /* 36 VERT */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_ESC }, /* 37 ESC */
|
||
{ 0000, 0000, 0000, 0000, 0000, 0 }, /* 40 space */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 41 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 42 ??? */
|
||
{ 0100, 0200, 0100, 0040, 0100, 0 }, /* 43 ~ */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 44 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 45 ??? */
|
||
{ 0040, 0100, 0376, 0100, 0040, 0 }, /* 46 up arrow */
|
||
{ 0020, 0020, 0124, 0070, 0020, 0 }, /* 47 left arrow */
|
||
{ 0010, 0004, 0376, 0004, 0010, 0 }, /* 50 down arrow */
|
||
{ 0020, 0070, 0124, 0020, 0020, 0 }, /* 51 right arrow */
|
||
{ 0100, 0040, 0020, 0010, 0004, 0 }, /* 52 \ */
|
||
{ 0000, 0376, 0202, 0202, 0000, 0 }, /* 53 [ */
|
||
{ 0000, 0202, 0202, 0376, 0000, 0 }, /* 54 ] */
|
||
{ 0000, 0020, 0154, 0202, 0000, 0 }, /* 55 { */
|
||
{ 0000, 0202, 0154, 0020, 0000, 0 }, /* 56 } */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 57 ??? */
|
||
{ 0002, 0002, 0002, 0002, 0002, 0 }, /* 60 _ */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 61 ??? */
|
||
{ 0000, 0000, 0376, 0000, 0000, 0 }, /* 62 | */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 63 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 64 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 65 ??? */
|
||
{ 0000, 0200, 0100, 0040, 0000, CH_NSPC }, /* 66 ` */
|
||
{ 0040, 0100, 0200, 0100, 0040, CH_NSPC }, /* 67 ^ */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 70 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 71 block? */
|
||
{ 0000, 0000, 0000, 0000, 0000, CH_BS }, /* 72 backspace */
|
||
{ 0376, 0376, 0376, 0376, 0376, CH_SUB }, /* 73 subscript */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 74 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 75 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, 0 }, /* 76 ??? */
|
||
{ 0376, 0376, 0376, 0376, 0376, CH_SUP } /* 77 superscript */
|
||
};
|
||
|
||
void
|
||
ty342_set_grid(int w, int h)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
u->width = w;
|
||
u->height = h;
|
||
}
|
||
|
||
/*
|
||
* type 342 Character/Symbol generator for type 340 display
|
||
* return true if ESCaped
|
||
*/
|
||
int
|
||
character(int n, unsigned char c)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
int x, y;
|
||
unsigned char s = u->scale;
|
||
unsigned char flags;
|
||
|
||
c |= u->shift;
|
||
flags = chars[c][5];
|
||
|
||
if (flags == CH_LF) { /* LF */
|
||
u->ypos -= u->height*s;
|
||
if (u->ypos < 0) {
|
||
u->status |= ST340_HEDGE;
|
||
u->ypos = 0;
|
||
}
|
||
return 0;
|
||
}
|
||
if (flags == CH_CR) { /* CR */
|
||
u->xpos = 0;
|
||
return 0;
|
||
}
|
||
if (flags == CH_UC) { /* "SHIFT IN (HORIZ)" */
|
||
u->shift = 0; /* upper case in SPCWAR 163 */
|
||
return 0;
|
||
}
|
||
if (flags == CH_LC) { /* "SHIFT OUT (VERT)" */
|
||
u->shift = 0100; /* lower case in SPCWAR 163 */
|
||
return 0;
|
||
}
|
||
if (flags == CH_ESC) { /* escape */
|
||
return 1;
|
||
}
|
||
if ((flags == CH_NSPC) && u->xpos >= u->width*s) {
|
||
u->xpos -= u->width*s; /* non spacing character */
|
||
}
|
||
if (flags == CH_D) { /* descender */
|
||
u->ypos -= 2*s;
|
||
}
|
||
if (flags == CH_SUB) { /* subscript */
|
||
u->ypos -= u->width*s/2;
|
||
return 0;
|
||
}
|
||
if (flags == CH_SUP) { /* superscript */
|
||
u->ypos += u->width*s/2;
|
||
return 0;
|
||
}
|
||
/* plot character from character set selected by "shift" */
|
||
for (x = 0; x < 5; x++) { /* column: 0 to 4, left to right */
|
||
for (y = 0; y < 7; y++) { /* row: 0 to 6, bottom to top */
|
||
if (chars[c][x] & (2<<y)) {
|
||
/* XXX check for raster violation? */
|
||
point(u->xpos+x*s, u->ypos+y*s, n);
|
||
}
|
||
}
|
||
}
|
||
if (flags == CH_BS) { /* backspace */
|
||
u->xpos -= u->width*s;
|
||
} else {
|
||
u->xpos += u->width*s;
|
||
}
|
||
if (flags == CH_D) { /* undo descender */
|
||
u->ypos += 2*s;
|
||
}
|
||
if (u->xpos > 1023) {
|
||
u->xpos = 1023;
|
||
u->status |= ST340_VEDGE;
|
||
}
|
||
return 0;
|
||
}
|
||
#endif
|
||
|
||
/*
|
||
* execute one type340 instruction
|
||
* returns status word
|
||
* (could return number of microseconds)
|
||
*/
|
||
ty340word
|
||
ty340_instruction(ty340word inst)
|
||
{
|
||
struct type340 *u = UNIT(0);
|
||
int i, escape;
|
||
#ifdef TYPE347
|
||
ty340word addr;
|
||
#endif
|
||
|
||
/* cleared by RFD */
|
||
u->status &= ~(ST340_HEDGE|ST340_VEDGE);
|
||
|
||
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 (u->mode) {
|
||
case PARAM:
|
||
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 = (enum mode)GETFIELD(inst, 2, 4);
|
||
if (TESTBIT(inst, 5)) { /* load l.p. enable */
|
||
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<<GETFIELD(inst, 12, 13); /* save as multiplier */
|
||
DEBUGF(("type340 set scale %d\r\n", u->scale));
|
||
}
|
||
if (TESTBIT(inst, 7)) {
|
||
u->status |= ST340_STOPPED;
|
||
DEBUGF(("type340 stop\r\n"));
|
||
if (TESTBIT(inst, 8)) {
|
||
DEBUGF(("type340 stop int\r\n"));
|
||
u->status |= ST340_STOP_INT;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case POINT:
|
||
u->mode = (enum mode)GETFIELD(inst, 2, 4);
|
||
|
||
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)) {
|
||
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:
|
||
DEBUGF(("type340 slave %06o\r\n", inst));
|
||
u->mode = (enum 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:
|
||
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:
|
||
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)))
|
||
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? */
|
||
|
||
u->mode = (enum mode)GETFIELD(inst, 2, 4);
|
||
addr = GETFIELD(inst, 5, 17);
|
||
|
||
switch (GETFIELD(inst, 0, 1)) {
|
||
case DJS: /* display jump and save */
|
||
u->ASR = u->DAC;
|
||
u->SAVE_FF = 1; /* set "save" flip-flop */
|
||
/* FALL */
|
||
case DJP: /* display jump */
|
||
u->DAC = addr;
|
||
break;
|
||
case DDS: /* display deposit save register */
|
||
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) {
|
||
u->mode = PARAM;
|
||
#if TYPE347
|
||
if (u->SAVE_FF) {
|
||
/* return from subroutine */
|
||
u->DAC = u->ASR;
|
||
u->SAVE_FF = 0;
|
||
}
|
||
#endif
|
||
}
|
||
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;
|
||
}
|