BESM6: Implemented formatted magnetic tapes.

At the moment formatting has to be done by means of SIMH rather than
using the standard OS mechanism.
This commit is contained in:
Leo Broukhis 2022-02-11 22:41:13 -08:00
parent d960c96f56
commit 9f5e40e240
6 changed files with 630 additions and 12 deletions

View file

@ -274,6 +274,7 @@ DEVICE *sim_devices[] = {
&reg_dev, &reg_dev,
&drum_dev, &drum_dev,
&disk_dev, &disk_dev,
&mg_dev,
&mmu_dev, &mmu_dev,
&clock_dev, &clock_dev,
&printer_dev, &printer_dev,
@ -569,8 +570,11 @@ static void cmd_033 ()
* с магнитными дисками */ * с магнитными дисками */
disk_io (Aex - 3, (uint32) ACC); disk_io (Aex - 3, (uint32) ACC);
break; break;
case 5: case 6: case 7: case 5: case 6:
/* TODO: управление обменом с магнитными лентами */ /* управление обменом с магнитными лентами */
mg_io (Aex - 3, (uint32) ACC);
break;
case 7:
longjmp (cpu_halt, STOP_UNIMPLEMENTED); longjmp (cpu_halt, STOP_UNIMPLEMENTED);
break; break;
case 010: case 011: case 010: case 011:
@ -627,7 +631,7 @@ static void cmd_033 ()
break; break;
case 0141: case 0141:
/* TODO: formatting magnetic tape */ /* TODO: formatting magnetic tape */
longjmp (cpu_halt, STOP_UNIMPLEMENTED); mg_format ((uint32) ACC);
break; break;
case 0142: case 0142:
/* TODO: имитация сигналов прерывания ПРП */ /* TODO: имитация сигналов прерывания ПРП */
@ -720,7 +724,7 @@ static void cmd_033 ()
break; break;
case 04035: case 04035:
/* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */ /* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */
ACC = drum_errors() | disk_errors(); ACC = drum_errors() | disk_errors() | mg_errors();
break; break;
case 04100: case 04100:
/* Опрос телеграфных каналов связи */ /* Опрос телеграфных каналов связи */
@ -732,13 +736,12 @@ static void cmd_033 ()
ACC = READY2; ACC = READY2;
break; break;
case 04103: case 04104: case 04105: case 04106: case 04103: case 04104: case 04105: case 04106:
/* Опрос состояния лентопротяжных механизмов. /* Опрос состояния лентопротяжных механизмов. */
* Все устройства не готовы. */ ACC = mg_state (Aex - 04103);
ACC = BITS(24);
break; break;
case 04107: case 04107:
/* TODO: опрос схемы контроля записи на МЛ */ /* опрос схемы контроля записи на МЛ */
longjmp (cpu_halt, STOP_UNIMPLEMENTED); ACC = 0;
break; break;
case 04115: case 04115:
/* Неизвестное обращение. ДИСПАК выдаёт эту команду /* Неизвестное обращение. ДИСПАК выдаёт эту команду
@ -772,7 +775,8 @@ static void cmd_033 ()
if (0100 <= val && val <= 0137) { if (0100 <= val && val <= 0137) {
/* Управление лентопротяжными механизмами /* Управление лентопротяжными механизмами
* и гашение разрядов регистров признаков * и гашение разрядов регистров признаков
* окончания подвода зоны. Игнорируем. */ * окончания подвода зоны. */
mg_ctl(Aex - 0100, (uint32) ACC);
} else if (04140 <= val && val <= 04157) { } else if (04140 <= val && val <= 04157) {
/* TODO: считывание строки перфокарты */ /* TODO: считывание строки перфокарты */
longjmp (cpu_halt, STOP_UNIMPLEMENTED); longjmp (cpu_halt, STOP_UNIMPLEMENTED);

View file

@ -149,6 +149,7 @@ extern DEVICE fs_dev;
extern DEVICE pl_dev; extern DEVICE pl_dev;
extern DEVICE vu_dev; extern DEVICE vu_dev;
extern DEVICE pi_dev; extern DEVICE pi_dev;
extern DEVICE mg_dev;
extern jmp_buf cpu_halt; extern jmp_buf cpu_halt;
/* /*
@ -333,6 +334,15 @@ void disk_ctl (int ctlr, uint32 cmd);
int disk_state (int ctlr); int disk_state (int ctlr);
int disk_errors (void); int disk_errors (void);
/*
* Magnetic tapes.
*/
void mg_io (int ctlr, uint32 cmd);
void mg_ctl (int ctlr, uint32 cmd);
int mg_state (int ctlr);
void mg_format(uint32 cmd);
int mg_errors (void);
/* /*
* Печать на АЦПУ. * Печать на АЦПУ.
*/ */

600
BESM6/besm6_mg.c Normal file
View file

@ -0,0 +1,600 @@
/*
* BESM-6 magnetic tape device (formatted)
*
* Copyright (c) 2009, Serge Vakulenko
* Copyright (c) 2009-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"
#include <ctype.h>
#include "sim_tape.h"
/*
* I/O command bits
*/
#define MG_BLOCK 0740000000 /* RAM block number - 27-24 рр */
#define MG_READ_SYSDATA 004000000 /* control words only */
#define MG_READ 000400000 /* reading to RAM flag */
#define MG_PAGE 000370000 /* номер страницы памяти */
#define MG_UNIT 000001600 /* номер устройства */
/*
* Tape movement bits
*/
#define MG_CLEARINTR 040000000
#define MG_BACK 000000002 /* 0 - forward, 1 - backward */
#define MG_MOVE 000000001 /* start moving the tape */
#define MG_OFFLINE (1<<8) /* 0 - online, 1 - offline */
#define MG_READONLY (1<<16) /* 0 - r/w, 1 - r/o */
#define MG_MOVING 1 /* 0 - stopped, 1 - moving */
/*
* Параметры обмена с внешним устройством.
*/
typedef struct {
int op; /* Условное слово обмена */
int dev; /* Номер устройства, 0..7 */
int memory; /* Начальный адрес памяти */
int format; /* Флаг разметки */
int last_moving; /* Last unit on which movement started */
int status; /* Регистр состояния */
t_value mask_done, mask_free; /* Маска готовности для ГРП */
int mask_fail; /* Маска ошибки обмена */
t_value *sysdata; /* Буфер системных данных */
} KMT;
static KMT controller [4]; /* Две стойки КМД */
int mg_fail; /* Маска ошибок по направлениям */
t_stat mg_event (UNIT *u);
#define MG_SIZE 0
#define MG_TOTBLK 02010
#define MG_IO_DELAY (200*MSEC)
#define MG_MOVE_DELAY (100*MSEC)
#define MG_GAP_DELAY (10*MSEC)
/*
* MG data structures
*
* mg_dev DISK device descriptor
* mg_unit DISK unit descriptor
* mg_reg DISK register list
*/
UNIT mg_unit [32] = {
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_DIS, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
{ UDATA (mg_event, UNIT_ATTABLE+UNIT_ROABLE, MG_SIZE) },
};
#define in_io u3
#define cmd u4
REG mg_reg[] = {
{ ORDATA (КУС_0, controller[0].op, 24) },
{ ORDATA (УСТР_0, controller[0].dev, 3) },
{ ORDATA (МОЗУ_0, controller[0].memory, 20) },
{ ORDATA (РС_0, controller[0].status, 24) },
{ ORDATA (КУС_1, controller[1].op, 24) },
{ ORDATA (УСТР_1, controller[1].dev, 3) },
{ ORDATA (МОЗУ_1, controller[1].memory, 20) },
{ ORDATA (РС_1, controller[1].status, 24) },
{ ORDATA (КУС_2, controller[2].op, 24) },
{ ORDATA (УСТР_2, controller[2].dev, 3) },
{ ORDATA (МОЗУ_2, controller[2].memory, 20) },
{ ORDATA (РС_2, controller[2].status, 24) },
{ ORDATA (КУС_3, controller[3].op, 24) },
{ ORDATA (УСТР_3, controller[3].dev, 3) },
{ ORDATA (МОЗУ_3, controller[3].memory, 20) },
{ ORDATA (РС_3, controller[3].status, 24) },
{ ORDATA (ОШ, mg_fail, 6) },
{ 0 }
};
MTAB mg_mod[] = {
{ 0 }
};
t_stat mg_reset (DEVICE *dptr);
t_stat mg_attach (UNIT *uptr, CONST char *cptr);
t_stat mg_detach (UNIT *uptr);
DEVICE mg_dev = {
"MG", mg_unit, mg_reg, mg_mod,
32, 8, 21, 1, 8, 50,
NULL, NULL, &mg_reset, NULL, &mg_attach, &mg_detach,
NULL, DEV_DISABLE | DEV_DEBUG | DEV_TAPE
};
/*
* Определение контроллера по устройству.
*/
static KMT *unit_to_ctlr (UNIT *u)
{
return &controller[(u - mg_unit) >> 3];
}
/*
* Reset routine
*/
t_stat mg_reset (DEVICE *dptr)
{
int i;
memset (&controller, 0, sizeof (controller));
controller[2].sysdata = &memory [050];
controller[3].sysdata = &memory [060];
controller[2].mask_done = GRP_CHAN5_DONE;
controller[3].mask_done = GRP_CHAN6_DONE;
controller[2].mask_free = GRP_CHAN5_FREE;
controller[3].mask_free = GRP_CHAN6_FREE;
controller[2].mask_fail = 04;
controller[3].mask_fail = 02;
controller[2].status = BITS(8) << 8; /* r/w, offline, not moving */
controller[3].status = BITS(8) << 8;
// Formatting is allowed only on controller 3
controller[3].last_moving = -1;
controller[3].format = 0;
for (i=16; i<32; ++i) {
if (mg_unit[i].flags & UNIT_ATT) {
controller[i/8].status &= ~(MG_OFFLINE << (i%8));
if (mg_unit[i].flags & UNIT_RO) {
controller[i/8].status |= MG_READONLY << (i%8);
}
}
mg_unit[i].in_io = 0;
sim_cancel (&mg_unit[i]);
}
return SCPE_OK;
}
t_stat mg_attach (UNIT *u, CONST char *cptr)
{
t_stat s;
int32 saved_switches = sim_switches;
int num = (u - mg_unit) & 7;
int ctrl = (u - mg_unit) / 8;
sim_switches |= SWMASK ('E');
while (1) {
s = sim_tape_attach (u, cptr);
if ((s == SCPE_OK) && (sim_switches & SWMASK ('N'))) {
t_value fullzone[8+1024];
t_value * control = fullzone; /* block (zone) number, key, userid, checksum */
t_value * zone = fullzone + 8;
t_value funit = u - mg_unit + 030;
int tapeno, blkno, word;
char *filenamepart = NULL;
char *pos;
/* Using the rightmost sequence of digits within the filename
* provided in the command line as a volume number,
* e.g. "/var/tmp/besm6/2052.bin" -> 2052
*/
filenamepart = sim_filepath_parts (u->filename, "n");
pos = filenamepart + strlen(filenamepart);
while (pos > filenamepart && !isdigit(*--pos));
while (pos > filenamepart && isdigit(*pos)) --pos;
if (!isdigit(*pos)) ++pos;
tapeno = strtoul (pos, NULL, 10);
free (filenamepart);
if (tapeno == 0 || tapeno >= 2048) {
if (tapeno == 0)
s = sim_messagef (SCPE_ARG,
"%s: filename must contain volume number 1..2047\n",
sim_uname(u));
else
s = sim_messagef (SCPE_ARG,
"%s: tape volume %d from filename %s invalid (must be 1..2047)\n",
sim_uname (u), tapeno, cptr);
filenamepart = strdup (u->filename);
sim_tape_detach (u);
remove (filenamepart);
free (filenamepart);
return s; /* not formatting */
}
sim_messagef (SCPE_OK, "%s: formatting tape volume %d\n", sim_uname (u), tapeno);
control[0] = SET_PARITY(funit << 42 | (memory[0221] & 0377774000000LL), PARITY_NUMBER);
control[1] = SET_PARITY(0x987654321000LL, PARITY_NUMBER); /* task ID */
control[2] = SET_PARITY((t_value)tapeno << 30 | tapeno, PARITY_NUMBER);
control[4] = SET_PARITY(12345, PARITY_NUMBER); /* time */
control[5] = SET_PARITY(0, PARITY_NUMBER); /* last word */
control[7] = SET_PARITY(0, PARITY_NUMBER); /* checksum */
for (word = 0; word < 02000; ++word) {
zone[word] = SET_PARITY(0, PARITY_NUMBER);
}
for (blkno = 0; blkno < MG_TOTBLK; ++blkno) {
int zno = blkno / 2;
control[3] = SET_PARITY(070707LL << 24 | zno << 13 | blkno, PARITY_NUMBER);
control[6] = control[3];
sim_tape_wrrecf(u, (uint8*)fullzone, sizeof(fullzone));
// sim_tape_wrgap(u, 20);
}
sim_tape_wrtmk(u);
sim_tape_wrtmk(u);
sim_tape_rewind(u);
break;
}
if (s == SCPE_OK ||
(saved_switches & SWMASK ('E')) ||
(sim_switches & SWMASK('N')))
break;
sim_switches |= SWMASK ('N');
}
if (sim_switches & SWMASK ('R'))
controller[ctrl].status |= MG_READONLY << num;
else
controller[ctrl].status &= ~(MG_READONLY << num);
/* ready */
controller[ctrl].status &= ~(MG_OFFLINE << num);
GRP |= controller[ctrl].mask_free;
return SCPE_OK;
}
t_stat mg_detach (UNIT *u)
{
/* TODO: сброс бита ГРП готовности направления при отключении последнего устройства. */
int num = (u - mg_unit) & 7;
int ctrl = (u - mg_unit) / 8;
/* Set RO, not ready */
controller[ctrl].status |= (1 << (16 + num));
controller[ctrl].status |= (1 << (8 + num));
return sim_tape_detach (u);
}
/*
* Отладочная печать массива данных обмена.
*/
static void log_data (t_value *data, int nwords)
{
int i;
t_value val;
for (i=0; i<nwords; ++i) {
val = data[i];
fprintf (sim_log, " %04o-%04o-%04o-%04o",
(int) (val >> 36) & 07777,
(int) (val >> 24) & 07777,
(int) (val >> 12) & 07777,
(int) val & 07777);
if ((i & 3) == 3)
fprintf (sim_log, "\n");
}
if ((i & 3) != 0)
fprintf (sim_log, "\n");
}
/*
* Writing to a tape.
*/
void mg_write (UNIT *u)
{
KMT *c = unit_to_ctlr (u);
int unit = u - mg_unit;
int ret;
t_value fullzone[8+1024];
int page = (u->cmd & MG_PAGE) >> 2 | (u->cmd & MG_BLOCK) >> 8;
if (mg_dev.dctrl)
sim_printf ("::: writing MG%d mem %05o\n",
unit, page);
memcpy(fullzone, c->sysdata, 8*sizeof(t_value));
memcpy(fullzone+8, &memory[page], 1024*sizeof(t_value));
ret = sim_tape_wrrecf (u, (uint8*) fullzone, sizeof(fullzone));
if (ret != MTSE_OK) {
mg_fail |= c->mask_fail;
}
}
/*
* Controlling formatting mode:
* 0 - disable, 2 - create gap, 3 - create synchrotrack
*/
void mg_format (uint32 op)
{
KMT *c = &controller[3];
c->format = op & 3;
if (mg_dev.dctrl)
sim_printf("Format mode %d\n", op);
switch (op & 3) {
case 0:
if (c->last_moving != -1) {
sim_printf("Formatting off on MG%d\n", c->last_moving);
}
// c->last_moving = -1;
break;
case 1:
sim_printf("Formatting mode 1 does not exist\n");
break;
case 2:
// When mode 2 (erasure) is enabled, if the tape is not yet moving,
// nothing happens; if the tape is already moving, the movement ceases
// to be self-sustaining; the runoff is 50 ms
if (c->last_moving != -1) {
int num = c->last_moving & 7;
UNIT * u = mg_unit + c->last_moving;
if (c->status & (MG_MOVING << num)) {
sim_cancel(u);
sim_activate(u, MG_GAP_DELAY);
sim_printf("Block runoff on MG%d\n", c->last_moving);
}
}
break;
case 3:
// A tape must already be moving
if (c->last_moving == -1) {
sim_printf("Enabling synchrotrack on a stationary tape?\n");
} else {
UNIT * u = mg_unit + c->last_moving;
int num = c->last_moving & 7;
if (c->status & (MG_MOVING << num)) {
t_value fullzone[8+1024];
sim_cancel(u);
u->in_io = 0;
sim_printf("(in_io = 0) Extending block on MG%d\n", c->last_moving);
// Writing the synchrotrack for a zone is like writing a zone of arbitrary values
sim_tape_wrrecf(u, (uint8*) fullzone, sizeof(fullzone));
// Writing the synchrotrack is self-sustaining, no end event requested.
sim_printf("Formatting block on MG%d\n", c->last_moving);
}
}
}
}
/*
* Reading from a tape.
*/
void mg_read (UNIT *u)
{
KMT *c = unit_to_ctlr (u);
t_mtrlnt len;
t_value fullzone[8+1024];
int ret;
int unit = u - mg_unit;
int page = (u->cmd & MG_PAGE) >> 2 | (u->cmd & MG_BLOCK) >> 8;
if (mg_dev.dctrl)
sim_printf ((u->cmd & MG_READ_SYSDATA) ?
"::: reading MG%d control words\n" :
"::: reading MG%d mem %05o\n",
unit, page);
ret = sim_tape_rdrecf (u, (uint8*) fullzone, &len, sizeof(t_value)*(8+1024));
if (ret != MTSE_OK || len != sizeof(t_value)*(8+1024)) {
/* Bad tape format */
if (mg_dev.dctrl)
sim_printf("MG%d: Bad read: ret %d len %d\n", unit, ret, len);
mg_fail |= c->mask_fail;
return;
}
memcpy(c->sysdata, fullzone, 8*sizeof(t_value));
if (! (u->cmd & MG_READ_SYSDATA)) {
memcpy(&memory [page], fullzone+8, 8*1024);
}
}
/*
* Specifying the operation (read/write) and the memory location.
* The actial I/O is initiated by a move command.
*/
void mg_io (int ctlr, uint32 op)
{
KMT *c = &controller [ctlr];
c->op = op;
c->dev = (op >> 7) & 7;
c->memory = (op & MG_PAGE) >> 2 | (op & MG_BLOCK) >> 8;
if (mg_dev.dctrl)
sim_printf ("::: MG%d: %s %s %08o\n",
ctlr*8 + c->dev,
(c->op & MG_READ) ? "read" : "write",
(c->op & MG_READ_SYSDATA) ? "sysdata" : "",
op);
mg_fail &= ~c->mask_fail;
/* Гасим главный регистр прерываний. */
GRP &= ~c->mask_free;
}
/*
* Moving the tape.
*/
void mg_ctl (int unit, uint32 op)
{
UNIT *u = &mg_unit [unit];
KMT *c = unit_to_ctlr (u);
int move, back;
if (op == MG_CLEARINTR) {
// Only the controller number matters, unit is not used.
GRP &= ~c->mask_done;
return;
}
if (op & MG_CLEARINTR) {
sim_printf("Clearing interrupts AND attempting to do something else (%08o)?\n", op);
longjmp (cpu_halt, SCPE_IOERR);
}
if ((mg_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) {
/* Device not attached. */
if (op != 0 && mg_dev.dctrl)
sim_printf("::: MG%d: unattached, but control %08o issued\n", unit, op);
mg_fail |= c->mask_fail;
return;
}
mg_fail &= ~c->mask_fail;
c->last_moving = unit;
if (c->format) {
c->status |= MG_MOVING << (unit & 7);
if (c->format == 3) {
// Must not be happening: starting from the stationary position
// while writing the synchrotrack is bad.
sim_printf("Accelerating while writing the synchrotrack is a bad idea.\n");
// Moving with synchrotrack is self-sustaining, no activation needed.
} else if (c->format == 2) {
// Erasing, will sustain for about 50 ms
sim_printf("Erasing MG%d\n", unit);
sim_activate (u, MG_GAP_DELAY);
} else if (c->format == 1) {
if (mg_dev.dctrl)
sim_printf("WHAT IS FORMAT 1?\n");
}
return;
}
move = op & MG_MOVE;
back = op & MG_BACK;
if ((unit & 7) == c->dev && move && !back) {
/* Reading or writing */
if (!(c->op & MG_READ) && u->flags & UNIT_RO) {
/* Read only. */
mg_fail |= c->mask_fail;
return;
}
u->cmd = c->op;
u->in_io = 1;
sim_printf("MG%d: in_io = 1\n", unit);
c->status |= MG_MOVING << (unit & 7);
sim_activate (u, MG_IO_DELAY);
} else if (move) {
t_mtrlnt len;
if (back) {
if (sim_tape_bot (u)) {
if (mg_dev.dctrl)
sim_printf("MG%d: at BOT, nowhere to step back\n", unit);
sim_activate (u, MG_GAP_DELAY);
} else {
if (mg_dev.dctrl)
sim_printf("MG%d: Step back\n", unit);
sim_tape_sprecr (u, &len);
sim_activate (u, MG_MOVE_DELAY);
}
} else {
if (mg_dev.dctrl)
sim_printf("MG%d: Step forward\n", unit);
sim_tape_sprecf (u, &len);
sim_activate (u, MG_MOVE_DELAY);
}
c->status |= MG_MOVING << (unit & 7);
} else {
if (mg_dev.dctrl)
sim_printf("Invalid command combination for MG%d: %08o\n", unit, op);
}
}
/*
* Запрос состояния контроллера.
*/
int mg_state (int ctlr)
{
KMT *c = &controller [ctlr];
static uint32 prev[4];
if (mg_dev.dctrl && c->status != prev[ctlr]) {
char status[24];
int i;
// Some tapes are online
sim_printf("::: MG%02d-%02d: READONLY-ONLINE--MOVING-\n", ctlr*8+7, ctlr*8);
for (i = 0; i < 8; ++i) {
status[23-i] = c->status & (MG_MOVING << i) ? '0'+i : ' ';
status[15-i] = c->status & (MG_OFFLINE << i) ? ' ': '0'+i;
status[7-i] = c->status & (MG_READONLY << i) ? '0'+i : ' ';
}
sim_printf("::: MG%02d-%02d: %.24s\n", ctlr*8+7, ctlr*8, status);
prev[ctlr] = c->status;
}
return c->status;
}
/*
* End of I/O, sending an interrupt.
*/
t_stat mg_event (UNIT *u)
{
KMT *c = unit_to_ctlr (u);
int unit = u - mg_unit;
int num = unit & 7;
if (u->in_io) {
if (u->cmd & MG_READ) {
mg_read(u);
} else {
mg_write(u);
}
GRP |= c->mask_free;
u->in_io = 0;
sim_activate (u, MG_GAP_DELAY);
if (mg_dev.dctrl)
sim_printf("::: MG%d: (in_io = 0) end of I/O event\n", unit);
} else {
c->status &= ~(MG_MOVING << num);
c->status &= ~(MG_OFFLINE << num);
GRP |= c->mask_done;
// if (mg_dev.dctrl)
sim_printf("::: MG%d: stopping event\n", unit);
}
return SCPE_OK;
}
/*
* Опрос ошибок обмена командой 033 4035.
*/
int mg_errors ()
{
#if 0
if (mg_dev.dctrl)
sim_printf ("::: КМД: опрос шкалы ошибок = %04o\n", mg_fail);
#endif
return mg_fail;
}

View file

@ -207,6 +207,10 @@
RelativePath="..\BESM6\besm6_drum.c" RelativePath="..\BESM6\besm6_drum.c"
> >
</File> </File>
<File
RelativePath="..\BESM6\besm6_mg.c"
>
</File>
<File <File
RelativePath="..\BESM6\besm6_mmu.c" RelativePath="..\BESM6\besm6_mmu.c"
> >

View file

@ -760,7 +760,7 @@ SWTP6800MP_A2_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP6800MP_A2_DIR))/DEF=($(CC_DEFS)
BESM6_DIR = SYS$DISK:[.BESM6] BESM6_DIR = SYS$DISK:[.BESM6]
BESM6_LIB = $(LIB_DIR)BESM6-$(ARCH).OLB 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_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_ARITH.C,$(BESM6_DIR)BESM6_DISK.C,$(BESM6_DIR)BESM6_DRUM.C,$(BESM6_DIR)BESM6_MG.C,\
$(BESM6_DIR)BESM6_TTY.C,$(BESM6_DIR)BESM6_PANEL.C,$(BESM6_DIR)BESM6_PRINTER.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_PL.C,$(BESM6_DIR)BESM6_VU.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") BESM6_OPTIONS = /INCL=($(SIMH_DIR),$(BESM6_DIR))/DEF=($(CC_DEFS),"USE_INT64=1")

View file

@ -1883,7 +1883,7 @@ BESM6D = ${SIMHD}/BESM6
BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \ 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_arith.c ${BESM6D}/besm6_disk.c ${BESM6D}/besm6_drum.c \
${BESM6D}/besm6_tty.c ${BESM6D}/besm6_panel.c ${BESM6D}/besm6_printer.c \ ${BESM6D}/besm6_tty.c ${BESM6D}/besm6_panel.c ${BESM6D}/besm6_printer.c \
${BESM6D}/besm6_pl.c \ ${BESM6D}/besm6_pl.c ${BESM6D}/besm6_mg.c \
${BESM6D}/besm6_punch.c ${BESM6D}/besm6_punchcard.c ${BESM6D}/besm6_vu.c ${BESM6D}/besm6_punch.c ${BESM6D}/besm6_punchcard.c ${BESM6D}/besm6_vu.c
ifneq (,$(BESM6_BUILD)) ifneq (,$(BESM6_BUILD))