1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

linc: Change line endings to simh CRLF standard

These file got missed when the linc simulator was original added
This commit is contained in:
Mark Pizzolato 2025-12-08 12:45:09 -10:00
parent e9908577fe
commit 89b992d468
4 changed files with 901 additions and 901 deletions

View File

@ -1,40 +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)
{
}
#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)
{
}

View File

@ -1,267 +1,267 @@
#include "linc_defs.h"
#include "sim_video.h"
/* Debug */
#define DBG 0001
#define A (*(uint16 *)cpu_reg[2].loc)
#define paused (*(int *)cpu_reg[11].loc)
static t_stat kbd_reset(DEVICE *dptr);
static DEBTAB kbd_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE kbd_dev = {
"KBD", NULL, NULL, NULL,
0, 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;
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);
kbd_pressed = 0;
return kbd_code;
} else if (wait) {
sim_debug(DBG, &kbd_dev, "KEY paused\n");
paused = 1;
}
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
case SIM_KEY_F11:
crt_toggle_fullscreen();
return;
default:
return;
}
sim_debug(DBG, &kbd_dev, "Key struck %s -> %02o\n",
vid_key_name(key), kbd_code);
if (paused)
A = kbd_code;
else
kbd_pressed = 1;
paused = 0;
}
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
return SCPE_OK;
}
#include "linc_defs.h"
#include "sim_video.h"
/* Debug */
#define DBG 0001
#define A (*(uint16 *)cpu_reg[2].loc)
#define paused (*(int *)cpu_reg[11].loc)
static t_stat kbd_reset(DEVICE *dptr);
static DEBTAB kbd_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE kbd_dev = {
"KBD", NULL, NULL, NULL,
0, 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;
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);
kbd_pressed = 0;
return kbd_code;
} else if (wait) {
sim_debug(DBG, &kbd_dev, "KEY paused\n");
paused = 1;
}
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
case SIM_KEY_F11:
crt_toggle_fullscreen();
return;
default:
return;
}
sim_debug(DBG, &kbd_dev, "Key struck %s -> %02o\n",
vid_key_name(key), kbd_code);
if (paused)
A = kbd_code;
else
kbd_pressed = 1;
paused = 0;
}
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
return SCPE_OK;
}

View File

