* IMLAC: Type consistency warnings. * Remove unintentional changes * Remove extra braces * CUR_AC -> AC (revert)
508 lines
11 KiB
C
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;
|
|
}
|