BESM6: Implemented punched card input and punched tape output
This commit is contained in:
parent
8c42a3436c
commit
5e539dc0b2
9 changed files with 767 additions and 25 deletions
|
@ -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 */
|
||||
|
|
|
@ -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
143
BESM6/besm6_pl.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
579
BESM6/besm6_vu.c
Normal 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];
|
||||
}
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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")
|
||||
|
||||
#
|
||||
|
|
3
makefile
3
makefile
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue