simh-testsetgenerator/BESM6/besm6_punch.c
2017-02-06 23:04:40 -08:00

481 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* besm6_punch.c: BESM-6 punchtape devices
*
* Copyright (c) 2009, 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 fs_event (UNIT *u);
UNIT fs_unit [] = {
{ UDATA (fs_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
{ UDATA (fs_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
};
int curchar[2], feed[2], isfifo[2];
char line[2][128];
#define FS1_READY (1<<15)
#define FS2_READY (1<<14)
/* #define NEGATIVE_RDY */
#ifndef NEGATIVE_RDY
# define ENB_RDY SET_RDY
# define DIS_RDY CLR_RDY
# define IS_RDY ISSET_RDY
#else
# define ENB_RDY CLR_RDY
# define DIS_RDY SET_RDY
# define IS_RDY ISCLR_RDY
#endif
#define SET_RDY(x) do READY |= x; while (0)
#define CLR_RDY(x) do READY &= ~(x); while (0)
#define ISSET_RDY(x) ((READY & (x)) != 0)
#define ISCLR_RDY(x) ((READY & (x)) == 0)
#define FS_RATE 1000*MSEC/1500
unsigned char FS[2];
REG fs_reg[] = {
{ REGDATA ( "Готов", READY, 2, 2, 14, 1, NULL, NULL, 0, 0, 0) },
{ ORDATA ( "ФС1500-1", FS[0], 8) },
{ ORDATA ( "ФС1500-2", FS[2], 8) },
{ 0 }
};
MTAB fs_mod[] = {
{ 0 }
};
t_stat fs_reset (DEVICE *dptr);
t_stat fs_attach (UNIT *uptr, CONST char *cptr);
t_stat fs_detach (UNIT *uptr);
DEVICE fs_dev = {
"FS", fs_unit, fs_reg, fs_mod,
2, 8, 19, 1, 8, 50,
NULL, NULL, &fs_reset, NULL, &fs_attach, &fs_detach,
NULL, DEV_DISABLE | DEV_DEBUG
};
#define CARD_LEN 120
enum {
FS_IDLE,
FS_STARTING,
FS_BINARY,
FS_RUNNING,
FS_IMAGE,
FS_IMAGE_LAST = FS_IMAGE + CARD_LEN - 1,
FS_TOOLONG,
FS_FILLUP,
FS_FILLUP_LAST = FS_FILLUP + CARD_LEN - 1,
FS_ENDA3,
FS_ENDA3_LAST = FS_ENDA3 + CARD_LEN - 1,
FS_TAIL,
} fs_state[2];
int fs_textmode[2];
/*
* Reset routine
*/
t_stat fs_reset (DEVICE *dptr)
{
sim_cancel (&fs_unit[0]);
sim_cancel (&fs_unit[1]);
fs_state[0] = fs_state[1] = FS_IDLE;
DIS_RDY(FS1_READY | FS2_READY);
if (fs_unit[0].flags & UNIT_ATT)
ENB_RDY(FS1_READY);
if (fs_unit[1].flags & UNIT_ATT)
ENB_RDY(FS2_READY);
return SCPE_OK;
}
/*
* Attaches a raw binary file by default,
* with a -t switch attaches a prepared text file in UTF-8.
*/
t_stat fs_attach (UNIT *u, CONST char *cptr)
{
t_stat s;
int num = u - fs_unit;
fs_textmode[num] = sim_switches & SWMASK('T');
sim_switches &= ~SWMASK('T');
s = attach_unit (u, cptr);
if (s != SCPE_OK)
return s;
isfifo[num] = (0 == sim_set_fifo_nonblock (u->fileref));
ENB_RDY(FS1_READY >> num);
return SCPE_OK;
}
t_stat fs_detach (UNIT *u)
{
int num = u - fs_unit;
DIS_RDY(FS1_READY >> num);
return detach_unit (u);
}
/*
* Управление двигателем, лампой, протяжкой
*/
void fs_control (int num, uint32 cmd)
{
UNIT *u = &fs_unit[num];
static int bytecnt = 0;
if (fs_dev.dctrl)
besm6_debug("<<< ФС1500-%d команда %o", num, cmd);
if (! IS_RDY(FS1_READY >> num)) {
if (fs_dev.dctrl)
besm6_debug("<<< ФС1500-%d не готово", num, cmd);
return;
}
switch (cmd) {
case 0: /* полное выключение */
sim_cancel (u);
fs_state[num] = FS_IDLE;
if (fs_dev.dctrl)
besm6_debug("<<<ФС1500-%d ВЫКЛ..", num);
bytecnt = 0;
break;
case 4: /* двигатель без протяжки */
fs_state[num] = FS_STARTING;
if (fs_dev.dctrl)
besm6_debug("<<<ФС1500-%d ВКЛ.", num);
sim_cancel (u);
break;
case 5: /* протяжка */
if (fs_state[num] == FS_IDLE)
besm6_debug("<<< ФС1500-%d протяжка без мотора", num);
else if (fs_state[num] != FS_TAIL) {
sim_activate (u, FS_RATE);
bytecnt++;
} else {
if (! isfifo[num]) {
fs_detach(u);
fs_state[num] = FS_IDLE;
}
}
break;
default:
besm6_debug ("<<< ФС1500-%d неизвестная команда %o", num, cmd);
}
if (cmd && fs_dev.dctrl) {
besm6_debug("<<<ФС1500-%d: %d симв.", num, bytecnt);
}
}
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;
}
static int utf8_getc (FILE *fin);
/*
* Событие: читаем очередной символ с перфоленты в регистр.
* Устанавливаем флаг прерывания.
*/
t_stat fs_event (UNIT *u)
{
int num = u - fs_unit;
again:
if (fs_state[num] == FS_STARTING) {
/* The first interrupt after starting the motor is dummy,
* no need to read anything from the attached file.
*/
FS[num] = 0;
fs_state[num] = fs_textmode[num] ? FS_RUNNING : FS_BINARY;
} else if (fs_state[num] == FS_BINARY) {
int ch = getc (u->fileref);
if (ch < 0) {
FS[num] = 0;
fs_state[num] = FS_TAIL;
} else {
FS[num] = ch;
}
} else if (fs_state[num] == FS_RUNNING) {
int ch;
/* Line separators are ignored in running text mode */
do ch = utf8_getc (u->fileref); while (ch == '\n' || ch == '\r');
if (ch < 0) {
/* the tail end of the tape has no holes */
FS[num] = 0;
fs_state[num] = FS_TAIL;
} else if (ch == (']' & 037)) {
/* Switching from running text mode to "virtual punchcard" mode and back
* is done with an ASCII GS (group separator) symbol ctrl-].
*/
fs_state[num] = FS_IMAGE;
goto again;
} else {
FS[num] = unicode_to_upp (ch);
}
} else if (FS_IMAGE <= fs_state[num] && fs_state[num] <= FS_IMAGE_LAST) {
int ch = utf8_getc (u->fileref);
if (ch < 0) {
/* premature end of tape */
FS[num] = 0;
fs_state[num] = FS_TAIL;
} else if (ch == '\r') {
/* always ignored */
goto again;
} else if (ch == '\n') {
/* Start returning zero bytes up to the end of the current "virtual punchard" */
fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE);
goto again;
} else if (ch == (']' & 037)) {
if (fs_state[num] != FS_IMAGE)
besm6_debug("<<< ENDA3 requested mid-card?");
fs_state[num] = FS_ENDA3;
goto again;
} else {
FS[num] = unicode_to_upp (ch);
if (++fs_state[num] == FS_TOOLONG) {
/* If a line is too long (> 120 chars), start the next "virtual punchcard" */
fs_state[num] = FS_IMAGE;
}
}
} else if (FS_FILLUP <= fs_state[num] && fs_state[num] <= FS_FILLUP_LAST) {
FS[num] = 0;
if (++fs_state[num] == FS_ENDA3) {
fs_state[num] = FS_IMAGE;
}
} else if (FS_ENDA3 <= fs_state[num] && fs_state[num] <= FS_ENDA3_LAST) {
if ((fs_state[num] - FS_ENDA3) % 5 == 0)
FS[num] = 0200;
else
FS[num] = 0;
if (++fs_state[num] == FS_TAIL) {
fs_state[num] = FS_RUNNING;
}
} else if (fs_state[num] == FS_IDLE || fs_state[num] == FS_TAIL) {
FS[num] = 0;
}
GRP |= GRP_FS1_SYNC >> num;
return SCPE_OK;
}
int fs_read(int num) {
if (fs_dev.dctrl)
besm6_debug("<<< ФС1500-%d: байт %03o", num, FS[num]);
return FS[num];
}
/*
* Unlike the OS which uses GOST overline (approximated by ^) as a line separator
* in running text mode, the BESM-ALGOL programming system used a nonprintable
* character (0174) from the unused part of the codetable to allow compressing multiple
* source lines on a punchcard. To specify that character,
* we use ASCII RS (record separator) symbol ctrl-^.
*/
unsigned char
unicode_to_gost (unsigned short val)
{
static const unsigned char tab0 [256] = {
/* 00 - 07 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 08 - 0f */ 017, 017, 0214, 017, 017, 017, 017, 017,
/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 0174, 017,
/* !"#$%&' */ 0017, 0133, 0134, 0034, 0127, 0126, 0121, 0033,
/* ()*+,-./ */ 0022, 0023, 0031, 0012, 0015, 0013, 0016, 0014,
/* 01234567 */ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
/* 89:;<=>? */ 0010, 0011, 0037, 0026, 0035, 0025, 0036, 0136,
/* @ABCDEFG */ 0021, 0040, 0042, 0061, 0077, 0045, 0100, 0101,
/* HIJKLMNO */ 0055, 0102, 0103, 0052, 0104, 0054, 0105, 0056,
/* PQRSTUVW */ 0060, 0106, 0107, 0110, 0062, 0111, 0112, 0113,
/* XYZ[\]^_ */ 0065, 0063, 0114, 0027, 017, 0030, 0115, 0132,
/* `abcdefg */ 0032, 0040, 0042, 0061, 0077, 0045, 0100, 0101,
/* hijklmno */ 0055, 0102, 0103, 0052, 0104, 0054, 0105, 0056,
/* pqrstuvw */ 0060, 0106, 0107, 0110, 0062, 0111, 0112, 0113,
/* xyz{|}~ */ 0065, 0063, 0114, 017, 0130, 017, 0123, 017,
/* 80 - 87 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 88 - 8f */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 90 - 97 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 98 - 9f */ 017, 017, 017, 017, 017, 017, 017, 017,
/* a0 - a7 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* a8 - af */ 017, 017, 017, 017, 0123, 017, 017, 017,
/* b0 - b7 */ 0136, 017, 017, 017, 017, 017, 017, 017,
/* b8 - bf */ 017, 017, 017, 017, 017, 017, 017, 017,
/* c0 - c7 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* c8 - cf */ 017, 017, 017, 017, 017, 017, 017, 017,
/* d0 - d7 */ 017, 017, 017, 017, 017, 017, 017, 0024,
/* d8 - df */ 017, 017, 017, 017, 017, 017, 017, 017,
/* e0 - e7 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* e8 - ef */ 017, 017, 017, 017, 017, 017, 017, 017,
/* f0 - f7 */ 017, 017, 017, 017, 017, 017, 017, 0124,
/* f8 - ff */ 017, 017, 017, 017, 017, 017, 017, 017,
};
switch (val >> 8) {
case 0x00:
return tab0 [val];
case 0x04:
switch ((unsigned char) val) {
case 0x10: return 0040;
case 0x11: return 0041;
case 0x12: return 0042;
case 0x13: return 0043;
case 0x14: return 0044;
case 0x15: return 0045;
case 0x16: return 0046;
case 0x17: return 0047;
case 0x18: return 0050;
case 0x19: return 0051;
case 0x1a: return 0052;
case 0x1b: return 0053;
case 0x1c: return 0054;
case 0x1d: return 0055;
case 0x1e: return 0056;
case 0x1f: return 0057;
case 0x20: return 0060;
case 0x21: return 0061;
case 0x22: return 0062;
case 0x23: return 0063;
case 0x24: return 0064;
case 0x25: return 0065;
case 0x26: return 0066;
case 0x27: return 0067;
case 0x28: return 0070;
case 0x29: return 0071;
case 0x2a: return 0135;
case 0x2b: return 0072;
case 0x2c: return 0073;
case 0x2d: return 0074;
case 0x2e: return 0075;
case 0x2f: return 0076;
case 0x30: return 0040;
case 0x31: return 0041;
case 0x32: return 0042;
case 0x33: return 0043;
case 0x34: return 0044;
case 0x35: return 0045;
case 0x36: return 0046;
case 0x37: return 0047;
case 0x38: return 0050;
case 0x39: return 0051;
case 0x3a: return 0052;
case 0x3b: return 0053;
case 0x3c: return 0054;
case 0x3d: return 0055;
case 0x3e: return 0056;
case 0x3f: return 0057;
case 0x40: return 0060;
case 0x41: return 0061;
case 0x42: return 0062;
case 0x43: return 0063;
case 0x44: return 0064;
case 0x45: return 0065;
case 0x46: return 0066;
case 0x47: return 0067;
case 0x48: return 0070;
case 0x49: return 0071;
case 0x4a: return 0135;
case 0x4b: return 0072;
case 0x4c: return 0073;
case 0x4d: return 0074;
case 0x4e: return 0075;
case 0x4f: return 0076;
}
break;
case 0x20:
switch ((unsigned char) val) {
case 0x15: return 0131;
case 0x18: return 0032;
case 0x19: return 0033;
case 0x32: return 0137;
case 0x3e: return 0115;
}
break;
case 0x21:
switch ((unsigned char) val) {
case 0x2f: return 0020;
case 0x91: return 0021;
}
break;
case 0x22:
switch ((unsigned char) val) {
case 0x27: return 0121;
case 0x28: return 0120;
case 0x60: return 0034;
case 0x61: return 0125;
case 0x64: return 0116;
case 0x65: return 0117;
case 0x83: return 0122;
}
break;
case 0x23:
switch ((unsigned char) val) {
case 0xe8: return 0020;
}
break;
case 0x25:
switch ((unsigned char) val) {
case 0xc7: return 0127;
case 0xca: return 0127;
}
break;
}
return 017;
}
/*
* Read Unicode symbol from file.
* Convert from UTF-8 encoding.
*/
static int
utf8_getc (FILE *fin)
{
int c1, c2, c3;
again:
c1 = getc (fin);
if (c1 < 0 || ! (c1 & 0x80))
return c1;
c2 = getc (fin);
if (! (c1 & 0x20))
return (c1 & 0x1f) << 6 | (c2 & 0x3f);
c3 = getc (fin);
if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
/* Skip zero width no-break space. */
goto again;
}
return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f);
}