simh-testsetgenerator/imlac/imlac_dp.c
B. Scott Michel bad1e0e565
IMLAC: Type consistency warnings. (#430)
* IMLAC: Type consistency warnings.

* Remove unintentional changes

* Remove extra braces

* CUR_AC -> AC (revert)
2025-01-13 12:09:25 -05:00

508 lines
11 KiB
C

/* imlac_dp.c: Imlac display processor
Copyright (c) 2020, Lars Brinkhoff
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
LARS BRINKHOFF 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 Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
/* Debug */
#define DBG 0001
static t_addr DPC;
static t_addr DT[8];
static uint16 SP = 0;
static uint16 ON = 0;
static uint16 HALT = 0;
static uint16 MODE = 0;
static uint16 XA, YA;
static uint16 SCALE = 2;
static uint16 BLOCK = 0;
static uint16 MIT8K;
static uint16 SGR;
static uint16 SYNC = 1;
/* Function declaration. */
static uint16 dp_iot (uint16, uint16);
static t_stat dp_svc (UNIT *uptr);
static t_stat dp_reset(DEVICE *dptr);
static uint16 sync_iot (uint16, uint16);
static t_stat sync_svc (UNIT *uptr);
static IMDEV dp_imdev = {
3,
{ { 0000, dp_iot, { NULL, NULL, NULL, "DLA" } },
{ 0001, dp_iot, { NULL, "CTB", "DOF", NULL } },
{ 0030, dp_iot, { NULL, NULL, NULL, "DCF" } } }
};
static UNIT dp_unit = {
UDATA (&dp_svc, UNIT_IDLE, 0)
};
static REG dp_reg[] = {
{ ORDATAD (DPC, DPC, 16, "Display program counter") },
{ ORDATAD (ON, ON, 1, "Display on") },
{ ORDATAD (HALT, HALT, 1, "Display halted") },
{ ORDATAD (MODE, MODE, 1, "Display mode") },
{ BRDATAD (DT, DT, 8, 16, 8, "Return address stack") },
{ ORDATAD (SP, SP, 3, "Stack pointer") },
{ ORDATAD (XA, XA, 11, "X accumulator") },
{ ORDATAD (YA, YA, 11, "Y accumulator") },
{ ORDATAD (SCALE, SCALE, 3, "Scale") },
{ ORDATAD (BLOCK, BLOCK, 3, "Block") },
{ ORDATAD (MIT8K, MIT8K, 1, "MIT 8K addressing") },
{ ORDATAD (SGR, SGR, 1, "Suppressed grid mode") },
{ NULL }
};
static DEBTAB dp_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE dp_dev = {
"DP", &dp_unit, dp_reg, NULL,
1, 8, 16, 1, 8, 16,
NULL, NULL, dp_reset,
NULL, NULL, NULL, &dp_imdev, DEV_DEBUG, 0, dp_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static UNIT sync_unit = {
UDATA (&sync_svc, UNIT_IDLE, 0)
};
static REG sync_reg[] = {
{ ORDATAD (SYNC, SYNC, 1, "Flag") },
{ NULL }
};
static IMDEV sync_imdev = {
1,
{ { 0007, sync_iot, { NULL, "SCF", "IOS", NULL } } }
};
static DEBTAB sync_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE sync_dev = {
"SYNC", &sync_unit, sync_reg, NULL,
1, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
NULL, NULL, NULL,
&sync_imdev, DEV_DEBUG, 0, sync_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
void
dp_on (int flag)
{
if (!ON && flag) {
SP = 0;
MIT8K = 0;
sim_activate_abs (&dp_unit, 0);
sim_debug (DBG, &dp_dev, "Display on\n");
} else if (ON && !flag) {
sim_cancel (&dp_unit);
sim_debug (DBG, &dp_dev, "Display off\n");
crt_idle ();
if (SYNC && HALT)
flag_on (FLAG_SYNC);
}
ON = (uint16) flag;
}
uint16
dp_is_on (void)
{
return ON;
}
static uint16
dp_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0001) { /* DLZ */
sim_debug (DBG, &dp_dev, "DPC cleared\n");
DPC = 0;
}
if ((insn & 0772) == 0002) { /* DLA */
sim_debug (DBG, &dp_dev, "DPC set to %06o\n", AC & memmask);
DPC = AC & memmask;
BLOCK = (AC >> 12) & 3;
}
if ((insn & 0771) == 0011) { /* CTB */
;
}
if ((insn & 0772) == 0012) { /* DOF */
dp_on (0);
}
if ((insn & 0774) == 0304) { /* DCF */
HALT = 0;
}
return AC;
}
static t_stat
dp_opr(uint16 insn)
{
if ((insn & 04000) == 0) {
sim_debug (DBG, &dp_dev, "DHLT ");
HALT = 1;
}
else if (insn == 04000)
sim_debug (DBG, &dp_dev, "DNOP");
dp_on ((insn & 04000) != 0); /* DHLT */
switch (insn & 00014) {
case 000:
if (insn & 1) {
sim_debug (DBG, &dp_dev, "DADR ");
MIT8K = !MIT8K;
}
break;
case 004:
sim_debug (DBG, &dp_dev, "DSTS%o ", insn & 3);
SCALE = insn & 3;
if (SCALE == 0)
SCALE = 1;
else
SCALE *= 2;
break;
case 010:
sim_debug (DBG, &dp_dev, "DSTB%o ", insn & 3);
BLOCK = insn & 3;
break;
case 014:
sim_debug (DBG, &dp_dev, "DSTL%o ", insn & 3);
/* TODO: Light pen. */
break;
}
if (insn & 00020) { /* DDSP */
sim_debug (DBG, &dp_dev, "DDSP ");
crt_point (XA, YA);
}
if (insn & 00040) { /* DRJM */
sim_debug (DBG, &dp_dev, "DRJM ");
if (SP > 0)
DPC = DT[--SP];
else
sim_debug (DBG, &dp_dev, "stack underflow");
}
if (insn & 00100) { /* DDYM */
sim_debug (DBG, &dp_dev, "DDYM ");
YA -= 040;
}
if (insn & 00200) { /* DDXM */
sim_debug (DBG, &dp_dev, "DDXM ");
XA -= 040;
}
if (insn & 00400) { /* DIYM */
sim_debug (DBG, &dp_dev, "DIYM ");
YA += 040;
}
if (insn & 01000) { /* DIXM */
sim_debug (DBG, &dp_dev, "DIXM ");
XA += 040;
}
if (insn & 02000) { /* DHVC */
sim_debug (DBG, &dp_dev, "DHVC ");
crt_hvc ();
}
sim_debug (DBG, &dp_dev, "\n");
return SCPE_OK;
}
static void
jump (uint16 insn)
{
DPC = insn & 07777;
if (MIT8K)
DPC |= (insn & 0100000) >> 3;
else
DPC |= BLOCK << 12;
}
static void
dp_sgr (uint16 insn)
{
sim_debug (DBG, &dp_dev, "DSGR %o\n", insn & 7);
SGR = insn & 1;
if (insn & 1) {
sim_debug (DBG, &dp_dev, "Enter SGR mode\n");
} else {
sim_debug (DBG, &dp_dev, "Exit SGR mode\n");
}
if (insn & 2) {
sim_debug (DBG, &dp_dev, "SGR: Return\n");
}
if (insn & 4) {
sim_debug (DBG, &dp_dev, "SGR: Beam on\n");
} else {
sim_debug (DBG, &dp_dev, "SGR: Beam off\n");
}
}
static void
dp_opt (uint16 insn)
{
switch (insn & 07770) {
case 07660: /* ASG-1 */
case 07667:
break;
case 07720: /* VIC-1 */
case 07730:
break;
case 07740: /* MCI-1 */
case 07750:
break;
case 07760: /* STI-1 or LPA-1 */
break;
case 07770: /* SGR-1 */
dp_sgr (insn);
break;
default:
sim_debug (DBG, &dp_dev, "Unknown instruction: %06o ", insn);
break;
}
}
static void
dp_inc_vector (uint16 byte)
{
uint16 x1 = XA, y1 = YA;
uint16 dx, dy;
if (byte == 0200) {
sim_debug (DBG, &dp_dev, "P");
} else {
sim_debug (DBG, &dp_dev, "%s", byte & 0100 ? "B" : "D");
if (byte & 00040)
sim_debug (DBG, &dp_dev, "M");
sim_debug (DBG, &dp_dev, "%o", (byte >> 3) & 3);
if (byte & 00004)
sim_debug (DBG, &dp_dev, "M");
sim_debug (DBG, &dp_dev, "%o", byte & 3);
}
dx = SCALE * ((byte >> 3) & 3);
dy = SCALE * (byte & 3);
if (byte & 040)
XA -= dx;
else
XA += dx;
if (byte & 4)
YA -= dy;
else
YA += dy;
if (byte & 0100)
crt_line (x1, y1, XA, YA);
}
static void
dp_inc_escape (uint16 byte)
{
if (byte == 0100)
sim_debug (DBG, &dp_dev, "T");
else if (byte == 0140)
sim_debug (DBG, &dp_dev, "X");
else if (byte == 0151)
sim_debug (DBG, &dp_dev, "R");
else
sim_debug (DBG, &dp_dev, "%03o", byte);
if (byte & 0100)
MODE = 0;
if (byte & 040) {
if (SP > 0)
DPC = DT[--SP];
else
sim_debug (DBG, &dp_dev, "stack underflow");
}
if (byte & 020)
XA += 040;
if (byte & 010)
XA &= 03740;
if (byte & 4) /* Enter PPM mode. */
;
if (byte & 2)
YA += 040;
if (byte & 1)
YA &= 03740;
}
static void
dp_inc (uint16 byte)
{
if (byte & 0200) {
/* Increment byte. */
dp_inc_vector (byte);
} else {
/* Escape byte. */
dp_inc_escape (byte);
}
}
static void
dp_deim (uint16 insn)
{
MODE = 1;
sim_debug (DBG, &dp_dev, "E,");
dp_inc (insn & 0377);
sim_debug (DBG, &dp_dev, "\n");
}
static void
dp_dlvh (uint16 insn1, uint16 insn2, uint16 insn3)
{
uint16 x1 = XA, y1 = YA;
uint16 m, n, dx, dy;
m = insn2 & 07777;
n = insn3 & 07777;
if (insn3 & 010000) {
dx = n;
dy = m;
} else {
dx = m;
dy = n;
}
if (insn3 & 040000)
XA -= SCALE * dx;
else
XA += SCALE * dx;
if (insn3 & 020000)
YA -= SCALE * dy;
else
YA += SCALE * dy;
if (insn2 & 020000)
crt_line (x1, y1, XA, YA);
}
static void
dp_insn (uint16 insn)
{
switch ((insn >> 12) & 7) {
case 0: /* DOPR */
dp_opr (insn);
break;
case 1: /* DLXA */
sim_debug (DBG, &dp_dev, "DLXA\n");
XA = (insn & 01777) << 1;
break;
case 2: /* DLYA */
sim_debug (DBG, &dp_dev, "DLYA\n");
YA = (insn & 01777) << 1;
break;
case 3: /* DEIM */
sim_debug (DBG, &dp_dev, "DEIM ");
dp_deim (insn);
break;
case 4: /* DLVH */
sim_debug (DBG, &dp_dev, "DLVH\n");
dp_dlvh (insn, M[DPC], M[DPC+1]);
DPC += 2;
break;
case 5: /* DJMS */
sim_debug (DBG, &dp_dev, "DJMS\n");
if (SP < 7)
DT[SP++] = DPC;
else
sim_debug (DBG, &dp_dev, "stack overflow");
jump (insn);
break;
case 6: /* DJMP */
sim_debug (DBG, &dp_dev, "DJMP\n");
jump (insn);
break;
case 7: /* optional */
dp_opt (insn);
break;
}
}
static t_stat
dp_svc(UNIT * uptr)
{
uint16 insn;
if (sim_brk_summ && sim_brk_test(DPC, SWMASK('D'))) {
sim_activate_abs (&dp_unit, 0);
return sim_messagef (SCPE_STOP, "Display processor breakpoint.\n");
}
sim_debug (DBG, &dp_dev, "%06o ", DPC);
insn = M[DPC];
DPC++;
if (MODE) {
sim_debug (DBG, &dp_dev, "INC ");
dp_inc (insn >> 8);
if (MODE) {
sim_debug (DBG, &dp_dev, ",");
dp_inc (insn & 0377);
}
sim_debug (DBG, &dp_dev, "\n");
} else
dp_insn (insn);
if (ON)
sim_activate_after (&dp_unit, 2);
return SCPE_OK;
}
static t_stat
dp_reset(DEVICE * uptr)
{
sim_activate_abs (&dp_unit, 0);
return SCPE_OK;
}
static t_stat
sync_svc (UNIT *uptr)
{
sim_debug (DBG, &sync_dev, "40 Hz sync\n");
SYNC = 1;
if (SYNC && HALT)
flag_on (FLAG_SYNC);
sim_cancel (&sync_unit);
return SCPE_OK;
}
static uint16
sync_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0071) { /* SCF */
sim_debug (DBG, &sync_dev, "Clear flag\n");
SYNC = 0;
flag_off (FLAG_SYNC);
sim_activate_after (&sync_unit, 25000);
}
if ((insn & 0772) == 0072) { /* IOS */
}
return AC;
}