@ -1,470 +1,470 @@
#include "linc_defs.h"
#define POS u3
#define SPEED u4
#define ACC u5
#define OFFSET u6
#define P (*(uint16 *)cpu_reg[0].loc)
#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 LSW (*(uint16 *)cpu_reg[8].loc)
#define RSW (*(uint16 *)cpu_reg[9].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 GOOD_CHECKSUM 07777
#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(uptr, 20);
paused = 1;
A = 0;
WANTED_BLOCK = B & TMASK;
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(FILE *fileref, t_addr block, t_addr offset)
{
offset = DATA_WORDS * block + offset;
offset *= 2;
if (sim_fseek(fileref, offset, SEEK_SET) == -1)
return SCPE_IOERR;
return SCPE_OK;
}
static uint16 read_word(FILE *fileref, t_addr block, t_addr offset)
{
t_stat stat;
uint8 data[2];
uint16 word;
stat = tape_seek(fileref, block, offset);
if (stat != SCPE_OK)
;
if (sim_fread(data, 1, 2, fileref) != 2)
;
if (data[1] & 0xF0)
;
word = data[1];
word <<= 8;
word |= data[0];
return word;
}
static void write_word(FILE *fileref, t_addr block, t_addr offset, uint16 word)
{
t_stat stat;
uint8 data[2];
stat = tape_seek(fileref, block, offset);
if (stat != SCPE_OK)
;
data[0] = word & 0xFF;
data[1] = word >> 8;
if (sim_fwrite(data, 1, 2, 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 = GOOD_CHECKSUM;
break;
case WRI:
A = (A ^ 07777) + 1;
A &= WMASK;
break;
case MTB:
A = (WANTED_BLOCK + ~CURRENT_BLOCK);
A += A >> 12;
A &= WMASK;
break;
}
switch (C & 7) {
case RDC:
if (A != GOOD_CHECKSUM) {
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 = GOOD_CHECKSUM;
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) & TMASK;
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 & IMASK) == 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->fileref, 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->fileref, block, offset, B);
break;
}
S = (S+1) & AMASK;
A += B;
A &= WMASK;
}
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)
{
uint16 block = 0300;
uint16 blocks = 8;
uint16 quarter = 0;
t_stat stat;
if (unit_num >= 2 && unit_num <= 3)
return SCPE_ARG;
if (blocks == 0)
return SCPE_ARG;
if (blocks == 1)
LSW = RDC;
else
LSW = RCG, quarter = blocks - 1;
LSW |= 0700 | (unit_num << 3);
RSW = (quarter << 9) | block;
stat = cpu_do();
if (stat != SCPE_OK)
return stat;
P = 020;
return SCPE_OK;
}
t_stat tape_metadata(FILE *fileref, uint16 *block_size, int16 *forward_offset, int16 *reverse_offset)
{
t_offset size = sim_fsize(fileref);
if (size == MAX_BLOCKS * DATA_WORDS * 2) {
/* Plain image. */
*block_size = DATA_WORDS;
*forward_offset = 0;
*reverse_offset = 0;
} else if ((size % (2 * DATA_WORDS)) == 6) {
/* Extended image with additional meta data. */
uint16 metadata = (uint16)(size / (2 * DATA_WORDS));
*block_size = read_word(fileref, metadata, 0);
*forward_offset = (int16)read_word(fileref, metadata, 1);
*reverse_offset = (int16)read_word(fileref, metadata, 2);
} else
return SCPE_FMT;
return SCPE_OK;
}
static t_stat tape_attach(UNIT *uptr, CONST char *cptr)
{
t_stat stat;
uint16 block_size;
int16 forward_offset, reverse_offset;
if (uptr - tape_unit >= 2 && uptr - tape_unit <= 3)
return SCPE_ARG;
stat = attach_unit(uptr, cptr);
if (stat != SCPE_OK)
return stat;
stat = tape_metadata(uptr->fileref, &block_size, &forward_offset, &reverse_offset);
if (stat != SCPE_OK)
return stat;
sim_debug(DBG, &tape_dev,
"Tape 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;
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);
}
#include "linc_defs.h"
#define POS u3
#define SPEED u4
#define ACC u5
#define OFFSET u6
#define P (*(uint16 *)cpu_reg[0].loc)
#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 LSW (*(uint16 *)cpu_reg[8].loc)
#define RSW (*(uint16 *)cpu_reg[9].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 GOOD_CHECKSUM 07777
#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(uptr, 20);
paused = 1;
A = 0;
WANTED_BLOCK = B & TMASK;
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(FILE *fileref, t_addr block, t_addr offset)
{
offset = DATA_WORDS * block + offset;
offset *= 2;
if (sim_fseek(fileref, offset, SEEK_SET) == -1)
return SCPE_IOERR;
return SCPE_OK;
}
static uint16 read_word(FILE *fileref, t_addr block, t_addr offset)
{
t_stat stat;
uint8 data[2];
uint16 word;
stat = tape_seek(fileref, block, offset);
if (stat != SCPE_OK)
;
if (sim_fread(data, 1, 2, fileref) != 2)
;
if (data[1] & 0xF0)
;
word = data[1];
word <<= 8;
word |= data[0];
return word;
}
static void write_word(FILE *fileref, t_addr block, t_addr offset, uint16 word)
{
t_stat stat;
uint8 data[2];
stat = tape_seek(fileref, block, offset);
if (stat != SCPE_OK)
;
data[0] = word & 0xFF;
data[1] = word >> 8;
if (sim_fwrite(data, 1, 2, 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 = GOOD_CHECKSUM;
break;
case WRI:
A = (A ^ 07777) + 1;
A &= WMASK;
break;
case MTB:
A = (WANTED_BLOCK + ~CURRENT_BLOCK);
A += A >> 12;
A &= WMASK;
break;
}
switch (C & 7) {
case RDC:
if (A != GOOD_CHECKSUM) {
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 = GOOD_CHECKSUM;
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) & TMASK;
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 & IMASK) == 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->fileref, 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->fileref, block, offset, B);
break;
}
S = (S+1) & AMASK;
A += B;
A &= WMASK;
}
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)
{
uint16 block = 0300;
uint16 blocks = 8;
uint16 quarter = 0;
t_stat stat;
if (unit_num >= 2 && unit_num <= 3)
return SCPE_ARG;
if (blocks == 0)
return SCPE_ARG;
if (blocks == 1)
LSW = RDC;
else
LSW = RCG, quarter = blocks - 1;
LSW |= 0700 | (unit_num << 3);
RSW = (quarter << 9) | block;
stat = cpu_do();
if (stat != SCPE_OK)
return stat;
P = 020;
return SCPE_OK;
}
t_stat tape_metadata(FILE *fileref, uint16 *block_size, int16 *forward_offset, int16 *reverse_offset)
{
t_offset size = sim_fsize(fileref);
if (size == MAX_BLOCKS * DATA_WORDS * 2) {
/* Plain image. */
*block_size = DATA_WORDS;
*forward_offset = 0;
*reverse_offset = 0;
} else if ((size % (2 * DATA_WORDS)) == 6) {
/* Extended image with additional meta data. */
uint16 metadata = (uint16)(size / (2 * DATA_WORDS));
*block_size = read_word(fileref, metadata, 0);
*forward_offset = (int16)read_word(fileref, metadata, 1);
*reverse_offset = (int16)read_word(fileref, metadata, 2);
} else
return SCPE_FMT;
return SCPE_OK;
}
static t_stat tape_attach(UNIT *uptr, CONST char *cptr)
{
t_stat stat;
uint16 block_size;
int16 forward_offset, reverse_offset;
if (uptr - tape_unit >= 2 && uptr - tape_unit <= 3)
return SCPE_ARG;
stat = attach_unit(uptr, cptr);
if (stat != SCPE_OK)
return stat;
stat = tape_metadata(uptr->fileref, &block_size, &forward_offset, &reverse_offset);
if (stat != SCPE_OK)
return stat;
sim_debug(DBG, &tape_dev,
"Tape 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;
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);
}

