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:
parent
e9908577fe
commit
89b992d468
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
534
linc/linc_kbd.c
534
linc/linc_kbd.c
@ -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;
|
||||
}
|
||||
|
||||
940
linc/linc_tape.c
940
linc/linc_tape.c
@ -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);
|
||||
}
|
||||
|
||||
248
linc/linc_tty.c
248
linc/linc_tty.c
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user