blob: e79637275812db3378487524a465885dfcad193d [file] [log] [blame] [raw]
/*
* besm6_drum.c: BESM-6 magnetic drum device
*
* Copyright (c) 2009, Serge Vakulenko
*
* 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"
/*
* Управляющее слово обмена с магнитным барабаном.
*/
#define DRUM_READ_OVERLAY 020000000 /* считывание с наложением */
#define DRUM_PARITY_FLAG 010000000 /* блокировка считывания слов с неверной
* чётностью или запись с неверной чётностью */
#define DRUM_READ_SYSDATA 004000000 /* считывание только служебных слов */
#define DRUM_PAGE_MODE 001000000 /* обмен целой страницей */
#define DRUM_READ 000400000 /* чтение с барабана в память */
#define DRUM_PAGE 000370000 /* номер страницы памяти */
#define DRUM_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */
#define DRUM_PARAGRAF 000006000 /* номер абзаца */
#define DRUM_UNIT 000001600 /* номер барабана */
#define DRUM_CYLINDER 000000174 /* номер тракта на барабане */
#define DRUM_SECTOR 000000003 /* номер сектора */
/*
* Параметры обмена с внешним устройством.
*/
int drum_op; /* Условное слово обмена */
int drum_zone; /* Номер зоны на барабане */
int drum_sector; /* Начальный номер сектора на барабане */
int drum_memory; /* Начальный адрес памяти */
int drum_nwords; /* Количество слов обмена */
int drum_fail; /* Маска ошибок по направлениям */
t_stat drum_event (UNIT *u);
/*
* DRUM data structures
*
* drum_dev DRUM device descriptor
* drum_unit DRUM unit descriptor
* drum_reg DRUM register list
*/
UNIT drum_unit [] = {
{ UDATA (drum_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DRUM_SIZE) },
{ UDATA (drum_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DRUM_SIZE) },
};
REG drum_reg[] = {
{ ORDATA ( "УС", drum_op, 24) },
{ ORDATA ( "ЗОНА", drum_zone, 10) },
{ ORDATA ( "СЕКТОР", drum_sector, 2) },
{ ORDATA ( "МОЗУ", drum_memory, 15) },
{ ORDATA ( "СЧСЛОВ", drum_nwords, 11) },
{ 0 }
};
MTAB drum_mod[] = {
{ 0 }
};
t_stat drum_reset (DEVICE *dptr);
t_stat drum_attach (UNIT *uptr, CONST char *cptr);
t_stat drum_detach (UNIT *uptr);
DEVICE drum_dev = {
"DRUM", drum_unit, drum_reg, drum_mod,
2, 8, 19, 1, 8, 50,
NULL, NULL, &drum_reset, NULL, &drum_attach, &drum_detach,
NULL, DEV_DISABLE | DEV_DEBUG
};
/*
* Reset routine
*/
t_stat drum_reset (DEVICE *dptr)
{
drum_op = 0;
drum_zone = 0;
drum_sector = 0;
drum_memory = 0;
drum_nwords = 0;
sim_cancel (&drum_unit[0]);
sim_cancel (&drum_unit[1]);
return SCPE_OK;
}
t_stat drum_attach (UNIT *u, CONST char *cptr)
{
t_stat s;
s = attach_unit (u, cptr);
if (s != SCPE_OK)
return s;
if (u == &drum_unit[0])
GRP |= GRP_DRUM1_FREE;
else
GRP |= GRP_DRUM2_FREE;
return SCPE_OK;
}
t_stat drum_detach (UNIT *u)
{
if (u == &drum_unit[0])
GRP &= ~GRP_DRUM1_FREE;
else
GRP &= ~GRP_DRUM2_FREE;
return detach_unit (u);
}
/*
* Отладочная печать массива данных обмена.
*/
#if 0
static void log_io (UNIT *u)
{
t_value *data, *sysdata;
int i;
void print_word (t_value val) {
fprintf (sim_log, " %o-%04o-%04o-%04o-%04o",
(int) (val >> 48) & 07,
(int) (val >> 36) & 07777,
(int) (val >> 24) & 07777,
(int) (val >> 12) & 07777, (int) val & 07777);
}
data = &memory [drum_memory];
sysdata = (u == &drum_unit[0]) ? &memory [010] : &memory [020];
if (drum_nwords == 1024) {
fprintf (sim_log, "=== зона МБ %d.%03o:",
(u == &drum_unit[0]) ? 1 : 2, drum_zone);
for (i=0; i<8; ++i)
print_word (sysdata[i]);
} else {
sysdata += drum_sector*2;
fprintf (sim_log, "=== сектор МБ %d.%03o.%o:",
(u == &drum_unit[0]) ? 1 : 2,
drum_zone, drum_sector);
for (i=0; i<2; ++i)
print_word (sysdata[i]);
}
if (! (drum_op & DRUM_READ_SYSDATA)) {
fprintf (sim_log, "\n\t\t ");
for (i=0; i<drum_nwords; ++i)
print_word (data[i]);
}
fprintf (sim_log, "\n");
}
#endif
/*
* Запись на барабан.
*/
void drum_write (UNIT *u)
{
int ctlr;
t_value *sysdata;
ctlr = (u == &drum_unit[1]);
sysdata = ctlr ? &memory [020] : &memory [010];
if (fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET) == 0) {
sim_fwrite (sysdata, 8, 8, u->fileref);
sim_fwrite (&memory [drum_memory], 8, 1024, u->fileref);
}
if (ferror (u->fileref))
longjmp (cpu_halt, SCPE_IOERR);
}
void drum_write_sector (UNIT *u)
{
int ctlr;
t_value *sysdata;
ctlr = (u == &drum_unit[1]);
sysdata = ctlr ? &memory [020] : &memory [010];
if (fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8,
SEEK_SET) == 0) {
sim_fwrite (&sysdata [drum_sector*2], 8, 2, u->fileref);
if (fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8,
SEEK_SET) == 0) {
sim_fwrite (&memory [drum_memory], 8, 256, u->fileref);
}
}
if (ferror (u->fileref))
longjmp (cpu_halt, SCPE_IOERR);
}
/*
* Чтение с барабана.
*/
void drum_read (UNIT *u)
{
int ctlr;
t_value *sysdata;
ctlr = (u == &drum_unit[1]);
sysdata = ctlr ? &memory [020] : &memory [010];
if (fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET) != 0 ||
sim_fread (sysdata, 8, 8, u->fileref) != 8) {
/* Чтение неинициализированного барабана */
drum_fail |= 0100 >> ctlr;
return;
}
if (! (drum_op & DRUM_READ_SYSDATA) &&
sim_fread (&memory[drum_memory], 8, 1024, u->fileref) != 1024) {
/* Чтение неинициализированного барабана */
drum_fail |= 0100 >> ctlr;
return;
}
if (ferror (u->fileref))
longjmp (cpu_halt, SCPE_IOERR);
}
void drum_read_sector (UNIT *u)
{
int ctlr;
t_value *sysdata;
ctlr = (u == &drum_unit[1]);
sysdata = ctlr ? &memory [020] : &memory [010];
if (fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, SEEK_SET) != 0 ||
sim_fread (&sysdata [drum_sector*2], 8, 2, u->fileref) != 2) {
/* Чтение неинициализированного барабана */
drum_fail |= 0100 >> ctlr;
return;
}
if (! (drum_op & DRUM_READ_SYSDATA)) {
if (fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8,
SEEK_SET) != 0 ||
sim_fread (&memory[drum_memory], 8, 256, u->fileref) != 256) {
/* Чтение неинициализированного барабана */
drum_fail |= 0100 >> ctlr;
return;
}
}
if (ferror (u->fileref))
longjmp (cpu_halt, SCPE_IOERR);
}
static void clear_memory (t_value *p, int nwords)
{
while (nwords-- > 0)
*p++ = SET_PARITY (0, PARITY_NUMBER);
}
/*
* Выполнение обращения к барабану.
*/
void drum (int ctlr, uint32 cmd)
{
UNIT *u = &drum_unit[ctlr];
drum_op = cmd;
if (drum_op & DRUM_PAGE_MODE) {
/* Обмен страницей */
drum_nwords = 1024;
drum_zone = (cmd & (DRUM_UNIT | DRUM_CYLINDER)) >> 2;
drum_sector = 0;
drum_memory = (cmd & DRUM_PAGE) >> 2 | (cmd & DRUM_BLOCK) >> 8;
if (drum_dev.dctrl)
besm6_debug ("### %s МБ %c%d зона %02o память %05o-%05o",
(drum_op & DRUM_READ) ? "чтение" : "запись",
ctlr + '1', (drum_zone >> 5 & 7), drum_zone & 037,
drum_memory, drum_memory + drum_nwords - 1);
if (drum_op & DRUM_READ) {
clear_memory (ctlr ? &memory [020] : &memory [010], 8);
if (! (drum_op & DRUM_READ_SYSDATA))
clear_memory (&memory[drum_memory], 1024);
}
} else {
/* Обмен сектором */
drum_nwords = 256;
drum_zone = (cmd & (DRUM_UNIT | DRUM_CYLINDER)) >> 2;
drum_sector = cmd & DRUM_SECTOR;
drum_memory = (cmd & (DRUM_PAGE | DRUM_PARAGRAF)) >> 2 | (cmd & DRUM_BLOCK) >> 8;
if (drum_dev.dctrl)
besm6_debug ("### %s МБ %c%d зона %02o сектор %d память %05o-%05o",
(drum_op & DRUM_READ) ? "чтение" : "запись",
ctlr + '1', (drum_zone >> 5 & 7), drum_zone & 037,
drum_sector & 3,
drum_memory, drum_memory + drum_nwords - 1);
if (drum_op & DRUM_READ) {
clear_memory (ctlr ? &memory [020 + drum_sector*2] :
&memory [010 + drum_sector*2], 2);
if (! (drum_op & DRUM_READ_SYSDATA))
clear_memory (&memory[drum_memory], 256);
}
}
if ((drum_dev.flags & DEV_DIS) || ! u->fileref) {
/* Device not attached. */
drum_fail |= 0100 >> ctlr;
return;
}
drum_fail &= ~(0100 >> ctlr);
if (drum_op & DRUM_READ_OVERLAY) {
/* Not implemented. */
longjmp (cpu_halt, SCPE_NOFNC);
}
if (drum_op & DRUM_READ) {
if (drum_op & DRUM_PAGE_MODE)
drum_read (u);
else
drum_read_sector (u);
} else {
if (drum_op & DRUM_PARITY_FLAG) {
besm6_log ("### запись МБ с неправильной чётностью не реализована");
longjmp (cpu_halt, SCPE_NOFNC);
}
if (u->flags & UNIT_RO) {
/* Read only. */
longjmp (cpu_halt, SCPE_RO);
}
if (drum_op & DRUM_PAGE_MODE)
drum_write (u);
else
drum_write_sector (u);
}
/*if (drum_dev.dctrl && sim_log)
log_io (u);*/
/* Гасим главный регистр прерываний. */
if (u == &drum_unit[0])
GRP &= ~GRP_DRUM1_FREE;
else
GRP &= ~GRP_DRUM2_FREE;
/* Ждём события от устройства.
* Согласно данным из книжки Мазного Г.Л.,
* даём 20 мсек на обмен, или 200 тыс.тактов. */
/*sim_activate (u, 20*MSEC);*/
sim_activate (u, 20*USEC); /* Ускорим для отладки. */
}
/*
* Событие: закончен обмен с МБ.
* Устанавливаем флаг прерывания.
*/
t_stat drum_event (UNIT *u)
{
if (u == &drum_unit[0])
GRP |= GRP_DRUM1_FREE;
else
GRP |= GRP_DRUM2_FREE;
return SCPE_OK;
}
/*
* Опрос ошибок обмена командой 033 4035.
*/
int drum_errors ()
{
return drum_fail;
}