BESM6: Implemented punched card input and punched tape output

This commit is contained in:
Leo Broukhis 2021-01-02 01:02:15 -08:00
parent 8c42a3436c
commit 5e539dc0b2
9 changed files with 767 additions and 25 deletions

View file

@ -73,7 +73,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
GRP_CHAN5_FREE | GRP_CHAN6_FREE |\
GRP_CHAN7_FREE )
#define PRP_WIRED_BITS (PRP_UVVK1_END | PRP_UVVK2_END |\
#define PRP_WIRED_BITS (PRP_VU1_END | PRP_VU2_END |\
PRP_PCARD1_PUNCH | PRP_PCARD2_PUNCH |\
PRP_PTAPE1_PUNCH | PRP_PTAPE2_PUNCH )
@ -278,6 +278,8 @@ DEVICE *sim_devices[] = {
&clock_dev,
&printer_dev,
&fs_dev,
&pl_dev,
&vu_dev,
&pi_dev,
&tty_dev, /* терминалы - телетайпы, видеотоны, "Консулы" */
0
@ -361,7 +363,7 @@ t_stat cpu_reset (DEVICE *dptr)
M[i] = 0;
/* Punchcard readers not yet implemented thus not ready */
READY2 |= 042000000;
/* READY2 |= 042000000; */
/* Регистр 17: БлП, БлЗ, ПОП, ПОК, БлПр */
M[PSW] = PSW_MMAP_DISABLE | PSW_PROT_DISABLE | PSW_INTR_HALT |
@ -637,8 +639,8 @@ static void cmd_033 ()
*/
break;
case 0150: case 0151:
/* TODO: reading from punchcards */
longjmp (cpu_halt, STOP_UNIMPLEMENTED);
/* sending commands to the punched card readers */
vu_control (Aex - 0150, (uint32) (ACC & 017));
break;
case 0153:
/* гашение аппаратуры сопряжения с терминалами */
@ -657,8 +659,11 @@ static void cmd_033 ()
pi_write (Aex & 7, (uint32) ACC & BITS(20));
break;
case 0170: case 0171:
/* TODO: пробивка строки на перфоленте */
longjmp (cpu_halt, STOP_UNIMPLEMENTED);
/* пробивка строки на перфоленте */
pl_control (Aex & 1, (uint32) ACC & BITS(8));
break;
case 0172: case 0173:
besm6_debug(">>> Potential plotter output: %03o", (uint32) ACC & BITS(8));
break;
case 0174: case 0175:
/* Выдача кода в пульт оператора */
@ -740,6 +745,10 @@ static void cmd_033 ()
* группами по 8 штук каждые несколько секунд. */
ACC = 0;
break;
case 04150: case 04154:
/* считывание строки с устройства ввода с перфоленты */
ACC = vu_read ((Aex - 04150) >> 2);
break;
case 04160: case 04161: case 04162: case 04163:
case 04164: case 04165: case 04166: case 04167:
/* Punchcard output: reading a punched line for checking, 20 bit at a time */

View file

@ -146,6 +146,8 @@ extern DEVICE clock_dev;
extern DEVICE printer_dev;
extern DEVICE tty_dev;
extern DEVICE fs_dev;
extern DEVICE pl_dev;
extern DEVICE vu_dev;
extern DEVICE pi_dev;
extern jmp_buf cpu_halt;
@ -355,6 +357,17 @@ int vt_is_idle (void);
void fs_control (int num, uint32 cmd);
int fs_read (int num);
/*
* Punchtape output.
*/
void pl_control (int num, uint32 cmd);
/*
* Punchcard input.
*/
void vu_control (int num, uint32 cmd);
int vu_read (int num);
/*
* Вывод на перфокарты.
*/
@ -399,8 +412,8 @@ t_value besm6_unpack (t_value val, t_value mask);
#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */
#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */
#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */
#define GRP_UVVK1_SYNC 00200000000000000LL /* 44 */
#define GRP_UVVK2_SYNC 00100000000000000LL /* 43 */
#define GRP_VU1_SYNC 00200000000000000LL /* 44 */
#define GRP_VU2_SYNC 00100000000000000LL /* 43 */
#define GRP_FS1_SYNC 00040000000000000LL /* 42 */
#define GRP_FS2_SYNC 00020000000000000LL /* 41 */
#define GRP_TIMER 00010000000000000LL /* 40 */
@ -443,8 +456,8 @@ t_value besm6_unpack (t_value val, t_value mask);
/*
* Bits of the peripheral interrupt register ПРП (PRP)
*/
#define PRP_UVVK1_END 010000000 /* 22 */
#define PRP_UVVK2_END 004000000 /* 21 */
#define PRP_VU1_END 010000000 /* 22 */
#define PRP_VU2_END 004000000 /* 21 */
#define PRP_PCARD1_CHECK 002000000 /* 20 */
#define PRP_PCARD2_CHECK 001000000 /* 19 */
#define PRP_PCARD1_PUNCH 000400000 /* 18 */

143
BESM6/besm6_pl.c Normal file
View file

@ -0,0 +1,143 @@
/*
* besm6_punch.c: BESM-6 punchtape output
*
* Copyright (c) 2020, Leonid Broukhis
*
* 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
* SERGE VAKULENKO OR LEONID BROUKHIS 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 Leonid Broukhis or
* Serge Vakulenko shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from Leonid Broukhis and Serge Vakulenko.
*/
#include "besm6_defs.h"
t_stat pl_event (UNIT *u);
UNIT pl_unit [] = {
{ UDATA (pl_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
{ UDATA (pl_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
};
#define PL1_READY 04000
#define PL2_READY 02000
#define SET_RDY2(x) do READY2 |= x; while (0)
#define CLR_RDY2(x) do READY2 &= ~(x); while (0)
#define ISSET_RDY2(x) ((READY2 & (x)) != 0)
#define ISCLR_RDY2(x) ((READY2 & (x)) == 0)
#define PL_RATE (int)(12.5*MSEC)
unsigned char PL[2];
t_stat pl_reset (DEVICE *dptr);
t_stat pl_attach (UNIT *uptr, CONST char *cptr);
t_stat pl_detach (UNIT *uptr);
DEVICE pl_dev = {
"PL", pl_unit, NULL, NULL,
2, 8, 19, 1, 8, 50,
NULL, NULL, &pl_reset, NULL, &pl_attach, &pl_detach,
NULL, DEV_DISABLE | DEV_DEBUG
};
t_stat pl_reset (DEVICE *dptr)
{
sim_cancel (&pl_unit[0]);
sim_cancel (&pl_unit[1]);
CLR_RDY2(PL1_READY | PL2_READY);
if (pl_unit[0].flags & UNIT_ATT) {
SET_RDY2(PL1_READY);
}
if (pl_unit[1].flags & UNIT_ATT) {
SET_RDY2(PL2_READY);
}
if (pl_dev.dctrl)
besm6_debug("reset READY2 := %08o", READY2);
return SCPE_OK;
}
t_stat pl_attach (UNIT *u, CONST char *cptr)
{
t_stat s;
int num = u - pl_unit;
s = attach_unit (u, cptr);
if (s != SCPE_OK)
return s;
SET_RDY2(PL1_READY >> num);
if (pl_dev.dctrl)
besm6_debug("attach READY2 := %08o", READY2);
return SCPE_OK;
}
t_stat pl_detach (UNIT *u)
{
int num = u - pl_unit;
CLR_RDY2(PL1_READY >> num);
if (pl_dev.dctrl)
besm6_debug("detach READY2 := %08o", READY2);
return detach_unit (u);
}
void pl_control (int num, uint32 cmd)
{
UNIT *u = &pl_unit[num];
FILE *f = u->fileref;
if (! ISSET_RDY2(PL1_READY >> num)) {
if (pl_dev.dctrl)
besm6_debug("<<< PL80-%d not ready", num);
return;
}
putc(cmd & 0xff, f);
PRP &= ~(PRP_PTAPE1_PUNCH >> num);
CLR_RDY2(PL1_READY >> num);
sim_activate_after(u, PL_RATE);
if (pl_dev.dctrl) {
besm6_debug("PL%d: punching %03o", num, cmd & 0xff);
besm6_debug("punch READY2 := %08o", READY2);
}
}
unsigned char unicode_to_gost (unsigned short val);
/*
* The UPP code is the GOST 10859 code with odd parity.
* UPP stood for "unit for preparation of punchards".
*/
static unsigned char unicode_to_upp (unsigned short ch) {
unsigned char ret;
ch = ret = unicode_to_gost (ch);
ch = (ch & 0x55) + ((ch >> 1) & 0x55);
ch = (ch & 0x33) + ((ch >> 2) & 0x33);
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
return (ch & 1) ? ret : ret | 0x80;
}
t_stat pl_event (UNIT *u)
{
int num = u - pl_unit;
PRP |= PRP_PTAPE1_PUNCH >> num;
SET_RDY2(PL1_READY >> num);
if (pl_dev.dctrl) {
besm6_debug("PL%d event, READY2 := %08o", num, READY2);
}
return SCPE_OK;
}

View file

@ -208,7 +208,7 @@ static unsigned char unicode_to_upp (unsigned short ch) {
return (ch & 1) ? ret : ret | 0x80;
}
static int utf8_getc (FILE *fin);
int utf8_getc (FILE *fin);
/*
* Событие: читаем очередной символ с перфоленты в регистр.
@ -461,7 +461,7 @@ unicode_to_gost (unsigned short val)
* Read Unicode symbol from file.
* Convert from UTF-8 encoding.
*/
static int
int
utf8_getc (FILE *fin)
{
int c1, c2, c3;

View file

@ -28,17 +28,6 @@
*/
#include "besm6_defs.h"
#if 0
/*
* Punchcard input not yet implemented.
*/
t_stat uvvk_event (UNIT *u); /* punched card reader */
UNIT uvvk_unit [] = {
{ UDATA (uvvk_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
{ UDATA (uvvk_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
};
#endif
t_stat pi_event (UNIT *u); /* punched card writer */
UNIT pi_unit [] = {
{ UDATA (pi_event, UNIT_SEQ+UNIT_ATTABLE, 0) },

579
BESM6/besm6_vu.c Normal file
View file

@ -0,0 +1,579 @@
/*
* besm6_vu.c: BESM-6 punchcard reader
*
* Copyright (c) 2020, Leonid Broukhis
*
* 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
* SERGE VAKULENKO OR LEONID BROUKHIS 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 Leonid Broukhis or
* Serge Vakulenko shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from Leonid Broukhis and Serge Vakulenko.
*/
#include "besm6_defs.h"
t_stat vu_event (UNIT *u); /* punched card reader */
UNIT vu_unit [] = {
{ UDATA (vu_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
{ UDATA (vu_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
};
/* Dispak seems to only care about the NOTREADY flag,
* the proper behavior of FEED and MAYSTART may vary.
*/
#define VU1_NOTREADY (1<<23)
#define VU1_FEED (1<<22)
#define VU1_MAYSTART (1<<21)
#define VU2_NOTREADY (1<<19)
#define VU2_FEED (1<<18)
#define VU2_MAYSTART (1<<17)
#define SET_RDY2(x) do READY2 |= x; while (0)
#define CLR_RDY2(x) do READY2 &= ~(x); while (0)
#define ISSET_RDY2(x) ((READY2 & (x)) != 0)
#define ISCLR_RDY2(x) ((READY2 & (x)) == 0)
#define VU_RATE_CPM 600
/* Interrupts are every 2 columns */
#define CARD_LEN (80/2)
#define DFLT_DELAY (60*1000*MSEC/VU_RATE_CPM/CARD_LEN)
/*
* The lines are first converted to GOST 10859; some GOST codes need to be known to the emulator.
*/
#define GOST_DOT 016 /* unpunched position */
#define GOST_O 056 /* punched position */
/* 6 "open quote" characters and an end-of-card indicator, can be entered as `````` */
#define DISP_END "\032\032\032\032\032\032\377"
unsigned int vu_col_dly = DFLT_DELAY;
unsigned int vu_end_dly = DFLT_DELAY/20; /* that seems to work */
unsigned int vu_card_dly = 10*DFLT_DELAY;
unsigned int vu_updkstart[2], vu_updkend[2];
unsigned int VU[2];
REG vu_reg[] = {
{ REGDATA ( Готов, READY2, 2, 8, 16, 1, NULL, NULL, 0, 0, 0) },
{ ORDATA ( ВУ-0, VU[0], 24) },
{ ORDATA ( ВУ-1, VU[1], 24) },
{ 0 }
};
t_stat vu_set_coldly (UNIT *u, int32 val, CONST char *cptr, void *desc)
{
if (cptr && atoi(cptr) > 0) {
vu_col_dly = atoi(cptr);
return SCPE_OK;
} else
sim_printf("Integer value required\n");
return SCPE_ARG;
}
t_stat vu_set_enddly (UNIT *u, int32 val, CONST char *cptr, void *desc)
{
if (cptr && atoi(cptr) > 0) {
vu_end_dly = atoi(cptr);
return SCPE_OK;
} else
sim_printf("Integer value required\n");
return SCPE_ARG;
}
t_stat vu_set_carddly (UNIT *u, int32 val, CONST char *cptr, void *desc)
{
if (cptr && atoi(cptr) > 0) {
vu_card_dly = atoi(cptr);
return SCPE_OK;
} else
sim_printf("Integer value required\n");
return SCPE_ARG;
}
t_stat vu_show_coldly (FILE *st, UNIT *u, int32 v, CONST void *dp)
{
fprintf(st, "Column delay is %d", vu_col_dly);
return SCPE_OK;
}
t_stat vu_show_enddly (FILE *st, UNIT *u, int32 v, CONST void *dp)
{
fprintf(st, "Delay before the end of card is %d", vu_end_dly);
return SCPE_OK;
}
t_stat vu_show_carddly (FILE *st, UNIT *u, int32 v, CONST void *dp)
{
fprintf(st, "Card delay is %d", vu_card_dly);
return SCPE_OK;
}
t_stat vu_set_updk (UNIT *u, int32 val, CONST char *cptr, void *desc)
{
unsigned start, end;
int num = u - vu_unit;
if (!cptr) {
sim_printf("Range set to MAX\n");
vu_updkstart[num] = 1;
vu_updkend[num] = 0;
return SCPE_OK;
}
if (sscanf(cptr, "%u-%u", &start, &end) != 2 ||
(start == 0 && end != 0) || (end != 0 && end < start)) {
sim_printf("Range required, e.g. 10-100, or 0-0 to disable.\n");
return SCPE_ARG;
}
vu_updkstart[num] = start;
vu_updkend[num] = end;
return SCPE_OK;
}
t_stat vu_show_updk (FILE *st, UNIT *u, int32 v, CONST void *dp)
{
int num = u - vu_unit;
if (vu_updkstart[num] == 0 && vu_updkend[num] == 0)
fprintf(st, "UPDK disabled");
else if (vu_updkend[num] == 0)
fprintf(st, "UPDK card %d to EOF", vu_updkstart[num]);
else
fprintf(st, "UPDK cards %d-%d", vu_updkstart[num], vu_updkend[num]);
return SCPE_OK;
}
MTAB vu_mod[] = {
{ MTAB_XTD|MTAB_VDV,
0, "COLDLY", "COLDLY", &vu_set_coldly, &vu_show_coldly, NULL,
"Delay between pair-of-columns interrupts,\n"
"and between the last column interrupt and posedge of the end-of-card signal." },
{ MTAB_XTD|MTAB_VDV,
0, "ENDDLY", "ENDDLY", &vu_set_enddly, &vu_show_enddly, NULL,
"Duration of the end-of-card signal." },
{ MTAB_XTD|MTAB_VDV,
0, "CARDDLY", "CARDDLY", &vu_set_carddly, &vu_show_carddly, NULL,
"Delay between the negedge of the end-of-card signal and the next card interrupt." },
{ MTAB_XTD|MTAB_VUN,
0, "UPDK", "UPDK", &vu_set_updk, &vu_show_updk, NULL,
"Range of cards to be converted to UPDK, e.g. SET UPDK 10-100. Use 0-0 to disable." },
{ 0 }
};
t_stat vu_reset (DEVICE *dptr);
t_stat vu_attach (UNIT *uptr, CONST char *cptr);
t_stat vu_detach (UNIT *uptr);
DEVICE vu_dev = {
"VU", vu_unit, vu_reg, vu_mod,
2, 8, 19, 1, 8, 50,
NULL, NULL, &vu_reset, NULL, &vu_attach, &vu_detach,
NULL, DEV_DISABLE | DEV_DEBUG
};
typedef enum {
VU_IDLE,
VU_STARTING,
VU_COL,
VU_COL_LAST = VU_COL + CARD_LEN - 1,
VU_TAIL, VU_TAIL2
} VU_state;
VU_state vu_state[2], vu_next[2];
int vu_isfifo[2];
// Each card can hold up to 120 bytes; potentially valid GOST chars, expressible in UPDK, are 0-0177.
// True spaces are 017; bytes past the end of line (empty columns) are 0377.
unsigned char vu_gost[2][120];
unsigned short vu_image[2][80];
unsigned int vu_cardcnt[2];
/*
* Reset routine
*/
t_stat vu_reset (DEVICE *dptr)
{
sim_cancel (&vu_unit[0]);
sim_cancel (&vu_unit[1]);
vu_state[0] = vu_state[1] = VU_IDLE;
SET_RDY2(VU1_NOTREADY | VU2_NOTREADY);
if (vu_unit[0].flags & UNIT_ATT) {
CLR_RDY2(VU1_NOTREADY);
}
if (vu_unit[1].flags & UNIT_ATT) {
CLR_RDY2(VU2_NOTREADY);
}
return SCPE_OK;
}
/*
* Attaches a text file in UTF-8. By default the lines are converted to the linewise GOST/UPP
* code as it allows each card to contain up to 120 characters. The columnwise GOST/UPDK code
* is not supported yet.
*/
t_stat vu_attach (UNIT *u, CONST char *cptr)
{
t_stat s;
int num = u - vu_unit;
s = attach_unit (u, cptr);
if (s != SCPE_OK)
return s;
vu_isfifo[num] = (0 == sim_set_fifo_nonblock (u->fileref));
CLR_RDY2(VU1_NOTREADY >> (num*4));
vu_cardcnt[num] = 0;
return SCPE_OK;
}
t_stat vu_detach (UNIT *u)
{
int num = u - vu_unit;
SET_RDY2(VU1_NOTREADY >>(num*4));
return detach_unit (u);
}
/*
* Controlling the card reader.
*/
void vu_control (int num, uint32 cmd)
{
UNIT *u = &vu_unit[num];
if (vu_dev.dctrl)
besm6_debug("<<< VU-%d cmd %o", num, cmd);
if (ISSET_RDY2(VU1_NOTREADY >> (num*4))) {
if (vu_dev.dctrl)
besm6_debug("<<< VU-%d not ready", num, cmd);
return;
}
if (cmd & 010) {
// Resetting the column buffer.
if (vu_dev.dctrl)
besm6_debug("<<< VU-%d buffer reset", num);
VU[num] = 0;
cmd &= ~010;
}
switch (cmd) {
case 2: /* stop */
sim_cancel (u);
vu_state[num] = VU_IDLE;
SET_RDY2(VU1_MAYSTART >> (num*4));
if (vu_dev.dctrl)
besm6_debug("<<< VU-%d OFF", num);
if (vu_state[num] == VU_TAIL) {
if (! vu_isfifo[num]) {
vu_detach(u);
return;
}
}
break;
case 4: /* read card */
case 1: /* read deck */
vu_state[num] = VU_STARTING;
CLR_RDY2(VU1_MAYSTART >> (num*4));
vu_next[num] = cmd == 1 ? VU_STARTING : VU_IDLE;
if (vu_dev.dctrl)
besm6_debug("<<< VU-%d %s read.", num, cmd == 1 ? "DECK" : "CARD");
sim_activate (u, vu_col_dly);
break;
case 0:
break;
default:
besm6_debug ("<<< VU-%d unknown cmd %o", num, cmd);
}
}
extern unsigned char unicode_to_gost(unsigned short);
extern unsigned short gost_to_unicode(unsigned char);
void uni2utf8(unsigned short ch, char buf[5]) {
int i = 0;
if (ch < 0x80) {
buf[i++] = ch & 0x7F;
} else if (ch < 0x800) {
buf[i++] = (ch >> 6 | 0xc0);
buf[i++] = ((ch & 0x3f) | 0x80);
} else {
buf[i++] = (ch >> 12 | 0xe0);
buf[i++] = (((ch >> 6) & 0x3f) | 0x80);
buf[i++] = ((ch & 0x3f) | 0x80);
}
buf[i] = '\0';
}
/*
* Converts a string consisting of 0-9+- digits, plus, or minus to a 12-bit map of punches.
*/
static int punch(const char * s) {
int r = 0;
while (*s) {
r |= *s >= '0' ? 4 << (*s - '0') : *s == '+' ? 1 : *s == '-' ? 2 : 0;
++s;
}
return r;
}
/*
* The UPDK code is a modified
* [GOST 10859-CARD](https://ub.fnwi.uva.nl/computermuseum//DWcodes.html#A056)
* for better distinctiveness wrt other column codes.
* The UPDK codes are taken from Maznyj, "Programming in the Dubna system".
*/
static unsigned short gost_to_updk (unsigned char ch) {
unsigned short ret;
// Assuming that bits in the card are 9876543210-+
// Bits from the upper and lower halves are XORed
static char * upper[4] = { "", "+0", "-0", "+-" };
static char * lower[2][16] = {
{ "0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "082", "083", "084", "085", "086", "087" },
{ "390", "391", "392", "39210", "394", "395", "396", "397",
"398", "39801", "39802", "39821", "39804", "39805", "39806", "39807" }
};
if (ch == 0377 /* filler */ || ch == 017 /* space */) {
ret = 0;
} else {
ret = punch(upper[(ch>>4)&3]) ^ punch(lower[ch>=0100][ch&0xF]);
}
return ret;
}
/*
* The UPP code is the GOST 10859 code with odd parity.
* UPP stood for "unit for preparation of punchards".
*/
static unsigned char gost_to_upp (unsigned char ch) {
unsigned char ret = ch;
ch = (ch & 0x55) + ((ch >> 1) & 0x55);
ch = (ch & 0x33) + ((ch >> 2) & 0x33);
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
return (ch & 1) ? ret : ret | 0x80;
}
static void display_card(int num) {
if (vu_updkstart[num] != 0 || vu_updkend[num] != 0) {
char buf[80];
int i, j;
for (i = 0; i < 12; ++i) {
for (j = 0; j < 80; ++j)
buf[j] = (vu_image[num][j] >> i) & 1 ? 'O' : '.';
besm6_debug("<<< VU-%d: %.80s", num, buf);
}
besm6_debug("<<< VU-%d: ###", num);
}
}
static void reverse_card(int num, int raw) {
char content[500];
int i, j;
memset(vu_image[num], 0, 160);
content[0] = 0;
for (i = 0; i < 120; ++i) {
unsigned char ch = vu_gost[num][i];
int mask = 1 << (i / 10);
int pos = 8 * (i % 10);
if (!raw) {
if (ch == 0377)
break;
ch = gost_to_upp(ch);
}
for (j = 7; j >= 0; --j) {
if (ch & 1)
vu_image[num][pos+j] |= mask;
ch >>= 1;
}
}
}
extern int utf8_getc(FILE*);
static int
is_prettycard (unsigned char *s)
{
int i;
for (i=0; i<80; ++i)
if (s[i] != GOST_DOT && s[i] != GOST_O) {
return 0;
}
for (i = 80; i < 120; ++i)
if (s[i] != 0377)
return 0;
return 1;
}
static int chad (int num, int bit, char val)
{
int index = bit / 8;
switch (val) {
case GOST_O:
vu_gost[num][index] <<= 1;
vu_gost[num][index] |= 1;
return 0;
case GOST_DOT:
vu_gost[num][index] <<= 1;
return 0;
default:
return -1;
}
}
int
prettycard (UNIT *u)
{
int bit, ch;
int num = u - vu_unit;
for (bit = 0; bit < 80; bit++) {
/* The first line is good, no need to check */
chad(num, bit, vu_gost[num][bit]);
}
for (bit = 80; bit < 12*80; bit++) {
ch = utf8_getc(u->fileref);
if (ch == '\n' && bit % 80 == 0)
ch = utf8_getc(u->fileref);
ch = unicode_to_gost(ch);
if (chad(num, bit, ch))
return -1;
if (bit % 80 == 79) {
do ch = utf8_getc(u->fileref); while (ch == '\r');
if (ch != '\n')
return -1;
}
}
/* there may be an empty line after a card */
ch = getc(u->fileref);
if (ch != '\n')
ungetc(ch, u->fileref);
return 0;
}
/*
* Event: reading two characters (two columns) into the register, sending an interrupt.
*/
t_stat vu_event (UNIT *u)
{
int num = u - vu_unit;
if (vu_state[num] == VU_STARTING) {
// Reading a line and forming the GOST array.
int ch;
do
ch = utf8_getc(u->fileref);
while (ch == '\r');
if (ch == EOF) {
if (vu_dev.dctrl) {
besm6_debug("<<< VU-%d: EOF, detaching", num);
}
vu_state[num] = VU_IDLE;
vu_detach(u);
} else {
int endline = 0, i;
++vu_cardcnt[num];
for (i = 0; i < 120; ++i) {
if (endline) {
vu_gost[num][i] = 0377;
} else {
int gost;
if (ch == EOF || ch == '\n') {
endline = 1;
gost = 0377;
} else {
gost = unicode_to_gost(ch);
}
vu_gost[num][i] = gost;
if (!endline && i != 119)
do
ch = utf8_getc(u->fileref);
while (ch == '\r');
}
}
if (!endline) {
int ch;
do
ch = utf8_getc(u->fileref);
while (ch == '\n' || ch == EOF);
}
if (0 == strncmp(vu_gost[num], DISP_END, 7)) {
// The "dispatcher's end" card, end of card image mode.
memset(vu_image[num], 0, 160);
vu_image[num][0] = vu_image[num][40] = 0xFFF;
} else if (is_prettycard(vu_gost[num])) {
if (prettycard(u) < 0) {
sim_printf("VU-%d: A badly formatted card image at card %d, garbage will follow",
num, vu_cardcnt[num]);
}
reverse_card(num, 1); /* raw */
} else if (vu_updkstart[num] != 0 && vu_cardcnt[num] >= vu_updkstart[num] &&
(vu_updkend[num] == 0 || vu_cardcnt[num] <= vu_updkend[num])) {
int i;
for (i = 0; i < 80; ++i)
vu_image[num][i] = gost_to_updk(vu_gost[num][i]);
} else {
reverse_card(num, 0); /* add parity */
}
if (vu_dev.dctrl) {
display_card(num);
besm6_debug("<<< VU-%d: card start", num);
}
GRP |= GRP_VU1_SYNC >> num;
sim_activate(u, vu_col_dly);
vu_state[num] = VU_COL;
VU[num] = 0;
}
} else if (VU_COL <= vu_state[num] && vu_state[num] <= VU_COL_LAST) {
int pos = (vu_state[num]++ - VU_COL) * 2;
VU[num] = (vu_image[num][pos] << 12) | vu_image[num][pos+1];
if (vu_dev.dctrl) {
besm6_debug("<<< VU-%d: cols %d-%d: reg %06x", num, pos+1, pos+2, VU[num]);
}
GRP |= GRP_VU1_SYNC >> num;
sim_activate (u, vu_col_dly);
} else if (vu_state[num] == VU_TAIL) {
PRP |= num == 0 ? PRP_VU1_END : PRP_VU2_END;
vu_state[num] = VU_TAIL2;
sim_activate(u, vu_end_dly);
if (vu_dev.dctrl) {
besm6_debug("<<< VU-%d: ------", num);
}
} else if (vu_state[num] == VU_TAIL2) {
PRP &= ~(num == 0 ? PRP_VU1_END : PRP_VU2_END);
SET_RDY2(VU1_FEED >> (num*4));
if (vu_next[num] == VU_STARTING) {
sim_activate (u, vu_card_dly);
}
vu_state[num] = vu_next[num];
if (vu_dev.dctrl) {
besm6_debug("<<< VU-%d: ======", num);
}
} else {
besm6_debug("<<< VU-%d: spurious event", num);
}
return SCPE_OK;
}
int vu_read(int num) {
if (vu_dev.dctrl)
besm6_debug("<<< VU-%d: reg %06x", num, VU[num]);
return VU[num];
}

View file

@ -215,6 +215,10 @@
RelativePath="..\BESM6\besm6_panel.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_pl.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_printer.c"
>
@ -235,6 +239,10 @@
RelativePath="..\BESM6\besm6_tty.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_vu.c"
>
</File>
<File
RelativePath="..\scp.c"
>

View file

@ -762,7 +762,7 @@ BESM6_LIB = $(LIB_DIR)BESM6-$(ARCH).OLB
BESM6_SOURCE = $(BESM6_DIR)BESM6_CPU.C,$(BESM6_DIR)BESM6_SYS.C,$(BESM6_DIR)BESM6_MMU.C,\
$(BESM6_DIR)BESM6_ARITH.C,$(BESM6_DIR)BESM6_DISK.C,$(BESM6_DIR)BESM6_DRUM.C,\
$(BESM6_DIR)BESM6_TTY.C,$(BESM6_DIR)BESM6_PANEL.C,$(BESM6_DIR)BESM6_PRINTER.C,\
$(BESM6_DIR)BESM6_PUNCHCARD.C,$(BESM6_DIR)BESM6_PUNCH.C
$(BESM6_DIR)BESM6_PUNCHCARD.C,$(BESM6_DIR)BESM6_PUNCH.C,$(BESM6_DIR)BESM6_PL.C,$(BESM6_DIR)BESM6_VU.C
BESM6_OPTIONS = /INCL=($(SIMH_DIR),$(BESM6_DIR))/DEF=($(CC_DEFS),"USE_INT64=1")
#

View file

@ -1935,7 +1935,8 @@ BESM6D = ${SIMHD}/BESM6
BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \
${BESM6D}/besm6_arith.c ${BESM6D}/besm6_disk.c ${BESM6D}/besm6_drum.c \
${BESM6D}/besm6_tty.c ${BESM6D}/besm6_panel.c ${BESM6D}/besm6_printer.c \
${BESM6D}/besm6_punch.c ${BESM6D}/besm6_punchcard.c
${BESM6D}/besm6_pl.c \
${BESM6D}/besm6_punch.c ${BESM6D}/besm6_punchcard.c ${BESM6D}/besm6_vu.c
ifneq (,$(BESM6_BUILD))
BESM6_OPT = -I ${BESM6D} -DUSE_INT64 $(BESM6_PANEL_OPT)