View File

@ -1,124 +1,124 @@
#include "linc_defs.h"
/* Data bits, 110 baud rate. */
#define BIT_TIME 1120
/* Sample rate to find the start bit edge. */
#define START_TIME (BIT_TIME / 5)
/* After finding the edge, wait until the middle of the first data bit. */
#define FIRST_TIME (BIT_TIME + (BIT_TIME - START_TIME) / 2)
#define R (*(uint16 *)cpu_reg[5].loc)
/* Debug */
#define DBG 0001
#define DBG_BIT 0002
#define DATA u3 /* Character being assembled. */
#define STATE u4 /* 0 for start bit, 1 for stop bit, otherwise data. */
#define PREVIOUS u5 /* Previous level seen. */
/* When a start bit is found, the state is set to 10 and then
decremented for each bit that is processed. */
#define STATE_START 0
#define STATE_STOP 1
/* STATE_DATA 2-9 */
#define STATE_FIRST 10
/* Function declaration. */
static t_stat tty_svc(UNIT *uptr);
static t_stat tty_attach(UNIT *uptr, CONST char *cptr);
static t_stat tty_detach(UNIT *uptr);
static UNIT tty_unit = {
UDATA(&tty_svc, UNIT_IDLE | UNIT_ATTABLE, 0)
};
static DEBTAB tty_deb[] = {
{ "DBG", DBG },
{ "BIT", DBG_BIT },
{ NULL, 0 }
};
DEVICE tty_dev = {
"TTY", &tty_unit, NULL, NULL,
1, 8, 12, 1, 8, 12,
NULL, NULL, NULL,
NULL, &tty_attach, &tty_detach,
NULL, DEV_DISABLE | DEV_DEBUG, 0, tty_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static void tty_output(UNIT *uptr)
{
uint8 ch = uptr->DATA;
sim_debug(DBG, &tty_dev, "Character %03o '%c'\n", ch, ch & 0177);
fputc(ch & 0177, uptr->fileref);
fflush(uptr->fileref);
}
static t_stat tty_svc(UNIT *uptr)
{
switch (uptr->STATE) {
case STATE_START:
if (uptr->PREVIOUS == 0 || (R & 1) == 1) {
/* Keep looking for start bit. */
uptr->PREVIOUS = R & 1;
sim_activate(uptr, START_TIME);
return SCPE_OK;
}
sim_debug(DBG_BIT, &tty_dev, "Start bit edge found.\n");
uptr->STATE = STATE_FIRST;
uptr->DATA = 0;
/* Wait until the middle of the first data bit. Since the edge
was just seen, this is a little longer than the time between
data bits. */
sim_activate(uptr, FIRST_TIME);
break;
default:
sim_debug(DBG_BIT, &tty_dev, "Data bit %d is %d\n",
STATE_FIRST - 1 - uptr->STATE, R & 1);
uptr->DATA >>= 1;
uptr->DATA |= (R & 1) << 7;
sim_activate(uptr, BIT_TIME);
break;
case STATE_STOP:
sim_debug(DBG_BIT, &tty_dev, "Stop bit is %d\n", R & 1);
if (R & 1)
tty_output(uptr);
else
sim_debug(DBG, &tty_dev, "Framing error.\n");
uptr->PREVIOUS = R & 1;
/* Look for next start bit. */
sim_activate(uptr, START_TIME);
break;
}
/* Decrease the state counter, first through the data bits, then
the stop bit, and finally the start bit. */
uptr->STATE--;
return SCPE_OK;
}
static t_stat tty_attach(UNIT *uptr, CONST char *cptr)
{
t_stat stat = attach_unit(uptr, cptr);
if (stat != SCPE_OK)
return stat;
uptr->STATE = 0;
uptr->PREVIOUS = 0;
sim_activate(uptr, 1);
return SCPE_OK;
}
static t_stat tty_detach(UNIT *uptr)
{
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_OK;
if (sim_is_active(uptr))
sim_cancel(uptr);
return detach_unit(uptr);
}
#include "linc_defs.h"
/* Data bits, 110 baud rate. */
#define BIT_TIME 1120
/* Sample rate to find the start bit edge. */
#define START_TIME (BIT_TIME / 5)
/* After finding the edge, wait until the middle of the first data bit. */
#define FIRST_TIME (BIT_TIME + (BIT_TIME - START_TIME) / 2)
#define R (*(uint16 *)cpu_reg[5].loc)
/* Debug */
#define DBG 0001
#define DBG_BIT 0002
#define DATA u3 /* Character being assembled. */
#define STATE u4 /* 0 for start bit, 1 for stop bit, otherwise data. */
#define PREVIOUS u5 /* Previous level seen. */
/* When a start bit is found, the state is set to 10 and then
decremented for each bit that is processed. */
#define STATE_START 0
#define STATE_STOP 1
/* STATE_DATA 2-9 */
#define STATE_FIRST 10
/* Function declaration. */
static t_stat tty_svc(UNIT *uptr);
static t_stat tty_attach(UNIT *uptr, CONST char *cptr);
static t_stat tty_detach(UNIT *uptr);
static UNIT tty_unit = {
UDATA(&tty_svc, UNIT_IDLE | UNIT_ATTABLE, 0)
};
static DEBTAB tty_deb[] = {
{ "DBG", DBG },
{ "BIT", DBG_BIT },
{ NULL, 0 }
};
DEVICE tty_dev = {
"TTY", &tty_unit, NULL, NULL,
1, 8, 12, 1, 8, 12,
NULL, NULL, NULL,
NULL, &tty_attach, &tty_detach,
NULL, DEV_DISABLE | DEV_DEBUG, 0, tty_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static void tty_output(UNIT *uptr)
{
uint8 ch = uptr->DATA;
sim_debug(DBG, &tty_dev, "Character %03o '%c'\n", ch, ch & 0177);
fputc(ch & 0177, uptr->fileref);
fflush(uptr->fileref);
}
static t_stat tty_svc(UNIT *uptr)
{
switch (uptr->STATE) {
case STATE_START:
if (uptr->PREVIOUS == 0 || (R & 1) == 1) {
/* Keep looking for start bit. */
uptr->PREVIOUS = R & 1;
sim_activate(uptr, START_TIME);
return SCPE_OK;
}
sim_debug(DBG_BIT, &tty_dev, "Start bit edge found.\n");
uptr->STATE = STATE_FIRST;
uptr->DATA = 0;
/* Wait until the middle of the first data bit. Since the edge
was just seen, this is a little longer than the time between
data bits. */
sim_activate(uptr, FIRST_TIME);
break;
default:
sim_debug(DBG_BIT, &tty_dev, "Data bit %d is %d\n",
STATE_FIRST - 1 - uptr->STATE, R & 1);
uptr->DATA >>= 1;
uptr->DATA |= (R & 1) << 7;
sim_activate(uptr, BIT_TIME);
break;
case STATE_STOP:
sim_debug(DBG_BIT, &tty_dev, "Stop bit is %d\n", R & 1);
if (R & 1)
tty_output(uptr);
else
sim_debug(DBG, &tty_dev, "Framing error.\n");
uptr->PREVIOUS = R & 1;
/* Look for next start bit. */
sim_activate(uptr, START_TIME);
break;
}
/* Decrease the state counter, first through the data bits, then
the stop bit, and finally the start bit. */
uptr->STATE--;
return SCPE_OK;
}
static t_stat tty_attach(UNIT *uptr, CONST char *cptr)
{
t_stat stat = attach_unit(uptr, cptr);
if (stat != SCPE_OK)
return stat;
uptr->STATE = 0;
uptr->PREVIOUS = 0;
sim_activate(uptr, 1);
return SCPE_OK;
}
static t_stat tty_detach(UNIT *uptr)
{
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_OK;
if (sim_is_active(uptr))
sim_cancel(uptr);
return detach_unit(uptr);
}