mirror of
https://github.com/simh/simh.git
synced 2026-02-27 17:13:44 +00:00
LINC: New emulator for the classic LINC.
This emulates the classic LINC. The design was settled in 1965, increasing memory to 2048 words, and adding a Z register, an overflow flag, and an interrupt facility.
This commit is contained in:
committed by
Mark Pizzolato
parent
3dd72309b5
commit
f5f2930712
@@ -131,6 +131,10 @@ struct color color_p31 = { p31, ELEMENTS(p31), 100000 };
|
||||
static struct phosphor p39[] = {{0.2, 1.0, 0.0, 0.5, 0.01}};
|
||||
struct color color_p39 = { p39, ELEMENTS(p39), 20000 };
|
||||
|
||||
/* orange phosphor for LINC */
|
||||
static struct phosphor p19[] = {{1.0, 0.7, 0.0, 0.1, 0.22}};
|
||||
struct color color_p19 = { p19, ELEMENTS(p19), 20000 };
|
||||
|
||||
static struct phosphor p40[] = {
|
||||
/* P40 blue-white spot with yellow-green decay (.045s to 10%?) */
|
||||
{0.4, 0.2, 0.924, 0.5, 0.0135},
|
||||
@@ -253,6 +257,15 @@ static struct display displays[] = {
|
||||
*/
|
||||
{ DIS_III, "III Display", &color_p39, NULL, 1024, 1024 },
|
||||
|
||||
/*
|
||||
* LINC display
|
||||
* 512x511 addressable points.
|
||||
* The horizontal position is a 9-bit unsigned value, but the
|
||||
* vertical is a one's complement signed 9-bit value with
|
||||
* both +0 and -0 referring to the same position.
|
||||
*/
|
||||
{ DIS_LINC, "LINC Display", &color_p19, NULL, 512, 511 },
|
||||
|
||||
/*
|
||||
* Imlac display
|
||||
* 1024x1024 addressable points.
|
||||
|
||||
@@ -47,6 +47,7 @@ enum display_type {
|
||||
DIS_VR17 = 17,
|
||||
DIS_VR20 = 20,
|
||||
DIS_TYPE30 = 30,
|
||||
DIS_LINC = 40,
|
||||
DIS_VR48 = 48,
|
||||
DIS_III = 111,
|
||||
DIS_TYPE340 = 340,
|
||||
|
||||
32
linc/CMakeLists.txt
Normal file
32
linc/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
## LINC simulator
|
||||
##
|
||||
## This is an automagically generated file. Do NOT EDIT.
|
||||
## Any changes you make will be overwritten!!
|
||||
##
|
||||
## Make changes to the SIMH top-level makefile and then run the
|
||||
## "cmake/generate.py" script to regenerate these files.
|
||||
##
|
||||
## cd cmake; python -m generate --help
|
||||
##
|
||||
## ------------------------------------------------------------
|
||||
|
||||
if (HAVE_UNITY_FRAMEWORK AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/CMakeLists.txt")
|
||||
add_subdirectory(unit-tests)
|
||||
endif ()
|
||||
|
||||
add_simulator(linc
|
||||
SOURCES
|
||||
linc_cpu.c
|
||||
linc_crt.c
|
||||
linc_dpy.c
|
||||
linc_kbd.c
|
||||
linc_sys.c
|
||||
linc_tape.c
|
||||
linc_tty.c
|
||||
INCLUDES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
FEATURE_DISPLAY
|
||||
USES_AIO
|
||||
LABEL linc
|
||||
PKG_FAMILY default_family
|
||||
TEST linc)
|
||||
863
linc/linc_cpu.c
Normal file
863
linc/linc_cpu.c
Normal file
@@ -0,0 +1,863 @@
|
||||
/* linc_cpu.c: LINC CPU simulator
|
||||
|
||||
Copyright (c) 2025, 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 "linc_defs.h"
|
||||
|
||||
|
||||
/* Debug */
|
||||
#define DBG_CPU 0001
|
||||
|
||||
#define WMASK 07777 /* Full word. */
|
||||
#define HMASK 04000 /* H bit; half word select. */
|
||||
#define AMASK 03777 /* Full memory address. */
|
||||
#define XMASK 01777 /* X part; low memory address. */
|
||||
#define DMASK 00777 /* Display coordinate. */
|
||||
#define LMASK 07700 /* Left half word. */
|
||||
#define RMASK 00077 /* Right half word; character. */
|
||||
#define IMASK 00020 /* Index bit. */
|
||||
#define BMASK 00017 /* Beta; index register. */
|
||||
|
||||
#define X(_X) ((_X) & XMASK)
|
||||
|
||||
/* CPU state. */
|
||||
static uint16 P;
|
||||
static uint16 C;
|
||||
static uint16 S;
|
||||
static uint16 B;
|
||||
static uint16 A;
|
||||
static uint16 L;
|
||||
static uint16 Z;
|
||||
static uint16 R;
|
||||
static uint16 LSW, RSW, SSW;
|
||||
static uint16 SAM[16];
|
||||
static uint16 XL[12];
|
||||
static int paused;
|
||||
static int IBZ;
|
||||
static int OVF;
|
||||
static int PINFF;
|
||||
static int interrupt;
|
||||
static int interrupt_enable = 0;
|
||||
|
||||
static t_stat stop_reason;
|
||||
|
||||
typedef struct {
|
||||
uint16 P;
|
||||
uint16 C;
|
||||
uint16 S;
|
||||
uint16 B;
|
||||
uint16 A;
|
||||
uint16 L;
|
||||
} HISTORY;
|
||||
static HISTORY *history = NULL;
|
||||
static uint32 history_i, history_m, history_n;
|
||||
|
||||
/* Function declaration. */
|
||||
static t_stat cpu_ex(t_value *vptr, t_addr ea, UNIT *uptr, int32 sw);
|
||||
static t_stat cpu_dep(t_value val, t_addr ea, UNIT *uptr, int32 sw);
|
||||
static t_stat cpu_reset(DEVICE *dptr);
|
||||
static t_stat cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||
static t_stat cpu_show_hist(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||||
|
||||
static UNIT cpu_unit = { UDATA(NULL, UNIT_FIX + UNIT_BINK, MEMSIZE) };
|
||||
|
||||
REG cpu_reg[] = {
|
||||
{ ORDATAD(P, P, 10, "Program Location") },
|
||||
{ ORDATAD(C, C, 12, "Control Register") },
|
||||
{ ORDATAD(A, A, 12, "Accumulator") },
|
||||
{ ORDATAD(L, L, 1, "Link") },
|
||||
{ ORDATAD(Z, Z, 12, "?") },
|
||||
{ ORDATAD(R, R, 6, "Relay Register") },
|
||||
{ ORDATAD(S, S, 12, "Memroy Address") },
|
||||
{ ORDATAD(B, B, 12, "Memory Buffer") },
|
||||
{ ORDATAD(LSW, LSW, 12, "Left Switches") },
|
||||
{ ORDATAD(RSW, RSW, 12, "Right Switches") },
|
||||
{ ORDATAD(SSW, SSW, 6, "Sense Switches") },
|
||||
{ FLDATAD(paused, paused, 1, "Paused") },
|
||||
{ FLDATAD(IBZ, IBZ, 1, "Interblock zone") },
|
||||
{ FLDATAD(OVF, OVF, 1, "Overflow") },
|
||||
{ BRDATAD(SAM, SAM, 8, 8, 16, "Sampled analog inputs") },
|
||||
{ BRDATAD(XL, XL, 8, 1, 12, "External levels") },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static MTAB cpu_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
|
||||
&cpu_set_hist, &cpu_show_hist },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static DEBTAB cpu_deb[] = {
|
||||
{ "CPU", DBG_CPU },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE cpu_dev = {
|
||||
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
||||
0, 8, 11, 1, 8, 12,
|
||||
&cpu_ex, &cpu_dep, &cpu_reset,
|
||||
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, cpu_deb,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
static void pcinc(int flag)
|
||||
{
|
||||
if (flag)
|
||||
P = X(P + 1);
|
||||
}
|
||||
|
||||
static void memaddr(uint16 addr)
|
||||
{
|
||||
S = addr & WMASK;
|
||||
}
|
||||
|
||||
static void membuf(uint16 data)
|
||||
{
|
||||
B = data & WMASK;
|
||||
}
|
||||
|
||||
static void memrd(void)
|
||||
{
|
||||
B = M[S & AMASK];
|
||||
sim_interval--;
|
||||
if (sim_brk_summ && sim_brk_test(S & AMASK, SWMASK('R')))
|
||||
stop_reason = STOP_RBKPT;
|
||||
}
|
||||
|
||||
static void memmd(void)
|
||||
{
|
||||
M[S & AMASK] = B;
|
||||
if (sim_brk_summ && sim_brk_test(S & AMASK, SWMASK('W')))
|
||||
stop_reason = STOP_WBKPT;
|
||||
}
|
||||
|
||||
static void memwr(void)
|
||||
{
|
||||
sim_interval--;
|
||||
memmd();
|
||||
}
|
||||
|
||||
static int cpu_halfword(void)
|
||||
{
|
||||
switch (C & 07740) {
|
||||
case 01300: //LDH
|
||||
case 01340: //STH
|
||||
case 01400: //SHD
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_index(void)
|
||||
{
|
||||
uint16 tmp;
|
||||
if (C & IMASK) {
|
||||
if (cpu_halfword()) {
|
||||
B += HMASK;
|
||||
tmp = B >> 12;
|
||||
} else {
|
||||
tmp = 1;
|
||||
}
|
||||
membuf((B & 06000) | X(B + tmp));
|
||||
memmd();
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_indexing(void)
|
||||
{
|
||||
uint16 a = C & BMASK;
|
||||
if (a == 0)
|
||||
{
|
||||
pcinc(1);
|
||||
memaddr(P);
|
||||
if ((C & IMASK) == 0) {
|
||||
memrd();
|
||||
memaddr(B);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memaddr(a);
|
||||
memrd();
|
||||
cpu_index();
|
||||
memaddr(B);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_misc(void)
|
||||
{
|
||||
switch (C) {
|
||||
case 00000: //HLT
|
||||
stop_reason = STOP_HALT;
|
||||
break;
|
||||
case 00005: //ZTA
|
||||
A = Z >> 1;
|
||||
break;
|
||||
case 00010: //ENI
|
||||
interrupt_enable = 1;
|
||||
break;
|
||||
case 00011: //CLR
|
||||
A = L = Z = 0;
|
||||
break;
|
||||
case 00013: //Write gate on.
|
||||
break;
|
||||
case 00014: //ATR
|
||||
R = A & RMASK;
|
||||
break;
|
||||
case 00015: //RTA
|
||||
A = R & RMASK;
|
||||
break;
|
||||
case 00016: //NOP
|
||||
break;
|
||||
case 00017: //COM
|
||||
A = (~A) & WMASK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_set(void)
|
||||
{
|
||||
memaddr(P);
|
||||
memrd();
|
||||
pcinc(1);
|
||||
if ((C & IMASK) == 0) {
|
||||
memaddr(B);
|
||||
memrd();
|
||||
}
|
||||
memaddr(C & BMASK);
|
||||
memwr();
|
||||
}
|
||||
|
||||
static void cpu_sam(void)
|
||||
{
|
||||
// sample analog input C & BMASK
|
||||
// 0-7 are pots, 10-17 are high speed inputs
|
||||
// i=0 wait 24 microseconds, i=1 do not wait
|
||||
if ((C & IMASK) == 0)
|
||||
sim_interval -= 3;
|
||||
A = SAM[C & BMASK];
|
||||
if (A & 0200) /* One's complement +/-177. */
|
||||
A |= 07600;
|
||||
}
|
||||
|
||||
static void cpu_dis(void)
|
||||
{
|
||||
memaddr(C & BMASK);
|
||||
memrd();
|
||||
cpu_index();
|
||||
sim_debug(DBG_CPU, &cpu_dev, "DIS α=%02o B=%04o A=%04o\n", S, B, A);
|
||||
dpy_dis(B >> 11, B & DMASK, A & DMASK);
|
||||
}
|
||||
|
||||
static void cpu_xsk(void)
|
||||
{
|
||||
memaddr(C & BMASK);
|
||||
memrd();
|
||||
cpu_index();
|
||||
pcinc(X(B) == 01777);
|
||||
}
|
||||
|
||||
static void cpu_rol(void)
|
||||
{
|
||||
while (C & BMASK) {
|
||||
if (C & IMASK) {
|
||||
A = (A << 1) | L;
|
||||
L = A >> 12;
|
||||
} else {
|
||||
A = (A << 1) | (A >> 11);
|
||||
}
|
||||
A &= WMASK;
|
||||
C--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_ror(void)
|
||||
{
|
||||
while (C & BMASK) {
|
||||
Z = (Z >> 1) | ((A & 1) << 11);
|
||||
if (C & IMASK) {
|
||||
A |= L << 12;
|
||||
L = A & 1;
|
||||
A = A >> 1;
|
||||
} else {
|
||||
A = (A >> 1) | (A << 11);
|
||||
A &= WMASK;
|
||||
}
|
||||
C--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_scr(void)
|
||||
{
|
||||
while (C & BMASK) {
|
||||
Z = (Z >> 1) | ((A & 1) << 11);
|
||||
if (C & IMASK)
|
||||
L = A & 1;
|
||||
A = (A & 04000) | (A >> 1);
|
||||
C--;
|
||||
}
|
||||
}
|
||||
|
||||
int cpu_skip(void)
|
||||
{
|
||||
int flag = 0;
|
||||
switch (C & 057) {
|
||||
case 000: case 001: case 002: case 003: case 004: case 005: case 006: case 007:
|
||||
case 010: case 011: case 012: case 013: //SXL
|
||||
flag = XL[C & BMASK];
|
||||
break;
|
||||
case 015: //KST
|
||||
flag = kbd_struck();
|
||||
break;
|
||||
case 040: case 041: case 042: case 043: case 044: case 045: //SNS
|
||||
flag = SSW & (1 << (C & 7));
|
||||
break;
|
||||
case 046: //PIN
|
||||
flag = PINFF;
|
||||
break;
|
||||
case 050: //AZE
|
||||
flag = (A == 0) || (A == WMASK);
|
||||
break;
|
||||
case 051: //APO
|
||||
flag = (A & 04000) == 0;
|
||||
break;
|
||||
case 052: //LZE
|
||||
flag = L == 0;
|
||||
break;
|
||||
case 053: //IBZ
|
||||
flag = IBZ;
|
||||
sim_debug(DBG_CPU, &cpu_dev, "IBZ%s => %d\n", C & IMASK ? " i" : "", flag);
|
||||
break;
|
||||
case 054: //OVF
|
||||
flag = OVF;
|
||||
break;
|
||||
case 055: //ZZZ
|
||||
flag = (Z & 1) == 0;
|
||||
break;
|
||||
default:
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
if (C & IMASK)
|
||||
flag = !flag;
|
||||
return flag;
|
||||
}
|
||||
|
||||
static void cpu_opr(void)
|
||||
{
|
||||
switch (C & BMASK) {
|
||||
case 000: case 001: case 002: case 003: case 004: case 005: case 006: case 007:
|
||||
case 010: case 011: case 012: case 013: case 014:
|
||||
if (C & IMASK)
|
||||
; //Pause.
|
||||
break;
|
||||
case 015: //KBD
|
||||
A = kbd_key(C & IMASK);
|
||||
break;
|
||||
case 016: //RSW
|
||||
A = RSW;
|
||||
break;
|
||||
case 017: //LSW
|
||||
A = LSW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_lmb(void)
|
||||
{
|
||||
//Instruction field.
|
||||
}
|
||||
|
||||
static void cpu_umb(void)
|
||||
{
|
||||
//Data field.
|
||||
}
|
||||
|
||||
static void cpu_tape(void)
|
||||
{
|
||||
memaddr(P);
|
||||
memrd();
|
||||
pcinc(1);
|
||||
tape_op();
|
||||
}
|
||||
|
||||
static void cpu_lda(void)
|
||||
{
|
||||
memrd();
|
||||
A = B;
|
||||
}
|
||||
|
||||
static void cpu_sta(void)
|
||||
{
|
||||
membuf(A);
|
||||
memwr();
|
||||
}
|
||||
|
||||
static void cpu_ada(void)
|
||||
{
|
||||
memrd();
|
||||
OVF = ~(A ^ B);
|
||||
A += B;
|
||||
A += A >> 12;
|
||||
A &= WMASK;
|
||||
OVF &= (A ^ B) & 04000;
|
||||
}
|
||||
|
||||
static void cpu_adm(void)
|
||||
{
|
||||
cpu_ada();
|
||||
membuf(A);
|
||||
memmd();
|
||||
}
|
||||
|
||||
static void cpu_lam(void)
|
||||
{
|
||||
memrd();
|
||||
A += L;
|
||||
L = A >> 12;
|
||||
A &= WMASK;
|
||||
A += B;
|
||||
if (A & 010000)
|
||||
L = 1;
|
||||
A &= WMASK;
|
||||
membuf(A);
|
||||
memmd();
|
||||
}
|
||||
|
||||
static int32 sign_extend(uint16 x)
|
||||
{
|
||||
if (x & 04000)
|
||||
return -(x ^ WMASK);
|
||||
else
|
||||
return x;
|
||||
}
|
||||
|
||||
static void cpu_mul(void)
|
||||
{
|
||||
int32 product;
|
||||
memrd();
|
||||
// C used for counting.
|
||||
product = sign_extend(A) * sign_extend(B);
|
||||
if (product == 0 && ((A ^ B) & HMASK))
|
||||
product = 037777777;
|
||||
else if (product < 0)
|
||||
product--;
|
||||
if (S & HMASK)
|
||||
A = (product >> 11) & WMASK;
|
||||
else if ((A ^ B) & HMASK)
|
||||
A = 04000 | (product & 03777);
|
||||
else
|
||||
A = product & 03777;
|
||||
L = A >> 11;
|
||||
}
|
||||
|
||||
static void cpu_ldh(void)
|
||||
{
|
||||
memrd();
|
||||
if ((S & HMASK) == 0)
|
||||
B >>= 6;
|
||||
A = B & RMASK;
|
||||
}
|
||||
|
||||
static void cpu_sth(void)
|
||||
{
|
||||
memrd();
|
||||
if (S & HMASK)
|
||||
membuf((A & RMASK) | (B & LMASK));
|
||||
else
|
||||
membuf((A << 6) | (B & RMASK));
|
||||
memmd();
|
||||
}
|
||||
|
||||
static void cpu_shd(void)
|
||||
{
|
||||
memrd();
|
||||
if ((S & HMASK) == 0)
|
||||
B >>= 6;
|
||||
pcinc((A & RMASK) != (B & RMASK));
|
||||
}
|
||||
|
||||
static void cpu_sae(void)
|
||||
{
|
||||
memrd();
|
||||
pcinc(A == B);
|
||||
}
|
||||
|
||||
static void cpu_sro(void)
|
||||
{
|
||||
memrd();
|
||||
pcinc((B & 1) == 0);
|
||||
membuf((B >> 1) | (B << 11));
|
||||
memmd();
|
||||
}
|
||||
|
||||
static void cpu_bcl(void)
|
||||
{
|
||||
memrd();
|
||||
A &= ~B;
|
||||
}
|
||||
|
||||
static void cpu_bse(void)
|
||||
{
|
||||
memrd();
|
||||
A |= B;
|
||||
}
|
||||
|
||||
static void cpu_bco(void)
|
||||
{
|
||||
memrd();
|
||||
A ^= B;
|
||||
}
|
||||
|
||||
static void cpu_dsc(void)
|
||||
{
|
||||
int i, j;
|
||||
uint16 data;
|
||||
|
||||
memrd();
|
||||
data = B;
|
||||
|
||||
// C used for counting.
|
||||
memaddr(1);
|
||||
memrd();
|
||||
sim_debug(DBG_CPU, &crt_dev, "DSC B=%04o A=%04o\n", B, A);
|
||||
for (j = 0; j < 2; j++) {
|
||||
membuf(B + 4);
|
||||
A &= 07740;
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (data & 1)
|
||||
dpy_dis(B >> 11, B & DMASK, A & DMASK);
|
||||
data >>= 1;
|
||||
A += 4;
|
||||
}
|
||||
}
|
||||
memmd();
|
||||
}
|
||||
|
||||
static void cpu_add(void)
|
||||
{
|
||||
memaddr(X(C));
|
||||
cpu_ada();
|
||||
}
|
||||
|
||||
static void cpu_stc(void)
|
||||
{
|
||||
memaddr(X(C));
|
||||
membuf(A);
|
||||
A = 0;
|
||||
memwr();
|
||||
}
|
||||
|
||||
static void cpu_jmp(void)
|
||||
{
|
||||
uint16 tmp = P;
|
||||
P = X(C);
|
||||
if (P != 0) {
|
||||
membuf(06000 | tmp);
|
||||
memaddr(0);
|
||||
memwr();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cpu_insn(void)
|
||||
{
|
||||
/* Cycle 0, or I. */
|
||||
memaddr(P);
|
||||
memrd();
|
||||
C = B;
|
||||
|
||||
/* Cycle 1, or X. */
|
||||
if ((C & 07000) == 01000)
|
||||
cpu_indexing();
|
||||
|
||||
if (history) {
|
||||
history[history_i].P = P;
|
||||
history[history_i].C = C;
|
||||
history[history_i].S = S;
|
||||
}
|
||||
|
||||
/* Cycle 2, or O. */
|
||||
pcinc(1);
|
||||
|
||||
/* Cycle 3, or E. */
|
||||
switch (C & 07740) {
|
||||
case 00000:
|
||||
cpu_misc();
|
||||
break;
|
||||
case 00040:
|
||||
cpu_set();
|
||||
break;
|
||||
case 00100:
|
||||
cpu_sam();
|
||||
break;
|
||||
case 00140:
|
||||
cpu_dis();
|
||||
break;
|
||||
case 00200:
|
||||
cpu_xsk();
|
||||
break;
|
||||
case 00240:
|
||||
cpu_rol();
|
||||
break;
|
||||
case 00300:
|
||||
cpu_ror();
|
||||
break;
|
||||
case 00340:
|
||||
cpu_scr();
|
||||
break;
|
||||
case 00400:
|
||||
case 00440:
|
||||
pcinc(cpu_skip());
|
||||
break;
|
||||
case 00500:
|
||||
case 00540:
|
||||
cpu_opr();
|
||||
break;
|
||||
case 00600:
|
||||
cpu_lmb();
|
||||
break;
|
||||
case 00640:
|
||||
cpu_umb();
|
||||
break;
|
||||
case 00700:
|
||||
case 00740:
|
||||
cpu_tape();
|
||||
break;
|
||||
case 01000:
|
||||
cpu_lda();
|
||||
break;
|
||||
case 01040:
|
||||
cpu_sta();
|
||||
break;
|
||||
case 01100:
|
||||
cpu_ada();
|
||||
break;
|
||||
case 01140:
|
||||
cpu_adm();
|
||||
break;
|
||||
case 01200:
|
||||
cpu_lam();
|
||||
break;
|
||||
case 01240:
|
||||
cpu_mul();
|
||||
break;
|
||||
case 01300:
|
||||
cpu_ldh();
|
||||
break;
|
||||
case 01340:
|
||||
cpu_sth();
|
||||
break;
|
||||
case 01400:
|
||||
cpu_shd();
|
||||
break;
|
||||
case 01440:
|
||||
cpu_sae();
|
||||
break;
|
||||
case 01500:
|
||||
cpu_sro();
|
||||
break;
|
||||
case 01540:
|
||||
cpu_bcl();
|
||||
break;
|
||||
case 01600:
|
||||
cpu_bse();
|
||||
break;
|
||||
case 01640:
|
||||
cpu_bco();
|
||||
break;
|
||||
case 01740:
|
||||
cpu_dsc();
|
||||
break;
|
||||
case 02000: case 02040: case 02100: case 02140: case 02200: case 02240: case 02300: case 02340:
|
||||
case 02400: case 02440: case 02500: case 02540: case 02600: case 02640: case 02700: case 02740:
|
||||
case 03000: case 03040: case 03100: case 03140: case 03200: case 03240: case 03300: case 03340:
|
||||
case 03400: case 03440: case 03500: case 03540: case 03600: case 03640: case 03700: case 03740:
|
||||
cpu_add();
|
||||
break;
|
||||
case 04000: case 04040: case 04100: case 04140: case 04200: case 04240: case 04300: case 04340:
|
||||
case 04400: case 04440: case 04500: case 04540: case 04600: case 04640: case 04700: case 04740:
|
||||
case 05000: case 05040: case 05100: case 05140: case 05200: case 05240: case 05300: case 05340:
|
||||
case 05400: case 05440: case 05500: case 05540: case 05600: case 05640: case 05700: case 05740:
|
||||
cpu_stc();
|
||||
break;
|
||||
case 06000: case 06040: case 06100: case 06140: case 06200: case 06240: case 06300: case 06340:
|
||||
case 06400: case 06440: case 06500: case 06540: case 06600: case 06640: case 06700: case 06740:
|
||||
case 07000: case 07040: case 07100: case 07140: case 07200: case 07240: case 07300: case 07340:
|
||||
case 07400: case 07440: case 07500: case 07540: case 07600: case 07640: case 07700: case 07740:
|
||||
cpu_jmp();
|
||||
break;
|
||||
}
|
||||
|
||||
if (history) {
|
||||
history[history_i].B = B;
|
||||
history[history_i].A = A;
|
||||
history[history_i].L = L;
|
||||
history_i = (history_i + 1) % history_m;
|
||||
if (history_n < history_m)
|
||||
history_n++;
|
||||
}
|
||||
|
||||
/* Check for interrupts. */
|
||||
if ((C & 06000) != 06000 && C != 00010 && interrupt && interrupt_enable) {
|
||||
interrupt = interrupt_enable = 0;
|
||||
memaddr(021);
|
||||
memrd();
|
||||
C = B;
|
||||
cpu_jmp();
|
||||
}
|
||||
}
|
||||
|
||||
t_stat sim_instr(void)
|
||||
{
|
||||
t_stat stat;
|
||||
|
||||
if ((stat = build_dev_tab()) != SCPE_OK)
|
||||
return stat;
|
||||
|
||||
stop_reason = 0;
|
||||
paused = 0;
|
||||
|
||||
for (;;) {
|
||||
AIO_CHECK_EVENT;
|
||||
if (sim_interval <= 0) {
|
||||
if ((stat = sim_process_event()) != SCPE_OK)
|
||||
return stat;
|
||||
}
|
||||
|
||||
if (sim_brk_summ && sim_brk_test(P, SWMASK('E')))
|
||||
return STOP_IBKPT;
|
||||
|
||||
#if 0
|
||||
if (paused)
|
||||
sim_debug(DBG_CPU, &cpu_dev, "Paused\n");
|
||||
#endif
|
||||
if (paused)
|
||||
sim_interval--;
|
||||
else
|
||||
cpu_insn();
|
||||
|
||||
if (sim_step != 0) {
|
||||
if (--sim_step == 0)
|
||||
return SCPE_STEP;
|
||||
}
|
||||
|
||||
if (stop_reason)
|
||||
return stop_reason;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat cpu_ex(t_value *vptr, t_addr ea, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (vptr == NULL)
|
||||
return SCPE_ARG;
|
||||
if (ea >= MEMSIZE)
|
||||
return SCPE_NXM;
|
||||
*vptr = M[ea];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat cpu_dep(t_value val, t_addr ea, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (ea >= MEMSIZE)
|
||||
return SCPE_NXM;
|
||||
M[ea] = val & WMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat
|
||||
cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||
{
|
||||
t_stat r;
|
||||
uint32 x;
|
||||
|
||||
if (cptr == NULL)
|
||||
return SCPE_ARG;
|
||||
|
||||
x = get_uint (cptr, 10, 1000000, &r);
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
|
||||
history = (HISTORY *)calloc (x, sizeof (*history));
|
||||
if (history == NULL)
|
||||
return SCPE_MEM;
|
||||
|
||||
history_m = x;
|
||||
history_n = 0;
|
||||
history_i = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat
|
||||
cpu_show_hist(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||
{
|
||||
t_value insn;
|
||||
uint32 i, j;
|
||||
|
||||
fprintf (st, "P___ C___ S___ B___ A___ L\n");
|
||||
|
||||
if (history_i >= history_n)
|
||||
j = history_i - history_n;
|
||||
else
|
||||
j = history_m + history_i - history_n;
|
||||
|
||||
for (i = 0; i < history_n; i++) {
|
||||
if (stop_cpu) { /* Control-C (SIGINT) */
|
||||
stop_cpu = FALSE;
|
||||
break; /* abandon remaining output */
|
||||
}
|
||||
fprintf (st, "%04o %04o %04o %04o %04o %d ",
|
||||
history[j].P,
|
||||
history[j].C,
|
||||
history[j].S,
|
||||
history[j].B,
|
||||
history[j].A,
|
||||
history[j].L);
|
||||
insn = history[j].C;
|
||||
fprint_sym (st, history[j].P, &insn, NULL, SWMASK ('M'));
|
||||
fputc ('\n', st);
|
||||
j = (j + 1) % history_m;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_bool pc_is_a_subroutine_call(t_addr **ret_addrs)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static t_stat
|
||||
cpu_reset(DEVICE *dptr)
|
||||
{
|
||||
sim_brk_types = SWMASK('E') | SWMASK('R') | SWMASK('W');
|
||||
sim_brk_dflt = SWMASK('E');
|
||||
sim_vm_is_subroutine_call = &pc_is_a_subroutine_call;
|
||||
return SCPE_OK;
|
||||
}
|
||||
122
linc/linc_crt.c
Normal file
122
linc/linc_crt.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/* linc_crt.c: LINC CRT display
|
||||
|
||||
Copyright (c) 2025, 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 "linc_defs.h"
|
||||
#include "sim_video.h"
|
||||
#include "display/display.h"
|
||||
|
||||
/* Function declaration. */
|
||||
static t_stat crt_svc (UNIT *uptr);
|
||||
static t_stat crt_reset (DEVICE *dptr);
|
||||
|
||||
static int crt_quit = FALSE;
|
||||
|
||||
/* Debug */
|
||||
#define DBG 0001
|
||||
|
||||
static UNIT crt_unit = {
|
||||
UDATA (&crt_svc, UNIT_IDLE, 0)
|
||||
};
|
||||
|
||||
static DEBTAB crt_deb[] = {
|
||||
{ "DBG", DBG },
|
||||
{ "VVID", SIM_VID_DBG_VIDEO },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
#ifdef USE_DISPLAY
|
||||
#define CRT_DIS 0
|
||||
#else
|
||||
#define CRT_DIS DEV_DIS
|
||||
#endif
|
||||
|
||||
DEVICE crt_dev = {
|
||||
"CRT", &crt_unit, NULL, NULL,
|
||||
1, 8, 12, 1, 8, 12,
|
||||
NULL, NULL, &crt_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, DEV_DISABLE | DEV_DEBUG | DEV_DISPLAY, 0, crt_deb,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
static t_stat
|
||||
crt_svc(UNIT *uptr)
|
||||
{
|
||||
#ifdef USE_DISPLAY
|
||||
display_age (100, 0);
|
||||
sim_activate_after (uptr, 100);
|
||||
if (crt_quit) {
|
||||
crt_quit = FALSE;
|
||||
return SCPE_STOP;
|
||||
}
|
||||
#endif
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static void crt_quit_callback (void)
|
||||
{
|
||||
crt_quit = TRUE;
|
||||
}
|
||||
|
||||
static t_stat
|
||||
crt_reset (DEVICE *dptr)
|
||||
{
|
||||
#ifdef USE_DISPLAY
|
||||
if ((dptr->flags & DEV_DIS) != 0 || (sim_switches & SWMASK('P')) != 0) {
|
||||
display_close (dptr);
|
||||
sim_cancel (&crt_unit);
|
||||
} else {
|
||||
display_reset ();
|
||||
display_init (DIS_LINC, 1, dptr);
|
||||
vid_register_quit_callback (&crt_quit_callback);
|
||||
sim_activate_abs (&crt_unit, 0);
|
||||
}
|
||||
#endif
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
crt_point (uint16 x, uint16 y)
|
||||
{
|
||||
sim_debug(DBG, &crt_dev, "Point %o,%o\n", x, y);
|
||||
#ifdef USE_DISPLAY
|
||||
if (crt_dev.flags & DEV_DIS)
|
||||
return;
|
||||
display_point(x, y, DISPLAY_INT_MAX, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Hook called when CRT goes idle. */
|
||||
void
|
||||
crt_idle (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Display high voltage sync. */
|
||||
void
|
||||
crt_hvc (void)
|
||||
{
|
||||
}
|
||||
58
linc/linc_defs.h
Normal file
58
linc/linc_defs.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* linc_defs.h: LINC simulator definitions
|
||||
|
||||
Copyright (c) 2025, 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.
|
||||
|
||||
17-Sept-25 LB New simulator.
|
||||
*/
|
||||
|
||||
#ifndef LINC_DEFS_H_
|
||||
#define LINC_DEFS_H_ 0
|
||||
|
||||
#include "sim_defs.h"
|
||||
|
||||
#define STOP_HALT 1
|
||||
#define STOP_IBKPT 2
|
||||
#define STOP_RBKPT 3
|
||||
#define STOP_WBKPT 3
|
||||
|
||||
#define MEMSIZE 2048
|
||||
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 M[];
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE crt_dev;
|
||||
extern DEVICE dpy_dev;
|
||||
extern DEVICE kbd_dev;
|
||||
extern DEVICE tape_dev;
|
||||
extern DEVICE tty_dev;
|
||||
|
||||
extern t_bool build_dev_tab(void);
|
||||
extern void dpy_dis(uint16 h, uint16 x, uint16 y);
|
||||
extern void crt_point (uint16 x, uint16 y);
|
||||
extern uint16 kbd_key(uint16 wait);
|
||||
extern int kbd_struck(void);
|
||||
extern void tape_op(void);
|
||||
|
||||
#endif /* LINC_DEFS_H_ */
|
||||
40
linc/linc_dpy.c
Normal file
40
linc/linc_dpy.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "linc_defs.h"
|
||||
|
||||
/* Debug */
|
||||
#define DBG 0001
|
||||
|
||||
static DEBTAB dpy_deb[] = {
|
||||
{ "DBG", DBG },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE dpy_dev = {
|
||||
"DPY", NULL, NULL, NULL,
|
||||
0, 8, 12, 1, 8, 12,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, DEV_DEBUG, 0, dpy_deb,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
void dpy_dis(uint16 h, uint16 x, uint16 y)
|
||||
{
|
||||
sim_debug(DBG, &dpy_dev, "DIS %u;%03o, A=%03o\n", h, x, y);
|
||||
/* Y coordinate +0 and -0 both refer to the same vertical position. */
|
||||
if (y < 256)
|
||||
y += 255;
|
||||
else
|
||||
y -= 256;
|
||||
crt_point(x, y);
|
||||
}
|
||||
|
||||
/* Called from display library to get data switches. */
|
||||
void
|
||||
cpu_get_switches (unsigned long *p1, unsigned long *p2)
|
||||
{
|
||||
}
|
||||
|
||||
/* Called from display library to set data switches. */
|
||||
void
|
||||
cpu_set_switches (unsigned long p1, unsigned long p2)
|
||||
{
|
||||
}
|
||||
427
linc/linc_kbd.c
Normal file
427
linc/linc_kbd.c
Normal file
@@ -0,0 +1,427 @@
|
||||
#include "linc_defs.h"
|
||||
#include "sim_video.h"
|
||||
|
||||
/* Debug */
|
||||
#define DBG 0001
|
||||
|
||||
static t_stat kbd_svc(UNIT *uptr);
|
||||
static t_stat kbd_reset(DEVICE *dptr);
|
||||
|
||||
static UNIT kbd_unit = {
|
||||
UDATA(&kbd_svc, UNIT_IDLE, 0)
|
||||
};
|
||||
|
||||
static DEBTAB kbd_deb[] = {
|
||||
{ "DBG", DBG },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE kbd_dev = {
|
||||
"KBD", &kbd_unit, NULL, NULL,
|
||||
1, 8, 12, 1, 8, 12,
|
||||
NULL, NULL, &kbd_reset,
|
||||
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, kbd_deb,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
/*
|
||||
CASE 0 1 2 3 4 5 6 7 8 9 DEL
|
||||
23 00 01 02 03 04 05 06 07 10 11 13
|
||||
|
||||
Q W E R T Y U I O P i=
|
||||
44 52 30 45 47 54 50 34 42 43 15
|
||||
|
||||
A S D F G H J K L +. -,
|
||||
24 46 27 31 32 33 35 36 37 10 17
|
||||
|
||||
#[ Z X C V B N M pu |⊟ META/EOL
|
||||
22 55 53 26 51 25 41 40 16 21 12
|
||||
|
||||
SPACE
|
||||
14
|
||||
*/
|
||||
|
||||
static int kbd_pressed = 0;
|
||||
static uint16 kbd_code;
|
||||
|
||||
void kbd_translate(int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case '0':
|
||||
kbd_code = 000;
|
||||
break;
|
||||
case '1':
|
||||
kbd_code = 001;
|
||||
break;
|
||||
case '2':
|
||||
kbd_code = 002;
|
||||
break;
|
||||
case '3':
|
||||
kbd_code = 003;
|
||||
break;
|
||||
case '4':
|
||||
kbd_code = 004;
|
||||
break;
|
||||
case '5':
|
||||
kbd_code = 005;
|
||||
break;
|
||||
case '6':
|
||||
kbd_code = 006;
|
||||
break;
|
||||
case '7':
|
||||
kbd_code = 007;
|
||||
break;
|
||||
case '8':
|
||||
kbd_code = 010;
|
||||
break;
|
||||
case '9':
|
||||
kbd_code = 011;
|
||||
break;
|
||||
case '\r': case '\n':
|
||||
kbd_code = 012;
|
||||
break;
|
||||
case '\b': case 0177:
|
||||
kbd_code = 013;
|
||||
break;
|
||||
case ' ':
|
||||
kbd_code = 014;
|
||||
break;
|
||||
case '=': case 'i':
|
||||
kbd_code = 015;
|
||||
break;
|
||||
case 'p': case 'u':
|
||||
kbd_code = 016;
|
||||
break;
|
||||
case ',': case '-':
|
||||
kbd_code = 017;
|
||||
break;
|
||||
case '.': case '+':
|
||||
kbd_code = 020;
|
||||
break;
|
||||
/*case '⊟':*/ case '|':
|
||||
kbd_code = 021;
|
||||
break;
|
||||
case '[': case '#':
|
||||
kbd_code = 022;
|
||||
break;
|
||||
/*case CASE:*/
|
||||
kbd_code = 023;
|
||||
break;
|
||||
case 'A': case 'a':
|
||||
kbd_code = 024;
|
||||
break;
|
||||
case 'B': case 'b':
|
||||
kbd_code = 025;
|
||||
break;
|
||||
case 'C': case 'c':
|
||||
kbd_code = 026;
|
||||
break;
|
||||
case 'D': case 'd':
|
||||
kbd_code = 027;
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
kbd_code = 030;
|
||||
break;
|
||||
case 'F': case 'f':
|
||||
kbd_code = 031;
|
||||
break;
|
||||
case 'G': case 'g':
|
||||
kbd_code = 032;
|
||||
break;
|
||||
case 'H': case 'h':
|
||||
kbd_code = 033;
|
||||
break;
|
||||
case 'I': /*case 'i':*/
|
||||
kbd_code = 034;
|
||||
break;
|
||||
case 'J': case 'j':
|
||||
kbd_code = 035;
|
||||
break;
|
||||
case 'K': case 'k':
|
||||
kbd_code = 036;
|
||||
break;
|
||||
case 'L': case 'l':
|
||||
kbd_code = 037;
|
||||
break;
|
||||
case 'M': case 'm':
|
||||
kbd_code = 040;
|
||||
break;
|
||||
case 'N': case 'n':
|
||||
kbd_code = 041;
|
||||
break;
|
||||
case 'O': case 'o':
|
||||
kbd_code = 042;
|
||||
break;
|
||||
case 'P': /*case 'p':*/
|
||||
kbd_code = 043;
|
||||
break;
|
||||
case 'Q': case 'q':
|
||||
kbd_code = 044;
|
||||
break;
|
||||
case 'R': case 'r':
|
||||
kbd_code = 045;
|
||||
break;
|
||||
case 'S': case 's':
|
||||
kbd_code = 046;
|
||||
break;
|
||||
case 'T': case 't':
|
||||
kbd_code = 047;
|
||||
break;
|
||||
case 'U': /*case 'u':*/
|
||||
kbd_code = 050;
|
||||
break;
|
||||
case 'V': case 'v':
|
||||
kbd_code = 051;
|
||||
break;
|
||||
case 'W': case 'w':
|
||||
kbd_code = 052;
|
||||
break;
|
||||
case 'X': case 'x':
|
||||
kbd_code = 053;
|
||||
break;
|
||||
case 'Y': case 'y':
|
||||
kbd_code = 054;
|
||||
break;
|
||||
case 'Z': case 'z':
|
||||
kbd_code = 055;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
sim_debug(DBG, &kbd_dev, "Key struck %c -> %02o\n", ch, kbd_code);
|
||||
kbd_pressed = 1;
|
||||
}
|
||||
|
||||
static t_stat kbd_svc(UNIT *uptr)
|
||||
{
|
||||
t_stat ch = sim_poll_kbd();
|
||||
|
||||
if ((ch & SCPE_KFLAG) == 0) {
|
||||
sim_activate_after(&kbd_unit, 10000);
|
||||
return ch;
|
||||
}
|
||||
|
||||
if (ch & SCPE_BREAK)
|
||||
;
|
||||
else
|
||||
kbd_translate(ch & 0177);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int kbd_struck(void)
|
||||
{
|
||||
if (kbd_pressed)
|
||||
sim_debug(DBG, &kbd_dev, "KST\n");
|
||||
return kbd_pressed;
|
||||
}
|
||||
|
||||
uint16 kbd_key(uint16 wait)
|
||||
{
|
||||
if (kbd_pressed) {
|
||||
sim_debug(DBG, &kbd_dev, "KEY %02o\n", kbd_code);
|
||||
sim_activate_abs(&kbd_unit, 1);
|
||||
kbd_pressed = 0;
|
||||
return kbd_code;
|
||||
} else {
|
||||
sim_debug(DBG, &kbd_dev, "KEY paused\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbd_convert(uint32 key)
|
||||
{
|
||||
switch (key) {
|
||||
case SIM_KEY_0: /* 0 Q */
|
||||
case SIM_KEY_BACKQUOTE:
|
||||
kbd_code = 000;
|
||||
break;
|
||||
case SIM_KEY_1: /* 1 R */
|
||||
kbd_code = 001;
|
||||
break;
|
||||
case SIM_KEY_2: /* 2 S */
|
||||
kbd_code = 002;
|
||||
break;
|
||||
case SIM_KEY_3: /* 3 T */
|
||||
kbd_code = 003;
|
||||
break;
|
||||
case SIM_KEY_4: /* 4 U */
|
||||
kbd_code = 004;
|
||||
break;
|
||||
case SIM_KEY_5: /* 5 V */
|
||||
kbd_code = 005;
|
||||
break;
|
||||
case SIM_KEY_6: /* 6 W */
|
||||
kbd_code = 006;
|
||||
break;
|
||||
case SIM_KEY_7: /* 7 X */
|
||||
kbd_code = 007;
|
||||
break;
|
||||
case SIM_KEY_8: /* 8 Y */
|
||||
kbd_code = 010;
|
||||
break;
|
||||
case SIM_KEY_9: /* 9 Z */
|
||||
kbd_code = 011;
|
||||
break;
|
||||
case SIM_KEY_ENTER:
|
||||
kbd_code = 012;
|
||||
break;
|
||||
case SIM_KEY_BACKSPACE:
|
||||
case SIM_KEY_DELETE:
|
||||
kbd_code = 013;
|
||||
break;
|
||||
case SIM_KEY_SPACE: /* Space ? */
|
||||
case SIM_KEY_SLASH:
|
||||
kbd_code = 014;
|
||||
break;
|
||||
case SIM_KEY_EQUALS: /* i = */
|
||||
kbd_code = 015;
|
||||
break;
|
||||
case SIM_KEY_F1: /* p u */
|
||||
kbd_code = 016;
|
||||
break;
|
||||
case SIM_KEY_MINUS: /* - , */
|
||||
case SIM_KEY_COMMA:
|
||||
kbd_code = 017;
|
||||
break;
|
||||
case SIM_KEY_PERIOD: /* + . */
|
||||
kbd_code = 020;
|
||||
break;
|
||||
case SIM_KEY_BACKSLASH: /* | ⊟ */
|
||||
kbd_code = 021;
|
||||
break;
|
||||
case SIM_KEY_LEFT_BRACKET: /* # [ */
|
||||
case SIM_KEY_LEFT_BACKSLASH:
|
||||
kbd_code = 022;
|
||||
break;
|
||||
case SIM_KEY_SHIFT_L: /* CASE _ */
|
||||
case SIM_KEY_SHIFT_R:
|
||||
kbd_code = 023;
|
||||
break;
|
||||
case SIM_KEY_A: /* A " */
|
||||
case SIM_KEY_SINGLE_QUOTE:
|
||||
kbd_code = 024;
|
||||
break;
|
||||
case SIM_KEY_B: /* B „ */
|
||||
kbd_code = 025;
|
||||
break;
|
||||
case SIM_KEY_C: /* C < */
|
||||
kbd_code = 026;
|
||||
break;
|
||||
case SIM_KEY_D: /* D > */
|
||||
kbd_code = 027;
|
||||
break;
|
||||
case SIM_KEY_E: /* E ] */
|
||||
case SIM_KEY_RIGHT_BRACKET:
|
||||
kbd_code = 030;
|
||||
break;
|
||||
case SIM_KEY_F: /* F ˣ */
|
||||
kbd_code = 031;
|
||||
break;
|
||||
case SIM_KEY_G: /* G : */
|
||||
case SIM_KEY_SEMICOLON:
|
||||
kbd_code = 032;
|
||||
break;
|
||||
case SIM_KEY_H: /* H */
|
||||
kbd_code = 033;
|
||||
break;
|
||||
case SIM_KEY_I: /* I */
|
||||
kbd_code = 034;
|
||||
break;
|
||||
case SIM_KEY_J: /* J */
|
||||
kbd_code = 035;
|
||||
break;
|
||||
case SIM_KEY_K: /* K */
|
||||
kbd_code = 036;
|
||||
break;
|
||||
case SIM_KEY_L: /* L */
|
||||
kbd_code = 037;
|
||||
break;
|
||||
case SIM_KEY_M: /* M */
|
||||
kbd_code = 040;
|
||||
break;
|
||||
case SIM_KEY_N: /* N */
|
||||
kbd_code = 041;
|
||||
break;
|
||||
case SIM_KEY_O: /* O */
|
||||
kbd_code = 042;
|
||||
break;
|
||||
case SIM_KEY_P: /* P */
|
||||
kbd_code = 043;
|
||||
break;
|
||||
case SIM_KEY_Q: /* Q */
|
||||
kbd_code = 044;
|
||||
break;
|
||||
case SIM_KEY_R: /* R */
|
||||
kbd_code = 045;
|
||||
break;
|
||||
case SIM_KEY_S: /* S */
|
||||
kbd_code = 046;
|
||||
break;
|
||||
case SIM_KEY_T: /* T */
|
||||
kbd_code = 047;
|
||||
break;
|
||||
case SIM_KEY_U: /* U */
|
||||
kbd_code = 050;
|
||||
break;
|
||||
case SIM_KEY_V: /* V */
|
||||
kbd_code = 051;
|
||||
break;
|
||||
case SIM_KEY_W: /* W */
|
||||
kbd_code = 052;
|
||||
break;
|
||||
case SIM_KEY_X: /* X */
|
||||
kbd_code = 053;
|
||||
break;
|
||||
case SIM_KEY_Y: /* Y */
|
||||
kbd_code = 054;
|
||||
break;
|
||||
case SIM_KEY_Z: /* Z */
|
||||
kbd_code = 055;
|
||||
break;
|
||||
case SIM_KEY_ALT_L: /* META? */
|
||||
case SIM_KEY_ALT_R:
|
||||
kbd_code = 056;
|
||||
break;
|
||||
// → 57
|
||||
// ? 60
|
||||
// = 61
|
||||
// u 62
|
||||
// , 63
|
||||
// . 64
|
||||
// ⊟ 65
|
||||
// [ 66
|
||||
// _ 67
|
||||
// " 70
|
||||
// „ 71
|
||||
// < 72
|
||||
// > 73
|
||||
// ] 74
|
||||
// ˣ 75
|
||||
// : 76
|
||||
// ʸ 77
|
||||
default:
|
||||
return;
|
||||
}
|
||||
sim_debug(DBG, &kbd_dev, "Key struck %s -> %02o\n",
|
||||
vid_key_name(key), kbd_code);
|
||||
kbd_pressed = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
kbd_event(SIM_KEY_EVENT *ev)
|
||||
{
|
||||
if (ev->state == SIM_KEYPRESS_DOWN)
|
||||
kbd_convert(ev->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static t_stat
|
||||
kbd_reset(DEVICE *dptr)
|
||||
{
|
||||
#ifdef USE_DISPLAY
|
||||
vid_display_kb_event_process = kbd_event;
|
||||
#endif
|
||||
sim_activate_abs(&kbd_unit, 0);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
593
linc/linc_sys.c
Normal file
593
linc/linc_sys.c
Normal file
@@ -0,0 +1,593 @@
|
||||
/* linc_sys.c: LINC simulator interface
|
||||
|
||||
Copyright (c) 2025, 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.
|
||||
|
||||
17-Sept-25 LB New simulator.
|
||||
*/
|
||||
|
||||
#include "linc_defs.h"
|
||||
|
||||
int32 sim_emax = 1;
|
||||
char sim_name[] = "LINC";
|
||||
|
||||
uint16 M[MEMSIZE];
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&crt_dev,
|
||||
&dpy_dev,
|
||||
&kbd_dev,
|
||||
&tape_dev,
|
||||
&tty_dev,
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *sim_stop_messages[SCPE_BASE] = {
|
||||
"Unknown error",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Read Breakpoint",
|
||||
"Write Breakpoint"
|
||||
};
|
||||
|
||||
static t_stat
|
||||
get_binary_word(FILE *fileref, uint16 *x)
|
||||
{
|
||||
uint16 y;
|
||||
int c = Fgetc(fileref);
|
||||
if (c == EOF)
|
||||
return SCPE_EOF;
|
||||
y = c & 0xFF;
|
||||
c = Fgetc(fileref);
|
||||
if (c == EOF)
|
||||
return SCPE_IOERR;
|
||||
if (c & 0xF0)
|
||||
return SCPE_FMT;
|
||||
*x = y | (c << 8);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat
|
||||
get_octal_word(FILE *fileref, uint16 *x)
|
||||
{
|
||||
uint16 y, i;
|
||||
int c;
|
||||
for (i = 0;;) {
|
||||
c = Fgetc(fileref);
|
||||
if (c == EOF)
|
||||
return SCPE_EOF;
|
||||
if (c >= '0' && c <= '9') {
|
||||
y = c - '0';
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; i < 4;) {
|
||||
c = Fgetc(fileref);
|
||||
if (c == EOF)
|
||||
return SCPE_IOERR;
|
||||
if (c < '0' || c > '9')
|
||||
break;
|
||||
y <<= 3;
|
||||
y |= c - '0';
|
||||
i++;
|
||||
}
|
||||
|
||||
*x = y;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat
|
||||
sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
|
||||
{
|
||||
t_stat (*get_word)(FILE *fileref, uint16 *x) = get_binary_word;
|
||||
t_addr addr, length = MEMSIZE, start = 0, end;
|
||||
long offset = 0;
|
||||
t_stat stat;
|
||||
|
||||
if (sim_switches & SWMASK('O'))
|
||||
get_word = get_octal_word;
|
||||
|
||||
while (cptr != NULL && *cptr != 0) {
|
||||
if (strncasecmp(cptr, "start=", 6) == 0)
|
||||
start = (t_addr)get_uint(cptr + 6, 8, ~0, &stat);
|
||||
else if (strncasecmp(cptr, "offset=", 7) == 0)
|
||||
offset = 2 * (long)get_uint(cptr + 7, 8, ~0, &stat);
|
||||
else if (strncasecmp(cptr, "block=", 6) == 0)
|
||||
offset = 512 * (long)get_uint(cptr + 6, 8, ~0, &stat);
|
||||
else if (strncasecmp(cptr, "length=", 7) == 0)
|
||||
length = (t_addr)get_uint(cptr + 7, 8, ~0, &stat);
|
||||
else
|
||||
return SCPE_ARG;
|
||||
cptr = strchr(cptr, ' ');
|
||||
if (cptr == NULL)
|
||||
break;
|
||||
while (*cptr == ' ')
|
||||
cptr++;
|
||||
}
|
||||
|
||||
end = start + length;
|
||||
if (end > MEMSIZE)
|
||||
end = MEMSIZE;
|
||||
|
||||
sim_fseek(fileref, offset, SEEK_SET);
|
||||
|
||||
for (addr = start; addr < end; addr++) {
|
||||
uint16 x;
|
||||
t_stat stat = get_word(fileref, &x);
|
||||
if (stat == SCPE_EOF)
|
||||
return SCPE_OK;
|
||||
if (stat != SCPE_OK)
|
||||
return stat;
|
||||
M[addr] = x;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_bool build_dev_tab(void)
|
||||
{
|
||||
DEVICE *dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; (dev = sim_devices[i]) != NULL; i++) {
|
||||
;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat fprint_next(FILE *of, uint16 addr)
|
||||
{
|
||||
fprintf(of, "\n");
|
||||
fprint_val(of, ++addr & 01777, 8, 10, PV_LEFT);
|
||||
fprintf(of, ":\t%04o", M[addr]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void fprint_misc(FILE *of, uint16 insn)
|
||||
{
|
||||
switch (insn) {
|
||||
case 00000:
|
||||
fprintf(of, "HLT");
|
||||
break;
|
||||
case 00005:
|
||||
fprintf(of, "ZTA");
|
||||
break;
|
||||
case 00010:
|
||||
fprintf(of, "ENI");
|
||||
break;
|
||||
case 00011:
|
||||
fprintf(of, "CLR");
|
||||
break;
|
||||
case 00013:
|
||||
fprintf(of, "%04o", insn);
|
||||
break;
|
||||
case 00014:
|
||||
fprintf(of, "ATR");
|
||||
break;
|
||||
case 00015:
|
||||
fprintf(of, "RTA");
|
||||
break;
|
||||
case 00016:
|
||||
fprintf(of, "NOP");
|
||||
break;
|
||||
case 00017:
|
||||
fprintf(of, "COM");
|
||||
break;
|
||||
default:
|
||||
fprintf(of, "%04o", insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static t_stat fprint_index(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
if (insn & 020)
|
||||
fprintf(of, " i");
|
||||
if (insn & 017)
|
||||
fprintf(of, " %o", insn & 017);
|
||||
else
|
||||
return fprint_next(of, addr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static void fprint_set(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "SET");
|
||||
fprint_index(of, insn, addr);
|
||||
fprint_next(of, addr);
|
||||
}
|
||||
|
||||
static void fprint_sam(FILE *of, uint16 insn)
|
||||
{
|
||||
fprintf(of, "SAM ");
|
||||
}
|
||||
|
||||
static t_stat fprint_dis(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "DIS");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_xsk(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "XSK");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_rol(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "ROL");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_ror(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "ROR");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_scr(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "SCR");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static void fprint_skip(FILE *of, uint16 insn)
|
||||
{
|
||||
char beta[3];
|
||||
switch (insn & 057) {
|
||||
case 000: case 001: case 002: case 003: case 004: case 005: case 006: case 007:
|
||||
case 010: case 011: case 012: case 013:
|
||||
fprintf(of, "SXL");
|
||||
snprintf(beta, sizeof beta, "%o", insn & 017);
|
||||
break;
|
||||
case 015:
|
||||
fprintf(of, "KST");
|
||||
break;
|
||||
case 040: case 041: case 042: case 043: case 044: case 045:
|
||||
fprintf(of, "SNS ");
|
||||
snprintf(beta, sizeof beta, "%o", insn & 7);
|
||||
break;
|
||||
case 046:
|
||||
fprintf(of, "PIN");
|
||||
break;
|
||||
case 050:
|
||||
fprintf(of, "AZE");
|
||||
break;
|
||||
case 051:
|
||||
fprintf(of, "APO");
|
||||
break;
|
||||
case 052:
|
||||
fprintf(of, "LZE");
|
||||
break;
|
||||
case 053:
|
||||
fprintf(of, "IBZ");
|
||||
break;
|
||||
case 054:
|
||||
fprintf(of, "OVF");
|
||||
break;
|
||||
case 055:
|
||||
fprintf(of, "ZZZ");
|
||||
break;
|
||||
default:
|
||||
fprintf(of, "%04o", insn);
|
||||
return;
|
||||
}
|
||||
if (insn & 020)
|
||||
fprintf(of, " i" );
|
||||
fprintf(of, " %s", beta);
|
||||
}
|
||||
|
||||
static void fprint_opr(FILE *of, uint16 insn)
|
||||
{
|
||||
switch (insn & 07757) {
|
||||
case 0500: case 0501: case 0502: case 0503: case 0504: case 0505: case 0506: case 0507:
|
||||
case 0510: case 0511: case 0512: case 0513:
|
||||
break;
|
||||
case 0535:
|
||||
case 0515:
|
||||
fprintf(of, "KBD ");
|
||||
break;
|
||||
case 0516:
|
||||
fprintf(of, "RSW ");
|
||||
break;
|
||||
case 0517:
|
||||
fprintf(of, "LSW ");
|
||||
break;
|
||||
default:
|
||||
fprintf(of, "%04o", insn);
|
||||
break;
|
||||
}
|
||||
if (insn & 020)
|
||||
fprintf(of, "i" );
|
||||
}
|
||||
|
||||
static void fprint_lmb(FILE *of, uint16 insn)
|
||||
{
|
||||
fprintf(of, "LMB ");
|
||||
}
|
||||
|
||||
static void fprint_umb(FILE *of, uint16 insn)
|
||||
{
|
||||
fprintf(of, "UMB ");
|
||||
}
|
||||
|
||||
static void fprint_tape(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
switch (insn & 0707) {
|
||||
case 0700:
|
||||
fprintf(of, "RDC");
|
||||
break;
|
||||
case 0701:
|
||||
fprintf(of, "RCG");
|
||||
break;
|
||||
case 0702:
|
||||
fprintf(of, "RDE");
|
||||
break;
|
||||
case 0703:
|
||||
fprintf(of, "MTB");
|
||||
break;
|
||||
case 0704:
|
||||
fprintf(of, "WRC");
|
||||
break;
|
||||
case 0705:
|
||||
fprintf(of, "WCG");
|
||||
break;
|
||||
case 0706:
|
||||
fprintf(of, "WRI");
|
||||
break;
|
||||
case 0707:
|
||||
fprintf(of, "CHK");
|
||||
break;
|
||||
}
|
||||
if (insn & 020)
|
||||
fprintf(of, " i");
|
||||
if (insn & 010)
|
||||
fprintf(of, " u");
|
||||
fprint_next(of, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_lda(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "LDA");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_sta(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "STA");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_ada(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "ADA");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_adm(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "ADM");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_lam(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "LAM");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_mul(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "MUL");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_ldh(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "LDH");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_sth(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "STH");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_shd(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "SHD");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_sae(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "SAE");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_sro(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "SRO");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_bcl(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "BCL");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_bse(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "BSE");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_bco(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "BCO");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static t_stat fprint_dsc(FILE *of, uint16 insn, uint16 addr)
|
||||
{
|
||||
fprintf(of, "DSC");
|
||||
return fprint_index(of, insn, addr);
|
||||
}
|
||||
|
||||
static void fprint_add(FILE *of, uint16 insn)
|
||||
{
|
||||
fprintf(of, "ADD %04o", insn & 01777);
|
||||
}
|
||||
|
||||
static void fprint_stc(FILE *of, uint16 insn)
|
||||
{
|
||||
fprintf(of, "STC %04o", insn & 01777);
|
||||
}
|
||||
|
||||
static void fprint_jmp(FILE *of, uint16 insn)
|
||||
{
|
||||
fprintf(of, "JMP %04o", insn & 01777);
|
||||
}
|
||||
|
||||
t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
|
||||
{
|
||||
t_stat stat;
|
||||
|
||||
if ((sw & SWMASK ('M')) == 0)
|
||||
return SCPE_ARG;
|
||||
|
||||
if ((stat = build_dev_tab()) != SCPE_OK)
|
||||
return stat;
|
||||
|
||||
switch (*val & 07740) {
|
||||
case 00000:
|
||||
fprint_misc(of, *val);
|
||||
break;
|
||||
case 00040:
|
||||
fprint_set(of, *val, addr);
|
||||
return -1;
|
||||
case 00100:
|
||||
fprint_sam(of, *val);
|
||||
break;
|
||||
case 00140:
|
||||
fprint_dis(of, *val, addr);
|
||||
break;
|
||||
case 00200:
|
||||
fprint_xsk(of, *val, addr);
|
||||
break;
|
||||
case 00240:
|
||||
fprint_rol(of, *val, addr);
|
||||
break;
|
||||
case 00300:
|
||||
fprint_ror(of, *val, addr);
|
||||
break;
|
||||
case 00340:
|
||||
fprint_scr(of, *val, addr);
|
||||
break;
|
||||
case 00400:
|
||||
case 00440:
|
||||
fprint_skip(of, *val);
|
||||
break;
|
||||
case 00500:
|
||||
case 00540:
|
||||
fprint_opr(of, *val);
|
||||
break;
|
||||
case 00600:
|
||||
fprint_lmb(of, *val);
|
||||
break;
|
||||
case 00640:
|
||||
fprint_umb(of, *val);
|
||||
break;
|
||||
case 00700:
|
||||
case 00740:
|
||||
fprint_tape(of, *val, addr);
|
||||
break;
|
||||
case 01000:
|
||||
return fprint_lda(of, *val, addr);
|
||||
case 01040:
|
||||
return fprint_sta(of, *val, addr);
|
||||
case 01100:
|
||||
return fprint_ada(of, *val, addr);
|
||||
case 01140:
|
||||
return fprint_adm(of, *val, addr);
|
||||
case 01200:
|
||||
return fprint_lam(of, *val, addr);
|
||||
case 01240:
|
||||
return fprint_mul(of, *val, addr);
|
||||
case 01300:
|
||||
return fprint_ldh(of, *val, addr);
|
||||
case 01340:
|
||||
return fprint_sth(of, *val, addr);
|
||||
case 01400:
|
||||
return fprint_shd(of, *val, addr);
|
||||
case 01440:
|
||||
return fprint_sae(of, *val, addr);
|
||||
case 01500:
|
||||
return fprint_sro(of, *val, addr);
|
||||
case 01540:
|
||||
return fprint_bcl(of, *val, addr);
|
||||
case 01600:
|
||||
return fprint_bse(of, *val, addr);
|
||||
case 01640:
|
||||
return fprint_bco(of, *val, addr);
|
||||
case 01740:
|
||||
return fprint_dsc(of, *val, addr);
|
||||
case 02000: case 02040: case 02100: case 02140: case 02200: case 02240: case 02300: case 02340:
|
||||
case 02400: case 02440: case 02500: case 02540: case 02600: case 02640: case 02700: case 02740:
|
||||
case 03000: case 03040: case 03100: case 03140: case 03200: case 03240: case 03300: case 03340:
|
||||
case 03400: case 03440: case 03500: case 03540: case 03600: case 03640: case 03700: case 03740:
|
||||
fprint_add(of, *val);
|
||||
break;
|
||||
case 04000: case 04040: case 04100: case 04140: case 04200: case 04240: case 04300: case 04340:
|
||||
case 04400: case 04440: case 04500: case 04540: case 04600: case 04640: case 04700: case 04740:
|
||||
case 05000: case 05040: case 05100: case 05140: case 05200: case 05240: case 05300: case 05340:
|
||||
case 05400: case 05440: case 05500: case 05540: case 05600: case 05640: case 05700: case 05740:
|
||||
fprint_stc(of, *val);
|
||||
break;
|
||||
case 06000: case 06040: case 06100: case 06140: case 06200: case 06240: case 06300: case 06340:
|
||||
case 06400: case 06440: case 06500: case 06540: case 06600: case 06640: case 06700: case 06740:
|
||||
case 07000: case 07040: case 07100: case 07140: case 07200: case 07240: case 07300: case 07340:
|
||||
case 07400: case 07440: case 07500: case 07540: case 07600: case 07640: case 07700: case 07740:
|
||||
fprint_jmp(of, *val);
|
||||
break;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat parse_sym(CONST char *cptr, t_addr addr, UNIT *uptr,
|
||||
t_value *val, int32 sw)
|
||||
{
|
||||
t_stat stat;
|
||||
*val = get_uint(cptr, 8, ~0, &stat);
|
||||
if (stat != SCPE_OK)
|
||||
return stat;
|
||||
return 0;
|
||||
}
|
||||
439
linc/linc_tape.c
Normal file
439
linc/linc_tape.c
Normal file
@@ -0,0 +1,439 @@
|
||||
#include "linc_defs.h"
|
||||
|
||||
#define POS u3
|
||||
#define SPEED u4
|
||||
#define ACC u5
|
||||
#define OFFSET u6
|
||||
|
||||
#define C (*(uint16 *)cpu_reg[1].loc)
|
||||
#define A (*(uint16 *)cpu_reg[2].loc)
|
||||
#define S (*(uint16 *)cpu_reg[6].loc)
|
||||
#define B (*(uint16 *)cpu_reg[7].loc)
|
||||
#define paused (*(int *)cpu_reg[11].loc)
|
||||
#define IBZ (*(int *)cpu_reg[12].loc)
|
||||
|
||||
#define ACC_START 3
|
||||
#define ACC_REVERSE 6
|
||||
#define ACC_STOP 1
|
||||
#define MAX_SPEED (ACC_START * 625) /* 0.1s / 160µs */
|
||||
#define IBZ_WORDS 5
|
||||
#define DATA_WORDS 256
|
||||
#define OTHER_WORDS 7
|
||||
#define BLOCK_WORDS (IBZ_WORDS + DATA_WORDS + OTHER_WORDS)
|
||||
#define START_POS (ACC_START * (625 + (625 * 625))/2)
|
||||
#define MAX_BLOCKS 512
|
||||
#define MAX_POS ((BLOCK_WORDS * MAX_BLOCKS + IBZ_WORDS) * MAX_SPEED)
|
||||
|
||||
#define RDC 0 /* read tape and check */
|
||||
#define RCG 1 /* read tape group */
|
||||
#define RDE 2 /* read tape */
|
||||
#define MTB 3 /* move toward block */
|
||||
#define WRC 4 /* write tape and check */
|
||||
#define WCG 5 /* write tape group */
|
||||
#define WRI 6 /* write tape */
|
||||
#define CHK 7 /* check tape */
|
||||
|
||||
#define DBG 0001
|
||||
#define DBG_SEEK 0002
|
||||
#define DBG_READ 0004
|
||||
#define DBG_WRITE 0010
|
||||
#define DBG_POS 0020
|
||||
|
||||
static uint16 GROUP;
|
||||
static int16 CURRENT_BLOCK;
|
||||
static int16 WANTED_BLOCK;
|
||||
|
||||
static t_stat tape_svc(UNIT *uptr);
|
||||
static t_stat tape_reset(DEVICE *dptr);
|
||||
static t_stat tape_boot(int32 u, DEVICE *dptr);
|
||||
static t_stat tape_attach(UNIT *uptr, CONST char *cptr);
|
||||
static t_stat tape_detach(UNIT *uptr);
|
||||
|
||||
#define UNIT_FLAGS (UNIT_IDLE|UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE)
|
||||
#define CAPACITY (MAX_BLOCKS * DATA_WORDS)
|
||||
|
||||
static UNIT tape_unit[] = {
|
||||
{ UDATA(&tape_svc, UNIT_FLAGS, CAPACITY) },
|
||||
{ UDATA(&tape_svc, UNIT_FLAGS, CAPACITY) },
|
||||
{ UDATA(&tape_svc, UNIT_DIS, 0) },
|
||||
{ UDATA(&tape_svc, UNIT_DIS, 0) },
|
||||
{ UDATA(&tape_svc, UNIT_FLAGS, CAPACITY) },
|
||||
{ UDATA(&tape_svc, UNIT_FLAGS, CAPACITY) }
|
||||
};
|
||||
|
||||
static DEBTAB tape_deb[] = {
|
||||
{ "DBG", DBG },
|
||||
{ "SEEK", DBG_SEEK },
|
||||
{ "READ", DBG_READ },
|
||||
{ "WRITE", DBG_WRITE },
|
||||
{ "POSITION", DBG_POS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE tape_dev = {
|
||||
"TAPE", tape_unit, NULL, NULL,
|
||||
6, 8, 12, 1, 8, 12,
|
||||
NULL, NULL, &tape_reset,
|
||||
&tape_boot, &tape_attach, &tape_detach,
|
||||
NULL, DEV_DEBUG, 0, tape_deb,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
void tape_op(void)
|
||||
{
|
||||
uint16 u = (C & 050) >> 3;
|
||||
UNIT *uptr = &tape_unit[u];
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return;
|
||||
|
||||
if (uptr->SPEED < 0) {
|
||||
if ((C & 7) != MTB) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "Reverse to forward\n");
|
||||
uptr->ACC = ACC_REVERSE;
|
||||
}
|
||||
} else if (uptr->POS >= MAX_POS) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "End zone; reverse\n");
|
||||
uptr->ACC = ACC_REVERSE;
|
||||
} else if (uptr->SPEED < MAX_SPEED || uptr->ACC < 0) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "Speed up\n");
|
||||
uptr->ACC = ACC_START;
|
||||
}
|
||||
if (!sim_is_active(uptr))
|
||||
sim_activate_after(uptr, 1);
|
||||
paused = 1;
|
||||
A = 0;
|
||||
WANTED_BLOCK = B & 0777;
|
||||
|
||||
switch (C & 7) {
|
||||
case RDC: case RDE: case WRC: case WRI: case CHK:
|
||||
S = 256 * (B >> 9);
|
||||
GROUP = 0;
|
||||
sim_debug(DBG, &tape_dev, "Single tranfer: S=%04o, BN=%03o\n",
|
||||
S, WANTED_BLOCK);
|
||||
break;
|
||||
case RCG: case WCG:
|
||||
S = 256 * (B & 7);
|
||||
GROUP = B >> 9;
|
||||
sim_debug(DBG, &tape_dev, "Group transfer: S=%04o, BN=%03o/%o\n",
|
||||
S, WANTED_BLOCK, GROUP+1);
|
||||
break;
|
||||
case MTB:
|
||||
sim_debug(DBG, &tape_dev, "Move towards block %03o\n", WANTED_BLOCK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static t_stat tape_seek(UNIT *uptr, t_addr block, t_addr offset)
|
||||
{
|
||||
offset = DATA_WORDS * block + offset;
|
||||
offset *= 2;
|
||||
if (sim_fseek(uptr->fileref, offset, SEEK_SET) == -1)
|
||||
return SCPE_IOERR;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static uint16 read_word(UNIT *uptr, t_addr block, t_addr offset)
|
||||
{
|
||||
t_stat stat;
|
||||
uint8 data[2];
|
||||
uint16 word;
|
||||
|
||||
stat = tape_seek(uptr, block, offset);
|
||||
if (stat != SCPE_OK)
|
||||
;
|
||||
if (sim_fread(data, 1, 2, uptr->fileref) != 2)
|
||||
;
|
||||
if (data[1] & 0xF0)
|
||||
;
|
||||
word = data[1];
|
||||
word <<= 8;
|
||||
word |= data[0];
|
||||
return word;
|
||||
}
|
||||
|
||||
static void write_word(UNIT *uptr, t_addr block, t_addr offset, uint16 word)
|
||||
{
|
||||
t_stat stat;
|
||||
uint8 data[2];
|
||||
|
||||
stat = tape_seek(uptr, block, offset);
|
||||
if (stat != SCPE_OK)
|
||||
;
|
||||
data[0] = word & 0xFF;
|
||||
data[1] = word >> 8;
|
||||
if (sim_fwrite(data, 1, 2, uptr->fileref) != 2)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
IBZ BN G block CS C C G BN IBZ
|
||||
5 1 1 256 1 1 1 1 1 5
|
||||
---------------------
|
||||
263
|
||||
--------------------------
|
||||
268
|
||||
|
||||
|
||||
start - 100 ms
|
||||
stop - 300 ms
|
||||
reverse - 100 ms
|
||||
BN to BN at 60 ips - 43 ms
|
||||
block length = 43 ms * 60 inch/s = 2.58 inch
|
||||
|
||||
per word - 160 µs
|
||||
word length = 0.0096 inch
|
||||
words per inch = 104
|
||||
words per second = 6250
|
||||
end zone to end zone - 23 s
|
||||
tape length = 23 * 60 = 1380 inch = 115 feet
|
||||
end zone length = 5 feet
|
||||
|
||||
*/
|
||||
|
||||
static void tape_done(UNIT *uptr)
|
||||
{
|
||||
sim_debug(DBG, &tape_dev, "Done with block\n");
|
||||
|
||||
switch (C & 7) {
|
||||
case RDC: case RCG: case RDE: case CHK:
|
||||
A = 07777;
|
||||
break;
|
||||
case WRI:
|
||||
A = A ^ 07777;
|
||||
A++;
|
||||
A &= 07777;
|
||||
break;
|
||||
case MTB:
|
||||
A = (WANTED_BLOCK + ~CURRENT_BLOCK);
|
||||
A += A >> 12;
|
||||
A &= 07777;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (C & 7) {
|
||||
case RDC:
|
||||
if (A != 07777) {
|
||||
sim_debug(DBG, &tape_dev, "Check failed; read again\n");
|
||||
S &= ~0377;
|
||||
} else {
|
||||
sim_debug(DBG, &tape_dev, "Check passed\n");
|
||||
paused = 0;
|
||||
}
|
||||
break;
|
||||
case WRC:
|
||||
sim_debug(DBG, &tape_dev, "Block written, go back and check\n");
|
||||
// For now, done.
|
||||
A = 07777;
|
||||
paused = 0;
|
||||
break;
|
||||
case RCG: case WCG:
|
||||
if (GROUP == 0) {
|
||||
sim_debug(DBG, &tape_dev, "Done with group\n");
|
||||
paused = 0;
|
||||
} else {
|
||||
sim_debug(DBG, &tape_dev, "Blocks left in group: %d\n", GROUP);
|
||||
GROUP--;
|
||||
}
|
||||
WANTED_BLOCK = (WANTED_BLOCK + 1) & 0777;
|
||||
break;
|
||||
case RDE: case WRI:
|
||||
sim_debug(DBG, &tape_dev, "Transfer done\n");
|
||||
paused = 0;
|
||||
break;
|
||||
case MTB:
|
||||
sim_debug(DBG, &tape_dev, "Move towards block done, result %04o\n", A);
|
||||
paused = 0;
|
||||
break;
|
||||
case CHK:
|
||||
sim_debug(DBG, &tape_dev, "Check done\n");
|
||||
paused = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (paused)
|
||||
;
|
||||
else if ((C & 020) == 0) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "Instruction done, stop tape\n");
|
||||
uptr->ACC = uptr->SPEED > 0 ? -ACC_STOP : ACC_STOP;
|
||||
} else {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "Instruction done, keep moving\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void tape_word(UNIT *uptr, uint16 block, uint16 offset)
|
||||
{
|
||||
switch (C & 7) {
|
||||
case RDC: case RCG: case RDE: case CHK:
|
||||
B = read_word(uptr, block, offset);
|
||||
sim_debug(DBG_READ, &tape_dev,
|
||||
"Read block %03o offset %03o data %04o address %04o\n",
|
||||
block, offset, B, S);
|
||||
if ((C & 7) != CHK)
|
||||
M[S] = B;
|
||||
break;
|
||||
case WRC: case WCG: case WRI:
|
||||
B = M[S];
|
||||
sim_debug(DBG_WRITE, &tape_dev,
|
||||
"Write block %03o offset %03o data %04o address %04o\n",
|
||||
block, offset, B, S);
|
||||
write_word(uptr, block, offset, B);
|
||||
break;
|
||||
}
|
||||
S = (S+1) & 03777;
|
||||
A += B;
|
||||
A &= 07777;
|
||||
}
|
||||
|
||||
static t_stat tape_svc(UNIT *uptr)
|
||||
{
|
||||
long pos, block, offset;
|
||||
|
||||
uptr->SPEED += uptr->ACC;
|
||||
if (uptr->SPEED >= MAX_SPEED) {
|
||||
uptr->SPEED = MAX_SPEED;
|
||||
uptr->ACC = 0;
|
||||
}
|
||||
else if (uptr->SPEED <= -MAX_SPEED) {
|
||||
uptr->SPEED = -MAX_SPEED;
|
||||
uptr->ACC = 0;
|
||||
} else if (uptr->SPEED == 0 && (uptr->ACC == ACC_STOP || uptr->ACC == -ACC_STOP))
|
||||
uptr->ACC = 0;
|
||||
uptr->POS += uptr->SPEED;
|
||||
sim_debug(DBG_POS, &tape_dev, "Speed %d, position %d (block %03o)\n",
|
||||
uptr->SPEED, uptr->POS, uptr->POS / MAX_SPEED / BLOCK_WORDS);
|
||||
|
||||
if (uptr->POS < 0 && uptr->ACC <= 0) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "End zone; stop tape\n");
|
||||
uptr->ACC = ACC_STOP;
|
||||
} else if(uptr->POS >= MAX_POS && uptr->ACC >= 0) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "End zone; stop tape\n");
|
||||
uptr->ACC = -ACC_STOP;
|
||||
}
|
||||
|
||||
if (uptr->SPEED != 0)
|
||||
/* The tape takes 160 microseconds between words. This is
|
||||
approximately 20 memory cycles, 8 microseconds each. */
|
||||
sim_activate(uptr, 20);
|
||||
|
||||
pos = uptr->POS / MAX_SPEED;
|
||||
if (pos < 0)
|
||||
return SCPE_OK;
|
||||
|
||||
block = pos / BLOCK_WORDS;
|
||||
offset = pos % BLOCK_WORDS;
|
||||
if (block >= MAX_BLOCKS)
|
||||
return SCPE_OK;
|
||||
|
||||
IBZ = offset < IBZ_WORDS;
|
||||
if (IBZ)
|
||||
sim_debug(DBG, &tape_dev, "Interblock zone\n");
|
||||
|
||||
if (uptr->SPEED > -MAX_SPEED && uptr->SPEED < MAX_SPEED)
|
||||
return SCPE_OK;
|
||||
|
||||
if (!paused)
|
||||
return SCPE_OK;
|
||||
|
||||
if (uptr->SPEED > 0) {
|
||||
if (offset == 5) {
|
||||
/* Forward block number. */
|
||||
CURRENT_BLOCK = (uint16)(block + uptr->OFFSET);
|
||||
sim_debug(DBG_SEEK, &tape_dev,
|
||||
"Found block number %03o; looking for %03o\n",
|
||||
CURRENT_BLOCK, WANTED_BLOCK);
|
||||
if (CURRENT_BLOCK > WANTED_BLOCK) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "Reverse to find lower block numbers\n");
|
||||
uptr->ACC = -ACC_REVERSE;
|
||||
}
|
||||
if ((C & 7) == MTB)
|
||||
tape_done(uptr);
|
||||
/* Word 6 is a guard. */
|
||||
} else if (offset >= 7 && offset < 263) {
|
||||
if (CURRENT_BLOCK == WANTED_BLOCK)
|
||||
tape_word(uptr, (uint16)block, (uint16)(offset - 7));
|
||||
}
|
||||
else if (offset == 263 && CURRENT_BLOCK == WANTED_BLOCK)
|
||||
/* Checksum here. */
|
||||
tape_done(uptr);
|
||||
}
|
||||
/* Word 264-265 are "C". */
|
||||
/* Word 266 is a guard. */
|
||||
else if (offset == 267 && uptr->SPEED < 0) {
|
||||
/* Reverse block number. */
|
||||
CURRENT_BLOCK = (uint16)(block + uptr->OFFSET);
|
||||
sim_debug(DBG_SEEK, &tape_dev,
|
||||
"Found reverse block number %03o; looking for %03o\n",
|
||||
CURRENT_BLOCK, WANTED_BLOCK);
|
||||
if (CURRENT_BLOCK <= WANTED_BLOCK) {
|
||||
sim_debug(DBG_SEEK, &tape_dev, "Reverse to find higher block numbers\n");
|
||||
uptr->ACC = ACC_REVERSE;
|
||||
uptr->POS -= MAX_SPEED * BLOCK_WORDS;
|
||||
}
|
||||
if ((C & 7) == MTB)
|
||||
tape_done(uptr);
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat tape_reset(DEVICE *dptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat tape_boot(int32 unit_num, DEVICE *dptr)
|
||||
{
|
||||
if (unit_num >= 2 && unit_num <= 3)
|
||||
return SCPE_ARG;
|
||||
|
||||
//LSW = 0701 + (unit_num << 3);
|
||||
//RSW = (7 << 9) | 0300;
|
||||
//P = 020;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat tape_attach(UNIT *uptr, CONST char *cptr)
|
||||
{
|
||||
t_stat stat;
|
||||
t_offset size;
|
||||
if (uptr - tape_unit >= 2 && uptr - tape_unit <= 3)
|
||||
return SCPE_ARG;
|
||||
stat = attach_unit(uptr, cptr);
|
||||
if (stat != SCPE_OK)
|
||||
return stat;
|
||||
size = sim_fsize(uptr->fileref);
|
||||
if (size == MAX_BLOCKS * DATA_WORDS * 2)
|
||||
uptr->OFFSET = 0; /* Plain image. */
|
||||
else if ((size % (2 * DATA_WORDS)) == 6) {
|
||||
/* Extended image with additional meta data. */
|
||||
uint16 metadata = (uint16)(size / (2 * DATA_WORDS));
|
||||
uint16 block_size = read_word(uptr, metadata, 0);
|
||||
int16 forward_offset = (int16)read_word(uptr, metadata, 1);
|
||||
int16 reverse_offset = (int16)read_word(uptr, metadata, 2);
|
||||
sim_debug(DBG, &tape_dev,
|
||||
"Extended image with block size %o, block offset %d/%d\r\n",
|
||||
block_size, forward_offset, reverse_offset);
|
||||
if (block_size != DATA_WORDS)
|
||||
return SCPE_FMT;
|
||||
if (forward_offset != reverse_offset)
|
||||
return SCPE_FMT;
|
||||
uptr->OFFSET = forward_offset;
|
||||
} else
|
||||
return SCPE_FMT;
|
||||
|
||||
uptr->POS = -2 * START_POS;
|
||||
uptr->SPEED = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat tape_detach(UNIT *uptr)
|
||||
{
|
||||
if (uptr - tape_unit >= 2 && uptr - tape_unit <= 3)
|
||||
return SCPE_ARG;
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
return SCPE_OK;
|
||||
if (sim_is_active(uptr))
|
||||
sim_cancel(uptr);
|
||||
return detach_unit(uptr);
|
||||
}
|
||||
6
linc/linc_tty.c
Normal file
6
linc/linc_tty.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "linc_defs.h"
|
||||
|
||||
DEVICE tty_dev = {
|
||||
"TTY", NULL, NULL, NULL,
|
||||
0, 8, 12, 1, 8, 12,
|
||||
};
|
||||
24
makefile
24
makefile
@@ -197,6 +197,10 @@ ifneq (3,${SIM_MAJOR})
|
||||
ifneq (,$(findstring imlac,${MAKECMDGOALS}))
|
||||
VIDEO_USEFUL = true
|
||||
endif
|
||||
# building the LINC needs video support
|
||||
ifneq (,$(findstring linc,${MAKECMDGOALS}))
|
||||
VIDEO_USEFUL = true
|
||||
endif
|
||||
# building the TT2500 needs video support
|
||||
ifneq (,$(findstring tt2500,${MAKECMDGOALS}))
|
||||
VIDEO_USEFUL = true
|
||||
@@ -2013,7 +2017,15 @@ IMLAC = ${IMLACD}/imlac_sys.c ${IMLACD}/imlac_cpu.c \
|
||||
${IMLACD}/imlac_dp.c ${IMLACD}/imlac_crt.c ${IMLACD}/imlac_kbd.c \
|
||||
${IMLACD}/imlac_tty.c ${IMLACD}/imlac_pt.c ${IMLACD}/imlac_bel.c \
|
||||
${DISPLAYL}
|
||||
IMLAC_OPT = -I ${IMLACD} ${DISPLAY_OPT}
|
||||
IMLAC_OPT = -I ${IMLACD} ${DISPLAY_OPT} ${AIO_CCDEFS}
|
||||
|
||||
|
||||
LINCD = ${SIMHD}/linc
|
||||
LINC = ${LINCD}/linc_sys.c ${LINCD}/linc_cpu.c \
|
||||
${LINCD}/linc_crt.c ${LINCD}/linc_dpy.c ${LINCD}/linc_kbd.c \
|
||||
${LINCD}/linc_tape.c ${LINCD}/linc_tty.c \
|
||||
${DISPLAYL}
|
||||
LINC_OPT = -I ${LINCD} ${DISPLAY_OPT} ${AIO_CCDEFS}
|
||||
|
||||
|
||||
TT2500D = ${SIMHD}/tt2500
|
||||
@@ -2021,7 +2033,7 @@ TT2500 = ${TT2500D}/tt2500_sys.c ${TT2500D}/tt2500_cpu.c \
|
||||
${TT2500D}/tt2500_dpy.c ${TT2500D}/tt2500_crt.c ${TT2500D}/tt2500_tv.c \
|
||||
${TT2500D}/tt2500_key.c ${TT2500D}/tt2500_uart.c ${TT2500D}/tt2500_rom.c \
|
||||
${DISPLAYL}
|
||||
TT2500_OPT = -I ${TT2500D} ${DISPLAY_OPT}
|
||||
TT2500_OPT = -I ${TT2500D} ${DISPLAY_OPT} ${AIO_CCDEFS}
|
||||
|
||||
|
||||
PDP8D = ${SIMHD}/PDP8
|
||||
@@ -2514,7 +2526,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \
|
||||
swtp6800mp-a swtp6800mp-a2 tx-0 ssem b5500 intel-mds \
|
||||
scelbi 3b2 3b2-700 i701 i704 i7010 i7070 i7080 i7090 \
|
||||
sigma uc15 pdp10-ka pdp10-ki pdp10-kl pdp10-ks pdp6 i650 \
|
||||
imlac tt2500 sel32
|
||||
imlac linc tt2500 sel32
|
||||
|
||||
all : ${ALL}
|
||||
|
||||
@@ -2592,6 +2604,12 @@ $(BIN)imlac$(EXE) : ${IMLAC} ${SIM}
|
||||
$(MAKEIT) OPTS="$(IMLAC_OPT)"
|
||||
|
||||
|
||||
linc : $(BIN)linc$(EXE)
|
||||
|
||||
$(BIN)linc$(EXE) : ${LINC} ${SIM}
|
||||
$(MAKEIT) OPTS="$(LINC_OPT)"
|
||||
|
||||
|
||||
tt2500 : $(BIN)tt2500$(EXE)
|
||||
|
||||
$(BIN)tt2500$(EXE) : ${TT2500} ${SIM}
|
||||
|
||||
Reference in New Issue
Block a user