/* * 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; ifileref, 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; }