From 659600ff595fcf55adcb5f6e0453bb5dd2ce470f Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Mon, 29 Dec 2014 21:13:00 -0800 Subject: [PATCH 01/41] BESM6: Added target 'besm6' to makefile; added new files in the BESM6 subdirectory. --- BESM6/besm6_arith.c | 483 +++++++++++ BESM6/besm6_cpu.c | 1768 +++++++++++++++++++++++++++++++++++++++++ BESM6/besm6_defs.h | 426 ++++++++++ BESM6/besm6_disk.c | 648 +++++++++++++++ BESM6/besm6_drum.c | 372 +++++++++ BESM6/besm6_mmu.c | 652 +++++++++++++++ BESM6/besm6_panel.c | 594 ++++++++++++++ BESM6/besm6_printer.c | 345 ++++++++ BESM6/besm6_punch.c | 472 +++++++++++ BESM6/besm6_sys.c | 719 +++++++++++++++++ BESM6/besm6_tty.c | 1243 +++++++++++++++++++++++++++++ makefile | 26 + 12 files changed, 7748 insertions(+) create mode 100644 BESM6/besm6_arith.c create mode 100644 BESM6/besm6_cpu.c create mode 100644 BESM6/besm6_defs.h create mode 100644 BESM6/besm6_disk.c create mode 100644 BESM6/besm6_drum.c create mode 100644 BESM6/besm6_mmu.c create mode 100644 BESM6/besm6_panel.c create mode 100644 BESM6/besm6_printer.c create mode 100644 BESM6/besm6_punch.c create mode 100644 BESM6/besm6_sys.c create mode 100644 BESM6/besm6_tty.c diff --git a/BESM6/besm6_arith.c b/BESM6/besm6_arith.c new file mode 100644 index 00000000..d29685e0 --- /dev/null +++ b/BESM6/besm6_arith.c @@ -0,0 +1,483 @@ +/* + * BESM-6 arithmetic instructions. + * + * Copyright (c) 1997-2009, Leonid Broukhis + * 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 +#include "besm6_defs.h" + +typedef struct { + t_uint64 mantissa; + unsigned exponent; /* offset by 64 */ +} alureg_t; /* ALU register type */ + +static alureg_t toalu (t_value val) +{ + alureg_t ret; + + ret.mantissa = val & BITS41; + ret.exponent = (val >> 41) & BITS(7); + if (ret.mantissa & BIT41) + ret.mantissa |= BIT42; + return ret; +} + +static int inline is_negative (alureg_t *word) +{ + return (word->mantissa & BIT41) != 0; +} + +static void negate (alureg_t *val) +{ + if (is_negative (val)) + val->mantissa |= BIT42; + val->mantissa = (~val->mantissa + 1) & BITS42; + if (((val->mantissa >> 1) ^ val->mantissa) & BIT41) { + val->mantissa >>= 1; + ++val->exponent; + } + if (is_negative (val)) + val->mantissa |= BIT42; +} + +/* + * 48-й разряд -> 1, 47-й -> 2 и т.п. + * Единица 1-го разряда и нулевое слово -> 48, + * как в первоначальном варианте системы команд. + */ +int besm6_highest_bit (t_value val) +{ + int n = 32, cnt = 0; + do { + t_value tmp = val; + if (tmp >>= n) { + cnt += n; + val = tmp; + } + } while (n >>= 1); + return 48 - cnt; +} + +/* + * Нормализация и округление. + * Результат помещается в регистры ACC и 40-1 разряды RMR. + * 48-41 разряды RMR сохраняются. + */ +static void normalize_and_round (alureg_t acc, t_uint64 mr, int rnd_rq) +{ + t_uint64 rr = 0; + int i; + t_uint64 r; + + if (RAU & RAU_NORM_DISABLE) + goto chk_rnd; + i = (acc.mantissa >> 39) & 3; + if (i == 0) { + r = acc.mantissa & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + r <<= cnt; + rr = mr >> (40 - cnt); + acc.mantissa = r | rr; + mr <<= cnt; + acc.exponent -= cnt; + goto chk_zero; + } + r = mr & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + rr = mr; + r <<= cnt; + acc.mantissa = r; + mr = 0; + acc.exponent -= 40 + cnt; + goto chk_zero; + } + goto zero; + } else if (i == 3) { + r = ~acc.mantissa & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + r = (r << cnt) | ((1LL << cnt) - 1); + rr = mr >> (40 - cnt); + acc.mantissa = BIT41 | (~r & BITS40) | rr; + mr <<= cnt; + acc.exponent -= cnt; + goto chk_zero; + } + r = ~mr & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + rr = mr; + r = (r << cnt) | ((1LL << cnt) - 1); + acc.mantissa = BIT41 | (~r & BITS40); + mr = 0; + acc.exponent -= 40 + cnt; + goto chk_zero; + } else { + rr = 1; + acc.mantissa = BIT41; + mr = 0; + acc.exponent -= 80; + goto chk_zero; + } + } +chk_zero: + if (rr) + rnd_rq = 0; +chk_rnd: + if (acc.exponent & 0x8000) + goto zero; + if (! (RAU & RAU_ROUND_DISABLE) && rnd_rq) + acc.mantissa |= 1; + + if (! acc.mantissa && ! (RAU & RAU_NORM_DISABLE)) { +zero: ACC = 0; + RMR &= ~BITS40; + return; + } + + ACC = (t_value) (acc.exponent & BITS(7)) << 41 | + (acc.mantissa & BITS41); + RMR = (RMR & ~BITS40) | (mr & BITS40); + /* При переполнении мантисса и младшие разряды порядка верны */ + if (acc.exponent & 0x80) { + if (! (RAU & RAU_OVF_DISABLE)) + longjmp (cpu_halt, STOP_OVFL); + } +} + +/* + * Сложение и все варианты вычитаний. + * Исходные значения: регистр ACC и аргумент 'val'. + * Результат помещается в регистр ACC и 40-1 разряды RMR. + */ +void besm6_add (t_value val, int negate_acc, int negate_val) +{ + t_uint64 mr; + alureg_t acc, word, a1, a2; + int diff, neg, rnd_rq = 0; + + acc = toalu (ACC); + word = toalu (val); + if (! negate_acc) { + if (! negate_val) { + /* Сложение */ + } else { + /* Вычитание */ + negate (&word); + } + } else { + if (! negate_val) { + /* Обратное вычитание */ + negate (&acc); + } else { + /* Вычитание модулей */ + if (is_negative (&acc)) + negate (&acc); + if (! is_negative (&word)) + negate (&word); + } + } + + diff = acc.exponent - word.exponent; + if (diff < 0) { + diff = -diff; + a1 = acc; + a2 = word; + } else { + a1 = word; + a2 = acc; + } + mr = 0; + neg = is_negative (&a1); + if (diff == 0) { + /* Nothing to do. */ + } else if (diff <= 40) { + rnd_rq = (mr = (a1.mantissa << (40 - diff)) & BITS40) != 0; + a1.mantissa = ((a1.mantissa >> diff) | + (neg ? (~0ll << (40 - diff)) : 0)) & BITS42; + } else if (diff <= 80) { + diff -= 40; + rnd_rq = a1.mantissa != 0; + mr = ((a1.mantissa >> diff) | + (neg ? (~0ll << (40 - diff)) : 0)) & BITS40; + if (neg) { + a1.mantissa = BITS42; + } else + a1.mantissa = 0; + } else { + rnd_rq = a1.mantissa != 0; + if (neg) { + mr = BITS40; + a1.mantissa = BITS42; + } else + mr = a1.mantissa = 0; + } + acc.exponent = a2.exponent; + acc.mantissa = a1.mantissa + a2.mantissa; + + /* Если требуется нормализация вправо, биты 42:41 + * принимают значение 01 или 10. */ + switch ((acc.mantissa >> 40) & 3) { + case 2: + case 1: + rnd_rq |= acc.mantissa & 1; + mr = (mr >> 1) | ((acc.mantissa & 1) << 39); + acc.mantissa >>= 1; + ++acc.exponent; + } + normalize_and_round (acc, mr, rnd_rq); +} + +/* + * non-restoring division + */ +#define ABS(x) ((x) < 0 ? -x : x) +#define INT64(x) ((x) & BIT41 ? (-1LL << 40) | (x) : x) +static alureg_t nrdiv (alureg_t n, alureg_t d) +{ + t_int64 nn, dd, q, res; + alureg_t quot; + + /* to compensate for potential normalization to the right */ + nn = INT64(n.mantissa)*2; + dd = INT64(d.mantissa)*2; + res = 0, q = BIT41; + + if (ABS(nn) >= ABS(dd)) { + /* normalization to the right */ + nn/=2; + n.exponent++; + } + while (q > 1) { + if (nn == 0) + break; + + if (ABS(nn) < BIT40) + nn *= 2; /* magic shortcut */ + else if ((nn > 0) ^ (dd > 0)) { + res -= q; + nn = 2*nn+dd; + } else { + res += q; + nn = 2*nn-dd; + } + q /= 2; + } + quot.mantissa = res/2; + quot.exponent = n.exponent-d.exponent+64; + return quot; +} + +/* + * Деление. + * Исходные значения: регистр ACC и аргумент 'val'. + * Результат помещается в регистр ACC, содержимое RMR не определено. + */ +void besm6_divide (t_value val) +{ + alureg_t acc; + alureg_t dividend, divisor; + + if (((val ^ (val << 1)) & BIT41) == 0) { + /* Ненормализованный делитель: деление на ноль. */ + longjmp (cpu_halt, STOP_DIVZERO); + } + dividend = toalu(ACC); + divisor = toalu(val); + + acc = nrdiv(dividend, divisor); + + normalize_and_round (acc, 0, 0); +} + +/* + * Умножение. + * Исходные значения: регистр ACC и аргумент 'val'. + * Результат помещается в регистр ACC и 40-1 разряды RMR. + */ +void besm6_multiply (t_value val) +{ + uint8 neg = 0; + alureg_t acc, word, a, b; + t_uint64 mr, alo, blo, ahi, bhi; + + register t_uint64 l; + + if (! ACC || ! val) { + /* multiplication by zero is zero */ + ACC = 0; + RMR &= ~BITS40; + return; + } + acc = toalu (ACC); + word = toalu (val); + + a = acc; + b = word; + mr = 0; + + if (is_negative (&a)) { + neg = 1; + negate (&a); + } + if (is_negative (&b)) { + neg ^= 1; + negate (&b); + } + acc.exponent = a.exponent + b.exponent - 64; + + alo = a.mantissa & BITS(20); + ahi = a.mantissa >> 20; + + blo = b.mantissa & BITS(20); + bhi = b.mantissa >> 20; + + l = alo * blo + ((alo * bhi + ahi * blo) << 20); + + mr = l & BITS40; + l >>= 40; + + acc.mantissa = l + ahi * bhi; + + if (neg) { + mr = (~mr & BITS40) + 1; + acc.mantissa = ((~acc.mantissa & BITS40) + (mr >> 40)) + | BIT41 | BIT42; + mr &= BITS40; + } + + normalize_and_round (acc, mr, mr != 0); +} + +/* + * Изменение знака числа на сумматоре ACC. + * Результат помещается в регистр ACC, RMR гасится. + */ +void besm6_change_sign (int negate_acc) +{ + alureg_t acc; + + acc = toalu (ACC); + if (negate_acc) + negate (&acc); + RMR = 0; + normalize_and_round (acc, 0, 0); +} + +/* + * Изменение порядка числа на сумматоре ACC. + * Результат помещается в регистр ACC, RMR гасится. + */ +void besm6_add_exponent (int val) +{ + alureg_t acc; + + acc = toalu (ACC); + acc.exponent += val; + RMR = 0; + normalize_and_round (acc, 0, 0); +} + +/* + * Сборка значения по маске. + */ +t_value besm6_pack (t_value val, t_value mask) +{ + t_value result; + + result = 0; + for (; mask; mask>>=1, val>>=1) + if (mask & 1) { + result >>= 1; + if (val & 1) + result |= BIT48; + } + return result; +} + +/* + * Разборка значения по маске. + */ +t_value besm6_unpack (t_value val, t_value mask) +{ + t_value result; + int i; + + result = 0; + for (i=0; i<48; ++i) { + result <<= 1; + if (mask & BIT48) { + if (val & BIT48) + result |= 1; + val <<= 1; + } + mask <<= 1; + } + return result; +} + +/* + * Подсчёт количества единиц в слове. + */ +int besm6_count_ones (t_value word) +{ + int c; + + for (c=0; word; ++c) + word &= word-1; + return c; +} + +/* + * Сдвиг сумматора ACC с выдвижением в регистр младших разрядов RMR. + * Величина сдвига находится в диапазоне -64..63. + */ +void besm6_shift (int i) +{ + RMR = 0; + if (i > 0) { + /* Сдвиг вправо. */ + if (i < 48) { + RMR = (ACC << (48-i)) & BITS48; + ACC >>= i; + } else { + RMR = ACC >> (i-48); + ACC = 0; + } + } else if (i < 0) { + /* Сдвиг влево. */ + i = -i; + if (i < 48) { + RMR = ACC >> (48-i); + ACC = (ACC << i) & BITS48; + } else { + RMR = (ACC << (i-48)) & BITS48; + ACC = 0; + } + } +} diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c new file mode 100644 index 00000000..50b92fe9 --- /dev/null +++ b/BESM6/besm6_cpu.c @@ -0,0 +1,1768 @@ +/* + * BESM-6 CPU simulator. + * + * Copyright (c) 1997-2009, Leonid Broukhis + * 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. + + * For more information about BESM-6 computer, visit sites: + * - http://www.computer-museum.ru/english/besm6.htm + * - http://mailcom.com/besm6/ + * - http://groups.google.com/group/besm6 + * + * Release notes for BESM-6/SIMH + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * 1) All addresses and data values are displayed in octal. + * 2) Memory size is 128 kwords. + * 3) Interrupt system is to be synchronized with wallclock time. + * 4) Execution times are in 1/10 of microsecond. + * 5) Magnetic drums are implemented as a single "DRUM" device. + * 6) Magnetic disks are implemented. + * 7) Magnetic tape is not implemented. + * 8) Punch tape reader is implemented, punch card reader is planned. + * 9) Card puncher is not implemented. + * 10) Displays are implemented. + * 11) Printer АЦПУ-128 is implemented. + * 12) Instruction mnemonics, register names and stop messages + * are in Russian using UTF-8 encoding. It is assumed, that + * user locale is UTF-8. + * 13) A lot of comments in Russian (UTF-8). + */ +#include "besm6_defs.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#undef SOFT_CLOCK + +t_value memory [MEMSIZE]; +uint32 PC, RK, Aex, M [NREGS], RAU, RUU; +t_value ACC, RMR, GRP, MGRP; +uint32 PRP, MPRP; +uint32 READY, READY2; /* ready flags of various devices */ + +extern const char *scp_errors[]; + +/* нехранящие биты ГРП должны сбрасываться путем обнуления тех регистров, + * сборкой которых они являются + */ +#define GRP_WIRED_BITS 01400743700000000LL + +#define PRP_WIRED_BITS 0770000 + +int corr_stack; +int redraw_panel; +uint32 delay; +jmp_buf cpu_halt; + +t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); + +/* + * CPU data structures + * + * cpu_dev CPU device descriptor + * cpu_unit CPU unit descriptor + * cpu_reg CPU register list + * cpu_mod CPU modifiers list + */ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MEMSIZE) }; + +REG cpu_reg[] = { +{ "СчАС", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ +{ "РК", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ +{ "Аисп", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ +{ "СМ", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ +{ "РМР", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ +{ "РАУ", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ +{ "М1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ +{ "М2", &M[2], 8, 15, 0, 1 }, +{ "М3", &M[3], 8, 15, 0, 1 }, +{ "М4", &M[4], 8, 15, 0, 1 }, +{ "М5", &M[5], 8, 15, 0, 1 }, +{ "М6", &M[6], 8, 15, 0, 1 }, +{ "М7", &M[7], 8, 15, 0, 1 }, +{ "М10", &M[010], 8, 15, 0, 1 }, +{ "М11", &M[011], 8, 15, 0, 1 }, +{ "М12", &M[012], 8, 15, 0, 1 }, +{ "М13", &M[013], 8, 15, 0, 1 }, +{ "М14", &M[014], 8, 15, 0, 1 }, +{ "М15", &M[015], 8, 15, 0, 1 }, +{ "М16", &M[016], 8, 15, 0, 1 }, +{ "М17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ +{ "М20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ +{ "М21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ +{ "М27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ +{ "М32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ +{ "М33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ +{ "М34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ +{ "М35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ +{ "РУУ", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ +{ "ГРП", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ +{ "МГРП", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ +{ "ПРП", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ +{ "МПРП", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ +{ 0 } +}; + +MTAB cpu_mod[] = { + { 0 } +}; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 17, 1, 8, 50, + &cpu_examine, &cpu_deposit, &cpu_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG +}; + +/* + * REG: псевдоустройство, содержащее латинские синонимы всех регистров. + */ +REG reg_reg[] = { +{ "PC", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ +{ "RK", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ +{ "Aex", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ +{ "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ +{ "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ +{ "RAU", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ +{ "M1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ +{ "M2", &M[2], 8, 15, 0, 1 }, +{ "M3", &M[3], 8, 15, 0, 1 }, +{ "M4", &M[4], 8, 15, 0, 1 }, +{ "M5", &M[5], 8, 15, 0, 1 }, +{ "M6", &M[6], 8, 15, 0, 1 }, +{ "M7", &M[7], 8, 15, 0, 1 }, +{ "M10", &M[010], 8, 15, 0, 1 }, +{ "M11", &M[011], 8, 15, 0, 1 }, +{ "M12", &M[012], 8, 15, 0, 1 }, +{ "M13", &M[013], 8, 15, 0, 1 }, +{ "M14", &M[014], 8, 15, 0, 1 }, +{ "M15", &M[015], 8, 15, 0, 1 }, +{ "M16", &M[016], 8, 15, 0, 1 }, +{ "M17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ +{ "M20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ +{ "M21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ +{ "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ +{ "M32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ +{ "M33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ +{ "M34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ +{ "M35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ +{ "RUU", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ +{ "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ +{ "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ +{ "PRP", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ +{ "MPRP", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ + +{ "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BAZ0", &BAZ[0], 8, 16, 0, 1 }, +{ "BAZ1", &BAZ[1], 8, 16, 0, 1 }, +{ "BAZ2", &BAZ[2], 8, 16, 0, 1 }, +{ "BAZ3", &BAZ[3], 8, 16, 0, 1 }, +{ "BAZ4", &BAZ[4], 8, 16, 0, 1 }, +{ "BAZ5", &BAZ[5], 8, 16, 0, 1 }, +{ "BAZ6", &BAZ[6], 8, 16, 0, 1 }, +{ "BAZ7", &BAZ[7], 8, 16, 0, 1 }, +{ "TABST", &TABST, 8, 28, 0, 1 }, +{ "RP0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RZ", &RZ, 8, 32, 0, 1 }, +{ "FP1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ 0 } +}; + +UNIT reg_unit = { + UDATA (NULL, 0, 8) +}; + +DEVICE reg_dev = { + "REG", ®_unit, reg_reg, NULL, + 1, 8, 1, 1, 8, 50, +}; + +/* + * SCP data structures and interface routines + * + * sim_name simulator name string + * sim_PC pointer to saved PC register descriptor + * sim_emax maximum number of words for examine/deposit + * sim_devices array of pointers to simulated devices + * sim_stop_messages array of pointers to stop messages + * sim_load binary loader + */ + +char sim_name[] = "БЭСМ-6"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; /* максимальное количество слов в машинной команде */ + +DEVICE *sim_devices[] = { + &cpu_dev, + ®_dev, + &drum_dev, + &disk_dev, + &mmu_dev, + &clock_dev, + &printer_dev, + &fs_dev, + &tty_dev, /* терминалы - телетайпы, видеотоны, "Консулы" */ + 0 +}; + +const char *sim_stop_messages[] = { + "Неизвестная ошибка", /* Unknown error */ + "Останов", /* STOP */ + "Точка останова", /* Emulator breakpoint */ + "Точка останова по считыванию", /* Emulator read watchpoint */ + "Точка останова по записи", /* Emulator write watchpoint */ + "Выход за пределы памяти", /* Run out end of memory */ + "Запрещенная команда", /* Invalid instruction */ + "Контроль команды", /* A data-tagged word fetched */ + "Команда в чужом листе", /* Paging error during fetch */ + "Число в чужом листе", /* Paging error during load/store */ + "Контроль числа МОЗУ", /* RAM parity error */ + "Контроль числа БРЗ", /* Write cache parity error */ + "Переполнение АУ", /* Arith. overflow */ + "Деление на нуль", /* Division by zero or denorm */ + "Двойное внутреннее прерывание", /* SIMH: Double internal interrupt */ + "Чтение неформатированного барабана", /* Reading unformatted drum */ + "Чтение неформатированного диска", /* Reading unformatted disk */ + "Останов по КРА", /* Hardware breakpoint */ + "Останов по считыванию", /* Load watchpoint */ + "Останов по записи", /* Store watchpoint */ + "Не реализовано", /* Unimplemented I/O or special reg. access */ +}; + +/* + * Memory examine + */ +t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + if (vptr) { + if (addr < 010) + *vptr = pult [addr]; + else + *vptr = memory [addr]; + } + return SCPE_OK; +} + +/* + * Memory deposit + */ +t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + if (addr < 010) + pult [addr] = SET_CONVOL (val, CONVOL_INSN); + else + memory [addr] = SET_CONVOL (val, CONVOL_INSN); + return SCPE_OK; +} + +/* + * Функция вызывается каждые 4 миллисекунды реального времени. + */ +static void cpu_sigalarm (int signum) +{ + static unsigned counter; + + ++counter; + +#ifndef SOFT_CLOCK + /* В 9-й части частота таймера 250 Гц (4 мс). */ + GRP |= GRP_TIMER; + + /* Медленный таймер: должен быть 16 Гц. + * Но от него почему-то зависит вывод на терминалы, + * поэтому ускорим. */ + if ((counter & 3) == 0) { + GRP |= GRP_SLOW_CLK; + } +#endif + + /* Перерисовка панели каждые 64 миллисекунды. */ + if ((counter & 15) == 0) { + redraw_panel = 1; + } +} + +/* + * Reset routine + */ +t_stat cpu_reset (DEVICE *dptr) +{ + int i; + + ACC = 0; + RMR = 0; + RAU = 0; + RUU = RUU_EXTRACODE | RUU_AVOST_DISABLE; + for (i=0; i 0xxxxxxx + * 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy + * xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz + */ +void +utf8_putc (unsigned ch, FILE *fout) +{ + if (ch < 0x80) { + putc (ch, fout); + return; + } + if (ch < 0x800) { + putc (ch >> 6 | 0xc0, fout); + putc ((ch & 0x3f) | 0x80, fout); + return; + } + putc (ch >> 12 | 0xe0, fout); + putc (((ch >> 6) & 0x3f) | 0x80, fout); + putc ((ch & 0x3f) | 0x80, fout); +} + +/* + * *call ОКНО - так называлась служебная подпрограмма в мониторной + * системе "Дубна", которая печатала полное состояние всех регистров. + */ +void besm6_okno (const char *message) +{ + besm6_log_cont ("_%%%%%% %s: ", message); + if (sim_log) + besm6_fprint_cmd (sim_log, RK); + besm6_log ("_"); + + /* СчАС, системные индекс-регистры 020-035. */ + besm6_log ("_ СчАС:%05o 20:%05o 21:%05o 27:%05o 32:%05o 33:%05o 34:%05o 35:%05o", + PC, M[020], M[021], M[027], M[032], M[033], M[034], M[035]); + /* Индекс-регистры 1-7. */ + besm6_log ("_ 1:%05o 2:%05o 3:%05o 4:%05o 5:%05o 6:%05o 7:%05o", + M[1], M[2], M[3], M[4], M[5], M[6], M[7]); + /* Индекс-регистры 010-017. */ + besm6_log ("_ 10:%05o 11:%05o 12:%05o 13:%05o 14:%05o 15:%05o 16:%05o 17:%05o", + M[010], M[011], M[012], M[013], M[014], M[015], M[016], M[017]); + /* Сумматор, РМР, режимы АУ и УУ. */ + besm6_log ("_ СМ:%04o %04o %04o %04o РМР:%04o %04o %04o %04o РАУ:%02o РУУ:%03o", + (int) (ACC >> 36) & BITS(12), (int) (ACC >> 24) & BITS(12), + (int) (ACC >> 12) & BITS(12), (int) ACC & BITS(12), + (int) (RMR >> 36) & BITS(12), (int) (RMR >> 24) & BITS(12), + (int) (RMR >> 12) & BITS(12), (int) RMR & BITS(12), + RAU, RUU); +} + +/* + * Команда "рег" + */ +static void cmd_002 () +{ +#if 0 + besm6_debug ("*** рег %03o", Aex & 0377); +#endif + switch (Aex & 0377) { + case 0 ... 7: + /* Запись в БРЗ */ + mmu_setcache (Aex & 7, ACC); + break; + case 020 ... 027: + /* Запись в регистры приписки */ + mmu_setrp (Aex & 7, ACC); + break; + case 030 ... 033: + /* Запись в регистры защиты */ + mmu_setprotection (Aex & 3, ACC); + break; + case 036: + /* Запись в маску главного регистра прерываний */ + MGRP = ACC; + break; + case 037: + /* Гашение главного регистра прерываний */ + /* нехранящие биты невозможно погасить */ + GRP &= ACC | GRP_WIRED_BITS; + break; + case 0100 ... 0137: + /* Бит 1: управление блокировкой режима останова БРО. + * Биты 2 и 3 - признаки формирования контрольных + * разрядов (ПКП и ПКЛ). */ + if (Aex & 1) + RUU |= RUU_AVOST_DISABLE; + else + RUU &= ~RUU_AVOST_DISABLE; + if (Aex & 2) + RUU |= RUU_CONVOL_RIGHT; + else + RUU &= ~RUU_CONVOL_RIGHT; + if (Aex & 4) + RUU |= RUU_CONVOL_LEFT; + else + RUU &= ~RUU_CONVOL_LEFT; + break; + case 0140 ... 0177: + /* TODO: управление блокировкой схемы + * автоматического запуска */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0200 ... 0207: + /* Чтение БРЗ */ + ACC = mmu_getcache (Aex & 7); + break; + case 0237: + /* Чтение главного регистра прерываний */ + ACC = GRP; + break; + default: + /* Неиспользуемые адреса */ + besm6_debug ("*** %05o%s: РЕГ %o - неправильный адрес спец.регистра", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); + break; + } +} + +/* + * Команда "увв" + */ +static void cmd_033 () +{ +#if 0 + besm6_debug ("*** увв %04o, СМ[24:1]=%08o", + Aex & 04177, (uint32) ACC & BITS(24)); +#endif + switch (Aex & 04177) { + case 0: + /* Точно неизвестно, что это такое, но драйвер МД + * иногда выдает команду "увв 0". */ + break; + case 1 ... 2: + /* Управление обменом с магнитными барабанами */ + drum (Aex - 1, (uint32) ACC); + break; + case 3 ... 4: + /* Передача управляющего слова для обмена + * с магнитными дисками */ + disk_io (Aex - 3, (uint32) ACC); + break; + case 5 ... 7: + /* TODO: управление обменом с магнитными лентами */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 010 ... 011: + /* управление устройствами ввода с перфоленты */ + fs_control (Aex - 010, (uint32) (ACC & 07)); + break; + case 012 ... 013: + /* TODO: управление устройствами ввода с перфоленты по запаянной программе */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 014 ... 015: + /* Управление АЦПУ */ + printer_control (Aex - 014, (uint32) (ACC & 017)); + break; + case 023 ... 024: + /* Управление обменом с магнитными дисками */ + disk_ctl (Aex - 023, (uint32) ACC); + break; + case 030: + /* Гашение ПРП */ +/* besm6_debug(">>> гашение ПРП");*/ + PRP &= ACC | PRP_WIRED_BITS; + break; + case 031: + /* Имитация сигналов прерывания ГРП */ + /*besm6_debug ("*** %05o%s: имитация прерываний ГРП %016llo", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", ACC << 24);*/ + GRP |= (ACC & BITS(24)) << 24; + break; + case 032 ... 033: + /* TODO: имитация сигналов из КМБ в КВУ */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 034: + /* Запись в МПРП */ +/* besm6_debug(">>> запись в МПРП");*/ + MPRP = ACC & 077777777; + break; + case 035: + /* TODO: управление режимом имитации обмена + * с МБ и МЛ, имитация обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 040 ... 057: + /* Управление молоточками АЦПУ */ + printer_hammer (Aex >= 050, Aex & 7, (uint32) (ACC & BITS(16))); + break; + case 0100 ... 0137: + /* Управление лентопротяжными механизмами + * и гашение разрядов регистров признаков + * окончания подвода зоны. Игнорируем. */ + break; + case 0140: + /* Запись в регистр телеграфных каналов */ + tty_send ((uint32) ACC & BITS(24)); + break; + case 0141: + /* TODO: управление разметкой магнитной ленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0142: + /* TODO: имитация сигналов прерывания ПРП */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0147: + /* Запись в регистр управления электропитанием, */ + /* не оказывает видимого эффекта на выполнение */ + break; + case 0150 ... 0151: + /* TODO: управление вводом с перфокарт */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0153: + /* гашение аппаратуры сопряжения с терминалами */ +/* besm6_debug(">>> гашение АС: %08o", (uint32) ACC & BITS(24));*/ + break; + case 0154 ... 0155: + /* TODO: управление выводом на перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0160 ... 0167: + /* TODO: управление электромагнитами пробивки перфокарт */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0170 ... 0171: + /* TODO: пробивка строки на перфоленте */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0174 ... 0175: + /* Выдача кода в пульт оператора */ + consul_print (Aex & 1, (uint32) ACC & BITS(8)); + break; + case 0177: + /* управление табло ГПВЦ СО АН СССР */ +/* besm6_debug(">>> ТАБЛО: %08o", (uint32) ACC & BITS(24));*/ + break; + case 04001 ... 04002: + /* TODO: считывание слога в режиме имитации обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04003 ... 04004: + /* Запрос статуса контроллера магнитных дисков */ + ACC = disk_state (Aex - 04003); + break; + case 04006: + /* TODO: считывание строки с устройства ввода + * с перфоленты в запаянной программе */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04007: + /* TODO: опрос синхроимпульса ненулевой строки + * в запаянной программе ввода с перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04014 ... 04015: + /* считывание строки с устройства ввода с перфоленты */ + ACC = fs_read (Aex - 04014); + break; + case 04016 ... 04017: + /* TODO: считывание строки с устройства + * ввода с перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04020 ... 04023: + /* TODO: считывание слога в режиме имитации + * внешнего обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04030: + /* Чтение старшей половины ПРП */ + ACC = PRP & 077770000; + break; + case 04031: + /* Опрос сигналов готовности (АЦПУ и пр.) */ +/* besm6_debug("Reading READY");*/ + ACC = READY; + break; + case 04034: + /* Чтение младшей половины ПРП */ + ACC = (PRP & 07777) | 0377; + break; + case 04035: + /* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */ + ACC = drum_errors() | disk_errors(); + break; + case 04100: + /* Опрос телеграфных каналов связи */ + ACC = tty_query (); + break; + case 04102: + /* Опрос сигналов готовности перфокарт и перфолент */ +/* besm6_debug("Reading punchcard/punchtape READY @%05o", PC);*/ + ACC = READY2; + break; + case 04103 ... 04106: + /* Опрос состояния лентопротяжных механизмов. + * Все устройства не готовы. */ + ACC = BITS(24); + break; + case 04107: + /* TODO: опрос схемы контроля записи на МЛ */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04115: + /* Неизвестное обращение. ДИСПАК выдаёт эту команду + * группами по 8 штук каждые несколько секунд. */ + ACC = 0; + break; + case 04140 ... 04157: + /* TODO: считывание строки перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04160 ... 04167: + /* TODO: контрольное считывание строки перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04170 ... 04173: + /* TODO: считывание контрольного кода + * строки перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04174 ... 04175: + /* Считывание кода с пульта оператора */ + ACC = consul_read (Aex & 1); + break; + case 04177: + /* чтение табло ГПВЦ СО АН СССР */ + ACC = 0; + break; + default: + /* Неиспользуемые адреса */ +/* if (sim_deb && cpu_dev.dctrl)*/ + besm6_debug ("*** %05o%s: УВВ %o - неправильный адрес ввода-вывода", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); + ACC = 0; + break; + } +} + +void check_initial_setup () +{ + const int MGRP_COPY = 01455; /* OS version specific? */ + const int TAKEN = 0442; /* fixed? */ + const int YEAR = 0221; /* fixed */ + + /* 47 р. яч. ЗАНЯТА - разр. приказы вообще */ + const t_value SETUP_REQS_ENABLED = 1LL << 46; + + /* 7 р. яч. ЗАНЯТА - разр любые приказы */ + const t_value ALL_REQS_ENABLED = 1 << 6; + + if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || + (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || + (MGRP & GRP_PANEL_REQ) == 0) { + /* Слишком рано, или уже не надо, или невовремя */ + return; + } + + /* Выдаем приказы оператора СМЕ и ВРЕ, + * а дату корректируем непосредственно в памяти. + */ + /* Номер смены в 22-24 рр. МГРП: если еще не установлен, установить */ + if (((memory[MGRP_COPY] >> 21) & 3) == 0) { + /* приказ СМЕ: ТР6 = 010, ТР4 = 1, 22-24 р ТР5 - #смены */ + pult[6] = 010; + pult[4] = 1; + pult[5] = 1 << 21; + GRP |= GRP_PANEL_REQ; + } else { + /* Яч. ГОД обновляем самостоятельно */ + time_t t; + t_value date; + time(&t); + struct tm * d; + d = localtime(&t); + ++d->tm_mon; + date = (t_value) (d->tm_mday / 10) << 33 | + (t_value) (d->tm_mday % 10) << 29 | + (d->tm_mon / 10) << 28 | + (d->tm_mon % 10) << 24 | + (d->tm_year % 10) << 20 | + ((d->tm_year / 10) % 10) << 16 | + (memory[YEAR] & 7); + memory[YEAR] = SET_CONVOL (date, CONVOL_NUMBER); + /* приказ ВРЕ: ТР6 = 016, ТР5 = 9-14 р.-часы, 1-8 р.-минуты */ + pult[6] = 016; + pult[4] = 0; + pult[5] = (d->tm_hour / 10) << 12 | + (d->tm_hour % 10) << 8 | + (d->tm_min / 10) << 4 | + (d->tm_min % 10); + GRP |= GRP_PANEL_REQ; + } +} + +/* + * Execute one instruction, placed on address PC:RUU_RIGHT_INSTR. + * Increment delay. When stopped, perform a longjmp to cpu_halt, + * sending a stop code. + */ +void cpu_one_inst () +{ + int reg, opcode, addr, nextpc, next_mod; + + corr_stack = 0; + t_value word = mmu_fetch (PC); + if (RUU & RUU_RIGHT_INSTR) + RK = word; /* get right instruction */ + else + RK = word >> 24; /* get left instruction */ + + RK &= BITS(24); + + reg = RK >> 20; + if (RK & BBIT(20)) { + addr = RK & BITS(15); + opcode = (RK >> 12) & 0370; + } else { + addr = RK & BITS(12); + if (RK & BBIT(19)) + addr |= 070000; + opcode = (RK >> 12) & 077; + } + + if (sim_deb && cpu_dev.dctrl) { + fprintf (sim_deb, "*** %05o%s: ", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); + besm6_fprint_cmd (sim_deb, RK); + fprintf (sim_deb, "\tСМ="); + fprint_sym (sim_deb, 0, &ACC, 0, 0); + fprintf (sim_deb, "\tРАУ=%02o", RAU); + if (reg) + fprintf (sim_deb, "\tМ[%o]=%05o", reg, M[reg]); + fprintf (sim_deb, "\n"); + } + nextpc = ADDR(PC + 1); + if (RUU & RUU_RIGHT_INSTR) { + PC += 1; /* increment PC */ + RUU &= ~RUU_RIGHT_INSTR; + } else { + mmu_prefetch(nextpc | (IS_SUPERVISOR(RUU) ? BBIT(16) : 0), 0); + RUU |= RUU_RIGHT_INSTR; + } + + if (RUU & RUU_MOD_RK) { + addr = ADDR (addr + M[MOD]); + } + next_mod = 0; + delay = 0; + + switch (opcode) { + case 000: /* зп, atx */ + Aex = ADDR (addr + M[reg]); + mmu_store (Aex, ACC); + if (! addr && reg == 017) + M[017] = ADDR (M[017] + 1); + delay = MEAN_TIME (3, 3); + break; + case 001: /* зпм, stx */ + Aex = ADDR (addr + M[reg]); + mmu_store (Aex, ACC); + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + ACC = mmu_load (M[017]); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (6, 6); + break; + case 002: /* рег, mod */ + Aex = ADDR (addr + M[reg]); + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + cmd_002 (); + /* Режим АУ - логический, если операция была "чтение" */ + if (Aex & 0200) + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 003: /* счм, xts */ + mmu_store (M[017], ACC); + M[017] = ADDR (M[017] + 1); + corr_stack = -1; + Aex = ADDR (addr + M[reg]); + ACC = mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (6, 6); + break; + case 004: /* сл, a+x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 0, 0); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 005: /* вч, a-x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 0, 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 006: /* вчоб, x-a */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 1, 0); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 007: /* вчаб, amx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 1, 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 010: /* сч, xta */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 011: /* и, aax */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC &= mmu_load (Aex); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4); + break; + case 012: /* нтж, aex */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + RMR = ACC; + ACC ^= mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 013: /* слц, arx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC += mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + RMR = 0; + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 6); + break; + case 014: /* знак, avx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_change_sign (mmu_load (Aex) >> 40 & 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 015: /* или, aox */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC |= mmu_load (Aex); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4); + break; + case 016: /* дел, a/x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_divide (mmu_load (Aex)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 50); + break; + case 017: /* умн, a*x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_multiply (mmu_load (Aex)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 18); + break; + case 020: /* сбр, apx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_pack (ACC, mmu_load (Aex)); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 53); + break; + case 021: /* рзб, aux */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_unpack (ACC, mmu_load (Aex)); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 53); + break; + case 022: /* чед, acx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_count_ones (ACC) + mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 56); + break; + case 023: /* нед, anx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + if (ACC) { + int n = besm6_highest_bit (ACC); + + /* "Остаток" сумматора, исключая бит, + * номер которого определен, помещается в РМР, + * начиная со старшего бита РМР. */ + besm6_shift (48 - n); + + /* Циклическое сложение номера со словом по Аисп. */ + ACC = n + mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + } else { + RMR = 0; + ACC = mmu_load (Aex); + } + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 32); + break; + case 024: /* слп, e+x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add_exponent ((mmu_load (Aex) >> 41) - 64); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 025: /* вчп, e-x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add_exponent (64 - (mmu_load (Aex) >> 41)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 026: { /* сд, asx */ + int n; + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + n = (mmu_load (Aex) >> 41) - 64; + besm6_shift (n); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4 + abs (n)); + break; + } + case 027: /* рж, xtr */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + RAU = (mmu_load (Aex) >> 41) & 077; + delay = MEAN_TIME (3, 3); + break; + case 030: /* счрж, rte */ + Aex = ADDR (addr + M[reg]); + ACC = (t_value) (RAU & Aex & 0177) << 41; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 031: /* счмр, yta */ + Aex = ADDR (addr + M[reg]); + if (IS_LOGICAL (RAU)) { + ACC = RMR; + } else { + t_value x = RMR; + ACC = (ACC & ~BITS41) | (RMR & BITS40); + besm6_add_exponent ((Aex & 0177) - 64); + RMR = x; + } + delay = MEAN_TIME (3, 5); + break; + case 032: /* э32, ext */ + /* Fall through... */ + case 033: /* увв, ext */ + Aex = ADDR (addr + M[reg]); + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + cmd_033 (); + /* Режим АУ - логический, если операция была "чтение" */ + if (Aex & 04000) + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 8); + break; + case 034: /* слпа, e+n */ + Aex = ADDR (addr + M[reg]); + besm6_add_exponent ((Aex & 0177) - 64); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 035: /* вчпа, e-n */ + Aex = ADDR (addr + M[reg]); + besm6_add_exponent (64 - (Aex & 0177)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 036: { /* сда, asn */ + int n; + Aex = ADDR (addr + M[reg]); + n = (Aex & 0177) - 64; + besm6_shift (n); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4 + abs (n)); + break; + } + case 037: /* ржа, ntr */ + Aex = ADDR (addr + M[reg]); + RAU = Aex & 077; + delay = MEAN_TIME (3, 3); + break; + case 040: /* уи, ati */ + Aex = ADDR (addr + M[reg]); + if (IS_SUPERVISOR (RUU)) { + int reg = Aex & 037; + M[reg] = ADDR (ACC); + /* breakpoint/watchpoint regs will match physical + * or virtual addresses depending on the current + * mapping mode. + */ + if ((M[PSW] & PSW_MMAP_DISABLE) && + (reg == IBP || reg == DWP)) + M[reg] |= BBIT(16); + + } else + M[Aex & 017] = ADDR (ACC); + M[0] = 0; + delay = MEAN_TIME (14, 3); + break; + case 041: { /* уим, sti */ + unsigned rg, ad; + + Aex = ADDR (addr + M[reg]); + rg = Aex & (IS_SUPERVISOR (RUU) ? 037 : 017); + ad = ADDR (ACC); + if (rg != 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + ACC = mmu_load (rg != 017 ? M[017] : ad); + M[rg] = ad; + if ((M[PSW] & PSW_MMAP_DISABLE) && (rg == IBP || rg == DWP)) + M[rg] |= BBIT(16); + M[0] = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (14, 3); + break; + } + case 042: /* счи, ita */ + delay = MEAN_TIME (6, 3); +load_modifier: Aex = ADDR (addr + M[reg]); + ACC = ADDR(M[Aex & (IS_SUPERVISOR (RUU) ? 037 : 017)]); + RAU = SET_LOGICAL (RAU); + break; + case 043: /* счим, its */ + mmu_store (M[017], ACC); + M[017] = ADDR (M[017] + 1); + delay = MEAN_TIME (9, 6); + goto load_modifier; + case 044: /* уии, mtj */ + Aex = addr; + if (IS_SUPERVISOR (RUU)) { +transfer_modifier: M[Aex & 037] = M[reg]; + if ((M[PSW] & PSW_MMAP_DISABLE) && + ((Aex & 037) == IBP || (Aex & 037) == DWP)) + M[Aex & 037] |= BBIT(16); + + } else + M[Aex & 017] = M[reg]; + M[0] = 0; + delay = 6; + break; + case 045: /* сли, j+m */ + Aex = addr; + if ((Aex & 020) && IS_SUPERVISOR (RUU)) + goto transfer_modifier; + M[Aex & 017] = ADDR (M[Aex & 017] + M[reg]); + M[0] = 0; + delay = 6; + break; + case 046: /* э46, x46 */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + M[Aex & 017] = ADDR (Aex); + M[0] = 0; + delay = 6; + break; + case 047: /* э47, x47 */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + M[Aex & 017] = ADDR (M[Aex & 017] + Aex); + M[0] = 0; + delay = 6; + break; + case 050 ... 077: /* э50...э77 */ + case 0200: /* э20 */ + case 0210: /* э21 */ + stop_as_extracode: + Aex = ADDR (addr + M[reg]); + if (! sim_deb && sim_log && cpu_dev.dctrl && opcode != 075) { + /* Если включен console log и cpu debug, + * но нет console debug, то печатаем только экстракоды. + * Пропускаем э75, их обычно слишком много. */ + t_value word = mmu_load (Aex); + fprintf (sim_log, "*** %05o%s: ", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); + besm6_fprint_cmd (sim_log, RK); + fprintf (sim_log, "\tАисп=%05o (=", Aex); + fprint_sym (sim_log, 0, &word, 0, 0); + fprintf (sim_log, ") СМ="); + fprint_sym (sim_log, 0, &ACC, 0, 0); + if (reg) + fprintf (sim_log, " М[%o]=%05o", reg, M[reg]); + fprintf (sim_log, "\n"); + } + /*besm6_okno ("экстракод");*/ + /* Адрес возврата из экстракода. */ + M[ERET] = nextpc; + /* Сохранённые режимы УУ. */ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + /* Текущие режимы УУ. */ + M[PSW] = PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE | /*?*/ PSW_INTR_HALT; + M[14] = Aex; + RUU = SET_SUPERVISOR (RUU, SPSW_EXTRACODE); + + if (opcode <= 077) + PC = 0500 + opcode; /* э50-э77 */ + else + PC = 0540 + (opcode >> 3); /* э20, э21 */ + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0220: /* мода, utc */ + Aex = ADDR (addr + M[reg]); + next_mod = Aex; + delay = 4; + break; + case 0230: /* мод, wtc */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + next_mod = ADDR (mmu_load (Aex)); + delay = MEAN_TIME (13, 3); + break; + case 0240: /* уиа, vtm */ + Aex = addr; + M[reg] = addr; + M[0] = 0; + if (IS_SUPERVISOR (RUU) && reg == 0) { + M[PSW] &= ~(PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + M[PSW] |= addr & (PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + } + delay = 4; + break; + case 0250: /* слиа, utm */ + Aex = ADDR (addr + M[reg]); + M[reg] = Aex; + M[0] = 0; + if (IS_SUPERVISOR (RUU) && reg == 0) { + M[PSW] &= ~(PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + M[PSW] |= addr & (PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + } + delay = 4; + break; + case 0260: /* по, uza */ + Aex = ADDR (addr + M[reg]); + RMR = ACC; + delay = MEAN_TIME (12, 3); + if (IS_ADDITIVE (RAU)) { + if (ACC & BIT41) + break; + } else if (IS_MULTIPLICATIVE (RAU)) { + if (! (ACC & BIT48)) + break; + } else if (IS_LOGICAL (RAU)) { + if (ACC) + break; + } else + break; + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + case 0270: /* пе, u1a */ + Aex = ADDR (addr + M[reg]); + RMR = ACC; + delay = MEAN_TIME (12, 3); + if (IS_ADDITIVE (RAU)) { + if (! (ACC & BIT41)) + break; + } else if (IS_MULTIPLICATIVE (RAU)) { + if (ACC & BIT48) + break; + } else if (IS_LOGICAL (RAU)) { + if (! ACC) + break; + } else + /* fall thru, i.e. branch */; + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + case 0300: /* пб, uj */ + Aex = ADDR (addr + M[reg]); + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0310: /* пв, vjm */ + Aex = addr; + M[reg] = nextpc; + M[0] = 0; + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0320: /* выпр, iret */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) { + longjmp (cpu_halt, STOP_BADCMD); + } + M[PSW] = (M[PSW] & PSW_WRITE_WATCH) | + (M[SPSW] & (SPSW_INTR_DISABLE | + SPSW_MMAP_DISABLE | SPSW_PROT_DISABLE)); + PC = M[(reg & 3) | 030]; + RUU &= ~RUU_RIGHT_INSTR; + if (M[SPSW] & SPSW_RIGHT_INSTR) + RUU |= RUU_RIGHT_INSTR; + else + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, + M[SPSW] & (SPSW_EXTRACODE | SPSW_INTERRUPT)); + if (M[SPSW] & SPSW_MOD_RK) + next_mod = M[MOD]; + /*besm6_okno ("Выход из прерывания");*/ + delay = 7; + break; + case 0330: /* стоп, stop */ + Aex = ADDR (addr + M[reg]); + delay = 7; + if (! IS_SUPERVISOR(RUU)) { + if (M[PSW] & PSW_CHECK_HALT) + break; + else { + opcode = 063; + goto stop_as_extracode; + } + } + mmu_print_brz (); + longjmp (cpu_halt, STOP_STOP); + break; + case 0340: /* пио, vzm */ +branch_zero: Aex = addr; + delay = 4; + if (! M[reg]) { + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + } + break; + case 0350: /* пино, v1m */ + Aex = addr; + delay = 4; + if (M[reg]) { + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + } + break; + case 0360: /* э36, *36 */ + goto branch_zero; + case 0370: /* цикл, vlm */ + Aex = addr; + delay = 4; + if (! M[reg]) + break; + M[reg] = ADDR (M[reg] + 1); + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + default: + /* Unknown instruction - cannot happen. */ + longjmp (cpu_halt, STOP_STOP); + break; + } + if (next_mod) { + /* Модификация адреса следующей команды. */ + M[MOD] = next_mod; + RUU |= RUU_MOD_RK; + } else + RUU &= ~RUU_MOD_RK; + + /* Не находимся ли мы в цикле "ЖДУ" диспака? */ + if (RUU == 047 && PC == 04440 && RK == 067704440) { + /* Притормаживаем выполнение каждой команды холостого цикла, + * чтобы быстрее обрабатывались прерывания: ускоряются + * терминалы и АЦПУ. */ + delay = sim_interval; + + /* Если периферия простаивает, освобождаем процессор + * до следующего тика таймера. */ + if (vt_is_idle() && + printer_is_idle() && fs_is_idle()) { + check_initial_setup (); + pause (); + } + } +} + +/* + * Операция прерывания 1: внутреннее прерывание. + * Описана в 9-м томе технического описания БЭСМ-6, страница 119. + */ +void op_int_1 (const char *msg) +{ + /*besm6_okno (msg);*/ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + if (RUU & RUU_RIGHT_INSTR) + M[SPSW] |= SPSW_RIGHT_INSTR; + M[IRET] = PC; + M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; + if (RUU & RUU_MOD_RK) { + M[SPSW] |= SPSW_MOD_RK; + RUU &= ~RUU_MOD_RK; + } + PC = 0500; + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); +} + +/* + * Операция прерывания 2: внешнее прерывание. + * Описана в 9-м томе технического описания БЭСМ-6, страница 129. + */ +void op_int_2 () +{ + /*besm6_okno ("Внешнее прерывание");*/ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + M[IRET] = PC; + M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; + if (RUU & RUU_MOD_RK) { + M[SPSW] |= SPSW_MOD_RK; + RUU &= ~RUU_MOD_RK; + } + PC = 0501; + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); +} + +/* + * Main instruction fetch/decode loop + */ +t_stat sim_instr (void) +{ + t_stat r; + int iintr = 0; + + /* Restore register state */ + PC = PC & BITS(15); /* mask PC */ + sim_cancel_step (); /* defang SCP step */ + mmu_setup (); /* copy RP to TLB */ + + /* An internal interrupt or user intervention */ + r = setjmp (cpu_halt); + if (r) { + M[017] += corr_stack; + if (cpu_dev.dctrl) { + const char *message = (r >= SCPE_BASE) ? + scp_errors [r - SCPE_BASE] : + sim_stop_messages [r]; + besm6_debug ("/// %05o%s: %s", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л", + message); + } + + /* + * ПоП и ПоК вызывают останов при любом внутреннем прерывании + * или прерывании по контролю, соответственно. + * Если произошёл останов по ПоП или ПоК, + * то продолжение выполнения начнётся с команды, следующей + * за вызвавшей прерывание. Как если бы кнопка "ТП" (тип + * перехода) была включена. Подробнее на странице 119 ТО9. + */ + switch (r) { + default: +ret: besm6_draw_panel(); + return r; + case STOP_RWATCH: + case STOP_WWATCH: + /* Step back one insn to reexecute it */ + if (! (RUU & RUU_RIGHT_INSTR)) { + --PC; + } + RUU ^= RUU_RIGHT_INSTR; + goto ret; + case STOP_BADCMD: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK is not important for this interrupt + GRP |= GRP_ILL_INSN; + break; + case STOP_INSN_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK must be 0 for this interrupt; it is already + GRP |= GRP_INSN_CHECK; + break; + case STOP_INSN_PROT: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK must be 1 for this interrupt + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_INSN_PROT; + break; + case STOP_OPERAND_PROT: +#if 0 +/* ДИСПАК держит признак ПоП установленным. + * При запуске СЕРП возникает обращение к чужому листу. */ + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; +#endif + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + // The offending virtual page is in bits 5-9 + GRP |= GRP_OPRND_PROT; + GRP = GRP_SET_PAGE (GRP, iintr_data); + break; + case STOP_RAM_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // The offending interleaved block # is in bits 1-3. + GRP |= GRP_CHECK | GRP_RAM_CHECK; + GRP = GRP_SET_BLOCK (GRP, iintr_data); + break; + case STOP_CACHE_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // The offending BRZ # is in bits 1-3. + GRP |= GRP_CHECK; + GRP &= ~GRP_RAM_CHECK; + GRP = GRP_SET_BLOCK (GRP, iintr_data); + break; + case STOP_INSN_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_BREAKPOINT; + break; + case STOP_LOAD_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_WATCHPT_R; + break; + case STOP_STORE_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_WATCHPT_W; + break; + case STOP_OVFL: + /* Прерывание по АУ вызывает останов, если БРО=0 + * и установлен ПоП или ПоК. + * Страница 118 ТО9.*/ + if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ + ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ + (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + GRP |= GRP_OVERFLOW|GRP_RAM_CHECK; + break; + case STOP_DIVZERO: + if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ + ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ + (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + GRP |= GRP_DIVZERO|GRP_RAM_CHECK; + break; + } + ++iintr; + } + + if (iintr > 1) { + besm6_draw_panel(); + return STOP_DOUBLE_INTR; + } + /* Main instruction fetch/decode loop */ + for (;;) { + if (sim_interval <= 0) { /* check clock queue */ + r = sim_process_event (); + if (r) { + besm6_draw_panel(); + return r; + } + } + + if (PC > BITS(15)) { /* выход за пределы памяти */ + besm6_draw_panel(); + return STOP_RUNOUT; /* stop simulation */ + } + + if (sim_brk_summ & SWMASK('E') && /* breakpoint? */ + sim_brk_test (PC, SWMASK ('E'))) { + besm6_draw_panel(); + return STOP_IBKPT; /* stop simulation */ + } + + if (PRP & MPRP) { + /* регистр хранящий, сбрасывается программно */ + GRP |= GRP_SLAVE; + } + + if (! iintr && ! (RUU & RUU_RIGHT_INSTR) && + ! (M[PSW] & PSW_INTR_DISABLE) && (GRP & MGRP)) { + /* external interrupt */ + op_int_2(); + } + cpu_one_inst (); /* one instr */ + iintr = 0; + if (redraw_panel) { + besm6_draw_panel(); + redraw_panel = 0; + } + + if (delay < 1) + delay = 1; + sim_interval -= delay; /* count down delay */ + if (sim_step && (--sim_step <= 0)) { /* do step count */ + besm6_draw_panel(); + return SCPE_STOP; + } + } +} + +t_stat slow_clk (UNIT * this) +{ + /*besm6_debug ("*** таймер 80 мсек");*/ + GRP |= GRP_SLOW_CLK; + return sim_activate (this, MSEC*125/2); +} + +/* + * В 9-й части частота таймера 250 Гц (4 мс), + * в жизни - 50 Гц (20 мс). + */ +t_stat fast_clk (UNIT * this) +{ + /*besm6_debug ("*** таймер 20 мсек");*/ + GRP |= GRP_TIMER; + return sim_activate (this, 20*MSEC); +} + +UNIT clocks[] = { + { UDATA(slow_clk, 0, 0) }, /* 10 р, 16 Гц */ + { UDATA(fast_clk, 0, 0) }, /* 40 р, 50 Гц */ +}; + +t_stat clk_reset (DEVICE * dev) +{ + /* Схема автозапуска включается по нереализованной кнопке "МР" */ +#ifdef SOFT_CLOCK + sim_activate (&clocks[0], MSEC*125/2); + return sim_activate (&clocks[1], 20*MSEC); +#else + return SCPE_OK; +#endif +} + +DEVICE clock_dev = { + "CLK", clocks, NULL, NULL, + 2, 0, 0, 0, 0, 0, + NULL, NULL, &clk_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG +}; diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h new file mode 100644 index 00000000..d782109a --- /dev/null +++ b/BESM6/besm6_defs.h @@ -0,0 +1,426 @@ +/* + * besm6_defs.h: BESM-6 simulator definitions + * + * Copyright (c) 2009, Serge Vakulenko + * 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. + */ +#ifndef _BESM6_DEFS_H_ +#define _BESM6_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ +#include + +/* + * Memory. + */ +#define NREGS 30 /* number of registers-modifiers */ +#define MEMSIZE (512 * 1024) /* memory size, words */ + +/* + * Drums and disks. + * + * One zone contains 1024 words of user memory and 8 system data words. + * Every word (t_value) is stored as 8-byte record, low byte first. + * System data is stored first, then user data. + */ +#define ZONE_SIZE (8 + 1024) /* 1kword zone size, words */ +#define DRUM_SIZE (256 * ZONE_SIZE) /* drum size per controller, words */ +#define DISK_SIZE (1024 * ZONE_SIZE) /* disk size per unit, words */ + +/* + * Simulator stop codes + */ +enum { + STOP_STOP = 1, /* STOP */ + STOP_IBKPT, /* SIMH breakpoint */ + STOP_RWATCH, /* SIMH read watchpoint */ + STOP_WWATCH, /* SIMH write watchpoint */ + STOP_RUNOUT, /* run out end of memory limits */ + STOP_BADCMD, /* invalid instruction */ + STOP_INSN_CHECK, /* not an instruction */ + STOP_INSN_PROT, /* fetch from blocked page */ + STOP_OPERAND_PROT, /* load from blocked page */ + STOP_RAM_CHECK, /* RAM parity error */ + STOP_CACHE_CHECK, /* data cache parity error */ + STOP_OVFL, /* arith. overflow */ + STOP_DIVZERO, /* division by 0 or denorm */ + STOP_DOUBLE_INTR, /* double internal interrupt */ + STOP_DRUMINVDATA, /* reading unformatted drum */ + STOP_DISKINVDATA, /* reading unformatted disk */ + STOP_INSN_ADDR_MATCH, /* fetch address matched breakpt reg */ + STOP_LOAD_ADDR_MATCH, /* load address matched watchpt reg */ + STOP_STORE_ADDR_MATCH, /* store address matched watchpt reg */ + STOP_UNIMPLEMENTED, /* unimplemented 033 or 002 insn feature */ +}; + +/* + * Разряды машинного слова, справа налево, начиная с 1. + */ +#define BBIT(n) (1 << (n-1)) /* один бит, от 1 до 32 */ +#define BIT40 000010000000000000LL /* 40-й бит - старший разряд мантиссы */ +#define BIT41 000020000000000000LL /* 41-й бит - знак */ +#define BIT42 000040000000000000LL /* 42-й бит - дубль-знак в мантиссе */ +#define BIT48 004000000000000000LL /* 48-й бит - знак порядка */ +#define BIT49 010000000000000000LL /* бит 49 */ +#define BITS(n) (~0U >> (32-n)) /* маска битов n..1 */ +#define BITS40 00017777777777777LL /* биты 41..1 - мантисса */ +#define BITS41 00037777777777777LL /* биты 41..1 - мантисса и знак */ +#define BITS42 00077777777777777LL /* биты 42..1 - мантисса и оба знака */ +#define BITS48 07777777777777777LL /* биты 48..1 */ +#define BITS48_42 07740000000000000LL /* биты 48..42 - порядок */ +#define ADDR(x) ((x) & BITS(15)) /* адрес слова */ + +/* + * Работа со сверткой. Значение разрядов свертки слова равно значению + * регистров ПКЛ и ПКП при записи слова. + * 00 - командная свертка + * 01 или 10 - контроль числа + * 11 - числовая свертка + * В памяти биты свертки имитируют четность полуслов. + */ +#define CONVOL_INSN 1 +#define CONVOL_NUMBER 2 +#define SET_CONVOL(x, c) (((x) & BITS48) | (((c) & 3LL) << 48)) +#define IS_INSN(x) (((x) >> 48) == CONVOL_INSN) +#define IS_NUMBER(x) (((x) >> 48) == CONVOL_INSN || \ + ((x) >> 48) == CONVOL_NUMBER) + +/* + * Вычисление правдоподобного времени выполнения команды, + * зная количество тактов в УУ и среднее в АУ. + * Предполагаем, что в 50% случаев происходит совмещение + * выполнения, поэтому суммируем большее и половину + * от меньшего значения. + */ +#define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y) + +/* + * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. + */ +#define USEC 10 /* одна микросекунда - десять тактов */ +#define MSEC (1000*USEC) /* одна миллисекунда */ + +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern int32 sim_interval, sim_step; +extern FILE *sim_deb, *sim_log; +extern int32 sim_switches; + +extern UNIT cpu_unit; +extern t_value memory [MEMSIZE]; +extern t_value pult [8]; +extern uint32 PC, RAU, RUU; +extern uint32 M[NREGS]; +extern t_value BRZ[8], RP[8], GRP, MGRP; +extern uint32 PRP, MPRP; +extern t_value ACC, RMR; +extern uint32 BAZ[8], TABST, RZ; +extern uint32 READY; /* read by ext 4031 */ +extern uint32 READY2; /* read by ext 4102 */ +extern DEVICE cpu_dev, drum_dev, mmu_dev, disk_dev; +extern DEVICE clock_dev; +extern DEVICE printer_dev; +extern DEVICE tty_dev; +extern DEVICE fs_dev; +extern jmp_buf cpu_halt; + +/* + * Разряды режима АУ. + */ +#define RAU_NORM_DISABLE 001 /* блокировка нормализации */ +#define RAU_ROUND_DISABLE 002 /* блокировка округления */ +#define RAU_LOG 004 /* признак логической группы */ +#define RAU_MULT 010 /* признак группы умножения */ +#define RAU_ADD 020 /* признак группы слодения */ +#define RAU_OVF_DISABLE 040 /* блокировка переполнения */ + +#define RAU_MODE (RAU_LOG | RAU_MULT | RAU_ADD) +#define SET_MODE(x,m) (((x) & ~RAU_MODE) | (m)) +#define SET_LOGICAL(x) (((x) & ~RAU_MODE) | RAU_LOG) +#define SET_MULTIPLICATIVE(x) (((x) & ~RAU_MODE) | RAU_MULT) +#define SET_ADDITIVE(x) (((x) & ~RAU_MODE) | RAU_ADD) +#define IS_LOGICAL(x) (((x) & RAU_MODE) == RAU_LOG) +#define IS_MULTIPLICATIVE(x) (((x) & (RAU_ADD | RAU_MULT)) == RAU_MULT) +#define IS_ADDITIVE(x) ((x) & RAU_ADD) + +/* + * Искусственный регистр режимов УУ, в реальной машине отсутствует. + */ +#define RUU_CONVOL_RIGHT 000001 /* ПКП - признак контроля правой половины */ +#define RUU_CONVOL_LEFT 000002 /* ПКЛ - признак контроля левой половины */ +#define RUU_EXTRACODE 000004 /* РежЭ - режим экстракода */ +#define RUU_INTERRUPT 000010 /* РежПр - режим прерывания */ +#define RUU_MOD_RK 000020 /* ПрИК - модификация регистром М[16] */ +#define RUU_AVOST_DISABLE 000040 /* БРО - блокировка режима останова */ +#define RUU_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ + +#define IS_SUPERVISOR(x) ((x) & (RUU_EXTRACODE | RUU_INTERRUPT)) +#define SET_SUPERVISOR(x,m) (((x) & ~(RUU_EXTRACODE | RUU_INTERRUPT)) | (m)) + +/* + * Специальные регистры. + */ +#define MOD 020 /* модификатор адреса */ +#define PSW 021 /* режимы УУ */ +#define SPSW 027 /* упрятывание режимов УУ */ +#define ERET 032 /* адрес возврата из экстракода */ +#define IRET 033 /* адрес возврата из прерывания */ +#define IBP 034 /* адрес прерывания по выполнению */ +#define DWP 035 /* адрес прерывания по чтению/записи */ + +/* + * Регистр 021: режимы УУ. + * PSW: program status word. + */ +#define PSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ +#define PSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ +#define PSW_INTR_HALT 000004 /* ПоП - признак останова при + любом внутреннем прерывании */ +#define PSW_CHECK_HALT 000010 /* ПоК - признак останова при + прерывании по контролю */ +#define PSW_WRITE_WATCH 000020 /* Зп(М29) - признак совпадения адреса + операнда прии записи в память + с содержанием регистра М29 */ +#define PSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ +#define PSW_AUT_B 004000 /* АвтБ - признак режима Автомат Б */ + +/* + * Регистр 027: сохранённые режимы УУ. + * SPSW: saved program status word. + */ +#define SPSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ +#define SPSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ +#define SPSW_EXTRACODE 000004 /* РежЭ - режим экстракода */ +#define SPSW_INTERRUPT 000010 /* РежПр - режим прерывания */ +#define SPSW_MOD_RK 000020 /* ПрИК(РК) - на регистр РК принята + команда, которая должна быть + модифицирована регистром М[16] */ +#define SPSW_MOD_RR 000040 /* ПрИК(РР) - на регистре РР находится + команда, выполненная с модификацией */ +#define SPSW_UNKNOWN 000100 /* НОК? вписано карандашом в 9 томе */ +#define SPSW_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ +#define SPSW_NEXT_RK 001000 /* ГД./ДК2 - на регистр РК принята + команда, следующая после вызвавшей + прерывание */ +#define SPSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ + +/* + * Кириллица Unicode. + */ +#define CYRILLIC_CAPITAL_LETTER_A 0x0410 +#define CYRILLIC_CAPITAL_LETTER_BE 0x0411 +#define CYRILLIC_CAPITAL_LETTER_VE 0x0412 +#define CYRILLIC_CAPITAL_LETTER_GHE 0x0413 +#define CYRILLIC_CAPITAL_LETTER_DE 0x0414 +#define CYRILLIC_CAPITAL_LETTER_IE 0x0415 +#define CYRILLIC_CAPITAL_LETTER_ZHE 0x0416 +#define CYRILLIC_CAPITAL_LETTER_ZE 0x0417 +#define CYRILLIC_CAPITAL_LETTER_I 0x0418 +#define CYRILLIC_CAPITAL_LETTER_SHORT_I 0x0419 +#define CYRILLIC_CAPITAL_LETTER_KA 0x041a +#define CYRILLIC_CAPITAL_LETTER_EL 0x041b +#define CYRILLIC_CAPITAL_LETTER_EM 0x041c +#define CYRILLIC_CAPITAL_LETTER_EN 0x041d +#define CYRILLIC_CAPITAL_LETTER_O 0x041e +#define CYRILLIC_CAPITAL_LETTER_PE 0x041f +#define CYRILLIC_CAPITAL_LETTER_ER 0x0420 +#define CYRILLIC_CAPITAL_LETTER_ES 0x0421 +#define CYRILLIC_CAPITAL_LETTER_TE 0x0422 +#define CYRILLIC_CAPITAL_LETTER_U 0x0423 +#define CYRILLIC_CAPITAL_LETTER_EF 0x0424 +#define CYRILLIC_CAPITAL_LETTER_HA 0x0425 +#define CYRILLIC_CAPITAL_LETTER_TSE 0x0426 +#define CYRILLIC_CAPITAL_LETTER_CHE 0x0427 +#define CYRILLIC_CAPITAL_LETTER_SHA 0x0428 +#define CYRILLIC_CAPITAL_LETTER_SHCHA 0x0429 +#define CYRILLIC_CAPITAL_LETTER_HARD_SIGN 0x042a +#define CYRILLIC_CAPITAL_LETTER_YERU 0x042b +#define CYRILLIC_CAPITAL_LETTER_SOFT_SIGN 0x042c +#define CYRILLIC_CAPITAL_LETTER_E 0x042d +#define CYRILLIC_CAPITAL_LETTER_YU 0x042e +#define CYRILLIC_CAPITAL_LETTER_YA 0x042f +#define CYRILLIC_SMALL_LETTER_A 0x0430 +#define CYRILLIC_SMALL_LETTER_BE 0x0431 +#define CYRILLIC_SMALL_LETTER_VE 0x0432 +#define CYRILLIC_SMALL_LETTER_GHE 0x0433 +#define CYRILLIC_SMALL_LETTER_DE 0x0434 +#define CYRILLIC_SMALL_LETTER_IE 0x0435 +#define CYRILLIC_SMALL_LETTER_ZHE 0x0436 +#define CYRILLIC_SMALL_LETTER_ZE 0x0437 +#define CYRILLIC_SMALL_LETTER_I 0x0438 +#define CYRILLIC_SMALL_LETTER_SHORT_I 0x0439 +#define CYRILLIC_SMALL_LETTER_KA 0x043a +#define CYRILLIC_SMALL_LETTER_EL 0x043b +#define CYRILLIC_SMALL_LETTER_EM 0x043c +#define CYRILLIC_SMALL_LETTER_EN 0x043d +#define CYRILLIC_SMALL_LETTER_O 0x043e +#define CYRILLIC_SMALL_LETTER_PE 0x043f +#define CYRILLIC_SMALL_LETTER_ER 0x0440 +#define CYRILLIC_SMALL_LETTER_ES 0x0441 +#define CYRILLIC_SMALL_LETTER_TE 0x0442 +#define CYRILLIC_SMALL_LETTER_U 0x0443 +#define CYRILLIC_SMALL_LETTER_EF 0x0444 +#define CYRILLIC_SMALL_LETTER_HA 0x0445 +#define CYRILLIC_SMALL_LETTER_TSE 0x0446 +#define CYRILLIC_SMALL_LETTER_CHE 0x0447 +#define CYRILLIC_SMALL_LETTER_SHA 0x0448 +#define CYRILLIC_SMALL_LETTER_SHCHA 0x0449 +#define CYRILLIC_SMALL_LETTER_HARD_SIGN 0x044a +#define CYRILLIC_SMALL_LETTER_YERU 0x044b +#define CYRILLIC_SMALL_LETTER_SOFT_SIGN 0x044c +#define CYRILLIC_SMALL_LETTER_E 0x044d +#define CYRILLIC_SMALL_LETTER_YU 0x044e +#define CYRILLIC_SMALL_LETTER_YA 0x044f + +/* + * Процедуры работы с памятью + */ +extern void mmu_store (int addr, t_value word); +extern t_value mmu_load (int addr); +extern t_value mmu_fetch (int addr); +extern t_value mmu_prefetch (int addr, int actual); +extern void mmu_setcache (int idx, t_value word); +extern t_value mmu_getcache (int idx); +extern void mmu_setrp (int idx, t_value word); +extern void mmu_setup (void); +extern void mmu_setprotection (int idx, t_value word); +extern void mmu_print_brz (void); + +/* + * Выполнение обращения к барабану. + */ +void drum (int ctlr, uint32 cmd); +int drum_errors (void); + +/* + * Обращение к дискам. + */ +void disk_io (int ctlr, uint32 cmd); +void disk_ctl (int ctlr, uint32 cmd); +int disk_state (int ctlr); +int disk_errors (void); + +/* + * Печать на АЦПУ. + */ +void printer_control (int num, uint32 cmd); +void printer_hammer (int num, int pos, uint32 mask); +int printer_is_idle (void); + +/* + * Терминалы (телетайпы, видеотоны, "Консулы"). + */ +void tty_send (uint32 mask); +int tty_query (void); +void vt_print (void); +void vt_receive (void); +void consul_print (int num, uint32 cmd); +uint32 consul_read (int num); +int vt_is_idle (void); + +/* + * Ввод с перфоленты. + */ +void fs_control (int num, uint32 cmd); +int fs_read (int num); +int fs_is_idle (void); + +/* + * Отладочная выдача. + */ +void besm6_fprint_cmd (FILE *of, uint32 cmd); +void besm6_log (const char *fmt, ...); +void besm6_log_cont (const char *fmt, ...); +void besm6_debug (const char *fmt, ...); +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); +void besm6_draw_panel (void); + +/* + * Арифметика. + */ +double besm6_to_ieee (t_value word); +void besm6_add (t_value val, int negate_acc, int negate_val); +void besm6_divide (t_value val); +void besm6_multiply (t_value val); +void besm6_change_sign (int sign); +void besm6_add_exponent (int val); +int besm6_highest_bit (t_value val); +void besm6_shift (int toright); +int besm6_count_ones (t_value word); +t_value besm6_pack (t_value val, t_value mask); +t_value besm6_unpack (t_value val, t_value mask); + +/* + * Разряды главного регистра прерываний (ГРП) + * Внешние: + */ +#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */ +#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */ +#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */ +#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */ +#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */ +#define GRP_FS1_SYNC 00040000000000000LL /* 42 */ +#define GRP_FS2_SYNC 00020000000000000LL /* 41 */ +#define GRP_TIMER 00010000000000000LL /* 40 */ +#define GRP_PRN1_ZERO 00004000000000000LL /* 39 */ +#define GRP_PRN2_ZERO 00002000000000000LL /* 38 */ +#define GRP_SLAVE 00001000000000000LL /* 37 */ +#define GRP_CHAN3_DONE 00000400000000000LL /* 36 */ +#define GRP_CHAN4_DONE 00000200000000000LL /* 35 */ +#define GRP_CHAN5_DONE 00000100000000000LL /* 34 */ +#define GRP_CHAN6_DONE 00000040000000000LL /* 33 */ +#define GRP_PANEL_REQ 00000020000000000LL /* 32 */ +#define GRP_TTY_START 00000010000000000LL /* 31 */ +#define GRP_IMITATION 00000004000000000LL /* 30 */ +#define GRP_CHAN3_FREE 00000002000000000LL /* 29 */ +#define GRP_CHAN4_FREE 00000001000000000LL /* 28 */ +#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ +#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ +#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ +#define GRP_WATCHDOG 00000000000002000LL /* 11 */ +#define GRP_SLOW_CLK 00000000000001000LL /* 10 */ +/* Внутренние: */ +#define GRP_DIVZERO 00000000034000000LL /* 23-21 */ +#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */ +#define GRP_CHECK 00000000004000000LL /* 21 */ +#define GRP_OPRND_PROT 00000000002000000LL /* 20 */ +#define GRP_WATCHPT_W 00000000000200000LL /* 17 */ +#define GRP_WATCHPT_R 00000000000100000LL /* 16 */ +#define GRP_INSN_CHECK 00000000000040000LL /* 15 */ +#define GRP_INSN_PROT 00000000000020000LL /* 14 */ +#define GRP_ILL_INSN 00000000000010000LL /* 13 */ +#define GRP_BREAKPOINT 00000000000004000LL /* 12 */ +#define GRP_PAGE_MASK 00000000000000760LL /* 9-5 */ +#define GRP_RAM_CHECK 00000000000000010LL /* 4 */ +#define GRP_BLOCK_MASK 00000000000000007LL /* 3-1 */ + +#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK)) +#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK)) + +/* Номер блока ОЗУ или номер страницы, вызвавших прерывание */ +extern uint32 iintr_data; + +#endif diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c new file mode 100644 index 00000000..37fbd23c --- /dev/null +++ b/BESM6/besm6_disk.c @@ -0,0 +1,648 @@ +/* + * BESM-6 magnetic disk device + * + * Copyright (c) 2009, Serge Vakulenko + * 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" + +/* + * Управляющее слово обмена с магнитным диском. + */ +#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */ +#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */ +#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */ +#define DISK_READ 000400000 /* чтение с диска в память */ +#define DISK_PAGE 000370000 /* номер страницы памяти */ +#define DISK_HALFPAGE 000004000 /* выбор половины листа */ +#define DISK_UNIT 000001600 /* номер устройства */ +#define DISK_HALFZONE 000000001 /* выбор половины зоны */ + +/* + * "Хороший" статус чтения/записи. + * Вычислено по текстам ОС Дубна. + * Диспак доволен. + */ +#define STATUS_GOOD 014000400 + +/* + * Параметры обмена с внешним устройством. + */ +typedef struct { + int op; /* Условное слово обмена */ + int dev; /* Номер устройства, 0..7 */ + int zone; /* Номер зоны на диске */ + int track; /* Выбор половины зоны на диске */ + int memory; /* Начальный адрес памяти */ + int format; /* Флаг разметки */ + int status; /* Регистр состояния */ + t_value mask_grp; /* Маска готовности для ГРП */ + int mask_fail; /* Маска ошибки обмена */ + t_value *sysdata; /* Буфер системных данных */ +} KMD; + +static KMD controller [2]; /* Две стойки КМД */ +int disk_fail; /* Маска ошибок по направлениям */ + +t_stat disk_event (UNIT *u); + +/* + * DISK data structures + * + * disk_dev DISK device descriptor + * disk_unit DISK unit descriptor + * disk_reg DISK register list + */ +UNIT disk_unit [16] = { + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, +}; + +REG disk_reg[] = { +{ "КУС_0", &controller[0].op, 8, 24, 0, 1 }, +{ "УСТР_0", &controller[0].dev, 8, 3, 0, 1 }, +{ "ЗОНА_0", &controller[0].zone, 8, 10, 0, 1 }, +{ "ДОРОЖКА_0", &controller[0].track, 8, 2, 0, 1 }, +{ "МОЗУ_0", &controller[0].memory, 8, 20, 0, 1 }, +{ "РС_0", &controller[0].status, 8, 24, 0, 1 }, +{ "КУС_1", &controller[1].op, 8, 24, 0, 1 }, +{ "УСТР_1", &controller[1].dev, 8, 3, 0, 1 }, +{ "ЗОНА_1", &controller[1].zone, 8, 10, 0, 1 }, +{ "ДОРОЖКА_1", &controller[1].track, 8, 2, 0, 1 }, +{ "МОЗУ_1", &controller[1].memory, 8, 20, 0, 1 }, +{ "РС_1", &controller[1].status, 8, 24, 0, 1 }, +{ "ОШ", &disk_fail, 8, 6, 0, 1 }, +{ 0 } +}; + +MTAB disk_mod[] = { + { 0 } +}; + +t_stat disk_reset (DEVICE *dptr); +t_stat disk_attach (UNIT *uptr, char *cptr); +t_stat disk_detach (UNIT *uptr); + +DEVICE disk_dev = { + "DISK", disk_unit, disk_reg, disk_mod, + 16, 8, 21, 1, 8, 50, + NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach, + NULL, DEV_DISABLE | DEV_DEBUG +}; + +/* + * Определение контроллера по устройству. + */ +static KMD *unit_to_ctlr (UNIT *u) +{ + if (u < &disk_unit[8]) + return &controller[0]; + else + return &controller[1]; +} + +/* + * Reset routine + */ +t_stat disk_reset (DEVICE *dptr) +{ + int i; + + memset (&controller, 0, sizeof (controller)); + controller[0].sysdata = &memory [030]; + controller[1].sysdata = &memory [040]; + controller[0].mask_grp = GRP_CHAN3_FREE; + controller[1].mask_grp = GRP_CHAN4_FREE; + controller[0].mask_fail = 020; + controller[1].mask_fail = 010; + for (i=0; i<16; ++i) + sim_cancel (&disk_unit[i]); + return SCPE_OK; +} + +t_stat disk_attach (UNIT *u, char *cptr) +{ + t_stat s; + + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + return SCPE_OK; +} + +t_stat disk_detach (UNIT *u) +{ + /* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */ + return detach_unit (u); +} + +t_value spread (t_value val) +{ + int i, j; + t_value res = 0; + + for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) + if (val & (1LL<<(i+j*5))) + res |= 1LL << (i*9+j); + return res & BITS48; +} + +/* + * Отладочная печать массива данных обмена. + */ +static void log_data (t_value *data, int nwords) +{ + int i; + t_value val; + + for (i=0; i> 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"); +} + +/* + * Сложение с переносом вправо. + */ +static unsigned sum_with_right_carry (unsigned a, unsigned b) +{ + unsigned c; + + while (b) { + c = a & b; + a ^= b; + b = c >> 1; + } + return a; +} + +/* + * Запись на диск. + */ +void disk_write (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ("::: запись МД %o зона %04o память %05o-%05o", + c->dev, c->zone, c->memory, c->memory + 1023); + fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); + sim_fwrite (c->sysdata, 8, 8, u->fileref); + sim_fwrite (&memory [c->memory], 8, 1024, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +void disk_write_track (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ("::: запись МД %o полузона %04o.%d память %05o-%05o", + c->dev, c->zone, c->track, c->memory, c->memory + 511); + fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); + sim_fwrite (c->sysdata + 4*c->track, 8, 4, u->fileref); + fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, + SEEK_SET); + sim_fwrite (&memory [c->memory], 8, 512, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +/* + * Форматирование дорожки. + */ +void disk_format (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + t_value fmtbuf[5], *ptr; + int i; + + /* По сути, эмулятору ничего делать не надо. */ + if (! disk_dev.dctrl) + return; + + /* Находим начало записываемого заголовка. */ + ptr = &memory [c->memory]; + while ((*ptr & BITS48) == 0) + ptr++; + + /* Декодируем из гребенки в нормальный вид. */ + for (i = 0; i < 5; i++) + fmtbuf[i] = spread (ptr[i]); + + /* При первой попытке разметки адресный маркер начинается в старшем 5-разрядном слоге, + * пропускаем первый слог. */ + for (i=0; i<4; i++) + fmtbuf[i] = ((fmtbuf[i] & BITS48) << 5) | + ((fmtbuf[i+1] >> 40) & BITS(5)); + + /* Печатаем идентификатор, адрес и контрольную сумму адреса. */ + besm6_debug ("::: формат МД %o полузона %04o.%d память %05o и-а-кса %010o %010o", + c->dev, c->zone, c->track, c->memory, + (int) (fmtbuf[0] >> 8 & BITS(30)), + (int) (fmtbuf[2] >> 14 & BITS(30))); + /* log_data (fmtbuf, 4); */ +} + +/* + * Чтение с диска. + */ +void disk_read (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ((c->op & DISK_READ_SYSDATA) ? + "::: чтение МД %o зона %04o служебные слова" : + "::: чтение МД %o зона %04o память %05o-%05o", + c->dev, c->zone, c->memory, c->memory + 1023); + fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); + if (sim_fread (c->sysdata, 8, 8, u->fileref) != 8) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (! (c->op & DISK_READ_SYSDATA) && + sim_fread (&memory [c->memory], 8, 1024, u->fileref) != 1024) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +t_value collect (t_value val) +{ + int i, j; + t_value res = 0; + + for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) + if (val & (1LL<<(i*9+j))) + res |= 1LL << (i+j*5); + return res & BITS48; +} + +void disk_read_track (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ((c->op & DISK_READ_SYSDATA) ? + "::: чтение МД %o полузона %04o.%d служебные слова" : + "::: чтение МД %o полузона %04o.%d память %05o-%05o", + c->dev, c->zone, c->track, c->memory, c->memory + 511); + fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); + if (sim_fread (c->sysdata + 4*c->track, 8, 4, u->fileref) != 4) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (! (c->op & DISK_READ_SYSDATA)) { + fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, + SEEK_SET); + if (sim_fread (&memory [c->memory], 8, 512, u->fileref) != 512) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + } + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +/* + * Чтение заголовка дорожки. + */ +void disk_read_header (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + t_value *sysdata = c->sysdata + 4*c->track; + int iaksa, i, cyl, head; + + /* Адрес: номер цилиндра и головки. */ + head = (c->zone << 1) + c->track; + cyl = head / 10; + head %= 10; + iaksa = (cyl << 20) | (head << 16); + + /* Идентификатор дорожки замены. */ + if (c->zone >= 01750) + iaksa |= BBIT(30); + + /* Контрольная сумма адреса с переносом вправо. */ + iaksa |= BITS(12) & ~sum_with_right_carry (iaksa >> 12, iaksa >> 24); + + /* Амиакса, 42 нуля, амиакса, много единиц. */ + sysdata[0] = 07404000000000000LL | (t_value) iaksa << 8; + sysdata[1] = 03740LL; + sysdata[2] = 00400000000037777LL | (t_value) iaksa << 14; + sysdata[3] = BITS48; + if (disk_dev.dctrl) + log_data (sysdata, 4); + + /* Кодируем гребенку. */ + for (i=0; i<4; i++) + sysdata[i] = SET_CONVOL (collect (sysdata[i]), CONVOL_NUMBER); +} + +/* + * Задание адреса памяти и длины массива для последующего обращения к диску. + * Номера дисковода и дорожки будут выданы позже, командой 033 0023(0024). + */ +void disk_io (int ctlr, uint32 cmd) +{ + KMD *c = &controller [ctlr]; + + c->op = cmd; + c->format = 0; + if (c->op & DISK_PAGE_MODE) { + /* Обмен страницей */ + c->memory = (cmd & DISK_PAGE) >> 2 | (cmd & DISK_BLOCK) >> 8; + } else { + /* Обмен половиной страницы (дорожкой) */ + c->memory = (cmd & (DISK_PAGE | DISK_HALFPAGE)) >> 2 | (cmd & DISK_BLOCK) >> 8; + } +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: задание на %s %08o", ctlr + '3', + (c->op & DISK_READ) ? "чтение" : "запись", cmd); +#endif + disk_fail &= ~c->mask_fail; + + /* Гасим главный регистр прерываний. */ + GRP &= ~c->mask_grp; +} + +/* + * Управление диском: команда 00 033 0023(0024). + */ +void disk_ctl (int ctlr, uint32 cmd) +{ + KMD *c = &controller [ctlr]; + UNIT *u = &disk_unit [c->dev]; + + if (cmd & BBIT(12)) { + /* Выдача в КМД адреса дорожки. + * Здесь же выполняем обмен с диском. + * Номер дисковода к этому моменту уже известен. */ + if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { + /* Device not attached. */ + disk_fail |= c->mask_fail; + return; + } + c->zone = (cmd >> 1) & BITS(10); + c->track = cmd & 1; +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: выдача адреса дорожки %04o.%d", + ctlr + '3', c->zone, c->track); +#endif + disk_fail &= ~c->mask_fail; + if (c->op & DISK_READ) { + if (c->op & DISK_PAGE_MODE) + disk_read (u); + else + disk_read_track (u); + } else { + if (u->flags & UNIT_RO) { + /* Read only. */ + /*longjmp (cpu_halt, SCPE_RO);*/ + disk_fail |= c->mask_fail; + return; + } + if (c->format) + disk_format (u); + else if (c->op & DISK_PAGE_MODE) + disk_write (u); + else + disk_write_track (u); + } + + /* Ждём события от устройства. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + + } else if (cmd & BBIT(11)) { + /* Выбора номера устройства и занесение в регистр маски КМД. + * Бит 8 - устройство 0, бит 7 - устройство 1, ... бит 1 - устройство 7. + * Также установлен бит 9 - что он означает? */ + if (cmd & BBIT(8)) c->dev = 7; + else if (cmd & BBIT(7)) c->dev = 6; + else if (cmd & BBIT(6)) c->dev = 5; + else if (cmd & BBIT(5)) c->dev = 4; + else if (cmd & BBIT(4)) c->dev = 3; + else if (cmd & BBIT(3)) c->dev = 2; + else if (cmd & BBIT(2)) c->dev = 1; + else if (cmd & BBIT(1)) c->dev = 0; + else { + /* Неверная маска выбора устройства. */ + c->dev = -1; + return; + } + c->dev += ctlr << 3; + u = &disk_unit[c->dev]; +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: выбор устройства %d", + ctlr + '3', c->dev); +#endif + if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { + /* Device not attached. */ + disk_fail |= c->mask_fail; + GRP &= ~c->mask_grp; + } + GRP |= c->mask_grp; + + } else if (cmd & BBIT(9)) { + /* Проверка прерывания от КМД? */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: проверка готовности", + ctlr + '3'); +#endif + GRP |= c->mask_grp; + + } else { + /* Команда, выдаваемая в КМД. */ + switch (cmd & 077) { + case 000: /* диспак выдаёт эту команду один раз в начале загрузки */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: недокументированная команда 00", + ctlr + '3'); +#endif + break; + case 001: /* сброс на 0 цилиндр */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: сброс на 0 цилиндр", + ctlr + '3'); +#endif + break; + case 002: /* подвод */ + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: подвод", ctlr + '3'); + break; + case 003: /* чтение (НСМД-МОЗУ) */ + case 043: /* резервной дорожки */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: чтение", ctlr + '3'); +#endif + break; + case 004: /* запись (МОЗУ-НСМД) */ + case 044: /* резервной дорожки */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: запись", ctlr + '3'); +#endif + break; + case 005: /* разметка */ + c->format = 1; + break; + case 006: /* сравнение кодов (МОЗУ-НСМД) */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: сравнение кодов", ctlr + '3'); +#endif + break; + case 007: /* чтение заголовка */ + case 047: /* резервной дорожки */ + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: чтение %s заголовка", ctlr + '3', + cmd & 040 ? "резервного" : ""); + disk_fail &= ~c->mask_fail; + disk_read_header (u); + + /* Ждём события от устройства. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + break; + case 010: /* гашение PC */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: гашение регистра состояния", + ctlr + '3'); +#endif + c->status = 0; + break; + case 011: /* опрос 1÷12 разрядов PC */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос младших разрядов состояния", + ctlr + '3'); +#endif + if (disk_unit[c->dev].flags & UNIT_ATT) + c->status = STATUS_GOOD & BITS(12); + else + c->status = 0; + break; + case 031: /* опрос 13÷24 разрядов РС */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос старших разрядов состояния", + ctlr + '3'); +#endif + if (disk_unit[c->dev].flags & UNIT_ATT) + c->status = (STATUS_GOOD >> 12) & BITS(12); + else + c->status = 0; + break; + case 050: /* освобождение НМД */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: освобождение накопителя", + ctlr + '3'); +#endif + break; + default: + besm6_debug ("::: КМД %c: неизвестная команда %02o", + ctlr + '3', cmd & 077); + GRP |= c->mask_grp; /* чтобы не зависало */ + break; + } + } +} + +/* + * Запрос состояния контроллера. + */ +int disk_state (int ctlr) +{ + KMD *c = &controller [ctlr]; +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос состояния = %04o", + ctlr + '3', c->status); +#endif + return c->status; +} + +/* + * Событие: закончен обмен с МД. + * Устанавливаем флаг прерывания. + */ +t_stat disk_event (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + GRP |= c->mask_grp; + return SCPE_OK; +} + +/* + * Опрос ошибок обмена командой 033 4035. + */ +int disk_errors () +{ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД: опрос шкалы ошибок = %04o", disk_fail); +#endif + return disk_fail; +} diff --git a/BESM6/besm6_drum.c b/BESM6/besm6_drum.c new file mode 100644 index 00000000..2766baa2 --- /dev/null +++ b/BESM6/besm6_drum.c @@ -0,0 +1,372 @@ +/* + * 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[] = { +{ "УС", &drum_op, 8, 24, 0, 1 }, +{ "ЗОНА", &drum_zone, 8, 10, 0, 1 }, +{ "СЕКТОР", &drum_sector, 8, 2, 0, 1 }, +{ "МОЗУ", &drum_memory, 8, 15, 0, 1 }, +{ "СЧСЛОВ", &drum_nwords, 8, 11, 0, 1 }, +{ 0 } +}; + +MTAB drum_mod[] = { + { 0 } +}; + +t_stat drum_reset (DEVICE *dptr); +t_stat drum_attach (UNIT *uptr, 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, 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); + 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]; + fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, + SEEK_SET); + sim_fwrite (&sysdata [drum_sector*2], 8, 2, u->fileref); + fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, + SEEK_SET); + 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]; + fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET); + if (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]; + fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, SEEK_SET); + if (sim_fread (&sysdata [drum_sector*2], 8, 2, u->fileref) != 2) { + /* Чтение неинициализированного барабана */ + drum_fail |= 0100 >> ctlr; + return; + } + if (! (drum_op & DRUM_READ_SYSDATA)) { + fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, + SEEK_SET); + if (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_CONVOL (0, CONVOL_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; +} diff --git a/BESM6/besm6_mmu.c b/BESM6/besm6_mmu.c new file mode 100644 index 00000000..beed6dc2 --- /dev/null +++ b/BESM6/besm6_mmu.c @@ -0,0 +1,652 @@ +/* + * besm6_mmu.c: BESM-6 fast write cache and TLB registers + *(стойка БРУС) + * + * 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" + +/* + * MMU data structures + * + * mmu_dev MMU device descriptor + * mmu_unit MMU unit descriptor + * mmu_reg MMU register list + */ +UNIT mmu_unit = { + UDATA (NULL, UNIT_FIX, 8) +}; + +t_value BRZ[8]; +uint32 BAZ[8], TABST, RZ, OLDEST, FLUSH; + +t_value BRS[4]; +uint32 BAS[4]; +uint32 BRSLRU; + +/* + * 64-битные регистры RP0-RP7 - для отображения регистров приписки, + * группами по 4 ради компактности, 12 бит на страницу. + * TLB0-TLB31 - постраничные регистры приписки, копии RPi. + * Обращение к памяти должно вестись через TLBi. + */ +t_value RP[8]; +uint32 TLB[32]; + +unsigned iintr_data; /* protected page number or parity check location */ + +t_value pult[8]; + +REG mmu_reg[] = { +{ "БРЗ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры записи */ +{ "БРЗ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БАЗ0", &BAZ[0], 8, 16, 0, 1 }, /* Буферные адреса записи */ +{ "БАЗ1", &BAZ[1], 8, 16, 0, 1 }, +{ "БАЗ2", &BAZ[2], 8, 16, 0, 1 }, +{ "БАЗ3", &BAZ[3], 8, 16, 0, 1 }, +{ "БАЗ4", &BAZ[4], 8, 16, 0, 1 }, +{ "БАЗ5", &BAZ[5], 8, 16, 0, 1 }, +{ "БАЗ6", &BAZ[6], 8, 16, 0, 1 }, +{ "БАЗ7", &BAZ[7], 8, 16, 0, 1 }, +{ "ТАБСТ", &TABST, 8, 28, 0, 1, NULL, NULL, REG_HIDDEN },/* Таблица старшинства БРЗ */ +{ "ЗпТР", &FLUSH, 8, 4, 0, 1, NULL, NULL, REG_HIDDEN },/* Признак выталкивания БРЗ */ +{ "Старш", &OLDEST, 8, 3, 0, 1 }, /* Номер вытолкнутого БРЗ */ +{ "РП0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* Регистры приписки, по 12 бит */ +{ "РП1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РЗ", &RZ, 8, 32, 0, 1 }, /* Регистр защиты */ +{ "ТР1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Тумблерные регистры */ +{ "ТР2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРС0", &BRS[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры слов */ +{ "БРС1", &BRS[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРС2", &BRS[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРС3", &BRS[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БАС0", &BAS[0], 8, 16, 0, 1 }, /* Буферные адреса слов */ +{ "БАС1", &BAS[1], 8, 16, 0, 1 }, +{ "БАС2", &BAS[2], 8, 16, 0, 1 }, +{ "БАС3", &BAS[3], 8, 16, 0, 1 }, +{ "БРСст", &BRSLRU, 8, 6, 0, 1, NULL, NULL, REG_HIDDEN}, +{ 0 } +}; + +#define CACHE_ENB 1 + +MTAB mmu_mod[] = { + { 1, 0, "NOCACHE", "NOCACHE" }, + { 1, 1, "CACHE", "CACHE" }, + { 0 } +}; + +t_stat mmu_reset (DEVICE *dptr); + +t_stat mmu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + mmu_print_brz(); + return SCPE_NOFNC; +} + +DEVICE mmu_dev = { + "MMU", &mmu_unit, mmu_reg, mmu_mod, + 1, 8, 3, 1, 8, 50, + &mmu_examine, NULL, &mmu_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG +}; + +/* + * Reset routine + */ +t_stat mmu_reset (DEVICE *dptr) +{ + int i; + for (i = 0; i < 8; ++i) { + BRZ[i] = BAZ[i] = RP[i] = 0; + } + TABST = 0; + OLDEST = 0; + FLUSH = 0; + RZ = 0; + /* + * Front panel switches survive the reset + */ + sim_cancel (&mmu_unit); + return SCPE_OK; +} + +#define loses_to_all(i) ((TABST & win_mask[i]) == 0 && \ + (TABST & lose_mask[i]) == lose_mask[i]) + +/* + * N wins over M if the bit is set + * M=1 2 3 4 5 6 7 + * N ------------------------- + * 0| 0 1 2 3 4 5 6 + * 1| 7 8 9 10 11 12 + * 2| 13 14 15 16 17 + * 3| 18 19 20 21 + * 4| 22 23 24 + * 5| 25 26 + * 6| 27 + */ + +static unsigned win_mask[8] = { + 0177, + 0077 << 7, + 0037 << 13, + 0017 << 18, + 0007 << 22, + 0003 << 25, + 0001 << 27, + 0 +}; + +static unsigned lose_mask[8] = { + 0, + 1<<0, + 1<<1|1<<7, + 1<<2|1<<8|1<<13, + 1<<3|1<<9|1<<14|1<<18, + 1<<4|1<<10|1<<15|1<<19|1<<22, + 1<<5|1<<11|1<<16|1<<20|1<<23|1<<25, + 1<<6|1<<12|1<<17|1<<21|1<<24|1<<26|1<<27 +}; + +#define set_wins(i) TABST = (TABST & ~lose_mask[i]) | win_mask[i] + +void mmu_protection_check (int addr) +{ + /* Защита блокируется в режиме супервизора для физических (!) адресов 1-7 (ТО-8) - WTF? */ + int tmp_prot_disabled = (M[PSW] & PSW_PROT_DISABLE) || + (IS_SUPERVISOR (RUU) && (M[PSW] & PSW_MMAP_DISABLE) && addr < 010); + + /* Защита не заблокирована, а лист закрыт */ + if (! tmp_prot_disabled && (RZ & (1 << (addr >> 10)))) { + iintr_data = addr >> 10; + if (mmu_dev.dctrl) + besm6_debug ("--- (%05o) защита числа", addr); + longjmp (cpu_halt, STOP_OPERAND_PROT); + } +} + +void mmu_flush (int idx) +{ + if (! BAZ[idx]) { + /* Был пуст после сброса или выталкивания */ + return; + } + /* Вычисляем физический адрес выталкиваемого БРЗ */ + int waddr = BAZ[idx]; + waddr = (waddr > 0100000) ? (waddr - 0100000) : + (waddr & 01777) | (TLB[waddr >> 10] << 10); + memory[waddr] = BRZ[idx]; + BAZ[idx] = 0; + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) запись ", waddr); + fprint_sym (sim_log, 0, &BRZ[idx], 0, 0); + fprintf (sim_log, " из БРЗ[%d]\n", idx); + } +} + +void mmu_update_oldest () +{ + int i; + + for (i = 0; i < 8; ++i) { + if (loses_to_all(i)) { + OLDEST = i; + // fprintf(stderr, "Oldest = %d\r\n", i); + return; + } + } +} + +int mmu_match (int addr, int fail) +{ + int i; + + for (i = 0; i < 8; ++i) { + if (addr == BAZ[i]) { + return i; + } + } + return fail; +} + +/* + * Разнообразные алгоритмы выталкивания БРЗ путем записи + * по адресам пультовых регистров. Тест УУ проходит дальше всего + * с mmu_flush_by_age(). + */ +void mmu_flush_by_age() +{ + switch (FLUSH) { + case 0: + break; + case 1 ... 8: + set_wins (OLDEST); + mmu_update_oldest (); + mmu_flush (OLDEST); + if (FLUSH == 7) { + TABST = 0; + OLDEST = 0; + } + break; + } + ++FLUSH; +} + +void mmu_flush_by_number() +{ + switch (FLUSH) { + case 0: + break; + case 1 ... 8: + mmu_flush (FLUSH-1); + set_wins (FLUSH-1); + if (FLUSH-1 == OLDEST) + mmu_update_oldest (); + if (FLUSH == 7) { + TABST = 0; + OLDEST = 0; + } + break; + } + ++FLUSH; +} + +/* + * Запись слова в память + */ +void mmu_store (int addr, t_value val) +{ + int matching; + + addr &= BITS(15); + if (addr == 0) + return; + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) запись ", addr); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, "\n"); + } + + mmu_protection_check (addr); + + /* Различаем адреса с припиской и без */ + if (M[PSW] & PSW_MMAP_DISABLE) + addr |= 0100000; + + /* ЗПСЧ: ЗП */ + if (M[DWP] == addr && (M[PSW] & PSW_WRITE_WATCH)) + longjmp(cpu_halt, STOP_STORE_ADDR_MATCH); + + if (sim_brk_summ & SWMASK('W') && + sim_brk_test (addr, SWMASK('W'))) + longjmp(cpu_halt, STOP_WWATCH); + + if (!(mmu_unit.flags & CACHE_ENB)) { + static int roundrobin; + int faked = (++roundrobin ^ addr ^ val) & 7; + + if (addr > 0100000 && addr < 0100010) + return; + + BRZ[faked] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BAZ[faked] = addr; + mmu_flush (faked); + return; + } + + /* Запись в тумблерные регистры - выталкивание БРЗ */ + if (addr > 0100000 && addr < 0100010) { + mmu_flush_by_age(); + return; + } else + FLUSH = 0; + + matching = mmu_match(addr, OLDEST); + + BRZ[matching] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BAZ[matching] = addr; + set_wins (matching); + + if (matching == OLDEST) { + mmu_update_oldest (); + mmu_flush (OLDEST); + } +} + +t_value mmu_memaccess (int addr) +{ + t_value val; + + /* Вычисляем физический адрес слова */ + addr = (addr > 0100000) ? (addr - 0100000) : + (addr & 01777) | (TLB[addr >> 10] << 10); + if (addr >= 010) { + /* Из памяти */ + val = memory[addr]; + } else { + /* С тумблерных регистров */ + if (mmu_dev.dctrl) + besm6_debug("--- (%05o) чтение ТР%o", PC, addr); + val = pult[addr]; + } + if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { + fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, "\n"); + } + + /* На тумблерных регистрах контроля числа не бывает */ + if (addr >= 010 && ! IS_NUMBER (val)) { + iintr_data = addr & 7; + besm6_debug ("--- (%05o) контроль числа", addr); + longjmp (cpu_halt, STOP_RAM_CHECK); + } + return val; +} + +/* + * Чтение операнда + */ +t_value mmu_load (int addr) +{ + int matching = -1; + t_value val; + + addr &= BITS(15); + if (addr == 0) + return 0; + + mmu_protection_check (addr); + + /* Различаем адреса с припиской и без */ + if (M[PSW] & PSW_MMAP_DISABLE) + addr |= 0100000; + + /* ЗПСЧ: СЧ */ + if (M[DWP] == addr && !(M[PSW] & PSW_WRITE_WATCH)) + longjmp(cpu_halt, STOP_LOAD_ADDR_MATCH); + + if (sim_brk_summ & SWMASK('R') && + sim_brk_test (addr, SWMASK('R'))) + longjmp(cpu_halt, STOP_RWATCH); + + if (!(mmu_unit.flags & CACHE_ENB)) { + return mmu_memaccess (addr) & BITS48; + } + + matching = mmu_match(addr, -1); + + if (matching == -1) { + val = mmu_memaccess (addr); + } else { + /* старшинство обновляется, только если оно не затрагивает + * старший БРЗ (ТО-2). + */ + if (matching != OLDEST) + set_wins (matching); + val = BRZ[matching]; + if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { + fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, " из БРЗ\n"); + } + if (! IS_NUMBER (val)) { + iintr_data = matching; + besm6_debug ("--- (%05o) контроль числа БРЗ", addr); + longjmp (cpu_halt, STOP_CACHE_CHECK); + } + } + return val & BITS48; +} + +/* A little BRS LRU table */ +#define brs_loses_to_all(i) ((BRSLRU & brs_win_mask[i]) == 0 && \ + (BRSLRU & brs_lose_mask[i]) == brs_lose_mask[i]) + +/* + * N wins over M if the bit is set + * M=1 2 3 + * N --------- + * 0| 0 1 2 + * 1| 3 4 + * 2| 5 + */ + +static unsigned brs_win_mask[4] = { + 07, + 03 << 3, + 01 << 5, + 0 +}; + +static unsigned brs_lose_mask[8] = { + 0, + 1<<0, + 1<<1|1<<3, + 1<<2|1<<4|1<<5 +}; + +#define brs_set_wins(i) BRSLRU = (BRSLRU & ~brs_lose_mask[i]) | brs_win_mask[i] + +void mmu_fetch_check (int addr) +{ + /* В режиме супервизора защиты нет */ + if (! IS_SUPERVISOR(RUU)) { + int page = TLB[addr >> 10]; + /* + * Для команд в режиме пользователя признак защиты - + * 0 в регистре приписки. + */ + if (page == 0) { + iintr_data = addr >> 10; + if (mmu_dev.dctrl) + besm6_debug ("--- (%05o) защита команды", addr); + longjmp (cpu_halt, STOP_INSN_PROT); + } + } +} + +/* + * Предвыборка команды на БРС + */ +t_value mmu_prefetch (int addr, int actual) +{ + t_value val; + int i; + + if (mmu_unit.flags & CACHE_ENB) { + for (i = 0; i < 4; ++i) { + if (BAS[i] == addr) { + if (actual) { + brs_set_wins (i); + } + return BRS[i]; + } + } + + for (i = 0; i < 4; ++i) { + if (brs_loses_to_all (i)) { + BAS[i] = addr; + if (actual) { + brs_set_wins (i); + } + break; + } + } + } else if (!actual) { + return 0; + } else { + /* Чтобы лампочки мигали */ + i = addr & 3; + } + + if (addr < 0100000) { + int page = TLB[addr >> 10]; + + /* Вычисляем физический адрес слова */ + addr = (addr & 01777) | (page << 10); + } else { + addr = addr & BITS(15); + } + + if (addr < 010) + val = pult[addr]; + else + val = memory[addr]; + BRS[i] = val; + return val; +} + +/* + * Выборка команды + */ +t_value mmu_fetch (int addr) +{ + t_value val; + + if (addr == 0) { + if (mmu_dev.dctrl) + besm6_debug ("--- передача управления на 0"); + longjmp (cpu_halt, STOP_INSN_CHECK); + } + + mmu_fetch_check(addr); + + /* Различаем адреса с припиской и без */ + if (IS_SUPERVISOR (RUU)) + addr |= 0100000; + + /* КРА */ + if (M[IBP] == addr) + longjmp(cpu_halt, STOP_INSN_ADDR_MATCH); + + val = mmu_prefetch(addr, 1); + + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) выборка ", addr); + fprint_sym (sim_log, 0, &val, 0, SWMASK ('I')); + fprintf (sim_log, "\n"); + } + + /* Тумблерные регистры пока только с командной сверткой */ + if (addr >= 010 && ! IS_INSN (val)) { + besm6_debug ("--- (%05o) контроль команды", addr); + longjmp (cpu_halt, STOP_INSN_CHECK); + } + return val & BITS48; +} + +void mmu_setrp (int idx, t_value val) +{ + uint32 p0, p1, p2, p3; + const uint32 mask = (MEMSIZE >> 10) - 1; + + /* Младшие 5 разрядов 4-х регистров приписки упакованы + * по 5 в 1-20 рр, 6-е разряды - в 29-32 рр, 7-е разряды - в 33-36 рр и т.п. + */ + p0 = (val & 037) | (((val>>28) & 1) << 5) | (((val>>32) & 1) << 6) | + (((val>>36) & 1) << 7) | (((val>>40) & 1) << 8) | (((val>>44) & 1) << 9); + p1 = ((val>>5) & 037) | (((val>>29) & 1) << 5) | (((val>>33) & 1) << 6) | + (((val>>37) & 1) << 7) | (((val>>41) & 1) << 8) | (((val>>45) & 1) << 9); + p2 = ((val>>10) & 037) | (((val>>30) & 1) << 5) | (((val>>34) & 1) << 6) | + (((val>>38) & 1) << 7) | (((val>>42) & 1) << 8) | (((val>>46) & 1) << 9); + p3 = ((val>>15) & 037) | (((val>>31) & 1) << 5) | (((val>>35) & 1) << 6) | + (((val>>39) & 1) << 7) | (((val>>43) & 1) << 8) | (((val>>47) & 1) << 9); + + p0 &= mask; + p1 &= mask; + p2 &= mask; + p3 &= mask; + + RP[idx] = p0 | p1 << 12 | p2 << 24 | (t_value) p3 << 36; + TLB[idx*4] = p0; + TLB[idx*4+1] = p1; + TLB[idx*4+2] = p2; + TLB[idx*4+3] = p3; +} + +void mmu_setup () +{ + const uint32 mask = (MEMSIZE >> 10) - 1; + int i; + + /* Перепись РПi в TLBj. */ + for (i=0; i<8; ++i) { + TLB[i*4] = RP[i] & mask; + TLB[i*4+1] = RP[i] >> 12 & mask; + TLB[i*4+2] = RP[i] >> 24 & mask; + TLB[i*4+3] = RP[i] >> 36 & mask; + } +} + +void mmu_setprotection (int idx, t_value val) +{ + /* Разряды сумматора, записываемые в регистр защиты - 21-28 */ + int mask = 0xff << (idx * 8); + val = ((val >> 20) & 0xff) << (idx * 8); + RZ = (RZ & ~mask) | val; +} + +void mmu_setcache (int idx, t_value val) +{ + BRZ[idx] = SET_CONVOL (val, RUU ^ CONVOL_INSN); +} + +t_value mmu_getcache (int idx) +{ + return BRZ[idx] & BITS48; +} + +void mmu_print_brz () +{ + int i, k; + + for (i=7; i>=0; --i) { + besm6_log_cont ("БРЗ [%d] = '", i); + for (k=47; k>=0; --k) + besm6_log_cont ("%c", (BRZ[i] >> k & 1) ? '*' : ' '); + besm6_log ("'"); + } +} diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c new file mode 100644 index 00000000..6ed387e8 --- /dev/null +++ b/BESM6/besm6_panel.c @@ -0,0 +1,594 @@ +/* + * Panel of BESM-6, displayed as a graphics window. + * Using libSDL for graphics and libSDL_ttf for fonts. + * + * Copyright (c) 2009, Serge Vakulenko + * Copyright (c) 2014, 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. + */ +#ifdef HAVE_LIBSDL + +#include "besm6_defs.h" +#include +#include + +/* + * Use a 640x480 window with 32 bit pixels. + */ +#define WIDTH 800 +#define HEIGHT 400 +#define DEPTH 32 + +#define STEPX 14 +#define STEPY 16 + +#define FONTNAME "LucidaSansRegular.ttf" +#define FONTPATH1 "/usr/share/fonts" +#define FONTPATH2 "/usr/lib/jvm" +#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions" + +#include +#include + +/* Data and functions that don't depend on SDL version */ +static char *font_path; +static TTF_Font *font_big; +static TTF_Font *font_small; +static SDL_Color foreground; +static SDL_Color background; +static const SDL_Color white = { 255, 255, 255 }; +static const SDL_Color black = { 0, 0, 0 }; +static const SDL_Color cyan = { 0, 128, 128 }; +static const SDL_Color grey = { 64, 64, 64 }; +static t_value old_BRZ [8], old_GRP [2]; +static t_value old_M [NREGS]; + +static const int regnum[] = { + 013, 012, 011, 010, 7, 6, 5, 4, + 027, 016, 015, 014, 3, 2, 1, 020, +}; + +static SDL_Surface *screen; + +/* + * Рисование текста в кодировке UTF-8, с антиалиасингом. + * Параметр halign задаёт выравнивание по горизонтали. + * Цвета заданы глобальными переменными foreground и background. + */ +static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message) +{ + SDL_Surface *text; + SDL_Rect area; + + /* Build image from text */ + text = TTF_RenderUTF8_Shaded (font, message, foreground, background); + + area.x = x; + if (halign < 0) + area.x -= text->w; /* align left */ + else if (halign == 0) + area.x -= text->w / 2; /* center */ + area.y = y; + area.w = text->w; + area.h = text->h; + + /* Put text image to screen */ + SDL_BlitSurface (text, 0, screen, &area); + SDL_FreeSurface (text); +} + +static SDL_Surface *sprite_from_data (int width, int height, + const unsigned char *data) +{ + SDL_Surface *sprite, *optimized; + unsigned *s, r, g, b, y, x; + + sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, + width, height, DEPTH, 0, 0, 0, 0); + /* + optimized = SDL_DisplayFormat (sprite); + SDL_FreeSurface (sprite); + sprite = optimized; + */ + SDL_LockSurface (sprite); + for (y=0; ypixels + y * sprite->pitch); + for (x=0; xformat, r, g, b); + } + } + SDL_UnlockSurface (sprite); + return sprite; +} + +/* + * Рисуем неонку. + */ +static void draw_lamp (int left, int top, int on) +{ + /* Images created by GIMP: save as C file without alpha channel. */ + static const int lamp_width = 12; + static const int lamp_height = 12; + static const unsigned char lamp_on [12 * 12 * 3 + 1] = + "\0\0\0\0\0\0\0\0\0\13\2\2-\14\14e\31\31e\31\31-\14\14\13\2\2\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0D\20\20\313,,\377??\377CC\377CC\377DD\31333D\21\21\0\0" + "\0\0\0\0\0\0\0D\20\20\357LL\377\243\243\376~~\37699\376@@\376@@\377AA\357" + "<>\377@@\377@@\377AA\31333\13\2\2-\14\14\377??\376~~\377\356\356\377\321" + "\321\377<<\377??\377@@\377@@\376@@\377DD-\14\14e\31\31\377CC\37699\377NN" + "\377<<\377??\377@@\377@@\377@@\376??\377CCe\31\31e\31\31\377CC\376@@\377" + ">>\377??\377@@\377@@\377@@\377@@\376??\377CCe\31\31-\14\14\377DD\376@@\377" + "@@\377@@\377@@\377@@\377@@\377@@\376@@\377DD-\14\14\13\2\2\31333\377AA\377" + "@@\377@@\377@@\377@@\377@@\377@@\377AA\31333\13\2\2\0\0\0D\21\21\357<<\377" + "AA\376@@\376??\376??\376@@\377AA\357<> (14-x) & 1); + } + } +} + +/* + * Отрисовка лампочек ГРП и МГРП. + */ +static void draw_grp_periodic (int top) +{ + int x, y; + t_value val; + + for (y=0; y<2; ++y) { + val = y ? MGRP : GRP; + if (val == old_GRP [y]) + continue; + old_GRP [y] = val; + for (x=0; x<48; ++x) { + draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); + } + } +} + +/* + * Отрисовка лампочек БРЗ. + */ +static void draw_brz_periodic (int top) +{ + int x, y; + t_value val; + + for (y=0; y<8; ++y) { + val = BRZ [7-y]; + if (val == old_BRZ [7-y]) + continue; + old_BRZ [7-y] = val; + for (x=0; x<48; ++x) { + draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); + } + } +} + +/* + * Отрисовка статичной части регистров-модификаторов. + */ +static void draw_modifiers_static (int group, int left, int top) +{ + int x, y, color, reg; + char message [40]; + SDL_Rect area; + + background = black; + foreground = cyan; + + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<15; x+=3) { + area.x = left + 74 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 8*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=0; y<8; ++y) { + reg = regnum [y + group*8]; + sprintf (message, "М%2o", reg); + render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message); + old_M [reg] = ~0; + } + /* Номера битов. */ + for (x=0; x<15; ++x) { + sprintf (message, "%d", 15-x); + render_utf8 (font_small, left+82 + x*STEPX, + (x & 1) ? top+4 : top+10, 0, message); + } +} + +/* + * Отрисовка статичной части регистров ГРП и МГРП. + */ +static void draw_grp_static (int top) +{ + int x, y, color; + char message [40]; + SDL_Rect area; + + background = black; + foreground = cyan; + + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<48; x+=3) { + area.x = 98 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 2*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=0; y<2; ++y) { + render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП"); + old_GRP[y] = ~0; + } + /* Номера битов. */ + for (x=0; x<48; ++x) { + sprintf (message, "%d", 48-x); + render_utf8 (font_small, 106 + x*STEPX, + (x & 1) ? top+10 : top+4, 0, message); + } +} + +/* + * Отрисовка статичной части регистров БРЗ. + */ +static void draw_brz_static (int top) +{ + int x, y, color; + char message [40]; + SDL_Rect area; + + background = black; + foreground = cyan; + + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<48; x+=3) { + area.x = 98 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 8*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=7; y>=0; --y) { + sprintf (message, "БРЗ %d", 7-y); + render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message); + old_BRZ[y] = ~0; + } +} + +/* + * Поиск файла шрифта по имени. + */ +static int probe_font (const char *path, const struct stat *st, int flag) +{ + const char *p; + + if (flag != FTW_F) + return 0; + p = path + strlen (path) - strlen (FONTNAME); + if (p < path || strcmp (p, FONTNAME) != 0) + return 0; + font_path = strdup (path); + return 1; +} + +/* + * Закрываем графическое окно. + */ +void besm6_close_panel () +{ + if (! screen) + return; + TTF_Quit(); + SDL_Quit(); + screen = 0; +} + +#if SDL_MAJOR_VERSION == 2 + +static SDL_Window *sdlWindow; +static SDL_Renderer *sdlRenderer; +static SDL_Texture *sdlTexture; + + +/* + * Начальная инициализация графического окна и шрифтов. + */ +static void init_panel () +{ + if (sim_switches & SWMASK('Q')) + return; + + /* Initialize SDL subsystems - in this case, only video. */ + if (SDL_Init (SDL_INIT_VIDEO) < 0) { + fprintf (stderr, "SDL: unable to init: %s\n", + SDL_GetError ()); + exit (1); + } + sdlWindow = SDL_CreateWindow ("BESM-6 panel", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + WIDTH, HEIGHT, 0 /* regular window */); + if (! sdlWindow) { + fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", + WIDTH, HEIGHT, DEPTH, SDL_GetError ()); + exit (1); + } + + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); + /* Make black background */ + SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); + SDL_RenderClear(sdlRenderer); + + /* Initialize the TTF library */ + if (TTF_Init() < 0) { + fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", + SDL_GetError()); + SDL_Quit(); + exit (1); + } + + /* Find font file */ + if (ftw (FONTPATH1, probe_font, 255) <= 0 && + ftw (FONTPATH2, probe_font, 255) <= 0 && + ftw (FONTPATH3, probe_font, 255) <= 0) { + fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", + FONTNAME, FONTPATH1); + besm6_close_panel(); + exit (1); + } + + /* Open the font file with the requested point size */ + font_big = TTF_OpenFont (font_path, 16); + font_small = TTF_OpenFont (font_path, 9); + if (! font_big || ! font_small) { + fprintf(stderr, "SDL: couldn't load font %s: %s\n", + font_path, SDL_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); + + screen = SDL_CreateRGBSurface(0, WIDTH, HEIGHT, 32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + + sdlTexture = SDL_CreateTexture(sdlRenderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, + WIDTH, HEIGHT); + + /* Отрисовка статичной части панели БЭСМ-6. */ + draw_modifiers_static (0, 24, 10); + draw_modifiers_static (1, 400, 10); + draw_grp_static (180); + draw_brz_static (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent (sdlRenderer); +} + +void (*sim_vm_init)() = init_panel; + +/* + * Обновляем графическое окно. + */ +void besm6_draw_panel () +{ + if (! screen) + return; + + /* Периодическая отрисовка: мигание лампочек. */ + draw_modifiers_periodic (0, 24, 10); + draw_modifiers_periodic (1, 400, 10); + draw_grp_periodic (180); + draw_brz_periodic (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent (sdlRenderer); + + /* Exit SIMH when window closed.*/ + SDL_Event event; + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); +} + +#else + +/* + * Начальная инициализация графического окна и шрифтов. + */ +static void init_panel () +{ + if (sim_switches & SWMASK('Q')) + return; + + /* Initialize SDL subsystems - in this case, only video. */ + if (SDL_Init (SDL_INIT_VIDEO) < 0) { + fprintf (stderr, "SDL: unable to init: %s\n", + SDL_GetError ()); + exit (1); + } + screen = SDL_SetVideoMode (WIDTH, HEIGHT, DEPTH, SDL_SWSURFACE); + if (! screen) { + fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", + WIDTH, HEIGHT, DEPTH, SDL_GetError ()); + exit (1); + } + + /* Initialize the TTF library */ + if (TTF_Init() < 0) { + fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", + SDL_GetError()); + SDL_Quit(); + exit (1); + } + + /* Find font file */ + if (ftw (FONTPATH1, probe_font, 255) <= 0 && + ftw (FONTPATH2, probe_font, 255) <= 0 && + ftw (FONTPATH3, probe_font, 255) <= 0) { + fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", + FONTNAME, FONTPATH1); + besm6_close_panel(); + exit (1); + } + + /* Open the font file with the requested point size */ + font_big = TTF_OpenFont (font_path, 16); + font_small = TTF_OpenFont (font_path, 9); + if (! font_big || ! font_small) { + fprintf(stderr, "SDL: couldn't load font %s: %s\n", + FONTNAME, TTF_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); + + /* Отрисовка статичной части панели БЭСМ-6. */ + draw_modifiers_static (0, 24, 10); + draw_modifiers_static (1, 400, 10); + draw_grp_static (180); + draw_brz_static (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); +} + +void (*sim_vm_init)() = init_panel; + +/* + * Обновляем графическое окно. + */ +void besm6_draw_panel () +{ + if (! screen) + return; + + /* Периодическая отрисовка: мигание лампочек. */ + draw_modifiers_periodic (0, 24, 10); + draw_modifiers_periodic (1, 400, 10); + draw_grp_periodic (180); + draw_brz_periodic (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); + + /* Exit SIMH when window closed.*/ + SDL_Event event; + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); +} + +#if !defined(__WIN32__) && \ + !(defined(__MWERKS__) && !defined(__BEOS__)) && \ + !defined(__MACOS__) && !defined(__MACOSX__) && \ + !defined(__SYMBIAN32__) && !defined(QWS) +#undef main + +/* + * Вот так всё непросто. + */ +int main (int argc, char *argv[]) +{ + extern int SDL_main (int, char**); + + return SDL_main (argc, argv); +} +#endif +#endif /* SDL_MAJOR_VERSION */ + +#else /* HAVE_LIBSDL */ +void besm6_draw_panel () +{ +} +#endif /* HAVE_LIBSDL */ diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c new file mode 100644 index 00000000..9618f76e --- /dev/null +++ b/BESM6/besm6_printer.c @@ -0,0 +1,345 @@ +/* + * besm6_printer.c: BESM-6 line printer device + * + * 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 printer_event (UNIT *u); +void offset_gost_write (int num, FILE *fout); + +/* + * Printer data structures + * + * printer_dev PRINTER device descriptor + * printer_unit PRINTER unit descriptor + * printer_reg PRINTER register list + */ +UNIT printer_unit [] = { + { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, + { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, +}; + + +#define MAX_STRIKES 10 +struct acpu_t { + int curchar, feed, rampup; + int strikes; + int length; + unsigned char line[128][MAX_STRIKES]; +} acpu[2]; + +int acpu_isatty[2]; + +#define PRN1_NOT_READY (1<<19) +#define PRN2_NOT_READY (1<<18) + +/* 1 = можно пользоваться молоточками, 0 - бумага в процессе протяжки */ +#define PRN1_LINEFEED (1<<23) +#define PRN2_LINEFEED (1<<22) + +#define SLOW_START 100*MSEC +#define FAST_START 1*MSEC +#define LINEFEED_SYNC 1 /* Чтобы быстрее печатало; в жизни 20-25 мс/1.4 мс ~= 17 */ + +REG printer_reg[] = { +{ "Готов", &READY, 2, 2, 18, 1 }, +{ "Прогон", &READY, 2, 2, 22, 1 }, +{ 0 } +}; + +MTAB printer_mod[] = { + { 0 } +}; + +t_stat printer_reset (DEVICE *dptr); +t_stat printer_attach (UNIT *uptr, char *cptr); +t_stat printer_detach (UNIT *uptr); + +DEVICE printer_dev = { + "PRN", printer_unit, printer_reg, printer_mod, + 2, 8, 19, 1, 8, 50, + NULL, NULL, &printer_reset, NULL, &printer_attach, &printer_detach, + NULL, DEV_DISABLE | DEV_DEBUG +}; + +/* + * Reset routine + */ +t_stat printer_reset (DEVICE *dptr) +{ + memset(acpu, 0, sizeof (acpu)); + acpu[0].rampup = acpu[1].rampup = SLOW_START; + sim_cancel (&printer_unit[0]); + sim_cancel (&printer_unit[1]); + READY |= PRN1_NOT_READY | PRN2_NOT_READY; + if (printer_unit[0].flags & UNIT_ATT) + READY &= ~PRN1_NOT_READY; + if (printer_unit[1].flags & UNIT_ATT) + READY &= ~PRN2_NOT_READY; + return SCPE_OK; +} + +t_stat printer_attach (UNIT *u, char *cptr) +{ + t_stat s; + int num = u - printer_unit; + + if (u->flags & UNIT_ATT) { + /* Switching files cleanly */ + detach_unit (u); + } + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + + acpu_isatty[num] = !strcmp(cptr, "/dev/tty"); + if (!acpu_isatty[num]) { + /* Write UTF-8 tag: zero width no-break space. */ + fputs ("\xEF\xBB\xBF", u->fileref); + } + + READY &= ~(PRN1_NOT_READY >> num); + return SCPE_OK; +} + +t_stat printer_detach (UNIT *u) +{ + int num = u - printer_unit; + READY |= PRN1_NOT_READY >> num; + return detach_unit (u); +} + +/* + * Управление двигателями, прогон + */ +void printer_control (int num, uint32 cmd) +{ + UNIT *u = &printer_unit[num]; + struct acpu_t * dev = acpu + num; + + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d команда %o", num, cmd); + if (READY & (PRN1_NOT_READY >> num)) { + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d не готово", num, cmd); + return; + } + switch (cmd) { + case 1: /* linefeed */ + READY &= ~(PRN1_LINEFEED >> num); + offset_gost_write (num, u->fileref); + dev->feed = LINEFEED_SYNC; + break; + case 4: /* start */ + /* стартуем из состояния прогона для надежности */ + dev->feed = LINEFEED_SYNC; + READY &= ~(PRN1_LINEFEED >> num); + if (dev->rampup) + sim_activate (u, dev->rampup); + dev->rampup = 0; + break; + case 10: /* motor and ribbon off */ + case 8: /* motor off? (undocumented) */ + case 2: /* ribbon off */ + dev->rampup = cmd == 2 ? FAST_START : SLOW_START; + sim_cancel (u); + break; + } +} + +/* + * Управление молоточками + */ +void printer_hammer (int num, int pos, uint32 mask) +{ + struct acpu_t * dev = acpu + num; + while (mask) { + if (mask & 1) { + int strike = 0; + while (dev->line[pos][strike] && strike < MAX_STRIKES) + ++strike; + if (strike < MAX_STRIKES) { + dev->line[pos][strike] = dev->curchar; + if (pos + 1 > dev->length) + dev->length = pos + 1; + if (strike + 1 > dev->strikes) + dev->strikes = strike + 1; + } + } + mask >>= 1; + pos += 8; + } +} + +/* + * Событие: вращение барабана АЦПУ. + * Устанавливаем флаг прерывания. + */ +t_stat printer_event (UNIT *u) +{ + int num = u - printer_unit; + struct acpu_t * dev = acpu + num; + + switch (dev->curchar) { + case 0 ... 0137: + GRP |= GRP_PRN1_SYNC >> num; + ++dev->curchar; + /* For next char */ + sim_activate (u, 1400*USEC); + if (dev->feed && --dev->feed == 0) { + READY |= PRN1_LINEFEED >> num; + } + break; + case 0140: + /* For "zero" */ + dev->curchar = 0; + GRP |= GRP_PRN1_ZERO >> num; + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d 'ноль'", num); + /* For first sync after "zero" */ + sim_activate (u, 1000*USEC); + break; + } + return SCPE_OK; +} + +int gost_latin = 0; /* default cyrillics */ + +/* + * GOST-10859 encoding. + * Documentation: http://en.wikipedia.org/wiki/GOST_10859 + */ +static const unsigned short gost_to_unicode_cyr [256] = { +/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, +/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, +/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, +/* 040-047 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, +/* 050-057 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, +/* 060-067 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, +/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, +/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, +/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, +/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, +/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, +}; + +static const unsigned short gost_to_unicode_lat [256] = { +/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, +/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, +/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, +/* 040-047 */ 0x41, 0x0411, 0x42, 0x0413, 0x0414, 0x45, 0x0416, 0x0417, +/* 050-057 */ 0x0418, 0x0419, 0x4b, 0x041b, 0x4d, 0x48, 0x4f, 0x041f, +/* 060-067 */ 0x50, 0x43, 0x54, 0x59, 0x0424, 0x58, 0x0426, 0x0427, +/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, +/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, +/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, +/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, +/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, +}; +/* + * Write Unicode symbol to file. + * Convert to UTF-8 encoding: + * 00000000.0xxxxxxx -> 0xxxxxxx + * 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy + * xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz + */ +static void +utf8_putc (unsigned short ch, FILE *fout) +{ + if (ch < 0x80) { + putc (ch, fout); + return; + } + if (ch < 0x800) { + putc (ch >> 6 | 0xc0, fout); + putc ((ch & 0x3f) | 0x80, fout); + return; + } + putc (ch >> 12 | 0xe0, fout); + putc (((ch >> 6) & 0x3f) | 0x80, fout); + putc ((ch & 0x3f) | 0x80, fout); +} + +unsigned short +gost_to_unicode (unsigned char ch) +{ + return gost_latin ? gost_to_unicode_lat [ch] : + gost_to_unicode_cyr [ch]; +} + +/* + * Write GOST-10859 symbol to file. + * Convert to local encoding (UTF-8, KOI8-R, CP-1251, CP-866). + */ +void +gost_putc (unsigned char ch, FILE *fout) +{ + unsigned short u; + + u = gost_to_unicode (ch); + if (! u) + u = ' '; + utf8_putc (u, fout); +} + +/* + * Write GOST-10859 string with overprint to file in UTF-8. + */ +void +offset_gost_write (int num, FILE *fout) +{ + struct acpu_t * dev = acpu + num; + int s, p; + for (s = 0; s < dev->strikes; ++s) { + if (s) + fputc ('\r', fout); + for (p = 0; p < dev->length; ++p) { + gost_putc (dev->line[p][s] - 1, fout); + } + } + + if (acpu_isatty[num]) + fputc('\r', fout); + + fputc ('\n', fout); + memset(dev->line, 0, sizeof (dev->line)); + dev->length = dev->strikes = 0; +} + +/* + * Выясняем, остановлены ли АЦПУ. Нужно для входа в "спящий" режим. + */ +int printer_is_idle () +{ + if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0) + return 0; + if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0) + return 0; + return 1; +} diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c new file mode 100644 index 00000000..d9d974f1 --- /dev/null +++ b/BESM6/besm6_punch.c @@ -0,0 +1,472 @@ +/* + * besm6_punch.c: BESM-6 punchcard/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" +#include +#include + +t_stat fs_event (UNIT *u); +t_stat uvvk_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[] = { +{ "Готов", &READY, 2, 2, 14, 1 }, +{ "ФС1500-1", &FS[0], 8, 8, 0, 1 }, +{ "ФС1500-2", &FS[2], 8, 8, 0, 1 }, +{ 0 } +}; + +MTAB fs_mod[] = { + { 0 } +}; + +t_stat fs_reset (DEVICE *dptr); +t_stat fs_attach (UNIT *uptr, 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_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]; + +/* + * 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; +} + +t_stat fs_attach (UNIT *u, char *cptr) +{ + t_stat s; + int num = u - fs_unit; + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + struct stat stbuf; + fstat (fileno(u->fileref), &stbuf); + isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0; + if (isfifo[num]) { + int flags = fcntl(fileno(u->fileref), F_GETFL, 0); + fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK); + } + 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); +static int utf8_getc (FILE *fin); + +/* + * Событие: читаем очередной символ с перфоленты в регистр. + * Устанавливаем флаг прерывания. + */ +t_stat fs_event (UNIT *u) +{ + int num = u - fs_unit; +again: + switch (fs_state[num]) { + case FS_STARTING: + /* По первому прерыванию после запуска двигателя ничего не читаем */ + FS[num] = 0; + fs_state[num] = FS_RUNNING; + break; + case FS_RUNNING: { + int ch; + /* переводы строк игнорируются */ + while ((ch = utf8_getc (u->fileref)) == '\n'); + if (ch < 0) { + /* хвост ленты без пробивок */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else if (ch == '\f') { + fs_state[num] = FS_IMAGE; + goto again; + } else { + ch = FS[num] = unicode_to_gost (ch); + ch = (ch & 0x55) + ((ch >> 1) & 0x55); + ch = (ch & 0x33) + ((ch >> 2) & 0x33); + ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); + if (ch & 1); else FS[num] |= 0x80; + } + break; + } + case FS_IMAGE ... FS_IMAGE_LAST: { + int ch = utf8_getc (u->fileref); + if (ch < 0) { + /* обрыв ленты */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else if (ch == '\n') { + /* идем дополнять образ карты нулевыми байтами */ + fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE); + goto again; + } else if (ch == '\f') { + if (fs_state[num] != FS_IMAGE) + besm6_debug("<<< ENDA3 requested mid-card?"); + fs_state[num] = FS_ENDA3; + goto again; + } else { + ch = FS[num] = unicode_to_gost (ch); + ch = (ch & 0x55) + ((ch >> 1) & 0x55); + ch = (ch & 0x33) + ((ch >> 2) & 0x33); + ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); + if (ch & 1); else FS[num] |= 0x80; + ++fs_state[num]; + } + break; + } + case FS_TOOLONG: { + /* дочитываем до конца строки */ + int ch; + besm6_debug("<<< too long???"); + while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0); + if (ch < 0) { + /* хвост ленты без пробивок */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else + goto again; + break; + } + case FS_FILLUP ... FS_FILLUP_LAST: + FS[num] = 0; + if (++fs_state[num] == FS_ENDA3) { + fs_state[num] = FS_IMAGE; + } + break; + case FS_ENDA3 ... 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; + } + break; + case FS_IDLE: + case FS_TAIL: + FS[num] = 0; + break; + } + 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]; +} + +int fs_is_idle (void) +{ + return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE; +} + +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, 0174, 017, 017, +/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017, +/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 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 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); +} diff --git a/BESM6/besm6_sys.c b/BESM6/besm6_sys.c new file mode 100644 index 00000000..5d6e6927 --- /dev/null +++ b/BESM6/besm6_sys.c @@ -0,0 +1,719 @@ +/* + * besm6_sys.c: BESM-6 simulator interface + * + * Copyright (c) 2009, Serge Vakulenko + * Copyright (c) 2009, Leonid Broukhis + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your discretion) any later version. + * See the accompanying file "COPYING" for more details. + * + * This file implements three essential functions: + * + * sim_load() - loading and dumping memory and CPU state + * in a way, specific for BESM-6 architecture + * fprint_sym() - print a machune instruction using + * opcode mnemonic or in a digital format + * parse_sym() - scan a string and build an instruction + * word from it + */ +#include "besm6_defs.h" +#include +#include + +const char *opname_short_bemsh [64] = { + "зп", "зпм", "рег", "счм", "сл", "вч", "вчоб", "вчаб", + "сч", "и", "нтж", "слц", "знак", "или", "дел", "умн", + "сбр", "рзб", "чед", "нед", "слп", "вчп", "сд", "рж", + "счрж", "счмр", "э32", "увв", "слпа", "вчпа", "сда", "ржа", + "уи", "уим", "счи", "счим", "уии", "сли", "э46", "э47", + "э50", "э51", "э52", "э53", "э54", "э55", "э56", "э57", + "э60", "э61", "э62", "э63", "э64", "э65", "э66", "э67", + "э70", "э71", "э72", "э73", "э74", "э75", "э76", "э77", +}; + +static const char *opname_long_bemsh [16] = { + "э20", "э21", "мода", "мод", "уиа", "слиа", "по", "пе", + "пб", "пв", "выпр", "стоп", "пио", "пино", "э36", "цикл", +}; + +const char *opname_short_madlen [64] = { + "atx", "stx", "mod", "xts", "a+x", "a-x", "x-a", "amx", + "xta", "aax", "aex", "arx", "avx", "aox", "a/x", "a*x", + "apx", "aux", "acx", "anx", "e+x", "e-x", "asx", "xtr", + "rte", "yta", "*32", "ext", "e+n", "e-n", "asn", "ntr", + "ati", "sti", "ita", "its", "mtj", "j+m", "*46", "*47", + "*50", "*51", "*52", "*53", "*54", "*55", "*56", "*57", + "*60", "*61", "*62", "*63", "*64", "*65", "*66", "*67", + "*70", "*71", "*72", "*73", "*74", "*75", "*76", "*77", +}; + +static const char *opname_long_madlen [16] = { + "*20", "*21", "utc", "wtc", "vtm", "utm", "uza", "u1a", + "uj", "vjm", "ij", "stop", "vzm", "v1m", "*36", "vlm", +}; + +/* + * Выдача мнемоники по коду инструкции. + * Код должен быть в диапазоне 000..077 или 0200..0370. + */ +const char *besm6_opname (int opcode) +{ + if (sim_switches & SWMASK ('L')) { + /* Latin mnemonics. */ + if (opcode & 0200) + return opname_long_madlen [(opcode >> 3) & 017]; + return opname_short_madlen [opcode]; + } + if (opcode & 0200) + return opname_long_bemsh [(opcode >> 3) & 017]; + return opname_short_bemsh [opcode]; +}; + +/* + * Выдача кода инструкции по мнемонике (UTF-8). + */ +int besm6_opcode (char *instr) +{ + int i; + + for (i=0; i<64; ++i) + if (strcmp (opname_short_bemsh[i], instr) == 0 || + strcmp (opname_short_madlen[i], instr) == 0) + return i; + for (i=0; i<16; ++i) + if (strcmp (opname_long_bemsh[i], instr) == 0 || + strcmp (opname_long_madlen[i], instr) == 0) + return (i << 3) | 0200; + return -1; +} + +/* + * Выдача на консоль и в файл протокола. + * Если первый символ формата - подчерк, на консоль не печатаем. + * Добавляет перевод строки. + */ +void besm6_log (const char *fmt, ...) +{ + va_list args; + + if (*fmt == '_') + ++fmt; + else { + va_start (args, fmt); + vprintf (fmt, args); + printf ("\r\n"); + va_end (args); + } + if (sim_log) { + va_start (args, fmt); + vfprintf (sim_log, fmt, args); + if (sim_log == stdout) + fprintf (sim_log, "\r"); + fprintf (sim_log, "\n"); + fflush (sim_log); + va_end (args); + } +} + +/* + * Не добавляет перевод строки. + */ +void besm6_log_cont (const char *fmt, ...) +{ + va_list args; + + if (*fmt == '_') + ++fmt; + else { + va_start (args, fmt); + vprintf (fmt, args); + va_end (args); + } + if (sim_log) { + va_start (args, fmt); + vfprintf (sim_log, fmt, args); + fflush (sim_log); + va_end (args); + } +} + +/* + * Выдача на консоль и в файл отладки: если включён режим "cpu debug". + * Добавляет перевод строки. + */ +void besm6_debug (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vprintf (fmt, args); + printf ("\r\n"); + va_end (args); + if (sim_deb && sim_deb != stdout) { + va_start (args, fmt); + vfprintf (sim_deb, fmt, args); + fprintf (sim_deb, "\n"); + fflush (sim_deb); + va_end (args); + } +} + +/* + * Преобразование вещественного числа в формат БЭСМ-6. + * + * Представление чисел в IEEE 754 (double): + * 64 63———53 52————–1 + * знак порядок мантисса + * Старший (53-й) бит мантиссы не хранится и всегда равен 1. + * + * Представление чисел в БЭСМ-6: + * 48——–42 41 40————————————————–1 + * порядок знак мантисса в доп. коде + */ +t_value ieee_to_besm6 (double d) +{ + t_value word; + int exponent; + int sign; + + sign = d < 0; + if (sign) + d = -d; + d = frexp (d, &exponent); + /* 0.5 <= d < 1.0 */ + d = ldexp (d, 40); + word = d; + if (d - word >= 0.5) + word += 1; /* Округление. */ + if (exponent < -64) + return 0LL; /* Близкое к нулю число */ + if (exponent > 63) { + return sign ? + 0xFEFFFFFFFFFFLL : /* Максимальное число */ + 0xFF0000000000LL; /* Минимальное число */ + } + if (sign) + word = 0x20000000000LL-word; /* Знак. */ + word |= ((t_value) (exponent + 64)) << 41; + return word; +} + +double besm6_to_ieee (t_value word) +{ + double mantissa; + + /* Убираем свертку */ + word &= BITS48; + + /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; + * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. + */ + mantissa = (t_int64) word << (64 - 48 + 7); + + int exponent = word >> 41; + + /* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */ + return ldexp (mantissa, exponent - 64 - 63); +} + +/* + * Пропуск пробелов. + */ +char *skip_spaces (char *p) +{ + for (;;) { + if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) { + /* Skip zero width no-break space. */ + p += 3; + continue; + } + if (*p == ' ' || *p == '\t') { + ++p; + continue; + } + return p; + } +} + +/* + * Fetch Unicode symbol from UTF-8 string. + * Advance string pointer. + */ +int utf8_to_unicode (char **p) +{ + int c1, c2, c3; + + c1 = (unsigned char) *(*p)++; + if (! (c1 & 0x80)) + return c1; + c2 = (unsigned char) *(*p)++; + if (! (c1 & 0x20)) + return (c1 & 0x1f) << 6 | (c2 & 0x3f); + c3 = (unsigned char) *(*p)++; + return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f); +} + +char *besm6_parse_octal (char *cptr, int *offset) +{ + char *eptr; + + *offset = strtol (cptr, &eptr, 8); + if (eptr == cptr) + return 0; + return eptr; +} + +static char *get_alnum (char *iptr, char *optr) +{ + while ((*iptr >= 'a' && *iptr<='z') || + (*iptr >= 'A' && *iptr<='Z') || + (*iptr >= '0' && *iptr<='9') || (*iptr & 0x80)) { + *optr++ = *iptr++; + } + *optr = 0; + return iptr; +} + +/* + * Parse single instruction (half word). + * Allow mnemonics or octal code. + */ +char *parse_instruction (char *cptr, uint32 *val) +{ + int opcode, reg, addr, negate; + char gbuf[CBUFSIZE]; + + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr >= '0' && *cptr <= '7') { + /* Восьмеричное представление. */ + cptr = besm6_parse_octal (cptr, ®); /* get register */ + if (! cptr || reg > 15) { + /*printf ("Bad register\n");*/ + return 0; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '2' || *cptr == '3') { + /* Длинная команда. */ + cptr = besm6_parse_octal (cptr, &opcode); + if (! cptr || opcode < 020 || opcode > 037) { + /*printf ("Bad long opcode\n");*/ + return 0; + } + opcode <<= 3; + } else { + /* Короткая команда. */ + cptr = besm6_parse_octal (cptr, &opcode); + if (! cptr || opcode > 0177) { + /*printf ("Bad short opcode\n");*/ + return 0; + } + } + cptr = besm6_parse_octal (cptr, &addr); /* get address */ + if (! cptr || addr > BITS(15) || + (opcode <= 0177 && addr > BITS(12))) { + /*printf ("Bad address\n");*/ + return 0; + } + } else { + /* Мнемоническое представление команды. */ + cptr = get_alnum (cptr, gbuf); /* get opcode */ + opcode = besm6_opcode (gbuf); + if (opcode < 0) { + /*printf ("Bad opname: %s\n", gbuf);*/ + return 0; + } + negate = 0; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '-') { /* negative offset */ + negate = 1; + cptr = skip_spaces (cptr + 1); /* absorb spaces */ + } + addr = 0; + if (*cptr >= '0' && *cptr <= '7') { + /* Восьмеричный адрес. */ + cptr = besm6_parse_octal (cptr, &addr); + if (! cptr || addr > BITS(15)) { + /*printf ("Bad address: %o\n", addr);*/ + return 0; + } + if (negate) + addr = (- addr) & BITS(15); + if (opcode <= 077 && addr > BITS(12)) { + if (addr < 070000) { + /*printf ("Bad short address: %o\n", addr);*/ + return 0; + } + opcode |= 0100; + addr &= BITS(12); + } + } + reg = 0; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '(') { + /* Индекс-регистр в скобках. */ + cptr = besm6_parse_octal (cptr+1, ®); + if (! cptr || reg > 15) { + /*printf ("Bad register: %o\n", reg);*/ + return 0; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr != ')') { + /*printf ("No closing brace\n");*/ + return 0; + } + ++cptr; + } + } + *val = reg << 20 | opcode << 12 | addr; + return cptr; +} + +/* + * Instruction parse: two commands per word. + */ +t_stat parse_instruction_word (char *cptr, t_value *val) +{ + uint32 left, right; + + *val = 0; + cptr = parse_instruction (cptr, &left); + if (! cptr) + return SCPE_ARG; + right = 0; + cptr = skip_spaces (cptr); + if (*cptr == ',') { + cptr = parse_instruction (cptr + 1, &right); + if (! cptr) + return SCPE_ARG; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { + /*printf ("Extra symbols at eoln: %s\n", cptr);*/ + return SCPE_2MARG; + } + *val = (t_value) left << 24 | right; + return SCPE_OK; +} + +/* + * Печать машинной инструкции с мнемоникой. + */ +void besm6_fprint_cmd (FILE *of, uint32 cmd) +{ + int reg, opcode, addr; + + reg = (cmd >> 20) & 017; + if (cmd & BBIT(20)) { + opcode = (cmd >> 12) & 0370; + addr = cmd & BITS(15); + } else { + opcode = (cmd >> 12) & 077; + addr = cmd & 07777; + if (cmd & BBIT(19)) + addr |= 070000; + } + fprintf (of, "%s", besm6_opname (opcode)); + if (addr) { + fprintf (of, " "); + if (addr >= 077700) + fprintf (of, "-%o", (addr ^ 077777) + 1); + else + fprintf (of, "%o", addr); + } + if (reg) { + if (! addr) + fprintf (of, " "); + fprintf (of, "(%o)", reg); + } +} + +/* + * Печать машинной инструкции в восьмеричном виде. + */ +void besm6_fprint_insn (FILE *of, uint32 insn) +{ + if (insn & BBIT(20)) + fprintf (of, "%02o %02o %05o ", + insn >> 20, (insn >> 15) & 037, insn & BITS(15)); + else + fprintf (of, "%02o %03o %04o ", + insn >> 20, (insn >> 12) & 0177, insn & 07777); +} + +/* + * Symbolic decode + * + * Inputs: + * *of = output stream + * addr = current PC + * *val = pointer to data + * *uptr = pointer to unit + * sw = switches + * Outputs: + * return = status code + */ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + t_value cmd; + + if (uptr && (uptr != &cpu_unit)) /* must be CPU */ + return SCPE_ARG; + + cmd = val[0]; + + + if (sw & SWMASK ('M')) { /* symbolic decode? */ + if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR)) + fprintf (of, "-> "); + besm6_fprint_cmd (of, cmd >> 24); + if (sw & SIM_SW_STOP) /* stop point */ + fprintf (of, ", "); + else + fprintf (of, ",\n\t"); + if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR)) + fprintf (of, "-> "); + besm6_fprint_cmd (of, cmd & BITS(24)); + + } else if (sw & SWMASK ('I')) { + besm6_fprint_insn (of, (cmd >> 24) & BITS(24)); + besm6_fprint_insn (of, cmd & BITS(24)); + } else if (sw & SWMASK ('F')) { + fprintf (of, "%#.2g", besm6_to_ieee(cmd)); + } else if (sw & SWMASK ('B')) { + fprintf (of, "%03o %03o %03o %03o %03o %03o", + (int) (cmd >> 40) & 0377, + (int) (cmd >> 32) & 0377, + (int) (cmd >> 24) & 0377, + (int) (cmd >> 16) & 0377, + (int) (cmd >> 8) & 0377, + (int) cmd & 0377); + } else if (sw & SWMASK ('X')) { + fprintf (of, "%013llx", cmd); + } else + fprintf (of, "%04o %04o %04o %04o", + (int) (cmd >> 36) & 07777, + (int) (cmd >> 24) & 07777, + (int) (cmd >> 12) & 07777, + (int) cmd & 07777); + return SCPE_OK; +} + +/* + * Symbolic input + * + * Inputs: + * *cptr = pointer to input string + * addr = current PC + * *uptr = pointer to unit + * *val = pointer to output values + * sw = switches + * Outputs: + * status = error status + */ +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + int32 i; + + if (uptr && (uptr != &cpu_unit)) /* must be CPU */ + return SCPE_ARG; + if (! parse_instruction_word (cptr, val)) /* symbolic parse? */ + return SCPE_OK; + + val[0] = 0; + for (i=0; i<16; i++) { + if (*cptr < '0' || *cptr > '7') + break; + val[0] = (val[0] << 3) | (*cptr - '0'); + cptr = skip_spaces (cptr+1); /* next char */ + } + if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { + /*printf ("Extra symbols at eoln: %s\n", cptr);*/ + return SCPE_2MARG; + } + return SCPE_OK; +} + +/* + * Чтение строки входного файла. + * Форматы строк: + * п 76543 - адрес пуска + * в 12345 - адрес ввода + * ч -123.45e+6 - вещественное число + * с 0123 4567 0123 4567 - восьмеричное слово + * к 00 22 00000 00 010 0000 - команды + */ +t_stat besm6_read_line (FILE *input, int *type, t_value *val) +{ + char buf [512], *p; + int i, c; +again: + if (! fgets (buf, sizeof (buf), input)) { + *type = 0; + return SCPE_OK; + } + p = skip_spaces (buf); + if (*p == '\n' || *p == ';') + goto again; + c = utf8_to_unicode (&p); + if (c == CYRILLIC_SMALL_LETTER_VE || + c == CYRILLIC_CAPITAL_LETTER_VE || + c == 'b' || c == 'B') { + /* Адрес размещения данных. */ + *type = ':'; + *val = strtol (p, 0, 8); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_PE || + c == CYRILLIC_CAPITAL_LETTER_PE || + c == 'p' || c == 'P') { + /* Стартовый адрес. */ + *type = '@'; + *val = strtol (p, 0, 8); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_CHE || + c == CYRILLIC_CAPITAL_LETTER_CHE || + c == 'f' || c == 'F') { + /* Вещественное число. */ + *type = '='; + *val = ieee_to_besm6 (strtod (p, 0)); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_ES || + c == CYRILLIC_CAPITAL_LETTER_ES || + c == 'c' || c == 'C') { + /* Восьмеричное слово. */ + *type = '='; + *val = 0; + for (i=0; i<16; ++i) { + p = skip_spaces (p); + if (*p < '0' || *p > '7') { + if (i == 0) { + /* слишком короткое слово */ + goto bad; + } + break; + } + *val = *val << 3 | (*p++ - '0'); + } + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_KA || + c == CYRILLIC_CAPITAL_LETTER_KA || + c == 'k' || c == 'K') { + /* Команда. */ + *type = '*'; + if (parse_instruction_word (p, val) != SCPE_OK) + goto bad; + return SCPE_OK; + } + /* Неверная строка входного файла */ +bad: besm6_log ("Invalid input line: %s", buf); + return SCPE_FMT; +} + +/* + * Load memory from file. + */ +t_stat besm6_load (FILE *input) +{ + int addr, type; + t_value word; + t_stat err; + + addr = 1; + PC = 1; + for (;;) { + err = besm6_read_line (input, &type, &word); + if (err) + return err; + switch (type) { + case 0: /* EOF */ + return SCPE_OK; + case ':': /* address */ + addr = word; + break; + case '=': /* word */ + if (addr < 010) + pult [addr] = SET_CONVOL (word, CONVOL_NUMBER); + else + memory [addr] = SET_CONVOL (word, CONVOL_NUMBER); + ++addr; + break; + case '*': /* instruction */ + if (addr < 010) + pult [addr] = SET_CONVOL (word, CONVOL_INSN); + else + memory [addr] = SET_CONVOL (word, CONVOL_INSN); + ++addr; + break; + case '@': /* start address */ + PC = word; + break; + } + if (addr > MEMSIZE) + return SCPE_FMT; + } + return SCPE_OK; +} + +/* + * Dump memory to file. + */ +t_stat besm6_dump (FILE *of, char *fnam) +{ + int addr, last_addr = -1; + t_value word; + + fprintf (of, "; %s\n", fnam); + for (addr=1; addr> 24); + fprintf (of, ", "); + besm6_fprint_cmd (of, word & BITS(24)); + fprintf (of, "\t\t; %05o - ", addr); + fprintf (of, "%04o %04o %04o %04o\n", + (int) (word >> 36) & 07777, + (int) (word >> 24) & 07777, + (int) (word >> 12) & 07777, + (int) word & 07777); + } else { + fprintf (of, "с %04o %04o %04o %04o", + (int) (word >> 36) & 07777, + (int) (word >> 24) & 07777, + (int) (word >> 12) & 07777, + (int) word & 07777); + fprintf (of, "\t\t; %05o\n", addr); + } + } + return SCPE_OK; +} + +/* + * Loader/dumper + */ +t_stat sim_load (FILE *fi, char *cptr, char *fnam, int dump_flag) +{ + if (dump_flag) + return besm6_dump (fi, fnam); + + return besm6_load (fi); +} diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c new file mode 100644 index 00000000..489de9b0 --- /dev/null +++ b/BESM6/besm6_tty.c @@ -0,0 +1,1243 @@ +/* + * besm6_tty.c: BESM-6 teletype device + * + * Copyright (c) 2009, Leo Broukhis + * Copyright (c) 2009, Serge Vakulenko + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your discretion) any later version. + * See the accompanying file "COPYING" for more details. + */ + +#include "besm6_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#define TTY_MAX 24 /* Количество последовательных терминалов */ +#define LINES_MAX TTY_MAX + 2 /* Включая параллельные интерфейсы "Консулов" */ +/* + * Согласно таблице в http://ru.wikipedia.org/wiki/МТК-2 + */ +char * rus[] = { 0, "Т", "\r", "О", " ", "Х", "Н", "М", "\n", "Л", "Р", "Г", "И", "П", "Ц", "Ж", + "Е", "З", "Д", "Б", "С", "Ы", "Ф", "Ь", "А", "В", "Й", 0, "У", "Я", "К", 0 }; + +char * lat[] = { 0, "T", "\r", "O", " ", "H", "N", "M", "\n", "L", "R", "G", "I", "P", "C", "V", + "E", "Z", "D", "B", "S", "Y", "F", "X", "A", "W", "J", 0, "U", "Q", "K", 0 }; + +/* $ = Кто там? */ +char * dig[] = { 0, "5", "\r", "9", " ", "Щ", ",", ".", "\n", ")", "4", "Ш", "8", "0", ":", "=", + "3", "+", "$", "?", "'", "6", "Э", "/", "-", "2", "Ю", 0, "7", "1", "(", 0 }; + +char ** reg = 0; + +char * process (int sym) +{ + /* Требуется инверсия */ + sym ^= 31; + switch (sym) { + case 0: + reg = rus; + break; + case 27: + reg = dig; + break; + case 31: + reg = lat; + break; + default: + return reg[sym]; + } + return ""; +} + +/* Только для последовательных линий */ +int tty_active [TTY_MAX+1], tty_sym [TTY_MAX+1]; +int tty_typed [TTY_MAX+1], tty_instate [TTY_MAX+1]; +time_t tty_last_time [TTY_MAX+1]; +int tty_idle_count [TTY_MAX+1]; + +uint32 vt_sending, vt_receiving; +uint32 tt_sending, tt_receiving; + +// Attachments survive the reset +uint32 tt_mask = 0, vt_mask = 0; + +uint32 TTY_OUT = 0, TTY_IN = 0, vt_idle = 0; +uint32 CONSUL_IN[2]; + +uint32 CONS_CAN_PRINT[2] = { 01000, 00400 }; +uint32 CONS_HAS_INPUT[2] = { 04000, 02000 }; + +/* Буфера командных строк для режима telnet. */ +char vt_cbuf [CBUFSIZE] [LINES_MAX+1]; +char *vt_cptr [LINES_MAX+1]; + +void tt_print(); +void consul_receive(); +t_stat vt_clk(UNIT *); +extern char *get_sim_sw (char *cptr); + +UNIT tty_unit [] = { + { UDATA (vt_clk, UNIT_DIS, 0) }, /* fake unit, clock */ + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + /* The next two units are parallel interface */ + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { 0 } +}; + +REG tty_reg[] = { + { 0 } +}; + +/* + * Дескрипторы линий для мультиплексора TMXR. + * Поле .conn содержит номер сокета и означает занятую линию. + * Для локальных терминалов делаем .conn = 1. + * Чтобы нумерация линий совпадала с нумерацией терминалов + * (с единицы), нулевую линию держим занятой (.conn = 1). + * Поле .rcve устанавливается в 1 для сетевых соединений. + * Для локальных терминалов оно равно 0. + */ +TMLN tty_line [LINES_MAX+1]; +TMXR tty_desc = { LINES_MAX+1, 0, 0, tty_line }; /* mux descriptor */ + +#define TTY_UNICODE_CHARSET 0 +#define TTY_KOI7_JCUKEN_CHARSET (1<>= 1)) { + tt_print(); + /* Прием не реализован */ + clk_divider = 1<<29; + } + + /* Есть новые сетевые подключения? */ + int num = tmxr_poll_conn (&tty_desc); + if (num > 0 && num <= LINES_MAX) { + char buf [80]; + TMLN *t = &tty_line [num]; + besm6_debug ("*** tty%d: новое подключение от %s", + num, t->ipad); + t->rcve = 1; + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_VT340_STATE; + if (num <= TTY_MAX) + vt_mask |= 1 << (TTY_MAX - num); + + switch (tty_unit[num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + tmxr_linemsg (t, "Encoding is KOI-7 (jcuken)\r\n"); + break; + case TTY_KOI7_QWERTY_CHARSET: + tmxr_linemsg (t, "Encoding is KOI-7 (qwerty)\r\n"); + break; + case TTY_UNICODE_CHARSET: + tmxr_linemsg (t, "Encoding is UTF-8\r\n"); + break; + } + tty_idle_count[num] = 0; + tty_last_time[num] = time (0); + sprintf (buf, "%.24s from %s\r\n", + ctime (&tty_last_time[num]), + t->ipad); + tmxr_linemsg (t, buf); + + /* Ввод ^C, чтобы получить приглашение. */ + t->rxb [t->rxbpi++] = '\3'; + } + + /* Опрашиваем сокеты на передачу. */ + tmxr_poll_tx (&tty_desc); + + return sim_activate (this, 1000*MSEC/300); +} + +t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) +{ + int num = u - tty_unit; + TMLN *t = &tty_line [num]; + uint32 mask = 1 << (TTY_MAX - num); + + switch (val & TTY_STATE_MASK) { + case TTY_OFFLINE_STATE: + if (t->conn) { + if (t->rcve) { + tmxr_reset_ln (t); + t->rcve = 0; + } else + t->conn = 0; + if (num <= TTY_MAX) { + tty_sym[num] = + tty_active[num] = + tty_typed[num] = + tty_instate[num] = 0; + vt_mask &= ~mask; + tt_mask &= ~mask; + } + } + break; + case TTY_TELETYPE_STATE: + if (num > TTY_MAX) + return SCPE_NXPAR; + t->conn = 1; + t->rcve = 0; + tt_mask |= mask; + vt_mask &= ~mask; + break; + case TTY_VT340_STATE: + t->conn = 1; + t->rcve = 0; + if (num <= TTY_MAX) { + vt_mask |= mask; + tt_mask &= ~mask; + } + break; + case TTY_CONSUL_STATE: + if (num <= TTY_MAX) + return SCPE_NXPAR; + t->conn = 1; + t->rcve = 0; + break; + } + return SCPE_OK; +} + +/* + * Разрешение подключения к терминалам через telnet. + * Делается командой: + * attach tty <порт> + * Здесь <порт> - номер порта telnet, например 4199. + */ +t_stat tty_attach (UNIT *u, char *cptr) +{ + int num = u - tty_unit; + int r, m, n; + + if (*cptr >= '0' && *cptr <= '9') { + /* Сохраняем и восстанавливаем все .conn, + * так как tmxr_attach() их обнуляет. */ + for (m=0, n=1; n<=LINES_MAX; ++n) + if (tty_line[n].conn) + m |= 1 << (LINES_MAX-n); + /* Неважно, какой номер порта указывать в команде задания + * порта telnet. Можно tty, можно tty1 - без разницы. */ + r = tmxr_attach (&tty_desc, &tty_unit[0], cptr); + for (n=1; n<=LINES_MAX; ++n) + if (m >> (LINES_MAX-n) & 1) + tty_line[n].conn = 1; + return r; + } + if (strcmp (cptr, "/dev/tty") == 0) { + /* Консоль. */ + u->flags &= ~TTY_STATE_MASK; + u->flags |= TTY_VT340_STATE; + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) + vt_mask |= 1 << (TTY_MAX - num); + besm6_debug ("*** консоль на T%03o", num); + return 0; + } + if (strcmp (cptr, "/dev/null") == 0) { + /* Запрещаем терминал. */ + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) { + vt_mask &= ~(1 << (TTY_MAX - num)); + tt_mask &= ~(1 << (TTY_MAX - num)); + } + besm6_debug ("*** отключение терминала T%03o", num); + return 0; + } + return SCPE_ALATT; +} + +t_stat tty_detach (UNIT *u) +{ + return tmxr_detach (&tty_desc, &tty_unit[0]); +} + +/* + * Управление терминалами. + * set ttyN unicode - выбор кодировки UTF-8 + * set ttyN jcuken - выбор кодировки КОИ-7, раскладка йцукен + * set ttyN qwerty - выбор кодировки КОИ-7, раскладка яверты + * set ttyN off - отключение + * set ttyN tt - установка типа терминала "Телетайп" + * set ttyN vt - установка типа терминала "Видеотон-340" + * set ttyN consul - установка типа терминала "Consul-254" + * set ttyN destrbs - "стирающий" backspace + * set ttyN authbs - классический backspace + * set tty disconnect=N - принудительное завершение сеанса telnet + * show tty - просмотр режимов терминалов + * show tty connections - просмотр IP-адресов и времени соединений + * show tty statistics - просмотр счетчиков переданных и принятых байтов + */ +MTAB tty_mod[] = { + { TTY_CHARSET_MASK, TTY_UNICODE_CHARSET, "UTF-8 input", + "UNICODE" }, + { TTY_CHARSET_MASK, TTY_KOI7_JCUKEN_CHARSET, "KOI7 (jcuken) input", + "JCUKEN" }, + { TTY_CHARSET_MASK, TTY_KOI7_QWERTY_CHARSET, "KOI7 (qwerty) input", + "QWERTY" }, + { TTY_STATE_MASK, TTY_OFFLINE_STATE, "offline", + "OFF", &tty_setmode }, + { TTY_STATE_MASK, TTY_TELETYPE_STATE, "Teletype", + "TT", &tty_setmode }, + { TTY_STATE_MASK, TTY_VT340_STATE, "Videoton-340", + "VT", &tty_setmode }, + { TTY_STATE_MASK, TTY_CONSUL_STATE, "Consul-254", + "CONSUL", &tty_setmode }, + { TTY_BSPACE_MASK, TTY_DESTRUCTIVE_BSPACE, "destructive backspace", + "DESTRBS" }, + { TTY_BSPACE_MASK, TTY_AUTHENTIC_BSPACE, NULL, + "AUTHBS" }, + { MTAB_XTD | MTAB_VDV, 1, NULL, + "DISCONNECT", &tmxr_dscln, NULL, (void*) &tty_desc }, + { UNIT_ATT, UNIT_ATT, "connections", + NULL, NULL, &tmxr_show_summ, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", + NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", + NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, + "LOG", &tmxr_set_log, &tmxr_show_log, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, + "NOLOG", &tmxr_set_nolog, NULL, (void*) &tty_desc }, + { 0 } +}; + +DEVICE tty_dev = { + "TTY", tty_unit, tty_reg, tty_mod, + 27, 2, 1, 1, 2, 1, + NULL, NULL, &tty_reset, NULL, &tty_attach, &tty_detach, + NULL, DEV_NET|DEV_DEBUG +}; + +void tty_send (uint32 mask) +{ + /* besm6_debug ("*** телетайпы: передача %08o", mask); */ + + TTY_OUT = mask; +} + +/* + * Выдача символа на терминал с указанным номером. + */ +void vt_putc (int num, int c) +{ + TMLN *t = &tty_line [num]; + + if (! t->conn) + return; + if (t->rcve) { + /* Передача через telnet. */ + tmxr_putc_ln (t, c); + } else { + /* Вывод на консоль. */ + if (t->txlog) { /* log if available */ + fputc (c, t->txlog); + if (c == '\n') + fflush (t->txlog); + } + fputc (c, stdout); + fflush (stdout); + } +} + +/* + * Выдача строки на терминал с указанным номером. + */ +void vt_puts (int num, const char *s) +{ + TMLN *t = &tty_line [num]; + + if (! t->conn) + return; + if (t->rcve) { + /* Передача через telnet. */ + tmxr_linemsg (t, (char*) s); + } else { + /* Вывод на консоль. */ + if (t->txlog) /* log if available */ + fputs (s, t->txlog); + fputs (s, stdout); + fflush (stdout); + } +} + +const char * koi7_rus_to_unicode [32] = { + "Ю", "А", "Б", "Ц", "Д", "Е", "Ф", "Г", + "Х", "И", "Й", "К", "Л", "М", "Н", "О", + "П", "Я", "Р", "С", "Т", "У", "Ж", "В", + "Ь", "Ы", "З", "Ш", "Э", "Щ", "Ч", "\0x7f", +}; + +void vt_send(int num, uint32 sym, int destructive_bs) +{ + if (sym < 0x60) { + switch (sym) { + case '\031': + /* Up */ + vt_puts (num, "\033["); + sym = 'A'; + break; + case '\032': + /* Down */ + vt_puts (num, "\033["); + sym = 'B'; + break; + case '\030': + /* Right */ + vt_puts (num, "\033["); + sym = 'C'; + break; + case '\b': + /* Left */ + vt_puts (num, "\033["); + if (destructive_bs) { + /* Стираем предыдущий символ. */ + vt_puts (num, "D \033["); + } + sym = 'D'; + break; + case '\v': + case '\033': + case '\0': + /* Выдаём управляющий символ. */ + break; + case '\037': + /* Очистка экрана */ + vt_puts (num, "\033[H\033["); + sym = 'J'; + break; + case '\n': + /* На VDT-340 также возвращал курсор в 1-ю позицию */ + vt_putc (num, '\r'); + sym = '\n'; + break; + case '\f': + /* Сообщение ERR при нажатии некоторых управляющих + * клавиш выдается с использованием reverse wraparound. + */ + vt_puts(num, "\033["); + sym = 'H'; + break; + case '\r': + case '\003': + /* Неотображаемые символы */ + sym = 0; + break; + default: + if (sym < ' ') { + /* Нефункциональные ctrl-символы были видны в половинной яркости */ + vt_puts (num, "\033[2m"); + vt_putc (num, sym | 0x40); + vt_puts (num, "\033["); + /* Завершаем ESC-последовательность */ + sym = 'm'; + } + } + if (sym) + vt_putc (num, sym); + } else + vt_puts (num, koi7_rus_to_unicode[sym - 0x60]); +} + +/* + * Обработка выдачи на все подключенные терминалы. + */ +void vt_print() +{ + uint32 workset = (TTY_OUT & vt_mask) | vt_sending; + int num; + + if (workset == 0) { + ++vt_idle; + return; + } + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + int mask = 1 << (TTY_MAX - num); + int c = (TTY_OUT & mask) != 0; + switch (tty_active[num]*2+c) { + case 0: /* idle */ + besm6_debug ("Warning: inactive ttys should have been screened"); + continue; + case 1: /* start bit */ + vt_sending |= mask; + tty_active[num] = 1; + break; + case 18: /* stop bit */ + tty_sym[num] = ~tty_sym[num] & 0x7f; + vt_send (num, tty_sym[num], + (tty_unit[num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); + tty_active[num] = 0; + tty_sym[num] = 0; + vt_sending &= ~mask; + break; + case 19: /* framing error */ + vt_putc (num, '#'); + break; + default: + /* little endian ordering */ + if (c) { + tty_sym[num] |= 1 << (tty_active[num]-1); + } + ++tty_active[num]; + break; + } + workset &= ~mask; + } + vt_idle = 0; +} + +/* Ввод с телетайпа не реализован; вывод работает только при использовании + * модельного времени. + */ +void tt_print() +{ + uint32 workset = (TTY_OUT & tt_mask) | tt_sending; + int num; + + if (workset == 0) { + return; + } + + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + int mask = 1 << (TTY_MAX - num); + int c = (TTY_OUT & mask) != 0; + switch (tty_active[num]*2+c) { + case 0: /* idle */ + break; + case 1: /* start bit */ + tt_sending |= mask; + tty_active[num] = 1; + break; + case 12: /* stop bit */ + vt_puts (num, process (tty_sym[num])); + tty_active[num] = 0; + tty_sym[num] = 0; + tt_sending &= ~mask; + break; + case 13: /* framing error */ + vt_putc (num, '#'); + break; + default: + /* big endian ordering */ + if (c) { + tty_sym[num] |= 1 << (5-tty_active[num]); + } + ++tty_active[num]; + break; + } + workset &= ~mask; + } + vt_idle = 0; +} + +/* + * Перекодировка из Unicode в КОИ-7. + * Если нет соответствия, возвращает -1. + */ +static int unicode_to_koi7 (unsigned val) +{ + switch (val) { + case '\0'... '_': return val; + case 'a' ... 'z': return val + 'Z' - 'z'; + case 0x007f: return 0x7f; + case 0x0410: case 0x0430: return 0x61; + case 0x0411: case 0x0431: return 0x62; + case 0x0412: case 0x0432: return 0x77; + case 0x0413: case 0x0433: return 0x67; + case 0x0414: case 0x0434: return 0x64; + case 0x0415: case 0x0435: return 0x65; + case 0x0416: case 0x0436: return 0x76; + case 0x0417: case 0x0437: return 0x7a; + case 0x0418: case 0x0438: return 0x69; + case 0x0419: case 0x0439: return 0x6a; + case 0x041a: case 0x043a: return 0x6b; + case 0x041b: case 0x043b: return 0x6c; + case 0x041c: case 0x043c: return 0x6d; + case 0x041d: case 0x043d: return 0x6e; + case 0x041e: case 0x043e: return 0x6f; + case 0x041f: case 0x043f: return 0x70; + case 0x0420: case 0x0440: return 0x72; + case 0x0421: case 0x0441: return 0x73; + case 0x0422: case 0x0442: return 0x74; + case 0x0423: case 0x0443: return 0x75; + case 0x0424: case 0x0444: return 0x66; + case 0x0425: case 0x0445: return 0x68; + case 0x0426: case 0x0446: return 0x63; + case 0x0427: case 0x0447: return 0x7e; + case 0x0428: case 0x0448: return 0x7b; + case 0x0429: case 0x0449: return 0x7d; + case 0x042b: case 0x044b: return 0x79; + case 0x042c: case 0x044c: return 0x78; + case 0x042d: case 0x044d: return 0x7c; + case 0x042e: case 0x044e: return 0x60; + case 0x042f: case 0x044f: return 0x71; + } + return -1; +} + +/* + * Set command + */ +static t_stat cmd_set (int32 num, char *cptr) +{ + char gbuf [CBUFSIZE]; + int len; + + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) + return SCPE_NOPARAM; + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + + len = strlen (gbuf); + if (strncmp ("UNICODE", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_UNICODE_CHARSET; + } else if (strncmp ("JCUKEN", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_KOI7_JCUKEN_CHARSET; + } else if (strncmp ("QWERTY", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_KOI7_QWERTY_CHARSET; + } else if (strncmp ("TT", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_TELETYPE_STATE; + } else if (strncmp ("VT", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_VT340_STATE; + } else if (strncmp ("CONSUL", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_CONSUL_STATE; + } else if (strncmp ("DESTRBS", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_BSPACE_MASK; + tty_unit[num].flags |= TTY_DESTRUCTIVE_BSPACE; + } else if (strncmp ("AUTHBS", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_BSPACE_MASK; + tty_unit[num].flags |= TTY_AUTHENTIC_BSPACE; + } else { + return SCPE_NXPAR; + } + return SCPE_OK; +} + +/* + * Show command + */ +static t_stat cmd_show (int32 num, char *cptr) +{ + TMLN *t = &tty_line [num]; + char gbuf [CBUFSIZE]; + MTAB *m; + int len; + + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) { + sprintf (gbuf, "TTY%d", num); + tmxr_linemsg (t, gbuf); + for (m=tty_mod; m->mask; m++) { + if (m->pstring && + (tty_unit[num].flags & m->mask) == m->match) { + tmxr_linemsg (t, ", "); + tmxr_linemsg (t, m->pstring); + } + } + if (t->txlog) + tmxr_linemsg (t, ", log"); + tmxr_linemsg (t, "\r\n"); + return SCPE_OK; + } + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + + len = strlen (gbuf); + if (strncmp ("STATISTICS", gbuf, len) == 0) { + sprintf (gbuf, "line %d: input queued/total = %d/%d, " + "output queued/total = %d/%d\r\n", num, + t->rxbpi - t->rxbpr, t->rxcnt, + t->txbpi - t->txbpr, t->txcnt); + tmxr_linemsg (t, gbuf); + } else { + return SCPE_NXPAR; + } + return SCPE_OK; +} + +/* + * Exit command + */ +static t_stat cmd_exit (int32 num, char *cptr) +{ + return SCPE_EXIT; +} + +static t_stat cmd_help (int32 num, char *cptr); + +static CTAB cmd_table[] = { + { "SET", &cmd_set, 0, + "set unicode select UTF-8 encoding\r\n" + "set jcuken select KOI7 encoding, 'jcuken' keymap\r\n" + "set qwerty select KOI7 encoding, 'qwerty' keymap\r\n" + "set tt use Teletype mode\r\n" + "set vt use Videoton-340 mode\r\n" + "set consul use Consul-254 mode\r\n" + "set destrbs destructive backspace\r\n" + "set authbs authentic backspace\r\n" + }, + { "SHOW", &cmd_show, 0, + "sh{ow} show modes of the terminal\r\n" + "sh{ow} s{tatistics} show network statistics\r\n" + }, + { "EXIT", &cmd_exit, 0, + "exi{t} | q{uit} | by{e} exit from simulation\r\n" + }, + { "QUIT", &cmd_exit, 0, NULL + }, + { "BYE", &cmd_exit, 0, NULL + }, + { "HELP", &cmd_help, 0, + "h{elp} type this message\r\n" + "h{elp} type help for command\r\n" + }, + { 0 } +}; + +/* + * Find command routine + */ +static CTAB *lookup_cmd (char *command) +{ + CTAB *c; + int len; + + len = strlen (command); + for (c=cmd_table; c->name; c++) { + if (strncmp (command, c->name, len) == 0) + return c; + } + return 0; +} + +/* + * Help command + */ +static t_stat cmd_help (int32 num, char *cptr) +{ + TMLN *t = &tty_line [num]; + char gbuf [CBUFSIZE]; + CTAB *c; + + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) { + /* Список всех команд. */ + tmxr_linemsg (t, "Commands may be abbreviated. Commands are:\r\n\r\n"); + for (c=cmd_table; c && c->name; c++) + if (c->help) + tmxr_linemsg (t, c->help); + return SCPE_OK; + } + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + c = lookup_cmd (gbuf); + if (! c) + return SCPE_ARG; + /* Описание конкретной команды. */ + tmxr_linemsg (t, c->help); + return SCPE_OK; +} + +/* + * Выполнение командной строки. + */ +void vt_cmd_exec (int num) +{ + TMLN *t = &tty_line [num]; + char *cptr, gbuf [CBUFSIZE]; + CTAB *cmdp; + t_stat err; + extern char *scp_errors[]; + + cptr = get_glyph (vt_cbuf [num], gbuf, 0); /* get command glyph */ + cmdp = lookup_cmd (gbuf); /* lookup command */ + if (! cmdp) { + tmxr_linemsg (t, scp_errors[SCPE_UNK - SCPE_BASE]); + tmxr_linemsg (t, "\r\n"); + return; + } + err = cmdp->action (num, cptr); /* if found, exec */ + if (err >= SCPE_BASE) { /* error? */ + tmxr_linemsg (t, scp_errors [err - SCPE_BASE]); + tmxr_linemsg (t, "\r\n"); + } + if (err == SCPE_EXIT) { /* close telnet session */ + tmxr_reset_ln (t); + } +} + +/* + * Режим управляющей командной строки. + */ +void vt_cmd_loop (int num, int c) +{ + TMLN *t = &tty_line [num]; + char *cbuf, **cptr; + + cbuf = vt_cbuf [num]; + cptr = &vt_cptr [num]; + + switch (c) { + case '\r': + case '\n': + tmxr_linemsg (t, "\r\n"); + if (*cptr <= cbuf) { + /* Пустая строка - возврат в обычный режим. */ + tty_unit[num].flags &= ~TTY_CMDLINE_MASK; + break; + } + /* Выполнение. */ + **cptr = 0; + vt_cmd_exec (num); + tmxr_linemsg (t, "sim>"); + *cptr = vt_cbuf[num]; + break; + case '\b': + case 0177: + /* Стирание предыдущего символа. */ + if (*cptr <= cbuf) + break; + tmxr_linemsg (t, "\b \b"); + while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + break; + } + break; + case 'U' & 037: + /* Стирание всей строки. */ +erase_line: while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + tmxr_linemsg (t, "\b \b"); + } + break; + case 033: + /* Escape [ X. */ + if (tmxr_getc_ln (t) != '[' + TMXR_VALID) + break; + switch (tmxr_getc_ln (t) - TMXR_VALID) { + case 'A': /* стрелка вверх */ + if (*cptr <= cbuf) { + *cptr = cbuf + strlen (cbuf); + if (*cptr > cbuf) + tmxr_linemsg (t, cbuf); + } + break; + case 'B': /* стрелка вниз */ + goto erase_line; + } + break; + default: + if (c < ' ' || *cptr > cbuf+CBUFSIZE-5) + break; + *(*cptr)++ = c; + tmxr_putc_ln (t, c); + break; + } +} + +/* + * Ввод символа с терминала с указанным номером. + * Если нет приёма, возвращает -1. + * В случае прерывания возвращает 0400 (только для консоли). + */ +int vt_getc (int num) +{ + TMLN *t = &tty_line [num]; + extern int32 sim_int_char; + int c; + time_t now; + + if (! t->conn) { + /* Пользователь отключился. */ + if (t->ipad) { + besm6_debug ("*** tty%d: отключение %s", + num, + t->ipad); + t->ipad = NULL; + } + tty_setmode (tty_unit+num, TTY_OFFLINE_STATE, 0, 0); + tty_unit[num].flags &= ~TTY_STATE_MASK; + return -1; + } + if (t->rcve) { + /* Приём через telnet. */ + c = tmxr_getc_ln (t); + if (! (c & TMXR_VALID)) { + now = time (0); + if (now > tty_last_time[num] + 5*60) { + ++tty_idle_count[num]; + if (tty_idle_count[num] > 3) { + tmxr_linemsg (t, "\r\nКОНЕЦ СЕАНСА\r\n"); + tmxr_reset_ln (t); + return -1; + } + tmxr_linemsg (t, "\r\nНЕ СПАТЬ!\r\n"); + tty_last_time[num] = now; + } + return -1; + } + tty_idle_count[num] = 0; + tty_last_time[num] = time (0); + + if (tty_unit[num].flags & TTY_CMDLINE_MASK) { + /* Продолжение режима управляющей командной строки. */ + vt_cmd_loop (num, c & 0377); + return -1; + } + if ((c & 0377) == sim_int_char) { + /* Вход в режим управляющей командной строки. */ + tty_unit[num].flags |= TTY_CMDLINE_MASK; + tmxr_linemsg (t, "sim>"); + vt_cptr[num] = vt_cbuf[num]; + return -1; + } + } else { + /* Ввод с клавиатуры. */ + c = sim_poll_kbd(); + if (c == SCPE_STOP) + return 0400; /* прерывание */ + if (! (c & SCPE_KFLAG)) + return -1; + } + return c & 0377; +} + +/* + * Ввод символа с клавиатуры. + * Перекодировка из UTF-8 в КОИ-7. + * Полученный символ находится в диапазоне 0..0177. + * Если нет ввода, возвращает -1. + * В случае прерывания (^E) возвращает 0400. + */ +static int vt_kbd_input_unicode (int num) +{ + int c1, c2, c3, r; +again: + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c1 = r & 0377; + if (! (c1 & 0x80)) + return unicode_to_koi7 (c1); + + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c2 = r & 0377; + if (! (c1 & 0x20)) + return unicode_to_koi7 ((c1 & 0x1f) << 6 | (c2 & 0x3f)); + + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c3 = r & 0377; + if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) { + /* Skip zero width no-break space. */ + goto again; + } + return unicode_to_koi7 ((c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | + (c3 & 0x3f)); +} + +/* + * Альтернативный вариант ввода, не требующий переключения на русскую клавиатуру. + * Символы "точка" и "запятая" вводятся через shift, "больше-меньше" - "тильда-гравис". + * "точка с запятой" - "закр. фиг. скобка", "апостроф" - "верт. черта". + */ +static int vt_kbd_input_koi7 (int num) +{ + int r; + + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + r &= 0377; + switch (r) { + case '\r': return '\003'; + case 'q': return 'j'; + case 'w': return 'c'; + case 'e': return 'u'; + case 'r': return 'k'; + case 't': return 'e'; + case 'y': return 'n'; + case 'u': return 'g'; + case 'i': return '{'; + case 'o': return '}'; + case 'p': return 'z'; + case '[': return 'h'; + case '{': return '['; + case 'a': return 'f'; + case 's': return 'y'; + case 'd': return 'w'; + case 'f': return 'a'; + case 'g': return 'p'; + case 'h': return 'r'; + case 'j': return 'o'; + case 'k': return 'l'; + case 'l': return 'd'; + case ';': return 'v'; + case '}': return ';'; + case '\'': return '|'; + case '|': return '\''; + case 'z': return 'q'; + case 'x': return '~'; + case 'c': return 's'; + case 'v': return 'm'; + case 'b': return 'i'; + case 'n': return 't'; + case 'm': return 'x'; + case ',': return 'b'; + case '<': return ','; + case '.': return '`'; + case '>': return '.'; + case '~': return '>'; + case '`': return '<'; + default: return r; + } +} + +int odd_parity(unsigned char c) +{ + c = (c & 0x55) + ((c >> 1) & 0x55); + c = (c & 0x33) + ((c >> 2) & 0x33); + c = (c & 0x0F) + ((c >> 4) & 0x0F); + return c & 1; +} + +/* + * Обработка ввода со всех подключенных терминалов. + */ +void vt_receive() +{ + uint32 workset = vt_mask; + int num; + + TTY_IN = 0; + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + uint32 mask = 1 << (TTY_MAX - num); + switch (tty_instate[num]) { + case 0: + switch (tty_unit[num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + tty_typed[num] = vt_kbd_input_koi7 (num); + break; + case TTY_KOI7_QWERTY_CHARSET: + tty_typed[num] = vt_getc (num); + break; + case TTY_UNICODE_CHARSET: + tty_typed[num] = vt_kbd_input_unicode (num); + break; + default: + tty_typed[num] = '?'; + break; + } + if (tty_typed[num] < 0) { + /* TODO: обработать исключение от "неоператорского" терминала */ + sim_interval = 0; + break; + } + if (tty_typed[num] <= 0177) { + if (tty_typed[num] == '\r' || tty_typed[num] == '\n') + tty_typed[num] = 3; /* ^C - конец строки */ + if (tty_typed[num] == '\177') + tty_typed[num] = '\b'; /* ASCII DEL -> BS */ + tty_instate[num] = 1; + TTY_IN |= mask; /* start bit */ + GRP |= GRP_TTY_START; /* не используется ? */ + MGRP |= BBIT(19); /* для терминалов по методу МГУ */ + vt_receiving |= mask; + } + break; + case 1 ... 7: + /* need inverted byte */ + TTY_IN |= (tty_typed[num] & (1 << (tty_instate[num]-1))) ? 0 : mask; + tty_instate[num]++; + break; + case 8: + TTY_IN |= odd_parity(tty_typed[num]) ? 0 : mask; /* even parity of inverted */ + tty_instate[num]++; + break; + case 9 ... 11: + /* stop bits are 0 */ + tty_instate[num]++; + break; + case 12: + tty_instate[num] = 0; /* ready for the next char */ + vt_receiving &= ~mask; + break; + } + workset &= ~mask; + } + if (vt_receiving) + vt_idle = 0; +} + +/* + * Выясняем, остановлены ли терминалы. Нужно для входа в "спящий" режим. + */ +int vt_is_idle () +{ + return (tt_mask ? vt_idle > 300 : vt_idle > 10); +} + +int tty_query () +{ +/* besm6_debug ("*** телетайпы: приём");*/ + return TTY_IN; +} + +void consul_print (int dev_num, uint32 cmd) +{ + int line_num = dev_num + TTY_MAX + 1; + if (tty_dev.dctrl) + besm6_debug(">>> CONSUL%o: %03o", line_num, cmd & 0377); + cmd &= 0177; + switch (tty_unit[line_num].flags & TTY_STATE_MASK) { + case TTY_VT340_STATE: + vt_send (line_num, cmd, + (tty_unit[line_num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); + break; + case TTY_CONSUL_STATE: + besm6_debug(">>> CONSUL%o: Native charset not implemented", line_num); + break; + } + // PRP |= CONS_CAN_PRINT[dev_num]; + vt_idle = 0; +} + +void consul_receive () +{ + int c, line_num, dev_num; + + for (dev_num = 0; dev_num < 2; ++dev_num){ + line_num = dev_num + TTY_MAX + 1; + if (! tty_line[line_num].conn) + continue; + switch (tty_unit[line_num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + c = vt_kbd_input_koi7 (line_num); + break; + case TTY_KOI7_QWERTY_CHARSET: + c = vt_getc (line_num); + break; + case TTY_UNICODE_CHARSET: + c = vt_kbd_input_unicode (line_num); + break; + default: + c = '?'; + break; + } + if (c >= 0 && c <= 0177) { + CONSUL_IN[dev_num] = odd_parity(c) ? c | 0200 : c; + if (c == '\r' || c == '\n') + CONSUL_IN[dev_num] = 3; + PRP |= CONS_HAS_INPUT[dev_num]; + vt_idle = 0; + } + } +} + +uint32 consul_read (int num) +{ + if (tty_dev.dctrl) + besm6_debug("<<< CONSUL%o: %03o", num+TTY_MAX+1, CONSUL_IN[num]); + return CONSUL_IN[num]; +} diff --git a/makefile b/makefile index 871cea54..74f5f698 100644 --- a/makefile +++ b/makefile @@ -68,6 +68,8 @@ ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS VIDEO_USEFUL = true DISPLAY_USEFUL = true endif +else ifeq ($(MAKECMDGOALS),besm6) + VIDEO_USEFUL = true else ifeq ($(MAKECMDGOALS),) # default target is all @@ -1159,6 +1161,24 @@ SSEMD = SSEM SSEM = ${SSEMD}/ssem_cpu.c ${SSEMD}/ssem_sys.c SSEM_OPT = -I ${SSEMD} +### +### Experimental simulators +### + +BESM6D = 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 + +ifeq (,${VIDEO_LDFLAGS}) + BESM6_OPT = -I ${BESM6D} -DUSE_INT64 +else ifneq (,$(and $(findstring,SDL2,${VIDEO_LDFLAGS})),$(and($(find_include, SDL2/SDL_ttf),$(find_lib,SDL2_ttf)))) + BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf +else ifneq (,$(and $(find_include, SDL/SDL_ttf),$(find_lib,SDL_ttf))) + BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf +endif + ### ### Unsupported/Incomplete simulators ### @@ -1462,6 +1482,12 @@ ${BIN}ssem${EXE} : ${SSEM} ${SIM} ${MKDIRBIN} ${CC} ${SSEM} ${SIM} ${SSEM_OPT} $(CC_OUTSPEC) ${LDFLAGS} +besm6 : ${BIN}besm6${EXE} + +${BIN}besm6${EXE} : ${BESM6} ${SIM} + ${MKDIRBIN} + ${CC} ${BESM6} ${SIM} ${BESM6_OPT} $(CC_OUTSPEC) ${LDFLAGS} + sigma : ${BIN}sigma${EXE} ${BIN}sigma${EXE} : ${SIGMA} ${SIM} From b4eeaa77ded86e11d295e2a627499506550afd8f Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Tue, 30 Dec 2014 00:41:31 -0800 Subject: [PATCH 02/41] BESM6: Converted files to CRLF format Also added support for loading such files, and a few tests. --- BESM6/besm6_arith.c | 966 +++++------ BESM6/besm6_cpu.c | 3536 ++++++++++++++++++++-------------------- BESM6/besm6_defs.h | 852 +++++----- BESM6/besm6_disk.c | 1296 +++++++-------- BESM6/besm6_drum.c | 744 ++++----- BESM6/besm6_mmu.c | 1304 +++++++-------- BESM6/besm6_panel.c | 1188 +++++++------- BESM6/besm6_printer.c | 690 ++++---- BESM6/besm6_punch.c | 944 +++++------ BESM6/besm6_sys.c | 1438 ++++++++-------- BESM6/besm6_tty.c | 2486 ++++++++++++++-------------- BESM6/boot_dispak.b6 | 484 ++++++ BESM6/dispak.ini | 92 ++ BESM6/formatdisk.c | 63 + BESM6/test_alu.b6 | 2425 +++++++++++++++++++++++++++ BESM6/test_alu.ini | 16 + BESM6/test_cu.ini | 16 + BESM6/test_pprog05.b6 | 37 + BESM6/test_pprog05.ini | 22 + makefile | 22 +- 20 files changed, 10891 insertions(+), 7730 deletions(-) create mode 100644 BESM6/boot_dispak.b6 create mode 100644 BESM6/dispak.ini create mode 100755 BESM6/formatdisk.c create mode 100644 BESM6/test_alu.b6 create mode 100644 BESM6/test_alu.ini create mode 100644 BESM6/test_cu.ini create mode 100644 BESM6/test_pprog05.b6 create mode 100644 BESM6/test_pprog05.ini diff --git a/BESM6/besm6_arith.c b/BESM6/besm6_arith.c index d29685e0..d88bdd6e 100644 --- a/BESM6/besm6_arith.c +++ b/BESM6/besm6_arith.c @@ -1,483 +1,483 @@ -/* - * BESM-6 arithmetic instructions. - * - * Copyright (c) 1997-2009, Leonid Broukhis - * 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 -#include "besm6_defs.h" - -typedef struct { - t_uint64 mantissa; - unsigned exponent; /* offset by 64 */ -} alureg_t; /* ALU register type */ - -static alureg_t toalu (t_value val) -{ - alureg_t ret; - - ret.mantissa = val & BITS41; - ret.exponent = (val >> 41) & BITS(7); - if (ret.mantissa & BIT41) - ret.mantissa |= BIT42; - return ret; -} - -static int inline is_negative (alureg_t *word) -{ - return (word->mantissa & BIT41) != 0; -} - -static void negate (alureg_t *val) -{ - if (is_negative (val)) - val->mantissa |= BIT42; - val->mantissa = (~val->mantissa + 1) & BITS42; - if (((val->mantissa >> 1) ^ val->mantissa) & BIT41) { - val->mantissa >>= 1; - ++val->exponent; - } - if (is_negative (val)) - val->mantissa |= BIT42; -} - -/* - * 48-й разряд -> 1, 47-й -> 2 и т.п. - * Единица 1-го разряда и нулевое слово -> 48, - * как в первоначальном варианте системы команд. - */ -int besm6_highest_bit (t_value val) -{ - int n = 32, cnt = 0; - do { - t_value tmp = val; - if (tmp >>= n) { - cnt += n; - val = tmp; - } - } while (n >>= 1); - return 48 - cnt; -} - -/* - * Нормализация и округление. - * Результат помещается в регистры ACC и 40-1 разряды RMR. - * 48-41 разряды RMR сохраняются. - */ -static void normalize_and_round (alureg_t acc, t_uint64 mr, int rnd_rq) -{ - t_uint64 rr = 0; - int i; - t_uint64 r; - - if (RAU & RAU_NORM_DISABLE) - goto chk_rnd; - i = (acc.mantissa >> 39) & 3; - if (i == 0) { - r = acc.mantissa & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - r <<= cnt; - rr = mr >> (40 - cnt); - acc.mantissa = r | rr; - mr <<= cnt; - acc.exponent -= cnt; - goto chk_zero; - } - r = mr & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - rr = mr; - r <<= cnt; - acc.mantissa = r; - mr = 0; - acc.exponent -= 40 + cnt; - goto chk_zero; - } - goto zero; - } else if (i == 3) { - r = ~acc.mantissa & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - r = (r << cnt) | ((1LL << cnt) - 1); - rr = mr >> (40 - cnt); - acc.mantissa = BIT41 | (~r & BITS40) | rr; - mr <<= cnt; - acc.exponent -= cnt; - goto chk_zero; - } - r = ~mr & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - rr = mr; - r = (r << cnt) | ((1LL << cnt) - 1); - acc.mantissa = BIT41 | (~r & BITS40); - mr = 0; - acc.exponent -= 40 + cnt; - goto chk_zero; - } else { - rr = 1; - acc.mantissa = BIT41; - mr = 0; - acc.exponent -= 80; - goto chk_zero; - } - } -chk_zero: - if (rr) - rnd_rq = 0; -chk_rnd: - if (acc.exponent & 0x8000) - goto zero; - if (! (RAU & RAU_ROUND_DISABLE) && rnd_rq) - acc.mantissa |= 1; - - if (! acc.mantissa && ! (RAU & RAU_NORM_DISABLE)) { -zero: ACC = 0; - RMR &= ~BITS40; - return; - } - - ACC = (t_value) (acc.exponent & BITS(7)) << 41 | - (acc.mantissa & BITS41); - RMR = (RMR & ~BITS40) | (mr & BITS40); - /* При переполнении мантисса и младшие разряды порядка верны */ - if (acc.exponent & 0x80) { - if (! (RAU & RAU_OVF_DISABLE)) - longjmp (cpu_halt, STOP_OVFL); - } -} - -/* - * Сложение и все варианты вычитаний. - * Исходные значения: регистр ACC и аргумент 'val'. - * Результат помещается в регистр ACC и 40-1 разряды RMR. - */ -void besm6_add (t_value val, int negate_acc, int negate_val) -{ - t_uint64 mr; - alureg_t acc, word, a1, a2; - int diff, neg, rnd_rq = 0; - - acc = toalu (ACC); - word = toalu (val); - if (! negate_acc) { - if (! negate_val) { - /* Сложение */ - } else { - /* Вычитание */ - negate (&word); - } - } else { - if (! negate_val) { - /* Обратное вычитание */ - negate (&acc); - } else { - /* Вычитание модулей */ - if (is_negative (&acc)) - negate (&acc); - if (! is_negative (&word)) - negate (&word); - } - } - - diff = acc.exponent - word.exponent; - if (diff < 0) { - diff = -diff; - a1 = acc; - a2 = word; - } else { - a1 = word; - a2 = acc; - } - mr = 0; - neg = is_negative (&a1); - if (diff == 0) { - /* Nothing to do. */ - } else if (diff <= 40) { - rnd_rq = (mr = (a1.mantissa << (40 - diff)) & BITS40) != 0; - a1.mantissa = ((a1.mantissa >> diff) | - (neg ? (~0ll << (40 - diff)) : 0)) & BITS42; - } else if (diff <= 80) { - diff -= 40; - rnd_rq = a1.mantissa != 0; - mr = ((a1.mantissa >> diff) | - (neg ? (~0ll << (40 - diff)) : 0)) & BITS40; - if (neg) { - a1.mantissa = BITS42; - } else - a1.mantissa = 0; - } else { - rnd_rq = a1.mantissa != 0; - if (neg) { - mr = BITS40; - a1.mantissa = BITS42; - } else - mr = a1.mantissa = 0; - } - acc.exponent = a2.exponent; - acc.mantissa = a1.mantissa + a2.mantissa; - - /* Если требуется нормализация вправо, биты 42:41 - * принимают значение 01 или 10. */ - switch ((acc.mantissa >> 40) & 3) { - case 2: - case 1: - rnd_rq |= acc.mantissa & 1; - mr = (mr >> 1) | ((acc.mantissa & 1) << 39); - acc.mantissa >>= 1; - ++acc.exponent; - } - normalize_and_round (acc, mr, rnd_rq); -} - -/* - * non-restoring division - */ -#define ABS(x) ((x) < 0 ? -x : x) -#define INT64(x) ((x) & BIT41 ? (-1LL << 40) | (x) : x) -static alureg_t nrdiv (alureg_t n, alureg_t d) -{ - t_int64 nn, dd, q, res; - alureg_t quot; - - /* to compensate for potential normalization to the right */ - nn = INT64(n.mantissa)*2; - dd = INT64(d.mantissa)*2; - res = 0, q = BIT41; - - if (ABS(nn) >= ABS(dd)) { - /* normalization to the right */ - nn/=2; - n.exponent++; - } - while (q > 1) { - if (nn == 0) - break; - - if (ABS(nn) < BIT40) - nn *= 2; /* magic shortcut */ - else if ((nn > 0) ^ (dd > 0)) { - res -= q; - nn = 2*nn+dd; - } else { - res += q; - nn = 2*nn-dd; - } - q /= 2; - } - quot.mantissa = res/2; - quot.exponent = n.exponent-d.exponent+64; - return quot; -} - -/* - * Деление. - * Исходные значения: регистр ACC и аргумент 'val'. - * Результат помещается в регистр ACC, содержимое RMR не определено. - */ -void besm6_divide (t_value val) -{ - alureg_t acc; - alureg_t dividend, divisor; - - if (((val ^ (val << 1)) & BIT41) == 0) { - /* Ненормализованный делитель: деление на ноль. */ - longjmp (cpu_halt, STOP_DIVZERO); - } - dividend = toalu(ACC); - divisor = toalu(val); - - acc = nrdiv(dividend, divisor); - - normalize_and_round (acc, 0, 0); -} - -/* - * Умножение. - * Исходные значения: регистр ACC и аргумент 'val'. - * Результат помещается в регистр ACC и 40-1 разряды RMR. - */ -void besm6_multiply (t_value val) -{ - uint8 neg = 0; - alureg_t acc, word, a, b; - t_uint64 mr, alo, blo, ahi, bhi; - - register t_uint64 l; - - if (! ACC || ! val) { - /* multiplication by zero is zero */ - ACC = 0; - RMR &= ~BITS40; - return; - } - acc = toalu (ACC); - word = toalu (val); - - a = acc; - b = word; - mr = 0; - - if (is_negative (&a)) { - neg = 1; - negate (&a); - } - if (is_negative (&b)) { - neg ^= 1; - negate (&b); - } - acc.exponent = a.exponent + b.exponent - 64; - - alo = a.mantissa & BITS(20); - ahi = a.mantissa >> 20; - - blo = b.mantissa & BITS(20); - bhi = b.mantissa >> 20; - - l = alo * blo + ((alo * bhi + ahi * blo) << 20); - - mr = l & BITS40; - l >>= 40; - - acc.mantissa = l + ahi * bhi; - - if (neg) { - mr = (~mr & BITS40) + 1; - acc.mantissa = ((~acc.mantissa & BITS40) + (mr >> 40)) - | BIT41 | BIT42; - mr &= BITS40; - } - - normalize_and_round (acc, mr, mr != 0); -} - -/* - * Изменение знака числа на сумматоре ACC. - * Результат помещается в регистр ACC, RMR гасится. - */ -void besm6_change_sign (int negate_acc) -{ - alureg_t acc; - - acc = toalu (ACC); - if (negate_acc) - negate (&acc); - RMR = 0; - normalize_and_round (acc, 0, 0); -} - -/* - * Изменение порядка числа на сумматоре ACC. - * Результат помещается в регистр ACC, RMR гасится. - */ -void besm6_add_exponent (int val) -{ - alureg_t acc; - - acc = toalu (ACC); - acc.exponent += val; - RMR = 0; - normalize_and_round (acc, 0, 0); -} - -/* - * Сборка значения по маске. - */ -t_value besm6_pack (t_value val, t_value mask) -{ - t_value result; - - result = 0; - for (; mask; mask>>=1, val>>=1) - if (mask & 1) { - result >>= 1; - if (val & 1) - result |= BIT48; - } - return result; -} - -/* - * Разборка значения по маске. - */ -t_value besm6_unpack (t_value val, t_value mask) -{ - t_value result; - int i; - - result = 0; - for (i=0; i<48; ++i) { - result <<= 1; - if (mask & BIT48) { - if (val & BIT48) - result |= 1; - val <<= 1; - } - mask <<= 1; - } - return result; -} - -/* - * Подсчёт количества единиц в слове. - */ -int besm6_count_ones (t_value word) -{ - int c; - - for (c=0; word; ++c) - word &= word-1; - return c; -} - -/* - * Сдвиг сумматора ACC с выдвижением в регистр младших разрядов RMR. - * Величина сдвига находится в диапазоне -64..63. - */ -void besm6_shift (int i) -{ - RMR = 0; - if (i > 0) { - /* Сдвиг вправо. */ - if (i < 48) { - RMR = (ACC << (48-i)) & BITS48; - ACC >>= i; - } else { - RMR = ACC >> (i-48); - ACC = 0; - } - } else if (i < 0) { - /* Сдвиг влево. */ - i = -i; - if (i < 48) { - RMR = ACC >> (48-i); - ACC = (ACC << i) & BITS48; - } else { - RMR = (ACC << (i-48)) & BITS48; - ACC = 0; - } - } -} +/* + * BESM-6 arithmetic instructions. + * + * Copyright (c) 1997-2009, Leonid Broukhis + * 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 +#include "besm6_defs.h" + +typedef struct { + t_uint64 mantissa; + unsigned exponent; /* offset by 64 */ +} alureg_t; /* ALU register type */ + +static alureg_t toalu (t_value val) +{ + alureg_t ret; + + ret.mantissa = val & BITS41; + ret.exponent = (val >> 41) & BITS(7); + if (ret.mantissa & BIT41) + ret.mantissa |= BIT42; + return ret; +} + +static int inline is_negative (alureg_t *word) +{ + return (word->mantissa & BIT41) != 0; +} + +static void negate (alureg_t *val) +{ + if (is_negative (val)) + val->mantissa |= BIT42; + val->mantissa = (~val->mantissa + 1) & BITS42; + if (((val->mantissa >> 1) ^ val->mantissa) & BIT41) { + val->mantissa >>= 1; + ++val->exponent; + } + if (is_negative (val)) + val->mantissa |= BIT42; +} + +/* + * 48-й разряд -> 1, 47-й -> 2 и т.п. + * Единица 1-го разряда и нулевое слово -> 48, + * как в первоначальном варианте системы команд. + */ +int besm6_highest_bit (t_value val) +{ + int n = 32, cnt = 0; + do { + t_value tmp = val; + if (tmp >>= n) { + cnt += n; + val = tmp; + } + } while (n >>= 1); + return 48 - cnt; +} + +/* + * Нормализация и округление. + * Результат помещается в регистры ACC и 40-1 разряды RMR. + * 48-41 разряды RMR сохраняются. + */ +static void normalize_and_round (alureg_t acc, t_uint64 mr, int rnd_rq) +{ + t_uint64 rr = 0; + int i; + t_uint64 r; + + if (RAU & RAU_NORM_DISABLE) + goto chk_rnd; + i = (acc.mantissa >> 39) & 3; + if (i == 0) { + r = acc.mantissa & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + r <<= cnt; + rr = mr >> (40 - cnt); + acc.mantissa = r | rr; + mr <<= cnt; + acc.exponent -= cnt; + goto chk_zero; + } + r = mr & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + rr = mr; + r <<= cnt; + acc.mantissa = r; + mr = 0; + acc.exponent -= 40 + cnt; + goto chk_zero; + } + goto zero; + } else if (i == 3) { + r = ~acc.mantissa & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + r = (r << cnt) | ((1LL << cnt) - 1); + rr = mr >> (40 - cnt); + acc.mantissa = BIT41 | (~r & BITS40) | rr; + mr <<= cnt; + acc.exponent -= cnt; + goto chk_zero; + } + r = ~mr & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + rr = mr; + r = (r << cnt) | ((1LL << cnt) - 1); + acc.mantissa = BIT41 | (~r & BITS40); + mr = 0; + acc.exponent -= 40 + cnt; + goto chk_zero; + } else { + rr = 1; + acc.mantissa = BIT41; + mr = 0; + acc.exponent -= 80; + goto chk_zero; + } + } +chk_zero: + if (rr) + rnd_rq = 0; +chk_rnd: + if (acc.exponent & 0x8000) + goto zero; + if (! (RAU & RAU_ROUND_DISABLE) && rnd_rq) + acc.mantissa |= 1; + + if (! acc.mantissa && ! (RAU & RAU_NORM_DISABLE)) { +zero: ACC = 0; + RMR &= ~BITS40; + return; + } + + ACC = (t_value) (acc.exponent & BITS(7)) << 41 | + (acc.mantissa & BITS41); + RMR = (RMR & ~BITS40) | (mr & BITS40); + /* При переполнении мантисса и младшие разряды порядка верны */ + if (acc.exponent & 0x80) { + if (! (RAU & RAU_OVF_DISABLE)) + longjmp (cpu_halt, STOP_OVFL); + } +} + +/* + * Сложение и все варианты вычитаний. + * Исходные значения: регистр ACC и аргумент 'val'. + * Результат помещается в регистр ACC и 40-1 разряды RMR. + */ +void besm6_add (t_value val, int negate_acc, int negate_val) +{ + t_uint64 mr; + alureg_t acc, word, a1, a2; + int diff, neg, rnd_rq = 0; + + acc = toalu (ACC); + word = toalu (val); + if (! negate_acc) { + if (! negate_val) { + /* Сложение */ + } else { + /* Вычитание */ + negate (&word); + } + } else { + if (! negate_val) { + /* Обратное вычитание */ + negate (&acc); + } else { + /* Вычитание модулей */ + if (is_negative (&acc)) + negate (&acc); + if (! is_negative (&word)) + negate (&word); + } + } + + diff = acc.exponent - word.exponent; + if (diff < 0) { + diff = -diff; + a1 = acc; + a2 = word; + } else { + a1 = word; + a2 = acc; + } + mr = 0; + neg = is_negative (&a1); + if (diff == 0) { + /* Nothing to do. */ + } else if (diff <= 40) { + rnd_rq = (mr = (a1.mantissa << (40 - diff)) & BITS40) != 0; + a1.mantissa = ((a1.mantissa >> diff) | + (neg ? (~0ll << (40 - diff)) : 0)) & BITS42; + } else if (diff <= 80) { + diff -= 40; + rnd_rq = a1.mantissa != 0; + mr = ((a1.mantissa >> diff) | + (neg ? (~0ll << (40 - diff)) : 0)) & BITS40; + if (neg) { + a1.mantissa = BITS42; + } else + a1.mantissa = 0; + } else { + rnd_rq = a1.mantissa != 0; + if (neg) { + mr = BITS40; + a1.mantissa = BITS42; + } else + mr = a1.mantissa = 0; + } + acc.exponent = a2.exponent; + acc.mantissa = a1.mantissa + a2.mantissa; + + /* Если требуется нормализация вправо, биты 42:41 + * принимают значение 01 или 10. */ + switch ((acc.mantissa >> 40) & 3) { + case 2: + case 1: + rnd_rq |= acc.mantissa & 1; + mr = (mr >> 1) | ((acc.mantissa & 1) << 39); + acc.mantissa >>= 1; + ++acc.exponent; + } + normalize_and_round (acc, mr, rnd_rq); +} + +/* + * non-restoring division + */ +#define ABS(x) ((x) < 0 ? -x : x) +#define INT64(x) ((x) & BIT41 ? (-1LL << 40) | (x) : x) +static alureg_t nrdiv (alureg_t n, alureg_t d) +{ + t_int64 nn, dd, q, res; + alureg_t quot; + + /* to compensate for potential normalization to the right */ + nn = INT64(n.mantissa)*2; + dd = INT64(d.mantissa)*2; + res = 0, q = BIT41; + + if (ABS(nn) >= ABS(dd)) { + /* normalization to the right */ + nn/=2; + n.exponent++; + } + while (q > 1) { + if (nn == 0) + break; + + if (ABS(nn) < BIT40) + nn *= 2; /* magic shortcut */ + else if ((nn > 0) ^ (dd > 0)) { + res -= q; + nn = 2*nn+dd; + } else { + res += q; + nn = 2*nn-dd; + } + q /= 2; + } + quot.mantissa = res/2; + quot.exponent = n.exponent-d.exponent+64; + return quot; +} + +/* + * Деление. + * Исходные значения: регистр ACC и аргумент 'val'. + * Результат помещается в регистр ACC, содержимое RMR не определено. + */ +void besm6_divide (t_value val) +{ + alureg_t acc; + alureg_t dividend, divisor; + + if (((val ^ (val << 1)) & BIT41) == 0) { + /* Ненормализованный делитель: деление на ноль. */ + longjmp (cpu_halt, STOP_DIVZERO); + } + dividend = toalu(ACC); + divisor = toalu(val); + + acc = nrdiv(dividend, divisor); + + normalize_and_round (acc, 0, 0); +} + +/* + * Умножение. + * Исходные значения: регистр ACC и аргумент 'val'. + * Результат помещается в регистр ACC и 40-1 разряды RMR. + */ +void besm6_multiply (t_value val) +{ + uint8 neg = 0; + alureg_t acc, word, a, b; + t_uint64 mr, alo, blo, ahi, bhi; + + register t_uint64 l; + + if (! ACC || ! val) { + /* multiplication by zero is zero */ + ACC = 0; + RMR &= ~BITS40; + return; + } + acc = toalu (ACC); + word = toalu (val); + + a = acc; + b = word; + mr = 0; + + if (is_negative (&a)) { + neg = 1; + negate (&a); + } + if (is_negative (&b)) { + neg ^= 1; + negate (&b); + } + acc.exponent = a.exponent + b.exponent - 64; + + alo = a.mantissa & BITS(20); + ahi = a.mantissa >> 20; + + blo = b.mantissa & BITS(20); + bhi = b.mantissa >> 20; + + l = alo * blo + ((alo * bhi + ahi * blo) << 20); + + mr = l & BITS40; + l >>= 40; + + acc.mantissa = l + ahi * bhi; + + if (neg) { + mr = (~mr & BITS40) + 1; + acc.mantissa = ((~acc.mantissa & BITS40) + (mr >> 40)) + | BIT41 | BIT42; + mr &= BITS40; + } + + normalize_and_round (acc, mr, mr != 0); +} + +/* + * Изменение знака числа на сумматоре ACC. + * Результат помещается в регистр ACC, RMR гасится. + */ +void besm6_change_sign (int negate_acc) +{ + alureg_t acc; + + acc = toalu (ACC); + if (negate_acc) + negate (&acc); + RMR = 0; + normalize_and_round (acc, 0, 0); +} + +/* + * Изменение порядка числа на сумматоре ACC. + * Результат помещается в регистр ACC, RMR гасится. + */ +void besm6_add_exponent (int val) +{ + alureg_t acc; + + acc = toalu (ACC); + acc.exponent += val; + RMR = 0; + normalize_and_round (acc, 0, 0); +} + +/* + * Сборка значения по маске. + */ +t_value besm6_pack (t_value val, t_value mask) +{ + t_value result; + + result = 0; + for (; mask; mask>>=1, val>>=1) + if (mask & 1) { + result >>= 1; + if (val & 1) + result |= BIT48; + } + return result; +} + +/* + * Разборка значения по маске. + */ +t_value besm6_unpack (t_value val, t_value mask) +{ + t_value result; + int i; + + result = 0; + for (i=0; i<48; ++i) { + result <<= 1; + if (mask & BIT48) { + if (val & BIT48) + result |= 1; + val <<= 1; + } + mask <<= 1; + } + return result; +} + +/* + * Подсчёт количества единиц в слове. + */ +int besm6_count_ones (t_value word) +{ + int c; + + for (c=0; word; ++c) + word &= word-1; + return c; +} + +/* + * Сдвиг сумматора ACC с выдвижением в регистр младших разрядов RMR. + * Величина сдвига находится в диапазоне -64..63. + */ +void besm6_shift (int i) +{ + RMR = 0; + if (i > 0) { + /* Сдвиг вправо. */ + if (i < 48) { + RMR = (ACC << (48-i)) & BITS48; + ACC >>= i; + } else { + RMR = ACC >> (i-48); + ACC = 0; + } + } else if (i < 0) { + /* Сдвиг влево. */ + i = -i; + if (i < 48) { + RMR = ACC >> (48-i); + ACC = (ACC << i) & BITS48; + } else { + RMR = (ACC << (i-48)) & BITS48; + ACC = 0; + } + } +} diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 50b92fe9..4b782a1e 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -1,1768 +1,1768 @@ -/* - * BESM-6 CPU simulator. - * - * Copyright (c) 1997-2009, Leonid Broukhis - * 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. - - * For more information about BESM-6 computer, visit sites: - * - http://www.computer-museum.ru/english/besm6.htm - * - http://mailcom.com/besm6/ - * - http://groups.google.com/group/besm6 - * - * Release notes for BESM-6/SIMH - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * 1) All addresses and data values are displayed in octal. - * 2) Memory size is 128 kwords. - * 3) Interrupt system is to be synchronized with wallclock time. - * 4) Execution times are in 1/10 of microsecond. - * 5) Magnetic drums are implemented as a single "DRUM" device. - * 6) Magnetic disks are implemented. - * 7) Magnetic tape is not implemented. - * 8) Punch tape reader is implemented, punch card reader is planned. - * 9) Card puncher is not implemented. - * 10) Displays are implemented. - * 11) Printer АЦПУ-128 is implemented. - * 12) Instruction mnemonics, register names and stop messages - * are in Russian using UTF-8 encoding. It is assumed, that - * user locale is UTF-8. - * 13) A lot of comments in Russian (UTF-8). - */ -#include "besm6_defs.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#undef SOFT_CLOCK - -t_value memory [MEMSIZE]; -uint32 PC, RK, Aex, M [NREGS], RAU, RUU; -t_value ACC, RMR, GRP, MGRP; -uint32 PRP, MPRP; -uint32 READY, READY2; /* ready flags of various devices */ - -extern const char *scp_errors[]; - -/* нехранящие биты ГРП должны сбрасываться путем обнуления тех регистров, - * сборкой которых они являются - */ -#define GRP_WIRED_BITS 01400743700000000LL - -#define PRP_WIRED_BITS 0770000 - -int corr_stack; -int redraw_panel; -uint32 delay; -jmp_buf cpu_halt; - -t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); - -/* - * CPU data structures - * - * cpu_dev CPU device descriptor - * cpu_unit CPU unit descriptor - * cpu_reg CPU register list - * cpu_mod CPU modifiers list - */ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MEMSIZE) }; - -REG cpu_reg[] = { -{ "СчАС", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ -{ "РК", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ -{ "Аисп", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ -{ "СМ", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ -{ "РМР", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ -{ "РАУ", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ -{ "М1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ -{ "М2", &M[2], 8, 15, 0, 1 }, -{ "М3", &M[3], 8, 15, 0, 1 }, -{ "М4", &M[4], 8, 15, 0, 1 }, -{ "М5", &M[5], 8, 15, 0, 1 }, -{ "М6", &M[6], 8, 15, 0, 1 }, -{ "М7", &M[7], 8, 15, 0, 1 }, -{ "М10", &M[010], 8, 15, 0, 1 }, -{ "М11", &M[011], 8, 15, 0, 1 }, -{ "М12", &M[012], 8, 15, 0, 1 }, -{ "М13", &M[013], 8, 15, 0, 1 }, -{ "М14", &M[014], 8, 15, 0, 1 }, -{ "М15", &M[015], 8, 15, 0, 1 }, -{ "М16", &M[016], 8, 15, 0, 1 }, -{ "М17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ -{ "М20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ -{ "М21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ -{ "М27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ -{ "М32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ -{ "М33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ -{ "М34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ -{ "М35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ -{ "РУУ", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ -{ "ГРП", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ -{ "МГРП", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ -{ "ПРП", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ -{ "МПРП", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ -{ 0 } -}; - -MTAB cpu_mod[] = { - { 0 } -}; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 17, 1, 8, 50, - &cpu_examine, &cpu_deposit, &cpu_reset, - NULL, NULL, NULL, NULL, - DEV_DEBUG -}; - -/* - * REG: псевдоустройство, содержащее латинские синонимы всех регистров. - */ -REG reg_reg[] = { -{ "PC", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ -{ "RK", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ -{ "Aex", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ -{ "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ -{ "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ -{ "RAU", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ -{ "M1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ -{ "M2", &M[2], 8, 15, 0, 1 }, -{ "M3", &M[3], 8, 15, 0, 1 }, -{ "M4", &M[4], 8, 15, 0, 1 }, -{ "M5", &M[5], 8, 15, 0, 1 }, -{ "M6", &M[6], 8, 15, 0, 1 }, -{ "M7", &M[7], 8, 15, 0, 1 }, -{ "M10", &M[010], 8, 15, 0, 1 }, -{ "M11", &M[011], 8, 15, 0, 1 }, -{ "M12", &M[012], 8, 15, 0, 1 }, -{ "M13", &M[013], 8, 15, 0, 1 }, -{ "M14", &M[014], 8, 15, 0, 1 }, -{ "M15", &M[015], 8, 15, 0, 1 }, -{ "M16", &M[016], 8, 15, 0, 1 }, -{ "M17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ -{ "M20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ -{ "M21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ -{ "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ -{ "M32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ -{ "M33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ -{ "M34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ -{ "M35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ -{ "RUU", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ -{ "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ -{ "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ -{ "PRP", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ -{ "MPRP", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ - -{ "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BAZ0", &BAZ[0], 8, 16, 0, 1 }, -{ "BAZ1", &BAZ[1], 8, 16, 0, 1 }, -{ "BAZ2", &BAZ[2], 8, 16, 0, 1 }, -{ "BAZ3", &BAZ[3], 8, 16, 0, 1 }, -{ "BAZ4", &BAZ[4], 8, 16, 0, 1 }, -{ "BAZ5", &BAZ[5], 8, 16, 0, 1 }, -{ "BAZ6", &BAZ[6], 8, 16, 0, 1 }, -{ "BAZ7", &BAZ[7], 8, 16, 0, 1 }, -{ "TABST", &TABST, 8, 28, 0, 1 }, -{ "RP0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RZ", &RZ, 8, 32, 0, 1 }, -{ "FP1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ 0 } -}; - -UNIT reg_unit = { - UDATA (NULL, 0, 8) -}; - -DEVICE reg_dev = { - "REG", ®_unit, reg_reg, NULL, - 1, 8, 1, 1, 8, 50, -}; - -/* - * SCP data structures and interface routines - * - * sim_name simulator name string - * sim_PC pointer to saved PC register descriptor - * sim_emax maximum number of words for examine/deposit - * sim_devices array of pointers to simulated devices - * sim_stop_messages array of pointers to stop messages - * sim_load binary loader - */ - -char sim_name[] = "БЭСМ-6"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; /* максимальное количество слов в машинной команде */ - -DEVICE *sim_devices[] = { - &cpu_dev, - ®_dev, - &drum_dev, - &disk_dev, - &mmu_dev, - &clock_dev, - &printer_dev, - &fs_dev, - &tty_dev, /* терминалы - телетайпы, видеотоны, "Консулы" */ - 0 -}; - -const char *sim_stop_messages[] = { - "Неизвестная ошибка", /* Unknown error */ - "Останов", /* STOP */ - "Точка останова", /* Emulator breakpoint */ - "Точка останова по считыванию", /* Emulator read watchpoint */ - "Точка останова по записи", /* Emulator write watchpoint */ - "Выход за пределы памяти", /* Run out end of memory */ - "Запрещенная команда", /* Invalid instruction */ - "Контроль команды", /* A data-tagged word fetched */ - "Команда в чужом листе", /* Paging error during fetch */ - "Число в чужом листе", /* Paging error during load/store */ - "Контроль числа МОЗУ", /* RAM parity error */ - "Контроль числа БРЗ", /* Write cache parity error */ - "Переполнение АУ", /* Arith. overflow */ - "Деление на нуль", /* Division by zero or denorm */ - "Двойное внутреннее прерывание", /* SIMH: Double internal interrupt */ - "Чтение неформатированного барабана", /* Reading unformatted drum */ - "Чтение неформатированного диска", /* Reading unformatted disk */ - "Останов по КРА", /* Hardware breakpoint */ - "Останов по считыванию", /* Load watchpoint */ - "Останов по записи", /* Store watchpoint */ - "Не реализовано", /* Unimplemented I/O or special reg. access */ -}; - -/* - * Memory examine - */ -t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MEMSIZE) - return SCPE_NXM; - if (vptr) { - if (addr < 010) - *vptr = pult [addr]; - else - *vptr = memory [addr]; - } - return SCPE_OK; -} - -/* - * Memory deposit - */ -t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MEMSIZE) - return SCPE_NXM; - if (addr < 010) - pult [addr] = SET_CONVOL (val, CONVOL_INSN); - else - memory [addr] = SET_CONVOL (val, CONVOL_INSN); - return SCPE_OK; -} - -/* - * Функция вызывается каждые 4 миллисекунды реального времени. - */ -static void cpu_sigalarm (int signum) -{ - static unsigned counter; - - ++counter; - -#ifndef SOFT_CLOCK - /* В 9-й части частота таймера 250 Гц (4 мс). */ - GRP |= GRP_TIMER; - - /* Медленный таймер: должен быть 16 Гц. - * Но от него почему-то зависит вывод на терминалы, - * поэтому ускорим. */ - if ((counter & 3) == 0) { - GRP |= GRP_SLOW_CLK; - } -#endif - - /* Перерисовка панели каждые 64 миллисекунды. */ - if ((counter & 15) == 0) { - redraw_panel = 1; - } -} - -/* - * Reset routine - */ -t_stat cpu_reset (DEVICE *dptr) -{ - int i; - - ACC = 0; - RMR = 0; - RAU = 0; - RUU = RUU_EXTRACODE | RUU_AVOST_DISABLE; - for (i=0; i 0xxxxxxx - * 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy - * xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz - */ -void -utf8_putc (unsigned ch, FILE *fout) -{ - if (ch < 0x80) { - putc (ch, fout); - return; - } - if (ch < 0x800) { - putc (ch >> 6 | 0xc0, fout); - putc ((ch & 0x3f) | 0x80, fout); - return; - } - putc (ch >> 12 | 0xe0, fout); - putc (((ch >> 6) & 0x3f) | 0x80, fout); - putc ((ch & 0x3f) | 0x80, fout); -} - -/* - * *call ОКНО - так называлась служебная подпрограмма в мониторной - * системе "Дубна", которая печатала полное состояние всех регистров. - */ -void besm6_okno (const char *message) -{ - besm6_log_cont ("_%%%%%% %s: ", message); - if (sim_log) - besm6_fprint_cmd (sim_log, RK); - besm6_log ("_"); - - /* СчАС, системные индекс-регистры 020-035. */ - besm6_log ("_ СчАС:%05o 20:%05o 21:%05o 27:%05o 32:%05o 33:%05o 34:%05o 35:%05o", - PC, M[020], M[021], M[027], M[032], M[033], M[034], M[035]); - /* Индекс-регистры 1-7. */ - besm6_log ("_ 1:%05o 2:%05o 3:%05o 4:%05o 5:%05o 6:%05o 7:%05o", - M[1], M[2], M[3], M[4], M[5], M[6], M[7]); - /* Индекс-регистры 010-017. */ - besm6_log ("_ 10:%05o 11:%05o 12:%05o 13:%05o 14:%05o 15:%05o 16:%05o 17:%05o", - M[010], M[011], M[012], M[013], M[014], M[015], M[016], M[017]); - /* Сумматор, РМР, режимы АУ и УУ. */ - besm6_log ("_ СМ:%04o %04o %04o %04o РМР:%04o %04o %04o %04o РАУ:%02o РУУ:%03o", - (int) (ACC >> 36) & BITS(12), (int) (ACC >> 24) & BITS(12), - (int) (ACC >> 12) & BITS(12), (int) ACC & BITS(12), - (int) (RMR >> 36) & BITS(12), (int) (RMR >> 24) & BITS(12), - (int) (RMR >> 12) & BITS(12), (int) RMR & BITS(12), - RAU, RUU); -} - -/* - * Команда "рег" - */ -static void cmd_002 () -{ -#if 0 - besm6_debug ("*** рег %03o", Aex & 0377); -#endif - switch (Aex & 0377) { - case 0 ... 7: - /* Запись в БРЗ */ - mmu_setcache (Aex & 7, ACC); - break; - case 020 ... 027: - /* Запись в регистры приписки */ - mmu_setrp (Aex & 7, ACC); - break; - case 030 ... 033: - /* Запись в регистры защиты */ - mmu_setprotection (Aex & 3, ACC); - break; - case 036: - /* Запись в маску главного регистра прерываний */ - MGRP = ACC; - break; - case 037: - /* Гашение главного регистра прерываний */ - /* нехранящие биты невозможно погасить */ - GRP &= ACC | GRP_WIRED_BITS; - break; - case 0100 ... 0137: - /* Бит 1: управление блокировкой режима останова БРО. - * Биты 2 и 3 - признаки формирования контрольных - * разрядов (ПКП и ПКЛ). */ - if (Aex & 1) - RUU |= RUU_AVOST_DISABLE; - else - RUU &= ~RUU_AVOST_DISABLE; - if (Aex & 2) - RUU |= RUU_CONVOL_RIGHT; - else - RUU &= ~RUU_CONVOL_RIGHT; - if (Aex & 4) - RUU |= RUU_CONVOL_LEFT; - else - RUU &= ~RUU_CONVOL_LEFT; - break; - case 0140 ... 0177: - /* TODO: управление блокировкой схемы - * автоматического запуска */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0200 ... 0207: - /* Чтение БРЗ */ - ACC = mmu_getcache (Aex & 7); - break; - case 0237: - /* Чтение главного регистра прерываний */ - ACC = GRP; - break; - default: - /* Неиспользуемые адреса */ - besm6_debug ("*** %05o%s: РЕГ %o - неправильный адрес спец.регистра", - PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); - break; - } -} - -/* - * Команда "увв" - */ -static void cmd_033 () -{ -#if 0 - besm6_debug ("*** увв %04o, СМ[24:1]=%08o", - Aex & 04177, (uint32) ACC & BITS(24)); -#endif - switch (Aex & 04177) { - case 0: - /* Точно неизвестно, что это такое, но драйвер МД - * иногда выдает команду "увв 0". */ - break; - case 1 ... 2: - /* Управление обменом с магнитными барабанами */ - drum (Aex - 1, (uint32) ACC); - break; - case 3 ... 4: - /* Передача управляющего слова для обмена - * с магнитными дисками */ - disk_io (Aex - 3, (uint32) ACC); - break; - case 5 ... 7: - /* TODO: управление обменом с магнитными лентами */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 010 ... 011: - /* управление устройствами ввода с перфоленты */ - fs_control (Aex - 010, (uint32) (ACC & 07)); - break; - case 012 ... 013: - /* TODO: управление устройствами ввода с перфоленты по запаянной программе */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 014 ... 015: - /* Управление АЦПУ */ - printer_control (Aex - 014, (uint32) (ACC & 017)); - break; - case 023 ... 024: - /* Управление обменом с магнитными дисками */ - disk_ctl (Aex - 023, (uint32) ACC); - break; - case 030: - /* Гашение ПРП */ -/* besm6_debug(">>> гашение ПРП");*/ - PRP &= ACC | PRP_WIRED_BITS; - break; - case 031: - /* Имитация сигналов прерывания ГРП */ - /*besm6_debug ("*** %05o%s: имитация прерываний ГРП %016llo", - PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", ACC << 24);*/ - GRP |= (ACC & BITS(24)) << 24; - break; - case 032 ... 033: - /* TODO: имитация сигналов из КМБ в КВУ */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 034: - /* Запись в МПРП */ -/* besm6_debug(">>> запись в МПРП");*/ - MPRP = ACC & 077777777; - break; - case 035: - /* TODO: управление режимом имитации обмена - * с МБ и МЛ, имитация обмена */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 040 ... 057: - /* Управление молоточками АЦПУ */ - printer_hammer (Aex >= 050, Aex & 7, (uint32) (ACC & BITS(16))); - break; - case 0100 ... 0137: - /* Управление лентопротяжными механизмами - * и гашение разрядов регистров признаков - * окончания подвода зоны. Игнорируем. */ - break; - case 0140: - /* Запись в регистр телеграфных каналов */ - tty_send ((uint32) ACC & BITS(24)); - break; - case 0141: - /* TODO: управление разметкой магнитной ленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0142: - /* TODO: имитация сигналов прерывания ПРП */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0147: - /* Запись в регистр управления электропитанием, */ - /* не оказывает видимого эффекта на выполнение */ - break; - case 0150 ... 0151: - /* TODO: управление вводом с перфокарт */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0153: - /* гашение аппаратуры сопряжения с терминалами */ -/* besm6_debug(">>> гашение АС: %08o", (uint32) ACC & BITS(24));*/ - break; - case 0154 ... 0155: - /* TODO: управление выводом на перфокарты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0160 ... 0167: - /* TODO: управление электромагнитами пробивки перфокарт */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0170 ... 0171: - /* TODO: пробивка строки на перфоленте */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0174 ... 0175: - /* Выдача кода в пульт оператора */ - consul_print (Aex & 1, (uint32) ACC & BITS(8)); - break; - case 0177: - /* управление табло ГПВЦ СО АН СССР */ -/* besm6_debug(">>> ТАБЛО: %08o", (uint32) ACC & BITS(24));*/ - break; - case 04001 ... 04002: - /* TODO: считывание слога в режиме имитации обмена */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04003 ... 04004: - /* Запрос статуса контроллера магнитных дисков */ - ACC = disk_state (Aex - 04003); - break; - case 04006: - /* TODO: считывание строки с устройства ввода - * с перфоленты в запаянной программе */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04007: - /* TODO: опрос синхроимпульса ненулевой строки - * в запаянной программе ввода с перфоленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04014 ... 04015: - /* считывание строки с устройства ввода с перфоленты */ - ACC = fs_read (Aex - 04014); - break; - case 04016 ... 04017: - /* TODO: считывание строки с устройства - * ввода с перфоленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04020 ... 04023: - /* TODO: считывание слога в режиме имитации - * внешнего обмена */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04030: - /* Чтение старшей половины ПРП */ - ACC = PRP & 077770000; - break; - case 04031: - /* Опрос сигналов готовности (АЦПУ и пр.) */ -/* besm6_debug("Reading READY");*/ - ACC = READY; - break; - case 04034: - /* Чтение младшей половины ПРП */ - ACC = (PRP & 07777) | 0377; - break; - case 04035: - /* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */ - ACC = drum_errors() | disk_errors(); - break; - case 04100: - /* Опрос телеграфных каналов связи */ - ACC = tty_query (); - break; - case 04102: - /* Опрос сигналов готовности перфокарт и перфолент */ -/* besm6_debug("Reading punchcard/punchtape READY @%05o", PC);*/ - ACC = READY2; - break; - case 04103 ... 04106: - /* Опрос состояния лентопротяжных механизмов. - * Все устройства не готовы. */ - ACC = BITS(24); - break; - case 04107: - /* TODO: опрос схемы контроля записи на МЛ */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04115: - /* Неизвестное обращение. ДИСПАК выдаёт эту команду - * группами по 8 штук каждые несколько секунд. */ - ACC = 0; - break; - case 04140 ... 04157: - /* TODO: считывание строки перфокарты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04160 ... 04167: - /* TODO: контрольное считывание строки перфокарты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04170 ... 04173: - /* TODO: считывание контрольного кода - * строки перфоленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04174 ... 04175: - /* Считывание кода с пульта оператора */ - ACC = consul_read (Aex & 1); - break; - case 04177: - /* чтение табло ГПВЦ СО АН СССР */ - ACC = 0; - break; - default: - /* Неиспользуемые адреса */ -/* if (sim_deb && cpu_dev.dctrl)*/ - besm6_debug ("*** %05o%s: УВВ %o - неправильный адрес ввода-вывода", - PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); - ACC = 0; - break; - } -} - -void check_initial_setup () -{ - const int MGRP_COPY = 01455; /* OS version specific? */ - const int TAKEN = 0442; /* fixed? */ - const int YEAR = 0221; /* fixed */ - - /* 47 р. яч. ЗАНЯТА - разр. приказы вообще */ - const t_value SETUP_REQS_ENABLED = 1LL << 46; - - /* 7 р. яч. ЗАНЯТА - разр любые приказы */ - const t_value ALL_REQS_ENABLED = 1 << 6; - - if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || - (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || - (MGRP & GRP_PANEL_REQ) == 0) { - /* Слишком рано, или уже не надо, или невовремя */ - return; - } - - /* Выдаем приказы оператора СМЕ и ВРЕ, - * а дату корректируем непосредственно в памяти. - */ - /* Номер смены в 22-24 рр. МГРП: если еще не установлен, установить */ - if (((memory[MGRP_COPY] >> 21) & 3) == 0) { - /* приказ СМЕ: ТР6 = 010, ТР4 = 1, 22-24 р ТР5 - #смены */ - pult[6] = 010; - pult[4] = 1; - pult[5] = 1 << 21; - GRP |= GRP_PANEL_REQ; - } else { - /* Яч. ГОД обновляем самостоятельно */ - time_t t; - t_value date; - time(&t); - struct tm * d; - d = localtime(&t); - ++d->tm_mon; - date = (t_value) (d->tm_mday / 10) << 33 | - (t_value) (d->tm_mday % 10) << 29 | - (d->tm_mon / 10) << 28 | - (d->tm_mon % 10) << 24 | - (d->tm_year % 10) << 20 | - ((d->tm_year / 10) % 10) << 16 | - (memory[YEAR] & 7); - memory[YEAR] = SET_CONVOL (date, CONVOL_NUMBER); - /* приказ ВРЕ: ТР6 = 016, ТР5 = 9-14 р.-часы, 1-8 р.-минуты */ - pult[6] = 016; - pult[4] = 0; - pult[5] = (d->tm_hour / 10) << 12 | - (d->tm_hour % 10) << 8 | - (d->tm_min / 10) << 4 | - (d->tm_min % 10); - GRP |= GRP_PANEL_REQ; - } -} - -/* - * Execute one instruction, placed on address PC:RUU_RIGHT_INSTR. - * Increment delay. When stopped, perform a longjmp to cpu_halt, - * sending a stop code. - */ -void cpu_one_inst () -{ - int reg, opcode, addr, nextpc, next_mod; - - corr_stack = 0; - t_value word = mmu_fetch (PC); - if (RUU & RUU_RIGHT_INSTR) - RK = word; /* get right instruction */ - else - RK = word >> 24; /* get left instruction */ - - RK &= BITS(24); - - reg = RK >> 20; - if (RK & BBIT(20)) { - addr = RK & BITS(15); - opcode = (RK >> 12) & 0370; - } else { - addr = RK & BITS(12); - if (RK & BBIT(19)) - addr |= 070000; - opcode = (RK >> 12) & 077; - } - - if (sim_deb && cpu_dev.dctrl) { - fprintf (sim_deb, "*** %05o%s: ", PC, - (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); - besm6_fprint_cmd (sim_deb, RK); - fprintf (sim_deb, "\tСМ="); - fprint_sym (sim_deb, 0, &ACC, 0, 0); - fprintf (sim_deb, "\tРАУ=%02o", RAU); - if (reg) - fprintf (sim_deb, "\tМ[%o]=%05o", reg, M[reg]); - fprintf (sim_deb, "\n"); - } - nextpc = ADDR(PC + 1); - if (RUU & RUU_RIGHT_INSTR) { - PC += 1; /* increment PC */ - RUU &= ~RUU_RIGHT_INSTR; - } else { - mmu_prefetch(nextpc | (IS_SUPERVISOR(RUU) ? BBIT(16) : 0), 0); - RUU |= RUU_RIGHT_INSTR; - } - - if (RUU & RUU_MOD_RK) { - addr = ADDR (addr + M[MOD]); - } - next_mod = 0; - delay = 0; - - switch (opcode) { - case 000: /* зп, atx */ - Aex = ADDR (addr + M[reg]); - mmu_store (Aex, ACC); - if (! addr && reg == 017) - M[017] = ADDR (M[017] + 1); - delay = MEAN_TIME (3, 3); - break; - case 001: /* зпм, stx */ - Aex = ADDR (addr + M[reg]); - mmu_store (Aex, ACC); - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - ACC = mmu_load (M[017]); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (6, 6); - break; - case 002: /* рег, mod */ - Aex = ADDR (addr + M[reg]); - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - cmd_002 (); - /* Режим АУ - логический, если операция была "чтение" */ - if (Aex & 0200) - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 003: /* счм, xts */ - mmu_store (M[017], ACC); - M[017] = ADDR (M[017] + 1); - corr_stack = -1; - Aex = ADDR (addr + M[reg]); - ACC = mmu_load (Aex); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (6, 6); - break; - case 004: /* сл, a+x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 0, 0); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 005: /* вч, a-x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 0, 1); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 006: /* вчоб, x-a */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 1, 0); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 007: /* вчаб, amx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 1, 1); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 010: /* сч, xta */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = mmu_load (Aex); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 011: /* и, aax */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC &= mmu_load (Aex); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4); - break; - case 012: /* нтж, aex */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - RMR = ACC; - ACC ^= mmu_load (Aex); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 013: /* слц, arx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC += mmu_load (Aex); - if (ACC & BIT49) - ACC = (ACC + 1) & BITS48; - RMR = 0; - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 6); - break; - case 014: /* знак, avx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_change_sign (mmu_load (Aex) >> 40 & 1); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 015: /* или, aox */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC |= mmu_load (Aex); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4); - break; - case 016: /* дел, a/x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_divide (mmu_load (Aex)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 50); - break; - case 017: /* умн, a*x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_multiply (mmu_load (Aex)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 18); - break; - case 020: /* сбр, apx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = besm6_pack (ACC, mmu_load (Aex)); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 53); - break; - case 021: /* рзб, aux */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = besm6_unpack (ACC, mmu_load (Aex)); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 53); - break; - case 022: /* чед, acx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = besm6_count_ones (ACC) + mmu_load (Aex); - if (ACC & BIT49) - ACC = (ACC + 1) & BITS48; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 56); - break; - case 023: /* нед, anx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - if (ACC) { - int n = besm6_highest_bit (ACC); - - /* "Остаток" сумматора, исключая бит, - * номер которого определен, помещается в РМР, - * начиная со старшего бита РМР. */ - besm6_shift (48 - n); - - /* Циклическое сложение номера со словом по Аисп. */ - ACC = n + mmu_load (Aex); - if (ACC & BIT49) - ACC = (ACC + 1) & BITS48; - } else { - RMR = 0; - ACC = mmu_load (Aex); - } - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 32); - break; - case 024: /* слп, e+x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add_exponent ((mmu_load (Aex) >> 41) - 64); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 025: /* вчп, e-x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add_exponent (64 - (mmu_load (Aex) >> 41)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 026: { /* сд, asx */ - int n; - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - n = (mmu_load (Aex) >> 41) - 64; - besm6_shift (n); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4 + abs (n)); - break; - } - case 027: /* рж, xtr */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - RAU = (mmu_load (Aex) >> 41) & 077; - delay = MEAN_TIME (3, 3); - break; - case 030: /* счрж, rte */ - Aex = ADDR (addr + M[reg]); - ACC = (t_value) (RAU & Aex & 0177) << 41; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 031: /* счмр, yta */ - Aex = ADDR (addr + M[reg]); - if (IS_LOGICAL (RAU)) { - ACC = RMR; - } else { - t_value x = RMR; - ACC = (ACC & ~BITS41) | (RMR & BITS40); - besm6_add_exponent ((Aex & 0177) - 64); - RMR = x; - } - delay = MEAN_TIME (3, 5); - break; - case 032: /* э32, ext */ - /* Fall through... */ - case 033: /* увв, ext */ - Aex = ADDR (addr + M[reg]); - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - cmd_033 (); - /* Режим АУ - логический, если операция была "чтение" */ - if (Aex & 04000) - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 8); - break; - case 034: /* слпа, e+n */ - Aex = ADDR (addr + M[reg]); - besm6_add_exponent ((Aex & 0177) - 64); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 035: /* вчпа, e-n */ - Aex = ADDR (addr + M[reg]); - besm6_add_exponent (64 - (Aex & 0177)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 036: { /* сда, asn */ - int n; - Aex = ADDR (addr + M[reg]); - n = (Aex & 0177) - 64; - besm6_shift (n); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4 + abs (n)); - break; - } - case 037: /* ржа, ntr */ - Aex = ADDR (addr + M[reg]); - RAU = Aex & 077; - delay = MEAN_TIME (3, 3); - break; - case 040: /* уи, ati */ - Aex = ADDR (addr + M[reg]); - if (IS_SUPERVISOR (RUU)) { - int reg = Aex & 037; - M[reg] = ADDR (ACC); - /* breakpoint/watchpoint regs will match physical - * or virtual addresses depending on the current - * mapping mode. - */ - if ((M[PSW] & PSW_MMAP_DISABLE) && - (reg == IBP || reg == DWP)) - M[reg] |= BBIT(16); - - } else - M[Aex & 017] = ADDR (ACC); - M[0] = 0; - delay = MEAN_TIME (14, 3); - break; - case 041: { /* уим, sti */ - unsigned rg, ad; - - Aex = ADDR (addr + M[reg]); - rg = Aex & (IS_SUPERVISOR (RUU) ? 037 : 017); - ad = ADDR (ACC); - if (rg != 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - ACC = mmu_load (rg != 017 ? M[017] : ad); - M[rg] = ad; - if ((M[PSW] & PSW_MMAP_DISABLE) && (rg == IBP || rg == DWP)) - M[rg] |= BBIT(16); - M[0] = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (14, 3); - break; - } - case 042: /* счи, ita */ - delay = MEAN_TIME (6, 3); -load_modifier: Aex = ADDR (addr + M[reg]); - ACC = ADDR(M[Aex & (IS_SUPERVISOR (RUU) ? 037 : 017)]); - RAU = SET_LOGICAL (RAU); - break; - case 043: /* счим, its */ - mmu_store (M[017], ACC); - M[017] = ADDR (M[017] + 1); - delay = MEAN_TIME (9, 6); - goto load_modifier; - case 044: /* уии, mtj */ - Aex = addr; - if (IS_SUPERVISOR (RUU)) { -transfer_modifier: M[Aex & 037] = M[reg]; - if ((M[PSW] & PSW_MMAP_DISABLE) && - ((Aex & 037) == IBP || (Aex & 037) == DWP)) - M[Aex & 037] |= BBIT(16); - - } else - M[Aex & 017] = M[reg]; - M[0] = 0; - delay = 6; - break; - case 045: /* сли, j+m */ - Aex = addr; - if ((Aex & 020) && IS_SUPERVISOR (RUU)) - goto transfer_modifier; - M[Aex & 017] = ADDR (M[Aex & 017] + M[reg]); - M[0] = 0; - delay = 6; - break; - case 046: /* э46, x46 */ - Aex = addr; - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - M[Aex & 017] = ADDR (Aex); - M[0] = 0; - delay = 6; - break; - case 047: /* э47, x47 */ - Aex = addr; - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - M[Aex & 017] = ADDR (M[Aex & 017] + Aex); - M[0] = 0; - delay = 6; - break; - case 050 ... 077: /* э50...э77 */ - case 0200: /* э20 */ - case 0210: /* э21 */ - stop_as_extracode: - Aex = ADDR (addr + M[reg]); - if (! sim_deb && sim_log && cpu_dev.dctrl && opcode != 075) { - /* Если включен console log и cpu debug, - * но нет console debug, то печатаем только экстракоды. - * Пропускаем э75, их обычно слишком много. */ - t_value word = mmu_load (Aex); - fprintf (sim_log, "*** %05o%s: ", PC, - (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); - besm6_fprint_cmd (sim_log, RK); - fprintf (sim_log, "\tАисп=%05o (=", Aex); - fprint_sym (sim_log, 0, &word, 0, 0); - fprintf (sim_log, ") СМ="); - fprint_sym (sim_log, 0, &ACC, 0, 0); - if (reg) - fprintf (sim_log, " М[%o]=%05o", reg, M[reg]); - fprintf (sim_log, "\n"); - } - /*besm6_okno ("экстракод");*/ - /* Адрес возврата из экстракода. */ - M[ERET] = nextpc; - /* Сохранённые режимы УУ. */ - M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); - /* Текущие режимы УУ. */ - M[PSW] = PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE | /*?*/ PSW_INTR_HALT; - M[14] = Aex; - RUU = SET_SUPERVISOR (RUU, SPSW_EXTRACODE); - - if (opcode <= 077) - PC = 0500 + opcode; /* э50-э77 */ - else - PC = 0540 + (opcode >> 3); /* э20, э21 */ - RUU &= ~RUU_RIGHT_INSTR; - delay = 7; - break; - case 0220: /* мода, utc */ - Aex = ADDR (addr + M[reg]); - next_mod = Aex; - delay = 4; - break; - case 0230: /* мод, wtc */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - next_mod = ADDR (mmu_load (Aex)); - delay = MEAN_TIME (13, 3); - break; - case 0240: /* уиа, vtm */ - Aex = addr; - M[reg] = addr; - M[0] = 0; - if (IS_SUPERVISOR (RUU) && reg == 0) { - M[PSW] &= ~(PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - M[PSW] |= addr & (PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - } - delay = 4; - break; - case 0250: /* слиа, utm */ - Aex = ADDR (addr + M[reg]); - M[reg] = Aex; - M[0] = 0; - if (IS_SUPERVISOR (RUU) && reg == 0) { - M[PSW] &= ~(PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - M[PSW] |= addr & (PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - } - delay = 4; - break; - case 0260: /* по, uza */ - Aex = ADDR (addr + M[reg]); - RMR = ACC; - delay = MEAN_TIME (12, 3); - if (IS_ADDITIVE (RAU)) { - if (ACC & BIT41) - break; - } else if (IS_MULTIPLICATIVE (RAU)) { - if (! (ACC & BIT48)) - break; - } else if (IS_LOGICAL (RAU)) { - if (ACC) - break; - } else - break; - PC = Aex; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - break; - case 0270: /* пе, u1a */ - Aex = ADDR (addr + M[reg]); - RMR = ACC; - delay = MEAN_TIME (12, 3); - if (IS_ADDITIVE (RAU)) { - if (! (ACC & BIT41)) - break; - } else if (IS_MULTIPLICATIVE (RAU)) { - if (ACC & BIT48) - break; - } else if (IS_LOGICAL (RAU)) { - if (! ACC) - break; - } else - /* fall thru, i.e. branch */; - PC = Aex; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - break; - case 0300: /* пб, uj */ - Aex = ADDR (addr + M[reg]); - PC = Aex; - RUU &= ~RUU_RIGHT_INSTR; - delay = 7; - break; - case 0310: /* пв, vjm */ - Aex = addr; - M[reg] = nextpc; - M[0] = 0; - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay = 7; - break; - case 0320: /* выпр, iret */ - Aex = addr; - if (! IS_SUPERVISOR (RUU)) { - longjmp (cpu_halt, STOP_BADCMD); - } - M[PSW] = (M[PSW] & PSW_WRITE_WATCH) | - (M[SPSW] & (SPSW_INTR_DISABLE | - SPSW_MMAP_DISABLE | SPSW_PROT_DISABLE)); - PC = M[(reg & 3) | 030]; - RUU &= ~RUU_RIGHT_INSTR; - if (M[SPSW] & SPSW_RIGHT_INSTR) - RUU |= RUU_RIGHT_INSTR; - else - RUU &= ~RUU_RIGHT_INSTR; - RUU = SET_SUPERVISOR (RUU, - M[SPSW] & (SPSW_EXTRACODE | SPSW_INTERRUPT)); - if (M[SPSW] & SPSW_MOD_RK) - next_mod = M[MOD]; - /*besm6_okno ("Выход из прерывания");*/ - delay = 7; - break; - case 0330: /* стоп, stop */ - Aex = ADDR (addr + M[reg]); - delay = 7; - if (! IS_SUPERVISOR(RUU)) { - if (M[PSW] & PSW_CHECK_HALT) - break; - else { - opcode = 063; - goto stop_as_extracode; - } - } - mmu_print_brz (); - longjmp (cpu_halt, STOP_STOP); - break; - case 0340: /* пио, vzm */ -branch_zero: Aex = addr; - delay = 4; - if (! M[reg]) { - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - } - break; - case 0350: /* пино, v1m */ - Aex = addr; - delay = 4; - if (M[reg]) { - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - } - break; - case 0360: /* э36, *36 */ - goto branch_zero; - case 0370: /* цикл, vlm */ - Aex = addr; - delay = 4; - if (! M[reg]) - break; - M[reg] = ADDR (M[reg] + 1); - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - break; - default: - /* Unknown instruction - cannot happen. */ - longjmp (cpu_halt, STOP_STOP); - break; - } - if (next_mod) { - /* Модификация адреса следующей команды. */ - M[MOD] = next_mod; - RUU |= RUU_MOD_RK; - } else - RUU &= ~RUU_MOD_RK; - - /* Не находимся ли мы в цикле "ЖДУ" диспака? */ - if (RUU == 047 && PC == 04440 && RK == 067704440) { - /* Притормаживаем выполнение каждой команды холостого цикла, - * чтобы быстрее обрабатывались прерывания: ускоряются - * терминалы и АЦПУ. */ - delay = sim_interval; - - /* Если периферия простаивает, освобождаем процессор - * до следующего тика таймера. */ - if (vt_is_idle() && - printer_is_idle() && fs_is_idle()) { - check_initial_setup (); - pause (); - } - } -} - -/* - * Операция прерывания 1: внутреннее прерывание. - * Описана в 9-м томе технического описания БЭСМ-6, страница 119. - */ -void op_int_1 (const char *msg) -{ - /*besm6_okno (msg);*/ - M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); - if (RUU & RUU_RIGHT_INSTR) - M[SPSW] |= SPSW_RIGHT_INSTR; - M[IRET] = PC; - M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; - if (RUU & RUU_MOD_RK) { - M[SPSW] |= SPSW_MOD_RK; - RUU &= ~RUU_MOD_RK; - } - PC = 0500; - RUU &= ~RUU_RIGHT_INSTR; - RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); -} - -/* - * Операция прерывания 2: внешнее прерывание. - * Описана в 9-м томе технического описания БЭСМ-6, страница 129. - */ -void op_int_2 () -{ - /*besm6_okno ("Внешнее прерывание");*/ - M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); - M[IRET] = PC; - M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; - if (RUU & RUU_MOD_RK) { - M[SPSW] |= SPSW_MOD_RK; - RUU &= ~RUU_MOD_RK; - } - PC = 0501; - RUU &= ~RUU_RIGHT_INSTR; - RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); -} - -/* - * Main instruction fetch/decode loop - */ -t_stat sim_instr (void) -{ - t_stat r; - int iintr = 0; - - /* Restore register state */ - PC = PC & BITS(15); /* mask PC */ - sim_cancel_step (); /* defang SCP step */ - mmu_setup (); /* copy RP to TLB */ - - /* An internal interrupt or user intervention */ - r = setjmp (cpu_halt); - if (r) { - M[017] += corr_stack; - if (cpu_dev.dctrl) { - const char *message = (r >= SCPE_BASE) ? - scp_errors [r - SCPE_BASE] : - sim_stop_messages [r]; - besm6_debug ("/// %05o%s: %s", PC, - (RUU & RUU_RIGHT_INSTR) ? "п" : "л", - message); - } - - /* - * ПоП и ПоК вызывают останов при любом внутреннем прерывании - * или прерывании по контролю, соответственно. - * Если произошёл останов по ПоП или ПоК, - * то продолжение выполнения начнётся с команды, следующей - * за вызвавшей прерывание. Как если бы кнопка "ТП" (тип - * перехода) была включена. Подробнее на странице 119 ТО9. - */ - switch (r) { - default: -ret: besm6_draw_panel(); - return r; - case STOP_RWATCH: - case STOP_WWATCH: - /* Step back one insn to reexecute it */ - if (! (RUU & RUU_RIGHT_INSTR)) { - --PC; - } - RUU ^= RUU_RIGHT_INSTR; - goto ret; - case STOP_BADCMD: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // SPSW_NEXT_RK is not important for this interrupt - GRP |= GRP_ILL_INSN; - break; - case STOP_INSN_CHECK: - if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // SPSW_NEXT_RK must be 0 for this interrupt; it is already - GRP |= GRP_INSN_CHECK; - break; - case STOP_INSN_PROT: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - // SPSW_NEXT_RK must be 1 for this interrupt - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_INSN_PROT; - break; - case STOP_OPERAND_PROT: -#if 0 -/* ДИСПАК держит признак ПоП установленным. - * При запуске СЕРП возникает обращение к чужому листу. */ - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; -#endif - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - // The offending virtual page is in bits 5-9 - GRP |= GRP_OPRND_PROT; - GRP = GRP_SET_PAGE (GRP, iintr_data); - break; - case STOP_RAM_CHECK: - if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // The offending interleaved block # is in bits 1-3. - GRP |= GRP_CHECK | GRP_RAM_CHECK; - GRP = GRP_SET_BLOCK (GRP, iintr_data); - break; - case STOP_CACHE_CHECK: - if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // The offending BRZ # is in bits 1-3. - GRP |= GRP_CHECK; - GRP &= ~GRP_RAM_CHECK; - GRP = GRP_SET_BLOCK (GRP, iintr_data); - break; - case STOP_INSN_ADDR_MATCH: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_BREAKPOINT; - break; - case STOP_LOAD_ADDR_MATCH: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_WATCHPT_R; - break; - case STOP_STORE_ADDR_MATCH: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_WATCHPT_W; - break; - case STOP_OVFL: - /* Прерывание по АУ вызывает останов, если БРО=0 - * и установлен ПоП или ПоК. - * Страница 118 ТО9.*/ - if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ - ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ - (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - GRP |= GRP_OVERFLOW|GRP_RAM_CHECK; - break; - case STOP_DIVZERO: - if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ - ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ - (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - GRP |= GRP_DIVZERO|GRP_RAM_CHECK; - break; - } - ++iintr; - } - - if (iintr > 1) { - besm6_draw_panel(); - return STOP_DOUBLE_INTR; - } - /* Main instruction fetch/decode loop */ - for (;;) { - if (sim_interval <= 0) { /* check clock queue */ - r = sim_process_event (); - if (r) { - besm6_draw_panel(); - return r; - } - } - - if (PC > BITS(15)) { /* выход за пределы памяти */ - besm6_draw_panel(); - return STOP_RUNOUT; /* stop simulation */ - } - - if (sim_brk_summ & SWMASK('E') && /* breakpoint? */ - sim_brk_test (PC, SWMASK ('E'))) { - besm6_draw_panel(); - return STOP_IBKPT; /* stop simulation */ - } - - if (PRP & MPRP) { - /* регистр хранящий, сбрасывается программно */ - GRP |= GRP_SLAVE; - } - - if (! iintr && ! (RUU & RUU_RIGHT_INSTR) && - ! (M[PSW] & PSW_INTR_DISABLE) && (GRP & MGRP)) { - /* external interrupt */ - op_int_2(); - } - cpu_one_inst (); /* one instr */ - iintr = 0; - if (redraw_panel) { - besm6_draw_panel(); - redraw_panel = 0; - } - - if (delay < 1) - delay = 1; - sim_interval -= delay; /* count down delay */ - if (sim_step && (--sim_step <= 0)) { /* do step count */ - besm6_draw_panel(); - return SCPE_STOP; - } - } -} - -t_stat slow_clk (UNIT * this) -{ - /*besm6_debug ("*** таймер 80 мсек");*/ - GRP |= GRP_SLOW_CLK; - return sim_activate (this, MSEC*125/2); -} - -/* - * В 9-й части частота таймера 250 Гц (4 мс), - * в жизни - 50 Гц (20 мс). - */ -t_stat fast_clk (UNIT * this) -{ - /*besm6_debug ("*** таймер 20 мсек");*/ - GRP |= GRP_TIMER; - return sim_activate (this, 20*MSEC); -} - -UNIT clocks[] = { - { UDATA(slow_clk, 0, 0) }, /* 10 р, 16 Гц */ - { UDATA(fast_clk, 0, 0) }, /* 40 р, 50 Гц */ -}; - -t_stat clk_reset (DEVICE * dev) -{ - /* Схема автозапуска включается по нереализованной кнопке "МР" */ -#ifdef SOFT_CLOCK - sim_activate (&clocks[0], MSEC*125/2); - return sim_activate (&clocks[1], 20*MSEC); -#else - return SCPE_OK; -#endif -} - -DEVICE clock_dev = { - "CLK", clocks, NULL, NULL, - 2, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, NULL, - DEV_DEBUG -}; +/* + * BESM-6 CPU simulator. + * + * Copyright (c) 1997-2009, Leonid Broukhis + * 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. + + * For more information about BESM-6 computer, visit sites: + * - http://www.computer-museum.ru/english/besm6.htm + * - http://mailcom.com/besm6/ + * - http://groups.google.com/group/besm6 + * + * Release notes for BESM-6/SIMH + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * 1) All addresses and data values are displayed in octal. + * 2) Memory size is 128 kwords. + * 3) Interrupt system is to be synchronized with wallclock time. + * 4) Execution times are in 1/10 of microsecond. + * 5) Magnetic drums are implemented as a single "DRUM" device. + * 6) Magnetic disks are implemented. + * 7) Magnetic tape is not implemented. + * 8) Punch tape reader is implemented, punch card reader is planned. + * 9) Card puncher is not implemented. + * 10) Displays are implemented. + * 11) Printer АЦПУ-128 is implemented. + * 12) Instruction mnemonics, register names and stop messages + * are in Russian using UTF-8 encoding. It is assumed, that + * user locale is UTF-8. + * 13) A lot of comments in Russian (UTF-8). + */ +#include "besm6_defs.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#undef SOFT_CLOCK + +t_value memory [MEMSIZE]; +uint32 PC, RK, Aex, M [NREGS], RAU, RUU; +t_value ACC, RMR, GRP, MGRP; +uint32 PRP, MPRP; +uint32 READY, READY2; /* ready flags of various devices */ + +extern const char *scp_errors[]; + +/* нехранящие биты ГРП должны сбрасываться путем обнуления тех регистров, + * сборкой которых они являются + */ +#define GRP_WIRED_BITS 01400743700000000LL + +#define PRP_WIRED_BITS 0770000 + +int corr_stack; +int redraw_panel; +uint32 delay; +jmp_buf cpu_halt; + +t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); + +/* + * CPU data structures + * + * cpu_dev CPU device descriptor + * cpu_unit CPU unit descriptor + * cpu_reg CPU register list + * cpu_mod CPU modifiers list + */ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MEMSIZE) }; + +REG cpu_reg[] = { +{ "СчАС", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ +{ "РК", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ +{ "Аисп", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ +{ "СМ", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ +{ "РМР", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ +{ "РАУ", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ +{ "М1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ +{ "М2", &M[2], 8, 15, 0, 1 }, +{ "М3", &M[3], 8, 15, 0, 1 }, +{ "М4", &M[4], 8, 15, 0, 1 }, +{ "М5", &M[5], 8, 15, 0, 1 }, +{ "М6", &M[6], 8, 15, 0, 1 }, +{ "М7", &M[7], 8, 15, 0, 1 }, +{ "М10", &M[010], 8, 15, 0, 1 }, +{ "М11", &M[011], 8, 15, 0, 1 }, +{ "М12", &M[012], 8, 15, 0, 1 }, +{ "М13", &M[013], 8, 15, 0, 1 }, +{ "М14", &M[014], 8, 15, 0, 1 }, +{ "М15", &M[015], 8, 15, 0, 1 }, +{ "М16", &M[016], 8, 15, 0, 1 }, +{ "М17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ +{ "М20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ +{ "М21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ +{ "М27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ +{ "М32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ +{ "М33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ +{ "М34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ +{ "М35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ +{ "РУУ", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ +{ "ГРП", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ +{ "МГРП", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ +{ "ПРП", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ +{ "МПРП", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ +{ 0 } +}; + +MTAB cpu_mod[] = { + { 0 } +}; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 17, 1, 8, 50, + &cpu_examine, &cpu_deposit, &cpu_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG +}; + +/* + * REG: псевдоустройство, содержащее латинские синонимы всех регистров. + */ +REG reg_reg[] = { +{ "PC", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ +{ "RK", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ +{ "Aex", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ +{ "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ +{ "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ +{ "RAU", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ +{ "M1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ +{ "M2", &M[2], 8, 15, 0, 1 }, +{ "M3", &M[3], 8, 15, 0, 1 }, +{ "M4", &M[4], 8, 15, 0, 1 }, +{ "M5", &M[5], 8, 15, 0, 1 }, +{ "M6", &M[6], 8, 15, 0, 1 }, +{ "M7", &M[7], 8, 15, 0, 1 }, +{ "M10", &M[010], 8, 15, 0, 1 }, +{ "M11", &M[011], 8, 15, 0, 1 }, +{ "M12", &M[012], 8, 15, 0, 1 }, +{ "M13", &M[013], 8, 15, 0, 1 }, +{ "M14", &M[014], 8, 15, 0, 1 }, +{ "M15", &M[015], 8, 15, 0, 1 }, +{ "M16", &M[016], 8, 15, 0, 1 }, +{ "M17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ +{ "M20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ +{ "M21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ +{ "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ +{ "M32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ +{ "M33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ +{ "M34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ +{ "M35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ +{ "RUU", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ +{ "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ +{ "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ +{ "PRP", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ +{ "MPRP", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ + +{ "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BRZ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "BAZ0", &BAZ[0], 8, 16, 0, 1 }, +{ "BAZ1", &BAZ[1], 8, 16, 0, 1 }, +{ "BAZ2", &BAZ[2], 8, 16, 0, 1 }, +{ "BAZ3", &BAZ[3], 8, 16, 0, 1 }, +{ "BAZ4", &BAZ[4], 8, 16, 0, 1 }, +{ "BAZ5", &BAZ[5], 8, 16, 0, 1 }, +{ "BAZ6", &BAZ[6], 8, 16, 0, 1 }, +{ "BAZ7", &BAZ[7], 8, 16, 0, 1 }, +{ "TABST", &TABST, 8, 28, 0, 1 }, +{ "RP0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RP7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, +{ "RZ", &RZ, 8, 32, 0, 1 }, +{ "FP1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ "FP7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, +{ 0 } +}; + +UNIT reg_unit = { + UDATA (NULL, 0, 8) +}; + +DEVICE reg_dev = { + "REG", ®_unit, reg_reg, NULL, + 1, 8, 1, 1, 8, 50, +}; + +/* + * SCP data structures and interface routines + * + * sim_name simulator name string + * sim_PC pointer to saved PC register descriptor + * sim_emax maximum number of words for examine/deposit + * sim_devices array of pointers to simulated devices + * sim_stop_messages array of pointers to stop messages + * sim_load binary loader + */ + +char sim_name[] = "БЭСМ-6"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; /* максимальное количество слов в машинной команде */ + +DEVICE *sim_devices[] = { + &cpu_dev, + ®_dev, + &drum_dev, + &disk_dev, + &mmu_dev, + &clock_dev, + &printer_dev, + &fs_dev, + &tty_dev, /* терминалы - телетайпы, видеотоны, "Консулы" */ + 0 +}; + +const char *sim_stop_messages[] = { + "Неизвестная ошибка", /* Unknown error */ + "Останов", /* STOP */ + "Точка останова", /* Emulator breakpoint */ + "Точка останова по считыванию", /* Emulator read watchpoint */ + "Точка останова по записи", /* Emulator write watchpoint */ + "Выход за пределы памяти", /* Run out end of memory */ + "Запрещенная команда", /* Invalid instruction */ + "Контроль команды", /* A data-tagged word fetched */ + "Команда в чужом листе", /* Paging error during fetch */ + "Число в чужом листе", /* Paging error during load/store */ + "Контроль числа МОЗУ", /* RAM parity error */ + "Контроль числа БРЗ", /* Write cache parity error */ + "Переполнение АУ", /* Arith. overflow */ + "Деление на нуль", /* Division by zero or denorm */ + "Двойное внутреннее прерывание", /* SIMH: Double internal interrupt */ + "Чтение неформатированного барабана", /* Reading unformatted drum */ + "Чтение неформатированного диска", /* Reading unformatted disk */ + "Останов по КРА", /* Hardware breakpoint */ + "Останов по считыванию", /* Load watchpoint */ + "Останов по записи", /* Store watchpoint */ + "Не реализовано", /* Unimplemented I/O or special reg. access */ +}; + +/* + * Memory examine + */ +t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + if (vptr) { + if (addr < 010) + *vptr = pult [addr]; + else + *vptr = memory [addr]; + } + return SCPE_OK; +} + +/* + * Memory deposit + */ +t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) + return SCPE_NXM; + if (addr < 010) + pult [addr] = SET_CONVOL (val, CONVOL_INSN); + else + memory [addr] = SET_CONVOL (val, CONVOL_INSN); + return SCPE_OK; +} + +/* + * Функция вызывается каждые 4 миллисекунды реального времени. + */ +static void cpu_sigalarm (int signum) +{ + static unsigned counter; + + ++counter; + +#ifndef SOFT_CLOCK + /* В 9-й части частота таймера 250 Гц (4 мс). */ + GRP |= GRP_TIMER; + + /* Медленный таймер: должен быть 16 Гц. + * Но от него почему-то зависит вывод на терминалы, + * поэтому ускорим. */ + if ((counter & 3) == 0) { + GRP |= GRP_SLOW_CLK; + } +#endif + + /* Перерисовка панели каждые 64 миллисекунды. */ + if ((counter & 15) == 0) { + redraw_panel = 1; + } +} + +/* + * Reset routine + */ +t_stat cpu_reset (DEVICE *dptr) +{ + int i; + + ACC = 0; + RMR = 0; + RAU = 0; + RUU = RUU_EXTRACODE | RUU_AVOST_DISABLE; + for (i=0; i 0xxxxxxx + * 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy + * xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz + */ +void +utf8_putc (unsigned ch, FILE *fout) +{ + if (ch < 0x80) { + putc (ch, fout); + return; + } + if (ch < 0x800) { + putc (ch >> 6 | 0xc0, fout); + putc ((ch & 0x3f) | 0x80, fout); + return; + } + putc (ch >> 12 | 0xe0, fout); + putc (((ch >> 6) & 0x3f) | 0x80, fout); + putc ((ch & 0x3f) | 0x80, fout); +} + +/* + * *call ОКНО - так называлась служебная подпрограмма в мониторной + * системе "Дубна", которая печатала полное состояние всех регистров. + */ +void besm6_okno (const char *message) +{ + besm6_log_cont ("_%%%%%% %s: ", message); + if (sim_log) + besm6_fprint_cmd (sim_log, RK); + besm6_log ("_"); + + /* СчАС, системные индекс-регистры 020-035. */ + besm6_log ("_ СчАС:%05o 20:%05o 21:%05o 27:%05o 32:%05o 33:%05o 34:%05o 35:%05o", + PC, M[020], M[021], M[027], M[032], M[033], M[034], M[035]); + /* Индекс-регистры 1-7. */ + besm6_log ("_ 1:%05o 2:%05o 3:%05o 4:%05o 5:%05o 6:%05o 7:%05o", + M[1], M[2], M[3], M[4], M[5], M[6], M[7]); + /* Индекс-регистры 010-017. */ + besm6_log ("_ 10:%05o 11:%05o 12:%05o 13:%05o 14:%05o 15:%05o 16:%05o 17:%05o", + M[010], M[011], M[012], M[013], M[014], M[015], M[016], M[017]); + /* Сумматор, РМР, режимы АУ и УУ. */ + besm6_log ("_ СМ:%04o %04o %04o %04o РМР:%04o %04o %04o %04o РАУ:%02o РУУ:%03o", + (int) (ACC >> 36) & BITS(12), (int) (ACC >> 24) & BITS(12), + (int) (ACC >> 12) & BITS(12), (int) ACC & BITS(12), + (int) (RMR >> 36) & BITS(12), (int) (RMR >> 24) & BITS(12), + (int) (RMR >> 12) & BITS(12), (int) RMR & BITS(12), + RAU, RUU); +} + +/* + * Команда "рег" + */ +static void cmd_002 () +{ +#if 0 + besm6_debug ("*** рег %03o", Aex & 0377); +#endif + switch (Aex & 0377) { + case 0 ... 7: + /* Запись в БРЗ */ + mmu_setcache (Aex & 7, ACC); + break; + case 020 ... 027: + /* Запись в регистры приписки */ + mmu_setrp (Aex & 7, ACC); + break; + case 030 ... 033: + /* Запись в регистры защиты */ + mmu_setprotection (Aex & 3, ACC); + break; + case 036: + /* Запись в маску главного регистра прерываний */ + MGRP = ACC; + break; + case 037: + /* Гашение главного регистра прерываний */ + /* нехранящие биты невозможно погасить */ + GRP &= ACC | GRP_WIRED_BITS; + break; + case 0100 ... 0137: + /* Бит 1: управление блокировкой режима останова БРО. + * Биты 2 и 3 - признаки формирования контрольных + * разрядов (ПКП и ПКЛ). */ + if (Aex & 1) + RUU |= RUU_AVOST_DISABLE; + else + RUU &= ~RUU_AVOST_DISABLE; + if (Aex & 2) + RUU |= RUU_CONVOL_RIGHT; + else + RUU &= ~RUU_CONVOL_RIGHT; + if (Aex & 4) + RUU |= RUU_CONVOL_LEFT; + else + RUU &= ~RUU_CONVOL_LEFT; + break; + case 0140 ... 0177: + /* TODO: управление блокировкой схемы + * автоматического запуска */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0200 ... 0207: + /* Чтение БРЗ */ + ACC = mmu_getcache (Aex & 7); + break; + case 0237: + /* Чтение главного регистра прерываний */ + ACC = GRP; + break; + default: + /* Неиспользуемые адреса */ + besm6_debug ("*** %05o%s: РЕГ %o - неправильный адрес спец.регистра", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); + break; + } +} + +/* + * Команда "увв" + */ +static void cmd_033 () +{ +#if 0 + besm6_debug ("*** увв %04o, СМ[24:1]=%08o", + Aex & 04177, (uint32) ACC & BITS(24)); +#endif + switch (Aex & 04177) { + case 0: + /* Точно неизвестно, что это такое, но драйвер МД + * иногда выдает команду "увв 0". */ + break; + case 1 ... 2: + /* Управление обменом с магнитными барабанами */ + drum (Aex - 1, (uint32) ACC); + break; + case 3 ... 4: + /* Передача управляющего слова для обмена + * с магнитными дисками */ + disk_io (Aex - 3, (uint32) ACC); + break; + case 5 ... 7: + /* TODO: управление обменом с магнитными лентами */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 010 ... 011: + /* управление устройствами ввода с перфоленты */ + fs_control (Aex - 010, (uint32) (ACC & 07)); + break; + case 012 ... 013: + /* TODO: управление устройствами ввода с перфоленты по запаянной программе */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 014 ... 015: + /* Управление АЦПУ */ + printer_control (Aex - 014, (uint32) (ACC & 017)); + break; + case 023 ... 024: + /* Управление обменом с магнитными дисками */ + disk_ctl (Aex - 023, (uint32) ACC); + break; + case 030: + /* Гашение ПРП */ +/* besm6_debug(">>> гашение ПРП");*/ + PRP &= ACC | PRP_WIRED_BITS; + break; + case 031: + /* Имитация сигналов прерывания ГРП */ + /*besm6_debug ("*** %05o%s: имитация прерываний ГРП %016llo", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", ACC << 24);*/ + GRP |= (ACC & BITS(24)) << 24; + break; + case 032 ... 033: + /* TODO: имитация сигналов из КМБ в КВУ */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 034: + /* Запись в МПРП */ +/* besm6_debug(">>> запись в МПРП");*/ + MPRP = ACC & 077777777; + break; + case 035: + /* TODO: управление режимом имитации обмена + * с МБ и МЛ, имитация обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 040 ... 057: + /* Управление молоточками АЦПУ */ + printer_hammer (Aex >= 050, Aex & 7, (uint32) (ACC & BITS(16))); + break; + case 0100 ... 0137: + /* Управление лентопротяжными механизмами + * и гашение разрядов регистров признаков + * окончания подвода зоны. Игнорируем. */ + break; + case 0140: + /* Запись в регистр телеграфных каналов */ + tty_send ((uint32) ACC & BITS(24)); + break; + case 0141: + /* TODO: управление разметкой магнитной ленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0142: + /* TODO: имитация сигналов прерывания ПРП */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0147: + /* Запись в регистр управления электропитанием, */ + /* не оказывает видимого эффекта на выполнение */ + break; + case 0150 ... 0151: + /* TODO: управление вводом с перфокарт */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0153: + /* гашение аппаратуры сопряжения с терминалами */ +/* besm6_debug(">>> гашение АС: %08o", (uint32) ACC & BITS(24));*/ + break; + case 0154 ... 0155: + /* TODO: управление выводом на перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0160 ... 0167: + /* TODO: управление электромагнитами пробивки перфокарт */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0170 ... 0171: + /* TODO: пробивка строки на перфоленте */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0174 ... 0175: + /* Выдача кода в пульт оператора */ + consul_print (Aex & 1, (uint32) ACC & BITS(8)); + break; + case 0177: + /* управление табло ГПВЦ СО АН СССР */ +/* besm6_debug(">>> ТАБЛО: %08o", (uint32) ACC & BITS(24));*/ + break; + case 04001 ... 04002: + /* TODO: считывание слога в режиме имитации обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04003 ... 04004: + /* Запрос статуса контроллера магнитных дисков */ + ACC = disk_state (Aex - 04003); + break; + case 04006: + /* TODO: считывание строки с устройства ввода + * с перфоленты в запаянной программе */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04007: + /* TODO: опрос синхроимпульса ненулевой строки + * в запаянной программе ввода с перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04014 ... 04015: + /* считывание строки с устройства ввода с перфоленты */ + ACC = fs_read (Aex - 04014); + break; + case 04016 ... 04017: + /* TODO: считывание строки с устройства + * ввода с перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04020 ... 04023: + /* TODO: считывание слога в режиме имитации + * внешнего обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04030: + /* Чтение старшей половины ПРП */ + ACC = PRP & 077770000; + break; + case 04031: + /* Опрос сигналов готовности (АЦПУ и пр.) */ +/* besm6_debug("Reading READY");*/ + ACC = READY; + break; + case 04034: + /* Чтение младшей половины ПРП */ + ACC = (PRP & 07777) | 0377; + break; + case 04035: + /* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */ + ACC = drum_errors() | disk_errors(); + break; + case 04100: + /* Опрос телеграфных каналов связи */ + ACC = tty_query (); + break; + case 04102: + /* Опрос сигналов готовности перфокарт и перфолент */ +/* besm6_debug("Reading punchcard/punchtape READY @%05o", PC);*/ + ACC = READY2; + break; + case 04103 ... 04106: + /* Опрос состояния лентопротяжных механизмов. + * Все устройства не готовы. */ + ACC = BITS(24); + break; + case 04107: + /* TODO: опрос схемы контроля записи на МЛ */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04115: + /* Неизвестное обращение. ДИСПАК выдаёт эту команду + * группами по 8 штук каждые несколько секунд. */ + ACC = 0; + break; + case 04140 ... 04157: + /* TODO: считывание строки перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04160 ... 04167: + /* TODO: контрольное считывание строки перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04170 ... 04173: + /* TODO: считывание контрольного кода + * строки перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04174 ... 04175: + /* Считывание кода с пульта оператора */ + ACC = consul_read (Aex & 1); + break; + case 04177: + /* чтение табло ГПВЦ СО АН СССР */ + ACC = 0; + break; + default: + /* Неиспользуемые адреса */ +/* if (sim_deb && cpu_dev.dctrl)*/ + besm6_debug ("*** %05o%s: УВВ %o - неправильный адрес ввода-вывода", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); + ACC = 0; + break; + } +} + +void check_initial_setup () +{ + const int MGRP_COPY = 01455; /* OS version specific? */ + const int TAKEN = 0442; /* fixed? */ + const int YEAR = 0221; /* fixed */ + + /* 47 р. яч. ЗАНЯТА - разр. приказы вообще */ + const t_value SETUP_REQS_ENABLED = 1LL << 46; + + /* 7 р. яч. ЗАНЯТА - разр любые приказы */ + const t_value ALL_REQS_ENABLED = 1 << 6; + + if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || + (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || + (MGRP & GRP_PANEL_REQ) == 0) { + /* Слишком рано, или уже не надо, или невовремя */ + return; + } + + /* Выдаем приказы оператора СМЕ и ВРЕ, + * а дату корректируем непосредственно в памяти. + */ + /* Номер смены в 22-24 рр. МГРП: если еще не установлен, установить */ + if (((memory[MGRP_COPY] >> 21) & 3) == 0) { + /* приказ СМЕ: ТР6 = 010, ТР4 = 1, 22-24 р ТР5 - #смены */ + pult[6] = 010; + pult[4] = 1; + pult[5] = 1 << 21; + GRP |= GRP_PANEL_REQ; + } else { + /* Яч. ГОД обновляем самостоятельно */ + time_t t; + t_value date; + time(&t); + struct tm * d; + d = localtime(&t); + ++d->tm_mon; + date = (t_value) (d->tm_mday / 10) << 33 | + (t_value) (d->tm_mday % 10) << 29 | + (d->tm_mon / 10) << 28 | + (d->tm_mon % 10) << 24 | + (d->tm_year % 10) << 20 | + ((d->tm_year / 10) % 10) << 16 | + (memory[YEAR] & 7); + memory[YEAR] = SET_CONVOL (date, CONVOL_NUMBER); + /* приказ ВРЕ: ТР6 = 016, ТР5 = 9-14 р.-часы, 1-8 р.-минуты */ + pult[6] = 016; + pult[4] = 0; + pult[5] = (d->tm_hour / 10) << 12 | + (d->tm_hour % 10) << 8 | + (d->tm_min / 10) << 4 | + (d->tm_min % 10); + GRP |= GRP_PANEL_REQ; + } +} + +/* + * Execute one instruction, placed on address PC:RUU_RIGHT_INSTR. + * Increment delay. When stopped, perform a longjmp to cpu_halt, + * sending a stop code. + */ +void cpu_one_inst () +{ + int reg, opcode, addr, nextpc, next_mod; + + corr_stack = 0; + t_value word = mmu_fetch (PC); + if (RUU & RUU_RIGHT_INSTR) + RK = word; /* get right instruction */ + else + RK = word >> 24; /* get left instruction */ + + RK &= BITS(24); + + reg = RK >> 20; + if (RK & BBIT(20)) { + addr = RK & BITS(15); + opcode = (RK >> 12) & 0370; + } else { + addr = RK & BITS(12); + if (RK & BBIT(19)) + addr |= 070000; + opcode = (RK >> 12) & 077; + } + + if (sim_deb && cpu_dev.dctrl) { + fprintf (sim_deb, "*** %05o%s: ", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); + besm6_fprint_cmd (sim_deb, RK); + fprintf (sim_deb, "\tСМ="); + fprint_sym (sim_deb, 0, &ACC, 0, 0); + fprintf (sim_deb, "\tРАУ=%02o", RAU); + if (reg) + fprintf (sim_deb, "\tМ[%o]=%05o", reg, M[reg]); + fprintf (sim_deb, "\n"); + } + nextpc = ADDR(PC + 1); + if (RUU & RUU_RIGHT_INSTR) { + PC += 1; /* increment PC */ + RUU &= ~RUU_RIGHT_INSTR; + } else { + mmu_prefetch(nextpc | (IS_SUPERVISOR(RUU) ? BBIT(16) : 0), 0); + RUU |= RUU_RIGHT_INSTR; + } + + if (RUU & RUU_MOD_RK) { + addr = ADDR (addr + M[MOD]); + } + next_mod = 0; + delay = 0; + + switch (opcode) { + case 000: /* зп, atx */ + Aex = ADDR (addr + M[reg]); + mmu_store (Aex, ACC); + if (! addr && reg == 017) + M[017] = ADDR (M[017] + 1); + delay = MEAN_TIME (3, 3); + break; + case 001: /* зпм, stx */ + Aex = ADDR (addr + M[reg]); + mmu_store (Aex, ACC); + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + ACC = mmu_load (M[017]); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (6, 6); + break; + case 002: /* рег, mod */ + Aex = ADDR (addr + M[reg]); + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + cmd_002 (); + /* Режим АУ - логический, если операция была "чтение" */ + if (Aex & 0200) + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 003: /* счм, xts */ + mmu_store (M[017], ACC); + M[017] = ADDR (M[017] + 1); + corr_stack = -1; + Aex = ADDR (addr + M[reg]); + ACC = mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (6, 6); + break; + case 004: /* сл, a+x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 0, 0); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 005: /* вч, a-x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 0, 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 006: /* вчоб, x-a */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 1, 0); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 007: /* вчаб, amx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 1, 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 010: /* сч, xta */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 011: /* и, aax */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC &= mmu_load (Aex); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4); + break; + case 012: /* нтж, aex */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + RMR = ACC; + ACC ^= mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 013: /* слц, arx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC += mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + RMR = 0; + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 6); + break; + case 014: /* знак, avx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_change_sign (mmu_load (Aex) >> 40 & 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 015: /* или, aox */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC |= mmu_load (Aex); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4); + break; + case 016: /* дел, a/x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_divide (mmu_load (Aex)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 50); + break; + case 017: /* умн, a*x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_multiply (mmu_load (Aex)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 18); + break; + case 020: /* сбр, apx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_pack (ACC, mmu_load (Aex)); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 53); + break; + case 021: /* рзб, aux */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_unpack (ACC, mmu_load (Aex)); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 53); + break; + case 022: /* чед, acx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_count_ones (ACC) + mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 56); + break; + case 023: /* нед, anx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + if (ACC) { + int n = besm6_highest_bit (ACC); + + /* "Остаток" сумматора, исключая бит, + * номер которого определен, помещается в РМР, + * начиная со старшего бита РМР. */ + besm6_shift (48 - n); + + /* Циклическое сложение номера со словом по Аисп. */ + ACC = n + mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + } else { + RMR = 0; + ACC = mmu_load (Aex); + } + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 32); + break; + case 024: /* слп, e+x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add_exponent ((mmu_load (Aex) >> 41) - 64); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 025: /* вчп, e-x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add_exponent (64 - (mmu_load (Aex) >> 41)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 026: { /* сд, asx */ + int n; + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + n = (mmu_load (Aex) >> 41) - 64; + besm6_shift (n); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4 + abs (n)); + break; + } + case 027: /* рж, xtr */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + RAU = (mmu_load (Aex) >> 41) & 077; + delay = MEAN_TIME (3, 3); + break; + case 030: /* счрж, rte */ + Aex = ADDR (addr + M[reg]); + ACC = (t_value) (RAU & Aex & 0177) << 41; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 031: /* счмр, yta */ + Aex = ADDR (addr + M[reg]); + if (IS_LOGICAL (RAU)) { + ACC = RMR; + } else { + t_value x = RMR; + ACC = (ACC & ~BITS41) | (RMR & BITS40); + besm6_add_exponent ((Aex & 0177) - 64); + RMR = x; + } + delay = MEAN_TIME (3, 5); + break; + case 032: /* э32, ext */ + /* Fall through... */ + case 033: /* увв, ext */ + Aex = ADDR (addr + M[reg]); + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + cmd_033 (); + /* Режим АУ - логический, если операция была "чтение" */ + if (Aex & 04000) + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 8); + break; + case 034: /* слпа, e+n */ + Aex = ADDR (addr + M[reg]); + besm6_add_exponent ((Aex & 0177) - 64); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 035: /* вчпа, e-n */ + Aex = ADDR (addr + M[reg]); + besm6_add_exponent (64 - (Aex & 0177)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 036: { /* сда, asn */ + int n; + Aex = ADDR (addr + M[reg]); + n = (Aex & 0177) - 64; + besm6_shift (n); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4 + abs (n)); + break; + } + case 037: /* ржа, ntr */ + Aex = ADDR (addr + M[reg]); + RAU = Aex & 077; + delay = MEAN_TIME (3, 3); + break; + case 040: /* уи, ati */ + Aex = ADDR (addr + M[reg]); + if (IS_SUPERVISOR (RUU)) { + int reg = Aex & 037; + M[reg] = ADDR (ACC); + /* breakpoint/watchpoint regs will match physical + * or virtual addresses depending on the current + * mapping mode. + */ + if ((M[PSW] & PSW_MMAP_DISABLE) && + (reg == IBP || reg == DWP)) + M[reg] |= BBIT(16); + + } else + M[Aex & 017] = ADDR (ACC); + M[0] = 0; + delay = MEAN_TIME (14, 3); + break; + case 041: { /* уим, sti */ + unsigned rg, ad; + + Aex = ADDR (addr + M[reg]); + rg = Aex & (IS_SUPERVISOR (RUU) ? 037 : 017); + ad = ADDR (ACC); + if (rg != 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + ACC = mmu_load (rg != 017 ? M[017] : ad); + M[rg] = ad; + if ((M[PSW] & PSW_MMAP_DISABLE) && (rg == IBP || rg == DWP)) + M[rg] |= BBIT(16); + M[0] = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (14, 3); + break; + } + case 042: /* счи, ita */ + delay = MEAN_TIME (6, 3); +load_modifier: Aex = ADDR (addr + M[reg]); + ACC = ADDR(M[Aex & (IS_SUPERVISOR (RUU) ? 037 : 017)]); + RAU = SET_LOGICAL (RAU); + break; + case 043: /* счим, its */ + mmu_store (M[017], ACC); + M[017] = ADDR (M[017] + 1); + delay = MEAN_TIME (9, 6); + goto load_modifier; + case 044: /* уии, mtj */ + Aex = addr; + if (IS_SUPERVISOR (RUU)) { +transfer_modifier: M[Aex & 037] = M[reg]; + if ((M[PSW] & PSW_MMAP_DISABLE) && + ((Aex & 037) == IBP || (Aex & 037) == DWP)) + M[Aex & 037] |= BBIT(16); + + } else + M[Aex & 017] = M[reg]; + M[0] = 0; + delay = 6; + break; + case 045: /* сли, j+m */ + Aex = addr; + if ((Aex & 020) && IS_SUPERVISOR (RUU)) + goto transfer_modifier; + M[Aex & 017] = ADDR (M[Aex & 017] + M[reg]); + M[0] = 0; + delay = 6; + break; + case 046: /* э46, x46 */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + M[Aex & 017] = ADDR (Aex); + M[0] = 0; + delay = 6; + break; + case 047: /* э47, x47 */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + M[Aex & 017] = ADDR (M[Aex & 017] + Aex); + M[0] = 0; + delay = 6; + break; + case 050 ... 077: /* э50...э77 */ + case 0200: /* э20 */ + case 0210: /* э21 */ + stop_as_extracode: + Aex = ADDR (addr + M[reg]); + if (! sim_deb && sim_log && cpu_dev.dctrl && opcode != 075) { + /* Если включен console log и cpu debug, + * но нет console debug, то печатаем только экстракоды. + * Пропускаем э75, их обычно слишком много. */ + t_value word = mmu_load (Aex); + fprintf (sim_log, "*** %05o%s: ", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); + besm6_fprint_cmd (sim_log, RK); + fprintf (sim_log, "\tАисп=%05o (=", Aex); + fprint_sym (sim_log, 0, &word, 0, 0); + fprintf (sim_log, ") СМ="); + fprint_sym (sim_log, 0, &ACC, 0, 0); + if (reg) + fprintf (sim_log, " М[%o]=%05o", reg, M[reg]); + fprintf (sim_log, "\n"); + } + /*besm6_okno ("экстракод");*/ + /* Адрес возврата из экстракода. */ + M[ERET] = nextpc; + /* Сохранённые режимы УУ. */ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + /* Текущие режимы УУ. */ + M[PSW] = PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE | /*?*/ PSW_INTR_HALT; + M[14] = Aex; + RUU = SET_SUPERVISOR (RUU, SPSW_EXTRACODE); + + if (opcode <= 077) + PC = 0500 + opcode; /* э50-э77 */ + else + PC = 0540 + (opcode >> 3); /* э20, э21 */ + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0220: /* мода, utc */ + Aex = ADDR (addr + M[reg]); + next_mod = Aex; + delay = 4; + break; + case 0230: /* мод, wtc */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + next_mod = ADDR (mmu_load (Aex)); + delay = MEAN_TIME (13, 3); + break; + case 0240: /* уиа, vtm */ + Aex = addr; + M[reg] = addr; + M[0] = 0; + if (IS_SUPERVISOR (RUU) && reg == 0) { + M[PSW] &= ~(PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + M[PSW] |= addr & (PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + } + delay = 4; + break; + case 0250: /* слиа, utm */ + Aex = ADDR (addr + M[reg]); + M[reg] = Aex; + M[0] = 0; + if (IS_SUPERVISOR (RUU) && reg == 0) { + M[PSW] &= ~(PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + M[PSW] |= addr & (PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + } + delay = 4; + break; + case 0260: /* по, uza */ + Aex = ADDR (addr + M[reg]); + RMR = ACC; + delay = MEAN_TIME (12, 3); + if (IS_ADDITIVE (RAU)) { + if (ACC & BIT41) + break; + } else if (IS_MULTIPLICATIVE (RAU)) { + if (! (ACC & BIT48)) + break; + } else if (IS_LOGICAL (RAU)) { + if (ACC) + break; + } else + break; + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + case 0270: /* пе, u1a */ + Aex = ADDR (addr + M[reg]); + RMR = ACC; + delay = MEAN_TIME (12, 3); + if (IS_ADDITIVE (RAU)) { + if (! (ACC & BIT41)) + break; + } else if (IS_MULTIPLICATIVE (RAU)) { + if (ACC & BIT48) + break; + } else if (IS_LOGICAL (RAU)) { + if (! ACC) + break; + } else + /* fall thru, i.e. branch */; + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + case 0300: /* пб, uj */ + Aex = ADDR (addr + M[reg]); + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0310: /* пв, vjm */ + Aex = addr; + M[reg] = nextpc; + M[0] = 0; + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0320: /* выпр, iret */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) { + longjmp (cpu_halt, STOP_BADCMD); + } + M[PSW] = (M[PSW] & PSW_WRITE_WATCH) | + (M[SPSW] & (SPSW_INTR_DISABLE | + SPSW_MMAP_DISABLE | SPSW_PROT_DISABLE)); + PC = M[(reg & 3) | 030]; + RUU &= ~RUU_RIGHT_INSTR; + if (M[SPSW] & SPSW_RIGHT_INSTR) + RUU |= RUU_RIGHT_INSTR; + else + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, + M[SPSW] & (SPSW_EXTRACODE | SPSW_INTERRUPT)); + if (M[SPSW] & SPSW_MOD_RK) + next_mod = M[MOD]; + /*besm6_okno ("Выход из прерывания");*/ + delay = 7; + break; + case 0330: /* стоп, stop */ + Aex = ADDR (addr + M[reg]); + delay = 7; + if (! IS_SUPERVISOR(RUU)) { + if (M[PSW] & PSW_CHECK_HALT) + break; + else { + opcode = 063; + goto stop_as_extracode; + } + } + mmu_print_brz (); + longjmp (cpu_halt, STOP_STOP); + break; + case 0340: /* пио, vzm */ +branch_zero: Aex = addr; + delay = 4; + if (! M[reg]) { + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + } + break; + case 0350: /* пино, v1m */ + Aex = addr; + delay = 4; + if (M[reg]) { + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + } + break; + case 0360: /* э36, *36 */ + goto branch_zero; + case 0370: /* цикл, vlm */ + Aex = addr; + delay = 4; + if (! M[reg]) + break; + M[reg] = ADDR (M[reg] + 1); + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + default: + /* Unknown instruction - cannot happen. */ + longjmp (cpu_halt, STOP_STOP); + break; + } + if (next_mod) { + /* Модификация адреса следующей команды. */ + M[MOD] = next_mod; + RUU |= RUU_MOD_RK; + } else + RUU &= ~RUU_MOD_RK; + + /* Не находимся ли мы в цикле "ЖДУ" диспака? */ + if (RUU == 047 && PC == 04440 && RK == 067704440) { + /* Притормаживаем выполнение каждой команды холостого цикла, + * чтобы быстрее обрабатывались прерывания: ускоряются + * терминалы и АЦПУ. */ + delay = sim_interval; + + /* Если периферия простаивает, освобождаем процессор + * до следующего тика таймера. */ + if (vt_is_idle() && + printer_is_idle() && fs_is_idle()) { + check_initial_setup (); + pause (); + } + } +} + +/* + * Операция прерывания 1: внутреннее прерывание. + * Описана в 9-м томе технического описания БЭСМ-6, страница 119. + */ +void op_int_1 (const char *msg) +{ + /*besm6_okno (msg);*/ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + if (RUU & RUU_RIGHT_INSTR) + M[SPSW] |= SPSW_RIGHT_INSTR; + M[IRET] = PC; + M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; + if (RUU & RUU_MOD_RK) { + M[SPSW] |= SPSW_MOD_RK; + RUU &= ~RUU_MOD_RK; + } + PC = 0500; + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); +} + +/* + * Операция прерывания 2: внешнее прерывание. + * Описана в 9-м томе технического описания БЭСМ-6, страница 129. + */ +void op_int_2 () +{ + /*besm6_okno ("Внешнее прерывание");*/ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + M[IRET] = PC; + M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; + if (RUU & RUU_MOD_RK) { + M[SPSW] |= SPSW_MOD_RK; + RUU &= ~RUU_MOD_RK; + } + PC = 0501; + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); +} + +/* + * Main instruction fetch/decode loop + */ +t_stat sim_instr (void) +{ + t_stat r; + int iintr = 0; + + /* Restore register state */ + PC = PC & BITS(15); /* mask PC */ + sim_cancel_step (); /* defang SCP step */ + mmu_setup (); /* copy RP to TLB */ + + /* An internal interrupt or user intervention */ + r = setjmp (cpu_halt); + if (r) { + M[017] += corr_stack; + if (cpu_dev.dctrl) { + const char *message = (r >= SCPE_BASE) ? + scp_errors [r - SCPE_BASE] : + sim_stop_messages [r]; + besm6_debug ("/// %05o%s: %s", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л", + message); + } + + /* + * ПоП и ПоК вызывают останов при любом внутреннем прерывании + * или прерывании по контролю, соответственно. + * Если произошёл останов по ПоП или ПоК, + * то продолжение выполнения начнётся с команды, следующей + * за вызвавшей прерывание. Как если бы кнопка "ТП" (тип + * перехода) была включена. Подробнее на странице 119 ТО9. + */ + switch (r) { + default: +ret: besm6_draw_panel(); + return r; + case STOP_RWATCH: + case STOP_WWATCH: + /* Step back one insn to reexecute it */ + if (! (RUU & RUU_RIGHT_INSTR)) { + --PC; + } + RUU ^= RUU_RIGHT_INSTR; + goto ret; + case STOP_BADCMD: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK is not important for this interrupt + GRP |= GRP_ILL_INSN; + break; + case STOP_INSN_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK must be 0 for this interrupt; it is already + GRP |= GRP_INSN_CHECK; + break; + case STOP_INSN_PROT: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK must be 1 for this interrupt + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_INSN_PROT; + break; + case STOP_OPERAND_PROT: +#if 0 +/* ДИСПАК держит признак ПоП установленным. + * При запуске СЕРП возникает обращение к чужому листу. */ + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; +#endif + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + // The offending virtual page is in bits 5-9 + GRP |= GRP_OPRND_PROT; + GRP = GRP_SET_PAGE (GRP, iintr_data); + break; + case STOP_RAM_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // The offending interleaved block # is in bits 1-3. + GRP |= GRP_CHECK | GRP_RAM_CHECK; + GRP = GRP_SET_BLOCK (GRP, iintr_data); + break; + case STOP_CACHE_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // The offending BRZ # is in bits 1-3. + GRP |= GRP_CHECK; + GRP &= ~GRP_RAM_CHECK; + GRP = GRP_SET_BLOCK (GRP, iintr_data); + break; + case STOP_INSN_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_BREAKPOINT; + break; + case STOP_LOAD_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_WATCHPT_R; + break; + case STOP_STORE_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_WATCHPT_W; + break; + case STOP_OVFL: + /* Прерывание по АУ вызывает останов, если БРО=0 + * и установлен ПоП или ПоК. + * Страница 118 ТО9.*/ + if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ + ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ + (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + GRP |= GRP_OVERFLOW|GRP_RAM_CHECK; + break; + case STOP_DIVZERO: + if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ + ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ + (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + GRP |= GRP_DIVZERO|GRP_RAM_CHECK; + break; + } + ++iintr; + } + + if (iintr > 1) { + besm6_draw_panel(); + return STOP_DOUBLE_INTR; + } + /* Main instruction fetch/decode loop */ + for (;;) { + if (sim_interval <= 0) { /* check clock queue */ + r = sim_process_event (); + if (r) { + besm6_draw_panel(); + return r; + } + } + + if (PC > BITS(15)) { /* выход за пределы памяти */ + besm6_draw_panel(); + return STOP_RUNOUT; /* stop simulation */ + } + + if (sim_brk_summ & SWMASK('E') && /* breakpoint? */ + sim_brk_test (PC, SWMASK ('E'))) { + besm6_draw_panel(); + return STOP_IBKPT; /* stop simulation */ + } + + if (PRP & MPRP) { + /* регистр хранящий, сбрасывается программно */ + GRP |= GRP_SLAVE; + } + + if (! iintr && ! (RUU & RUU_RIGHT_INSTR) && + ! (M[PSW] & PSW_INTR_DISABLE) && (GRP & MGRP)) { + /* external interrupt */ + op_int_2(); + } + cpu_one_inst (); /* one instr */ + iintr = 0; + if (redraw_panel) { + besm6_draw_panel(); + redraw_panel = 0; + } + + if (delay < 1) + delay = 1; + sim_interval -= delay; /* count down delay */ + if (sim_step && (--sim_step <= 0)) { /* do step count */ + besm6_draw_panel(); + return SCPE_STOP; + } + } +} + +t_stat slow_clk (UNIT * this) +{ + /*besm6_debug ("*** таймер 80 мсек");*/ + GRP |= GRP_SLOW_CLK; + return sim_activate (this, MSEC*125/2); +} + +/* + * В 9-й части частота таймера 250 Гц (4 мс), + * в жизни - 50 Гц (20 мс). + */ +t_stat fast_clk (UNIT * this) +{ + /*besm6_debug ("*** таймер 20 мсек");*/ + GRP |= GRP_TIMER; + return sim_activate (this, 20*MSEC); +} + +UNIT clocks[] = { + { UDATA(slow_clk, 0, 0) }, /* 10 р, 16 Гц */ + { UDATA(fast_clk, 0, 0) }, /* 40 р, 50 Гц */ +}; + +t_stat clk_reset (DEVICE * dev) +{ + /* Схема автозапуска включается по нереализованной кнопке "МР" */ +#ifdef SOFT_CLOCK + sim_activate (&clocks[0], MSEC*125/2); + return sim_activate (&clocks[1], 20*MSEC); +#else + return SCPE_OK; +#endif +} + +DEVICE clock_dev = { + "CLK", clocks, NULL, NULL, + 2, 0, 0, 0, 0, 0, + NULL, NULL, &clk_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG +}; diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index d782109a..3da2fa62 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -1,426 +1,426 @@ -/* - * besm6_defs.h: BESM-6 simulator definitions - * - * Copyright (c) 2009, Serge Vakulenko - * 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. - */ -#ifndef _BESM6_DEFS_H_ -#define _BESM6_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ -#include - -/* - * Memory. - */ -#define NREGS 30 /* number of registers-modifiers */ -#define MEMSIZE (512 * 1024) /* memory size, words */ - -/* - * Drums and disks. - * - * One zone contains 1024 words of user memory and 8 system data words. - * Every word (t_value) is stored as 8-byte record, low byte first. - * System data is stored first, then user data. - */ -#define ZONE_SIZE (8 + 1024) /* 1kword zone size, words */ -#define DRUM_SIZE (256 * ZONE_SIZE) /* drum size per controller, words */ -#define DISK_SIZE (1024 * ZONE_SIZE) /* disk size per unit, words */ - -/* - * Simulator stop codes - */ -enum { - STOP_STOP = 1, /* STOP */ - STOP_IBKPT, /* SIMH breakpoint */ - STOP_RWATCH, /* SIMH read watchpoint */ - STOP_WWATCH, /* SIMH write watchpoint */ - STOP_RUNOUT, /* run out end of memory limits */ - STOP_BADCMD, /* invalid instruction */ - STOP_INSN_CHECK, /* not an instruction */ - STOP_INSN_PROT, /* fetch from blocked page */ - STOP_OPERAND_PROT, /* load from blocked page */ - STOP_RAM_CHECK, /* RAM parity error */ - STOP_CACHE_CHECK, /* data cache parity error */ - STOP_OVFL, /* arith. overflow */ - STOP_DIVZERO, /* division by 0 or denorm */ - STOP_DOUBLE_INTR, /* double internal interrupt */ - STOP_DRUMINVDATA, /* reading unformatted drum */ - STOP_DISKINVDATA, /* reading unformatted disk */ - STOP_INSN_ADDR_MATCH, /* fetch address matched breakpt reg */ - STOP_LOAD_ADDR_MATCH, /* load address matched watchpt reg */ - STOP_STORE_ADDR_MATCH, /* store address matched watchpt reg */ - STOP_UNIMPLEMENTED, /* unimplemented 033 or 002 insn feature */ -}; - -/* - * Разряды машинного слова, справа налево, начиная с 1. - */ -#define BBIT(n) (1 << (n-1)) /* один бит, от 1 до 32 */ -#define BIT40 000010000000000000LL /* 40-й бит - старший разряд мантиссы */ -#define BIT41 000020000000000000LL /* 41-й бит - знак */ -#define BIT42 000040000000000000LL /* 42-й бит - дубль-знак в мантиссе */ -#define BIT48 004000000000000000LL /* 48-й бит - знак порядка */ -#define BIT49 010000000000000000LL /* бит 49 */ -#define BITS(n) (~0U >> (32-n)) /* маска битов n..1 */ -#define BITS40 00017777777777777LL /* биты 41..1 - мантисса */ -#define BITS41 00037777777777777LL /* биты 41..1 - мантисса и знак */ -#define BITS42 00077777777777777LL /* биты 42..1 - мантисса и оба знака */ -#define BITS48 07777777777777777LL /* биты 48..1 */ -#define BITS48_42 07740000000000000LL /* биты 48..42 - порядок */ -#define ADDR(x) ((x) & BITS(15)) /* адрес слова */ - -/* - * Работа со сверткой. Значение разрядов свертки слова равно значению - * регистров ПКЛ и ПКП при записи слова. - * 00 - командная свертка - * 01 или 10 - контроль числа - * 11 - числовая свертка - * В памяти биты свертки имитируют четность полуслов. - */ -#define CONVOL_INSN 1 -#define CONVOL_NUMBER 2 -#define SET_CONVOL(x, c) (((x) & BITS48) | (((c) & 3LL) << 48)) -#define IS_INSN(x) (((x) >> 48) == CONVOL_INSN) -#define IS_NUMBER(x) (((x) >> 48) == CONVOL_INSN || \ - ((x) >> 48) == CONVOL_NUMBER) - -/* - * Вычисление правдоподобного времени выполнения команды, - * зная количество тактов в УУ и среднее в АУ. - * Предполагаем, что в 50% случаев происходит совмещение - * выполнения, поэтому суммируем большее и половину - * от меньшего значения. - */ -#define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y) - -/* - * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. - */ -#define USEC 10 /* одна микросекунда - десять тактов */ -#define MSEC (1000*USEC) /* одна миллисекунда */ - -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern int32 sim_interval, sim_step; -extern FILE *sim_deb, *sim_log; -extern int32 sim_switches; - -extern UNIT cpu_unit; -extern t_value memory [MEMSIZE]; -extern t_value pult [8]; -extern uint32 PC, RAU, RUU; -extern uint32 M[NREGS]; -extern t_value BRZ[8], RP[8], GRP, MGRP; -extern uint32 PRP, MPRP; -extern t_value ACC, RMR; -extern uint32 BAZ[8], TABST, RZ; -extern uint32 READY; /* read by ext 4031 */ -extern uint32 READY2; /* read by ext 4102 */ -extern DEVICE cpu_dev, drum_dev, mmu_dev, disk_dev; -extern DEVICE clock_dev; -extern DEVICE printer_dev; -extern DEVICE tty_dev; -extern DEVICE fs_dev; -extern jmp_buf cpu_halt; - -/* - * Разряды режима АУ. - */ -#define RAU_NORM_DISABLE 001 /* блокировка нормализации */ -#define RAU_ROUND_DISABLE 002 /* блокировка округления */ -#define RAU_LOG 004 /* признак логической группы */ -#define RAU_MULT 010 /* признак группы умножения */ -#define RAU_ADD 020 /* признак группы слодения */ -#define RAU_OVF_DISABLE 040 /* блокировка переполнения */ - -#define RAU_MODE (RAU_LOG | RAU_MULT | RAU_ADD) -#define SET_MODE(x,m) (((x) & ~RAU_MODE) | (m)) -#define SET_LOGICAL(x) (((x) & ~RAU_MODE) | RAU_LOG) -#define SET_MULTIPLICATIVE(x) (((x) & ~RAU_MODE) | RAU_MULT) -#define SET_ADDITIVE(x) (((x) & ~RAU_MODE) | RAU_ADD) -#define IS_LOGICAL(x) (((x) & RAU_MODE) == RAU_LOG) -#define IS_MULTIPLICATIVE(x) (((x) & (RAU_ADD | RAU_MULT)) == RAU_MULT) -#define IS_ADDITIVE(x) ((x) & RAU_ADD) - -/* - * Искусственный регистр режимов УУ, в реальной машине отсутствует. - */ -#define RUU_CONVOL_RIGHT 000001 /* ПКП - признак контроля правой половины */ -#define RUU_CONVOL_LEFT 000002 /* ПКЛ - признак контроля левой половины */ -#define RUU_EXTRACODE 000004 /* РежЭ - режим экстракода */ -#define RUU_INTERRUPT 000010 /* РежПр - режим прерывания */ -#define RUU_MOD_RK 000020 /* ПрИК - модификация регистром М[16] */ -#define RUU_AVOST_DISABLE 000040 /* БРО - блокировка режима останова */ -#define RUU_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ - -#define IS_SUPERVISOR(x) ((x) & (RUU_EXTRACODE | RUU_INTERRUPT)) -#define SET_SUPERVISOR(x,m) (((x) & ~(RUU_EXTRACODE | RUU_INTERRUPT)) | (m)) - -/* - * Специальные регистры. - */ -#define MOD 020 /* модификатор адреса */ -#define PSW 021 /* режимы УУ */ -#define SPSW 027 /* упрятывание режимов УУ */ -#define ERET 032 /* адрес возврата из экстракода */ -#define IRET 033 /* адрес возврата из прерывания */ -#define IBP 034 /* адрес прерывания по выполнению */ -#define DWP 035 /* адрес прерывания по чтению/записи */ - -/* - * Регистр 021: режимы УУ. - * PSW: program status word. - */ -#define PSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ -#define PSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ -#define PSW_INTR_HALT 000004 /* ПоП - признак останова при - любом внутреннем прерывании */ -#define PSW_CHECK_HALT 000010 /* ПоК - признак останова при - прерывании по контролю */ -#define PSW_WRITE_WATCH 000020 /* Зп(М29) - признак совпадения адреса - операнда прии записи в память - с содержанием регистра М29 */ -#define PSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ -#define PSW_AUT_B 004000 /* АвтБ - признак режима Автомат Б */ - -/* - * Регистр 027: сохранённые режимы УУ. - * SPSW: saved program status word. - */ -#define SPSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ -#define SPSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ -#define SPSW_EXTRACODE 000004 /* РежЭ - режим экстракода */ -#define SPSW_INTERRUPT 000010 /* РежПр - режим прерывания */ -#define SPSW_MOD_RK 000020 /* ПрИК(РК) - на регистр РК принята - команда, которая должна быть - модифицирована регистром М[16] */ -#define SPSW_MOD_RR 000040 /* ПрИК(РР) - на регистре РР находится - команда, выполненная с модификацией */ -#define SPSW_UNKNOWN 000100 /* НОК? вписано карандашом в 9 томе */ -#define SPSW_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ -#define SPSW_NEXT_RK 001000 /* ГД./ДК2 - на регистр РК принята - команда, следующая после вызвавшей - прерывание */ -#define SPSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ - -/* - * Кириллица Unicode. - */ -#define CYRILLIC_CAPITAL_LETTER_A 0x0410 -#define CYRILLIC_CAPITAL_LETTER_BE 0x0411 -#define CYRILLIC_CAPITAL_LETTER_VE 0x0412 -#define CYRILLIC_CAPITAL_LETTER_GHE 0x0413 -#define CYRILLIC_CAPITAL_LETTER_DE 0x0414 -#define CYRILLIC_CAPITAL_LETTER_IE 0x0415 -#define CYRILLIC_CAPITAL_LETTER_ZHE 0x0416 -#define CYRILLIC_CAPITAL_LETTER_ZE 0x0417 -#define CYRILLIC_CAPITAL_LETTER_I 0x0418 -#define CYRILLIC_CAPITAL_LETTER_SHORT_I 0x0419 -#define CYRILLIC_CAPITAL_LETTER_KA 0x041a -#define CYRILLIC_CAPITAL_LETTER_EL 0x041b -#define CYRILLIC_CAPITAL_LETTER_EM 0x041c -#define CYRILLIC_CAPITAL_LETTER_EN 0x041d -#define CYRILLIC_CAPITAL_LETTER_O 0x041e -#define CYRILLIC_CAPITAL_LETTER_PE 0x041f -#define CYRILLIC_CAPITAL_LETTER_ER 0x0420 -#define CYRILLIC_CAPITAL_LETTER_ES 0x0421 -#define CYRILLIC_CAPITAL_LETTER_TE 0x0422 -#define CYRILLIC_CAPITAL_LETTER_U 0x0423 -#define CYRILLIC_CAPITAL_LETTER_EF 0x0424 -#define CYRILLIC_CAPITAL_LETTER_HA 0x0425 -#define CYRILLIC_CAPITAL_LETTER_TSE 0x0426 -#define CYRILLIC_CAPITAL_LETTER_CHE 0x0427 -#define CYRILLIC_CAPITAL_LETTER_SHA 0x0428 -#define CYRILLIC_CAPITAL_LETTER_SHCHA 0x0429 -#define CYRILLIC_CAPITAL_LETTER_HARD_SIGN 0x042a -#define CYRILLIC_CAPITAL_LETTER_YERU 0x042b -#define CYRILLIC_CAPITAL_LETTER_SOFT_SIGN 0x042c -#define CYRILLIC_CAPITAL_LETTER_E 0x042d -#define CYRILLIC_CAPITAL_LETTER_YU 0x042e -#define CYRILLIC_CAPITAL_LETTER_YA 0x042f -#define CYRILLIC_SMALL_LETTER_A 0x0430 -#define CYRILLIC_SMALL_LETTER_BE 0x0431 -#define CYRILLIC_SMALL_LETTER_VE 0x0432 -#define CYRILLIC_SMALL_LETTER_GHE 0x0433 -#define CYRILLIC_SMALL_LETTER_DE 0x0434 -#define CYRILLIC_SMALL_LETTER_IE 0x0435 -#define CYRILLIC_SMALL_LETTER_ZHE 0x0436 -#define CYRILLIC_SMALL_LETTER_ZE 0x0437 -#define CYRILLIC_SMALL_LETTER_I 0x0438 -#define CYRILLIC_SMALL_LETTER_SHORT_I 0x0439 -#define CYRILLIC_SMALL_LETTER_KA 0x043a -#define CYRILLIC_SMALL_LETTER_EL 0x043b -#define CYRILLIC_SMALL_LETTER_EM 0x043c -#define CYRILLIC_SMALL_LETTER_EN 0x043d -#define CYRILLIC_SMALL_LETTER_O 0x043e -#define CYRILLIC_SMALL_LETTER_PE 0x043f -#define CYRILLIC_SMALL_LETTER_ER 0x0440 -#define CYRILLIC_SMALL_LETTER_ES 0x0441 -#define CYRILLIC_SMALL_LETTER_TE 0x0442 -#define CYRILLIC_SMALL_LETTER_U 0x0443 -#define CYRILLIC_SMALL_LETTER_EF 0x0444 -#define CYRILLIC_SMALL_LETTER_HA 0x0445 -#define CYRILLIC_SMALL_LETTER_TSE 0x0446 -#define CYRILLIC_SMALL_LETTER_CHE 0x0447 -#define CYRILLIC_SMALL_LETTER_SHA 0x0448 -#define CYRILLIC_SMALL_LETTER_SHCHA 0x0449 -#define CYRILLIC_SMALL_LETTER_HARD_SIGN 0x044a -#define CYRILLIC_SMALL_LETTER_YERU 0x044b -#define CYRILLIC_SMALL_LETTER_SOFT_SIGN 0x044c -#define CYRILLIC_SMALL_LETTER_E 0x044d -#define CYRILLIC_SMALL_LETTER_YU 0x044e -#define CYRILLIC_SMALL_LETTER_YA 0x044f - -/* - * Процедуры работы с памятью - */ -extern void mmu_store (int addr, t_value word); -extern t_value mmu_load (int addr); -extern t_value mmu_fetch (int addr); -extern t_value mmu_prefetch (int addr, int actual); -extern void mmu_setcache (int idx, t_value word); -extern t_value mmu_getcache (int idx); -extern void mmu_setrp (int idx, t_value word); -extern void mmu_setup (void); -extern void mmu_setprotection (int idx, t_value word); -extern void mmu_print_brz (void); - -/* - * Выполнение обращения к барабану. - */ -void drum (int ctlr, uint32 cmd); -int drum_errors (void); - -/* - * Обращение к дискам. - */ -void disk_io (int ctlr, uint32 cmd); -void disk_ctl (int ctlr, uint32 cmd); -int disk_state (int ctlr); -int disk_errors (void); - -/* - * Печать на АЦПУ. - */ -void printer_control (int num, uint32 cmd); -void printer_hammer (int num, int pos, uint32 mask); -int printer_is_idle (void); - -/* - * Терминалы (телетайпы, видеотоны, "Консулы"). - */ -void tty_send (uint32 mask); -int tty_query (void); -void vt_print (void); -void vt_receive (void); -void consul_print (int num, uint32 cmd); -uint32 consul_read (int num); -int vt_is_idle (void); - -/* - * Ввод с перфоленты. - */ -void fs_control (int num, uint32 cmd); -int fs_read (int num); -int fs_is_idle (void); - -/* - * Отладочная выдача. - */ -void besm6_fprint_cmd (FILE *of, uint32 cmd); -void besm6_log (const char *fmt, ...); -void besm6_log_cont (const char *fmt, ...); -void besm6_debug (const char *fmt, ...); -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); -void besm6_draw_panel (void); - -/* - * Арифметика. - */ -double besm6_to_ieee (t_value word); -void besm6_add (t_value val, int negate_acc, int negate_val); -void besm6_divide (t_value val); -void besm6_multiply (t_value val); -void besm6_change_sign (int sign); -void besm6_add_exponent (int val); -int besm6_highest_bit (t_value val); -void besm6_shift (int toright); -int besm6_count_ones (t_value word); -t_value besm6_pack (t_value val, t_value mask); -t_value besm6_unpack (t_value val, t_value mask); - -/* - * Разряды главного регистра прерываний (ГРП) - * Внешние: - */ -#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */ -#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */ -#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */ -#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */ -#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */ -#define GRP_FS1_SYNC 00040000000000000LL /* 42 */ -#define GRP_FS2_SYNC 00020000000000000LL /* 41 */ -#define GRP_TIMER 00010000000000000LL /* 40 */ -#define GRP_PRN1_ZERO 00004000000000000LL /* 39 */ -#define GRP_PRN2_ZERO 00002000000000000LL /* 38 */ -#define GRP_SLAVE 00001000000000000LL /* 37 */ -#define GRP_CHAN3_DONE 00000400000000000LL /* 36 */ -#define GRP_CHAN4_DONE 00000200000000000LL /* 35 */ -#define GRP_CHAN5_DONE 00000100000000000LL /* 34 */ -#define GRP_CHAN6_DONE 00000040000000000LL /* 33 */ -#define GRP_PANEL_REQ 00000020000000000LL /* 32 */ -#define GRP_TTY_START 00000010000000000LL /* 31 */ -#define GRP_IMITATION 00000004000000000LL /* 30 */ -#define GRP_CHAN3_FREE 00000002000000000LL /* 29 */ -#define GRP_CHAN4_FREE 00000001000000000LL /* 28 */ -#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ -#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ -#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ -#define GRP_WATCHDOG 00000000000002000LL /* 11 */ -#define GRP_SLOW_CLK 00000000000001000LL /* 10 */ -/* Внутренние: */ -#define GRP_DIVZERO 00000000034000000LL /* 23-21 */ -#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */ -#define GRP_CHECK 00000000004000000LL /* 21 */ -#define GRP_OPRND_PROT 00000000002000000LL /* 20 */ -#define GRP_WATCHPT_W 00000000000200000LL /* 17 */ -#define GRP_WATCHPT_R 00000000000100000LL /* 16 */ -#define GRP_INSN_CHECK 00000000000040000LL /* 15 */ -#define GRP_INSN_PROT 00000000000020000LL /* 14 */ -#define GRP_ILL_INSN 00000000000010000LL /* 13 */ -#define GRP_BREAKPOINT 00000000000004000LL /* 12 */ -#define GRP_PAGE_MASK 00000000000000760LL /* 9-5 */ -#define GRP_RAM_CHECK 00000000000000010LL /* 4 */ -#define GRP_BLOCK_MASK 00000000000000007LL /* 3-1 */ - -#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK)) -#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK)) - -/* Номер блока ОЗУ или номер страницы, вызвавших прерывание */ -extern uint32 iintr_data; - -#endif +/* + * besm6_defs.h: BESM-6 simulator definitions + * + * Copyright (c) 2009, Serge Vakulenko + * 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. + */ +#ifndef _BESM6_DEFS_H_ +#define _BESM6_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ +#include + +/* + * Memory. + */ +#define NREGS 30 /* number of registers-modifiers */ +#define MEMSIZE (512 * 1024) /* memory size, words */ + +/* + * Drums and disks. + * + * One zone contains 1024 words of user memory and 8 system data words. + * Every word (t_value) is stored as 8-byte record, low byte first. + * System data is stored first, then user data. + */ +#define ZONE_SIZE (8 + 1024) /* 1kword zone size, words */ +#define DRUM_SIZE (256 * ZONE_SIZE) /* drum size per controller, words */ +#define DISK_SIZE (1024 * ZONE_SIZE) /* disk size per unit, words */ + +/* + * Simulator stop codes + */ +enum { + STOP_STOP = 1, /* STOP */ + STOP_IBKPT, /* SIMH breakpoint */ + STOP_RWATCH, /* SIMH read watchpoint */ + STOP_WWATCH, /* SIMH write watchpoint */ + STOP_RUNOUT, /* run out end of memory limits */ + STOP_BADCMD, /* invalid instruction */ + STOP_INSN_CHECK, /* not an instruction */ + STOP_INSN_PROT, /* fetch from blocked page */ + STOP_OPERAND_PROT, /* load from blocked page */ + STOP_RAM_CHECK, /* RAM parity error */ + STOP_CACHE_CHECK, /* data cache parity error */ + STOP_OVFL, /* arith. overflow */ + STOP_DIVZERO, /* division by 0 or denorm */ + STOP_DOUBLE_INTR, /* double internal interrupt */ + STOP_DRUMINVDATA, /* reading unformatted drum */ + STOP_DISKINVDATA, /* reading unformatted disk */ + STOP_INSN_ADDR_MATCH, /* fetch address matched breakpt reg */ + STOP_LOAD_ADDR_MATCH, /* load address matched watchpt reg */ + STOP_STORE_ADDR_MATCH, /* store address matched watchpt reg */ + STOP_UNIMPLEMENTED, /* unimplemented 033 or 002 insn feature */ +}; + +/* + * Разряды машинного слова, справа налево, начиная с 1. + */ +#define BBIT(n) (1 << (n-1)) /* один бит, от 1 до 32 */ +#define BIT40 000010000000000000LL /* 40-й бит - старший разряд мантиссы */ +#define BIT41 000020000000000000LL /* 41-й бит - знак */ +#define BIT42 000040000000000000LL /* 42-й бит - дубль-знак в мантиссе */ +#define BIT48 004000000000000000LL /* 48-й бит - знак порядка */ +#define BIT49 010000000000000000LL /* бит 49 */ +#define BITS(n) (~0U >> (32-n)) /* маска битов n..1 */ +#define BITS40 00017777777777777LL /* биты 41..1 - мантисса */ +#define BITS41 00037777777777777LL /* биты 41..1 - мантисса и знак */ +#define BITS42 00077777777777777LL /* биты 42..1 - мантисса и оба знака */ +#define BITS48 07777777777777777LL /* биты 48..1 */ +#define BITS48_42 07740000000000000LL /* биты 48..42 - порядок */ +#define ADDR(x) ((x) & BITS(15)) /* адрес слова */ + +/* + * Работа со сверткой. Значение разрядов свертки слова равно значению + * регистров ПКЛ и ПКП при записи слова. + * 00 - командная свертка + * 01 или 10 - контроль числа + * 11 - числовая свертка + * В памяти биты свертки имитируют четность полуслов. + */ +#define CONVOL_INSN 1 +#define CONVOL_NUMBER 2 +#define SET_CONVOL(x, c) (((x) & BITS48) | (((c) & 3LL) << 48)) +#define IS_INSN(x) (((x) >> 48) == CONVOL_INSN) +#define IS_NUMBER(x) (((x) >> 48) == CONVOL_INSN || \ + ((x) >> 48) == CONVOL_NUMBER) + +/* + * Вычисление правдоподобного времени выполнения команды, + * зная количество тактов в УУ и среднее в АУ. + * Предполагаем, что в 50% случаев происходит совмещение + * выполнения, поэтому суммируем большее и половину + * от меньшего значения. + */ +#define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y) + +/* + * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. + */ +#define USEC 10 /* одна микросекунда - десять тактов */ +#define MSEC (1000*USEC) /* одна миллисекунда */ + +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern int32 sim_interval, sim_step; +extern FILE *sim_deb, *sim_log; +extern int32 sim_switches; + +extern UNIT cpu_unit; +extern t_value memory [MEMSIZE]; +extern t_value pult [8]; +extern uint32 PC, RAU, RUU; +extern uint32 M[NREGS]; +extern t_value BRZ[8], RP[8], GRP, MGRP; +extern uint32 PRP, MPRP; +extern t_value ACC, RMR; +extern uint32 BAZ[8], TABST, RZ; +extern uint32 READY; /* read by ext 4031 */ +extern uint32 READY2; /* read by ext 4102 */ +extern DEVICE cpu_dev, drum_dev, mmu_dev, disk_dev; +extern DEVICE clock_dev; +extern DEVICE printer_dev; +extern DEVICE tty_dev; +extern DEVICE fs_dev; +extern jmp_buf cpu_halt; + +/* + * Разряды режима АУ. + */ +#define RAU_NORM_DISABLE 001 /* блокировка нормализации */ +#define RAU_ROUND_DISABLE 002 /* блокировка округления */ +#define RAU_LOG 004 /* признак логической группы */ +#define RAU_MULT 010 /* признак группы умножения */ +#define RAU_ADD 020 /* признак группы слодения */ +#define RAU_OVF_DISABLE 040 /* блокировка переполнения */ + +#define RAU_MODE (RAU_LOG | RAU_MULT | RAU_ADD) +#define SET_MODE(x,m) (((x) & ~RAU_MODE) | (m)) +#define SET_LOGICAL(x) (((x) & ~RAU_MODE) | RAU_LOG) +#define SET_MULTIPLICATIVE(x) (((x) & ~RAU_MODE) | RAU_MULT) +#define SET_ADDITIVE(x) (((x) & ~RAU_MODE) | RAU_ADD) +#define IS_LOGICAL(x) (((x) & RAU_MODE) == RAU_LOG) +#define IS_MULTIPLICATIVE(x) (((x) & (RAU_ADD | RAU_MULT)) == RAU_MULT) +#define IS_ADDITIVE(x) ((x) & RAU_ADD) + +/* + * Искусственный регистр режимов УУ, в реальной машине отсутствует. + */ +#define RUU_CONVOL_RIGHT 000001 /* ПКП - признак контроля правой половины */ +#define RUU_CONVOL_LEFT 000002 /* ПКЛ - признак контроля левой половины */ +#define RUU_EXTRACODE 000004 /* РежЭ - режим экстракода */ +#define RUU_INTERRUPT 000010 /* РежПр - режим прерывания */ +#define RUU_MOD_RK 000020 /* ПрИК - модификация регистром М[16] */ +#define RUU_AVOST_DISABLE 000040 /* БРО - блокировка режима останова */ +#define RUU_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ + +#define IS_SUPERVISOR(x) ((x) & (RUU_EXTRACODE | RUU_INTERRUPT)) +#define SET_SUPERVISOR(x,m) (((x) & ~(RUU_EXTRACODE | RUU_INTERRUPT)) | (m)) + +/* + * Специальные регистры. + */ +#define MOD 020 /* модификатор адреса */ +#define PSW 021 /* режимы УУ */ +#define SPSW 027 /* упрятывание режимов УУ */ +#define ERET 032 /* адрес возврата из экстракода */ +#define IRET 033 /* адрес возврата из прерывания */ +#define IBP 034 /* адрес прерывания по выполнению */ +#define DWP 035 /* адрес прерывания по чтению/записи */ + +/* + * Регистр 021: режимы УУ. + * PSW: program status word. + */ +#define PSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ +#define PSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ +#define PSW_INTR_HALT 000004 /* ПоП - признак останова при + любом внутреннем прерывании */ +#define PSW_CHECK_HALT 000010 /* ПоК - признак останова при + прерывании по контролю */ +#define PSW_WRITE_WATCH 000020 /* Зп(М29) - признак совпадения адреса + операнда прии записи в память + с содержанием регистра М29 */ +#define PSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ +#define PSW_AUT_B 004000 /* АвтБ - признак режима Автомат Б */ + +/* + * Регистр 027: сохранённые режимы УУ. + * SPSW: saved program status word. + */ +#define SPSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ +#define SPSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ +#define SPSW_EXTRACODE 000004 /* РежЭ - режим экстракода */ +#define SPSW_INTERRUPT 000010 /* РежПр - режим прерывания */ +#define SPSW_MOD_RK 000020 /* ПрИК(РК) - на регистр РК принята + команда, которая должна быть + модифицирована регистром М[16] */ +#define SPSW_MOD_RR 000040 /* ПрИК(РР) - на регистре РР находится + команда, выполненная с модификацией */ +#define SPSW_UNKNOWN 000100 /* НОК? вписано карандашом в 9 томе */ +#define SPSW_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ +#define SPSW_NEXT_RK 001000 /* ГД./ДК2 - на регистр РК принята + команда, следующая после вызвавшей + прерывание */ +#define SPSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ + +/* + * Кириллица Unicode. + */ +#define CYRILLIC_CAPITAL_LETTER_A 0x0410 +#define CYRILLIC_CAPITAL_LETTER_BE 0x0411 +#define CYRILLIC_CAPITAL_LETTER_VE 0x0412 +#define CYRILLIC_CAPITAL_LETTER_GHE 0x0413 +#define CYRILLIC_CAPITAL_LETTER_DE 0x0414 +#define CYRILLIC_CAPITAL_LETTER_IE 0x0415 +#define CYRILLIC_CAPITAL_LETTER_ZHE 0x0416 +#define CYRILLIC_CAPITAL_LETTER_ZE 0x0417 +#define CYRILLIC_CAPITAL_LETTER_I 0x0418 +#define CYRILLIC_CAPITAL_LETTER_SHORT_I 0x0419 +#define CYRILLIC_CAPITAL_LETTER_KA 0x041a +#define CYRILLIC_CAPITAL_LETTER_EL 0x041b +#define CYRILLIC_CAPITAL_LETTER_EM 0x041c +#define CYRILLIC_CAPITAL_LETTER_EN 0x041d +#define CYRILLIC_CAPITAL_LETTER_O 0x041e +#define CYRILLIC_CAPITAL_LETTER_PE 0x041f +#define CYRILLIC_CAPITAL_LETTER_ER 0x0420 +#define CYRILLIC_CAPITAL_LETTER_ES 0x0421 +#define CYRILLIC_CAPITAL_LETTER_TE 0x0422 +#define CYRILLIC_CAPITAL_LETTER_U 0x0423 +#define CYRILLIC_CAPITAL_LETTER_EF 0x0424 +#define CYRILLIC_CAPITAL_LETTER_HA 0x0425 +#define CYRILLIC_CAPITAL_LETTER_TSE 0x0426 +#define CYRILLIC_CAPITAL_LETTER_CHE 0x0427 +#define CYRILLIC_CAPITAL_LETTER_SHA 0x0428 +#define CYRILLIC_CAPITAL_LETTER_SHCHA 0x0429 +#define CYRILLIC_CAPITAL_LETTER_HARD_SIGN 0x042a +#define CYRILLIC_CAPITAL_LETTER_YERU 0x042b +#define CYRILLIC_CAPITAL_LETTER_SOFT_SIGN 0x042c +#define CYRILLIC_CAPITAL_LETTER_E 0x042d +#define CYRILLIC_CAPITAL_LETTER_YU 0x042e +#define CYRILLIC_CAPITAL_LETTER_YA 0x042f +#define CYRILLIC_SMALL_LETTER_A 0x0430 +#define CYRILLIC_SMALL_LETTER_BE 0x0431 +#define CYRILLIC_SMALL_LETTER_VE 0x0432 +#define CYRILLIC_SMALL_LETTER_GHE 0x0433 +#define CYRILLIC_SMALL_LETTER_DE 0x0434 +#define CYRILLIC_SMALL_LETTER_IE 0x0435 +#define CYRILLIC_SMALL_LETTER_ZHE 0x0436 +#define CYRILLIC_SMALL_LETTER_ZE 0x0437 +#define CYRILLIC_SMALL_LETTER_I 0x0438 +#define CYRILLIC_SMALL_LETTER_SHORT_I 0x0439 +#define CYRILLIC_SMALL_LETTER_KA 0x043a +#define CYRILLIC_SMALL_LETTER_EL 0x043b +#define CYRILLIC_SMALL_LETTER_EM 0x043c +#define CYRILLIC_SMALL_LETTER_EN 0x043d +#define CYRILLIC_SMALL_LETTER_O 0x043e +#define CYRILLIC_SMALL_LETTER_PE 0x043f +#define CYRILLIC_SMALL_LETTER_ER 0x0440 +#define CYRILLIC_SMALL_LETTER_ES 0x0441 +#define CYRILLIC_SMALL_LETTER_TE 0x0442 +#define CYRILLIC_SMALL_LETTER_U 0x0443 +#define CYRILLIC_SMALL_LETTER_EF 0x0444 +#define CYRILLIC_SMALL_LETTER_HA 0x0445 +#define CYRILLIC_SMALL_LETTER_TSE 0x0446 +#define CYRILLIC_SMALL_LETTER_CHE 0x0447 +#define CYRILLIC_SMALL_LETTER_SHA 0x0448 +#define CYRILLIC_SMALL_LETTER_SHCHA 0x0449 +#define CYRILLIC_SMALL_LETTER_HARD_SIGN 0x044a +#define CYRILLIC_SMALL_LETTER_YERU 0x044b +#define CYRILLIC_SMALL_LETTER_SOFT_SIGN 0x044c +#define CYRILLIC_SMALL_LETTER_E 0x044d +#define CYRILLIC_SMALL_LETTER_YU 0x044e +#define CYRILLIC_SMALL_LETTER_YA 0x044f + +/* + * Процедуры работы с памятью + */ +extern void mmu_store (int addr, t_value word); +extern t_value mmu_load (int addr); +extern t_value mmu_fetch (int addr); +extern t_value mmu_prefetch (int addr, int actual); +extern void mmu_setcache (int idx, t_value word); +extern t_value mmu_getcache (int idx); +extern void mmu_setrp (int idx, t_value word); +extern void mmu_setup (void); +extern void mmu_setprotection (int idx, t_value word); +extern void mmu_print_brz (void); + +/* + * Выполнение обращения к барабану. + */ +void drum (int ctlr, uint32 cmd); +int drum_errors (void); + +/* + * Обращение к дискам. + */ +void disk_io (int ctlr, uint32 cmd); +void disk_ctl (int ctlr, uint32 cmd); +int disk_state (int ctlr); +int disk_errors (void); + +/* + * Печать на АЦПУ. + */ +void printer_control (int num, uint32 cmd); +void printer_hammer (int num, int pos, uint32 mask); +int printer_is_idle (void); + +/* + * Терминалы (телетайпы, видеотоны, "Консулы"). + */ +void tty_send (uint32 mask); +int tty_query (void); +void vt_print (void); +void vt_receive (void); +void consul_print (int num, uint32 cmd); +uint32 consul_read (int num); +int vt_is_idle (void); + +/* + * Ввод с перфоленты. + */ +void fs_control (int num, uint32 cmd); +int fs_read (int num); +int fs_is_idle (void); + +/* + * Отладочная выдача. + */ +void besm6_fprint_cmd (FILE *of, uint32 cmd); +void besm6_log (const char *fmt, ...); +void besm6_log_cont (const char *fmt, ...); +void besm6_debug (const char *fmt, ...); +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); +void besm6_draw_panel (void); + +/* + * Арифметика. + */ +double besm6_to_ieee (t_value word); +void besm6_add (t_value val, int negate_acc, int negate_val); +void besm6_divide (t_value val); +void besm6_multiply (t_value val); +void besm6_change_sign (int sign); +void besm6_add_exponent (int val); +int besm6_highest_bit (t_value val); +void besm6_shift (int toright); +int besm6_count_ones (t_value word); +t_value besm6_pack (t_value val, t_value mask); +t_value besm6_unpack (t_value val, t_value mask); + +/* + * Разряды главного регистра прерываний (ГРП) + * Внешние: + */ +#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */ +#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */ +#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */ +#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */ +#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */ +#define GRP_FS1_SYNC 00040000000000000LL /* 42 */ +#define GRP_FS2_SYNC 00020000000000000LL /* 41 */ +#define GRP_TIMER 00010000000000000LL /* 40 */ +#define GRP_PRN1_ZERO 00004000000000000LL /* 39 */ +#define GRP_PRN2_ZERO 00002000000000000LL /* 38 */ +#define GRP_SLAVE 00001000000000000LL /* 37 */ +#define GRP_CHAN3_DONE 00000400000000000LL /* 36 */ +#define GRP_CHAN4_DONE 00000200000000000LL /* 35 */ +#define GRP_CHAN5_DONE 00000100000000000LL /* 34 */ +#define GRP_CHAN6_DONE 00000040000000000LL /* 33 */ +#define GRP_PANEL_REQ 00000020000000000LL /* 32 */ +#define GRP_TTY_START 00000010000000000LL /* 31 */ +#define GRP_IMITATION 00000004000000000LL /* 30 */ +#define GRP_CHAN3_FREE 00000002000000000LL /* 29 */ +#define GRP_CHAN4_FREE 00000001000000000LL /* 28 */ +#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ +#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ +#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ +#define GRP_WATCHDOG 00000000000002000LL /* 11 */ +#define GRP_SLOW_CLK 00000000000001000LL /* 10 */ +/* Внутренние: */ +#define GRP_DIVZERO 00000000034000000LL /* 23-21 */ +#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */ +#define GRP_CHECK 00000000004000000LL /* 21 */ +#define GRP_OPRND_PROT 00000000002000000LL /* 20 */ +#define GRP_WATCHPT_W 00000000000200000LL /* 17 */ +#define GRP_WATCHPT_R 00000000000100000LL /* 16 */ +#define GRP_INSN_CHECK 00000000000040000LL /* 15 */ +#define GRP_INSN_PROT 00000000000020000LL /* 14 */ +#define GRP_ILL_INSN 00000000000010000LL /* 13 */ +#define GRP_BREAKPOINT 00000000000004000LL /* 12 */ +#define GRP_PAGE_MASK 00000000000000760LL /* 9-5 */ +#define GRP_RAM_CHECK 00000000000000010LL /* 4 */ +#define GRP_BLOCK_MASK 00000000000000007LL /* 3-1 */ + +#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK)) +#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK)) + +/* Номер блока ОЗУ или номер страницы, вызвавших прерывание */ +extern uint32 iintr_data; + +#endif diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index 37fbd23c..1ff0ed32 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -1,648 +1,648 @@ -/* - * BESM-6 magnetic disk device - * - * Copyright (c) 2009, Serge Vakulenko - * 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" - -/* - * Управляющее слово обмена с магнитным диском. - */ -#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */ -#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */ -#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */ -#define DISK_READ 000400000 /* чтение с диска в память */ -#define DISK_PAGE 000370000 /* номер страницы памяти */ -#define DISK_HALFPAGE 000004000 /* выбор половины листа */ -#define DISK_UNIT 000001600 /* номер устройства */ -#define DISK_HALFZONE 000000001 /* выбор половины зоны */ - -/* - * "Хороший" статус чтения/записи. - * Вычислено по текстам ОС Дубна. - * Диспак доволен. - */ -#define STATUS_GOOD 014000400 - -/* - * Параметры обмена с внешним устройством. - */ -typedef struct { - int op; /* Условное слово обмена */ - int dev; /* Номер устройства, 0..7 */ - int zone; /* Номер зоны на диске */ - int track; /* Выбор половины зоны на диске */ - int memory; /* Начальный адрес памяти */ - int format; /* Флаг разметки */ - int status; /* Регистр состояния */ - t_value mask_grp; /* Маска готовности для ГРП */ - int mask_fail; /* Маска ошибки обмена */ - t_value *sysdata; /* Буфер системных данных */ -} KMD; - -static KMD controller [2]; /* Две стойки КМД */ -int disk_fail; /* Маска ошибок по направлениям */ - -t_stat disk_event (UNIT *u); - -/* - * DISK data structures - * - * disk_dev DISK device descriptor - * disk_unit DISK unit descriptor - * disk_reg DISK register list - */ -UNIT disk_unit [16] = { - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, -}; - -REG disk_reg[] = { -{ "КУС_0", &controller[0].op, 8, 24, 0, 1 }, -{ "УСТР_0", &controller[0].dev, 8, 3, 0, 1 }, -{ "ЗОНА_0", &controller[0].zone, 8, 10, 0, 1 }, -{ "ДОРОЖКА_0", &controller[0].track, 8, 2, 0, 1 }, -{ "МОЗУ_0", &controller[0].memory, 8, 20, 0, 1 }, -{ "РС_0", &controller[0].status, 8, 24, 0, 1 }, -{ "КУС_1", &controller[1].op, 8, 24, 0, 1 }, -{ "УСТР_1", &controller[1].dev, 8, 3, 0, 1 }, -{ "ЗОНА_1", &controller[1].zone, 8, 10, 0, 1 }, -{ "ДОРОЖКА_1", &controller[1].track, 8, 2, 0, 1 }, -{ "МОЗУ_1", &controller[1].memory, 8, 20, 0, 1 }, -{ "РС_1", &controller[1].status, 8, 24, 0, 1 }, -{ "ОШ", &disk_fail, 8, 6, 0, 1 }, -{ 0 } -}; - -MTAB disk_mod[] = { - { 0 } -}; - -t_stat disk_reset (DEVICE *dptr); -t_stat disk_attach (UNIT *uptr, char *cptr); -t_stat disk_detach (UNIT *uptr); - -DEVICE disk_dev = { - "DISK", disk_unit, disk_reg, disk_mod, - 16, 8, 21, 1, 8, 50, - NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach, - NULL, DEV_DISABLE | DEV_DEBUG -}; - -/* - * Определение контроллера по устройству. - */ -static KMD *unit_to_ctlr (UNIT *u) -{ - if (u < &disk_unit[8]) - return &controller[0]; - else - return &controller[1]; -} - -/* - * Reset routine - */ -t_stat disk_reset (DEVICE *dptr) -{ - int i; - - memset (&controller, 0, sizeof (controller)); - controller[0].sysdata = &memory [030]; - controller[1].sysdata = &memory [040]; - controller[0].mask_grp = GRP_CHAN3_FREE; - controller[1].mask_grp = GRP_CHAN4_FREE; - controller[0].mask_fail = 020; - controller[1].mask_fail = 010; - for (i=0; i<16; ++i) - sim_cancel (&disk_unit[i]); - return SCPE_OK; -} - -t_stat disk_attach (UNIT *u, char *cptr) -{ - t_stat s; - - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; - return SCPE_OK; -} - -t_stat disk_detach (UNIT *u) -{ - /* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */ - return detach_unit (u); -} - -t_value spread (t_value val) -{ - int i, j; - t_value res = 0; - - for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) - if (val & (1LL<<(i+j*5))) - res |= 1LL << (i*9+j); - return res & BITS48; -} - -/* - * Отладочная печать массива данных обмена. - */ -static void log_data (t_value *data, int nwords) -{ - int i; - t_value val; - - for (i=0; i> 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"); -} - -/* - * Сложение с переносом вправо. - */ -static unsigned sum_with_right_carry (unsigned a, unsigned b) -{ - unsigned c; - - while (b) { - c = a & b; - a ^= b; - b = c >> 1; - } - return a; -} - -/* - * Запись на диск. - */ -void disk_write (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - - if (disk_dev.dctrl) - besm6_debug ("::: запись МД %o зона %04o память %05o-%05o", - c->dev, c->zone, c->memory, c->memory + 1023); - fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); - sim_fwrite (c->sysdata, 8, 8, u->fileref); - sim_fwrite (&memory [c->memory], 8, 1024, u->fileref); - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); -} - -void disk_write_track (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - - if (disk_dev.dctrl) - besm6_debug ("::: запись МД %o полузона %04o.%d память %05o-%05o", - c->dev, c->zone, c->track, c->memory, c->memory + 511); - fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); - sim_fwrite (c->sysdata + 4*c->track, 8, 4, u->fileref); - fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, - SEEK_SET); - sim_fwrite (&memory [c->memory], 8, 512, u->fileref); - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); -} - -/* - * Форматирование дорожки. - */ -void disk_format (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - t_value fmtbuf[5], *ptr; - int i; - - /* По сути, эмулятору ничего делать не надо. */ - if (! disk_dev.dctrl) - return; - - /* Находим начало записываемого заголовка. */ - ptr = &memory [c->memory]; - while ((*ptr & BITS48) == 0) - ptr++; - - /* Декодируем из гребенки в нормальный вид. */ - for (i = 0; i < 5; i++) - fmtbuf[i] = spread (ptr[i]); - - /* При первой попытке разметки адресный маркер начинается в старшем 5-разрядном слоге, - * пропускаем первый слог. */ - for (i=0; i<4; i++) - fmtbuf[i] = ((fmtbuf[i] & BITS48) << 5) | - ((fmtbuf[i+1] >> 40) & BITS(5)); - - /* Печатаем идентификатор, адрес и контрольную сумму адреса. */ - besm6_debug ("::: формат МД %o полузона %04o.%d память %05o и-а-кса %010o %010o", - c->dev, c->zone, c->track, c->memory, - (int) (fmtbuf[0] >> 8 & BITS(30)), - (int) (fmtbuf[2] >> 14 & BITS(30))); - /* log_data (fmtbuf, 4); */ -} - -/* - * Чтение с диска. - */ -void disk_read (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - - if (disk_dev.dctrl) - besm6_debug ((c->op & DISK_READ_SYSDATA) ? - "::: чтение МД %o зона %04o служебные слова" : - "::: чтение МД %o зона %04o память %05o-%05o", - c->dev, c->zone, c->memory, c->memory + 1023); - fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); - if (sim_fread (c->sysdata, 8, 8, u->fileref) != 8) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - if (! (c->op & DISK_READ_SYSDATA) && - sim_fread (&memory [c->memory], 8, 1024, u->fileref) != 1024) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); -} - -t_value collect (t_value val) -{ - int i, j; - t_value res = 0; - - for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) - if (val & (1LL<<(i*9+j))) - res |= 1LL << (i+j*5); - return res & BITS48; -} - -void disk_read_track (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - - if (disk_dev.dctrl) - besm6_debug ((c->op & DISK_READ_SYSDATA) ? - "::: чтение МД %o полузона %04o.%d служебные слова" : - "::: чтение МД %o полузона %04o.%d память %05o-%05o", - c->dev, c->zone, c->track, c->memory, c->memory + 511); - fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); - if (sim_fread (c->sysdata + 4*c->track, 8, 4, u->fileref) != 4) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - if (! (c->op & DISK_READ_SYSDATA)) { - fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, - SEEK_SET); - if (sim_fread (&memory [c->memory], 8, 512, u->fileref) != 512) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - } - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); -} - -/* - * Чтение заголовка дорожки. - */ -void disk_read_header (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - t_value *sysdata = c->sysdata + 4*c->track; - int iaksa, i, cyl, head; - - /* Адрес: номер цилиндра и головки. */ - head = (c->zone << 1) + c->track; - cyl = head / 10; - head %= 10; - iaksa = (cyl << 20) | (head << 16); - - /* Идентификатор дорожки замены. */ - if (c->zone >= 01750) - iaksa |= BBIT(30); - - /* Контрольная сумма адреса с переносом вправо. */ - iaksa |= BITS(12) & ~sum_with_right_carry (iaksa >> 12, iaksa >> 24); - - /* Амиакса, 42 нуля, амиакса, много единиц. */ - sysdata[0] = 07404000000000000LL | (t_value) iaksa << 8; - sysdata[1] = 03740LL; - sysdata[2] = 00400000000037777LL | (t_value) iaksa << 14; - sysdata[3] = BITS48; - if (disk_dev.dctrl) - log_data (sysdata, 4); - - /* Кодируем гребенку. */ - for (i=0; i<4; i++) - sysdata[i] = SET_CONVOL (collect (sysdata[i]), CONVOL_NUMBER); -} - -/* - * Задание адреса памяти и длины массива для последующего обращения к диску. - * Номера дисковода и дорожки будут выданы позже, командой 033 0023(0024). - */ -void disk_io (int ctlr, uint32 cmd) -{ - KMD *c = &controller [ctlr]; - - c->op = cmd; - c->format = 0; - if (c->op & DISK_PAGE_MODE) { - /* Обмен страницей */ - c->memory = (cmd & DISK_PAGE) >> 2 | (cmd & DISK_BLOCK) >> 8; - } else { - /* Обмен половиной страницы (дорожкой) */ - c->memory = (cmd & (DISK_PAGE | DISK_HALFPAGE)) >> 2 | (cmd & DISK_BLOCK) >> 8; - } -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: задание на %s %08o", ctlr + '3', - (c->op & DISK_READ) ? "чтение" : "запись", cmd); -#endif - disk_fail &= ~c->mask_fail; - - /* Гасим главный регистр прерываний. */ - GRP &= ~c->mask_grp; -} - -/* - * Управление диском: команда 00 033 0023(0024). - */ -void disk_ctl (int ctlr, uint32 cmd) -{ - KMD *c = &controller [ctlr]; - UNIT *u = &disk_unit [c->dev]; - - if (cmd & BBIT(12)) { - /* Выдача в КМД адреса дорожки. - * Здесь же выполняем обмен с диском. - * Номер дисковода к этому моменту уже известен. */ - if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { - /* Device not attached. */ - disk_fail |= c->mask_fail; - return; - } - c->zone = (cmd >> 1) & BITS(10); - c->track = cmd & 1; -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: выдача адреса дорожки %04o.%d", - ctlr + '3', c->zone, c->track); -#endif - disk_fail &= ~c->mask_fail; - if (c->op & DISK_READ) { - if (c->op & DISK_PAGE_MODE) - disk_read (u); - else - disk_read_track (u); - } else { - if (u->flags & UNIT_RO) { - /* Read only. */ - /*longjmp (cpu_halt, SCPE_RO);*/ - disk_fail |= c->mask_fail; - return; - } - if (c->format) - disk_format (u); - else if (c->op & DISK_PAGE_MODE) - disk_write (u); - else - disk_write_track (u); - } - - /* Ждём события от устройства. */ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ - - } else if (cmd & BBIT(11)) { - /* Выбора номера устройства и занесение в регистр маски КМД. - * Бит 8 - устройство 0, бит 7 - устройство 1, ... бит 1 - устройство 7. - * Также установлен бит 9 - что он означает? */ - if (cmd & BBIT(8)) c->dev = 7; - else if (cmd & BBIT(7)) c->dev = 6; - else if (cmd & BBIT(6)) c->dev = 5; - else if (cmd & BBIT(5)) c->dev = 4; - else if (cmd & BBIT(4)) c->dev = 3; - else if (cmd & BBIT(3)) c->dev = 2; - else if (cmd & BBIT(2)) c->dev = 1; - else if (cmd & BBIT(1)) c->dev = 0; - else { - /* Неверная маска выбора устройства. */ - c->dev = -1; - return; - } - c->dev += ctlr << 3; - u = &disk_unit[c->dev]; -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: выбор устройства %d", - ctlr + '3', c->dev); -#endif - if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { - /* Device not attached. */ - disk_fail |= c->mask_fail; - GRP &= ~c->mask_grp; - } - GRP |= c->mask_grp; - - } else if (cmd & BBIT(9)) { - /* Проверка прерывания от КМД? */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: проверка готовности", - ctlr + '3'); -#endif - GRP |= c->mask_grp; - - } else { - /* Команда, выдаваемая в КМД. */ - switch (cmd & 077) { - case 000: /* диспак выдаёт эту команду один раз в начале загрузки */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: недокументированная команда 00", - ctlr + '3'); -#endif - break; - case 001: /* сброс на 0 цилиндр */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: сброс на 0 цилиндр", - ctlr + '3'); -#endif - break; - case 002: /* подвод */ - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: подвод", ctlr + '3'); - break; - case 003: /* чтение (НСМД-МОЗУ) */ - case 043: /* резервной дорожки */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: чтение", ctlr + '3'); -#endif - break; - case 004: /* запись (МОЗУ-НСМД) */ - case 044: /* резервной дорожки */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: запись", ctlr + '3'); -#endif - break; - case 005: /* разметка */ - c->format = 1; - break; - case 006: /* сравнение кодов (МОЗУ-НСМД) */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: сравнение кодов", ctlr + '3'); -#endif - break; - case 007: /* чтение заголовка */ - case 047: /* резервной дорожки */ - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: чтение %s заголовка", ctlr + '3', - cmd & 040 ? "резервного" : ""); - disk_fail &= ~c->mask_fail; - disk_read_header (u); - - /* Ждём события от устройства. */ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ - break; - case 010: /* гашение PC */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: гашение регистра состояния", - ctlr + '3'); -#endif - c->status = 0; - break; - case 011: /* опрос 1÷12 разрядов PC */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: опрос младших разрядов состояния", - ctlr + '3'); -#endif - if (disk_unit[c->dev].flags & UNIT_ATT) - c->status = STATUS_GOOD & BITS(12); - else - c->status = 0; - break; - case 031: /* опрос 13÷24 разрядов РС */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: опрос старших разрядов состояния", - ctlr + '3'); -#endif - if (disk_unit[c->dev].flags & UNIT_ATT) - c->status = (STATUS_GOOD >> 12) & BITS(12); - else - c->status = 0; - break; - case 050: /* освобождение НМД */ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: освобождение накопителя", - ctlr + '3'); -#endif - break; - default: - besm6_debug ("::: КМД %c: неизвестная команда %02o", - ctlr + '3', cmd & 077); - GRP |= c->mask_grp; /* чтобы не зависало */ - break; - } - } -} - -/* - * Запрос состояния контроллера. - */ -int disk_state (int ctlr) -{ - KMD *c = &controller [ctlr]; -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: опрос состояния = %04o", - ctlr + '3', c->status); -#endif - return c->status; -} - -/* - * Событие: закончен обмен с МД. - * Устанавливаем флаг прерывания. - */ -t_stat disk_event (UNIT *u) -{ - KMD *c = unit_to_ctlr (u); - - GRP |= c->mask_grp; - return SCPE_OK; -} - -/* - * Опрос ошибок обмена командой 033 4035. - */ -int disk_errors () -{ -#if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД: опрос шкалы ошибок = %04o", disk_fail); -#endif - return disk_fail; -} +/* + * BESM-6 magnetic disk device + * + * Copyright (c) 2009, Serge Vakulenko + * 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" + +/* + * Управляющее слово обмена с магнитным диском. + */ +#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */ +#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */ +#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */ +#define DISK_READ 000400000 /* чтение с диска в память */ +#define DISK_PAGE 000370000 /* номер страницы памяти */ +#define DISK_HALFPAGE 000004000 /* выбор половины листа */ +#define DISK_UNIT 000001600 /* номер устройства */ +#define DISK_HALFZONE 000000001 /* выбор половины зоны */ + +/* + * "Хороший" статус чтения/записи. + * Вычислено по текстам ОС Дубна. + * Диспак доволен. + */ +#define STATUS_GOOD 014000400 + +/* + * Параметры обмена с внешним устройством. + */ +typedef struct { + int op; /* Условное слово обмена */ + int dev; /* Номер устройства, 0..7 */ + int zone; /* Номер зоны на диске */ + int track; /* Выбор половины зоны на диске */ + int memory; /* Начальный адрес памяти */ + int format; /* Флаг разметки */ + int status; /* Регистр состояния */ + t_value mask_grp; /* Маска готовности для ГРП */ + int mask_fail; /* Маска ошибки обмена */ + t_value *sysdata; /* Буфер системных данных */ +} KMD; + +static KMD controller [2]; /* Две стойки КМД */ +int disk_fail; /* Маска ошибок по направлениям */ + +t_stat disk_event (UNIT *u); + +/* + * DISK data structures + * + * disk_dev DISK device descriptor + * disk_unit DISK unit descriptor + * disk_reg DISK register list + */ +UNIT disk_unit [16] = { + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, +}; + +REG disk_reg[] = { +{ "КУС_0", &controller[0].op, 8, 24, 0, 1 }, +{ "УСТР_0", &controller[0].dev, 8, 3, 0, 1 }, +{ "ЗОНА_0", &controller[0].zone, 8, 10, 0, 1 }, +{ "ДОРОЖКА_0", &controller[0].track, 8, 2, 0, 1 }, +{ "МОЗУ_0", &controller[0].memory, 8, 20, 0, 1 }, +{ "РС_0", &controller[0].status, 8, 24, 0, 1 }, +{ "КУС_1", &controller[1].op, 8, 24, 0, 1 }, +{ "УСТР_1", &controller[1].dev, 8, 3, 0, 1 }, +{ "ЗОНА_1", &controller[1].zone, 8, 10, 0, 1 }, +{ "ДОРОЖКА_1", &controller[1].track, 8, 2, 0, 1 }, +{ "МОЗУ_1", &controller[1].memory, 8, 20, 0, 1 }, +{ "РС_1", &controller[1].status, 8, 24, 0, 1 }, +{ "ОШ", &disk_fail, 8, 6, 0, 1 }, +{ 0 } +}; + +MTAB disk_mod[] = { + { 0 } +}; + +t_stat disk_reset (DEVICE *dptr); +t_stat disk_attach (UNIT *uptr, char *cptr); +t_stat disk_detach (UNIT *uptr); + +DEVICE disk_dev = { + "DISK", disk_unit, disk_reg, disk_mod, + 16, 8, 21, 1, 8, 50, + NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach, + NULL, DEV_DISABLE | DEV_DEBUG +}; + +/* + * Определение контроллера по устройству. + */ +static KMD *unit_to_ctlr (UNIT *u) +{ + if (u < &disk_unit[8]) + return &controller[0]; + else + return &controller[1]; +} + +/* + * Reset routine + */ +t_stat disk_reset (DEVICE *dptr) +{ + int i; + + memset (&controller, 0, sizeof (controller)); + controller[0].sysdata = &memory [030]; + controller[1].sysdata = &memory [040]; + controller[0].mask_grp = GRP_CHAN3_FREE; + controller[1].mask_grp = GRP_CHAN4_FREE; + controller[0].mask_fail = 020; + controller[1].mask_fail = 010; + for (i=0; i<16; ++i) + sim_cancel (&disk_unit[i]); + return SCPE_OK; +} + +t_stat disk_attach (UNIT *u, char *cptr) +{ + t_stat s; + + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + return SCPE_OK; +} + +t_stat disk_detach (UNIT *u) +{ + /* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */ + return detach_unit (u); +} + +t_value spread (t_value val) +{ + int i, j; + t_value res = 0; + + for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) + if (val & (1LL<<(i+j*5))) + res |= 1LL << (i*9+j); + return res & BITS48; +} + +/* + * Отладочная печать массива данных обмена. + */ +static void log_data (t_value *data, int nwords) +{ + int i; + t_value val; + + for (i=0; i> 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"); +} + +/* + * Сложение с переносом вправо. + */ +static unsigned sum_with_right_carry (unsigned a, unsigned b) +{ + unsigned c; + + while (b) { + c = a & b; + a ^= b; + b = c >> 1; + } + return a; +} + +/* + * Запись на диск. + */ +void disk_write (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ("::: запись МД %o зона %04o память %05o-%05o", + c->dev, c->zone, c->memory, c->memory + 1023); + fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); + sim_fwrite (c->sysdata, 8, 8, u->fileref); + sim_fwrite (&memory [c->memory], 8, 1024, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +void disk_write_track (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ("::: запись МД %o полузона %04o.%d память %05o-%05o", + c->dev, c->zone, c->track, c->memory, c->memory + 511); + fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); + sim_fwrite (c->sysdata + 4*c->track, 8, 4, u->fileref); + fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, + SEEK_SET); + sim_fwrite (&memory [c->memory], 8, 512, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +/* + * Форматирование дорожки. + */ +void disk_format (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + t_value fmtbuf[5], *ptr; + int i; + + /* По сути, эмулятору ничего делать не надо. */ + if (! disk_dev.dctrl) + return; + + /* Находим начало записываемого заголовка. */ + ptr = &memory [c->memory]; + while ((*ptr & BITS48) == 0) + ptr++; + + /* Декодируем из гребенки в нормальный вид. */ + for (i = 0; i < 5; i++) + fmtbuf[i] = spread (ptr[i]); + + /* При первой попытке разметки адресный маркер начинается в старшем 5-разрядном слоге, + * пропускаем первый слог. */ + for (i=0; i<4; i++) + fmtbuf[i] = ((fmtbuf[i] & BITS48) << 5) | + ((fmtbuf[i+1] >> 40) & BITS(5)); + + /* Печатаем идентификатор, адрес и контрольную сумму адреса. */ + besm6_debug ("::: формат МД %o полузона %04o.%d память %05o и-а-кса %010o %010o", + c->dev, c->zone, c->track, c->memory, + (int) (fmtbuf[0] >> 8 & BITS(30)), + (int) (fmtbuf[2] >> 14 & BITS(30))); + /* log_data (fmtbuf, 4); */ +} + +/* + * Чтение с диска. + */ +void disk_read (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ((c->op & DISK_READ_SYSDATA) ? + "::: чтение МД %o зона %04o служебные слова" : + "::: чтение МД %o зона %04o память %05o-%05o", + c->dev, c->zone, c->memory, c->memory + 1023); + fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); + if (sim_fread (c->sysdata, 8, 8, u->fileref) != 8) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (! (c->op & DISK_READ_SYSDATA) && + sim_fread (&memory [c->memory], 8, 1024, u->fileref) != 1024) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +t_value collect (t_value val) +{ + int i, j; + t_value res = 0; + + for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) + if (val & (1LL<<(i*9+j))) + res |= 1LL << (i+j*5); + return res & BITS48; +} + +void disk_read_track (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + if (disk_dev.dctrl) + besm6_debug ((c->op & DISK_READ_SYSDATA) ? + "::: чтение МД %o полузона %04o.%d служебные слова" : + "::: чтение МД %o полузона %04o.%d память %05o-%05o", + c->dev, c->zone, c->track, c->memory, c->memory + 511); + fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); + if (sim_fread (c->sysdata + 4*c->track, 8, 4, u->fileref) != 4) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (! (c->op & DISK_READ_SYSDATA)) { + fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, + SEEK_SET); + if (sim_fread (&memory [c->memory], 8, 512, u->fileref) != 512) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + } + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); +} + +/* + * Чтение заголовка дорожки. + */ +void disk_read_header (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + t_value *sysdata = c->sysdata + 4*c->track; + int iaksa, i, cyl, head; + + /* Адрес: номер цилиндра и головки. */ + head = (c->zone << 1) + c->track; + cyl = head / 10; + head %= 10; + iaksa = (cyl << 20) | (head << 16); + + /* Идентификатор дорожки замены. */ + if (c->zone >= 01750) + iaksa |= BBIT(30); + + /* Контрольная сумма адреса с переносом вправо. */ + iaksa |= BITS(12) & ~sum_with_right_carry (iaksa >> 12, iaksa >> 24); + + /* Амиакса, 42 нуля, амиакса, много единиц. */ + sysdata[0] = 07404000000000000LL | (t_value) iaksa << 8; + sysdata[1] = 03740LL; + sysdata[2] = 00400000000037777LL | (t_value) iaksa << 14; + sysdata[3] = BITS48; + if (disk_dev.dctrl) + log_data (sysdata, 4); + + /* Кодируем гребенку. */ + for (i=0; i<4; i++) + sysdata[i] = SET_CONVOL (collect (sysdata[i]), CONVOL_NUMBER); +} + +/* + * Задание адреса памяти и длины массива для последующего обращения к диску. + * Номера дисковода и дорожки будут выданы позже, командой 033 0023(0024). + */ +void disk_io (int ctlr, uint32 cmd) +{ + KMD *c = &controller [ctlr]; + + c->op = cmd; + c->format = 0; + if (c->op & DISK_PAGE_MODE) { + /* Обмен страницей */ + c->memory = (cmd & DISK_PAGE) >> 2 | (cmd & DISK_BLOCK) >> 8; + } else { + /* Обмен половиной страницы (дорожкой) */ + c->memory = (cmd & (DISK_PAGE | DISK_HALFPAGE)) >> 2 | (cmd & DISK_BLOCK) >> 8; + } +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: задание на %s %08o", ctlr + '3', + (c->op & DISK_READ) ? "чтение" : "запись", cmd); +#endif + disk_fail &= ~c->mask_fail; + + /* Гасим главный регистр прерываний. */ + GRP &= ~c->mask_grp; +} + +/* + * Управление диском: команда 00 033 0023(0024). + */ +void disk_ctl (int ctlr, uint32 cmd) +{ + KMD *c = &controller [ctlr]; + UNIT *u = &disk_unit [c->dev]; + + if (cmd & BBIT(12)) { + /* Выдача в КМД адреса дорожки. + * Здесь же выполняем обмен с диском. + * Номер дисковода к этому моменту уже известен. */ + if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { + /* Device not attached. */ + disk_fail |= c->mask_fail; + return; + } + c->zone = (cmd >> 1) & BITS(10); + c->track = cmd & 1; +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: выдача адреса дорожки %04o.%d", + ctlr + '3', c->zone, c->track); +#endif + disk_fail &= ~c->mask_fail; + if (c->op & DISK_READ) { + if (c->op & DISK_PAGE_MODE) + disk_read (u); + else + disk_read_track (u); + } else { + if (u->flags & UNIT_RO) { + /* Read only. */ + /*longjmp (cpu_halt, SCPE_RO);*/ + disk_fail |= c->mask_fail; + return; + } + if (c->format) + disk_format (u); + else if (c->op & DISK_PAGE_MODE) + disk_write (u); + else + disk_write_track (u); + } + + /* Ждём события от устройства. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + + } else if (cmd & BBIT(11)) { + /* Выбора номера устройства и занесение в регистр маски КМД. + * Бит 8 - устройство 0, бит 7 - устройство 1, ... бит 1 - устройство 7. + * Также установлен бит 9 - что он означает? */ + if (cmd & BBIT(8)) c->dev = 7; + else if (cmd & BBIT(7)) c->dev = 6; + else if (cmd & BBIT(6)) c->dev = 5; + else if (cmd & BBIT(5)) c->dev = 4; + else if (cmd & BBIT(4)) c->dev = 3; + else if (cmd & BBIT(3)) c->dev = 2; + else if (cmd & BBIT(2)) c->dev = 1; + else if (cmd & BBIT(1)) c->dev = 0; + else { + /* Неверная маска выбора устройства. */ + c->dev = -1; + return; + } + c->dev += ctlr << 3; + u = &disk_unit[c->dev]; +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: выбор устройства %d", + ctlr + '3', c->dev); +#endif + if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { + /* Device not attached. */ + disk_fail |= c->mask_fail; + GRP &= ~c->mask_grp; + } + GRP |= c->mask_grp; + + } else if (cmd & BBIT(9)) { + /* Проверка прерывания от КМД? */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: проверка готовности", + ctlr + '3'); +#endif + GRP |= c->mask_grp; + + } else { + /* Команда, выдаваемая в КМД. */ + switch (cmd & 077) { + case 000: /* диспак выдаёт эту команду один раз в начале загрузки */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: недокументированная команда 00", + ctlr + '3'); +#endif + break; + case 001: /* сброс на 0 цилиндр */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: сброс на 0 цилиндр", + ctlr + '3'); +#endif + break; + case 002: /* подвод */ + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: подвод", ctlr + '3'); + break; + case 003: /* чтение (НСМД-МОЗУ) */ + case 043: /* резервной дорожки */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: чтение", ctlr + '3'); +#endif + break; + case 004: /* запись (МОЗУ-НСМД) */ + case 044: /* резервной дорожки */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: запись", ctlr + '3'); +#endif + break; + case 005: /* разметка */ + c->format = 1; + break; + case 006: /* сравнение кодов (МОЗУ-НСМД) */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: сравнение кодов", ctlr + '3'); +#endif + break; + case 007: /* чтение заголовка */ + case 047: /* резервной дорожки */ + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: чтение %s заголовка", ctlr + '3', + cmd & 040 ? "резервного" : ""); + disk_fail &= ~c->mask_fail; + disk_read_header (u); + + /* Ждём события от устройства. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + break; + case 010: /* гашение PC */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: гашение регистра состояния", + ctlr + '3'); +#endif + c->status = 0; + break; + case 011: /* опрос 1÷12 разрядов PC */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос младших разрядов состояния", + ctlr + '3'); +#endif + if (disk_unit[c->dev].flags & UNIT_ATT) + c->status = STATUS_GOOD & BITS(12); + else + c->status = 0; + break; + case 031: /* опрос 13÷24 разрядов РС */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос старших разрядов состояния", + ctlr + '3'); +#endif + if (disk_unit[c->dev].flags & UNIT_ATT) + c->status = (STATUS_GOOD >> 12) & BITS(12); + else + c->status = 0; + break; + case 050: /* освобождение НМД */ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: освобождение накопителя", + ctlr + '3'); +#endif + break; + default: + besm6_debug ("::: КМД %c: неизвестная команда %02o", + ctlr + '3', cmd & 077); + GRP |= c->mask_grp; /* чтобы не зависало */ + break; + } + } +} + +/* + * Запрос состояния контроллера. + */ +int disk_state (int ctlr) +{ + KMD *c = &controller [ctlr]; +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос состояния = %04o", + ctlr + '3', c->status); +#endif + return c->status; +} + +/* + * Событие: закончен обмен с МД. + * Устанавливаем флаг прерывания. + */ +t_stat disk_event (UNIT *u) +{ + KMD *c = unit_to_ctlr (u); + + GRP |= c->mask_grp; + return SCPE_OK; +} + +/* + * Опрос ошибок обмена командой 033 4035. + */ +int disk_errors () +{ +#if 0 + if (disk_dev.dctrl) + besm6_debug ("::: КМД: опрос шкалы ошибок = %04o", disk_fail); +#endif + return disk_fail; +} diff --git a/BESM6/besm6_drum.c b/BESM6/besm6_drum.c index 2766baa2..6dedcb5a 100644 --- a/BESM6/besm6_drum.c +++ b/BESM6/besm6_drum.c @@ -1,372 +1,372 @@ -/* - * 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[] = { -{ "УС", &drum_op, 8, 24, 0, 1 }, -{ "ЗОНА", &drum_zone, 8, 10, 0, 1 }, -{ "СЕКТОР", &drum_sector, 8, 2, 0, 1 }, -{ "МОЗУ", &drum_memory, 8, 15, 0, 1 }, -{ "СЧСЛОВ", &drum_nwords, 8, 11, 0, 1 }, -{ 0 } -}; - -MTAB drum_mod[] = { - { 0 } -}; - -t_stat drum_reset (DEVICE *dptr); -t_stat drum_attach (UNIT *uptr, 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, 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); - 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]; - fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, - SEEK_SET); - sim_fwrite (&sysdata [drum_sector*2], 8, 2, u->fileref); - fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, - SEEK_SET); - 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]; - fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET); - if (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]; - fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, SEEK_SET); - if (sim_fread (&sysdata [drum_sector*2], 8, 2, u->fileref) != 2) { - /* Чтение неинициализированного барабана */ - drum_fail |= 0100 >> ctlr; - return; - } - if (! (drum_op & DRUM_READ_SYSDATA)) { - fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, - SEEK_SET); - if (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_CONVOL (0, CONVOL_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; -} +/* + * 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[] = { +{ "УС", &drum_op, 8, 24, 0, 1 }, +{ "ЗОНА", &drum_zone, 8, 10, 0, 1 }, +{ "СЕКТОР", &drum_sector, 8, 2, 0, 1 }, +{ "МОЗУ", &drum_memory, 8, 15, 0, 1 }, +{ "СЧСЛОВ", &drum_nwords, 8, 11, 0, 1 }, +{ 0 } +}; + +MTAB drum_mod[] = { + { 0 } +}; + +t_stat drum_reset (DEVICE *dptr); +t_stat drum_attach (UNIT *uptr, 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, 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); + 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]; + fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, + SEEK_SET); + sim_fwrite (&sysdata [drum_sector*2], 8, 2, u->fileref); + fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, + SEEK_SET); + 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]; + fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET); + if (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]; + fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, SEEK_SET); + if (sim_fread (&sysdata [drum_sector*2], 8, 2, u->fileref) != 2) { + /* Чтение неинициализированного барабана */ + drum_fail |= 0100 >> ctlr; + return; + } + if (! (drum_op & DRUM_READ_SYSDATA)) { + fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, + SEEK_SET); + if (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_CONVOL (0, CONVOL_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; +} diff --git a/BESM6/besm6_mmu.c b/BESM6/besm6_mmu.c index beed6dc2..c9d2c2e5 100644 --- a/BESM6/besm6_mmu.c +++ b/BESM6/besm6_mmu.c @@ -1,652 +1,652 @@ -/* - * besm6_mmu.c: BESM-6 fast write cache and TLB registers - *(стойка БРУС) - * - * 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" - -/* - * MMU data structures - * - * mmu_dev MMU device descriptor - * mmu_unit MMU unit descriptor - * mmu_reg MMU register list - */ -UNIT mmu_unit = { - UDATA (NULL, UNIT_FIX, 8) -}; - -t_value BRZ[8]; -uint32 BAZ[8], TABST, RZ, OLDEST, FLUSH; - -t_value BRS[4]; -uint32 BAS[4]; -uint32 BRSLRU; - -/* - * 64-битные регистры RP0-RP7 - для отображения регистров приписки, - * группами по 4 ради компактности, 12 бит на страницу. - * TLB0-TLB31 - постраничные регистры приписки, копии RPi. - * Обращение к памяти должно вестись через TLBi. - */ -t_value RP[8]; -uint32 TLB[32]; - -unsigned iintr_data; /* protected page number or parity check location */ - -t_value pult[8]; - -REG mmu_reg[] = { -{ "БРЗ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры записи */ -{ "БРЗ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БАЗ0", &BAZ[0], 8, 16, 0, 1 }, /* Буферные адреса записи */ -{ "БАЗ1", &BAZ[1], 8, 16, 0, 1 }, -{ "БАЗ2", &BAZ[2], 8, 16, 0, 1 }, -{ "БАЗ3", &BAZ[3], 8, 16, 0, 1 }, -{ "БАЗ4", &BAZ[4], 8, 16, 0, 1 }, -{ "БАЗ5", &BAZ[5], 8, 16, 0, 1 }, -{ "БАЗ6", &BAZ[6], 8, 16, 0, 1 }, -{ "БАЗ7", &BAZ[7], 8, 16, 0, 1 }, -{ "ТАБСТ", &TABST, 8, 28, 0, 1, NULL, NULL, REG_HIDDEN },/* Таблица старшинства БРЗ */ -{ "ЗпТР", &FLUSH, 8, 4, 0, 1, NULL, NULL, REG_HIDDEN },/* Признак выталкивания БРЗ */ -{ "Старш", &OLDEST, 8, 3, 0, 1 }, /* Номер вытолкнутого БРЗ */ -{ "РП0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* Регистры приписки, по 12 бит */ -{ "РП1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РЗ", &RZ, 8, 32, 0, 1 }, /* Регистр защиты */ -{ "ТР1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Тумблерные регистры */ -{ "ТР2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРС0", &BRS[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры слов */ -{ "БРС1", &BRS[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРС2", &BRS[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРС3", &BRS[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БАС0", &BAS[0], 8, 16, 0, 1 }, /* Буферные адреса слов */ -{ "БАС1", &BAS[1], 8, 16, 0, 1 }, -{ "БАС2", &BAS[2], 8, 16, 0, 1 }, -{ "БАС3", &BAS[3], 8, 16, 0, 1 }, -{ "БРСст", &BRSLRU, 8, 6, 0, 1, NULL, NULL, REG_HIDDEN}, -{ 0 } -}; - -#define CACHE_ENB 1 - -MTAB mmu_mod[] = { - { 1, 0, "NOCACHE", "NOCACHE" }, - { 1, 1, "CACHE", "CACHE" }, - { 0 } -}; - -t_stat mmu_reset (DEVICE *dptr); - -t_stat mmu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ - mmu_print_brz(); - return SCPE_NOFNC; -} - -DEVICE mmu_dev = { - "MMU", &mmu_unit, mmu_reg, mmu_mod, - 1, 8, 3, 1, 8, 50, - &mmu_examine, NULL, &mmu_reset, - NULL, NULL, NULL, NULL, - DEV_DEBUG -}; - -/* - * Reset routine - */ -t_stat mmu_reset (DEVICE *dptr) -{ - int i; - for (i = 0; i < 8; ++i) { - BRZ[i] = BAZ[i] = RP[i] = 0; - } - TABST = 0; - OLDEST = 0; - FLUSH = 0; - RZ = 0; - /* - * Front panel switches survive the reset - */ - sim_cancel (&mmu_unit); - return SCPE_OK; -} - -#define loses_to_all(i) ((TABST & win_mask[i]) == 0 && \ - (TABST & lose_mask[i]) == lose_mask[i]) - -/* - * N wins over M if the bit is set - * M=1 2 3 4 5 6 7 - * N ------------------------- - * 0| 0 1 2 3 4 5 6 - * 1| 7 8 9 10 11 12 - * 2| 13 14 15 16 17 - * 3| 18 19 20 21 - * 4| 22 23 24 - * 5| 25 26 - * 6| 27 - */ - -static unsigned win_mask[8] = { - 0177, - 0077 << 7, - 0037 << 13, - 0017 << 18, - 0007 << 22, - 0003 << 25, - 0001 << 27, - 0 -}; - -static unsigned lose_mask[8] = { - 0, - 1<<0, - 1<<1|1<<7, - 1<<2|1<<8|1<<13, - 1<<3|1<<9|1<<14|1<<18, - 1<<4|1<<10|1<<15|1<<19|1<<22, - 1<<5|1<<11|1<<16|1<<20|1<<23|1<<25, - 1<<6|1<<12|1<<17|1<<21|1<<24|1<<26|1<<27 -}; - -#define set_wins(i) TABST = (TABST & ~lose_mask[i]) | win_mask[i] - -void mmu_protection_check (int addr) -{ - /* Защита блокируется в режиме супервизора для физических (!) адресов 1-7 (ТО-8) - WTF? */ - int tmp_prot_disabled = (M[PSW] & PSW_PROT_DISABLE) || - (IS_SUPERVISOR (RUU) && (M[PSW] & PSW_MMAP_DISABLE) && addr < 010); - - /* Защита не заблокирована, а лист закрыт */ - if (! tmp_prot_disabled && (RZ & (1 << (addr >> 10)))) { - iintr_data = addr >> 10; - if (mmu_dev.dctrl) - besm6_debug ("--- (%05o) защита числа", addr); - longjmp (cpu_halt, STOP_OPERAND_PROT); - } -} - -void mmu_flush (int idx) -{ - if (! BAZ[idx]) { - /* Был пуст после сброса или выталкивания */ - return; - } - /* Вычисляем физический адрес выталкиваемого БРЗ */ - int waddr = BAZ[idx]; - waddr = (waddr > 0100000) ? (waddr - 0100000) : - (waddr & 01777) | (TLB[waddr >> 10] << 10); - memory[waddr] = BRZ[idx]; - BAZ[idx] = 0; - if (sim_log && mmu_dev.dctrl) { - fprintf (sim_log, "--- (%05o) запись ", waddr); - fprint_sym (sim_log, 0, &BRZ[idx], 0, 0); - fprintf (sim_log, " из БРЗ[%d]\n", idx); - } -} - -void mmu_update_oldest () -{ - int i; - - for (i = 0; i < 8; ++i) { - if (loses_to_all(i)) { - OLDEST = i; - // fprintf(stderr, "Oldest = %d\r\n", i); - return; - } - } -} - -int mmu_match (int addr, int fail) -{ - int i; - - for (i = 0; i < 8; ++i) { - if (addr == BAZ[i]) { - return i; - } - } - return fail; -} - -/* - * Разнообразные алгоритмы выталкивания БРЗ путем записи - * по адресам пультовых регистров. Тест УУ проходит дальше всего - * с mmu_flush_by_age(). - */ -void mmu_flush_by_age() -{ - switch (FLUSH) { - case 0: - break; - case 1 ... 8: - set_wins (OLDEST); - mmu_update_oldest (); - mmu_flush (OLDEST); - if (FLUSH == 7) { - TABST = 0; - OLDEST = 0; - } - break; - } - ++FLUSH; -} - -void mmu_flush_by_number() -{ - switch (FLUSH) { - case 0: - break; - case 1 ... 8: - mmu_flush (FLUSH-1); - set_wins (FLUSH-1); - if (FLUSH-1 == OLDEST) - mmu_update_oldest (); - if (FLUSH == 7) { - TABST = 0; - OLDEST = 0; - } - break; - } - ++FLUSH; -} - -/* - * Запись слова в память - */ -void mmu_store (int addr, t_value val) -{ - int matching; - - addr &= BITS(15); - if (addr == 0) - return; - if (sim_log && mmu_dev.dctrl) { - fprintf (sim_log, "--- (%05o) запись ", addr); - fprint_sym (sim_log, 0, &val, 0, 0); - fprintf (sim_log, "\n"); - } - - mmu_protection_check (addr); - - /* Различаем адреса с припиской и без */ - if (M[PSW] & PSW_MMAP_DISABLE) - addr |= 0100000; - - /* ЗПСЧ: ЗП */ - if (M[DWP] == addr && (M[PSW] & PSW_WRITE_WATCH)) - longjmp(cpu_halt, STOP_STORE_ADDR_MATCH); - - if (sim_brk_summ & SWMASK('W') && - sim_brk_test (addr, SWMASK('W'))) - longjmp(cpu_halt, STOP_WWATCH); - - if (!(mmu_unit.flags & CACHE_ENB)) { - static int roundrobin; - int faked = (++roundrobin ^ addr ^ val) & 7; - - if (addr > 0100000 && addr < 0100010) - return; - - BRZ[faked] = SET_CONVOL (val, RUU ^ CONVOL_INSN); - BAZ[faked] = addr; - mmu_flush (faked); - return; - } - - /* Запись в тумблерные регистры - выталкивание БРЗ */ - if (addr > 0100000 && addr < 0100010) { - mmu_flush_by_age(); - return; - } else - FLUSH = 0; - - matching = mmu_match(addr, OLDEST); - - BRZ[matching] = SET_CONVOL (val, RUU ^ CONVOL_INSN); - BAZ[matching] = addr; - set_wins (matching); - - if (matching == OLDEST) { - mmu_update_oldest (); - mmu_flush (OLDEST); - } -} - -t_value mmu_memaccess (int addr) -{ - t_value val; - - /* Вычисляем физический адрес слова */ - addr = (addr > 0100000) ? (addr - 0100000) : - (addr & 01777) | (TLB[addr >> 10] << 10); - if (addr >= 010) { - /* Из памяти */ - val = memory[addr]; - } else { - /* С тумблерных регистров */ - if (mmu_dev.dctrl) - besm6_debug("--- (%05o) чтение ТР%o", PC, addr); - val = pult[addr]; - } - if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { - fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); - fprint_sym (sim_log, 0, &val, 0, 0); - fprintf (sim_log, "\n"); - } - - /* На тумблерных регистрах контроля числа не бывает */ - if (addr >= 010 && ! IS_NUMBER (val)) { - iintr_data = addr & 7; - besm6_debug ("--- (%05o) контроль числа", addr); - longjmp (cpu_halt, STOP_RAM_CHECK); - } - return val; -} - -/* - * Чтение операнда - */ -t_value mmu_load (int addr) -{ - int matching = -1; - t_value val; - - addr &= BITS(15); - if (addr == 0) - return 0; - - mmu_protection_check (addr); - - /* Различаем адреса с припиской и без */ - if (M[PSW] & PSW_MMAP_DISABLE) - addr |= 0100000; - - /* ЗПСЧ: СЧ */ - if (M[DWP] == addr && !(M[PSW] & PSW_WRITE_WATCH)) - longjmp(cpu_halt, STOP_LOAD_ADDR_MATCH); - - if (sim_brk_summ & SWMASK('R') && - sim_brk_test (addr, SWMASK('R'))) - longjmp(cpu_halt, STOP_RWATCH); - - if (!(mmu_unit.flags & CACHE_ENB)) { - return mmu_memaccess (addr) & BITS48; - } - - matching = mmu_match(addr, -1); - - if (matching == -1) { - val = mmu_memaccess (addr); - } else { - /* старшинство обновляется, только если оно не затрагивает - * старший БРЗ (ТО-2). - */ - if (matching != OLDEST) - set_wins (matching); - val = BRZ[matching]; - if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { - fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); - fprint_sym (sim_log, 0, &val, 0, 0); - fprintf (sim_log, " из БРЗ\n"); - } - if (! IS_NUMBER (val)) { - iintr_data = matching; - besm6_debug ("--- (%05o) контроль числа БРЗ", addr); - longjmp (cpu_halt, STOP_CACHE_CHECK); - } - } - return val & BITS48; -} - -/* A little BRS LRU table */ -#define brs_loses_to_all(i) ((BRSLRU & brs_win_mask[i]) == 0 && \ - (BRSLRU & brs_lose_mask[i]) == brs_lose_mask[i]) - -/* - * N wins over M if the bit is set - * M=1 2 3 - * N --------- - * 0| 0 1 2 - * 1| 3 4 - * 2| 5 - */ - -static unsigned brs_win_mask[4] = { - 07, - 03 << 3, - 01 << 5, - 0 -}; - -static unsigned brs_lose_mask[8] = { - 0, - 1<<0, - 1<<1|1<<3, - 1<<2|1<<4|1<<5 -}; - -#define brs_set_wins(i) BRSLRU = (BRSLRU & ~brs_lose_mask[i]) | brs_win_mask[i] - -void mmu_fetch_check (int addr) -{ - /* В режиме супервизора защиты нет */ - if (! IS_SUPERVISOR(RUU)) { - int page = TLB[addr >> 10]; - /* - * Для команд в режиме пользователя признак защиты - - * 0 в регистре приписки. - */ - if (page == 0) { - iintr_data = addr >> 10; - if (mmu_dev.dctrl) - besm6_debug ("--- (%05o) защита команды", addr); - longjmp (cpu_halt, STOP_INSN_PROT); - } - } -} - -/* - * Предвыборка команды на БРС - */ -t_value mmu_prefetch (int addr, int actual) -{ - t_value val; - int i; - - if (mmu_unit.flags & CACHE_ENB) { - for (i = 0; i < 4; ++i) { - if (BAS[i] == addr) { - if (actual) { - brs_set_wins (i); - } - return BRS[i]; - } - } - - for (i = 0; i < 4; ++i) { - if (brs_loses_to_all (i)) { - BAS[i] = addr; - if (actual) { - brs_set_wins (i); - } - break; - } - } - } else if (!actual) { - return 0; - } else { - /* Чтобы лампочки мигали */ - i = addr & 3; - } - - if (addr < 0100000) { - int page = TLB[addr >> 10]; - - /* Вычисляем физический адрес слова */ - addr = (addr & 01777) | (page << 10); - } else { - addr = addr & BITS(15); - } - - if (addr < 010) - val = pult[addr]; - else - val = memory[addr]; - BRS[i] = val; - return val; -} - -/* - * Выборка команды - */ -t_value mmu_fetch (int addr) -{ - t_value val; - - if (addr == 0) { - if (mmu_dev.dctrl) - besm6_debug ("--- передача управления на 0"); - longjmp (cpu_halt, STOP_INSN_CHECK); - } - - mmu_fetch_check(addr); - - /* Различаем адреса с припиской и без */ - if (IS_SUPERVISOR (RUU)) - addr |= 0100000; - - /* КРА */ - if (M[IBP] == addr) - longjmp(cpu_halt, STOP_INSN_ADDR_MATCH); - - val = mmu_prefetch(addr, 1); - - if (sim_log && mmu_dev.dctrl) { - fprintf (sim_log, "--- (%05o) выборка ", addr); - fprint_sym (sim_log, 0, &val, 0, SWMASK ('I')); - fprintf (sim_log, "\n"); - } - - /* Тумблерные регистры пока только с командной сверткой */ - if (addr >= 010 && ! IS_INSN (val)) { - besm6_debug ("--- (%05o) контроль команды", addr); - longjmp (cpu_halt, STOP_INSN_CHECK); - } - return val & BITS48; -} - -void mmu_setrp (int idx, t_value val) -{ - uint32 p0, p1, p2, p3; - const uint32 mask = (MEMSIZE >> 10) - 1; - - /* Младшие 5 разрядов 4-х регистров приписки упакованы - * по 5 в 1-20 рр, 6-е разряды - в 29-32 рр, 7-е разряды - в 33-36 рр и т.п. - */ - p0 = (val & 037) | (((val>>28) & 1) << 5) | (((val>>32) & 1) << 6) | - (((val>>36) & 1) << 7) | (((val>>40) & 1) << 8) | (((val>>44) & 1) << 9); - p1 = ((val>>5) & 037) | (((val>>29) & 1) << 5) | (((val>>33) & 1) << 6) | - (((val>>37) & 1) << 7) | (((val>>41) & 1) << 8) | (((val>>45) & 1) << 9); - p2 = ((val>>10) & 037) | (((val>>30) & 1) << 5) | (((val>>34) & 1) << 6) | - (((val>>38) & 1) << 7) | (((val>>42) & 1) << 8) | (((val>>46) & 1) << 9); - p3 = ((val>>15) & 037) | (((val>>31) & 1) << 5) | (((val>>35) & 1) << 6) | - (((val>>39) & 1) << 7) | (((val>>43) & 1) << 8) | (((val>>47) & 1) << 9); - - p0 &= mask; - p1 &= mask; - p2 &= mask; - p3 &= mask; - - RP[idx] = p0 | p1 << 12 | p2 << 24 | (t_value) p3 << 36; - TLB[idx*4] = p0; - TLB[idx*4+1] = p1; - TLB[idx*4+2] = p2; - TLB[idx*4+3] = p3; -} - -void mmu_setup () -{ - const uint32 mask = (MEMSIZE >> 10) - 1; - int i; - - /* Перепись РПi в TLBj. */ - for (i=0; i<8; ++i) { - TLB[i*4] = RP[i] & mask; - TLB[i*4+1] = RP[i] >> 12 & mask; - TLB[i*4+2] = RP[i] >> 24 & mask; - TLB[i*4+3] = RP[i] >> 36 & mask; - } -} - -void mmu_setprotection (int idx, t_value val) -{ - /* Разряды сумматора, записываемые в регистр защиты - 21-28 */ - int mask = 0xff << (idx * 8); - val = ((val >> 20) & 0xff) << (idx * 8); - RZ = (RZ & ~mask) | val; -} - -void mmu_setcache (int idx, t_value val) -{ - BRZ[idx] = SET_CONVOL (val, RUU ^ CONVOL_INSN); -} - -t_value mmu_getcache (int idx) -{ - return BRZ[idx] & BITS48; -} - -void mmu_print_brz () -{ - int i, k; - - for (i=7; i>=0; --i) { - besm6_log_cont ("БРЗ [%d] = '", i); - for (k=47; k>=0; --k) - besm6_log_cont ("%c", (BRZ[i] >> k & 1) ? '*' : ' '); - besm6_log ("'"); - } -} +/* + * besm6_mmu.c: BESM-6 fast write cache and TLB registers + *(стойка БРУС) + * + * 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" + +/* + * MMU data structures + * + * mmu_dev MMU device descriptor + * mmu_unit MMU unit descriptor + * mmu_reg MMU register list + */ +UNIT mmu_unit = { + UDATA (NULL, UNIT_FIX, 8) +}; + +t_value BRZ[8]; +uint32 BAZ[8], TABST, RZ, OLDEST, FLUSH; + +t_value BRS[4]; +uint32 BAS[4]; +uint32 BRSLRU; + +/* + * 64-битные регистры RP0-RP7 - для отображения регистров приписки, + * группами по 4 ради компактности, 12 бит на страницу. + * TLB0-TLB31 - постраничные регистры приписки, копии RPi. + * Обращение к памяти должно вестись через TLBi. + */ +t_value RP[8]; +uint32 TLB[32]; + +unsigned iintr_data; /* protected page number or parity check location */ + +t_value pult[8]; + +REG mmu_reg[] = { +{ "БРЗ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры записи */ +{ "БРЗ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРЗ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БАЗ0", &BAZ[0], 8, 16, 0, 1 }, /* Буферные адреса записи */ +{ "БАЗ1", &BAZ[1], 8, 16, 0, 1 }, +{ "БАЗ2", &BAZ[2], 8, 16, 0, 1 }, +{ "БАЗ3", &BAZ[3], 8, 16, 0, 1 }, +{ "БАЗ4", &BAZ[4], 8, 16, 0, 1 }, +{ "БАЗ5", &BAZ[5], 8, 16, 0, 1 }, +{ "БАЗ6", &BAZ[6], 8, 16, 0, 1 }, +{ "БАЗ7", &BAZ[7], 8, 16, 0, 1 }, +{ "ТАБСТ", &TABST, 8, 28, 0, 1, NULL, NULL, REG_HIDDEN },/* Таблица старшинства БРЗ */ +{ "ЗпТР", &FLUSH, 8, 4, 0, 1, NULL, NULL, REG_HIDDEN },/* Признак выталкивания БРЗ */ +{ "Старш", &OLDEST, 8, 3, 0, 1 }, /* Номер вытолкнутого БРЗ */ +{ "РП0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* Регистры приписки, по 12 бит */ +{ "РП1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РП7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, +{ "РЗ", &RZ, 8, 32, 0, 1 }, /* Регистр защиты */ +{ "ТР1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Тумблерные регистры */ +{ "ТР2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "ТР7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРС0", &BRS[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры слов */ +{ "БРС1", &BRS[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРС2", &BRS[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БРС3", &BRS[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, +{ "БАС0", &BAS[0], 8, 16, 0, 1 }, /* Буферные адреса слов */ +{ "БАС1", &BAS[1], 8, 16, 0, 1 }, +{ "БАС2", &BAS[2], 8, 16, 0, 1 }, +{ "БАС3", &BAS[3], 8, 16, 0, 1 }, +{ "БРСст", &BRSLRU, 8, 6, 0, 1, NULL, NULL, REG_HIDDEN}, +{ 0 } +}; + +#define CACHE_ENB 1 + +MTAB mmu_mod[] = { + { 1, 0, "NOCACHE", "NOCACHE" }, + { 1, 1, "CACHE", "CACHE" }, + { 0 } +}; + +t_stat mmu_reset (DEVICE *dptr); + +t_stat mmu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + mmu_print_brz(); + return SCPE_NOFNC; +} + +DEVICE mmu_dev = { + "MMU", &mmu_unit, mmu_reg, mmu_mod, + 1, 8, 3, 1, 8, 50, + &mmu_examine, NULL, &mmu_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG +}; + +/* + * Reset routine + */ +t_stat mmu_reset (DEVICE *dptr) +{ + int i; + for (i = 0; i < 8; ++i) { + BRZ[i] = BAZ[i] = RP[i] = 0; + } + TABST = 0; + OLDEST = 0; + FLUSH = 0; + RZ = 0; + /* + * Front panel switches survive the reset + */ + sim_cancel (&mmu_unit); + return SCPE_OK; +} + +#define loses_to_all(i) ((TABST & win_mask[i]) == 0 && \ + (TABST & lose_mask[i]) == lose_mask[i]) + +/* + * N wins over M if the bit is set + * M=1 2 3 4 5 6 7 + * N ------------------------- + * 0| 0 1 2 3 4 5 6 + * 1| 7 8 9 10 11 12 + * 2| 13 14 15 16 17 + * 3| 18 19 20 21 + * 4| 22 23 24 + * 5| 25 26 + * 6| 27 + */ + +static unsigned win_mask[8] = { + 0177, + 0077 << 7, + 0037 << 13, + 0017 << 18, + 0007 << 22, + 0003 << 25, + 0001 << 27, + 0 +}; + +static unsigned lose_mask[8] = { + 0, + 1<<0, + 1<<1|1<<7, + 1<<2|1<<8|1<<13, + 1<<3|1<<9|1<<14|1<<18, + 1<<4|1<<10|1<<15|1<<19|1<<22, + 1<<5|1<<11|1<<16|1<<20|1<<23|1<<25, + 1<<6|1<<12|1<<17|1<<21|1<<24|1<<26|1<<27 +}; + +#define set_wins(i) TABST = (TABST & ~lose_mask[i]) | win_mask[i] + +void mmu_protection_check (int addr) +{ + /* Защита блокируется в режиме супервизора для физических (!) адресов 1-7 (ТО-8) - WTF? */ + int tmp_prot_disabled = (M[PSW] & PSW_PROT_DISABLE) || + (IS_SUPERVISOR (RUU) && (M[PSW] & PSW_MMAP_DISABLE) && addr < 010); + + /* Защита не заблокирована, а лист закрыт */ + if (! tmp_prot_disabled && (RZ & (1 << (addr >> 10)))) { + iintr_data = addr >> 10; + if (mmu_dev.dctrl) + besm6_debug ("--- (%05o) защита числа", addr); + longjmp (cpu_halt, STOP_OPERAND_PROT); + } +} + +void mmu_flush (int idx) +{ + if (! BAZ[idx]) { + /* Был пуст после сброса или выталкивания */ + return; + } + /* Вычисляем физический адрес выталкиваемого БРЗ */ + int waddr = BAZ[idx]; + waddr = (waddr > 0100000) ? (waddr - 0100000) : + (waddr & 01777) | (TLB[waddr >> 10] << 10); + memory[waddr] = BRZ[idx]; + BAZ[idx] = 0; + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) запись ", waddr); + fprint_sym (sim_log, 0, &BRZ[idx], 0, 0); + fprintf (sim_log, " из БРЗ[%d]\n", idx); + } +} + +void mmu_update_oldest () +{ + int i; + + for (i = 0; i < 8; ++i) { + if (loses_to_all(i)) { + OLDEST = i; + // fprintf(stderr, "Oldest = %d\r\n", i); + return; + } + } +} + +int mmu_match (int addr, int fail) +{ + int i; + + for (i = 0; i < 8; ++i) { + if (addr == BAZ[i]) { + return i; + } + } + return fail; +} + +/* + * Разнообразные алгоритмы выталкивания БРЗ путем записи + * по адресам пультовых регистров. Тест УУ проходит дальше всего + * с mmu_flush_by_age(). + */ +void mmu_flush_by_age() +{ + switch (FLUSH) { + case 0: + break; + case 1 ... 8: + set_wins (OLDEST); + mmu_update_oldest (); + mmu_flush (OLDEST); + if (FLUSH == 7) { + TABST = 0; + OLDEST = 0; + } + break; + } + ++FLUSH; +} + +void mmu_flush_by_number() +{ + switch (FLUSH) { + case 0: + break; + case 1 ... 8: + mmu_flush (FLUSH-1); + set_wins (FLUSH-1); + if (FLUSH-1 == OLDEST) + mmu_update_oldest (); + if (FLUSH == 7) { + TABST = 0; + OLDEST = 0; + } + break; + } + ++FLUSH; +} + +/* + * Запись слова в память + */ +void mmu_store (int addr, t_value val) +{ + int matching; + + addr &= BITS(15); + if (addr == 0) + return; + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) запись ", addr); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, "\n"); + } + + mmu_protection_check (addr); + + /* Различаем адреса с припиской и без */ + if (M[PSW] & PSW_MMAP_DISABLE) + addr |= 0100000; + + /* ЗПСЧ: ЗП */ + if (M[DWP] == addr && (M[PSW] & PSW_WRITE_WATCH)) + longjmp(cpu_halt, STOP_STORE_ADDR_MATCH); + + if (sim_brk_summ & SWMASK('W') && + sim_brk_test (addr, SWMASK('W'))) + longjmp(cpu_halt, STOP_WWATCH); + + if (!(mmu_unit.flags & CACHE_ENB)) { + static int roundrobin; + int faked = (++roundrobin ^ addr ^ val) & 7; + + if (addr > 0100000 && addr < 0100010) + return; + + BRZ[faked] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BAZ[faked] = addr; + mmu_flush (faked); + return; + } + + /* Запись в тумблерные регистры - выталкивание БРЗ */ + if (addr > 0100000 && addr < 0100010) { + mmu_flush_by_age(); + return; + } else + FLUSH = 0; + + matching = mmu_match(addr, OLDEST); + + BRZ[matching] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BAZ[matching] = addr; + set_wins (matching); + + if (matching == OLDEST) { + mmu_update_oldest (); + mmu_flush (OLDEST); + } +} + +t_value mmu_memaccess (int addr) +{ + t_value val; + + /* Вычисляем физический адрес слова */ + addr = (addr > 0100000) ? (addr - 0100000) : + (addr & 01777) | (TLB[addr >> 10] << 10); + if (addr >= 010) { + /* Из памяти */ + val = memory[addr]; + } else { + /* С тумблерных регистров */ + if (mmu_dev.dctrl) + besm6_debug("--- (%05o) чтение ТР%o", PC, addr); + val = pult[addr]; + } + if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { + fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, "\n"); + } + + /* На тумблерных регистрах контроля числа не бывает */ + if (addr >= 010 && ! IS_NUMBER (val)) { + iintr_data = addr & 7; + besm6_debug ("--- (%05o) контроль числа", addr); + longjmp (cpu_halt, STOP_RAM_CHECK); + } + return val; +} + +/* + * Чтение операнда + */ +t_value mmu_load (int addr) +{ + int matching = -1; + t_value val; + + addr &= BITS(15); + if (addr == 0) + return 0; + + mmu_protection_check (addr); + + /* Различаем адреса с припиской и без */ + if (M[PSW] & PSW_MMAP_DISABLE) + addr |= 0100000; + + /* ЗПСЧ: СЧ */ + if (M[DWP] == addr && !(M[PSW] & PSW_WRITE_WATCH)) + longjmp(cpu_halt, STOP_LOAD_ADDR_MATCH); + + if (sim_brk_summ & SWMASK('R') && + sim_brk_test (addr, SWMASK('R'))) + longjmp(cpu_halt, STOP_RWATCH); + + if (!(mmu_unit.flags & CACHE_ENB)) { + return mmu_memaccess (addr) & BITS48; + } + + matching = mmu_match(addr, -1); + + if (matching == -1) { + val = mmu_memaccess (addr); + } else { + /* старшинство обновляется, только если оно не затрагивает + * старший БРЗ (ТО-2). + */ + if (matching != OLDEST) + set_wins (matching); + val = BRZ[matching]; + if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { + fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, " из БРЗ\n"); + } + if (! IS_NUMBER (val)) { + iintr_data = matching; + besm6_debug ("--- (%05o) контроль числа БРЗ", addr); + longjmp (cpu_halt, STOP_CACHE_CHECK); + } + } + return val & BITS48; +} + +/* A little BRS LRU table */ +#define brs_loses_to_all(i) ((BRSLRU & brs_win_mask[i]) == 0 && \ + (BRSLRU & brs_lose_mask[i]) == brs_lose_mask[i]) + +/* + * N wins over M if the bit is set + * M=1 2 3 + * N --------- + * 0| 0 1 2 + * 1| 3 4 + * 2| 5 + */ + +static unsigned brs_win_mask[4] = { + 07, + 03 << 3, + 01 << 5, + 0 +}; + +static unsigned brs_lose_mask[8] = { + 0, + 1<<0, + 1<<1|1<<3, + 1<<2|1<<4|1<<5 +}; + +#define brs_set_wins(i) BRSLRU = (BRSLRU & ~brs_lose_mask[i]) | brs_win_mask[i] + +void mmu_fetch_check (int addr) +{ + /* В режиме супервизора защиты нет */ + if (! IS_SUPERVISOR(RUU)) { + int page = TLB[addr >> 10]; + /* + * Для команд в режиме пользователя признак защиты - + * 0 в регистре приписки. + */ + if (page == 0) { + iintr_data = addr >> 10; + if (mmu_dev.dctrl) + besm6_debug ("--- (%05o) защита команды", addr); + longjmp (cpu_halt, STOP_INSN_PROT); + } + } +} + +/* + * Предвыборка команды на БРС + */ +t_value mmu_prefetch (int addr, int actual) +{ + t_value val; + int i; + + if (mmu_unit.flags & CACHE_ENB) { + for (i = 0; i < 4; ++i) { + if (BAS[i] == addr) { + if (actual) { + brs_set_wins (i); + } + return BRS[i]; + } + } + + for (i = 0; i < 4; ++i) { + if (brs_loses_to_all (i)) { + BAS[i] = addr; + if (actual) { + brs_set_wins (i); + } + break; + } + } + } else if (!actual) { + return 0; + } else { + /* Чтобы лампочки мигали */ + i = addr & 3; + } + + if (addr < 0100000) { + int page = TLB[addr >> 10]; + + /* Вычисляем физический адрес слова */ + addr = (addr & 01777) | (page << 10); + } else { + addr = addr & BITS(15); + } + + if (addr < 010) + val = pult[addr]; + else + val = memory[addr]; + BRS[i] = val; + return val; +} + +/* + * Выборка команды + */ +t_value mmu_fetch (int addr) +{ + t_value val; + + if (addr == 0) { + if (mmu_dev.dctrl) + besm6_debug ("--- передача управления на 0"); + longjmp (cpu_halt, STOP_INSN_CHECK); + } + + mmu_fetch_check(addr); + + /* Различаем адреса с припиской и без */ + if (IS_SUPERVISOR (RUU)) + addr |= 0100000; + + /* КРА */ + if (M[IBP] == addr) + longjmp(cpu_halt, STOP_INSN_ADDR_MATCH); + + val = mmu_prefetch(addr, 1); + + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) выборка ", addr); + fprint_sym (sim_log, 0, &val, 0, SWMASK ('I')); + fprintf (sim_log, "\n"); + } + + /* Тумблерные регистры пока только с командной сверткой */ + if (addr >= 010 && ! IS_INSN (val)) { + besm6_debug ("--- (%05o) контроль команды", addr); + longjmp (cpu_halt, STOP_INSN_CHECK); + } + return val & BITS48; +} + +void mmu_setrp (int idx, t_value val) +{ + uint32 p0, p1, p2, p3; + const uint32 mask = (MEMSIZE >> 10) - 1; + + /* Младшие 5 разрядов 4-х регистров приписки упакованы + * по 5 в 1-20 рр, 6-е разряды - в 29-32 рр, 7-е разряды - в 33-36 рр и т.п. + */ + p0 = (val & 037) | (((val>>28) & 1) << 5) | (((val>>32) & 1) << 6) | + (((val>>36) & 1) << 7) | (((val>>40) & 1) << 8) | (((val>>44) & 1) << 9); + p1 = ((val>>5) & 037) | (((val>>29) & 1) << 5) | (((val>>33) & 1) << 6) | + (((val>>37) & 1) << 7) | (((val>>41) & 1) << 8) | (((val>>45) & 1) << 9); + p2 = ((val>>10) & 037) | (((val>>30) & 1) << 5) | (((val>>34) & 1) << 6) | + (((val>>38) & 1) << 7) | (((val>>42) & 1) << 8) | (((val>>46) & 1) << 9); + p3 = ((val>>15) & 037) | (((val>>31) & 1) << 5) | (((val>>35) & 1) << 6) | + (((val>>39) & 1) << 7) | (((val>>43) & 1) << 8) | (((val>>47) & 1) << 9); + + p0 &= mask; + p1 &= mask; + p2 &= mask; + p3 &= mask; + + RP[idx] = p0 | p1 << 12 | p2 << 24 | (t_value) p3 << 36; + TLB[idx*4] = p0; + TLB[idx*4+1] = p1; + TLB[idx*4+2] = p2; + TLB[idx*4+3] = p3; +} + +void mmu_setup () +{ + const uint32 mask = (MEMSIZE >> 10) - 1; + int i; + + /* Перепись РПi в TLBj. */ + for (i=0; i<8; ++i) { + TLB[i*4] = RP[i] & mask; + TLB[i*4+1] = RP[i] >> 12 & mask; + TLB[i*4+2] = RP[i] >> 24 & mask; + TLB[i*4+3] = RP[i] >> 36 & mask; + } +} + +void mmu_setprotection (int idx, t_value val) +{ + /* Разряды сумматора, записываемые в регистр защиты - 21-28 */ + int mask = 0xff << (idx * 8); + val = ((val >> 20) & 0xff) << (idx * 8); + RZ = (RZ & ~mask) | val; +} + +void mmu_setcache (int idx, t_value val) +{ + BRZ[idx] = SET_CONVOL (val, RUU ^ CONVOL_INSN); +} + +t_value mmu_getcache (int idx) +{ + return BRZ[idx] & BITS48; +} + +void mmu_print_brz () +{ + int i, k; + + for (i=7; i>=0; --i) { + besm6_log_cont ("БРЗ [%d] = '", i); + for (k=47; k>=0; --k) + besm6_log_cont ("%c", (BRZ[i] >> k & 1) ? '*' : ' '); + besm6_log ("'"); + } +} diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c index 6ed387e8..6b673ab1 100644 --- a/BESM6/besm6_panel.c +++ b/BESM6/besm6_panel.c @@ -1,594 +1,594 @@ -/* - * Panel of BESM-6, displayed as a graphics window. - * Using libSDL for graphics and libSDL_ttf for fonts. - * - * Copyright (c) 2009, Serge Vakulenko - * Copyright (c) 2014, 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. - */ -#ifdef HAVE_LIBSDL - -#include "besm6_defs.h" -#include -#include - -/* - * Use a 640x480 window with 32 bit pixels. - */ -#define WIDTH 800 -#define HEIGHT 400 -#define DEPTH 32 - -#define STEPX 14 -#define STEPY 16 - -#define FONTNAME "LucidaSansRegular.ttf" -#define FONTPATH1 "/usr/share/fonts" -#define FONTPATH2 "/usr/lib/jvm" -#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions" - -#include -#include - -/* Data and functions that don't depend on SDL version */ -static char *font_path; -static TTF_Font *font_big; -static TTF_Font *font_small; -static SDL_Color foreground; -static SDL_Color background; -static const SDL_Color white = { 255, 255, 255 }; -static const SDL_Color black = { 0, 0, 0 }; -static const SDL_Color cyan = { 0, 128, 128 }; -static const SDL_Color grey = { 64, 64, 64 }; -static t_value old_BRZ [8], old_GRP [2]; -static t_value old_M [NREGS]; - -static const int regnum[] = { - 013, 012, 011, 010, 7, 6, 5, 4, - 027, 016, 015, 014, 3, 2, 1, 020, -}; - -static SDL_Surface *screen; - -/* - * Рисование текста в кодировке UTF-8, с антиалиасингом. - * Параметр halign задаёт выравнивание по горизонтали. - * Цвета заданы глобальными переменными foreground и background. - */ -static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message) -{ - SDL_Surface *text; - SDL_Rect area; - - /* Build image from text */ - text = TTF_RenderUTF8_Shaded (font, message, foreground, background); - - area.x = x; - if (halign < 0) - area.x -= text->w; /* align left */ - else if (halign == 0) - area.x -= text->w / 2; /* center */ - area.y = y; - area.w = text->w; - area.h = text->h; - - /* Put text image to screen */ - SDL_BlitSurface (text, 0, screen, &area); - SDL_FreeSurface (text); -} - -static SDL_Surface *sprite_from_data (int width, int height, - const unsigned char *data) -{ - SDL_Surface *sprite, *optimized; - unsigned *s, r, g, b, y, x; - - sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, - width, height, DEPTH, 0, 0, 0, 0); - /* - optimized = SDL_DisplayFormat (sprite); - SDL_FreeSurface (sprite); - sprite = optimized; - */ - SDL_LockSurface (sprite); - for (y=0; ypixels + y * sprite->pitch); - for (x=0; xformat, r, g, b); - } - } - SDL_UnlockSurface (sprite); - return sprite; -} - -/* - * Рисуем неонку. - */ -static void draw_lamp (int left, int top, int on) -{ - /* Images created by GIMP: save as C file without alpha channel. */ - static const int lamp_width = 12; - static const int lamp_height = 12; - static const unsigned char lamp_on [12 * 12 * 3 + 1] = - "\0\0\0\0\0\0\0\0\0\13\2\2-\14\14e\31\31e\31\31-\14\14\13\2\2\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0D\20\20\313,,\377??\377CC\377CC\377DD\31333D\21\21\0\0" - "\0\0\0\0\0\0\0D\20\20\357LL\377\243\243\376~~\37699\376@@\376@@\377AA\357" - "<>\377@@\377@@\377AA\31333\13\2\2-\14\14\377??\376~~\377\356\356\377\321" - "\321\377<<\377??\377@@\377@@\376@@\377DD-\14\14e\31\31\377CC\37699\377NN" - "\377<<\377??\377@@\377@@\377@@\376??\377CCe\31\31e\31\31\377CC\376@@\377" - ">>\377??\377@@\377@@\377@@\377@@\376??\377CCe\31\31-\14\14\377DD\376@@\377" - "@@\377@@\377@@\377@@\377@@\377@@\376@@\377DD-\14\14\13\2\2\31333\377AA\377" - "@@\377@@\377@@\377@@\377@@\377@@\377AA\31333\13\2\2\0\0\0D\21\21\357<<\377" - "AA\376@@\376??\376??\376@@\377AA\357<> (14-x) & 1); - } - } -} - -/* - * Отрисовка лампочек ГРП и МГРП. - */ -static void draw_grp_periodic (int top) -{ - int x, y; - t_value val; - - for (y=0; y<2; ++y) { - val = y ? MGRP : GRP; - if (val == old_GRP [y]) - continue; - old_GRP [y] = val; - for (x=0; x<48; ++x) { - draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); - } - } -} - -/* - * Отрисовка лампочек БРЗ. - */ -static void draw_brz_periodic (int top) -{ - int x, y; - t_value val; - - for (y=0; y<8; ++y) { - val = BRZ [7-y]; - if (val == old_BRZ [7-y]) - continue; - old_BRZ [7-y] = val; - for (x=0; x<48; ++x) { - draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); - } - } -} - -/* - * Отрисовка статичной части регистров-модификаторов. - */ -static void draw_modifiers_static (int group, int left, int top) -{ - int x, y, color, reg; - char message [40]; - SDL_Rect area; - - background = black; - foreground = cyan; - - /* Оттеняем группы разрядов. */ - color = grey.r << 16 | grey.g << 8 | grey.b; - for (x=3; x<15; x+=3) { - area.x = left + 74 + x*STEPX; - area.y = top + 26; - area.w = 2; - area.h = 8*STEPY + 2; - SDL_FillRect (screen, &area, color); - } - /* Названия регистров. */ - for (y=0; y<8; ++y) { - reg = regnum [y + group*8]; - sprintf (message, "М%2o", reg); - render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message); - old_M [reg] = ~0; - } - /* Номера битов. */ - for (x=0; x<15; ++x) { - sprintf (message, "%d", 15-x); - render_utf8 (font_small, left+82 + x*STEPX, - (x & 1) ? top+4 : top+10, 0, message); - } -} - -/* - * Отрисовка статичной части регистров ГРП и МГРП. - */ -static void draw_grp_static (int top) -{ - int x, y, color; - char message [40]; - SDL_Rect area; - - background = black; - foreground = cyan; - - /* Оттеняем группы разрядов. */ - color = grey.r << 16 | grey.g << 8 | grey.b; - for (x=3; x<48; x+=3) { - area.x = 98 + x*STEPX; - area.y = top + 26; - area.w = 2; - area.h = 2*STEPY + 2; - SDL_FillRect (screen, &area, color); - } - /* Названия регистров. */ - for (y=0; y<2; ++y) { - render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП"); - old_GRP[y] = ~0; - } - /* Номера битов. */ - for (x=0; x<48; ++x) { - sprintf (message, "%d", 48-x); - render_utf8 (font_small, 106 + x*STEPX, - (x & 1) ? top+10 : top+4, 0, message); - } -} - -/* - * Отрисовка статичной части регистров БРЗ. - */ -static void draw_brz_static (int top) -{ - int x, y, color; - char message [40]; - SDL_Rect area; - - background = black; - foreground = cyan; - - /* Оттеняем группы разрядов. */ - color = grey.r << 16 | grey.g << 8 | grey.b; - for (x=3; x<48; x+=3) { - area.x = 98 + x*STEPX; - area.y = top + 26; - area.w = 2; - area.h = 8*STEPY + 2; - SDL_FillRect (screen, &area, color); - } - /* Названия регистров. */ - for (y=7; y>=0; --y) { - sprintf (message, "БРЗ %d", 7-y); - render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message); - old_BRZ[y] = ~0; - } -} - -/* - * Поиск файла шрифта по имени. - */ -static int probe_font (const char *path, const struct stat *st, int flag) -{ - const char *p; - - if (flag != FTW_F) - return 0; - p = path + strlen (path) - strlen (FONTNAME); - if (p < path || strcmp (p, FONTNAME) != 0) - return 0; - font_path = strdup (path); - return 1; -} - -/* - * Закрываем графическое окно. - */ -void besm6_close_panel () -{ - if (! screen) - return; - TTF_Quit(); - SDL_Quit(); - screen = 0; -} - -#if SDL_MAJOR_VERSION == 2 - -static SDL_Window *sdlWindow; -static SDL_Renderer *sdlRenderer; -static SDL_Texture *sdlTexture; - - -/* - * Начальная инициализация графического окна и шрифтов. - */ -static void init_panel () -{ - if (sim_switches & SWMASK('Q')) - return; - - /* Initialize SDL subsystems - in this case, only video. */ - if (SDL_Init (SDL_INIT_VIDEO) < 0) { - fprintf (stderr, "SDL: unable to init: %s\n", - SDL_GetError ()); - exit (1); - } - sdlWindow = SDL_CreateWindow ("BESM-6 panel", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - WIDTH, HEIGHT, 0 /* regular window */); - if (! sdlWindow) { - fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", - WIDTH, HEIGHT, DEPTH, SDL_GetError ()); - exit (1); - } - - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); - /* Make black background */ - SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); - SDL_RenderClear(sdlRenderer); - - /* Initialize the TTF library */ - if (TTF_Init() < 0) { - fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", - SDL_GetError()); - SDL_Quit(); - exit (1); - } - - /* Find font file */ - if (ftw (FONTPATH1, probe_font, 255) <= 0 && - ftw (FONTPATH2, probe_font, 255) <= 0 && - ftw (FONTPATH3, probe_font, 255) <= 0) { - fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", - FONTNAME, FONTPATH1); - besm6_close_panel(); - exit (1); - } - - /* Open the font file with the requested point size */ - font_big = TTF_OpenFont (font_path, 16); - font_small = TTF_OpenFont (font_path, 9); - if (! font_big || ! font_small) { - fprintf(stderr, "SDL: couldn't load font %s: %s\n", - font_path, SDL_GetError()); - besm6_close_panel(); - exit (1); - } - atexit (besm6_close_panel); - - screen = SDL_CreateRGBSurface(0, WIDTH, HEIGHT, 32, - 0x00FF0000, - 0x0000FF00, - 0x000000FF, - 0xFF000000); - - sdlTexture = SDL_CreateTexture(sdlRenderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STATIC, - WIDTH, HEIGHT); - - /* Отрисовка статичной части панели БЭСМ-6. */ - draw_modifiers_static (0, 24, 10); - draw_modifiers_static (1, 400, 10); - draw_grp_static (180); - draw_brz_static (230); - - /* Tell SDL to update the whole screen */ - SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - SDL_RenderPresent (sdlRenderer); -} - -void (*sim_vm_init)() = init_panel; - -/* - * Обновляем графическое окно. - */ -void besm6_draw_panel () -{ - if (! screen) - return; - - /* Периодическая отрисовка: мигание лампочек. */ - draw_modifiers_periodic (0, 24, 10); - draw_modifiers_periodic (1, 400, 10); - draw_grp_periodic (180); - draw_brz_periodic (230); - - /* Tell SDL to update the whole screen */ - SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - SDL_RenderPresent (sdlRenderer); - - /* Exit SIMH when window closed.*/ - SDL_Event event; - if (SDL_PollEvent (&event) && event.type == SDL_QUIT) - longjmp (cpu_halt, SCPE_STOP); -} - -#else - -/* - * Начальная инициализация графического окна и шрифтов. - */ -static void init_panel () -{ - if (sim_switches & SWMASK('Q')) - return; - - /* Initialize SDL subsystems - in this case, only video. */ - if (SDL_Init (SDL_INIT_VIDEO) < 0) { - fprintf (stderr, "SDL: unable to init: %s\n", - SDL_GetError ()); - exit (1); - } - screen = SDL_SetVideoMode (WIDTH, HEIGHT, DEPTH, SDL_SWSURFACE); - if (! screen) { - fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", - WIDTH, HEIGHT, DEPTH, SDL_GetError ()); - exit (1); - } - - /* Initialize the TTF library */ - if (TTF_Init() < 0) { - fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", - SDL_GetError()); - SDL_Quit(); - exit (1); - } - - /* Find font file */ - if (ftw (FONTPATH1, probe_font, 255) <= 0 && - ftw (FONTPATH2, probe_font, 255) <= 0 && - ftw (FONTPATH3, probe_font, 255) <= 0) { - fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", - FONTNAME, FONTPATH1); - besm6_close_panel(); - exit (1); - } - - /* Open the font file with the requested point size */ - font_big = TTF_OpenFont (font_path, 16); - font_small = TTF_OpenFont (font_path, 9); - if (! font_big || ! font_small) { - fprintf(stderr, "SDL: couldn't load font %s: %s\n", - FONTNAME, TTF_GetError()); - besm6_close_panel(); - exit (1); - } - atexit (besm6_close_panel); - - /* Отрисовка статичной части панели БЭСМ-6. */ - draw_modifiers_static (0, 24, 10); - draw_modifiers_static (1, 400, 10); - draw_grp_static (180); - draw_brz_static (230); - - /* Tell SDL to update the whole screen */ - SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); -} - -void (*sim_vm_init)() = init_panel; - -/* - * Обновляем графическое окно. - */ -void besm6_draw_panel () -{ - if (! screen) - return; - - /* Периодическая отрисовка: мигание лампочек. */ - draw_modifiers_periodic (0, 24, 10); - draw_modifiers_periodic (1, 400, 10); - draw_grp_periodic (180); - draw_brz_periodic (230); - - /* Tell SDL to update the whole screen */ - SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); - - /* Exit SIMH when window closed.*/ - SDL_Event event; - if (SDL_PollEvent (&event) && event.type == SDL_QUIT) - longjmp (cpu_halt, SCPE_STOP); -} - -#if !defined(__WIN32__) && \ - !(defined(__MWERKS__) && !defined(__BEOS__)) && \ - !defined(__MACOS__) && !defined(__MACOSX__) && \ - !defined(__SYMBIAN32__) && !defined(QWS) -#undef main - -/* - * Вот так всё непросто. - */ -int main (int argc, char *argv[]) -{ - extern int SDL_main (int, char**); - - return SDL_main (argc, argv); -} -#endif -#endif /* SDL_MAJOR_VERSION */ - -#else /* HAVE_LIBSDL */ -void besm6_draw_panel () -{ -} -#endif /* HAVE_LIBSDL */ +/* + * Panel of BESM-6, displayed as a graphics window. + * Using libSDL for graphics and libSDL_ttf for fonts. + * + * Copyright (c) 2009, Serge Vakulenko + * Copyright (c) 2014, 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. + */ +#ifdef HAVE_LIBSDL + +#include "besm6_defs.h" +#include +#include + +/* + * Use a 640x480 window with 32 bit pixels. + */ +#define WIDTH 800 +#define HEIGHT 400 +#define DEPTH 32 + +#define STEPX 14 +#define STEPY 16 + +#define FONTNAME "LucidaSansRegular.ttf" +#define FONTPATH1 "/usr/share/fonts" +#define FONTPATH2 "/usr/lib/jvm" +#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions" + +#include +#include + +/* Data and functions that don't depend on SDL version */ +static char *font_path; +static TTF_Font *font_big; +static TTF_Font *font_small; +static SDL_Color foreground; +static SDL_Color background; +static const SDL_Color white = { 255, 255, 255 }; +static const SDL_Color black = { 0, 0, 0 }; +static const SDL_Color cyan = { 0, 128, 128 }; +static const SDL_Color grey = { 64, 64, 64 }; +static t_value old_BRZ [8], old_GRP [2]; +static t_value old_M [NREGS]; + +static const int regnum[] = { + 013, 012, 011, 010, 7, 6, 5, 4, + 027, 016, 015, 014, 3, 2, 1, 020, +}; + +static SDL_Surface *screen; + +/* + * Рисование текста в кодировке UTF-8, с антиалиасингом. + * Параметр halign задаёт выравнивание по горизонтали. + * Цвета заданы глобальными переменными foreground и background. + */ +static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message) +{ + SDL_Surface *text; + SDL_Rect area; + + /* Build image from text */ + text = TTF_RenderUTF8_Shaded (font, message, foreground, background); + + area.x = x; + if (halign < 0) + area.x -= text->w; /* align left */ + else if (halign == 0) + area.x -= text->w / 2; /* center */ + area.y = y; + area.w = text->w; + area.h = text->h; + + /* Put text image to screen */ + SDL_BlitSurface (text, 0, screen, &area); + SDL_FreeSurface (text); +} + +static SDL_Surface *sprite_from_data (int width, int height, + const unsigned char *data) +{ + SDL_Surface *sprite, *optimized; + unsigned *s, r, g, b, y, x; + + sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, + width, height, DEPTH, 0, 0, 0, 0); + /* + optimized = SDL_DisplayFormat (sprite); + SDL_FreeSurface (sprite); + sprite = optimized; + */ + SDL_LockSurface (sprite); + for (y=0; ypixels + y * sprite->pitch); + for (x=0; xformat, r, g, b); + } + } + SDL_UnlockSurface (sprite); + return sprite; +} + +/* + * Рисуем неонку. + */ +static void draw_lamp (int left, int top, int on) +{ + /* Images created by GIMP: save as C file without alpha channel. */ + static const int lamp_width = 12; + static const int lamp_height = 12; + static const unsigned char lamp_on [12 * 12 * 3 + 1] = + "\0\0\0\0\0\0\0\0\0\13\2\2-\14\14e\31\31e\31\31-\14\14\13\2\2\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0D\20\20\313,,\377??\377CC\377CC\377DD\31333D\21\21\0\0" + "\0\0\0\0\0\0\0D\20\20\357LL\377\243\243\376~~\37699\376@@\376@@\377AA\357" + "<>\377@@\377@@\377AA\31333\13\2\2-\14\14\377??\376~~\377\356\356\377\321" + "\321\377<<\377??\377@@\377@@\376@@\377DD-\14\14e\31\31\377CC\37699\377NN" + "\377<<\377??\377@@\377@@\377@@\376??\377CCe\31\31e\31\31\377CC\376@@\377" + ">>\377??\377@@\377@@\377@@\377@@\376??\377CCe\31\31-\14\14\377DD\376@@\377" + "@@\377@@\377@@\377@@\377@@\377@@\376@@\377DD-\14\14\13\2\2\31333\377AA\377" + "@@\377@@\377@@\377@@\377@@\377@@\377AA\31333\13\2\2\0\0\0D\21\21\357<<\377" + "AA\376@@\376??\376??\376@@\377AA\357<> (14-x) & 1); + } + } +} + +/* + * Отрисовка лампочек ГРП и МГРП. + */ +static void draw_grp_periodic (int top) +{ + int x, y; + t_value val; + + for (y=0; y<2; ++y) { + val = y ? MGRP : GRP; + if (val == old_GRP [y]) + continue; + old_GRP [y] = val; + for (x=0; x<48; ++x) { + draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); + } + } +} + +/* + * Отрисовка лампочек БРЗ. + */ +static void draw_brz_periodic (int top) +{ + int x, y; + t_value val; + + for (y=0; y<8; ++y) { + val = BRZ [7-y]; + if (val == old_BRZ [7-y]) + continue; + old_BRZ [7-y] = val; + for (x=0; x<48; ++x) { + draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); + } + } +} + +/* + * Отрисовка статичной части регистров-модификаторов. + */ +static void draw_modifiers_static (int group, int left, int top) +{ + int x, y, color, reg; + char message [40]; + SDL_Rect area; + + background = black; + foreground = cyan; + + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<15; x+=3) { + area.x = left + 74 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 8*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=0; y<8; ++y) { + reg = regnum [y + group*8]; + sprintf (message, "М%2o", reg); + render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message); + old_M [reg] = ~0; + } + /* Номера битов. */ + for (x=0; x<15; ++x) { + sprintf (message, "%d", 15-x); + render_utf8 (font_small, left+82 + x*STEPX, + (x & 1) ? top+4 : top+10, 0, message); + } +} + +/* + * Отрисовка статичной части регистров ГРП и МГРП. + */ +static void draw_grp_static (int top) +{ + int x, y, color; + char message [40]; + SDL_Rect area; + + background = black; + foreground = cyan; + + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<48; x+=3) { + area.x = 98 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 2*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=0; y<2; ++y) { + render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП"); + old_GRP[y] = ~0; + } + /* Номера битов. */ + for (x=0; x<48; ++x) { + sprintf (message, "%d", 48-x); + render_utf8 (font_small, 106 + x*STEPX, + (x & 1) ? top+10 : top+4, 0, message); + } +} + +/* + * Отрисовка статичной части регистров БРЗ. + */ +static void draw_brz_static (int top) +{ + int x, y, color; + char message [40]; + SDL_Rect area; + + background = black; + foreground = cyan; + + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<48; x+=3) { + area.x = 98 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 8*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=7; y>=0; --y) { + sprintf (message, "БРЗ %d", 7-y); + render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message); + old_BRZ[y] = ~0; + } +} + +/* + * Поиск файла шрифта по имени. + */ +static int probe_font (const char *path, const struct stat *st, int flag) +{ + const char *p; + + if (flag != FTW_F) + return 0; + p = path + strlen (path) - strlen (FONTNAME); + if (p < path || strcmp (p, FONTNAME) != 0) + return 0; + font_path = strdup (path); + return 1; +} + +/* + * Закрываем графическое окно. + */ +void besm6_close_panel () +{ + if (! screen) + return; + TTF_Quit(); + SDL_Quit(); + screen = 0; +} + +#if SDL_MAJOR_VERSION == 2 + +static SDL_Window *sdlWindow; +static SDL_Renderer *sdlRenderer; +static SDL_Texture *sdlTexture; + + +/* + * Начальная инициализация графического окна и шрифтов. + */ +static void init_panel () +{ + if (sim_switches & SWMASK('Q')) + return; + + /* Initialize SDL subsystems - in this case, only video. */ + if (SDL_Init (SDL_INIT_VIDEO) < 0) { + fprintf (stderr, "SDL: unable to init: %s\n", + SDL_GetError ()); + exit (1); + } + sdlWindow = SDL_CreateWindow ("BESM-6 panel", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + WIDTH, HEIGHT, 0 /* regular window */); + if (! sdlWindow) { + fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", + WIDTH, HEIGHT, DEPTH, SDL_GetError ()); + exit (1); + } + + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); + /* Make black background */ + SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); + SDL_RenderClear(sdlRenderer); + + /* Initialize the TTF library */ + if (TTF_Init() < 0) { + fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", + SDL_GetError()); + SDL_Quit(); + exit (1); + } + + /* Find font file */ + if (ftw (FONTPATH1, probe_font, 255) <= 0 && + ftw (FONTPATH2, probe_font, 255) <= 0 && + ftw (FONTPATH3, probe_font, 255) <= 0) { + fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", + FONTNAME, FONTPATH1); + besm6_close_panel(); + exit (1); + } + + /* Open the font file with the requested point size */ + font_big = TTF_OpenFont (font_path, 16); + font_small = TTF_OpenFont (font_path, 9); + if (! font_big || ! font_small) { + fprintf(stderr, "SDL: couldn't load font %s: %s\n", + font_path, SDL_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); + + screen = SDL_CreateRGBSurface(0, WIDTH, HEIGHT, 32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + + sdlTexture = SDL_CreateTexture(sdlRenderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, + WIDTH, HEIGHT); + + /* Отрисовка статичной части панели БЭСМ-6. */ + draw_modifiers_static (0, 24, 10); + draw_modifiers_static (1, 400, 10); + draw_grp_static (180); + draw_brz_static (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent (sdlRenderer); +} + +void (*sim_vm_init)() = init_panel; + +/* + * Обновляем графическое окно. + */ +void besm6_draw_panel () +{ + if (! screen) + return; + + /* Периодическая отрисовка: мигание лампочек. */ + draw_modifiers_periodic (0, 24, 10); + draw_modifiers_periodic (1, 400, 10); + draw_grp_periodic (180); + draw_brz_periodic (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent (sdlRenderer); + + /* Exit SIMH when window closed.*/ + SDL_Event event; + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); +} + +#else + +/* + * Начальная инициализация графического окна и шрифтов. + */ +static void init_panel () +{ + if (sim_switches & SWMASK('Q')) + return; + + /* Initialize SDL subsystems - in this case, only video. */ + if (SDL_Init (SDL_INIT_VIDEO) < 0) { + fprintf (stderr, "SDL: unable to init: %s\n", + SDL_GetError ()); + exit (1); + } + screen = SDL_SetVideoMode (WIDTH, HEIGHT, DEPTH, SDL_SWSURFACE); + if (! screen) { + fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", + WIDTH, HEIGHT, DEPTH, SDL_GetError ()); + exit (1); + } + + /* Initialize the TTF library */ + if (TTF_Init() < 0) { + fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", + SDL_GetError()); + SDL_Quit(); + exit (1); + } + + /* Find font file */ + if (ftw (FONTPATH1, probe_font, 255) <= 0 && + ftw (FONTPATH2, probe_font, 255) <= 0 && + ftw (FONTPATH3, probe_font, 255) <= 0) { + fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", + FONTNAME, FONTPATH1); + besm6_close_panel(); + exit (1); + } + + /* Open the font file with the requested point size */ + font_big = TTF_OpenFont (font_path, 16); + font_small = TTF_OpenFont (font_path, 9); + if (! font_big || ! font_small) { + fprintf(stderr, "SDL: couldn't load font %s: %s\n", + FONTNAME, TTF_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); + + /* Отрисовка статичной части панели БЭСМ-6. */ + draw_modifiers_static (0, 24, 10); + draw_modifiers_static (1, 400, 10); + draw_grp_static (180); + draw_brz_static (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); +} + +void (*sim_vm_init)() = init_panel; + +/* + * Обновляем графическое окно. + */ +void besm6_draw_panel () +{ + if (! screen) + return; + + /* Периодическая отрисовка: мигание лампочек. */ + draw_modifiers_periodic (0, 24, 10); + draw_modifiers_periodic (1, 400, 10); + draw_grp_periodic (180); + draw_brz_periodic (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); + + /* Exit SIMH when window closed.*/ + SDL_Event event; + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); +} + +#if !defined(__WIN32__) && \ + !(defined(__MWERKS__) && !defined(__BEOS__)) && \ + !defined(__MACOS__) && !defined(__MACOSX__) && \ + !defined(__SYMBIAN32__) && !defined(QWS) +#undef main + +/* + * Вот так всё непросто. + */ +int main (int argc, char *argv[]) +{ + extern int SDL_main (int, char**); + + return SDL_main (argc, argv); +} +#endif +#endif /* SDL_MAJOR_VERSION */ + +#else /* HAVE_LIBSDL */ +void besm6_draw_panel () +{ +} +#endif /* HAVE_LIBSDL */ diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c index 9618f76e..d6dee824 100644 --- a/BESM6/besm6_printer.c +++ b/BESM6/besm6_printer.c @@ -1,345 +1,345 @@ -/* - * besm6_printer.c: BESM-6 line printer device - * - * 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 printer_event (UNIT *u); -void offset_gost_write (int num, FILE *fout); - -/* - * Printer data structures - * - * printer_dev PRINTER device descriptor - * printer_unit PRINTER unit descriptor - * printer_reg PRINTER register list - */ -UNIT printer_unit [] = { - { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, - { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, -}; - - -#define MAX_STRIKES 10 -struct acpu_t { - int curchar, feed, rampup; - int strikes; - int length; - unsigned char line[128][MAX_STRIKES]; -} acpu[2]; - -int acpu_isatty[2]; - -#define PRN1_NOT_READY (1<<19) -#define PRN2_NOT_READY (1<<18) - -/* 1 = можно пользоваться молоточками, 0 - бумага в процессе протяжки */ -#define PRN1_LINEFEED (1<<23) -#define PRN2_LINEFEED (1<<22) - -#define SLOW_START 100*MSEC -#define FAST_START 1*MSEC -#define LINEFEED_SYNC 1 /* Чтобы быстрее печатало; в жизни 20-25 мс/1.4 мс ~= 17 */ - -REG printer_reg[] = { -{ "Готов", &READY, 2, 2, 18, 1 }, -{ "Прогон", &READY, 2, 2, 22, 1 }, -{ 0 } -}; - -MTAB printer_mod[] = { - { 0 } -}; - -t_stat printer_reset (DEVICE *dptr); -t_stat printer_attach (UNIT *uptr, char *cptr); -t_stat printer_detach (UNIT *uptr); - -DEVICE printer_dev = { - "PRN", printer_unit, printer_reg, printer_mod, - 2, 8, 19, 1, 8, 50, - NULL, NULL, &printer_reset, NULL, &printer_attach, &printer_detach, - NULL, DEV_DISABLE | DEV_DEBUG -}; - -/* - * Reset routine - */ -t_stat printer_reset (DEVICE *dptr) -{ - memset(acpu, 0, sizeof (acpu)); - acpu[0].rampup = acpu[1].rampup = SLOW_START; - sim_cancel (&printer_unit[0]); - sim_cancel (&printer_unit[1]); - READY |= PRN1_NOT_READY | PRN2_NOT_READY; - if (printer_unit[0].flags & UNIT_ATT) - READY &= ~PRN1_NOT_READY; - if (printer_unit[1].flags & UNIT_ATT) - READY &= ~PRN2_NOT_READY; - return SCPE_OK; -} - -t_stat printer_attach (UNIT *u, char *cptr) -{ - t_stat s; - int num = u - printer_unit; - - if (u->flags & UNIT_ATT) { - /* Switching files cleanly */ - detach_unit (u); - } - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; - - acpu_isatty[num] = !strcmp(cptr, "/dev/tty"); - if (!acpu_isatty[num]) { - /* Write UTF-8 tag: zero width no-break space. */ - fputs ("\xEF\xBB\xBF", u->fileref); - } - - READY &= ~(PRN1_NOT_READY >> num); - return SCPE_OK; -} - -t_stat printer_detach (UNIT *u) -{ - int num = u - printer_unit; - READY |= PRN1_NOT_READY >> num; - return detach_unit (u); -} - -/* - * Управление двигателями, прогон - */ -void printer_control (int num, uint32 cmd) -{ - UNIT *u = &printer_unit[num]; - struct acpu_t * dev = acpu + num; - - if (printer_dev.dctrl) - besm6_debug(">>> АЦПУ%d команда %o", num, cmd); - if (READY & (PRN1_NOT_READY >> num)) { - if (printer_dev.dctrl) - besm6_debug(">>> АЦПУ%d не готово", num, cmd); - return; - } - switch (cmd) { - case 1: /* linefeed */ - READY &= ~(PRN1_LINEFEED >> num); - offset_gost_write (num, u->fileref); - dev->feed = LINEFEED_SYNC; - break; - case 4: /* start */ - /* стартуем из состояния прогона для надежности */ - dev->feed = LINEFEED_SYNC; - READY &= ~(PRN1_LINEFEED >> num); - if (dev->rampup) - sim_activate (u, dev->rampup); - dev->rampup = 0; - break; - case 10: /* motor and ribbon off */ - case 8: /* motor off? (undocumented) */ - case 2: /* ribbon off */ - dev->rampup = cmd == 2 ? FAST_START : SLOW_START; - sim_cancel (u); - break; - } -} - -/* - * Управление молоточками - */ -void printer_hammer (int num, int pos, uint32 mask) -{ - struct acpu_t * dev = acpu + num; - while (mask) { - if (mask & 1) { - int strike = 0; - while (dev->line[pos][strike] && strike < MAX_STRIKES) - ++strike; - if (strike < MAX_STRIKES) { - dev->line[pos][strike] = dev->curchar; - if (pos + 1 > dev->length) - dev->length = pos + 1; - if (strike + 1 > dev->strikes) - dev->strikes = strike + 1; - } - } - mask >>= 1; - pos += 8; - } -} - -/* - * Событие: вращение барабана АЦПУ. - * Устанавливаем флаг прерывания. - */ -t_stat printer_event (UNIT *u) -{ - int num = u - printer_unit; - struct acpu_t * dev = acpu + num; - - switch (dev->curchar) { - case 0 ... 0137: - GRP |= GRP_PRN1_SYNC >> num; - ++dev->curchar; - /* For next char */ - sim_activate (u, 1400*USEC); - if (dev->feed && --dev->feed == 0) { - READY |= PRN1_LINEFEED >> num; - } - break; - case 0140: - /* For "zero" */ - dev->curchar = 0; - GRP |= GRP_PRN1_ZERO >> num; - if (printer_dev.dctrl) - besm6_debug(">>> АЦПУ%d 'ноль'", num); - /* For first sync after "zero" */ - sim_activate (u, 1000*USEC); - break; - } - return SCPE_OK; -} - -int gost_latin = 0; /* default cyrillics */ - -/* - * GOST-10859 encoding. - * Documentation: http://en.wikipedia.org/wiki/GOST_10859 - */ -static const unsigned short gost_to_unicode_cyr [256] = { -/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, -/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, -/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, -/* 040-047 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, -/* 050-057 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, -/* 060-067 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, -/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, -/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, -/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, -/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, -/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, -}; - -static const unsigned short gost_to_unicode_lat [256] = { -/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, -/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, -/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, -/* 040-047 */ 0x41, 0x0411, 0x42, 0x0413, 0x0414, 0x45, 0x0416, 0x0417, -/* 050-057 */ 0x0418, 0x0419, 0x4b, 0x041b, 0x4d, 0x48, 0x4f, 0x041f, -/* 060-067 */ 0x50, 0x43, 0x54, 0x59, 0x0424, 0x58, 0x0426, 0x0427, -/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, -/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, -/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, -/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, -/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, -}; -/* - * Write Unicode symbol to file. - * Convert to UTF-8 encoding: - * 00000000.0xxxxxxx -> 0xxxxxxx - * 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy - * xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz - */ -static void -utf8_putc (unsigned short ch, FILE *fout) -{ - if (ch < 0x80) { - putc (ch, fout); - return; - } - if (ch < 0x800) { - putc (ch >> 6 | 0xc0, fout); - putc ((ch & 0x3f) | 0x80, fout); - return; - } - putc (ch >> 12 | 0xe0, fout); - putc (((ch >> 6) & 0x3f) | 0x80, fout); - putc ((ch & 0x3f) | 0x80, fout); -} - -unsigned short -gost_to_unicode (unsigned char ch) -{ - return gost_latin ? gost_to_unicode_lat [ch] : - gost_to_unicode_cyr [ch]; -} - -/* - * Write GOST-10859 symbol to file. - * Convert to local encoding (UTF-8, KOI8-R, CP-1251, CP-866). - */ -void -gost_putc (unsigned char ch, FILE *fout) -{ - unsigned short u; - - u = gost_to_unicode (ch); - if (! u) - u = ' '; - utf8_putc (u, fout); -} - -/* - * Write GOST-10859 string with overprint to file in UTF-8. - */ -void -offset_gost_write (int num, FILE *fout) -{ - struct acpu_t * dev = acpu + num; - int s, p; - for (s = 0; s < dev->strikes; ++s) { - if (s) - fputc ('\r', fout); - for (p = 0; p < dev->length; ++p) { - gost_putc (dev->line[p][s] - 1, fout); - } - } - - if (acpu_isatty[num]) - fputc('\r', fout); - - fputc ('\n', fout); - memset(dev->line, 0, sizeof (dev->line)); - dev->length = dev->strikes = 0; -} - -/* - * Выясняем, остановлены ли АЦПУ. Нужно для входа в "спящий" режим. - */ -int printer_is_idle () -{ - if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0) - return 0; - if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0) - return 0; - return 1; -} +/* + * besm6_printer.c: BESM-6 line printer device + * + * 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 printer_event (UNIT *u); +void offset_gost_write (int num, FILE *fout); + +/* + * Printer data structures + * + * printer_dev PRINTER device descriptor + * printer_unit PRINTER unit descriptor + * printer_reg PRINTER register list + */ +UNIT printer_unit [] = { + { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, + { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, +}; + + +#define MAX_STRIKES 10 +struct acpu_t { + int curchar, feed, rampup; + int strikes; + int length; + unsigned char line[128][MAX_STRIKES]; +} acpu[2]; + +int acpu_isatty[2]; + +#define PRN1_NOT_READY (1<<19) +#define PRN2_NOT_READY (1<<18) + +/* 1 = можно пользоваться молоточками, 0 - бумага в процессе протяжки */ +#define PRN1_LINEFEED (1<<23) +#define PRN2_LINEFEED (1<<22) + +#define SLOW_START 100*MSEC +#define FAST_START 1*MSEC +#define LINEFEED_SYNC 1 /* Чтобы быстрее печатало; в жизни 20-25 мс/1.4 мс ~= 17 */ + +REG printer_reg[] = { +{ "Готов", &READY, 2, 2, 18, 1 }, +{ "Прогон", &READY, 2, 2, 22, 1 }, +{ 0 } +}; + +MTAB printer_mod[] = { + { 0 } +}; + +t_stat printer_reset (DEVICE *dptr); +t_stat printer_attach (UNIT *uptr, char *cptr); +t_stat printer_detach (UNIT *uptr); + +DEVICE printer_dev = { + "PRN", printer_unit, printer_reg, printer_mod, + 2, 8, 19, 1, 8, 50, + NULL, NULL, &printer_reset, NULL, &printer_attach, &printer_detach, + NULL, DEV_DISABLE | DEV_DEBUG +}; + +/* + * Reset routine + */ +t_stat printer_reset (DEVICE *dptr) +{ + memset(acpu, 0, sizeof (acpu)); + acpu[0].rampup = acpu[1].rampup = SLOW_START; + sim_cancel (&printer_unit[0]); + sim_cancel (&printer_unit[1]); + READY |= PRN1_NOT_READY | PRN2_NOT_READY; + if (printer_unit[0].flags & UNIT_ATT) + READY &= ~PRN1_NOT_READY; + if (printer_unit[1].flags & UNIT_ATT) + READY &= ~PRN2_NOT_READY; + return SCPE_OK; +} + +t_stat printer_attach (UNIT *u, char *cptr) +{ + t_stat s; + int num = u - printer_unit; + + if (u->flags & UNIT_ATT) { + /* Switching files cleanly */ + detach_unit (u); + } + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + + acpu_isatty[num] = !strcmp(cptr, "/dev/tty"); + if (!acpu_isatty[num]) { + /* Write UTF-8 tag: zero width no-break space. */ + fputs ("\xEF\xBB\xBF", u->fileref); + } + + READY &= ~(PRN1_NOT_READY >> num); + return SCPE_OK; +} + +t_stat printer_detach (UNIT *u) +{ + int num = u - printer_unit; + READY |= PRN1_NOT_READY >> num; + return detach_unit (u); +} + +/* + * Управление двигателями, прогон + */ +void printer_control (int num, uint32 cmd) +{ + UNIT *u = &printer_unit[num]; + struct acpu_t * dev = acpu + num; + + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d команда %o", num, cmd); + if (READY & (PRN1_NOT_READY >> num)) { + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d не готово", num, cmd); + return; + } + switch (cmd) { + case 1: /* linefeed */ + READY &= ~(PRN1_LINEFEED >> num); + offset_gost_write (num, u->fileref); + dev->feed = LINEFEED_SYNC; + break; + case 4: /* start */ + /* стартуем из состояния прогона для надежности */ + dev->feed = LINEFEED_SYNC; + READY &= ~(PRN1_LINEFEED >> num); + if (dev->rampup) + sim_activate (u, dev->rampup); + dev->rampup = 0; + break; + case 10: /* motor and ribbon off */ + case 8: /* motor off? (undocumented) */ + case 2: /* ribbon off */ + dev->rampup = cmd == 2 ? FAST_START : SLOW_START; + sim_cancel (u); + break; + } +} + +/* + * Управление молоточками + */ +void printer_hammer (int num, int pos, uint32 mask) +{ + struct acpu_t * dev = acpu + num; + while (mask) { + if (mask & 1) { + int strike = 0; + while (dev->line[pos][strike] && strike < MAX_STRIKES) + ++strike; + if (strike < MAX_STRIKES) { + dev->line[pos][strike] = dev->curchar; + if (pos + 1 > dev->length) + dev->length = pos + 1; + if (strike + 1 > dev->strikes) + dev->strikes = strike + 1; + } + } + mask >>= 1; + pos += 8; + } +} + +/* + * Событие: вращение барабана АЦПУ. + * Устанавливаем флаг прерывания. + */ +t_stat printer_event (UNIT *u) +{ + int num = u - printer_unit; + struct acpu_t * dev = acpu + num; + + switch (dev->curchar) { + case 0 ... 0137: + GRP |= GRP_PRN1_SYNC >> num; + ++dev->curchar; + /* For next char */ + sim_activate (u, 1400*USEC); + if (dev->feed && --dev->feed == 0) { + READY |= PRN1_LINEFEED >> num; + } + break; + case 0140: + /* For "zero" */ + dev->curchar = 0; + GRP |= GRP_PRN1_ZERO >> num; + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d 'ноль'", num); + /* For first sync after "zero" */ + sim_activate (u, 1000*USEC); + break; + } + return SCPE_OK; +} + +int gost_latin = 0; /* default cyrillics */ + +/* + * GOST-10859 encoding. + * Documentation: http://en.wikipedia.org/wiki/GOST_10859 + */ +static const unsigned short gost_to_unicode_cyr [256] = { +/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, +/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, +/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, +/* 040-047 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, +/* 050-057 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, +/* 060-067 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, +/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, +/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, +/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, +/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, +/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, +}; + +static const unsigned short gost_to_unicode_lat [256] = { +/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, +/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, +/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, +/* 040-047 */ 0x41, 0x0411, 0x42, 0x0413, 0x0414, 0x45, 0x0416, 0x0417, +/* 050-057 */ 0x0418, 0x0419, 0x4b, 0x041b, 0x4d, 0x48, 0x4f, 0x041f, +/* 060-067 */ 0x50, 0x43, 0x54, 0x59, 0x0424, 0x58, 0x0426, 0x0427, +/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, +/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, +/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, +/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, +/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, +}; +/* + * Write Unicode symbol to file. + * Convert to UTF-8 encoding: + * 00000000.0xxxxxxx -> 0xxxxxxx + * 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy + * xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz + */ +static void +utf8_putc (unsigned short ch, FILE *fout) +{ + if (ch < 0x80) { + putc (ch, fout); + return; + } + if (ch < 0x800) { + putc (ch >> 6 | 0xc0, fout); + putc ((ch & 0x3f) | 0x80, fout); + return; + } + putc (ch >> 12 | 0xe0, fout); + putc (((ch >> 6) & 0x3f) | 0x80, fout); + putc ((ch & 0x3f) | 0x80, fout); +} + +unsigned short +gost_to_unicode (unsigned char ch) +{ + return gost_latin ? gost_to_unicode_lat [ch] : + gost_to_unicode_cyr [ch]; +} + +/* + * Write GOST-10859 symbol to file. + * Convert to local encoding (UTF-8, KOI8-R, CP-1251, CP-866). + */ +void +gost_putc (unsigned char ch, FILE *fout) +{ + unsigned short u; + + u = gost_to_unicode (ch); + if (! u) + u = ' '; + utf8_putc (u, fout); +} + +/* + * Write GOST-10859 string with overprint to file in UTF-8. + */ +void +offset_gost_write (int num, FILE *fout) +{ + struct acpu_t * dev = acpu + num; + int s, p; + for (s = 0; s < dev->strikes; ++s) { + if (s) + fputc ('\r', fout); + for (p = 0; p < dev->length; ++p) { + gost_putc (dev->line[p][s] - 1, fout); + } + } + + if (acpu_isatty[num]) + fputc('\r', fout); + + fputc ('\n', fout); + memset(dev->line, 0, sizeof (dev->line)); + dev->length = dev->strikes = 0; +} + +/* + * Выясняем, остановлены ли АЦПУ. Нужно для входа в "спящий" режим. + */ +int printer_is_idle () +{ + if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0) + return 0; + if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0) + return 0; + return 1; +} diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c index d9d974f1..7f1a5235 100644 --- a/BESM6/besm6_punch.c +++ b/BESM6/besm6_punch.c @@ -1,472 +1,472 @@ -/* - * besm6_punch.c: BESM-6 punchcard/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" -#include -#include - -t_stat fs_event (UNIT *u); -t_stat uvvk_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[] = { -{ "Готов", &READY, 2, 2, 14, 1 }, -{ "ФС1500-1", &FS[0], 8, 8, 0, 1 }, -{ "ФС1500-2", &FS[2], 8, 8, 0, 1 }, -{ 0 } -}; - -MTAB fs_mod[] = { - { 0 } -}; - -t_stat fs_reset (DEVICE *dptr); -t_stat fs_attach (UNIT *uptr, 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_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]; - -/* - * 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; -} - -t_stat fs_attach (UNIT *u, char *cptr) -{ - t_stat s; - int num = u - fs_unit; - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; - struct stat stbuf; - fstat (fileno(u->fileref), &stbuf); - isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0; - if (isfifo[num]) { - int flags = fcntl(fileno(u->fileref), F_GETFL, 0); - fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK); - } - 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); -static int utf8_getc (FILE *fin); - -/* - * Событие: читаем очередной символ с перфоленты в регистр. - * Устанавливаем флаг прерывания. - */ -t_stat fs_event (UNIT *u) -{ - int num = u - fs_unit; -again: - switch (fs_state[num]) { - case FS_STARTING: - /* По первому прерыванию после запуска двигателя ничего не читаем */ - FS[num] = 0; - fs_state[num] = FS_RUNNING; - break; - case FS_RUNNING: { - int ch; - /* переводы строк игнорируются */ - while ((ch = utf8_getc (u->fileref)) == '\n'); - if (ch < 0) { - /* хвост ленты без пробивок */ - FS[num] = 0; - fs_state[num] = FS_TAIL; - } else if (ch == '\f') { - fs_state[num] = FS_IMAGE; - goto again; - } else { - ch = FS[num] = unicode_to_gost (ch); - ch = (ch & 0x55) + ((ch >> 1) & 0x55); - ch = (ch & 0x33) + ((ch >> 2) & 0x33); - ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); - if (ch & 1); else FS[num] |= 0x80; - } - break; - } - case FS_IMAGE ... FS_IMAGE_LAST: { - int ch = utf8_getc (u->fileref); - if (ch < 0) { - /* обрыв ленты */ - FS[num] = 0; - fs_state[num] = FS_TAIL; - } else if (ch == '\n') { - /* идем дополнять образ карты нулевыми байтами */ - fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE); - goto again; - } else if (ch == '\f') { - if (fs_state[num] != FS_IMAGE) - besm6_debug("<<< ENDA3 requested mid-card?"); - fs_state[num] = FS_ENDA3; - goto again; - } else { - ch = FS[num] = unicode_to_gost (ch); - ch = (ch & 0x55) + ((ch >> 1) & 0x55); - ch = (ch & 0x33) + ((ch >> 2) & 0x33); - ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); - if (ch & 1); else FS[num] |= 0x80; - ++fs_state[num]; - } - break; - } - case FS_TOOLONG: { - /* дочитываем до конца строки */ - int ch; - besm6_debug("<<< too long???"); - while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0); - if (ch < 0) { - /* хвост ленты без пробивок */ - FS[num] = 0; - fs_state[num] = FS_TAIL; - } else - goto again; - break; - } - case FS_FILLUP ... FS_FILLUP_LAST: - FS[num] = 0; - if (++fs_state[num] == FS_ENDA3) { - fs_state[num] = FS_IMAGE; - } - break; - case FS_ENDA3 ... 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; - } - break; - case FS_IDLE: - case FS_TAIL: - FS[num] = 0; - break; - } - 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]; -} - -int fs_is_idle (void) -{ - return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE; -} - -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, 0174, 017, 017, -/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017, -/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 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 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); -} +/* + * besm6_punch.c: BESM-6 punchcard/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" +#include +#include + +t_stat fs_event (UNIT *u); +t_stat uvvk_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[] = { +{ "Готов", &READY, 2, 2, 14, 1 }, +{ "ФС1500-1", &FS[0], 8, 8, 0, 1 }, +{ "ФС1500-2", &FS[2], 8, 8, 0, 1 }, +{ 0 } +}; + +MTAB fs_mod[] = { + { 0 } +}; + +t_stat fs_reset (DEVICE *dptr); +t_stat fs_attach (UNIT *uptr, 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_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]; + +/* + * 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; +} + +t_stat fs_attach (UNIT *u, char *cptr) +{ + t_stat s; + int num = u - fs_unit; + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + struct stat stbuf; + fstat (fileno(u->fileref), &stbuf); + isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0; + if (isfifo[num]) { + int flags = fcntl(fileno(u->fileref), F_GETFL, 0); + fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK); + } + 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); +static int utf8_getc (FILE *fin); + +/* + * Событие: читаем очередной символ с перфоленты в регистр. + * Устанавливаем флаг прерывания. + */ +t_stat fs_event (UNIT *u) +{ + int num = u - fs_unit; +again: + switch (fs_state[num]) { + case FS_STARTING: + /* По первому прерыванию после запуска двигателя ничего не читаем */ + FS[num] = 0; + fs_state[num] = FS_RUNNING; + break; + case FS_RUNNING: { + int ch; + /* переводы строк игнорируются */ + while ((ch = utf8_getc (u->fileref)) == '\n'); + if (ch < 0) { + /* хвост ленты без пробивок */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else if (ch == '\f') { + fs_state[num] = FS_IMAGE; + goto again; + } else { + ch = FS[num] = unicode_to_gost (ch); + ch = (ch & 0x55) + ((ch >> 1) & 0x55); + ch = (ch & 0x33) + ((ch >> 2) & 0x33); + ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); + if (ch & 1); else FS[num] |= 0x80; + } + break; + } + case FS_IMAGE ... FS_IMAGE_LAST: { + int ch = utf8_getc (u->fileref); + if (ch < 0) { + /* обрыв ленты */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else if (ch == '\n') { + /* идем дополнять образ карты нулевыми байтами */ + fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE); + goto again; + } else if (ch == '\f') { + if (fs_state[num] != FS_IMAGE) + besm6_debug("<<< ENDA3 requested mid-card?"); + fs_state[num] = FS_ENDA3; + goto again; + } else { + ch = FS[num] = unicode_to_gost (ch); + ch = (ch & 0x55) + ((ch >> 1) & 0x55); + ch = (ch & 0x33) + ((ch >> 2) & 0x33); + ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); + if (ch & 1); else FS[num] |= 0x80; + ++fs_state[num]; + } + break; + } + case FS_TOOLONG: { + /* дочитываем до конца строки */ + int ch; + besm6_debug("<<< too long???"); + while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0); + if (ch < 0) { + /* хвост ленты без пробивок */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else + goto again; + break; + } + case FS_FILLUP ... FS_FILLUP_LAST: + FS[num] = 0; + if (++fs_state[num] == FS_ENDA3) { + fs_state[num] = FS_IMAGE; + } + break; + case FS_ENDA3 ... 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; + } + break; + case FS_IDLE: + case FS_TAIL: + FS[num] = 0; + break; + } + 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]; +} + +int fs_is_idle (void) +{ + return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE; +} + +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, 0174, 017, 017, +/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017, +/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 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 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); +} diff --git a/BESM6/besm6_sys.c b/BESM6/besm6_sys.c index 5d6e6927..1c128938 100644 --- a/BESM6/besm6_sys.c +++ b/BESM6/besm6_sys.c @@ -1,719 +1,719 @@ -/* - * besm6_sys.c: BESM-6 simulator interface - * - * Copyright (c) 2009, Serge Vakulenko - * Copyright (c) 2009, Leonid Broukhis - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You can redistribute this program and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation; - * either version 2 of the License, or (at your discretion) any later version. - * See the accompanying file "COPYING" for more details. - * - * This file implements three essential functions: - * - * sim_load() - loading and dumping memory and CPU state - * in a way, specific for BESM-6 architecture - * fprint_sym() - print a machune instruction using - * opcode mnemonic or in a digital format - * parse_sym() - scan a string and build an instruction - * word from it - */ -#include "besm6_defs.h" -#include -#include - -const char *opname_short_bemsh [64] = { - "зп", "зпм", "рег", "счм", "сл", "вч", "вчоб", "вчаб", - "сч", "и", "нтж", "слц", "знак", "или", "дел", "умн", - "сбр", "рзб", "чед", "нед", "слп", "вчп", "сд", "рж", - "счрж", "счмр", "э32", "увв", "слпа", "вчпа", "сда", "ржа", - "уи", "уим", "счи", "счим", "уии", "сли", "э46", "э47", - "э50", "э51", "э52", "э53", "э54", "э55", "э56", "э57", - "э60", "э61", "э62", "э63", "э64", "э65", "э66", "э67", - "э70", "э71", "э72", "э73", "э74", "э75", "э76", "э77", -}; - -static const char *opname_long_bemsh [16] = { - "э20", "э21", "мода", "мод", "уиа", "слиа", "по", "пе", - "пб", "пв", "выпр", "стоп", "пио", "пино", "э36", "цикл", -}; - -const char *opname_short_madlen [64] = { - "atx", "stx", "mod", "xts", "a+x", "a-x", "x-a", "amx", - "xta", "aax", "aex", "arx", "avx", "aox", "a/x", "a*x", - "apx", "aux", "acx", "anx", "e+x", "e-x", "asx", "xtr", - "rte", "yta", "*32", "ext", "e+n", "e-n", "asn", "ntr", - "ati", "sti", "ita", "its", "mtj", "j+m", "*46", "*47", - "*50", "*51", "*52", "*53", "*54", "*55", "*56", "*57", - "*60", "*61", "*62", "*63", "*64", "*65", "*66", "*67", - "*70", "*71", "*72", "*73", "*74", "*75", "*76", "*77", -}; - -static const char *opname_long_madlen [16] = { - "*20", "*21", "utc", "wtc", "vtm", "utm", "uza", "u1a", - "uj", "vjm", "ij", "stop", "vzm", "v1m", "*36", "vlm", -}; - -/* - * Выдача мнемоники по коду инструкции. - * Код должен быть в диапазоне 000..077 или 0200..0370. - */ -const char *besm6_opname (int opcode) -{ - if (sim_switches & SWMASK ('L')) { - /* Latin mnemonics. */ - if (opcode & 0200) - return opname_long_madlen [(opcode >> 3) & 017]; - return opname_short_madlen [opcode]; - } - if (opcode & 0200) - return opname_long_bemsh [(opcode >> 3) & 017]; - return opname_short_bemsh [opcode]; -}; - -/* - * Выдача кода инструкции по мнемонике (UTF-8). - */ -int besm6_opcode (char *instr) -{ - int i; - - for (i=0; i<64; ++i) - if (strcmp (opname_short_bemsh[i], instr) == 0 || - strcmp (opname_short_madlen[i], instr) == 0) - return i; - for (i=0; i<16; ++i) - if (strcmp (opname_long_bemsh[i], instr) == 0 || - strcmp (opname_long_madlen[i], instr) == 0) - return (i << 3) | 0200; - return -1; -} - -/* - * Выдача на консоль и в файл протокола. - * Если первый символ формата - подчерк, на консоль не печатаем. - * Добавляет перевод строки. - */ -void besm6_log (const char *fmt, ...) -{ - va_list args; - - if (*fmt == '_') - ++fmt; - else { - va_start (args, fmt); - vprintf (fmt, args); - printf ("\r\n"); - va_end (args); - } - if (sim_log) { - va_start (args, fmt); - vfprintf (sim_log, fmt, args); - if (sim_log == stdout) - fprintf (sim_log, "\r"); - fprintf (sim_log, "\n"); - fflush (sim_log); - va_end (args); - } -} - -/* - * Не добавляет перевод строки. - */ -void besm6_log_cont (const char *fmt, ...) -{ - va_list args; - - if (*fmt == '_') - ++fmt; - else { - va_start (args, fmt); - vprintf (fmt, args); - va_end (args); - } - if (sim_log) { - va_start (args, fmt); - vfprintf (sim_log, fmt, args); - fflush (sim_log); - va_end (args); - } -} - -/* - * Выдача на консоль и в файл отладки: если включён режим "cpu debug". - * Добавляет перевод строки. - */ -void besm6_debug (const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - vprintf (fmt, args); - printf ("\r\n"); - va_end (args); - if (sim_deb && sim_deb != stdout) { - va_start (args, fmt); - vfprintf (sim_deb, fmt, args); - fprintf (sim_deb, "\n"); - fflush (sim_deb); - va_end (args); - } -} - -/* - * Преобразование вещественного числа в формат БЭСМ-6. - * - * Представление чисел в IEEE 754 (double): - * 64 63———53 52————–1 - * знак порядок мантисса - * Старший (53-й) бит мантиссы не хранится и всегда равен 1. - * - * Представление чисел в БЭСМ-6: - * 48——–42 41 40————————————————–1 - * порядок знак мантисса в доп. коде - */ -t_value ieee_to_besm6 (double d) -{ - t_value word; - int exponent; - int sign; - - sign = d < 0; - if (sign) - d = -d; - d = frexp (d, &exponent); - /* 0.5 <= d < 1.0 */ - d = ldexp (d, 40); - word = d; - if (d - word >= 0.5) - word += 1; /* Округление. */ - if (exponent < -64) - return 0LL; /* Близкое к нулю число */ - if (exponent > 63) { - return sign ? - 0xFEFFFFFFFFFFLL : /* Максимальное число */ - 0xFF0000000000LL; /* Минимальное число */ - } - if (sign) - word = 0x20000000000LL-word; /* Знак. */ - word |= ((t_value) (exponent + 64)) << 41; - return word; -} - -double besm6_to_ieee (t_value word) -{ - double mantissa; - - /* Убираем свертку */ - word &= BITS48; - - /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; - * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. - */ - mantissa = (t_int64) word << (64 - 48 + 7); - - int exponent = word >> 41; - - /* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */ - return ldexp (mantissa, exponent - 64 - 63); -} - -/* - * Пропуск пробелов. - */ -char *skip_spaces (char *p) -{ - for (;;) { - if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) { - /* Skip zero width no-break space. */ - p += 3; - continue; - } - if (*p == ' ' || *p == '\t') { - ++p; - continue; - } - return p; - } -} - -/* - * Fetch Unicode symbol from UTF-8 string. - * Advance string pointer. - */ -int utf8_to_unicode (char **p) -{ - int c1, c2, c3; - - c1 = (unsigned char) *(*p)++; - if (! (c1 & 0x80)) - return c1; - c2 = (unsigned char) *(*p)++; - if (! (c1 & 0x20)) - return (c1 & 0x1f) << 6 | (c2 & 0x3f); - c3 = (unsigned char) *(*p)++; - return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f); -} - -char *besm6_parse_octal (char *cptr, int *offset) -{ - char *eptr; - - *offset = strtol (cptr, &eptr, 8); - if (eptr == cptr) - return 0; - return eptr; -} - -static char *get_alnum (char *iptr, char *optr) -{ - while ((*iptr >= 'a' && *iptr<='z') || - (*iptr >= 'A' && *iptr<='Z') || - (*iptr >= '0' && *iptr<='9') || (*iptr & 0x80)) { - *optr++ = *iptr++; - } - *optr = 0; - return iptr; -} - -/* - * Parse single instruction (half word). - * Allow mnemonics or octal code. - */ -char *parse_instruction (char *cptr, uint32 *val) -{ - int opcode, reg, addr, negate; - char gbuf[CBUFSIZE]; - - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr >= '0' && *cptr <= '7') { - /* Восьмеричное представление. */ - cptr = besm6_parse_octal (cptr, ®); /* get register */ - if (! cptr || reg > 15) { - /*printf ("Bad register\n");*/ - return 0; - } - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr == '2' || *cptr == '3') { - /* Длинная команда. */ - cptr = besm6_parse_octal (cptr, &opcode); - if (! cptr || opcode < 020 || opcode > 037) { - /*printf ("Bad long opcode\n");*/ - return 0; - } - opcode <<= 3; - } else { - /* Короткая команда. */ - cptr = besm6_parse_octal (cptr, &opcode); - if (! cptr || opcode > 0177) { - /*printf ("Bad short opcode\n");*/ - return 0; - } - } - cptr = besm6_parse_octal (cptr, &addr); /* get address */ - if (! cptr || addr > BITS(15) || - (opcode <= 0177 && addr > BITS(12))) { - /*printf ("Bad address\n");*/ - return 0; - } - } else { - /* Мнемоническое представление команды. */ - cptr = get_alnum (cptr, gbuf); /* get opcode */ - opcode = besm6_opcode (gbuf); - if (opcode < 0) { - /*printf ("Bad opname: %s\n", gbuf);*/ - return 0; - } - negate = 0; - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr == '-') { /* negative offset */ - negate = 1; - cptr = skip_spaces (cptr + 1); /* absorb spaces */ - } - addr = 0; - if (*cptr >= '0' && *cptr <= '7') { - /* Восьмеричный адрес. */ - cptr = besm6_parse_octal (cptr, &addr); - if (! cptr || addr > BITS(15)) { - /*printf ("Bad address: %o\n", addr);*/ - return 0; - } - if (negate) - addr = (- addr) & BITS(15); - if (opcode <= 077 && addr > BITS(12)) { - if (addr < 070000) { - /*printf ("Bad short address: %o\n", addr);*/ - return 0; - } - opcode |= 0100; - addr &= BITS(12); - } - } - reg = 0; - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr == '(') { - /* Индекс-регистр в скобках. */ - cptr = besm6_parse_octal (cptr+1, ®); - if (! cptr || reg > 15) { - /*printf ("Bad register: %o\n", reg);*/ - return 0; - } - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr != ')') { - /*printf ("No closing brace\n");*/ - return 0; - } - ++cptr; - } - } - *val = reg << 20 | opcode << 12 | addr; - return cptr; -} - -/* - * Instruction parse: two commands per word. - */ -t_stat parse_instruction_word (char *cptr, t_value *val) -{ - uint32 left, right; - - *val = 0; - cptr = parse_instruction (cptr, &left); - if (! cptr) - return SCPE_ARG; - right = 0; - cptr = skip_spaces (cptr); - if (*cptr == ',') { - cptr = parse_instruction (cptr + 1, &right); - if (! cptr) - return SCPE_ARG; - } - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { - /*printf ("Extra symbols at eoln: %s\n", cptr);*/ - return SCPE_2MARG; - } - *val = (t_value) left << 24 | right; - return SCPE_OK; -} - -/* - * Печать машинной инструкции с мнемоникой. - */ -void besm6_fprint_cmd (FILE *of, uint32 cmd) -{ - int reg, opcode, addr; - - reg = (cmd >> 20) & 017; - if (cmd & BBIT(20)) { - opcode = (cmd >> 12) & 0370; - addr = cmd & BITS(15); - } else { - opcode = (cmd >> 12) & 077; - addr = cmd & 07777; - if (cmd & BBIT(19)) - addr |= 070000; - } - fprintf (of, "%s", besm6_opname (opcode)); - if (addr) { - fprintf (of, " "); - if (addr >= 077700) - fprintf (of, "-%o", (addr ^ 077777) + 1); - else - fprintf (of, "%o", addr); - } - if (reg) { - if (! addr) - fprintf (of, " "); - fprintf (of, "(%o)", reg); - } -} - -/* - * Печать машинной инструкции в восьмеричном виде. - */ -void besm6_fprint_insn (FILE *of, uint32 insn) -{ - if (insn & BBIT(20)) - fprintf (of, "%02o %02o %05o ", - insn >> 20, (insn >> 15) & 037, insn & BITS(15)); - else - fprintf (of, "%02o %03o %04o ", - insn >> 20, (insn >> 12) & 0177, insn & 07777); -} - -/* - * Symbolic decode - * - * Inputs: - * *of = output stream - * addr = current PC - * *val = pointer to data - * *uptr = pointer to unit - * sw = switches - * Outputs: - * return = status code - */ -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ - t_value cmd; - - if (uptr && (uptr != &cpu_unit)) /* must be CPU */ - return SCPE_ARG; - - cmd = val[0]; - - - if (sw & SWMASK ('M')) { /* symbolic decode? */ - if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR)) - fprintf (of, "-> "); - besm6_fprint_cmd (of, cmd >> 24); - if (sw & SIM_SW_STOP) /* stop point */ - fprintf (of, ", "); - else - fprintf (of, ",\n\t"); - if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR)) - fprintf (of, "-> "); - besm6_fprint_cmd (of, cmd & BITS(24)); - - } else if (sw & SWMASK ('I')) { - besm6_fprint_insn (of, (cmd >> 24) & BITS(24)); - besm6_fprint_insn (of, cmd & BITS(24)); - } else if (sw & SWMASK ('F')) { - fprintf (of, "%#.2g", besm6_to_ieee(cmd)); - } else if (sw & SWMASK ('B')) { - fprintf (of, "%03o %03o %03o %03o %03o %03o", - (int) (cmd >> 40) & 0377, - (int) (cmd >> 32) & 0377, - (int) (cmd >> 24) & 0377, - (int) (cmd >> 16) & 0377, - (int) (cmd >> 8) & 0377, - (int) cmd & 0377); - } else if (sw & SWMASK ('X')) { - fprintf (of, "%013llx", cmd); - } else - fprintf (of, "%04o %04o %04o %04o", - (int) (cmd >> 36) & 07777, - (int) (cmd >> 24) & 07777, - (int) (cmd >> 12) & 07777, - (int) cmd & 07777); - return SCPE_OK; -} - -/* - * Symbolic input - * - * Inputs: - * *cptr = pointer to input string - * addr = current PC - * *uptr = pointer to unit - * *val = pointer to output values - * sw = switches - * Outputs: - * status = error status - */ -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ - int32 i; - - if (uptr && (uptr != &cpu_unit)) /* must be CPU */ - return SCPE_ARG; - if (! parse_instruction_word (cptr, val)) /* symbolic parse? */ - return SCPE_OK; - - val[0] = 0; - for (i=0; i<16; i++) { - if (*cptr < '0' || *cptr > '7') - break; - val[0] = (val[0] << 3) | (*cptr - '0'); - cptr = skip_spaces (cptr+1); /* next char */ - } - if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { - /*printf ("Extra symbols at eoln: %s\n", cptr);*/ - return SCPE_2MARG; - } - return SCPE_OK; -} - -/* - * Чтение строки входного файла. - * Форматы строк: - * п 76543 - адрес пуска - * в 12345 - адрес ввода - * ч -123.45e+6 - вещественное число - * с 0123 4567 0123 4567 - восьмеричное слово - * к 00 22 00000 00 010 0000 - команды - */ -t_stat besm6_read_line (FILE *input, int *type, t_value *val) -{ - char buf [512], *p; - int i, c; -again: - if (! fgets (buf, sizeof (buf), input)) { - *type = 0; - return SCPE_OK; - } - p = skip_spaces (buf); - if (*p == '\n' || *p == ';') - goto again; - c = utf8_to_unicode (&p); - if (c == CYRILLIC_SMALL_LETTER_VE || - c == CYRILLIC_CAPITAL_LETTER_VE || - c == 'b' || c == 'B') { - /* Адрес размещения данных. */ - *type = ':'; - *val = strtol (p, 0, 8); - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_PE || - c == CYRILLIC_CAPITAL_LETTER_PE || - c == 'p' || c == 'P') { - /* Стартовый адрес. */ - *type = '@'; - *val = strtol (p, 0, 8); - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_CHE || - c == CYRILLIC_CAPITAL_LETTER_CHE || - c == 'f' || c == 'F') { - /* Вещественное число. */ - *type = '='; - *val = ieee_to_besm6 (strtod (p, 0)); - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_ES || - c == CYRILLIC_CAPITAL_LETTER_ES || - c == 'c' || c == 'C') { - /* Восьмеричное слово. */ - *type = '='; - *val = 0; - for (i=0; i<16; ++i) { - p = skip_spaces (p); - if (*p < '0' || *p > '7') { - if (i == 0) { - /* слишком короткое слово */ - goto bad; - } - break; - } - *val = *val << 3 | (*p++ - '0'); - } - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_KA || - c == CYRILLIC_CAPITAL_LETTER_KA || - c == 'k' || c == 'K') { - /* Команда. */ - *type = '*'; - if (parse_instruction_word (p, val) != SCPE_OK) - goto bad; - return SCPE_OK; - } - /* Неверная строка входного файла */ -bad: besm6_log ("Invalid input line: %s", buf); - return SCPE_FMT; -} - -/* - * Load memory from file. - */ -t_stat besm6_load (FILE *input) -{ - int addr, type; - t_value word; - t_stat err; - - addr = 1; - PC = 1; - for (;;) { - err = besm6_read_line (input, &type, &word); - if (err) - return err; - switch (type) { - case 0: /* EOF */ - return SCPE_OK; - case ':': /* address */ - addr = word; - break; - case '=': /* word */ - if (addr < 010) - pult [addr] = SET_CONVOL (word, CONVOL_NUMBER); - else - memory [addr] = SET_CONVOL (word, CONVOL_NUMBER); - ++addr; - break; - case '*': /* instruction */ - if (addr < 010) - pult [addr] = SET_CONVOL (word, CONVOL_INSN); - else - memory [addr] = SET_CONVOL (word, CONVOL_INSN); - ++addr; - break; - case '@': /* start address */ - PC = word; - break; - } - if (addr > MEMSIZE) - return SCPE_FMT; - } - return SCPE_OK; -} - -/* - * Dump memory to file. - */ -t_stat besm6_dump (FILE *of, char *fnam) -{ - int addr, last_addr = -1; - t_value word; - - fprintf (of, "; %s\n", fnam); - for (addr=1; addr> 24); - fprintf (of, ", "); - besm6_fprint_cmd (of, word & BITS(24)); - fprintf (of, "\t\t; %05o - ", addr); - fprintf (of, "%04o %04o %04o %04o\n", - (int) (word >> 36) & 07777, - (int) (word >> 24) & 07777, - (int) (word >> 12) & 07777, - (int) word & 07777); - } else { - fprintf (of, "с %04o %04o %04o %04o", - (int) (word >> 36) & 07777, - (int) (word >> 24) & 07777, - (int) (word >> 12) & 07777, - (int) word & 07777); - fprintf (of, "\t\t; %05o\n", addr); - } - } - return SCPE_OK; -} - -/* - * Loader/dumper - */ -t_stat sim_load (FILE *fi, char *cptr, char *fnam, int dump_flag) -{ - if (dump_flag) - return besm6_dump (fi, fnam); - - return besm6_load (fi); -} +/* + * besm6_sys.c: BESM-6 simulator interface + * + * Copyright (c) 2009, Serge Vakulenko + * Copyright (c) 2009, Leonid Broukhis + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your discretion) any later version. + * See the accompanying file "COPYING" for more details. + * + * This file implements three essential functions: + * + * sim_load() - loading and dumping memory and CPU state + * in a way, specific for BESM-6 architecture + * fprint_sym() - print a machune instruction using + * opcode mnemonic or in a digital format + * parse_sym() - scan a string and build an instruction + * word from it + */ +#include "besm6_defs.h" +#include +#include + +const char *opname_short_bemsh [64] = { + "зп", "зпм", "рег", "счм", "сл", "вч", "вчоб", "вчаб", + "сч", "и", "нтж", "слц", "знак", "или", "дел", "умн", + "сбр", "рзб", "чед", "нед", "слп", "вчп", "сд", "рж", + "счрж", "счмр", "э32", "увв", "слпа", "вчпа", "сда", "ржа", + "уи", "уим", "счи", "счим", "уии", "сли", "э46", "э47", + "э50", "э51", "э52", "э53", "э54", "э55", "э56", "э57", + "э60", "э61", "э62", "э63", "э64", "э65", "э66", "э67", + "э70", "э71", "э72", "э73", "э74", "э75", "э76", "э77", +}; + +static const char *opname_long_bemsh [16] = { + "э20", "э21", "мода", "мод", "уиа", "слиа", "по", "пе", + "пб", "пв", "выпр", "стоп", "пио", "пино", "э36", "цикл", +}; + +const char *opname_short_madlen [64] = { + "atx", "stx", "mod", "xts", "a+x", "a-x", "x-a", "amx", + "xta", "aax", "aex", "arx", "avx", "aox", "a/x", "a*x", + "apx", "aux", "acx", "anx", "e+x", "e-x", "asx", "xtr", + "rte", "yta", "*32", "ext", "e+n", "e-n", "asn", "ntr", + "ati", "sti", "ita", "its", "mtj", "j+m", "*46", "*47", + "*50", "*51", "*52", "*53", "*54", "*55", "*56", "*57", + "*60", "*61", "*62", "*63", "*64", "*65", "*66", "*67", + "*70", "*71", "*72", "*73", "*74", "*75", "*76", "*77", +}; + +static const char *opname_long_madlen [16] = { + "*20", "*21", "utc", "wtc", "vtm", "utm", "uza", "u1a", + "uj", "vjm", "ij", "stop", "vzm", "v1m", "*36", "vlm", +}; + +/* + * Выдача мнемоники по коду инструкции. + * Код должен быть в диапазоне 000..077 или 0200..0370. + */ +const char *besm6_opname (int opcode) +{ + if (sim_switches & SWMASK ('L')) { + /* Latin mnemonics. */ + if (opcode & 0200) + return opname_long_madlen [(opcode >> 3) & 017]; + return opname_short_madlen [opcode]; + } + if (opcode & 0200) + return opname_long_bemsh [(opcode >> 3) & 017]; + return opname_short_bemsh [opcode]; +}; + +/* + * Выдача кода инструкции по мнемонике (UTF-8). + */ +int besm6_opcode (char *instr) +{ + int i; + + for (i=0; i<64; ++i) + if (strcmp (opname_short_bemsh[i], instr) == 0 || + strcmp (opname_short_madlen[i], instr) == 0) + return i; + for (i=0; i<16; ++i) + if (strcmp (opname_long_bemsh[i], instr) == 0 || + strcmp (opname_long_madlen[i], instr) == 0) + return (i << 3) | 0200; + return -1; +} + +/* + * Выдача на консоль и в файл протокола. + * Если первый символ формата - подчерк, на консоль не печатаем. + * Добавляет перевод строки. + */ +void besm6_log (const char *fmt, ...) +{ + va_list args; + + if (*fmt == '_') + ++fmt; + else { + va_start (args, fmt); + vprintf (fmt, args); + printf ("\r\n"); + va_end (args); + } + if (sim_log) { + va_start (args, fmt); + vfprintf (sim_log, fmt, args); + if (sim_log == stdout) + fprintf (sim_log, "\r"); + fprintf (sim_log, "\n"); + fflush (sim_log); + va_end (args); + } +} + +/* + * Не добавляет перевод строки. + */ +void besm6_log_cont (const char *fmt, ...) +{ + va_list args; + + if (*fmt == '_') + ++fmt; + else { + va_start (args, fmt); + vprintf (fmt, args); + va_end (args); + } + if (sim_log) { + va_start (args, fmt); + vfprintf (sim_log, fmt, args); + fflush (sim_log); + va_end (args); + } +} + +/* + * Выдача на консоль и в файл отладки: если включён режим "cpu debug". + * Добавляет перевод строки. + */ +void besm6_debug (const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vprintf (fmt, args); + printf ("\r\n"); + va_end (args); + if (sim_deb && sim_deb != stdout) { + va_start (args, fmt); + vfprintf (sim_deb, fmt, args); + fprintf (sim_deb, "\n"); + fflush (sim_deb); + va_end (args); + } +} + +/* + * Преобразование вещественного числа в формат БЭСМ-6. + * + * Представление чисел в IEEE 754 (double): + * 64 63———53 52————–1 + * знак порядок мантисса + * Старший (53-й) бит мантиссы не хранится и всегда равен 1. + * + * Представление чисел в БЭСМ-6: + * 48——–42 41 40————————————————–1 + * порядок знак мантисса в доп. коде + */ +t_value ieee_to_besm6 (double d) +{ + t_value word; + int exponent; + int sign; + + sign = d < 0; + if (sign) + d = -d; + d = frexp (d, &exponent); + /* 0.5 <= d < 1.0 */ + d = ldexp (d, 40); + word = d; + if (d - word >= 0.5) + word += 1; /* Округление. */ + if (exponent < -64) + return 0LL; /* Близкое к нулю число */ + if (exponent > 63) { + return sign ? + 0xFEFFFFFFFFFFLL : /* Максимальное число */ + 0xFF0000000000LL; /* Минимальное число */ + } + if (sign) + word = 0x20000000000LL-word; /* Знак. */ + word |= ((t_value) (exponent + 64)) << 41; + return word; +} + +double besm6_to_ieee (t_value word) +{ + double mantissa; + + /* Убираем свертку */ + word &= BITS48; + + /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; + * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. + */ + mantissa = (t_int64) word << (64 - 48 + 7); + + int exponent = word >> 41; + + /* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */ + return ldexp (mantissa, exponent - 64 - 63); +} + +/* + * Пропуск пробелов. + */ +char *skip_spaces (char *p) +{ + for (;;) { + if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) { + /* Skip zero width no-break space. */ + p += 3; + continue; + } + if (*p == ' ' || *p == '\t' || *p == '\r') { + ++p; + continue; + } + return p; + } +} + +/* + * Fetch Unicode symbol from UTF-8 string. + * Advance string pointer. + */ +int utf8_to_unicode (char **p) +{ + int c1, c2, c3; + + c1 = (unsigned char) *(*p)++; + if (! (c1 & 0x80)) + return c1; + c2 = (unsigned char) *(*p)++; + if (! (c1 & 0x20)) + return (c1 & 0x1f) << 6 | (c2 & 0x3f); + c3 = (unsigned char) *(*p)++; + return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f); +} + +char *besm6_parse_octal (char *cptr, int *offset) +{ + char *eptr; + + *offset = strtol (cptr, &eptr, 8); + if (eptr == cptr) + return 0; + return eptr; +} + +static char *get_alnum (char *iptr, char *optr) +{ + while ((*iptr >= 'a' && *iptr<='z') || + (*iptr >= 'A' && *iptr<='Z') || + (*iptr >= '0' && *iptr<='9') || (*iptr & 0x80)) { + *optr++ = *iptr++; + } + *optr = 0; + return iptr; +} + +/* + * Parse single instruction (half word). + * Allow mnemonics or octal code. + */ +char *parse_instruction (char *cptr, uint32 *val) +{ + int opcode, reg, addr, negate; + char gbuf[CBUFSIZE]; + + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr >= '0' && *cptr <= '7') { + /* Восьмеричное представление. */ + cptr = besm6_parse_octal (cptr, ®); /* get register */ + if (! cptr || reg > 15) { + /*printf ("Bad register\n");*/ + return 0; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '2' || *cptr == '3') { + /* Длинная команда. */ + cptr = besm6_parse_octal (cptr, &opcode); + if (! cptr || opcode < 020 || opcode > 037) { + /*printf ("Bad long opcode\n");*/ + return 0; + } + opcode <<= 3; + } else { + /* Короткая команда. */ + cptr = besm6_parse_octal (cptr, &opcode); + if (! cptr || opcode > 0177) { + /*printf ("Bad short opcode\n");*/ + return 0; + } + } + cptr = besm6_parse_octal (cptr, &addr); /* get address */ + if (! cptr || addr > BITS(15) || + (opcode <= 0177 && addr > BITS(12))) { + /*printf ("Bad address\n");*/ + return 0; + } + } else { + /* Мнемоническое представление команды. */ + cptr = get_alnum (cptr, gbuf); /* get opcode */ + opcode = besm6_opcode (gbuf); + if (opcode < 0) { + /*printf ("Bad opname: %s\n", gbuf);*/ + return 0; + } + negate = 0; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '-') { /* negative offset */ + negate = 1; + cptr = skip_spaces (cptr + 1); /* absorb spaces */ + } + addr = 0; + if (*cptr >= '0' && *cptr <= '7') { + /* Восьмеричный адрес. */ + cptr = besm6_parse_octal (cptr, &addr); + if (! cptr || addr > BITS(15)) { + /*printf ("Bad address: %o\n", addr);*/ + return 0; + } + if (negate) + addr = (- addr) & BITS(15); + if (opcode <= 077 && addr > BITS(12)) { + if (addr < 070000) { + /*printf ("Bad short address: %o\n", addr);*/ + return 0; + } + opcode |= 0100; + addr &= BITS(12); + } + } + reg = 0; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '(') { + /* Индекс-регистр в скобках. */ + cptr = besm6_parse_octal (cptr+1, ®); + if (! cptr || reg > 15) { + /*printf ("Bad register: %o\n", reg);*/ + return 0; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr != ')') { + /*printf ("No closing brace\n");*/ + return 0; + } + ++cptr; + } + } + *val = reg << 20 | opcode << 12 | addr; + return cptr; +} + +/* + * Instruction parse: two commands per word. + */ +t_stat parse_instruction_word (char *cptr, t_value *val) +{ + uint32 left, right; + + *val = 0; + cptr = parse_instruction (cptr, &left); + if (! cptr) + return SCPE_ARG; + right = 0; + cptr = skip_spaces (cptr); + if (*cptr == ',') { + cptr = parse_instruction (cptr + 1, &right); + if (! cptr) + return SCPE_ARG; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { + /*printf ("Extra symbols at eoln: %s\n", cptr);*/ + return SCPE_2MARG; + } + *val = (t_value) left << 24 | right; + return SCPE_OK; +} + +/* + * Печать машинной инструкции с мнемоникой. + */ +void besm6_fprint_cmd (FILE *of, uint32 cmd) +{ + int reg, opcode, addr; + + reg = (cmd >> 20) & 017; + if (cmd & BBIT(20)) { + opcode = (cmd >> 12) & 0370; + addr = cmd & BITS(15); + } else { + opcode = (cmd >> 12) & 077; + addr = cmd & 07777; + if (cmd & BBIT(19)) + addr |= 070000; + } + fprintf (of, "%s", besm6_opname (opcode)); + if (addr) { + fprintf (of, " "); + if (addr >= 077700) + fprintf (of, "-%o", (addr ^ 077777) + 1); + else + fprintf (of, "%o", addr); + } + if (reg) { + if (! addr) + fprintf (of, " "); + fprintf (of, "(%o)", reg); + } +} + +/* + * Печать машинной инструкции в восьмеричном виде. + */ +void besm6_fprint_insn (FILE *of, uint32 insn) +{ + if (insn & BBIT(20)) + fprintf (of, "%02o %02o %05o ", + insn >> 20, (insn >> 15) & 037, insn & BITS(15)); + else + fprintf (of, "%02o %03o %04o ", + insn >> 20, (insn >> 12) & 0177, insn & 07777); +} + +/* + * Symbolic decode + * + * Inputs: + * *of = output stream + * addr = current PC + * *val = pointer to data + * *uptr = pointer to unit + * sw = switches + * Outputs: + * return = status code + */ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + t_value cmd; + + if (uptr && (uptr != &cpu_unit)) /* must be CPU */ + return SCPE_ARG; + + cmd = val[0]; + + + if (sw & SWMASK ('M')) { /* symbolic decode? */ + if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR)) + fprintf (of, "-> "); + besm6_fprint_cmd (of, cmd >> 24); + if (sw & SIM_SW_STOP) /* stop point */ + fprintf (of, ", "); + else + fprintf (of, ",\n\t"); + if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR)) + fprintf (of, "-> "); + besm6_fprint_cmd (of, cmd & BITS(24)); + + } else if (sw & SWMASK ('I')) { + besm6_fprint_insn (of, (cmd >> 24) & BITS(24)); + besm6_fprint_insn (of, cmd & BITS(24)); + } else if (sw & SWMASK ('F')) { + fprintf (of, "%#.2g", besm6_to_ieee(cmd)); + } else if (sw & SWMASK ('B')) { + fprintf (of, "%03o %03o %03o %03o %03o %03o", + (int) (cmd >> 40) & 0377, + (int) (cmd >> 32) & 0377, + (int) (cmd >> 24) & 0377, + (int) (cmd >> 16) & 0377, + (int) (cmd >> 8) & 0377, + (int) cmd & 0377); + } else if (sw & SWMASK ('X')) { + fprintf (of, "%013llx", cmd); + } else + fprintf (of, "%04o %04o %04o %04o", + (int) (cmd >> 36) & 07777, + (int) (cmd >> 24) & 07777, + (int) (cmd >> 12) & 07777, + (int) cmd & 07777); + return SCPE_OK; +} + +/* + * Symbolic input + * + * Inputs: + * *cptr = pointer to input string + * addr = current PC + * *uptr = pointer to unit + * *val = pointer to output values + * sw = switches + * Outputs: + * status = error status + */ +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + int32 i; + + if (uptr && (uptr != &cpu_unit)) /* must be CPU */ + return SCPE_ARG; + if (! parse_instruction_word (cptr, val)) /* symbolic parse? */ + return SCPE_OK; + + val[0] = 0; + for (i=0; i<16; i++) { + if (*cptr < '0' || *cptr > '7') + break; + val[0] = (val[0] << 3) | (*cptr - '0'); + cptr = skip_spaces (cptr+1); /* next char */ + } + if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { + /*printf ("Extra symbols at eoln: %s\n", cptr);*/ + return SCPE_2MARG; + } + return SCPE_OK; +} + +/* + * Чтение строки входного файла. + * Форматы строк: + * п 76543 - адрес пуска + * в 12345 - адрес ввода + * ч -123.45e+6 - вещественное число + * с 0123 4567 0123 4567 - восьмеричное слово + * к 00 22 00000 00 010 0000 - команды + */ +t_stat besm6_read_line (FILE *input, int *type, t_value *val) +{ + char buf [512], *p; + int i, c; +again: + if (! fgets (buf, sizeof (buf), input)) { + *type = 0; + return SCPE_OK; + } + p = skip_spaces (buf); + if (*p == '\n' || *p == ';') + goto again; + c = utf8_to_unicode (&p); + if (c == CYRILLIC_SMALL_LETTER_VE || + c == CYRILLIC_CAPITAL_LETTER_VE || + c == 'b' || c == 'B') { + /* Адрес размещения данных. */ + *type = ':'; + *val = strtol (p, 0, 8); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_PE || + c == CYRILLIC_CAPITAL_LETTER_PE || + c == 'p' || c == 'P') { + /* Стартовый адрес. */ + *type = '@'; + *val = strtol (p, 0, 8); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_CHE || + c == CYRILLIC_CAPITAL_LETTER_CHE || + c == 'f' || c == 'F') { + /* Вещественное число. */ + *type = '='; + *val = ieee_to_besm6 (strtod (p, 0)); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_ES || + c == CYRILLIC_CAPITAL_LETTER_ES || + c == 'c' || c == 'C') { + /* Восьмеричное слово. */ + *type = '='; + *val = 0; + for (i=0; i<16; ++i) { + p = skip_spaces (p); + if (*p < '0' || *p > '7') { + if (i == 0) { + /* слишком короткое слово */ + goto bad; + } + break; + } + *val = *val << 3 | (*p++ - '0'); + } + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_KA || + c == CYRILLIC_CAPITAL_LETTER_KA || + c == 'k' || c == 'K') { + /* Команда. */ + *type = '*'; + if (parse_instruction_word (p, val) != SCPE_OK) + goto bad; + return SCPE_OK; + } + /* Неверная строка входного файла */ +bad: besm6_log ("Invalid input line: %s", buf); + return SCPE_FMT; +} + +/* + * Load memory from file. + */ +t_stat besm6_load (FILE *input) +{ + int addr, type; + t_value word; + t_stat err; + + addr = 1; + PC = 1; + for (;;) { + err = besm6_read_line (input, &type, &word); + if (err) + return err; + switch (type) { + case 0: /* EOF */ + return SCPE_OK; + case ':': /* address */ + addr = word; + break; + case '=': /* word */ + if (addr < 010) + pult [addr] = SET_CONVOL (word, CONVOL_NUMBER); + else + memory [addr] = SET_CONVOL (word, CONVOL_NUMBER); + ++addr; + break; + case '*': /* instruction */ + if (addr < 010) + pult [addr] = SET_CONVOL (word, CONVOL_INSN); + else + memory [addr] = SET_CONVOL (word, CONVOL_INSN); + ++addr; + break; + case '@': /* start address */ + PC = word; + break; + } + if (addr > MEMSIZE) + return SCPE_FMT; + } + return SCPE_OK; +} + +/* + * Dump memory to file. + */ +t_stat besm6_dump (FILE *of, char *fnam) +{ + int addr, last_addr = -1; + t_value word; + + fprintf (of, "; %s\n", fnam); + for (addr=1; addr> 24); + fprintf (of, ", "); + besm6_fprint_cmd (of, word & BITS(24)); + fprintf (of, "\t\t; %05o - ", addr); + fprintf (of, "%04o %04o %04o %04o\n", + (int) (word >> 36) & 07777, + (int) (word >> 24) & 07777, + (int) (word >> 12) & 07777, + (int) word & 07777); + } else { + fprintf (of, "с %04o %04o %04o %04o", + (int) (word >> 36) & 07777, + (int) (word >> 24) & 07777, + (int) (word >> 12) & 07777, + (int) word & 07777); + fprintf (of, "\t\t; %05o\n", addr); + } + } + return SCPE_OK; +} + +/* + * Loader/dumper + */ +t_stat sim_load (FILE *fi, char *cptr, char *fnam, int dump_flag) +{ + if (dump_flag) + return besm6_dump (fi, fnam); + + return besm6_load (fi); +} diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 489de9b0..9d37e23f 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -1,1243 +1,1243 @@ -/* - * besm6_tty.c: BESM-6 teletype device - * - * Copyright (c) 2009, Leo Broukhis - * Copyright (c) 2009, Serge Vakulenko - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You can redistribute this program and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation; - * either version 2 of the License, or (at your discretion) any later version. - * See the accompanying file "COPYING" for more details. - */ - -#include "besm6_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" -#include - -#define TTY_MAX 24 /* Количество последовательных терминалов */ -#define LINES_MAX TTY_MAX + 2 /* Включая параллельные интерфейсы "Консулов" */ -/* - * Согласно таблице в http://ru.wikipedia.org/wiki/МТК-2 - */ -char * rus[] = { 0, "Т", "\r", "О", " ", "Х", "Н", "М", "\n", "Л", "Р", "Г", "И", "П", "Ц", "Ж", - "Е", "З", "Д", "Б", "С", "Ы", "Ф", "Ь", "А", "В", "Й", 0, "У", "Я", "К", 0 }; - -char * lat[] = { 0, "T", "\r", "O", " ", "H", "N", "M", "\n", "L", "R", "G", "I", "P", "C", "V", - "E", "Z", "D", "B", "S", "Y", "F", "X", "A", "W", "J", 0, "U", "Q", "K", 0 }; - -/* $ = Кто там? */ -char * dig[] = { 0, "5", "\r", "9", " ", "Щ", ",", ".", "\n", ")", "4", "Ш", "8", "0", ":", "=", - "3", "+", "$", "?", "'", "6", "Э", "/", "-", "2", "Ю", 0, "7", "1", "(", 0 }; - -char ** reg = 0; - -char * process (int sym) -{ - /* Требуется инверсия */ - sym ^= 31; - switch (sym) { - case 0: - reg = rus; - break; - case 27: - reg = dig; - break; - case 31: - reg = lat; - break; - default: - return reg[sym]; - } - return ""; -} - -/* Только для последовательных линий */ -int tty_active [TTY_MAX+1], tty_sym [TTY_MAX+1]; -int tty_typed [TTY_MAX+1], tty_instate [TTY_MAX+1]; -time_t tty_last_time [TTY_MAX+1]; -int tty_idle_count [TTY_MAX+1]; - -uint32 vt_sending, vt_receiving; -uint32 tt_sending, tt_receiving; - -// Attachments survive the reset -uint32 tt_mask = 0, vt_mask = 0; - -uint32 TTY_OUT = 0, TTY_IN = 0, vt_idle = 0; -uint32 CONSUL_IN[2]; - -uint32 CONS_CAN_PRINT[2] = { 01000, 00400 }; -uint32 CONS_HAS_INPUT[2] = { 04000, 02000 }; - -/* Буфера командных строк для режима telnet. */ -char vt_cbuf [CBUFSIZE] [LINES_MAX+1]; -char *vt_cptr [LINES_MAX+1]; - -void tt_print(); -void consul_receive(); -t_stat vt_clk(UNIT *); -extern char *get_sim_sw (char *cptr); - -UNIT tty_unit [] = { - { UDATA (vt_clk, UNIT_DIS, 0) }, /* fake unit, clock */ - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - /* The next two units are parallel interface */ - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { 0 } -}; - -REG tty_reg[] = { - { 0 } -}; - -/* - * Дескрипторы линий для мультиплексора TMXR. - * Поле .conn содержит номер сокета и означает занятую линию. - * Для локальных терминалов делаем .conn = 1. - * Чтобы нумерация линий совпадала с нумерацией терминалов - * (с единицы), нулевую линию держим занятой (.conn = 1). - * Поле .rcve устанавливается в 1 для сетевых соединений. - * Для локальных терминалов оно равно 0. - */ -TMLN tty_line [LINES_MAX+1]; -TMXR tty_desc = { LINES_MAX+1, 0, 0, tty_line }; /* mux descriptor */ - -#define TTY_UNICODE_CHARSET 0 -#define TTY_KOI7_JCUKEN_CHARSET (1<>= 1)) { - tt_print(); - /* Прием не реализован */ - clk_divider = 1<<29; - } - - /* Есть новые сетевые подключения? */ - int num = tmxr_poll_conn (&tty_desc); - if (num > 0 && num <= LINES_MAX) { - char buf [80]; - TMLN *t = &tty_line [num]; - besm6_debug ("*** tty%d: новое подключение от %s", - num, t->ipad); - t->rcve = 1; - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_VT340_STATE; - if (num <= TTY_MAX) - vt_mask |= 1 << (TTY_MAX - num); - - switch (tty_unit[num].flags & TTY_CHARSET_MASK) { - case TTY_KOI7_JCUKEN_CHARSET: - tmxr_linemsg (t, "Encoding is KOI-7 (jcuken)\r\n"); - break; - case TTY_KOI7_QWERTY_CHARSET: - tmxr_linemsg (t, "Encoding is KOI-7 (qwerty)\r\n"); - break; - case TTY_UNICODE_CHARSET: - tmxr_linemsg (t, "Encoding is UTF-8\r\n"); - break; - } - tty_idle_count[num] = 0; - tty_last_time[num] = time (0); - sprintf (buf, "%.24s from %s\r\n", - ctime (&tty_last_time[num]), - t->ipad); - tmxr_linemsg (t, buf); - - /* Ввод ^C, чтобы получить приглашение. */ - t->rxb [t->rxbpi++] = '\3'; - } - - /* Опрашиваем сокеты на передачу. */ - tmxr_poll_tx (&tty_desc); - - return sim_activate (this, 1000*MSEC/300); -} - -t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) -{ - int num = u - tty_unit; - TMLN *t = &tty_line [num]; - uint32 mask = 1 << (TTY_MAX - num); - - switch (val & TTY_STATE_MASK) { - case TTY_OFFLINE_STATE: - if (t->conn) { - if (t->rcve) { - tmxr_reset_ln (t); - t->rcve = 0; - } else - t->conn = 0; - if (num <= TTY_MAX) { - tty_sym[num] = - tty_active[num] = - tty_typed[num] = - tty_instate[num] = 0; - vt_mask &= ~mask; - tt_mask &= ~mask; - } - } - break; - case TTY_TELETYPE_STATE: - if (num > TTY_MAX) - return SCPE_NXPAR; - t->conn = 1; - t->rcve = 0; - tt_mask |= mask; - vt_mask &= ~mask; - break; - case TTY_VT340_STATE: - t->conn = 1; - t->rcve = 0; - if (num <= TTY_MAX) { - vt_mask |= mask; - tt_mask &= ~mask; - } - break; - case TTY_CONSUL_STATE: - if (num <= TTY_MAX) - return SCPE_NXPAR; - t->conn = 1; - t->rcve = 0; - break; - } - return SCPE_OK; -} - -/* - * Разрешение подключения к терминалам через telnet. - * Делается командой: - * attach tty <порт> - * Здесь <порт> - номер порта telnet, например 4199. - */ -t_stat tty_attach (UNIT *u, char *cptr) -{ - int num = u - tty_unit; - int r, m, n; - - if (*cptr >= '0' && *cptr <= '9') { - /* Сохраняем и восстанавливаем все .conn, - * так как tmxr_attach() их обнуляет. */ - for (m=0, n=1; n<=LINES_MAX; ++n) - if (tty_line[n].conn) - m |= 1 << (LINES_MAX-n); - /* Неважно, какой номер порта указывать в команде задания - * порта telnet. Можно tty, можно tty1 - без разницы. */ - r = tmxr_attach (&tty_desc, &tty_unit[0], cptr); - for (n=1; n<=LINES_MAX; ++n) - if (m >> (LINES_MAX-n) & 1) - tty_line[n].conn = 1; - return r; - } - if (strcmp (cptr, "/dev/tty") == 0) { - /* Консоль. */ - u->flags &= ~TTY_STATE_MASK; - u->flags |= TTY_VT340_STATE; - tty_line[num].conn = 1; - tty_line[num].rcve = 0; - if (num <= TTY_MAX) - vt_mask |= 1 << (TTY_MAX - num); - besm6_debug ("*** консоль на T%03o", num); - return 0; - } - if (strcmp (cptr, "/dev/null") == 0) { - /* Запрещаем терминал. */ - tty_line[num].conn = 1; - tty_line[num].rcve = 0; - if (num <= TTY_MAX) { - vt_mask &= ~(1 << (TTY_MAX - num)); - tt_mask &= ~(1 << (TTY_MAX - num)); - } - besm6_debug ("*** отключение терминала T%03o", num); - return 0; - } - return SCPE_ALATT; -} - -t_stat tty_detach (UNIT *u) -{ - return tmxr_detach (&tty_desc, &tty_unit[0]); -} - -/* - * Управление терминалами. - * set ttyN unicode - выбор кодировки UTF-8 - * set ttyN jcuken - выбор кодировки КОИ-7, раскладка йцукен - * set ttyN qwerty - выбор кодировки КОИ-7, раскладка яверты - * set ttyN off - отключение - * set ttyN tt - установка типа терминала "Телетайп" - * set ttyN vt - установка типа терминала "Видеотон-340" - * set ttyN consul - установка типа терминала "Consul-254" - * set ttyN destrbs - "стирающий" backspace - * set ttyN authbs - классический backspace - * set tty disconnect=N - принудительное завершение сеанса telnet - * show tty - просмотр режимов терминалов - * show tty connections - просмотр IP-адресов и времени соединений - * show tty statistics - просмотр счетчиков переданных и принятых байтов - */ -MTAB tty_mod[] = { - { TTY_CHARSET_MASK, TTY_UNICODE_CHARSET, "UTF-8 input", - "UNICODE" }, - { TTY_CHARSET_MASK, TTY_KOI7_JCUKEN_CHARSET, "KOI7 (jcuken) input", - "JCUKEN" }, - { TTY_CHARSET_MASK, TTY_KOI7_QWERTY_CHARSET, "KOI7 (qwerty) input", - "QWERTY" }, - { TTY_STATE_MASK, TTY_OFFLINE_STATE, "offline", - "OFF", &tty_setmode }, - { TTY_STATE_MASK, TTY_TELETYPE_STATE, "Teletype", - "TT", &tty_setmode }, - { TTY_STATE_MASK, TTY_VT340_STATE, "Videoton-340", - "VT", &tty_setmode }, - { TTY_STATE_MASK, TTY_CONSUL_STATE, "Consul-254", - "CONSUL", &tty_setmode }, - { TTY_BSPACE_MASK, TTY_DESTRUCTIVE_BSPACE, "destructive backspace", - "DESTRBS" }, - { TTY_BSPACE_MASK, TTY_AUTHENTIC_BSPACE, NULL, - "AUTHBS" }, - { MTAB_XTD | MTAB_VDV, 1, NULL, - "DISCONNECT", &tmxr_dscln, NULL, (void*) &tty_desc }, - { UNIT_ATT, UNIT_ATT, "connections", - NULL, NULL, &tmxr_show_summ, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", - NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", - NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, - "LOG", &tmxr_set_log, &tmxr_show_log, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, - "NOLOG", &tmxr_set_nolog, NULL, (void*) &tty_desc }, - { 0 } -}; - -DEVICE tty_dev = { - "TTY", tty_unit, tty_reg, tty_mod, - 27, 2, 1, 1, 2, 1, - NULL, NULL, &tty_reset, NULL, &tty_attach, &tty_detach, - NULL, DEV_NET|DEV_DEBUG -}; - -void tty_send (uint32 mask) -{ - /* besm6_debug ("*** телетайпы: передача %08o", mask); */ - - TTY_OUT = mask; -} - -/* - * Выдача символа на терминал с указанным номером. - */ -void vt_putc (int num, int c) -{ - TMLN *t = &tty_line [num]; - - if (! t->conn) - return; - if (t->rcve) { - /* Передача через telnet. */ - tmxr_putc_ln (t, c); - } else { - /* Вывод на консоль. */ - if (t->txlog) { /* log if available */ - fputc (c, t->txlog); - if (c == '\n') - fflush (t->txlog); - } - fputc (c, stdout); - fflush (stdout); - } -} - -/* - * Выдача строки на терминал с указанным номером. - */ -void vt_puts (int num, const char *s) -{ - TMLN *t = &tty_line [num]; - - if (! t->conn) - return; - if (t->rcve) { - /* Передача через telnet. */ - tmxr_linemsg (t, (char*) s); - } else { - /* Вывод на консоль. */ - if (t->txlog) /* log if available */ - fputs (s, t->txlog); - fputs (s, stdout); - fflush (stdout); - } -} - -const char * koi7_rus_to_unicode [32] = { - "Ю", "А", "Б", "Ц", "Д", "Е", "Ф", "Г", - "Х", "И", "Й", "К", "Л", "М", "Н", "О", - "П", "Я", "Р", "С", "Т", "У", "Ж", "В", - "Ь", "Ы", "З", "Ш", "Э", "Щ", "Ч", "\0x7f", -}; - -void vt_send(int num, uint32 sym, int destructive_bs) -{ - if (sym < 0x60) { - switch (sym) { - case '\031': - /* Up */ - vt_puts (num, "\033["); - sym = 'A'; - break; - case '\032': - /* Down */ - vt_puts (num, "\033["); - sym = 'B'; - break; - case '\030': - /* Right */ - vt_puts (num, "\033["); - sym = 'C'; - break; - case '\b': - /* Left */ - vt_puts (num, "\033["); - if (destructive_bs) { - /* Стираем предыдущий символ. */ - vt_puts (num, "D \033["); - } - sym = 'D'; - break; - case '\v': - case '\033': - case '\0': - /* Выдаём управляющий символ. */ - break; - case '\037': - /* Очистка экрана */ - vt_puts (num, "\033[H\033["); - sym = 'J'; - break; - case '\n': - /* На VDT-340 также возвращал курсор в 1-ю позицию */ - vt_putc (num, '\r'); - sym = '\n'; - break; - case '\f': - /* Сообщение ERR при нажатии некоторых управляющих - * клавиш выдается с использованием reverse wraparound. - */ - vt_puts(num, "\033["); - sym = 'H'; - break; - case '\r': - case '\003': - /* Неотображаемые символы */ - sym = 0; - break; - default: - if (sym < ' ') { - /* Нефункциональные ctrl-символы были видны в половинной яркости */ - vt_puts (num, "\033[2m"); - vt_putc (num, sym | 0x40); - vt_puts (num, "\033["); - /* Завершаем ESC-последовательность */ - sym = 'm'; - } - } - if (sym) - vt_putc (num, sym); - } else - vt_puts (num, koi7_rus_to_unicode[sym - 0x60]); -} - -/* - * Обработка выдачи на все подключенные терминалы. - */ -void vt_print() -{ - uint32 workset = (TTY_OUT & vt_mask) | vt_sending; - int num; - - if (workset == 0) { - ++vt_idle; - return; - } - for (num = besm6_highest_bit (workset) - TTY_MAX; - workset; num = besm6_highest_bit (workset) - TTY_MAX) { - int mask = 1 << (TTY_MAX - num); - int c = (TTY_OUT & mask) != 0; - switch (tty_active[num]*2+c) { - case 0: /* idle */ - besm6_debug ("Warning: inactive ttys should have been screened"); - continue; - case 1: /* start bit */ - vt_sending |= mask; - tty_active[num] = 1; - break; - case 18: /* stop bit */ - tty_sym[num] = ~tty_sym[num] & 0x7f; - vt_send (num, tty_sym[num], - (tty_unit[num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); - tty_active[num] = 0; - tty_sym[num] = 0; - vt_sending &= ~mask; - break; - case 19: /* framing error */ - vt_putc (num, '#'); - break; - default: - /* little endian ordering */ - if (c) { - tty_sym[num] |= 1 << (tty_active[num]-1); - } - ++tty_active[num]; - break; - } - workset &= ~mask; - } - vt_idle = 0; -} - -/* Ввод с телетайпа не реализован; вывод работает только при использовании - * модельного времени. - */ -void tt_print() -{ - uint32 workset = (TTY_OUT & tt_mask) | tt_sending; - int num; - - if (workset == 0) { - return; - } - - for (num = besm6_highest_bit (workset) - TTY_MAX; - workset; num = besm6_highest_bit (workset) - TTY_MAX) { - int mask = 1 << (TTY_MAX - num); - int c = (TTY_OUT & mask) != 0; - switch (tty_active[num]*2+c) { - case 0: /* idle */ - break; - case 1: /* start bit */ - tt_sending |= mask; - tty_active[num] = 1; - break; - case 12: /* stop bit */ - vt_puts (num, process (tty_sym[num])); - tty_active[num] = 0; - tty_sym[num] = 0; - tt_sending &= ~mask; - break; - case 13: /* framing error */ - vt_putc (num, '#'); - break; - default: - /* big endian ordering */ - if (c) { - tty_sym[num] |= 1 << (5-tty_active[num]); - } - ++tty_active[num]; - break; - } - workset &= ~mask; - } - vt_idle = 0; -} - -/* - * Перекодировка из Unicode в КОИ-7. - * Если нет соответствия, возвращает -1. - */ -static int unicode_to_koi7 (unsigned val) -{ - switch (val) { - case '\0'... '_': return val; - case 'a' ... 'z': return val + 'Z' - 'z'; - case 0x007f: return 0x7f; - case 0x0410: case 0x0430: return 0x61; - case 0x0411: case 0x0431: return 0x62; - case 0x0412: case 0x0432: return 0x77; - case 0x0413: case 0x0433: return 0x67; - case 0x0414: case 0x0434: return 0x64; - case 0x0415: case 0x0435: return 0x65; - case 0x0416: case 0x0436: return 0x76; - case 0x0417: case 0x0437: return 0x7a; - case 0x0418: case 0x0438: return 0x69; - case 0x0419: case 0x0439: return 0x6a; - case 0x041a: case 0x043a: return 0x6b; - case 0x041b: case 0x043b: return 0x6c; - case 0x041c: case 0x043c: return 0x6d; - case 0x041d: case 0x043d: return 0x6e; - case 0x041e: case 0x043e: return 0x6f; - case 0x041f: case 0x043f: return 0x70; - case 0x0420: case 0x0440: return 0x72; - case 0x0421: case 0x0441: return 0x73; - case 0x0422: case 0x0442: return 0x74; - case 0x0423: case 0x0443: return 0x75; - case 0x0424: case 0x0444: return 0x66; - case 0x0425: case 0x0445: return 0x68; - case 0x0426: case 0x0446: return 0x63; - case 0x0427: case 0x0447: return 0x7e; - case 0x0428: case 0x0448: return 0x7b; - case 0x0429: case 0x0449: return 0x7d; - case 0x042b: case 0x044b: return 0x79; - case 0x042c: case 0x044c: return 0x78; - case 0x042d: case 0x044d: return 0x7c; - case 0x042e: case 0x044e: return 0x60; - case 0x042f: case 0x044f: return 0x71; - } - return -1; -} - -/* - * Set command - */ -static t_stat cmd_set (int32 num, char *cptr) -{ - char gbuf [CBUFSIZE]; - int len; - - cptr = get_sim_sw (cptr); - if (! cptr) - return SCPE_INVSW; - if (! *cptr) - return SCPE_NOPARAM; - cptr = get_glyph (cptr, gbuf, 0); - if (*cptr) - return SCPE_2MARG; - - len = strlen (gbuf); - if (strncmp ("UNICODE", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_CHARSET_MASK; - tty_unit[num].flags |= TTY_UNICODE_CHARSET; - } else if (strncmp ("JCUKEN", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_CHARSET_MASK; - tty_unit[num].flags |= TTY_KOI7_JCUKEN_CHARSET; - } else if (strncmp ("QWERTY", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_CHARSET_MASK; - tty_unit[num].flags |= TTY_KOI7_QWERTY_CHARSET; - } else if (strncmp ("TT", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_TELETYPE_STATE; - } else if (strncmp ("VT", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_VT340_STATE; - } else if (strncmp ("CONSUL", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_CONSUL_STATE; - } else if (strncmp ("DESTRBS", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_BSPACE_MASK; - tty_unit[num].flags |= TTY_DESTRUCTIVE_BSPACE; - } else if (strncmp ("AUTHBS", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_BSPACE_MASK; - tty_unit[num].flags |= TTY_AUTHENTIC_BSPACE; - } else { - return SCPE_NXPAR; - } - return SCPE_OK; -} - -/* - * Show command - */ -static t_stat cmd_show (int32 num, char *cptr) -{ - TMLN *t = &tty_line [num]; - char gbuf [CBUFSIZE]; - MTAB *m; - int len; - - cptr = get_sim_sw (cptr); - if (! cptr) - return SCPE_INVSW; - if (! *cptr) { - sprintf (gbuf, "TTY%d", num); - tmxr_linemsg (t, gbuf); - for (m=tty_mod; m->mask; m++) { - if (m->pstring && - (tty_unit[num].flags & m->mask) == m->match) { - tmxr_linemsg (t, ", "); - tmxr_linemsg (t, m->pstring); - } - } - if (t->txlog) - tmxr_linemsg (t, ", log"); - tmxr_linemsg (t, "\r\n"); - return SCPE_OK; - } - cptr = get_glyph (cptr, gbuf, 0); - if (*cptr) - return SCPE_2MARG; - - len = strlen (gbuf); - if (strncmp ("STATISTICS", gbuf, len) == 0) { - sprintf (gbuf, "line %d: input queued/total = %d/%d, " - "output queued/total = %d/%d\r\n", num, - t->rxbpi - t->rxbpr, t->rxcnt, - t->txbpi - t->txbpr, t->txcnt); - tmxr_linemsg (t, gbuf); - } else { - return SCPE_NXPAR; - } - return SCPE_OK; -} - -/* - * Exit command - */ -static t_stat cmd_exit (int32 num, char *cptr) -{ - return SCPE_EXIT; -} - -static t_stat cmd_help (int32 num, char *cptr); - -static CTAB cmd_table[] = { - { "SET", &cmd_set, 0, - "set unicode select UTF-8 encoding\r\n" - "set jcuken select KOI7 encoding, 'jcuken' keymap\r\n" - "set qwerty select KOI7 encoding, 'qwerty' keymap\r\n" - "set tt use Teletype mode\r\n" - "set vt use Videoton-340 mode\r\n" - "set consul use Consul-254 mode\r\n" - "set destrbs destructive backspace\r\n" - "set authbs authentic backspace\r\n" - }, - { "SHOW", &cmd_show, 0, - "sh{ow} show modes of the terminal\r\n" - "sh{ow} s{tatistics} show network statistics\r\n" - }, - { "EXIT", &cmd_exit, 0, - "exi{t} | q{uit} | by{e} exit from simulation\r\n" - }, - { "QUIT", &cmd_exit, 0, NULL - }, - { "BYE", &cmd_exit, 0, NULL - }, - { "HELP", &cmd_help, 0, - "h{elp} type this message\r\n" - "h{elp} type help for command\r\n" - }, - { 0 } -}; - -/* - * Find command routine - */ -static CTAB *lookup_cmd (char *command) -{ - CTAB *c; - int len; - - len = strlen (command); - for (c=cmd_table; c->name; c++) { - if (strncmp (command, c->name, len) == 0) - return c; - } - return 0; -} - -/* - * Help command - */ -static t_stat cmd_help (int32 num, char *cptr) -{ - TMLN *t = &tty_line [num]; - char gbuf [CBUFSIZE]; - CTAB *c; - - cptr = get_sim_sw (cptr); - if (! cptr) - return SCPE_INVSW; - if (! *cptr) { - /* Список всех команд. */ - tmxr_linemsg (t, "Commands may be abbreviated. Commands are:\r\n\r\n"); - for (c=cmd_table; c && c->name; c++) - if (c->help) - tmxr_linemsg (t, c->help); - return SCPE_OK; - } - cptr = get_glyph (cptr, gbuf, 0); - if (*cptr) - return SCPE_2MARG; - c = lookup_cmd (gbuf); - if (! c) - return SCPE_ARG; - /* Описание конкретной команды. */ - tmxr_linemsg (t, c->help); - return SCPE_OK; -} - -/* - * Выполнение командной строки. - */ -void vt_cmd_exec (int num) -{ - TMLN *t = &tty_line [num]; - char *cptr, gbuf [CBUFSIZE]; - CTAB *cmdp; - t_stat err; - extern char *scp_errors[]; - - cptr = get_glyph (vt_cbuf [num], gbuf, 0); /* get command glyph */ - cmdp = lookup_cmd (gbuf); /* lookup command */ - if (! cmdp) { - tmxr_linemsg (t, scp_errors[SCPE_UNK - SCPE_BASE]); - tmxr_linemsg (t, "\r\n"); - return; - } - err = cmdp->action (num, cptr); /* if found, exec */ - if (err >= SCPE_BASE) { /* error? */ - tmxr_linemsg (t, scp_errors [err - SCPE_BASE]); - tmxr_linemsg (t, "\r\n"); - } - if (err == SCPE_EXIT) { /* close telnet session */ - tmxr_reset_ln (t); - } -} - -/* - * Режим управляющей командной строки. - */ -void vt_cmd_loop (int num, int c) -{ - TMLN *t = &tty_line [num]; - char *cbuf, **cptr; - - cbuf = vt_cbuf [num]; - cptr = &vt_cptr [num]; - - switch (c) { - case '\r': - case '\n': - tmxr_linemsg (t, "\r\n"); - if (*cptr <= cbuf) { - /* Пустая строка - возврат в обычный режим. */ - tty_unit[num].flags &= ~TTY_CMDLINE_MASK; - break; - } - /* Выполнение. */ - **cptr = 0; - vt_cmd_exec (num); - tmxr_linemsg (t, "sim>"); - *cptr = vt_cbuf[num]; - break; - case '\b': - case 0177: - /* Стирание предыдущего символа. */ - if (*cptr <= cbuf) - break; - tmxr_linemsg (t, "\b \b"); - while (*cptr > cbuf) { - --*cptr; - if (! (**cptr & 0x80)) - break; - } - break; - case 'U' & 037: - /* Стирание всей строки. */ -erase_line: while (*cptr > cbuf) { - --*cptr; - if (! (**cptr & 0x80)) - tmxr_linemsg (t, "\b \b"); - } - break; - case 033: - /* Escape [ X. */ - if (tmxr_getc_ln (t) != '[' + TMXR_VALID) - break; - switch (tmxr_getc_ln (t) - TMXR_VALID) { - case 'A': /* стрелка вверх */ - if (*cptr <= cbuf) { - *cptr = cbuf + strlen (cbuf); - if (*cptr > cbuf) - tmxr_linemsg (t, cbuf); - } - break; - case 'B': /* стрелка вниз */ - goto erase_line; - } - break; - default: - if (c < ' ' || *cptr > cbuf+CBUFSIZE-5) - break; - *(*cptr)++ = c; - tmxr_putc_ln (t, c); - break; - } -} - -/* - * Ввод символа с терминала с указанным номером. - * Если нет приёма, возвращает -1. - * В случае прерывания возвращает 0400 (только для консоли). - */ -int vt_getc (int num) -{ - TMLN *t = &tty_line [num]; - extern int32 sim_int_char; - int c; - time_t now; - - if (! t->conn) { - /* Пользователь отключился. */ - if (t->ipad) { - besm6_debug ("*** tty%d: отключение %s", - num, - t->ipad); - t->ipad = NULL; - } - tty_setmode (tty_unit+num, TTY_OFFLINE_STATE, 0, 0); - tty_unit[num].flags &= ~TTY_STATE_MASK; - return -1; - } - if (t->rcve) { - /* Приём через telnet. */ - c = tmxr_getc_ln (t); - if (! (c & TMXR_VALID)) { - now = time (0); - if (now > tty_last_time[num] + 5*60) { - ++tty_idle_count[num]; - if (tty_idle_count[num] > 3) { - tmxr_linemsg (t, "\r\nКОНЕЦ СЕАНСА\r\n"); - tmxr_reset_ln (t); - return -1; - } - tmxr_linemsg (t, "\r\nНЕ СПАТЬ!\r\n"); - tty_last_time[num] = now; - } - return -1; - } - tty_idle_count[num] = 0; - tty_last_time[num] = time (0); - - if (tty_unit[num].flags & TTY_CMDLINE_MASK) { - /* Продолжение режима управляющей командной строки. */ - vt_cmd_loop (num, c & 0377); - return -1; - } - if ((c & 0377) == sim_int_char) { - /* Вход в режим управляющей командной строки. */ - tty_unit[num].flags |= TTY_CMDLINE_MASK; - tmxr_linemsg (t, "sim>"); - vt_cptr[num] = vt_cbuf[num]; - return -1; - } - } else { - /* Ввод с клавиатуры. */ - c = sim_poll_kbd(); - if (c == SCPE_STOP) - return 0400; /* прерывание */ - if (! (c & SCPE_KFLAG)) - return -1; - } - return c & 0377; -} - -/* - * Ввод символа с клавиатуры. - * Перекодировка из UTF-8 в КОИ-7. - * Полученный символ находится в диапазоне 0..0177. - * Если нет ввода, возвращает -1. - * В случае прерывания (^E) возвращает 0400. - */ -static int vt_kbd_input_unicode (int num) -{ - int c1, c2, c3, r; -again: - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - c1 = r & 0377; - if (! (c1 & 0x80)) - return unicode_to_koi7 (c1); - - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - c2 = r & 0377; - if (! (c1 & 0x20)) - return unicode_to_koi7 ((c1 & 0x1f) << 6 | (c2 & 0x3f)); - - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - c3 = r & 0377; - if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) { - /* Skip zero width no-break space. */ - goto again; - } - return unicode_to_koi7 ((c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | - (c3 & 0x3f)); -} - -/* - * Альтернативный вариант ввода, не требующий переключения на русскую клавиатуру. - * Символы "точка" и "запятая" вводятся через shift, "больше-меньше" - "тильда-гравис". - * "точка с запятой" - "закр. фиг. скобка", "апостроф" - "верт. черта". - */ -static int vt_kbd_input_koi7 (int num) -{ - int r; - - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - r &= 0377; - switch (r) { - case '\r': return '\003'; - case 'q': return 'j'; - case 'w': return 'c'; - case 'e': return 'u'; - case 'r': return 'k'; - case 't': return 'e'; - case 'y': return 'n'; - case 'u': return 'g'; - case 'i': return '{'; - case 'o': return '}'; - case 'p': return 'z'; - case '[': return 'h'; - case '{': return '['; - case 'a': return 'f'; - case 's': return 'y'; - case 'd': return 'w'; - case 'f': return 'a'; - case 'g': return 'p'; - case 'h': return 'r'; - case 'j': return 'o'; - case 'k': return 'l'; - case 'l': return 'd'; - case ';': return 'v'; - case '}': return ';'; - case '\'': return '|'; - case '|': return '\''; - case 'z': return 'q'; - case 'x': return '~'; - case 'c': return 's'; - case 'v': return 'm'; - case 'b': return 'i'; - case 'n': return 't'; - case 'm': return 'x'; - case ',': return 'b'; - case '<': return ','; - case '.': return '`'; - case '>': return '.'; - case '~': return '>'; - case '`': return '<'; - default: return r; - } -} - -int odd_parity(unsigned char c) -{ - c = (c & 0x55) + ((c >> 1) & 0x55); - c = (c & 0x33) + ((c >> 2) & 0x33); - c = (c & 0x0F) + ((c >> 4) & 0x0F); - return c & 1; -} - -/* - * Обработка ввода со всех подключенных терминалов. - */ -void vt_receive() -{ - uint32 workset = vt_mask; - int num; - - TTY_IN = 0; - for (num = besm6_highest_bit (workset) - TTY_MAX; - workset; num = besm6_highest_bit (workset) - TTY_MAX) { - uint32 mask = 1 << (TTY_MAX - num); - switch (tty_instate[num]) { - case 0: - switch (tty_unit[num].flags & TTY_CHARSET_MASK) { - case TTY_KOI7_JCUKEN_CHARSET: - tty_typed[num] = vt_kbd_input_koi7 (num); - break; - case TTY_KOI7_QWERTY_CHARSET: - tty_typed[num] = vt_getc (num); - break; - case TTY_UNICODE_CHARSET: - tty_typed[num] = vt_kbd_input_unicode (num); - break; - default: - tty_typed[num] = '?'; - break; - } - if (tty_typed[num] < 0) { - /* TODO: обработать исключение от "неоператорского" терминала */ - sim_interval = 0; - break; - } - if (tty_typed[num] <= 0177) { - if (tty_typed[num] == '\r' || tty_typed[num] == '\n') - tty_typed[num] = 3; /* ^C - конец строки */ - if (tty_typed[num] == '\177') - tty_typed[num] = '\b'; /* ASCII DEL -> BS */ - tty_instate[num] = 1; - TTY_IN |= mask; /* start bit */ - GRP |= GRP_TTY_START; /* не используется ? */ - MGRP |= BBIT(19); /* для терминалов по методу МГУ */ - vt_receiving |= mask; - } - break; - case 1 ... 7: - /* need inverted byte */ - TTY_IN |= (tty_typed[num] & (1 << (tty_instate[num]-1))) ? 0 : mask; - tty_instate[num]++; - break; - case 8: - TTY_IN |= odd_parity(tty_typed[num]) ? 0 : mask; /* even parity of inverted */ - tty_instate[num]++; - break; - case 9 ... 11: - /* stop bits are 0 */ - tty_instate[num]++; - break; - case 12: - tty_instate[num] = 0; /* ready for the next char */ - vt_receiving &= ~mask; - break; - } - workset &= ~mask; - } - if (vt_receiving) - vt_idle = 0; -} - -/* - * Выясняем, остановлены ли терминалы. Нужно для входа в "спящий" режим. - */ -int vt_is_idle () -{ - return (tt_mask ? vt_idle > 300 : vt_idle > 10); -} - -int tty_query () -{ -/* besm6_debug ("*** телетайпы: приём");*/ - return TTY_IN; -} - -void consul_print (int dev_num, uint32 cmd) -{ - int line_num = dev_num + TTY_MAX + 1; - if (tty_dev.dctrl) - besm6_debug(">>> CONSUL%o: %03o", line_num, cmd & 0377); - cmd &= 0177; - switch (tty_unit[line_num].flags & TTY_STATE_MASK) { - case TTY_VT340_STATE: - vt_send (line_num, cmd, - (tty_unit[line_num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); - break; - case TTY_CONSUL_STATE: - besm6_debug(">>> CONSUL%o: Native charset not implemented", line_num); - break; - } - // PRP |= CONS_CAN_PRINT[dev_num]; - vt_idle = 0; -} - -void consul_receive () -{ - int c, line_num, dev_num; - - for (dev_num = 0; dev_num < 2; ++dev_num){ - line_num = dev_num + TTY_MAX + 1; - if (! tty_line[line_num].conn) - continue; - switch (tty_unit[line_num].flags & TTY_CHARSET_MASK) { - case TTY_KOI7_JCUKEN_CHARSET: - c = vt_kbd_input_koi7 (line_num); - break; - case TTY_KOI7_QWERTY_CHARSET: - c = vt_getc (line_num); - break; - case TTY_UNICODE_CHARSET: - c = vt_kbd_input_unicode (line_num); - break; - default: - c = '?'; - break; - } - if (c >= 0 && c <= 0177) { - CONSUL_IN[dev_num] = odd_parity(c) ? c | 0200 : c; - if (c == '\r' || c == '\n') - CONSUL_IN[dev_num] = 3; - PRP |= CONS_HAS_INPUT[dev_num]; - vt_idle = 0; - } - } -} - -uint32 consul_read (int num) -{ - if (tty_dev.dctrl) - besm6_debug("<<< CONSUL%o: %03o", num+TTY_MAX+1, CONSUL_IN[num]); - return CONSUL_IN[num]; -} +/* + * besm6_tty.c: BESM-6 teletype device + * + * Copyright (c) 2009, Leo Broukhis + * Copyright (c) 2009, Serge Vakulenko + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your discretion) any later version. + * See the accompanying file "COPYING" for more details. + */ + +#include "besm6_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#define TTY_MAX 24 /* Количество последовательных терминалов */ +#define LINES_MAX TTY_MAX + 2 /* Включая параллельные интерфейсы "Консулов" */ +/* + * Согласно таблице в http://ru.wikipedia.org/wiki/МТК-2 + */ +char * rus[] = { 0, "Т", "\r", "О", " ", "Х", "Н", "М", "\n", "Л", "Р", "Г", "И", "П", "Ц", "Ж", + "Е", "З", "Д", "Б", "С", "Ы", "Ф", "Ь", "А", "В", "Й", 0, "У", "Я", "К", 0 }; + +char * lat[] = { 0, "T", "\r", "O", " ", "H", "N", "M", "\n", "L", "R", "G", "I", "P", "C", "V", + "E", "Z", "D", "B", "S", "Y", "F", "X", "A", "W", "J", 0, "U", "Q", "K", 0 }; + +/* $ = Кто там? */ +char * dig[] = { 0, "5", "\r", "9", " ", "Щ", ",", ".", "\n", ")", "4", "Ш", "8", "0", ":", "=", + "3", "+", "$", "?", "'", "6", "Э", "/", "-", "2", "Ю", 0, "7", "1", "(", 0 }; + +char ** reg = 0; + +char * process (int sym) +{ + /* Требуется инверсия */ + sym ^= 31; + switch (sym) { + case 0: + reg = rus; + break; + case 27: + reg = dig; + break; + case 31: + reg = lat; + break; + default: + return reg[sym]; + } + return ""; +} + +/* Только для последовательных линий */ +int tty_active [TTY_MAX+1], tty_sym [TTY_MAX+1]; +int tty_typed [TTY_MAX+1], tty_instate [TTY_MAX+1]; +time_t tty_last_time [TTY_MAX+1]; +int tty_idle_count [TTY_MAX+1]; + +uint32 vt_sending, vt_receiving; +uint32 tt_sending, tt_receiving; + +// Attachments survive the reset +uint32 tt_mask = 0, vt_mask = 0; + +uint32 TTY_OUT = 0, TTY_IN = 0, vt_idle = 0; +uint32 CONSUL_IN[2]; + +uint32 CONS_CAN_PRINT[2] = { 01000, 00400 }; +uint32 CONS_HAS_INPUT[2] = { 04000, 02000 }; + +/* Буфера командных строк для режима telnet. */ +char vt_cbuf [CBUFSIZE] [LINES_MAX+1]; +char *vt_cptr [LINES_MAX+1]; + +void tt_print(); +void consul_receive(); +t_stat vt_clk(UNIT *); +extern char *get_sim_sw (char *cptr); + +UNIT tty_unit [] = { + { UDATA (vt_clk, UNIT_DIS, 0) }, /* fake unit, clock */ + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + /* The next two units are parallel interface */ + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { 0 } +}; + +REG tty_reg[] = { + { 0 } +}; + +/* + * Дескрипторы линий для мультиплексора TMXR. + * Поле .conn содержит номер сокета и означает занятую линию. + * Для локальных терминалов делаем .conn = 1. + * Чтобы нумерация линий совпадала с нумерацией терминалов + * (с единицы), нулевую линию держим занятой (.conn = 1). + * Поле .rcve устанавливается в 1 для сетевых соединений. + * Для локальных терминалов оно равно 0. + */ +TMLN tty_line [LINES_MAX+1]; +TMXR tty_desc = { LINES_MAX+1, 0, 0, tty_line }; /* mux descriptor */ + +#define TTY_UNICODE_CHARSET 0 +#define TTY_KOI7_JCUKEN_CHARSET (1<>= 1)) { + tt_print(); + /* Прием не реализован */ + clk_divider = 1<<29; + } + + /* Есть новые сетевые подключения? */ + int num = tmxr_poll_conn (&tty_desc); + if (num > 0 && num <= LINES_MAX) { + char buf [80]; + TMLN *t = &tty_line [num]; + besm6_debug ("*** tty%d: новое подключение от %s", + num, t->ipad); + t->rcve = 1; + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_VT340_STATE; + if (num <= TTY_MAX) + vt_mask |= 1 << (TTY_MAX - num); + + switch (tty_unit[num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + tmxr_linemsg (t, "Encoding is KOI-7 (jcuken)\r\n"); + break; + case TTY_KOI7_QWERTY_CHARSET: + tmxr_linemsg (t, "Encoding is KOI-7 (qwerty)\r\n"); + break; + case TTY_UNICODE_CHARSET: + tmxr_linemsg (t, "Encoding is UTF-8\r\n"); + break; + } + tty_idle_count[num] = 0; + tty_last_time[num] = time (0); + sprintf (buf, "%.24s from %s\r\n", + ctime (&tty_last_time[num]), + t->ipad); + tmxr_linemsg (t, buf); + + /* Ввод ^C, чтобы получить приглашение. */ + t->rxb [t->rxbpi++] = '\3'; + } + + /* Опрашиваем сокеты на передачу. */ + tmxr_poll_tx (&tty_desc); + + return sim_activate (this, 1000*MSEC/300); +} + +t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) +{ + int num = u - tty_unit; + TMLN *t = &tty_line [num]; + uint32 mask = 1 << (TTY_MAX - num); + + switch (val & TTY_STATE_MASK) { + case TTY_OFFLINE_STATE: + if (t->conn) { + if (t->rcve) { + tmxr_reset_ln (t); + t->rcve = 0; + } else + t->conn = 0; + if (num <= TTY_MAX) { + tty_sym[num] = + tty_active[num] = + tty_typed[num] = + tty_instate[num] = 0; + vt_mask &= ~mask; + tt_mask &= ~mask; + } + } + break; + case TTY_TELETYPE_STATE: + if (num > TTY_MAX) + return SCPE_NXPAR; + t->conn = 1; + t->rcve = 0; + tt_mask |= mask; + vt_mask &= ~mask; + break; + case TTY_VT340_STATE: + t->conn = 1; + t->rcve = 0; + if (num <= TTY_MAX) { + vt_mask |= mask; + tt_mask &= ~mask; + } + break; + case TTY_CONSUL_STATE: + if (num <= TTY_MAX) + return SCPE_NXPAR; + t->conn = 1; + t->rcve = 0; + break; + } + return SCPE_OK; +} + +/* + * Разрешение подключения к терминалам через telnet. + * Делается командой: + * attach tty <порт> + * Здесь <порт> - номер порта telnet, например 4199. + */ +t_stat tty_attach (UNIT *u, char *cptr) +{ + int num = u - tty_unit; + int r, m, n; + + if (*cptr >= '0' && *cptr <= '9') { + /* Сохраняем и восстанавливаем все .conn, + * так как tmxr_attach() их обнуляет. */ + for (m=0, n=1; n<=LINES_MAX; ++n) + if (tty_line[n].conn) + m |= 1 << (LINES_MAX-n); + /* Неважно, какой номер порта указывать в команде задания + * порта telnet. Можно tty, можно tty1 - без разницы. */ + r = tmxr_attach (&tty_desc, &tty_unit[0], cptr); + for (n=1; n<=LINES_MAX; ++n) + if (m >> (LINES_MAX-n) & 1) + tty_line[n].conn = 1; + return r; + } + if (strcmp (cptr, "/dev/tty") == 0) { + /* Консоль. */ + u->flags &= ~TTY_STATE_MASK; + u->flags |= TTY_VT340_STATE; + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) + vt_mask |= 1 << (TTY_MAX - num); + besm6_debug ("*** консоль на T%03o", num); + return 0; + } + if (strcmp (cptr, "/dev/null") == 0) { + /* Запрещаем терминал. */ + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) { + vt_mask &= ~(1 << (TTY_MAX - num)); + tt_mask &= ~(1 << (TTY_MAX - num)); + } + besm6_debug ("*** отключение терминала T%03o", num); + return 0; + } + return SCPE_ALATT; +} + +t_stat tty_detach (UNIT *u) +{ + return tmxr_detach (&tty_desc, &tty_unit[0]); +} + +/* + * Управление терминалами. + * set ttyN unicode - выбор кодировки UTF-8 + * set ttyN jcuken - выбор кодировки КОИ-7, раскладка йцукен + * set ttyN qwerty - выбор кодировки КОИ-7, раскладка яверты + * set ttyN off - отключение + * set ttyN tt - установка типа терминала "Телетайп" + * set ttyN vt - установка типа терминала "Видеотон-340" + * set ttyN consul - установка типа терминала "Consul-254" + * set ttyN destrbs - "стирающий" backspace + * set ttyN authbs - классический backspace + * set tty disconnect=N - принудительное завершение сеанса telnet + * show tty - просмотр режимов терминалов + * show tty connections - просмотр IP-адресов и времени соединений + * show tty statistics - просмотр счетчиков переданных и принятых байтов + */ +MTAB tty_mod[] = { + { TTY_CHARSET_MASK, TTY_UNICODE_CHARSET, "UTF-8 input", + "UNICODE" }, + { TTY_CHARSET_MASK, TTY_KOI7_JCUKEN_CHARSET, "KOI7 (jcuken) input", + "JCUKEN" }, + { TTY_CHARSET_MASK, TTY_KOI7_QWERTY_CHARSET, "KOI7 (qwerty) input", + "QWERTY" }, + { TTY_STATE_MASK, TTY_OFFLINE_STATE, "offline", + "OFF", &tty_setmode }, + { TTY_STATE_MASK, TTY_TELETYPE_STATE, "Teletype", + "TT", &tty_setmode }, + { TTY_STATE_MASK, TTY_VT340_STATE, "Videoton-340", + "VT", &tty_setmode }, + { TTY_STATE_MASK, TTY_CONSUL_STATE, "Consul-254", + "CONSUL", &tty_setmode }, + { TTY_BSPACE_MASK, TTY_DESTRUCTIVE_BSPACE, "destructive backspace", + "DESTRBS" }, + { TTY_BSPACE_MASK, TTY_AUTHENTIC_BSPACE, NULL, + "AUTHBS" }, + { MTAB_XTD | MTAB_VDV, 1, NULL, + "DISCONNECT", &tmxr_dscln, NULL, (void*) &tty_desc }, + { UNIT_ATT, UNIT_ATT, "connections", + NULL, NULL, &tmxr_show_summ, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", + NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", + NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, + "LOG", &tmxr_set_log, &tmxr_show_log, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, + "NOLOG", &tmxr_set_nolog, NULL, (void*) &tty_desc }, + { 0 } +}; + +DEVICE tty_dev = { + "TTY", tty_unit, tty_reg, tty_mod, + 27, 2, 1, 1, 2, 1, + NULL, NULL, &tty_reset, NULL, &tty_attach, &tty_detach, + NULL, DEV_NET|DEV_DEBUG +}; + +void tty_send (uint32 mask) +{ + /* besm6_debug ("*** телетайпы: передача %08o", mask); */ + + TTY_OUT = mask; +} + +/* + * Выдача символа на терминал с указанным номером. + */ +void vt_putc (int num, int c) +{ + TMLN *t = &tty_line [num]; + + if (! t->conn) + return; + if (t->rcve) { + /* Передача через telnet. */ + tmxr_putc_ln (t, c); + } else { + /* Вывод на консоль. */ + if (t->txlog) { /* log if available */ + fputc (c, t->txlog); + if (c == '\n') + fflush (t->txlog); + } + fputc (c, stdout); + fflush (stdout); + } +} + +/* + * Выдача строки на терминал с указанным номером. + */ +void vt_puts (int num, const char *s) +{ + TMLN *t = &tty_line [num]; + + if (! t->conn) + return; + if (t->rcve) { + /* Передача через telnet. */ + tmxr_linemsg (t, (char*) s); + } else { + /* Вывод на консоль. */ + if (t->txlog) /* log if available */ + fputs (s, t->txlog); + fputs (s, stdout); + fflush (stdout); + } +} + +const char * koi7_rus_to_unicode [32] = { + "Ю", "А", "Б", "Ц", "Д", "Е", "Ф", "Г", + "Х", "И", "Й", "К", "Л", "М", "Н", "О", + "П", "Я", "Р", "С", "Т", "У", "Ж", "В", + "Ь", "Ы", "З", "Ш", "Э", "Щ", "Ч", "\0x7f", +}; + +void vt_send(int num, uint32 sym, int destructive_bs) +{ + if (sym < 0x60) { + switch (sym) { + case '\031': + /* Up */ + vt_puts (num, "\033["); + sym = 'A'; + break; + case '\032': + /* Down */ + vt_puts (num, "\033["); + sym = 'B'; + break; + case '\030': + /* Right */ + vt_puts (num, "\033["); + sym = 'C'; + break; + case '\b': + /* Left */ + vt_puts (num, "\033["); + if (destructive_bs) { + /* Стираем предыдущий символ. */ + vt_puts (num, "D \033["); + } + sym = 'D'; + break; + case '\v': + case '\033': + case '\0': + /* Выдаём управляющий символ. */ + break; + case '\037': + /* Очистка экрана */ + vt_puts (num, "\033[H\033["); + sym = 'J'; + break; + case '\n': + /* На VDT-340 также возвращал курсор в 1-ю позицию */ + vt_putc (num, '\r'); + sym = '\n'; + break; + case '\f': + /* Сообщение ERR при нажатии некоторых управляющих + * клавиш выдается с использованием reverse wraparound. + */ + vt_puts(num, "\033["); + sym = 'H'; + break; + case '\r': + case '\003': + /* Неотображаемые символы */ + sym = 0; + break; + default: + if (sym < ' ') { + /* Нефункциональные ctrl-символы были видны в половинной яркости */ + vt_puts (num, "\033[2m"); + vt_putc (num, sym | 0x40); + vt_puts (num, "\033["); + /* Завершаем ESC-последовательность */ + sym = 'm'; + } + } + if (sym) + vt_putc (num, sym); + } else + vt_puts (num, koi7_rus_to_unicode[sym - 0x60]); +} + +/* + * Обработка выдачи на все подключенные терминалы. + */ +void vt_print() +{ + uint32 workset = (TTY_OUT & vt_mask) | vt_sending; + int num; + + if (workset == 0) { + ++vt_idle; + return; + } + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + int mask = 1 << (TTY_MAX - num); + int c = (TTY_OUT & mask) != 0; + switch (tty_active[num]*2+c) { + case 0: /* idle */ + besm6_debug ("Warning: inactive ttys should have been screened"); + continue; + case 1: /* start bit */ + vt_sending |= mask; + tty_active[num] = 1; + break; + case 18: /* stop bit */ + tty_sym[num] = ~tty_sym[num] & 0x7f; + vt_send (num, tty_sym[num], + (tty_unit[num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); + tty_active[num] = 0; + tty_sym[num] = 0; + vt_sending &= ~mask; + break; + case 19: /* framing error */ + vt_putc (num, '#'); + break; + default: + /* little endian ordering */ + if (c) { + tty_sym[num] |= 1 << (tty_active[num]-1); + } + ++tty_active[num]; + break; + } + workset &= ~mask; + } + vt_idle = 0; +} + +/* Ввод с телетайпа не реализован; вывод работает только при использовании + * модельного времени. + */ +void tt_print() +{ + uint32 workset = (TTY_OUT & tt_mask) | tt_sending; + int num; + + if (workset == 0) { + return; + } + + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + int mask = 1 << (TTY_MAX - num); + int c = (TTY_OUT & mask) != 0; + switch (tty_active[num]*2+c) { + case 0: /* idle */ + break; + case 1: /* start bit */ + tt_sending |= mask; + tty_active[num] = 1; + break; + case 12: /* stop bit */ + vt_puts (num, process (tty_sym[num])); + tty_active[num] = 0; + tty_sym[num] = 0; + tt_sending &= ~mask; + break; + case 13: /* framing error */ + vt_putc (num, '#'); + break; + default: + /* big endian ordering */ + if (c) { + tty_sym[num] |= 1 << (5-tty_active[num]); + } + ++tty_active[num]; + break; + } + workset &= ~mask; + } + vt_idle = 0; +} + +/* + * Перекодировка из Unicode в КОИ-7. + * Если нет соответствия, возвращает -1. + */ +static int unicode_to_koi7 (unsigned val) +{ + switch (val) { + case '\0'... '_': return val; + case 'a' ... 'z': return val + 'Z' - 'z'; + case 0x007f: return 0x7f; + case 0x0410: case 0x0430: return 0x61; + case 0x0411: case 0x0431: return 0x62; + case 0x0412: case 0x0432: return 0x77; + case 0x0413: case 0x0433: return 0x67; + case 0x0414: case 0x0434: return 0x64; + case 0x0415: case 0x0435: return 0x65; + case 0x0416: case 0x0436: return 0x76; + case 0x0417: case 0x0437: return 0x7a; + case 0x0418: case 0x0438: return 0x69; + case 0x0419: case 0x0439: return 0x6a; + case 0x041a: case 0x043a: return 0x6b; + case 0x041b: case 0x043b: return 0x6c; + case 0x041c: case 0x043c: return 0x6d; + case 0x041d: case 0x043d: return 0x6e; + case 0x041e: case 0x043e: return 0x6f; + case 0x041f: case 0x043f: return 0x70; + case 0x0420: case 0x0440: return 0x72; + case 0x0421: case 0x0441: return 0x73; + case 0x0422: case 0x0442: return 0x74; + case 0x0423: case 0x0443: return 0x75; + case 0x0424: case 0x0444: return 0x66; + case 0x0425: case 0x0445: return 0x68; + case 0x0426: case 0x0446: return 0x63; + case 0x0427: case 0x0447: return 0x7e; + case 0x0428: case 0x0448: return 0x7b; + case 0x0429: case 0x0449: return 0x7d; + case 0x042b: case 0x044b: return 0x79; + case 0x042c: case 0x044c: return 0x78; + case 0x042d: case 0x044d: return 0x7c; + case 0x042e: case 0x044e: return 0x60; + case 0x042f: case 0x044f: return 0x71; + } + return -1; +} + +/* + * Set command + */ +static t_stat cmd_set (int32 num, char *cptr) +{ + char gbuf [CBUFSIZE]; + int len; + + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) + return SCPE_NOPARAM; + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + + len = strlen (gbuf); + if (strncmp ("UNICODE", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_UNICODE_CHARSET; + } else if (strncmp ("JCUKEN", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_KOI7_JCUKEN_CHARSET; + } else if (strncmp ("QWERTY", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_KOI7_QWERTY_CHARSET; + } else if (strncmp ("TT", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_TELETYPE_STATE; + } else if (strncmp ("VT", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_VT340_STATE; + } else if (strncmp ("CONSUL", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_CONSUL_STATE; + } else if (strncmp ("DESTRBS", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_BSPACE_MASK; + tty_unit[num].flags |= TTY_DESTRUCTIVE_BSPACE; + } else if (strncmp ("AUTHBS", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_BSPACE_MASK; + tty_unit[num].flags |= TTY_AUTHENTIC_BSPACE; + } else { + return SCPE_NXPAR; + } + return SCPE_OK; +} + +/* + * Show command + */ +static t_stat cmd_show (int32 num, char *cptr) +{ + TMLN *t = &tty_line [num]; + char gbuf [CBUFSIZE]; + MTAB *m; + int len; + + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) { + sprintf (gbuf, "TTY%d", num); + tmxr_linemsg (t, gbuf); + for (m=tty_mod; m->mask; m++) { + if (m->pstring && + (tty_unit[num].flags & m->mask) == m->match) { + tmxr_linemsg (t, ", "); + tmxr_linemsg (t, m->pstring); + } + } + if (t->txlog) + tmxr_linemsg (t, ", log"); + tmxr_linemsg (t, "\r\n"); + return SCPE_OK; + } + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + + len = strlen (gbuf); + if (strncmp ("STATISTICS", gbuf, len) == 0) { + sprintf (gbuf, "line %d: input queued/total = %d/%d, " + "output queued/total = %d/%d\r\n", num, + t->rxbpi - t->rxbpr, t->rxcnt, + t->txbpi - t->txbpr, t->txcnt); + tmxr_linemsg (t, gbuf); + } else { + return SCPE_NXPAR; + } + return SCPE_OK; +} + +/* + * Exit command + */ +static t_stat cmd_exit (int32 num, char *cptr) +{ + return SCPE_EXIT; +} + +static t_stat cmd_help (int32 num, char *cptr); + +static CTAB cmd_table[] = { + { "SET", &cmd_set, 0, + "set unicode select UTF-8 encoding\r\n" + "set jcuken select KOI7 encoding, 'jcuken' keymap\r\n" + "set qwerty select KOI7 encoding, 'qwerty' keymap\r\n" + "set tt use Teletype mode\r\n" + "set vt use Videoton-340 mode\r\n" + "set consul use Consul-254 mode\r\n" + "set destrbs destructive backspace\r\n" + "set authbs authentic backspace\r\n" + }, + { "SHOW", &cmd_show, 0, + "sh{ow} show modes of the terminal\r\n" + "sh{ow} s{tatistics} show network statistics\r\n" + }, + { "EXIT", &cmd_exit, 0, + "exi{t} | q{uit} | by{e} exit from simulation\r\n" + }, + { "QUIT", &cmd_exit, 0, NULL + }, + { "BYE", &cmd_exit, 0, NULL + }, + { "HELP", &cmd_help, 0, + "h{elp} type this message\r\n" + "h{elp} type help for command\r\n" + }, + { 0 } +}; + +/* + * Find command routine + */ +static CTAB *lookup_cmd (char *command) +{ + CTAB *c; + int len; + + len = strlen (command); + for (c=cmd_table; c->name; c++) { + if (strncmp (command, c->name, len) == 0) + return c; + } + return 0; +} + +/* + * Help command + */ +static t_stat cmd_help (int32 num, char *cptr) +{ + TMLN *t = &tty_line [num]; + char gbuf [CBUFSIZE]; + CTAB *c; + + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) { + /* Список всех команд. */ + tmxr_linemsg (t, "Commands may be abbreviated. Commands are:\r\n\r\n"); + for (c=cmd_table; c && c->name; c++) + if (c->help) + tmxr_linemsg (t, c->help); + return SCPE_OK; + } + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + c = lookup_cmd (gbuf); + if (! c) + return SCPE_ARG; + /* Описание конкретной команды. */ + tmxr_linemsg (t, c->help); + return SCPE_OK; +} + +/* + * Выполнение командной строки. + */ +void vt_cmd_exec (int num) +{ + TMLN *t = &tty_line [num]; + char *cptr, gbuf [CBUFSIZE]; + CTAB *cmdp; + t_stat err; + extern char *scp_errors[]; + + cptr = get_glyph (vt_cbuf [num], gbuf, 0); /* get command glyph */ + cmdp = lookup_cmd (gbuf); /* lookup command */ + if (! cmdp) { + tmxr_linemsg (t, scp_errors[SCPE_UNK - SCPE_BASE]); + tmxr_linemsg (t, "\r\n"); + return; + } + err = cmdp->action (num, cptr); /* if found, exec */ + if (err >= SCPE_BASE) { /* error? */ + tmxr_linemsg (t, scp_errors [err - SCPE_BASE]); + tmxr_linemsg (t, "\r\n"); + } + if (err == SCPE_EXIT) { /* close telnet session */ + tmxr_reset_ln (t); + } +} + +/* + * Режим управляющей командной строки. + */ +void vt_cmd_loop (int num, int c) +{ + TMLN *t = &tty_line [num]; + char *cbuf, **cptr; + + cbuf = vt_cbuf [num]; + cptr = &vt_cptr [num]; + + switch (c) { + case '\r': + case '\n': + tmxr_linemsg (t, "\r\n"); + if (*cptr <= cbuf) { + /* Пустая строка - возврат в обычный режим. */ + tty_unit[num].flags &= ~TTY_CMDLINE_MASK; + break; + } + /* Выполнение. */ + **cptr = 0; + vt_cmd_exec (num); + tmxr_linemsg (t, "sim>"); + *cptr = vt_cbuf[num]; + break; + case '\b': + case 0177: + /* Стирание предыдущего символа. */ + if (*cptr <= cbuf) + break; + tmxr_linemsg (t, "\b \b"); + while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + break; + } + break; + case 'U' & 037: + /* Стирание всей строки. */ +erase_line: while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + tmxr_linemsg (t, "\b \b"); + } + break; + case 033: + /* Escape [ X. */ + if (tmxr_getc_ln (t) != '[' + TMXR_VALID) + break; + switch (tmxr_getc_ln (t) - TMXR_VALID) { + case 'A': /* стрелка вверх */ + if (*cptr <= cbuf) { + *cptr = cbuf + strlen (cbuf); + if (*cptr > cbuf) + tmxr_linemsg (t, cbuf); + } + break; + case 'B': /* стрелка вниз */ + goto erase_line; + } + break; + default: + if (c < ' ' || *cptr > cbuf+CBUFSIZE-5) + break; + *(*cptr)++ = c; + tmxr_putc_ln (t, c); + break; + } +} + +/* + * Ввод символа с терминала с указанным номером. + * Если нет приёма, возвращает -1. + * В случае прерывания возвращает 0400 (только для консоли). + */ +int vt_getc (int num) +{ + TMLN *t = &tty_line [num]; + extern int32 sim_int_char; + int c; + time_t now; + + if (! t->conn) { + /* Пользователь отключился. */ + if (t->ipad) { + besm6_debug ("*** tty%d: отключение %s", + num, + t->ipad); + t->ipad = NULL; + } + tty_setmode (tty_unit+num, TTY_OFFLINE_STATE, 0, 0); + tty_unit[num].flags &= ~TTY_STATE_MASK; + return -1; + } + if (t->rcve) { + /* Приём через telnet. */ + c = tmxr_getc_ln (t); + if (! (c & TMXR_VALID)) { + now = time (0); + if (now > tty_last_time[num] + 5*60) { + ++tty_idle_count[num]; + if (tty_idle_count[num] > 3) { + tmxr_linemsg (t, "\r\nКОНЕЦ СЕАНСА\r\n"); + tmxr_reset_ln (t); + return -1; + } + tmxr_linemsg (t, "\r\nНЕ СПАТЬ!\r\n"); + tty_last_time[num] = now; + } + return -1; + } + tty_idle_count[num] = 0; + tty_last_time[num] = time (0); + + if (tty_unit[num].flags & TTY_CMDLINE_MASK) { + /* Продолжение режима управляющей командной строки. */ + vt_cmd_loop (num, c & 0377); + return -1; + } + if ((c & 0377) == sim_int_char) { + /* Вход в режим управляющей командной строки. */ + tty_unit[num].flags |= TTY_CMDLINE_MASK; + tmxr_linemsg (t, "sim>"); + vt_cptr[num] = vt_cbuf[num]; + return -1; + } + } else { + /* Ввод с клавиатуры. */ + c = sim_poll_kbd(); + if (c == SCPE_STOP) + return 0400; /* прерывание */ + if (! (c & SCPE_KFLAG)) + return -1; + } + return c & 0377; +} + +/* + * Ввод символа с клавиатуры. + * Перекодировка из UTF-8 в КОИ-7. + * Полученный символ находится в диапазоне 0..0177. + * Если нет ввода, возвращает -1. + * В случае прерывания (^E) возвращает 0400. + */ +static int vt_kbd_input_unicode (int num) +{ + int c1, c2, c3, r; +again: + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c1 = r & 0377; + if (! (c1 & 0x80)) + return unicode_to_koi7 (c1); + + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c2 = r & 0377; + if (! (c1 & 0x20)) + return unicode_to_koi7 ((c1 & 0x1f) << 6 | (c2 & 0x3f)); + + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c3 = r & 0377; + if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) { + /* Skip zero width no-break space. */ + goto again; + } + return unicode_to_koi7 ((c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | + (c3 & 0x3f)); +} + +/* + * Альтернативный вариант ввода, не требующий переключения на русскую клавиатуру. + * Символы "точка" и "запятая" вводятся через shift, "больше-меньше" - "тильда-гравис". + * "точка с запятой" - "закр. фиг. скобка", "апостроф" - "верт. черта". + */ +static int vt_kbd_input_koi7 (int num) +{ + int r; + + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + r &= 0377; + switch (r) { + case '\r': return '\003'; + case 'q': return 'j'; + case 'w': return 'c'; + case 'e': return 'u'; + case 'r': return 'k'; + case 't': return 'e'; + case 'y': return 'n'; + case 'u': return 'g'; + case 'i': return '{'; + case 'o': return '}'; + case 'p': return 'z'; + case '[': return 'h'; + case '{': return '['; + case 'a': return 'f'; + case 's': return 'y'; + case 'd': return 'w'; + case 'f': return 'a'; + case 'g': return 'p'; + case 'h': return 'r'; + case 'j': return 'o'; + case 'k': return 'l'; + case 'l': return 'd'; + case ';': return 'v'; + case '}': return ';'; + case '\'': return '|'; + case '|': return '\''; + case 'z': return 'q'; + case 'x': return '~'; + case 'c': return 's'; + case 'v': return 'm'; + case 'b': return 'i'; + case 'n': return 't'; + case 'm': return 'x'; + case ',': return 'b'; + case '<': return ','; + case '.': return '`'; + case '>': return '.'; + case '~': return '>'; + case '`': return '<'; + default: return r; + } +} + +int odd_parity(unsigned char c) +{ + c = (c & 0x55) + ((c >> 1) & 0x55); + c = (c & 0x33) + ((c >> 2) & 0x33); + c = (c & 0x0F) + ((c >> 4) & 0x0F); + return c & 1; +} + +/* + * Обработка ввода со всех подключенных терминалов. + */ +void vt_receive() +{ + uint32 workset = vt_mask; + int num; + + TTY_IN = 0; + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + uint32 mask = 1 << (TTY_MAX - num); + switch (tty_instate[num]) { + case 0: + switch (tty_unit[num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + tty_typed[num] = vt_kbd_input_koi7 (num); + break; + case TTY_KOI7_QWERTY_CHARSET: + tty_typed[num] = vt_getc (num); + break; + case TTY_UNICODE_CHARSET: + tty_typed[num] = vt_kbd_input_unicode (num); + break; + default: + tty_typed[num] = '?'; + break; + } + if (tty_typed[num] < 0) { + /* TODO: обработать исключение от "неоператорского" терминала */ + sim_interval = 0; + break; + } + if (tty_typed[num] <= 0177) { + if (tty_typed[num] == '\r' || tty_typed[num] == '\n') + tty_typed[num] = 3; /* ^C - конец строки */ + if (tty_typed[num] == '\177') + tty_typed[num] = '\b'; /* ASCII DEL -> BS */ + tty_instate[num] = 1; + TTY_IN |= mask; /* start bit */ + GRP |= GRP_TTY_START; /* не используется ? */ + MGRP |= BBIT(19); /* для терминалов по методу МГУ */ + vt_receiving |= mask; + } + break; + case 1 ... 7: + /* need inverted byte */ + TTY_IN |= (tty_typed[num] & (1 << (tty_instate[num]-1))) ? 0 : mask; + tty_instate[num]++; + break; + case 8: + TTY_IN |= odd_parity(tty_typed[num]) ? 0 : mask; /* even parity of inverted */ + tty_instate[num]++; + break; + case 9 ... 11: + /* stop bits are 0 */ + tty_instate[num]++; + break; + case 12: + tty_instate[num] = 0; /* ready for the next char */ + vt_receiving &= ~mask; + break; + } + workset &= ~mask; + } + if (vt_receiving) + vt_idle = 0; +} + +/* + * Выясняем, остановлены ли терминалы. Нужно для входа в "спящий" режим. + */ +int vt_is_idle () +{ + return (tt_mask ? vt_idle > 300 : vt_idle > 10); +} + +int tty_query () +{ +/* besm6_debug ("*** телетайпы: приём");*/ + return TTY_IN; +} + +void consul_print (int dev_num, uint32 cmd) +{ + int line_num = dev_num + TTY_MAX + 1; + if (tty_dev.dctrl) + besm6_debug(">>> CONSUL%o: %03o", line_num, cmd & 0377); + cmd &= 0177; + switch (tty_unit[line_num].flags & TTY_STATE_MASK) { + case TTY_VT340_STATE: + vt_send (line_num, cmd, + (tty_unit[line_num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); + break; + case TTY_CONSUL_STATE: + besm6_debug(">>> CONSUL%o: Native charset not implemented", line_num); + break; + } + // PRP |= CONS_CAN_PRINT[dev_num]; + vt_idle = 0; +} + +void consul_receive () +{ + int c, line_num, dev_num; + + for (dev_num = 0; dev_num < 2; ++dev_num){ + line_num = dev_num + TTY_MAX + 1; + if (! tty_line[line_num].conn) + continue; + switch (tty_unit[line_num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + c = vt_kbd_input_koi7 (line_num); + break; + case TTY_KOI7_QWERTY_CHARSET: + c = vt_getc (line_num); + break; + case TTY_UNICODE_CHARSET: + c = vt_kbd_input_unicode (line_num); + break; + default: + c = '?'; + break; + } + if (c >= 0 && c <= 0177) { + CONSUL_IN[dev_num] = odd_parity(c) ? c | 0200 : c; + if (c == '\r' || c == '\n') + CONSUL_IN[dev_num] = 3; + PRP |= CONS_HAS_INPUT[dev_num]; + vt_idle = 0; + } + } +} + +uint32 consul_read (int num) +{ + if (tty_dev.dctrl) + besm6_debug("<<< CONSUL%o: %03o", num+TTY_MAX+1, CONSUL_IN[num]); + return CONSUL_IN[num]; +} diff --git a/BESM6/boot_dispak.b6 b/BESM6/boot_dispak.b6 new file mode 100644 index 00000000..7c3c74a6 --- /dev/null +++ b/BESM6/boot_dispak.b6 @@ -0,0 +1,484 @@ +; boot_dispak.b6 +п 2000 + +; Использование клавиатуры пульта БРУС при вызове ОС ДИСПАК. +; +; ТР2: 32, 31, 26 и 25-й разряды = '1' - при работе с ЭНМД-3, +; либо - 33 и 27-й разряды = '1' - при работе с ЭНМД-4; +; 000 000 000 000 000 011 000 011 000 000 000 000 000 000 000 000 ЭНМД-3 +; 3 0 3 +; 000 000 000 000 000 100 000 100 000 000 000 000 000 000 000 000 ЭНМД-4 +; 4 0 4 +в 2 +с 0000 0303 0000 0000 + +; ТРЗ: 24 ÷ 17 и 4-й разряды = '1' - для чистки каталогов ОС; +; 000 000 000 000 000 000 000 000 111 111 110 000 000 000 001 000 +; 7 7 6 0 0 0 1 0 +;с 7760 0010 +с 0 + +в 02000 +к рег 101, уиа 2260(2) ; 02000 - 0002 0101 1240 2260 +к уиа 2502(12), уиа -56(6) ; 02001 - 5240 2502 3247 7722 +к сч 2537, зп 2605 ; 02002 - 0010 2537 0000 2605 +к сда 101, зп 2664(6) ; 02003 - 0036 0101 3000 2664 +к цикл 2003(6), уиа -2(1) ; 02004 - 3370 2003 0647 7776 +к сч 2521(1), зп 502(1) ; 02005 - 0410 2521 0400 0502 +к цикл 2005(1), уиа -2(6) ; 02006 - 0770 2005 3247 7776 +к уиа (13), сч ; 02007 - 5640 0000 0010 0000 +к слц 2546(6), цикл 2010(6) ; 02010 - 3013 2546 3370 2010 +к нтж, по 2070 ; 02011 - 0012 0000 0260 2070 +к уиа 2444(5), пв 2346(10) ; 02012 - 2640 2444 4310 2346 +к нтж 2543, пе 2345 ; 02013 - 0012 2543 0270 2345 +к сч 2, пб 3000 ; 02014 - 0010 0002 0300 3000 +к сда 136, и 2427 ; 02015 - 0036 0136 0011 2427 +к по 2017, вч 2664 ; 02016 - 0260 2017 0005 2664 +к уи 16, уии 3(16) ; 02017 - 0040 0016 7044 0003 +к сли 16(16), сли 16(3) ; 02020 - 7045 0016 1445 0016 +к уиа -2(3), мода ; 02021 - 1647 7776 0220 0000 +к мода (16), сч 2546(3) ; 02022 - 7220 0000 1410 2546 +к зп 1777(3), цикл 2022(3) ; 02023 - 1400 1777 1770 2022 +к уиа -1(3), мода ; 02024 - 1647 7777 0220 0000 +к сч 1776, пио 2027(3) ; 02025 - 0010 1776 1740 2027 +к сда 110, мода ; 02026 - 0036 0110 0220 0000 +к сда 50, зп 1033(3) ; 02027 - 0036 0050 1400 1033 +к сч 1775, сда 115 ; 02030 - 0010 1775 0036 0115 +к пио 2032(3), сда 120 ; 02031 - 1740 2032 0036 0120 +к и 2540, сда 70 ; 02032 - 0011 2540 0036 0070 +к или 1033(3), зп 1033(3) ; 02033 - 1415 1033 1400 1033 +к сч 1777, пио 2036(3) ; 02034 - 0010 1777 1740 2036 +к сда 110, мода ; 02035 - 0036 0110 0220 0000 +к и 2541, или 1033(3) ; 02036 - 0011 2541 1415 1033 +к зп 1033(3), цикл 2025(3) ; 02037 - 1400 1033 1770 2025 +к уиа 3(16), уиа -1(3) ; 02040 - 7240 0003 1647 7777 +к сч, зп 1773 ; 02041 - 0010 0000 0000 1773 +к уиа 10(7), мода ; 02042 - 3640 0010 0220 0000 +к уиа -1(15), уиа -7(14) ; 02043 - 6647 7777 6247 7771 +к сч 1777(3), слиа 1(15) ; 02044 - 1410 1777 6650 0001 +к сда 140(7), и 2655(15) ; 02045 - 3436 0140 6411 2655 +к по 2060, счи 15 ; 02046 - 0260 2060 0042 0015 +к нтж 2415, уи 17 ; 02047 - 0012 2415 0040 0017 +к сда 71, или 2532 ; 02050 - 0036 0071 0015 2532 +к зп 1774, сч 1773 ; 02051 - 0000 1774 0010 1773 +к сда 33, или 1774 ; 02052 - 0036 0033 0015 1774 +к зп 1774, пв 2126(11) ; 02053 - 0000 1774 4710 2126 +к сч 2534, и 2615 ; 02054 - 0010 2534 0011 2615 +к по 2074, сч 2534 ; 02055 - 0260 2074 0010 2534 +к сда 114, нтж 1775 ; 02056 - 0036 0114 0012 1775 +к и 2423, по 2076 ; 02057 - 0011 2423 0260 2076 +к цикл 2044(14), слиа -10(7) ; 02060 - 6370 2044 3657 7770 +к сч 1773, слц 2664 ; 02061 - 0010 1773 0013 2664 +к зп 1773, сда 102 ; 02062 - 0000 1773 0036 0102 +к по 2043, пио 2066(3) ; 02063 - 0260 2043 1740 2066 +к уиа 4(16), уиа (3) ; 02064 - 7240 0004 1640 0000 +к пб 2041, мода ; 02065 - 0300 2041 0220 0000 +к уиа 2502(5), пв 2367(7) ; 02066 - 2640 2502 3710 2367 +к стоп, пб 2040 ; 02067 - 0330 0000 0300 2040 +к уиа -35(16), уиа 1(13) ; 02070 - 7247 7743 5640 0001 +к сч 72035(16), зп 2601(16) ; 02071 - 7110 2035 7000 2601 +к цикл 2071(16), пв 2346(10) ; 02072 - 7370 2071 4310 2346 +к зп 2543, пб 2014 ; 02073 - 0000 2543 0300 2014 +к сч 2534, нтж 1775 ; 02074 - 0010 2534 0012 1775 +к и 2423, пе 2060 ; 02075 - 0011 2423 0270 2060 +к счи 17, сда 71 ; 02076 - 0042 0017 0036 0071 +к или 2420, зп 1774 ; 02077 - 0015 2420 0000 1774 +к счи 16, сда 76 ; 02100 - 0042 0016 0036 0076 +к слц 1773, сда 33 ; 02101 - 0013 1773 0036 0033 +к или 1774, пб 2105 ; 02102 - 0015 1774 0300 2105 +к уиа 2257(11), мода ; 02103 - 4640 2257 0220 0000 +к уиа 2106(2), сч 1027 ; 02104 - 1240 2106 0010 1027 +к зп 1774, пб (2) ; 02105 - 0000 1774 1300 0000 +к сч 1774, сда 147 ; 02106 - 0010 1774 0036 0147 +к уи 16, сч 1774 ; 02107 - 0040 0016 0010 1774 +к сда 107, и 2415 ; 02110 - 0036 0107 0011 2415 +к уи 17, нтж 2415 ; 02111 - 0040 0017 0012 2415 +к уи 15, сч 1774 ; 02112 - 0040 0015 0010 1774 +к сда 145, и 2416 ; 02113 - 0036 0145 0011 2416 +к сда 75, уи 6 ; 02114 - 0036 0075 0040 0006 +к сли 6(17), сч 1027(16) ; 02115 - 7445 0006 7010 1027 +к и 2625(6), уиа (1) ; 02116 - 3011 2625 0640 0000 +к по 2120, уиа 2(1) ; 02117 - 0260 2120 0640 0002 +к сч 1775, мода ; 02120 - 0010 1775 0220 0000 +к сда 130, слц 2531 ; 02121 - 0036 0130 0013 2531 +к и 2526, мода ; 02122 - 0011 2526 0220 0000 +к сда 77(1), зп 2527 ; 02123 - 0436 0077 0000 2527 +к счмр, сда 146 ; 02124 - 0031 0000 0036 0146 +к и 2653, зп 2604 ; 02125 - 0011 2653 0000 2604 +к сч, рег 37 ; 02126 - 0010 0000 0002 0037 +к сч 2417, увв 20(16) ; 02127 - 0010 2417 7033 0020 +к уи, сч 1774 ; 02130 - 0040 0000 0010 1774 +к сда 145, и 2416 ; 02131 - 0036 0145 0011 2416 +к или 2654, или 2653 ; 02132 - 0015 2654 0015 2653 +к увв 20(16), уи ; 02133 - 7033 0020 0040 0000 +к рег 237, и 2625(16) ; 02134 - 0002 0237 7011 2625 +к по 2134, сч 2661 ; 02135 - 0260 2134 0010 2661 +к увв 20(16), уи ; 02136 - 7033 0020 0040 0000 +к уи, рег 37 ; 02137 - 0040 0000 0002 0037 +к уиа 2147(6), уиа 11(4) ; 02140 - 3240 2147 2240 0011 +к сч 2655(15), пио 2143(1) ; 02141 - 6410 2655 0740 2143 +к или 2604, мода ; 02142 - 0015 2604 0220 0000 +к или 2421, увв 20(16) ; 02143 - 0015 2421 7033 0020 +к уи, счи 4 ; 02144 - 0040 0000 0042 0004 +к увв 20(16), уи ; 02145 - 7033 0020 0040 0000 +к увв 4000(16), пб (6) ; 02146 - 7033 4000 3300 0000 +к и 2654, уиа 2430(5) ; 02147 - 0011 2654 2640 2430 +к по 2412, уиа -7(6) ; 02150 - 0260 2412 3247 7771 +к сч, мода ; 02151 - 0010 0000 0220 0000 +к мод 2521(16), зп 7(6) ; 02152 - 7230 2521 3000 0007 +к цикл 2152(6), уиа -7(6) ; 02153 - 3370 2152 3247 7771 +к зп 1, цикл 2154(6) ; 02154 - 0000 0001 3370 2154 +к сч 1774, увв (16) ; 02155 - 0010 1774 7033 0000 +к сч 2416, или 2422 ; 02156 - 0010 2416 0015 2422 +к увв 20(16), уи ; 02157 - 7033 0020 0040 0000 +к сч 2527, или 2651 ; 02160 - 0010 2527 0015 2651 +к уи, увв 20(16) ; 02161 - 0040 0000 7033 0020 +к уи, увв ; 02162 - 0040 0000 0033 0000 +к уиа -50(6), мода ; 02163 - 3247 7730 0220 0000 +к зп 1, цикл 2164(6) ; 02164 - 0000 0001 3370 2164 +к сч, уи ; 02165 - 0010 0000 0040 0000 +к рег 37, уиа 76030(6) ; 02166 - 0002 0037 3247 6030 +к уиа 77540(10), мода ; 02167 - 4247 7540 0220 0000 +к сбр, рег 237 ; 02170 - 0020 0000 0002 0237 +к и 2625(16), пе 2175 ; 02171 - 7011 2625 0270 2175 +к цикл 2170(10), цикл 2167(6) ; 02172 - 4370 2170 3370 2167 +к стоп, уиа 2126(7) ; 02173 - 0330 0000 3640 2126 +к уиа 2474(5), пб 2366 ; 02174 - 2640 2474 0300 2366 +к уиа 11(4), пв 2144(6) ; 02175 - 2240 0011 3310 2144 +к зп 2533, и 2651 ; 02176 - 0000 2533 0011 2651 +к пе 2351, увв 4035 ; 02177 - 0270 2351 0033 4035 +к и 2655(16), уиа 2436(5) ; 02200 - 7011 2655 2640 2436 +к пе 2412, уиа 1(10) ; 02201 - 0270 2412 4240 0001 +к уиа 2206(6), уиа 2206(5) ; 02202 - 3240 2206 2640 2206 +к сч 2424, уи 21 ; 02203 - 0010 2424 0040 0021 +к мод 2521(16), сч (10) ; 02204 - 7230 2521 4010 0000 +к уи, пб (6) ; 02205 - 0040 0000 3300 0000 +к зп 2534, и 2535 ; 02206 - 0000 2534 0011 2535 +к нтж 2536, уиа 2460(5) ; 02207 - 0012 2536 2640 2460 +к пе 2412, сч 1774 ; 02210 - 0270 2412 0010 1774 +к и 2660, пе 2302 ; 02211 - 0011 2660 0270 2302 +к сч 2533, и 2652 ; 02212 - 0010 2533 0011 2652 +к уиа 2444(5), пе 2366 ; 02213 - 2640 2444 0270 2366 +к уиа -3(4), уиа (12) ; 02214 - 2247 7775 5240 0000 +к счи 11, нтж 2530 ; 02215 - 0042 0011 0012 2530 +к пе 2217, слиа 2000(12) ; 02216 - 0270 2217 5250 2000 +к сч 2534, и 2614 ; 02217 - 0010 2534 0011 2614 +к пе 2240, уиа -1(10) ; 02220 - 0270 2240 4247 7777 +к уиа 2411(5), сч 2424 ; 02221 - 2640 2411 0010 2424 +к уи 21, уиа 77401(6) ; 02222 - 0040 0021 3247 7401 +к слиа 2(10), сч ; 02223 - 4250 0002 0010 0000 +к мода 70000(12), слц 377(6) ; 02224 - 5227 0000 3013 0377 +к цикл 2224(6), зп 2534 ; 02225 - 3370 2224 0000 2534 +к уиа 2227(5), пв 2203(6) ; 02226 - 2640 2227 3310 2203 +к зп 2533, нтж 2534 ; 02227 - 0000 2533 0012 2534 +к и 2423, пе 2250 ; 02230 - 0011 2423 0270 2250 +к сч 2533, и 2615 ; 02231 - 0010 2533 0011 2615 +к уиа 2444(5), по 2366 ; 02232 - 2640 2444 0260 2366 +к слиа 400(12), мода ; 02233 - 5250 0400 0220 0000 +к цикл 2221(4), уиа 2255(6) ; 02234 - 2370 2221 3240 2255 +к сч 2425, уи 21 ; 02235 - 0010 2425 0040 0021 +к сч 2417, увв 20(16) ; 02236 - 0010 2417 7033 0020 +к уи, пб (6) ; 02237 - 0040 0000 3300 0000 +к уиа 2411(5), сч 2424 ; 02240 - 2640 2411 0010 2424 +к уи 21, уиа 76001(6) ; 02241 - 0040 0021 3247 6001 +к сч, уиа 3(10) ; 02242 - 0010 0000 4240 0003 +к мода 70000(12), слц 1777(6) ; 02243 - 5227 0000 3013 1777 +к цикл 2243(6), зп 2534 ; 02244 - 3370 2243 0000 2534 +к уиа 2246(5), пв 2203(6) ; 02245 - 2640 2246 3310 2203 +к нтж 2534, пе 2213 ; 02246 - 0012 2534 0270 2213 +к уиа 2255(6), пб 2235 ; 02247 - 3240 2255 0300 2235 +к слиа -1(10), уиа 2252(5) ; 02250 - 4257 7777 2640 2252 +к мода, пв 2203(6) ; 02251 - 0220 0000 3310 2203 +к нтж 2534, и 2423 ; 02252 - 0012 2534 0011 2423 +к пе 2213, слиа 1(10) ; 02253 - 0270 2213 4250 0001 +к слиа 400(12), пб 2234 ; 02254 - 5250 0400 0300 2234 +к сч, уи ; 02255 - 0010 0000 0040 0000 +к рег 37, пб (11) ; 02256 - 0002 0037 4700 0000 +к уиа 1(14), пб 2335 ; 02257 - 6240 0001 0300 2335 +к зп 1027, сч 2516 ; 02260 - 0000 1027 0010 2516 +к или 1775, зп 1775 ; 02261 - 0015 1775 0000 1775 +к уиа 2265(11), пб 2104 ; 02262 - 4640 2265 0300 2104 +к слиа 40(4), цикл 2272(14) ; 02263 - 2250 0040 6370 2272 +к уиа 2466(5), пв 2367(7) ; 02264 - 2640 2466 3710 2367 +к сч 2, сда 130 ; 02265 - 0010 0002 0036 0130 +к и 2427, уиа -17(14) ; 02266 - 0011 2427 6247 7761 +к уиа (2), уиа (4) ; 02267 - 1240 0000 2240 0000 +к по 2271, вч 2664 ; 02270 - 0260 2271 0005 2664 +к зп 2542, мода ; 02271 - 0000 2542 0220 0000 +к уиа -37(7), сч 1775 ; 02272 - 3647 7741 0010 1775 +к нтж 70000(4), и 2423 ; 02273 - 2112 0000 0011 2423 +к пе 2263, сч 1775 ; 02274 - 0270 2263 0010 1775 +к сда 155, нтж 70016(4) ; 02275 - 0036 0155 2112 0016 +к и 2415, пе 2263 ; 02276 - 0011 2415 0270 2263 +к счи 2, нтж 2542 ; 02277 - 0042 0002 0012 2542 +к по 2303, слиа 1(2) ; 02300 - 0260 2303 1250 0001 +к пб 2263, мода ; 02301 - 0300 2263 0220 0000 +к уии 6(11), пб 2235 ; 02302 - 4444 0006 0300 2235 +к мода (4), сч 70037(7) ; 02303 - 2220 0000 3510 0037 +к зп 3537(7), цикл 2303(7) ; 02304 - 3400 3537 3770 2303 +к сч 3502, зп 1775 ; 02305 - 0010 3502 0000 1775 +к мода, пв 2040(2) ; 02306 - 0220 0000 1310 2040 +к зп 1030, сч 3500 ; 02307 - 0000 1030 0010 3500 +к зп 1775, сч 3 ; 02310 - 0000 1775 0010 0003 +к и 2660, пб 2103 ; 02311 - 0011 2660 0300 2103 +к уиа -2(14), сч 3515 ; 02312 - 6247 7776 0010 3515 +к сда 117, зп 1775 ; 02313 - 0036 0117 0000 1775 +к и 2423, по 2103 ; 02314 - 0011 2423 0260 2103 +к сч 2663, пв 2123(11) ; 02315 - 0010 2663 4710 2123 +к сч 3516, и 2415 ; 02316 - 0010 3516 0011 2415 +к сда 75, уи 6 ; 02317 - 0036 0075 0040 0006 +к сч 70000(6), нтж 3516 ; 02320 - 3110 0000 0012 3516 +к и 2415, пе 2103 ; 02321 - 0011 2415 0270 2103 +к мода (6), сч 70002(14) ; 02322 - 3220 0000 6110 0002 +к зп 2604(14), цикл 2322(14) ; 02323 - 6000 2604 6370 2322 +к уиа 2510(12), пв 2040(2) ; 02324 - 5240 2510 1310 2040 +к уиа -2(14), пв 2126(11) ; 02325 - 6247 7776 4710 2126 +к сч 70002(14), нтж 2604(14) ; 02326 - 6110 0002 6012 2604 +к уиа 2257(11), пе 2103 ; 02327 - 4640 2257 0270 2103 +к цикл 2326(14), уиа -22(14) ; 02330 - 6370 2326 6247 7756 +к сч 70026(14), зп 1026(14) ; 02331 - 6110 0026 6000 1026 +к цикл 2331(14), уиа 2335(11) ; 02332 - 6370 2331 4640 2335 +к сч 1774, зп 1031 ; 02333 - 0010 1774 0000 1031 +к пб 2104, мода ; 02334 - 0300 2104 0220 0000 +к сч 1774, слц 2650 ; 02335 - 0010 1774 0013 2650 +к зп 1774, сч 1775 ; 02336 - 0000 1774 0010 1775 +к слц 2634, пв 2121(11) ; 02337 - 0013 2634 4710 2121 +к сч 2522, зп 502 ; 02340 - 0010 2522 0000 0502 +к уиа -37(6), мода ; 02341 - 3247 7741 0220 0000 +к сч 3537(6), зп 71777(6) ; 02342 - 3010 3537 3100 1777 +к цикл 2342(6), сч ; 02343 - 3370 2342 0010 0000 +к зп 72000, пб 70000 ; 02344 - 0100 2000 0307 0000 +к уиа 2345(7), пб 2367 ; 02345 - 3640 2345 0300 2367 +к уиа -2(3), сч ; 02346 - 1647 7776 0010 0000 +к слц 2546(3), цикл 2347(3) ; 02347 - 1413 2546 1770 2347 +к пб (10), мода ; 02350 - 4300 0000 0220 0000 +к сч 1774, и 2660 ; 02351 - 0010 1774 0011 2660 +к пе 2060, уиа 31(4) ; 02352 - 0270 2060 2240 0031 +к мода, пв 2144(6) ; 02353 - 0220 0000 3310 2144 +к зп 2534, сч 2533 ; 02354 - 0000 2534 0010 2533 +к и 2654, по 2402 ; 02355 - 0011 2654 0260 2402 +к сч 2534, и 2662 ; 02356 - 0010 2534 0011 2662 +к уиа 2452(5), пе 2404 ; 02357 - 2640 2452 0270 2404 +к сч 2534, и 2660 ; 02360 - 0010 2534 0011 2660 +к уиа 2466(5), пе 2366 ; 02361 - 2640 2466 0270 2366 +к сч 2534, и 2661 ; 02362 - 0010 2534 0011 2661 +к пе 2410, сч 2534 ; 02363 - 0270 2410 0010 2534 +к и 2652, уиа 2452(5) ; 02364 - 0011 2652 2640 2452 +к пе 2366, уиа 2452(5) ; 02365 - 0270 2366 2640 2452 +к уиа 2126(7), пв 2235(6) ; 02366 - 3640 2126 3310 2235 +к уиа -10(10), мода ; 02367 - 4247 7770 0220 0000 +к зп 1, цикл 2370(10) ; 02370 - 0000 0001 4370 2370 +к сч, рег ; 02371 - 0010 0000 0002 0000 +к уиа -5(10), мода ; 02372 - 4247 7773 0220 0000 +к мода (5), сч 5(10) ; 02373 - 2620 0000 4010 0005 +к рег 6(10), цикл 2373(10) ; 02374 - 4002 0006 4370 2373 +к сч, рег 7 ; 02375 - 0010 0000 0002 0007 +к уиа 76030(10), мода ; 02376 - 4247 6030 0220 0000 +к уиа 77526(3), мода ; 02377 - 1647 7526 0220 0000 +к сбр, цикл 2400(3) ; 02400 - 0020 0000 1770 2400 +к цикл 2377(10), пб (7) ; 02401 - 4370 2377 3700 0000 +к сч 2533, уиа 2430(5) ; 02402 - 0010 2533 2640 2430 +к и 2653, по 2366 ; 02403 - 0011 2653 0260 2366 +к уиа 1(4), пв 2144(6) ; 02404 - 2240 0001 3310 2144 +к мода, пв 2235(6) ; 02405 - 0220 0000 3310 2235 +к уиа 76030(10), пв 2377(7) ; 02406 - 4247 6030 3710 2377 +к уиа 2126(7), пб 2367 ; 02407 - 3640 2126 0300 2367 +к уиа 2452(5), пб 2366 ; 02410 - 2640 2452 0300 2366 +к уиа 2126(6), пб 2235 ; 02411 - 3240 2126 0300 2235 +к сч 1774, и 2660 ; 02412 - 0010 1774 0011 2660 +к по 2366, пв 2235(6) ; 02413 - 0260 2366 3310 2235 +к пб 2060, мода ; 02414 - 0300 2060 0220 0000 + +в 02415 +с 0000 0000 0000 0007 ; 02415 +с 0000 0000 0000 0003 ; 02416 +с 0000 0000 0000 1050 ; 02417 +с 0000 0000 0174 0000 ; 02420 +с 0000 0000 0000 2400 ; 02421 +с 0000 0000 0000 0000 ; 02422 +с 0000 0000 0000 7777 ; 02423 +с 0000 0000 0000 2003 ; 02424 +с 0000 0000 0000 2013 ; 02425 +с 0000 0000 0000 0000 ; 02426 +с 0000 0000 0000 0017 ; 02427 +с 2236 0400 4176 2000 ; 02430 +с 2220 0400 4044 0000 ; 02431 +с 2220 0400 4044 0000 ; 02432 +с 3636 0400 4044 0000 ; 02433 +с 2220 0400 4044 0000 ; 02434 +с 2236 3700 7434 0000 ; 02435 +с 0003 4376 2022 0000 ; 02436 +с 0004 2222 2220 0000 ; 02437 +с 0004 2222 2220 0000 ; 02440 +с 0004 2222 2220 0000 ; 02441 +с 0004 2222 2520 0000 ; 02442 +с 0003 4222 3060 0000 ; 02443 +с 3476 2046 3440 4000 ; 02444 +с 4252 0044 4244 4000 ; 02445 +с 4252 0044 4044 4000 ; 02446 +с 4252 0070 4044 4000 ; 02447 +с 4252 0044 4252 4000 ; 02450 +с 3452 0046 3461 4000 ; 02451 +с 0000 0021 0740 0000 ; 02452 +с 0000 0021 0420 0000 ; 02453 +с 0000 0037 0420 0000 ; 02454 +с 0000 0021 0740 0000 ; 02455 +с 0000 0021 0420 0000 ; 02456 +с 0000 0017 0740 0000 ; 02457 +с 2236 0046 6247 0040 ; 02460 +с 2220 0044 2250 4040 ; 02461 +с 2220 0044 2250 4040 ; 02462 +с 3636 0070 2270 4740 ; 02463 +с 2220 0044 2250 4440 ; 02464 +с 2236 0046 1647 0440 ; 02465 +с 0022 3604 0070 4440 ; 02466 +с 0022 2004 0044 4440 ; 02467 +с 0022 2004 0044 4470 ; 02470 +с 0036 3604 0072 7444 ; 02471 +с 0022 2004 0044 4444 ; 02472 +с 0022 3637 0070 3470 ; 02473 +с 2236 0400 3470 4044 ; 02474 +с 2220 0400 4244 4440 ; 02475 +с 2220 0400 4244 4440 ; 02476 +с 3636 0400 4270 4440 ; 02477 +с 2220 0400 4240 5240 ; 02500 +с 2236 3700 3474 6140 ; 02501 +с 4561 0213 7462 2422 ; 02502 +с 4501 0211 1112 2420 ; 02503 +с 4501 0251 1013 6434 ; 02504 +с 7561 0251 1022 2422 ; 02505 +с 4501 0251 1112 2422 ; 02506 +с 4567 6330 7061 6734 ; 02507 +с 0456 1021 3716 2240 ; 02510 +с 0450 1021 1101 2240 ; 02511 +с 0450 1025 1107 2270 ; 02512 +с 0756 1025 1111 2244 ; 02513 +с 0450 1025 1111 2244 ; 02514 +с 0456 7633 0711 3670 ; 02515 +с 0000 0757 0000 0000 ; 02516 +с 0000 2523 0000 0000 ; 02517 +с 0010 2425 0040 0021 ; 02520 +с 0010 2523 2700 0000 ; 02521 +с 0010 2523 1700 0000 ; 02522 +с 0000 0000 0000 0000 ; 02523 +с 0000 0000 0000 0030 ; 02524 +с 0000 0000 0000 0040 ; 02525 +с 0000 0000 0003 7777 ; 02526 +с 0000 0000 0000 1334 ; 02527 +с 0000 0000 0000 2340 ; 02530 +с 0000 0000 0007 7775 ; 02531 +с 0000 0000 0440 0020 ; 02532 +с 0017 0707 4005 0513 ; 02533 +с 1646 5273 4157 0513 ; 02534 +с 0007 7777 0000 0000 ; 02535 +с 0007 0707 0000 0000 ; 02536 +с 4000 0000 0000 0000 ; 02537 +с 0000 0000 0017 7777 ; 02540 +с 0000 0000 0000 0377 ; 02541 +с 0000 0000 0000 0000 ; 02542 +с 2740 0000 0000 4007 ; 02543 +с 3000 0000 0000 4005 ; 02544 +с 7760 0000 0000 0000 ; 02545 +с 7760 0000 0000 0000 ; 02546 +с 3000 0000 0000 4005 ; 02547 +с 7777 7400 0000 0000 ; 02550 +с 7760 0000 0000 0000 ; 02551 +с 3000 0000 0000 4005 ; 02552 +с 7777 7400 0000 0000 ; 02553 +с 0000 0000 0000 0000 ; 02554 + +в 02600 +с 0000 0000 0000 0000 ; 02600 +с 0000 0000 0000 0037 ; 02601 +с 0000 0000 0742 1025 ; 02602 +с 0000 0000 0021 0000 ; 02603 +с 0000 0000 0000 0000 ; 02604 +с 4000 0000 0000 0000 ; 02605 +с 2000 0000 0000 0000 ; 02606 +с 1000 0000 0000 0000 ; 02607 +с 0400 0000 0000 0000 ; 02610 +с 0200 0000 0000 0000 ; 02611 +с 0100 0000 0000 0000 ; 02612 +с 0040 0000 0000 0000 ; 02613 +с 0020 0000 0000 0000 ; 02614 +с 0010 0000 0000 0000 ; 02615 +с 0004 0000 0000 0000 ; 02616 +с 0002 0000 0000 0000 ; 02617 +с 0001 0000 0000 0000 ; 02620 +с 0000 4000 0000 0000 ; 02621 +с 0000 2000 0000 0000 ; 02622 +с 0000 1000 0000 0000 ; 02623 +с 0000 0400 0000 0000 ; 02624 +с 0000 0200 0000 0000 ; 02625 +с 0000 0100 0000 0000 ; 02626 +с 0000 0040 0000 0000 ; 02627 +с 0000 0020 0000 0000 ; 02630 +с 0000 0010 0000 0000 ; 02631 +с 0000 0004 0000 0000 ; 02632 +с 0000 0002 0000 0000 ; 02633 +с 0000 0001 0000 0000 ; 02634 +с 0000 0000 4000 0000 ; 02635 +с 0000 0000 2000 0000 ; 02636 +с 0000 0000 1000 0000 ; 02637 +с 0000 0000 0400 0000 ; 02640 +с 0000 0000 0200 0000 ; 02641 +с 0000 0000 0100 0000 ; 02642 +с 0000 0000 0040 0000 ; 02643 +с 0000 0000 0020 0000 ; 02644 +с 0000 0000 0010 0000 ; 02645 +с 0000 0000 0004 0000 ; 02646 +с 0000 0000 0002 0000 ; 02647 +с 0000 0000 0001 0000 ; 02650 +с 0000 0000 0000 4000 ; 02651 +с 0000 0000 0000 2000 ; 02652 +с 0000 0000 0000 1000 ; 02653 +с 0000 0000 0000 0400 ; 02654 +с 0000 0000 0000 0200 ; 02655 +с 0000 0000 0000 0100 ; 02656 +с 0000 0000 0000 0040 ; 02657 +с 0000 0000 0000 0020 ; 02660 +с 0000 0000 0000 0010 ; 02661 +с 0000 0000 0000 0004 ; 02662 +с 0000 0000 0000 0002 ; 02663 +с 0000 0000 0000 0001 ; 02664 + +в 03000 +к по 3002, мода ; 03000 - 0260 3002 0220 0000 +к ржа 3, пб 2015 ; 03001 - 0037 0003 0300 2015 +к уиа 3004(7), уиа 2466(5) ; 03002 - 3640 3004 2640 2466 +к пб 2367, мода ; 03003 - 0300 2367 0220 0000 +к слиа 1(1), пб 3004 ; 03004 - 0650 0001 0300 3004 + +в 03500 +с 0000 0560 0000 4005 ; 03500 +с 4000 0000 0000 4005 ; 03501 +с 0000 0000 0000 4005 ; 03502 +с 0000 0000 0000 4005 ; 03503 +с 0000 0000 0000 0006 ; 03504 +с 4000 0000 0000 0000 ; 03505 +с 0000 0000 0000 3320 ; 03506 +с 0000 0000 0000 0022 ; 03507 +с 0000 0000 0000 0021 ; 03510 +с 7760 0000 3760 0000 ; 03511 +с 0000 0000 0000 0000 ; 03512 +с 0000 0000 0000 0000 ; 03513 +с 0000 0000 0000 0000 ; 03514 +с 4000 0070 0004 0310 ; 03515 +с 1770 0000 0000 0003 ; 03516 +с 0000 0000 1600 4227 ; 03517 +с 3722 1066 0361 6435 ; 03520 +с 0000 0000 0000 0000 ; 03521 +с 7760 0000 0000 0000 ; 03522 +с 7760 0000 0000 3220 ; 03523 +с 0000 0000 1022 4005 ; 03524 +с 1240 0000 0000 0000 ; 03525 +с 1313 1413 1413 1413 ; 03526 +с 7777 4000 6000 0000 ; 03527 +с 7403 0000 0000 0000 ; 03530 +с 7777 7777 7777 7777 ; 03531 +с 0000 0017 7760 0000 ; 03532 +с 0000 0000 0000 0000 ; 03533 +с 0000 0000 0000 0000 ; 03534 +с 0000 0000 0000 0000 ; 03535 +с 0000 0000 7760 0000 ; 03536 +с 0000 0000 0000 0000 ; 03537 diff --git a/BESM6/dispak.ini b/BESM6/dispak.ini new file mode 100644 index 00000000..d182d028 --- /dev/null +++ b/BESM6/dispak.ini @@ -0,0 +1,92 @@ +! rm -f log.txt +set console log=log.txt +set console debug=log +;set cpu debug +;set mmu debug +;set drum debug +;set disk debug + +; +; Приводим барабаны в исходное состояние. +; +! rm -f drum1x.bin drum2x.bin +attach drum0 drum1x.bin +attach drum1 drum2x.bin + +; +; Создаем рабочий диск. +; +! ./formatdisk 2052 > 2052.bin + +; +; Подключаем диски. +; +attach -e disk7 sbor2053.bin +attach -e disk6 2052.bin +attach -e disk5 krab2063.bin +attach -e disk0 sbor2048.bin +attach -e disk1 svs2048.bin +attach -e disk2 alt2048.bin + +; +; Подключаем АЦПУ. +; +attach prn0 /dev/tty + +; +; Активируем операторский терминал, +; на который идут сообщения. +; +attach tty1 /dev/tty + +; +; Режимы по вкусу +; +;set tty1 jcuken,authbs +set tty1 authbs +set tty1 log=tty1.txt + +; +; Разрешаем подключение пользователей по telnet, порт 4199. +; +attach tty 4199 +set tty2 authbs +set tty3 authbs +set tty4 authbs +set tty5 authbs +set tty6 authbs +set tty7 authbs +set tty8 authbs +set tty9 authbs +set tty10 authbs +set tty11 authbs +set tty12 authbs +set tty13 authbs +set tty14 authbs +set tty15 authbs +set tty16 authbs +set tty17 authbs +set tty18 authbs +set tty19 authbs +set tty20 authbs +set tty21 authbs +set tty22 authbs +set tty23 authbs +set tty24 authbs + +; +; Включение БРС/БРЗ для совместимости. +; Замедляет работу на 20%. +; +;set mmu cache + +; +; Запуск ОС ДИСПАК. +; +load boot_dispak.b6 + +; Происходит контроль числа по адресу 1031 +d 1031 0 + +run 2000 +;quit diff --git a/BESM6/formatdisk.c b/BESM6/formatdisk.c new file mode 100755 index 00000000..b72c7b86 --- /dev/null +++ b/BESM6/formatdisk.c @@ -0,0 +1,63 @@ +/* + * formatdisk.c - A utility to produce blank BESM-6 disk images. + * + * Copyright (c) 2014 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 +#include +#include +#include "besm6_defs.h" + +#define TOTBLK 01767 + +int main(int argc, char ** argv) { + t_value control[4]; /* block (zone) number, key, userid, checksum */ + int diskno, blkno, word; + + if (argc != 2 || (diskno = atoi(argv[1])) < 2048 || diskno > 4095) { + fprintf(stderr, "Usage: formatdisk NNNN > diskNNNN.bin, where 2048 <= NNNN <= 4095\n"); + exit(1); + } + + control[1] = SET_CONVOL(0, CONVOL_NUMBER); + control[2] = SET_CONVOL(0, CONVOL_NUMBER); + control[3] = SET_CONVOL(0, CONVOL_NUMBER); + + control[1] |= 01370707LL << 24; /* Magic */ + control[1] |= diskno << 12; + + for (blkno = 0; blkno < TOTBLK; ++blkno) { + control[0] = SET_CONVOL((t_value)(2*blkno) << 36, CONVOL_NUMBER); + fwrite(control, sizeof(t_value), 4, stdout); + control[0] = SET_CONVOL((t_value)(2*blkno+1) << 36, CONVOL_NUMBER); + fwrite(control, sizeof(t_value), 4, stdout); + for (word = 0; word < 02000; ++word) { + fwrite(control+2, sizeof(t_value), 1, stdout); + } + } + exit(0); +} diff --git a/BESM6/test_alu.b6 b/BESM6/test_alu.b6 new file mode 100644 index 00000000..6ee7c1fa --- /dev/null +++ b/BESM6/test_alu.b6 @@ -0,0 +1,2425 @@ +; +; Тест арифметического устройства БЭСМ-6. +; Если все хорошо, бесконечно циклится, начиная с адреса 32013. +; +п 32000 + +в 32000 +к уиа 30000(1), слц 2011(1) +к мода, мода +к мода, мода +к мода, мода +к мода, мода +к мода, мода +к мода, мода +к пб 2012(1), мода +с 0 +с 0000010000000001 +к сч, зп -12 ; 2012 +к ржа, мода ; 2013 +к сч, по 2016(1) +к стоп 2014(1), мода +к сч 4412(1), сч ; 2016 +к по 2020(1), стоп 2016(1) +к сч, сч 4412(1) ; 2020 +к нтж 4412(1), по 2023(1) +к стоп 2020(1), мода +к сч 4412(1), нтж ; 2023 +к пе 2025(1), стоп 2023(1) +к сч, по 2026(1) ; 2025 +к сч 4412(1), пе 2030(1) ; 2026 +к стоп 2025(1), мода +к сч 4412(1), нтж 4412(1) ; 2030 +к сч, по 2033(1) +к стоп 2030(1), мода +к сч 4412(1), зп 7777 ; 2033 +к сч 7777, нтж 4412(1) +к по 2036(1), стоп 2033(1) +к зп 7777, сч 7777 ; 2036 +к нтж, по 2041(1) +к стоп 2036(1), мода +к сч, нтж ; 2041 +к по 2043(1), стоп 2041(1) +к сч 4412(1), нтж 4412(1) ; 2043 +к по 2045(1), стоп 2043(1) +к сч 4413(1), нтж 4413(1) ; 2045 +к по 2047(1), стоп 2045(1) +к сч 4414(1), нтж 4414(1) ; 2047 +к по 2051(1), стоп 2047(1) +к сч 4412(1), нтж ; 2051 +к нтж 4412(1), по 2054(1) +к стоп 2051(1), мода +к сч, нтж 4412(1) ; 2054 +к счмр, по 2057(1) +к стоп 2054(1), мода +к сч, нтж 4412(1) ; 2057 +к нтж 4412(1), по 2062(1) +к стоп 2057(1), мода +к сч 4412(1), нтж 4412(1) ; 2062 +к счмр, нтж 4412(1) +к по 2065(1), стоп 2062(1) +к сч 4415(1), нтж ; 2065 +к счмр, нтж 4415(1) +к по 2070(1), стоп 2065(1) +к сч 4416(1), нтж ; 2070 +к счмр, нтж 4416(1) +к по 2073(1), стоп 2070(1) +к сч 4417(1), нтж ; 2073 +к счмр, нтж 4417(1) +к по 2076(1), стоп 2073(1) +к сч 4420(1), нтж ; 2076 +к счмр, нтж 4420(1) +к по 2101(1), стоп 2076(1) +к сч 4421(1), нтж ; 2101 +к зп 7777, счмр +к нтж 4421(1), по 2105(1) +к стоп 2101(1), мода +к сч 4422(1), нтж 4422(1) ; 2105 +к счмр 1, нтж 4422(1) +к по 2110(1), стоп 2105(1) +к сч, и ; 2110 +к по 2112(1), стоп 2110(1) +к сч, и 4412(1) ; 2112 +к по 2114(1), стоп 2112(1) +к сч 4412(1), и 4412(1) ; 2114 +к нтж 4412(1), по 2117(1) +к стоп 2114(1), мода +к сч 4413(1), и 4412(1) ; 2117 +к нтж 4413(1), по 2122(1) +к стоп 2117(1), мода +к сч 4414(1), и 4412(1) ; 2122 +к нтж 4414(1), по 2125(1) +к стоп 2122(1), мода +к сч 4423(1), и 4423(1) ; 2125 +к нтж 4423(1), по 2130(1) +к стоп 2125(1), мода +к сч, или ; 2130 +к по 2132(1), стоп 2130(1) +к сч, или 4412(1) ; 2132 +к нтж 4412(1), по 2135(1) +к стоп 2132(1), мода +к сч 4412(1), или ; 2135 +к нтж 4412(1), по 2140(1) +к стоп 2135(1), мода +к сч 4412(1), или 4412(1) ; 2140 +к нтж 4412(1), по 2143(1) +к стоп 2140(1), мода +к сч 4413(1), или 4413(1) ; 2143 +к нтж 4413(1), по 2146(1) +к стоп 2143(1), мода +к сч 4414(1), или 4414(1) ; 2146 +к нтж 4414(1), по 2151(1) +к стоп 2146(1), мода +к сч 4412(1), слц ; 2151 +к по 2153(1), стоп 2151(1) +к сч 4412(1), слц 4412(1) ; 2153 +к нтж 4412(1), по 2156(1) +к стоп 2153(1), мода +к сч, слц 4412(1) ; 2156 +к нтж 4412(1), по 2161(1) +к стоп 2156(1), мода +к сч 4412(1), слц ; 2161 +к нтж 4412(1), по 2164(1) +к стоп 2161(1), мода +к сч 4424(1), слц 4412(1) ; 2164 +к нтж 4424(1), по 2167(1) +к стоп 2164(1), мода +к сч 4425(1), слц 4412(1) ; 2167 +к нтж 4425(1), по 2172(1) +к стоп 2167(1), мода +к сч 4413(1), слц 4413(1) ; 2172 +к нтж 4414(1), по 2175(1) +к стоп 2172(1), мода +к сч 4414(1), слц 4414(1) ; 2175 +к нтж 4413(1), по 2200(1) +к стоп 2175(1), мода +к сч, слц ; 2200 +к пе 2202(1), стоп 2200(1) +к сч 4426(1), сда 20 ; 2202 +к по 2204(1), стоп 2202(1) +к сч 4427(1), сда 102 ; 2204 +к нтж 4430(1), по 2207(1) +к стоп 2204(1), мода +к сч 4431(1), сда 77 ; 2207 +к нтж 4432(1), по 2212(1) +к стоп 2207(1), мода +к сч 4433(1), сда 160 ; 2212 +к счмр, нтж 4433(1) +к по 2215(1), стоп 2212(1) +к сч 4426(1), сда 130 ; 2215 +к счмр, нтж 4434(1) +к по 2220(1), стоп 2215(1) +к сч, сда 157 ; 2220 +к счмр, по 2223(1) +к стоп 2220(1), мода +к сч 4435(1), сда 20 ; 2223 +к счмр, нтж 4435(1) +к по 2226(1), стоп 2223(1) +к сч 4412(1), сда 20 ; 2226 +к счмр, нтж 4412(1) +к по 2231(1), стоп 2226(1) +к сч 4426(1), сда 20 ; 2231 +к сч 4412(1), счмр +к нтж 4426(1), по 2235(1) +к стоп 2231(1), мода +к сч 4414(1), сда 77 ; 2235 +к нтж 4436(1), по 2240(1) +к стоп 2235(1), мода +к сч 4413(1), сда 77 ; 2240 +к нтж 4414(1), по 2243(1) +к стоп 2240(1), мода +к сч 4412(1), сд 4437(1) ; 2243 +к по 2245(1), стоп 2243(1) +к сч 4412(1), сд 4440(1) ; 2245 +к по 2247(1), стоп 2245(1) +к сч 4414(1), сд 4441(1) ; 2247 +к нтж 4442(1), по 2252(1) +к стоп 2247(1), мода +к сч 4413(1), сд 4443(1) ; 2252 +к нтж 4436(1), по 2255(1) +к стоп 2252(1), мода +к сч 4414(1), сд 4444(1) ; 2255 +к нтж 4436(1), по 2260(1) +к стоп 2255(1), мода +к сч 4413(1), сд 4445(1) ; 2260 +к нтж 4414(1), по 2263(1) +к стоп 2260(1), мода +к сч 4412(1), сд 4440(1) ; 2263 +к счмр, нтж 4412(1) +к по 2266(1), стоп 2263(1) +к сч 4412(1), сд 4440(1) ; 2266 +к сч 4412(1), нтж 4412(1) +к по 2271(1), стоп 2266(1) +к сч 4412(1), сд 4440(1) ; 2271 +к сч 4412(1), счмр +к нтж 4412(1), по 2275(1) +к стоп 2271(1), мода +к сч 4412(1), мод 36431 ; 2275 +к нтж, по 2300(1) +к стоп 2275(1), мода +к сч 4446(1), рж 4447(1) ; 2300 +к нтж 4446(1), по 2303(1) +к стоп 2300(1), мода +к сч 4446(1), рж 4450(1) ; 2303 +к нтж 4446(1), по 2306(1) +к стоп 2303(1), мода +к сч 4451(1), рж ; 2306 +к нтж 4451(1), по 2311(1) +к стоп 2306(1), мода +к сч 4422(1), рж 4452(1) ; 2311 +к зп 7777, нтж 4422(1) +к по 2314(1), стоп 2311(1) +к сч 4453(1), ржа ; 2314 +к нтж 4453(1), по 2317(1) +к стоп 2314(1), мода +к сч 4412(1), нтж 4412(1) ; 2317 +к ржа 4, счмр +к нтж 4412(1), по 2323(1) +к стоп 2317(1), мода +к сч 4412(1), нтж 4412(1) ; 2323 +к счрж, счмр +к нтж 4412(1), по 2327(1) +к стоп 2323(1), мода +к ржа 77, сч 4454(1) ; 2327 +к сл 4454(1), ржа +к нтж 4455(1), по 2333(1) +к стоп 2327(1), мода +к сч, ржа 77 ; 2333 +к зп 7774, счрж 77 +к нтж 4456(1), по 2337(1) +к стоп 2333(1), мода +к сч, ржа ; 2337 +к по 2341(1), пб 2342(1) +к стоп 2337(1), мода ; 2341 +к сч 4437(1), ржа 30 ; 2342 +к пе 2344(1), стоп 2342(1) +к сч 4454(1), ржа 10 ; 2344 +к пе 2346(1), стоп 2344(1) +к сч 4412(1), пе 2350(1) ; 2346 +к стоп 2346(1), мода +к сч, счрж 77 ; 2350 +к нтж 4457(1), по 2353(1) +к стоп 2350(1), мода +к сч, сч ; 2353 +к или, счрж 77 +к нтж 4457(1), по 2357(1) +к стоп 2353(1), мода +к сч, слц 4412(1) ; 2357 +к счрж 77, нтж 4460(1) +к по 2362(1), стоп 2357(1) +к сч 4461(1), сч 4461(1) ; 2362 +к сда, сл +к счрж 77, нтж 4462(1) +к по 2366(1), стоп 2362(1) +к сч 4422(1), сд 4422(1) ; 2366 +к счрж 177, нтж 4457(1) +к по 2371(1), стоп 2366(1) +к сч, сч ; 2371 +к рж 4463(1), счрж 37 +к нтж 4463(1), по 2375(1) +к стоп 2371(1), мода +к сч, сч ; 2375 +к рж 4463(1), счрж +к нтж, по 2401(1) +к стоп 2375(1), мода +к сч, сч ; 2401 +к рж, счрж 4463(1) +к нтж, по 2405(1) +к стоп 2401(1), мода +к сч, ржа 77 ; 2405 +к счрж 77, нтж 4456(1) +к по 2410(1), стоп 2405(1) +к сч, ржа ; 2410 +к счрж 77, по 2413(1) +к стоп 2410(1), мода +к сч 4412(1), нтж ; 2413 +к ржа 77, счрж 77 +к нтж 4456(1), по 2417(1) +к стоп 2413(1), мода +к ржа, мода ; 2417 +к сч 4461(1), ржа 40 +к сч 4422(1), сл 4422(1) +к нтж 4454(1), ржа 4 +к по 2424(1), стоп 2420(1) +к сч, сч ; 2424 +к сбр, счрж 77 +к нтж 4457(1), по 2430(1) +к стоп 2424(1), мода +к сч 4422(1), нед 4422(1) ; 2430 +к счрж 177, нтж 4457(1) +к по 2433(1), стоп 2430(1) +к сч 4461(1), сч 4461(1) ; 2433 +к слп, сл +к счрж 77, нтж 4462(1) +к по 2437(1), стоп 2433(1) +к сч 4433(1), слпа 101 ; 2437 +к счрж 177, нтж 4460(1) +к по 2442(1), стоп 2437(1) +к ржа, сч 4433(1) ; 2442 +к слпа 100, счрж 177 +к нтж 4460(1), по 2446(1) +к стоп 2442(1), мода +к сч 4422(1), вчп 4422(1) ; 2446 +к счрж 177, нтж 4460(1) +к по 2451(1), стоп 2446(1) +к сч 4464(1), вчп 4465(1) ; 2451 +к счрж 77, нтж 4460(1) +к по 2454(1), стоп 2451(1) +к сч 4422(1), вчаб 4422(1) ; 2454 +к счрж 177, нтж 4462(1) +к по 2457(1), стоп 2454(1) +к сч 4461(1), сл ; 2457 +к сда, счрж 77 +к нтж 4457(1), по 2463(1) +к стоп 2457(1), мода +к сч 4461(1), знак ; 2463 +к счрж 77, нтж 4462(1) +к по 2466(1), стоп 2463(1) +к сч 4464(1), сл 4465(1) ; 2466 +к счрж 77, нтж 4462(1) +к по 2471(1), стоп 2466(1) +к сч 4466(1), сл ; 2471 +к сда, счмр +к счрж 77, нтж 4457(1) +к по 2475(1), стоп 2471(1) +к сч 4433(1), умн 4433(1) ; 2475 +к счрж 177, нтж 4460(1) +к по 2500(1), стоп 2475(1) +к сч 4433(1), умн 4433(1) ; 2500 +к счрж 177, нтж 4460(1) +к по 2503(1), стоп 2500(1) +к сда 100, по 2505(1) ; 2503 +к стоп 2503(1), мода +к сч 4467(1), сбр 4470(1) ; 2505 +к нтж 4471(1), по 2510(1) +к стоп 2505(1), мода +к сч 4472(1), рзб 4473(1) ; 2510 +к нтж 4474(1), по 2513(1) +к стоп 2510(1), мода +к сч 4412(1), рзб 4437(1) ; 2513 +к нтж 4437(1), по 2516(1) +к стоп 2513(1), мода +к сч 4475(1), нед 4476(1) ; 2516 +к нтж 4477(1), по 2521(1) +к стоп 2516(1), мода +к сч 4475(1), нед 4476(1) ; 2521 +к счмр, нтж 4500(1) +к по 2524(1), стоп 2521(1) +к сч 4426(1), чед 4501(1) ; 2524 +к нтж 4502(1), по 2527(1) +к стоп 2524(1), мода +к сч 4503(1), слп 4504(1) ; 2527 +к нтж 4505(1), по 2532(1) +к стоп 2527(1), мода +к сч 4506(1), слп 4507(1) ; 2532 +к нтж 4433(1), по 2535(1) +к стоп 2532(1), мода +к сч 4461(1), слп ; 2535 +к нтж 4461(1), по 2540(1) +к стоп 2535(1), мода +к сч 4452(1), слп 4510(1) ; 2540 +к нтж 4511(1), по 2543(1) +к стоп 2540(1), мода +к сч 4512(1), слп 4476(1) ; 2543 +к нтж 4513(1), по 2546(1) +к стоп 2543(1), мода +к сч 4423(1), слп 4423(1) ; 2546 +к нтж 4461(1), по 2551(1) +к стоп 2546(1), мода +к сч 4500(1), слп 4433(1) ; 2551 +к нтж 4514(1), по 2554(1) +к стоп 2551(1), мода +к сч 4515(1), слп 4515(1) ; 2554 +к нтж 4506(1), по 2557(1) +к стоп 2554(1), мода +к сч 4476(1), слп 4512(1) ; 2557 +к нтж 4516(1), по 2562(1) +к стоп 2557(1), мода +к сч 4433(1), слпа 177 ; 2562 +к нтж 4422(1), по 2565(1) +к стоп 2562(1), мода +к сч 4453(1), слпа 140 ; 2565 +к нтж 4517(1), по 2570(1) +к стоп 2565(1), мода +к сч 4520(1), вчп 4421(1) ; 2570 +к нтж 4521(1), по 2573(1) +к стоп 2570(1), мода +к сч 4422(1), вчп 4466(1) ; 2573 +к нтж 4433(1), по 2576(1) +к стоп 2573(1), мода +к сч 4522(1), вчп 4523(1) ; 2576 +к нтж 4461(1), по 2601(1) +к стоп 2576(1), мода +к сч 4422(1), вчп 4412(1) ; 2601 +к нтж 4433(1), по 2604(1) +к стоп 2601(1), мода +к сч 4422(1), вчп 4466(1) ; 2604 +к нтж 4433(1), по 2607(1) +к стоп 2604(1), мода +к сч 4506(1), вчп ; 2607 +к нтж 4422(1), по 2612(1) +к стоп 2607(1), мода +к сч 4454(1), вчп 4507(1) ; 2612 +к нтж, по 2615(1) +к стоп 2612(1), мода +к сч 4524(1), вчп ; 2615 +к нтж 4422(1), по 2620(1) +к стоп 2615(1), мода +к сч 4412(1), нтж 4525(1) ; 2620 +к вчпа 101, нтж 4526(1) +к по 2623(1), стоп 2620(1) +к сч 4465(1), сл 4527(1) ; 2623 +к нтж 4530(1), по 2626(1) +к стоп 2623(1), мода +к сч 4531(1), сл 4532(1) ; 2626 +к нтж 4533(1), по 2631(1) +к стоп 2626(1), мода +к сч 4515(1), сл 4534(1) ; 2631 +к нтж 4535(1), по 2634(1) +к стоп 2631(1), мода +к сч 4536(1), сл 4537(1) ; 2634 +к нтж 4461(1), по 2637(1) +к стоп 2634(1), мода +к сч 4471(1), сл 4466(1) ; 2637 +к нтж 4471(1), по 2642(1) +к стоп 2637(1), мода +к сч 4540(1), сл 4541(1) ; 2642 +к нтж 4542(1), по 2645(1) +к стоп 2642(1), мода +к сч 4543(1), сл 4433(1) ; 2645 +к нтж 4544(1), по 2650(1) +к стоп 2645(1), мода +к сч 4545(1), сл 4512(1) ; 2650 +к нтж 4546(1), по 2653(1) +к стоп 2650(1), мода +к сч 4512(1), сл 4512(1) ; 2653 +к нтж 4547(1), по 2656(1) +к стоп 2653(1), мода +к сч 4512(1), сл 4550(1) ; 2656 +к нтж 4551(1), по 2661(1) +к стоп 2656(1), мода +к сч 4527(1), сл 4532(1) ; 2661 +к нтж 4552(1), по 2664(1) +к стоп 2661(1), мода +к сч 4553(1), сл 4554(1) ; 2664 +к нтж 4555(1), по 2667(1) +к стоп 2664(1), мода +к сч 4435(1), сл 4556(1) ; 2667 +к нтж 4557(1), по 2672(1) +к стоп 2667(1), мода +к сч 4560(1), сл 4554(1) ; 2672 +к нтж 4561(1), по 2675(1) +к стоп 2672(1), мода +к сч 4562(1), сл 4512(1) ; 2675 +к нтж 4433(1), по 2700(1) +к стоп 2675(1), мода +к сч 4554(1), сл 4553(1) ; 2700 +к нтж 4555(1), по 2703(1) +к стоп 2700(1), мода +к сч 4554(1), сл 4433(1) ; 2703 +к нтж 4563(1), по 2706(1) +к стоп 2703(1), мода +к сч 4564(1), сл 4565(1) ; 2706 +к нтж 4566(1), по 2711(1) +к стоп 2706(1), мода +к сч 4567(1), сл 4454(1) ; 2711 +к нтж 4570(1), по 2714(1) +к стоп 2711(1), мода +к сч 4571(1), сл 4572(1) ; 2714 +к нтж 4573(1), по 2717(1) +к стоп 2714(1), мода +к сч 4574(1), сл 4575(1) ; 2717 +к нтж 4576(1), по 2722(1) +к стоп 2717(1), мода +к сч 4422(1), сл 4465(1) ; 2722 +к нтж 4577(1), по 2725(1) +к стоп 2722(1), мода +к сч 4422(1), сл 4465(1) ; 2725 +к нтж 4577(1), по 2730(1) +к стоп 2725(1), мода +к сч 4461(1), сл 4600(1) ; 2730 +к нтж 4600(1), по 2733(1) +к стоп 2730(1), мода +к сч 4601(1), сл 4600(1) ; 2733 +к нтж 4600(1), по 2736(1) +к стоп 2733(1), мода +к сч 4602(1), сл 4603(1) ; 2736 +к нтж 4603(1), по 2741(1) +к стоп 2736(1), мода +к сч 4523(1), сл 4532(1) ; 2741 +к счмр 100, нтж 4604(1) +к по 2744(1), стоп 2741(1) +к сч 4564(1), сл 4565(1) ; 2744 +к счмр 100, нтж 4455(1) +к по 2747(1), стоп 2744(1) +к сч 4574(1), сл 4575(1) ; 2747 +к счмр 100, нтж 4455(1) +к по 2752(1), стоп 2747(1) +к сч 4605(1), сл 4606(1) ; 2752 +к счмр 1, нтж 4544(1) +к по 2755(1), стоп 2752(1) +к сч 4541(1), сл 4530(1) ; 2755 +к счмр, по 2760(1) +к стоп 2755(1), мода +к сч 4527(1), сл 4532(1) ; 2760 +к счмр 100, нтж 4604(1) +к по 2763(1), стоп 2760(1) +к сч 4465(1), ржа 2 ; 2763 +к сл 4422(1), нтж 4607(1) +к по 2766(1), стоп 2763(1) +к сч 4461(1), рж 4610(1) ; 2766 +к сч 4512(1), сл 4611(1) +к нтж 4611(1), по 2772(1) +к стоп 2766(1), мода +к ржа, мода ; 2772 +к сч 4612(1), сл 4613(1) +к нтж 4614(1), по 2776(1) +к стоп 2773(1), мода +к сч 4612(1), сл 4615(1) ; 2776 +к нтж 4616(1), по 3001(1) +к стоп 2776(1), мода +к сч 4421(1), сл 4613(1) ; 3001 +к нтж 4617(1), по 3004(1) +к стоп 3001(1), мода +к сч 4421(1), сл 4615(1) ; 3004 +к нтж 4620(1), по 3007(1) +к стоп 3004(1), мода +к сч 4613(1), сл 4612(1) ; 3007 +к нтж 4614(1), по 3012(1) +к стоп 3007(1), мода +к сч 4615(1), сл 4612(1) ; 3012 +к нтж 4616(1), по 3015(1) +к стоп 3012(1), мода +к сч 4613(1), сл 4421(1) ; 3015 +к нтж 4617(1), по 3020(1) +к стоп 3015(1), мода +к сч 4615(1), сл 4421(1) ; 3020 +к нтж 4620(1), по 3023(1) +к стоп 3020(1), мода +к сч 4621(1), сл 4622(1) ; 3023 +к нтж 4623(1), по 3026(1) +к стоп 3023(1), мода +к сч 4624(1), сл 4622(1) ; 3026 +к нтж 4625(1), по 3031(1) +к стоп 3026(1), мода +к сч 4626(1), сл 4622(1) ; 3031 +к нтж 4627(1), по 3034(1) +к стоп 3031(1), мода +к сч 4630(1), сл 4631(1) ; 3034 +к нтж 4630(1), по 3037(1) +к стоп 3034(1), мода +к сч 4630(1), сл 4632(1) ; 3037 +к нтж 4630(1), по 3042(1) +к стоп 3037(1), мода +к сч 4605(1), вч 4433(1) ; 3042 +к нтж 4605(1), по 3045(1) +к стоп 3042(1), мода +к сч 4611(1), вч 4512(1) ; 3045 +к нтж 4544(1), по 3050(1) +к стоп 3045(1), мода +к сч 4612(1), вч 4613(1) ; 3050 +к нтж 4633(1), по 3053(1) +к стоп 3050(1), мода +к сч 4612(1), вч 4615(1) ; 3053 +к нтж 4634(1), по 3056(1) +к стоп 3053(1), мода +к сч 4421(1), вч 4613(1) ; 3056 +к нтж 4635(1), по 3061(1) +к стоп 3056(1), мода +к сч 4421(1), вч 4615(1) ; 3061 +к нтж 4636(1), по 3064(1) +к стоп 3061(1), мода +к сч 4630(1), вч 4631(1) ; 3064 +к нтж 4630(1), по 3067(1) +к стоп 3064(1), мода +к сч 4630(1), вч 4632(1) ; 3067 +к нтж 4630(1), по 3072(1) +к стоп 3067(1), мода +к сч 4526(1), вч 4637(1) ; 3072 +к счмр 100, нтж 4640(1) +к по 3075(1), стоп 3072(1) +к сч 4641(1), вч 4642(1) ; 3075 +к нтж 4643(1), по 3100(1) +к стоп 3075(1), мода +к сч 4641(1), вч 4642(1) ; 3100 +к счмр 100, нтж 4644(1) +к по 3103(1), стоп 3100(1) +к сч 4527(1), вч 4532(1) ; 3103 +к счмр 100, нтж 4645(1) +к по 3106(1), стоп 3103(1) +к сч 4541(1), вч 4530(1) ; 3106 +к счмр, по 3111(1) +к стоп 3106(1), мода +к сч 4412(1), нтж 4412(1) ; 3111 +к сч 4641(1), вч 4642(1) +к счмр 160, нтж 4646(1) +к по 3115(1), стоп 3111(1) +к сч 4454(1), вчоб 4433(1) ; 3115 +к нтж 4647(1), по 3120(1) +к стоп 3115(1), мода +к сч 4454(1), вчоб 4433(1) ; 3120 +к счмр 100, нтж 4650(1) +к по 3123(1), стоп 3120(1) +к сч 4651(1), вчаб 4555(1) ; 3123 +к нтж 4652(1), по 3126(1) +к стоп 3123(1), мода +к сч 4433(1), вчаб 4454(1) ; 3126 +к нтж 4647(1), по 3131(1) +к стоп 3126(1), мода +к сч 4433(1), вчаб 4653(1) ; 3131 +к нтж 4654(1), по 3134(1) +к стоп 3131(1), мода +к сч 4655(1), вчаб 4656(1) ; 3134 +к нтж 4657(1), по 3137(1) +к стоп 3134(1), мода +к сч 4433(1), вчаб 4454(1) ; 3137 +к нтж 4647(1), по 3142(1) +к стоп 3137(1), мода +к сч 4655(1), вчаб 4656(1) ; 3142 +к счмр 100, нтж 4455(1) +к по 3145(1), стоп 3142(1) +к сч 4433(1), вчаб 4454(1) ; 3145 +к счмр 100, нтж 4650(1) +к по 3150(1), стоп 3145(1) +к сч 4452(1), знак ; 3150 +к нтж 4452(1), по 3153(1) +к стоп 3150(1), мода +к сч 4433(1), знак 4437(1) ; 3153 +к нтж 4654(1), по 3156(1) +к стоп 3153(1), мода +к сч 4562(1), умн 4433(1) ; 3156 +к нтж 4660(1), по 3161(1) +к стоп 3156(1), мода +к сч 4661(1), умн 4452(1) ; 3161 +к нтж 4661(1), по 3164(1) +к стоп 3161(1), мода +к сч 4555(1), умн 4653(1) ; 3164 +к нтж 4560(1), по 3167(1) +к стоп 3164(1), мода +к сч 4554(1), умн 4560(1) ; 3167 +к нтж 4554(1), по 3172(1) +к стоп 3167(1), мода +к сч 4555(1), умн 4662(1) ; 3172 +к нтж 4663(1), по 3175(1) +к стоп 3172(1), мода +к сч 4664(1), умн 4560(1) ; 3175 +к нтж 4665(1), по 3200(1) +к стоп 3175(1), мода +к сч 4413(1), умн 4662(1) ; 3200 +к нтж 4666(1), по 3203(1) +к стоп 3200(1), мода +к сч 4414(1), умн 4662(1) ; 3203 +к нтж 4667(1), по 3206(1) +к стоп 3203(1), мода +к сч 4466(1), умн 4512(1) ; 3206 +к нтж 4461(1), по 3211(1) +к стоп 3206(1), мода +к сч 4670(1), умн 4543(1) ; 3211 +к нтж 4671(1), по 3214(1) +к стоп 3211(1), мода +к сч 4672(1), умн 4543(1) ; 3214 +к нтж 4673(1), по 3217(1) +к стоп 3214(1), мода +к сч 4674(1), умн 4675(1) ; 3217 +к нтж 4676(1), по 3222(1) +к стоп 3217(1), мода +к сч 4677(1), умн 4700(1) ; 3222 +к нтж 4701(1), по 3225(1) +к стоп 3222(1), мода +к сч 4702(1), умн 4543(1) ; 3225 +к нтж 4703(1), по 3230(1) +к стоп 3225(1), мода +к сч 4704(1), умн 4433(1) ; 3230 +к нтж 4705(1), по 3233(1) +к стоп 3230(1), мода +к сч 4615(1), умн 4706(1) ; 3233 +к нтж 4707(1), по 3236(1) +к стоп 3233(1), мода +к сч 4710(1), умн 4615(1) ; 3236 +к нтж 4711(1), по 3241(1) +к стоп 3236(1), мода +к сч 4712(1), умн 4615(1) ; 3241 +к нтж 4647(1), по 3244(1) +к стоп 3241(1), мода +к сч 4712(1), умн 4636(1) ; 3244 +к нтж 4713(1), по 3247(1) +к стоп 3244(1), мода +к сч 4714(1), умн 4560(1) ; 3247 +к нтж 4714(1), по 3252(1) +к стоп 3247(1), мода +к сч 4715(1), умн 4716(1) ; 3252 +к нтж 4717(1), по 3255(1) +к стоп 3252(1), мода +к сч 4720(1), умн 4721(1) ; 3255 +к нтж 4722(1), по 3260(1) +к стоп 3255(1), мода +к сч 4454(1), умн 4452(1) ; 3260 +к нтж 4454(1), по 3263(1) +к стоп 3260(1), мода +к сч 4723(1), умн 4554(1) ; 3263 +к нтж 4724(1), по 3266(1) +к стоп 3263(1), мода +к сч 4555(1), умн 4653(1) ; 3266 +к счмр 100, нтж 4461(1) +к по 3271(1), стоп 3266(1) +к сч 4554(1), умн 4560(1) ; 3271 +к счмр 100, нтж 4544(1) +к по 3274(1), стоп 3271(1) +к сч 4555(1), умн 4662(1) ; 3274 +к счмр 100, нтж 4662(1) +к по 3277(1), стоп 3274(1) +к сч 4413(1), умн 4662(1) ; 3277 +к счмр 100, нтж 4725(1) +к по 3302(1), стоп 3277(1) +к сч 4672(1), умн 4662(1) ; 3302 +к счмр, нтж 4726(1) +к по 3305(1), стоп 3302(1) +к сч 4414(1), умн 4662(1) ; 3305 +к счмр, нтж 4727(1) +к по 3310(1), стоп 3305(1) +к сч 4614(1), умн 4662(1) ; 3310 +к счмр 100, нтж 4730(1) +к по 3313(1), стоп 3310(1) +к сч 4731(1), умн 4662(1) ; 3313 +к счмр, нтж 4732(1) +к по 3316(1), стоп 3313(1) +к ржа 1, сч 4702(1) ; 3316 +к умн 4543(1), счмр 100 +к нтж 4733(1), по 3322(1) +к стоп 3316(1), мода +к ржа, сч 4714(1) ; 3322 +к умн 4542(1), счмр 100 +к нтж 4734(1), по 3326(1) +к стоп 3322(1), мода +к сч 4735(1), умн 4716(1) ; 3326 +к счмр 100, нтж 4736(1) +к по 3331(1), стоп 3326(1) +к сч 4720(1), умн 4721(1) ; 3331 +к счмр, нтж 4737(1) +к по 3334(1), стоп 3331(1) +к сч 4704(1), умн 4433(1) ; 3334 +к счмр 100, нтж +к по 3337(1), стоп 3334(1) +к сч 4615(1), умн 4706(1) ; 3337 +к счмр 100, нтж 4740(1) +к по 3342(1), стоп 3337(1) +к сч 4714(1), умн 4560(1) ; 3342 +к счмр 100, нтж 4741(1) +к по 3345(1), стоп 3342(1) +к сч 4715(1), умн 4716(1) ; 3345 +к счмр 100, нтж 4742(1) +к по 3350(1), стоп 3345(1) +к сч 4720(1), умн 4721(1) ; 3350 +к счмр 100, нтж 4743(1) +к по 3353(1), стоп 3350(1) +к сч 4561(1), умн 4561(1) ; 3353 +к счмр, нтж 4461(1) +к по 3356(1), стоп 3353(1) +к сч 4561(1), умн 4563(1) ; 3356 +к счмр 77, нтж 4433(1) +к по 3361(1), стоп 3356(1) +к ржа 1, сч 4512(1) ; 3361 +к умн 4512(1), нтж 4512(1) +к по 3364(1), стоп 3361(1) +к сч 4744(1), умн 4512(1) ; 3364 +к нтж 4512(1), по 3367(1) +к стоп 3364(1), мода +к сч 4745(1), умн 4512(1) ; 3367 +к нтж 4512(1), по 3372(1) +к стоп 3367(1), мода +к сч 4746(1), умн 4512(1) ; 3372 +к нтж 4512(1), по 3375(1) +к стоп 3372(1), мода +к сч 4507(1), умн 4507(1) ; 3375 +к нтж 4747(1), по 3400(1) +к стоп 3375(1), мода +к ржа 2, сч 4723(1) ; 3400 +к умн 4554(1), нтж 4724(1) +к по 3403(1), стоп 3400(1) +к ржа, мода ; 3403 +к сч 4750(1), дел 4452(1) +к нтж 4750(1), по 3407(1) +к стоп 3404(1), мода +к сч 4751(1), дел 4751(1) ; 3407 +к нтж 4452(1), по 3412(1) +к стоп 3407(1), мода +к сч 4751(1), дел 4752(1) ; 3412 +к нтж 4653(1), по 3415(1) +к стоп 3412(1), мода +к сч 4452(1), дел 4653(1) ; 3415 +к нтж 4653(1), по 3420(1) +к стоп 3415(1), мода +к сч 4561(1), дел 4553(1) ; 3420 +к нтж 4653(1), по 3423(1) +к стоп 3420(1), мода +к сч 4753(1), дел 4751(1) ; 3423 +к нтж 4754(1), по 3426(1) +к стоп 3423(1), мода +к сч 4753(1), дел 4653(1) ; 3426 +к нтж 4755(1), по 3431(1) +к стоп 3426(1), мода +к сч 4756(1), дел 4757(1) ; 3431 +к нтж 4760(1), по 3434(1) +к стоп 3431(1), мода +к сч 4761(1), дел 4762(1) ; 3434 +к нтж 4763(1), по 3437(1) +к стоп 3434(1), мода +к сч 4764(1), дел 4765(1) ; 3437 +к нтж 4766(1), по 3442(1) +к стоп 3437(1), мода +к сч 4767(1), дел 4770(1) ; 3442 +к нтж 4653(1), по 3445(1) +к стоп 3442(1), мода +к сч 4446(1), дел 4771(1) ; 3445 +к нтж 4653(1), по 3450(1) +к стоп 3445(1), мода +к сч 4771(1), дел 4452(1) ; 3450 +к нтж 4771(1), по 3453(1) +к стоп 3450(1), мода +к сч 4753(1), дел 4772(1) ; 3453 +к нтж 4773(1), по 3456(1) +к стоп 3453(1), мода +к сч 4774(1), сда 103 ; 3456 +к пе 3460(1), пб 3461(1) +к стоп 3456(1), мода ; 3460 +к сч 4774(1), по 103 ; 3461 +к по 3463(1), пб 3464(1) +к стоп 3461(1), мода ; 3463 +к сч 4542(1), сл 4560(1) ; 3464 +к пе 3467(1), нтж 4775(1) +к по 3470(1), стоп 3464(1) +к стоп 33464(17), мода ; 3467 +к сч 4776(1), сл 4554(1) ; 3470 +к по 3473(1), нтж 4777(1) +к по 3474(1), мода +к стоп 3470(1), мода ; 3473 +к сч 4542(1), зп 7777 ; 3474 +к сч 4560(1), зп 7776 +к сч 7777, сл 7776 +к сда 31, сл 4726(1) +к нтж 5000(1), по 3502(1) +к стоп 3474(1), мода +к сч 7777, сл 7776 ; 3502 +к сда 157, нед 4412(1) +к нтж 4637(1), по 3506(1) +к стоп 3502(1), мода +к сч 7777, сл 7776 ; 3506 +к сда 32, вчаб 5001(1) +к нтж 5002(1), по 3512(1) +к стоп 3506(1), мода +к сч 7777, сл 7776 ; 3512 +к сда 31, вчаб 4452(1) +к нтж 4555(1), по 3516(1) +к стоп 3512(1), мода +к сч 7777, сл 7776 ; 3516 +к сда 31, вч 4452(1) +к нтж 4555(1), по 3522(1) +к стоп 3516(1), мода +к сч 5003(1), сда 77 ; 3522 +к сл 4651(1), нтж 4525(1) +к по 3525(1), стоп 3522(1) +к сч 4466(1), сл 4461(1) ; 3525 +к сч 4554(1), сл 4553(1) +к сл 4512(1), нтж 5004(1) +к по 3531(1), стоп 3525(1) +к сч 4542(1), сл 4433(1) ; 3531 +к сч 4412(1), слц 4424(1) +к нтж 4424(1), по 3535(1) +к стоп 3531(1), мода +к сч 5005(1), сл 4433(1) ; 3535 +к сда 30, нтж 4437(1) +к по 3540(1), стоп 3535(1) +к сч 5005(1), сл 4433(1) ; 3540 +к слц 4423(1), и 4412(1) +к нтж 4541(1), по 3544(1) +к стоп 3540(1), мода +к сч 5005(1), сл 4433(1) ; 3544 +к слц 4423(1), нтж 4541(1) +к по 3547(1), стоп 3544(1) +к сч 5005(1), сл 4433(1) ; 3547 +к сч 5006(1), сд 5007(1) +к знак 4437(1), нтж 4654(1) +к по 3553(1), стоп 3547(1) +к сч 5005(1), сл 4433(1) ; 3553 +к сч 4452(1), умн 5010(1) +к умн 4452(1), нтж 5010(1) +к по 3557(1), стоп 3553(1) +к сч 5005(1), сл 4433(1) ; 3557 +к сч 4424(1), сда 31 +к дел 4454(1), нтж 4452(1) +к по 3563(1), стоп 3557(1) +к сч 5011(1), зп 7777 ; 3563 +к сч 4560(1), зп 7776 +к сч 4750(1), зп 7775 +к сч 7777, сл 7776 +к сда, сч 7775 +к сл 4461(1), нтж 7775 +к по 3572(1), стоп 3563(1) +к сч 7777, сл 7776 ; 3572 +к сда, сл 7775 +к вч 4461(1), нтж 7775 +к по 3576(1), стоп 3572(1) +к сч 5012(1), зп 7775 ; 3576 +к сч 7777, сл 7776 +к вч 7775, вчаб 7775 +к нтж 5013(1), по 3603(1) +к стоп 3576(1), мода +к сч 7777, сл 7776 ; 3603 +к вч 7775, вчоб 5014(1) +к нтж 5015(1), по 3607(1) +к стоп 3603(1), мода +к сч 4412(1), зп 7775 ; 3607 +к сч 7777, сл 7776 +к и 4412(1), счмр +к по 3613(1), стоп 3607(1) +к сч 7777, сл 7776 ; 3613 +к рзб 7775, зп 7774 +к нтж 5014(1), по 3617(1) +к стоп 3613(1), мода +к сч 7777, сл 7776 ; 3617 +к рзб 7775, уи 5 +к нтж 7774, по 3623(1) +к стоп 3617(1), мода +к сч 7775, зп 7774 ; 3623 +к сч 7777, сл 7776 +к зп 7774, сч 7774 +к нтж 5014(1), по 3630(1) +к стоп 3623(1), мода +к сч 7777, сл 7776 ; 3630 +к и 7775, нтж 7774 +к по 3633(1), стоп 3630(1) +к сч 7777, сл 7776 ; 3633 +к и 7775, слц 7775 +к нтж 7774, по 3637(1) +к стоп 3633(1), мода +к сч 7777, сл 7776 ; 3637 +к или 7775, нтж 7775 +к по 3642(1), стоп 3637(1) +к сч 7777, сл 7776 ; 3642 +к сч 7775, и 7775 +к нтж 7775, по 3646(1) +к стоп 3642(1), мода +к сч 4437(1), зп 7774 ; 3646 +к сч 7777, сл 7776 +к слц 7775, знак 7774 +к нтж 5005(1), по 3653(1) +к стоп 3646(1), мода +к сч 7777, сл 7776 ; 3653 +к и, или 7775 +к нтж 7775, по 3657(1) +к стоп 3653(1), мода +к сч 4433(1), зп 7773 ; 3657 +к сч 7777, сл 7776 +к знак 7774, дел 7773 +к нтж 4542(1), по 3664(1) +к стоп 3657(1), мода +к сч 4452(1), зп 7773 ; 3664 +к сч 7777, сл 7776 +к слц 7775, умн 7773 +к нтж 5014(1), по 3671(1) +к стоп 3664(1), мода +к сч 7777, сл 7776 ; 3671 +к вчпа 146, слпа 146 +к нтж 5014(1), по 3675(1) +к стоп 3671(1), мода +к сч 4560(1), зп 7774 ; 3675 +к сч 7777, сл 7776 +к сл 7774, счмр 117 +к нтж 5016(1), по 3702(1) +к стоп 3675(1), мода +к сч 5017(1), зп 7774 ; 3702 +к сч 7777, сл 7776 +к сл 7774, рж +к нтж 4670(1), по 3707(1) +к стоп 3702(1), мода +к сч 5020(1), зп 7774 ; 3707 +к сч 7777, сл 7776 +к слп 7773, вчп 7774 +к нтж 4555(1), по 3714(1) +к стоп 3707(1), мода +к сч 4464(1), зп 7774 ; 3714 +к сч 7777, сл 7776 +к слц 7775, сд 7774 +к нтж 5021(1), по 3721(1) +к стоп 3714(1), мода +к сч 4433(1), зп 7774 ; 3721 +к сч 7777, сл 7776 +к слп 7774, счрж 177 +к нтж 4460(1), по 3726(1) +к стоп 3721(1), мода +к сч 5022(1), зп 7773 ; 3726 +к сч 7777, сл 7776 +к чед 7773, сбр 7775 +к нтж 5023(1), по 3733(1) +к стоп 3726(1), мода +к сч 4543(1), зп 7773 ; 3733 +к сч 7777, сл 7776 +к слп 7774, рзб 7775 +к нтж 5014(1), по 3740(1) +к стоп 3733(1), мода +к сч 7777, сл 7776 ; 3740 +к чед, нед +к нтж 5024(1), по 3744(1) +к стоп 3740(1), мода +к сч 7777, сл 7776 ; 3744 +к сбр 7775, чед +к нтж 4477(1), по 3750(1) +к стоп 3744(1), мода +к сч 7777, сл 7776 ; 3750 +к слц 7775, чед +к нтж 4477(1), по 3754(1) +к стоп 3750(1), мода +к сч 5014(1), зп 7774 ; 3754 +к сч 7777, сл 7776 +к нтж 7774, по 3760(1) +к стоп 3754(1), мода +к сч 5025(1), зп 7773 ; 3760 +к сч 7777, сл 7776 +к умн 7773, уи 5 +к счи 5, нтж 5026(1) +к по 3765(1), стоп 3760(1) +к сч 5027(1), зп 7773 ; 3765 +к сч 7777, сл 7776 +к сбр 7775, мод 7773 +к нтж, по 3772(1) +к стоп 3765(1), мода +к сч 7777, сл 7776 ; 3772 +к сда 151, и 7775 +к нтж 5030(1), по 3776(1) +к стоп 3772(1), мода +к сч 7777, сл 7776 ; 3776 +к и 7775, слц 7775 +к нтж 5014(1), по 4002(1) +к стоп 3776(1), мода +к сч 7775, мод 5027(1) ; 4002 +к зп, сч 7774 +к нтж 7775, по 4006(1) +к стоп 4002(1), мода +к сч 4466(1), зп 7774 ; 4006 +к сч 7774, сл +к сч 5026(1), слц 4424(1) +к слп 7775, нтж 5031(1) +к по 4013(1), стоп 4006(1) +к сч 7774, сл ; 4013 +к сч 5032(1), слц 4424(1) +к умн 7775, нтж 5033(1) +к по 4017(1), стоп 4013(1) +к сч 4532(1), слп 4421(1) ; 4017 +к слц 4437(1), нтж 5034(1) +к по 4022(1), стоп 4017(1) +к сч 7774, сл 4461(1) ; 4022 +к сч 5035(1), слц 4424(1) +к вчп 4451(1), нтж 5003(1) +к по 4026(1), стоп 4022(1) +к сч 7774, сл 4461(1) ; 4026 +к сч 5035(1), слц 4424(1) +к дел 4505(1), нтж 5036(1) +к по 4032(1), стоп 4026(1) +к слп 4412(1), нтж 4461(1) ; 4032 +к по 4034(1), стоп 4026(1) +к вчп 4412(1), нтж 4461(1) ; 4034 +к по 4036(1), стоп 4034(1) +к сч 4532(1), вчп 4421(1) ; 4036 +к слц 4437(1), нтж 5037(1) +к по 4041(1), стоп 4036(1) +к сч 7774, сл 4461(1) ; 4041 +к сч 5040(1), сда 32 +к сл 4532(1), нтж 4533(1) +к по 4045(1), стоп 4041(1) +к сч 7774, сл 4461(1) ; 4045 +к сч 5040(1), сда 32 +к знак 4437(1), нтж 5041(1) +к по 4051(1), стоп 4045(1) +к сч 7777, сл 7776 ; 4051 +к сда, слц 7775 +к нтж 7775, по 4055(1) +к стоп 4051(1), мода +к сч 7777, сл 7776 ; 4055 +к слц 7775, сда 50 +к нтж 5042(1), по 4061(1) +к стоп 4055(1), мода +к сч 7777, сл 7776 ; 4061 +к сда 100, сл 5043(1) +к нтж 5044(1), по 4065(1) +к стоп 4061(1), мода +к сч 7777, сл 7776 ; 4065 +к сбр 7775, сл 5043(1) +к нтж 5044(1), по 4071(1) +к стоп 4065(1), мода +к ржа 1, сч 7774 ; 4071 +к сл, сда 177 +к сл, нтж +к по 4075(1), стоп 4071(1) +к сч 7774, сл 4461(1) ; 4075 +к сч 4552(1), сда 111 +к умн 5020(1), счмр 100 +к нтж 5045(1), по 4102(1) +к стоп 4075(1), мода +к ржа, сч 4452(1) ; 4102 +к сл 4421(1), сбр 4476(1) +к нтж 5046(1), по 4106(1) +к стоп 4102(1), мода +к сч 4433(1), сл 4433(1) ; 4106 +к сда 161, по 4111(1) +к стоп 4106(1), мода +к ржа 1, сч 4542(1) ; 4111 +к сл 4433(1), сч 4461(1) +к по 4114(1), стоп 4111(1) +к ржа, сч 4653(1) ; 4114 +к зп 7776, сч 4651(1) +к зп 7777, сч 7776 +к сл 7777, сч +к по 4121(1), стоп 4114(1) +к сч 4466(1), сл ; 4121 +к сч 7776, сл 7776 +к сч, по 4125(1) +к стоп 4121(1), мода +к сч 4466(1), сл 4461(1) ; 4125 +к сч 4542(1), сл 5020(1) +к сч 4461(1), по 4131(1) +к стоп 4125(1), мода +к сч 4466(1), сл 4461(1) ; 4131 +к сч 4500(1), сл 5047(1) +к сч 4461(1), по 4135(1) +к стоп 4131(1), мода +к сч 5011(1), зп 7777 ; 4135 +к сч 4560(1), зп 7776 +к сч 5020(1), зп 7774 +к сч 7777, сл 7776 +к сл 7774, ржа 77 +к нтж 4712(1), по 4144(1) +к стоп 4135(1), мода +к ржа, мода ; 4144 +к сч 5011(1), зп 7777 +к сч 4560(1), зп 7776 +к сч 7777, сл 7776 +к сда 20, счрж 77 +к счмр, нтж 5014(1) +к по 4153(1), стоп 4145(1) +к ржа, уиа -20(4) ; 4153 +к сч, уиа (5) +к уиа -1(2), уиа -3(3) +к сл 4466(1), счи 5 +к зп 7773(3), счи 2 +к зп 7777(3), цикл 34156(3) +к уиа -3(3), мода +к сч, сч +к сч, сч 7773(3) +к по 4165(1), стоп 34162(3) +к цикл 34162(3), уиа -3(3) ; 4165 +к сч, сч +к сч 7777(3), нтж 5026(1) +к по 4171(1), стоп 34166(3) +к цикл 34166(3), уиа -3(3) ; 4171 +к сч 4412(1), и +к по 4174(1), стоп 4172(1) +к цикл 34172(3), мода ; 4174 +к уиа -7(5), уиа -10(2) +к слиа 1(2), цикл 34176(5) +к пио 34200(2), стоп 4175(1) +к сч, уи 5 +к пио 34202(5), стоп 4200(1) +к сч 5026(1), уи 5 +к слиа 1(5), пио 34205(5) +к стоп 4202(1), мода +к уиа -7(2), уиа (5) +к счи 5, нтж +к по 4211(1), стоп 4205(1) +к цикл 34206(2), мода +к уиа -7(2), уиа -1(5) ; 4211 +к счи 5, нтж 5026(1) +к по 4215(1), стоп 4211(1) +к цикл 34212(2), мода +к мода -1, сч 6431(1) ; 4215 +к нтж 4412(1), по 4220(1) +к стоп 4215(1), мода +к уиа 77000(5), уиа 1(2) ; 4220 +к мода (2), мода 777(5) +к сч 6430(1), нтж 4412(1) +к по 4224(1), стоп 4220(1) +к мод 5026(1), сч 6431(1) ; 4224 +к нтж 4412(1), по 4227(1) +к стоп 4224(1), мода +к мод 5026(1), уиа (5) ; 4227 +к счи 5, нтж 5026(1) +к по 4232(1), стоп 4227(1) +к уиа (5), пио 34234(5) ; 4232 +к стоп 4232(1), мода +к пино 34235(5), пб 4236(1) +к стоп 4232(1), мода +к уиа -1(5), пино 34240(5) ; 4236 +к стоп 4232(1), мода +к пио 34241(5), пб 4242(1) +к стоп 4232(1), мода +к уиа 1(5), уиа -17(2) ; 4242 +к пино 34245(5), пио 34247(2) ; 4243 +к стоп 4242(1), мода +к сли 5(5), слиа 1(2) +к пб 4243(1), мода +к сч, уиа -1(5) +к уи 5, пио 34252(5) +к стоп 4247(1), мода +к сч 5026(1), счи 5 +к по 4254(1), стоп 4252(1) +к сч 5026(1), уи 5 ; 4254 +к слиа 1(5), пио 34257(5) +к стоп 4254(1), мода +к сч, уиа -1(5) +к мод 5026(1), уи 6 +к пио 34262(5), стоп 4257(1) +к сч 6430(1), уиа (5) +к мод, уи 5 +к счи 5, нтж 5026(1) +к по 4266(1), стоп 4262(1) +к пв 34267(5), мода ; 4266 +к счи 5, нтж 6434(1) ; 4267 +к по 4271(1), стоп 4266(1) +к зп, пв 34272(5) ; 4271 +к счи 5, нтж 6435(1) ; 4272 +к по 4274(1), стоп 4271(1) +к сч 5050(1), мода 70000 ; 4274 +к зп 7777, мода +к сч, уи 17 +к сч (17), нтж 5050(1) +к по 4301(1), стоп 4274(1) +к счи 17, нтж 5026(1) ; 4301 +к по 4303(1), стоп 4276(1) +к сч 4412(1), зп (17) ; 4303 +к сч -1, нтж 4412(1) +к по 4306(1), стоп 4303(1) +к счи 17, по 4310(1) ; 4306 +к стоп 4306(1), мода +к сч, зп 100 ; 4310 +к мода 40000, зп +к уиа 1(5), мода +к уиа (17), мода (5) +к сч (17), счи 17 +к по 4316(1), стоп 4310(1) +к сли 5(5), пино 34313(5) ; 4316 +к сч 5026(1), уи 17 +к сч 4412(1), счм 4413(1) +к нтж 4413(1), по 4323(1) +к стоп 4310(1), мода +к сч -1, нтж 4412(1) ; 4323 +к по 4325(1), стоп 4310(1) +к сч 4413(1), зпм -2 ; 4325 +к нтж 4412(1), по 4330(1) +к стоп 4325(1), мода +к сч -2, нтж 4413(1) ; 4330 +к по 4332(1), стоп 4325(1) +к счи 17, нтж 5026(1) ; 4332 +к по 4334(1), стоп 4325(1) +к уиа -1(5), сч 4413(1) ; 4334 +к счим 5, нтж 5026(1) +к по 4337(1), стоп 4334(1) +к сч -1, нтж 4413(1) ; 4337 +к по 4341(1), стоп 4334(1) +к нтж 4414(1), уиа (5) ; 4341 +к уим 5, нтж 4413(1) +к по 4344(1), стоп 4341(1) +к счи 5, нтж 5051(1) ; 4344 +к по 4346(1), стоп 4341(1) +к уиа (5), слиа 1(17) ; 4346 +к пио 34350(17), стоп 4341(1) +к сч 6433(1), уи 17 +к уим 3, нтж 6432(1) +к по 4353(1), стоп 4350(1) +к уиа (17), сч 5026(1) ; 4353 +к зп -1, мод (17) +к уиа (5), слиа 1(5) +к пио 34357(5), стоп 4353(1) +к сч 4412(1), зп -1 +к сч 4414(1), зп -2 +к сч, уиа -1(17) +к зпм (17), нтж -2 +к по 4364(1), стоп 4366(1) +к сч -1, по 4366(1) ; 4364 +к стоп 4357(1), мода +к сч 4412(1), зп -2 ; 4366 +к зп -1, сч +к уиа -2(17), счм (17) +к нтж 4412(1), по 4373(1) +к стоп 4366(1), мода +к сч -2, по 4375(1) ; 4373 +к стоп 4366(1), мода +к уиа 17(17), сч 5026(1) ; 4375 +к уим (17), нтж 4412(1) +к по 4400(1), стоп 4375(1) +к счи 17, нтж 5026(1) ; 4400 +к по 4402(1), стоп 4375(1) +к уиа -2(17), сч 4412(1) ; 4402 +к счим 20(17), нтж 5026(1) +к по 4405(1), стоп 4375(1) +к сч -2, нтж 4412(1) ; 4405 +к по 35052, стоп 4375(1) +к пб 35052, мода +с 0000000007700000 +с 0000000000010177 +с 7777777777777777 +с 2525252525252525 +с 5252525252525252 +с 4021042104210421 +с 4010421042104210 +с 4004210421042104 +с 4002104210421042 +с 4077777777777777 +с 7750000000000000 +с 0037777777777777 +с 0000000000000001 +с 0000000000000002 +с 5125252525252525 +с 7767777777777777 +с 1775777777777777 +с 7737777777777777 +с 7677777777777776 +с 4010000000000000 +с 2525252500000000 +с 4000000000000000 +с 2525252525252524 +с 0020000000000000 +с 7000000000000000 +с 3725252525252525 +с 5252525252525250 +с 3712525252525252 +с 3765252525252525 +с 3752525252525252 +с 4114000000000000 +с 0057000000000000 +с 1717000000000000 +с 1760000000000000 +с 4050000000000000 +с 7740000000000001 +с 0010000000000000 +с 0050000000000000 +с 3740000000000000 +с 0200000000000000 +с 0400000000000000 +с 0000000000000000 +с 1000000000000000 +с 1740000000000000 +с 5710000000000000 +с 7710000000000001 +с 7740000000000000 +с 4020000077777765 +с 4020000000000677 +с 7724000000000000 +с 4777000000000000 +с 5252524000000000 +с 4052524000000000 +с 0000001703000000 +с 7777777777777760 +с 0000000000000006 +с 7030000000000000 +с 7777777777777776 +с 0000000000000027 +с 0044000000000000 +с 5777777777777777 +с 1750000000000000 +с 3750000000000000 +с 4040000000000000 +с 4100000000000001 +с 4150000000000000 +с 4000000000000001 +с 5410000000000000 +с 6760000000000000 +с 4004000000000000 +с 5560000000000000 +с 7410000000000000 +с 7760000000000000 +с 7720000000000000 +с 3744000000000000 +с 7744000000000000 +с 4042000000000000 +с 6467777777777777 +с 1250000000000000 +с 7710000000000000 +с 7750000000000001 +с 5710000000000001 +с 5757777777777777 +с 6011777777777777 +с 4002000000000000 +с 3754000000000000 +с 0003777777777777 +с 0002000000000000 +с 4030000000000000 +с 6410000000000000 +с 6357777777777777 +с 4037777777777777 +с 3757777777777776 +с 7700000000001000 +с 6010000000000001 +с 1510000000000000 +с 4140400000000000 +с 3750000000000002 +с 7710000000000777 +с 4064000000000000 +с 4010000000000001 +с 4020000000000001 +с 3740000000000002 +с 1450000000000000 +с 4017777777777777 +с 4054000000000000 +с 4007777777777777 +с 4050000000000001 +с 0054000000000000 +с 0010000000000001 +с 0110000000000001 +с 0110000000000000 +с 0112000000000000 +с 0201000000000000 +с 0010000000000010 +с 0054000000000004 +с 0410000000000000 +с 0030000000000001 +с 0357740000000001 +с 7754000000000001 +с 0027777777777777 +с 0040000000000000 +с 4700000000000000 +с 0014000000000000 +с 7717777777777000 +с 7717777777777777 +с 5357777777777777 +с 7754000000000000 +с 0140000000000000 +с 4044000000000000 +с 4137777777777777 +с 4025252525252525 +с 4025252525252521 +с 4012525252525252 +с 4012525252525246 +с 4025252525252523 +с 4012525252525250 +с 4037677777777776 +с 6400000000000000 +с 3527777777777600 +с 4037777577777776 +с 3127777777700000 +с 4037777777377776 +с 2527777740000000 +с 5367777777777777 +с 4340000000000000 +с 4300000000000000 +с 4012525252525247 +с 4025252525252522 +с 4012525252525251 +с 4025252525252524 +с 0000000000000060 +с 1217777500000000 +с 1010000000000000 +с 0030000000000004 +с 1010000037777777 +с 1017777400000000 +с 6010000000000000 +с 4017777400000000 +с 3757777777777777 +с 3757777777600000 +с 6420000000000000 +с 6417777777777777 +с 4020000000000000 +с 3760000000000000 +с 2020000000000000 +с 0020000000000001 +с 2017777777777401 +с 3717777777777776 +с 4020077451545465 +с 4017777777777776 +с 4020000000000003 +с 4025000000000000 +с 4025000000000001 +с 2525252525252527 +с 5252525252525251 +с 4024000000000000 +с 1414000000000000 +с 4020000000000005 +с 1417777777777773 +с 7740000000000005 +с 4037777777777776 +с 3166000000000000 +с 7740000000000011 +с 4037777777777756 +с 3365700000000000 +с 4010000000000025 +с 1427777777777753 +с 4023733455635120 +с 3763733455635120 +с 4011000000000000 +с 3753777777777777 +с 4006000000000000 +с 3717777777777777 +с 4014000000000000 +с 4027777777777777 +с 4010007270374325 +с 4010465735157101 +с 4017035107377453 +с 4010062167461731 +с 4010003737062525 +с 4017776537664567 +с 4010003216547543 +с 4010000002602602 +с 3750000002602603 +с 2452525252525254 +с 0017777777777766 +с 1252525252525254 +с 3752525252525274 +с 4012525252525241 +с 0012525252525276 +с 4007777777777753 +с 6317761217007126 +с 4010465771157101 +с 3757366630423726 +с 0015210643373603 +с 3710000000000000 +с 3757761217007126 +с 3753416060423726 +с 4015210643373603 +с 4000000000000002 +с 4000000000000004 +с 4000000000000010 +с 4100000000000000 +с 4057777777777777 +с 4217000000000000 +с 4221000000000000 +с 4353161703700000 +с 4153760742000000 +с 4364616074100000 +с 4050003216547543 +с 4057776537664567 +с 4010003737062524 +с 4027000000000000 +с 4015000000000000 +с 4024730473047305 +с 4026736000000000 +с 4011434000000000 +с 4020642511033154 +с 4017000000000000 +с 4021000000000000 +с 4124000000000000 +с 4060000000000000 +с 4324616074100000 +с 0000000000000007 +с 6410000000000001 +с 6376777777777777 +с 6160000000000001 +с 0053777777777773 +с 0020000000000077 +с 0024000000000077 +с 2010000000000000 +с 4020000000000002 +с 6317777777777777 +с 0000000000000401 +с 1460000000000000 +с 0052525252525252 +с 6367777777777777 +с 6310000000000000 +с 6317777777777776 +с 6320000000000001 +с 6257777777777776 +с 7257777777777774 +с 6347777777777776 +с 6350000000000001 +с 0000000000632000 +с 7777777777777774 +с 0000000000000003 +с 0000000000000056 +с 4011000000000001 +с 0000000000077777 +с 0000000000007774 +с 0000000000000146 +с 2350000000000000 +с 0000000037777777 +с 0320000000000000 +с 6037777777777777 +с 1500000000007777 +с 2050000000000000 +с 5737777777777777 +с 0000000000001371 +с 5660000000000000 +с 0000000100000000 +с 6320000000777777 +с 6360000000400000 +с 2347710000000000 +с 4017777777777760 +с 7020000000000000 +с 0330000003300000 +с 0000000000025252 +к уиа 30000(1), мода ; 5052 +к уиа -60(5), сч +к зп 7777, сч 6440(1) +к слц 7777, зп 7777 +к нтж, пе 5060(1) +к стоп 5053(1), мода +к цикл 35055(5), мода ; 5060 +к уиа -57(5), сч 6440(1) +к пе 5063(1), стоп 5061(1) +к сда 77, цикл 35062(5) ; 5063 +к по 5065(1), стоп 5061(1) +к уиа 77661(4), уиа 77660(5) ; 5065 +к счи 5, сда 27 +к сл 6441(1), нтж 6441(1) +к по 5071(1), стоп 5065(1) +к слиа 1(5), цикл 35066(4) ; 5071 +к уиа 77661(4), уиа 77660(5) +к счи 5, сда 27 +к зп 7773, сч 6441(1) +к сл 7773, нтж 6441(1) +к по 5077(1), стоп 5072(1) +к слиа 1(5), цикл 35073(4) ; 5077 +к уиа 77663(4), уиа 77662(5) +к счи 5, сда 27 +к сл 6442(1), нтж 6442(1) +к по 5104(1), стоп 5100(1) +к слиа 1(5), цикл 35101(4) ; 5104 +к уиа -7(4), уиа -3(2) +к сч 6443(1), мода +к зп 6537(1), нтж 6444(1) +к зп 6524(1), сч +к зп 6533(1), мода +к сч 6444(1), нтж 6537(1) +к сл 6533(1), нтж 6524(1) +к по 5115(1), стоп 5114(1) +к сч 6533(1), слц 6445(1) ; 5115 +к зп 6533(1), цикл 35112(4) +к уиа -7(4), сч 6537(1) +к сда 101, цикл 35107(2) +к уиа -57(4), уиа -60(5) +к счи 5, сда 27 +к сл 6446(1), зп 6532(1) +к по 5125(1), стоп 5122(1) +к слиа 1(5), цикл 35122 ; 5125 +к уиа 77660(4), уиа 77657(5) +к счи 5, сда 27 +к сл 6447(1), нтж 6447(1) +к по 5132(1), стоп 5126(1) +к слиа 1(5), цикл 35127(4) ; 5132 +к уиа 77660(4), уиа 77657(5) +к счи 5, сда 27 +к зп 7773, сч 6447(1) +к сл 7773, нтж 6447(1) +к по 5140(1), стоп 5133(1) +к слиа 1(5), цикл 35134(4) ; 5140 +к уиа -7(6), мода +к уиа -11(4), уиа 77667(5) +к счи 5, сда 27 +к мода (6), сл 5166(1) +к мода (6), нтж 5176(1) +к по 5147(1), стоп 5143(1) +к мода (6), сч 5166(1) ; 5147 +к нтж 6450(1), зп 6520(1) +к счи 5, сда 27 +к сл 6520(1), мода (6) +к нтж 5206(1), по 5155(1) +к стоп 5147(1), мода +к слиа 10(5), цикл 35143(4) ; 5155 +к цикл 35142(6), пб 5207(1) +с 3351240000000000 +с 3343240000000000 +с 3340440000000000 +с 3352400000000000 +с 3350040000000000 +с 3344100000000000 +с 3342400000000000 +с 3340140000000000 +с 3351240000000000 +с 3255200000000000 +с 3151000000000000 +с 3352400000000000 +с 3350040000000000 +с 3310200000000000 +с 3252000000000000 +с 3054000000000000 +с 3366500000000000 +с 3262400000000000 +с 3166000000000000 +с 3365340000000000 +с 3367700000000000 +с 3327500000000000 +с 3265600000000000 +с 3060000000000000 +к уиа -47(4), уиа 50(5) ; 5207 +к сч 6430(1), мода +к зп 6520(1), сч 6451(1) +к и 6520(1), зп 6521(1) +к счи 5, сда 27 +к сл 6451(1), нтж 6521(1) +к по 5216(1), стоп 5207(1) +к слиа 1(5), сч 6520(1) ; 5216 +к сда 77, цикл 35211(4) +к уиа -47(4), уиа (5) +к счи 5, сда 27 +к сл 6451(1), нтж 6451(1) +к по 5224(1), стоп 5220(1) +к слиа 1(5), цикл 35221(4) ; 5224 +к уиа -46(5), сч 6452(1) +к зп 6536(1), зп 6535(1) +к счи 5, слц 6453(1) +к сда 27, зп 6533(1) +к сч 6535(1), нтж 6430(1) +к сда 100(5), и 6454(1) +к или 6533(1), зп 6524(1) +к сч 6440(1), сда 101(5) +к зп 6530(1), мода +к сч 6535(1), или 6455(1) ; 5236 +к умн 6430(1), нтж 6524(1) +к по 5241(1), стоп 5236(1) +к сч 6535(1), или 6455(1) ; 5241 +к умн 6430(1), ржа 6 +к счмр, по 5245(1) +к стоп 5241(1), мода +к сч 6535(1), и 6456(1) ; 5245 +к пе 5254(1), сч 6535(1) +к сда 77, зп 6535(1) +к сч 6524(1), слц 6445(1) +к или 6530(1), зп 6524(1) +к сч 6530(1), сда 101 +к зп 6530(1), пб 5236(1) +к сч 6536(1), сда 77 ; 5254 +к зп 6536(1), или 6452(1) +к зп 6535(1), цикл 35227(5) +к уиа 100(3), уиа -47(4) +к сч 6457(1), зп 6546(1) +к сч 6456(1), зп 6527(1) +к зп 6540(1), зп 6547(1) +к или 6457(1), зп 6541(1) +к сч 6460(1), сда (3) +к и 6444(1), зп 6545(1) +к уии 5(4), мода +к сч 6546(1), или 6454(1) +к нтж 6527(1), и 6461(1) +к зп 6543(1), сч 6454(1) +к вч 6541(1), нтж 6543(1) +к по 5274(1), стоп 5267(1) +к сч 6454(1), вч 6541(1) ; 5274 +к ржа 6, счмр +к нтж 6545(1), по 5300(1) +к стоп 5274(1), мода +к сч 6547(1), сда 101 ; 5300 +к зп 6547(1), или 6540(1) +к или 6457(1), зп 6541(1) +к сч 6527(1), сда 101 +к зп 6527(1), цикл 35267(5) +к уиа -47(2), сч 6462(1) +к зп 6542(1), мода +к сч 6546(1), или 6454(1) +к нтж 6527(1), и 6461(1) +к зп 6543(1), сч 6542(1) +к сда 101, зп 6542(1) +к нтж 6454(1), вч 6541(1) +к нтж 6543(1), по 5316(1) +к стоп 5307(1), мода +к сч 6542(1), нтж 6444(1) ; 5316 +к сда (3), и 6444(1) +к зп 6544(1), сч 6542(1) +к нтж 6454(1), вч 6541(1) +к ржа 6, счмр +к зп 6532(1), нтж 6544(1) +к по 5325(1), стоп 5316(1) +к сч 6527(1), сда 101 ; 5325 +к зп 6527(1), цикл 35307(2) +к слиа -1(3), сч 6546(1) +к слц 6463(1), и 6464(1) +к зп 6546(1), сч 6456(1) +к зп 6527(1), сч 6540(1) +к сда 101, цикл 35262(4) +к уиа -57(3), уиа 100(4) +к уиа 100(5), мода +к сч 6465(1), сда (4) +к сда (5), нтж 6465(1) +к по 5341(1), стоп 5334(1) +к слиа 1(4), слиа -1(5) ; 5341 +к цикл 35336(3), мода +к уиа -57(4), уиа 160(5) +к сч, зп 6520(1) +к сч 6430(1), сда (5) +к нтж 6520(1), по 5350(1) +к стоп 5343(1), мода +к сч 6520(1), слц 6520(1) ; 5350 +к или 6440(1), зп 6520(1) +к слиа -1(5), цикл 35345(4) +к уиа -16(4), уиа 161(5) +к сч 6430(1), сда (5) +к по 5356(1), стоп 5353(1) +к слиа 1(5), цикл 35354(4) ; 5356 +к уиа 77602(4), сч 6461(1) +к зп 6523(1), мода +к сч, сд 6523(1) +к по 5363(1), стоп 5357(1) +к сд 6523(1), счмр ; 5363 +к по 5365(1), стоп 5363(1) +к сч 6523(1), слпа 77 ; 5365 +к зп 6523(1), цикл 35361(4) +к уиа -57(5), уиа -57(2) +к сч 6466(1), зп 6523(1) +к сч 6460(1), зп 6527(1) +к сч 6440(1), зп 6552(1) +к зп 6551(1), мода +к зп 6550(1), уии 3(2) +к сч 6527(1), нтж 6552(1) +к зп 6524(1), сч 6460(1) +к нтж 6550(1), сд 6523(1) +к нтж 6524(1), по 5402(1) +к стоп 5375(1), мода +к сч 6550(1), слц 6550(1) ; 5402 +к зп 6550(1), сч 6552(1) +к слц 6552(1), зп 6552(1) +к цикл 35375(3), сч 6440(1) +к зп 6552(1), сч 6527(1) +к сда 101, и 6467(1) +к зп 6527(1), сч 6523(1) +к слпа 101, зп 6523(1) +к слиа 1(2), сч 6551(1) +к слц 6551(1), зп 6551(1) +к цикл 35374(5), мода +к уиа -57(3), уиа 101(4) +к уиа 100(5), мода +к сч 6440(1), сда (4) +к счмр, сда (5) +к нтж 6465(1), по 5423(1) +к стоп 5415(1), мода +к слиа 1(4), слиа -1(5) ; 5423 +к цикл 35417(3), мода +к уиа -16(4), уиа 177(5) +к сч 6470(1), зп 6520(1) +к сч 6430(1), сда (5) +к счмр, нтж 6520(1) +к по 5432(1), стоп 5425(1) +к сч 6520(1), слц 6520(1) ; 5432 +к или 6440(1), зп 6520(1) +к слиа -1(5), цикл 35427(4) +к уиа -57(5), уиа -57(2) +к сч 6471(1), зп 6523(1) +к сч 6460(1), зп 6527(1) +к сч 6440(1), мода +к зп 6526(1), зп 6525(1) +к сч 6440(1), зп 6522(1) +к уии 3(2), мода +к сч 6527(1), нтж 6525(1) +к зп 6524(1), сч 6460(1) +к нтж 6522(1), сд 6523(1) +к счмр, нтж 6524(1) +к по 5451(1), стоп 5444(1) +к сч 6522(1), слц 6522(1) ; 5451 +к зп 6522(1), сч 6525(1) +к слц 6525(1), зп 6525(1) +к цикл 35444(3), сч 6523(1) +к слпа 77, зп 6523(1) +к слиа 1(2), сч 6527(1) +к слц 6527(1), и 6464(1) +к зп 6527(1), сч 6526(1) +к слц 6526(1), цикл 35441(5) +к уиа -16(5), уиа -56(2) +к сч 6471(1), зп 6523(1) +к сч 6467(1), зп 6527(1) +к сч 6452(1), мода +к зп 6551(1), зп 6550(1) +к сч 6440(1), зп 6552(1) +к уии 3(2), сч 6523(1) +к слпа 101, зп 6523(1) +к сч 6527(1), нтж 6552(1) +к зп 6524(1), сч 6460(1) +к нтж 6550(1), сд 6523(1) +к счмр, нтж 6524(1) +к по 5477(1), стоп 5472(1) +к сч 6550(1), слц 6550(1) ; 5477 +к зп 6550(1), сч 6552(1) +к слц 6552(1), зп 6552(1) +к цикл 35472(3), слиа 1(2) +к сч 6527(1), сда 101 +к зп 6527(1), сч 6551(1) +к слц 6551(1), цикл 35466(5) +к уиа -57(3), уиа 100(4) +к уиа 100(5), мода +к сч 6440(1), сда (4) +к сда (5), нтж 6440(1) +к по 5513(1), стоп 5506(1) +к слиа -1(4), слиа 1(5) ; 5513 +к цикл 35510(3), мода +к уиа -47(5), уиа -47(4) +к сч 6456(1), зп 6534(1) +к сч 6447(1), зп 6531(1) +к сч 6472(1), мода +к зп 6527(1), зп 6530(1) +к или 6531(1), зп 6524(1) +к сч 6473(1), зп 6533(1) +к уиа -50(3), уии 2(4) +к сч 6474(1), нтж 6534(1) +к сл 6533(1), зп 6532(1) +к нтж 6524(1), по 5531(1) +к стоп 5525(1), мода +к сч 6533(1), слц 6445(1) ; 5531 +к зп 6533(1), цикл 35525(3) +к уиа (3), сч 6530(1) +к слц 6530(1), и 6472(1) +к зп 6530(1), или 6531(1) +к зп 6524(1), цикл 35525(2) +к ржа 3, сч 6534(1) +к умн 6475(1), зп 6534(1) +к ржа, слиа 1(4) +к сч 6531(1), слц 6463(1) +к и 6476(1), зп 6531(1) +к сч 6527(1), слц 6527(1) +к и 6472(1), цикл 35521(5) +к уиа 100(5), уиа -60(4) +к сч 6430(1), зп 6520(1) +к сч 6430(1), сда (5) +к нтж 6520(1), по 5553(1) +к стоп 5546(1), мода +к сч 6520(1), слц 6520(1) ; 5553 +к и 6464(1), зп 6520(1) +к слиа -1(5), цикл 35550(4) +к уиа -17(4), уиа 17(5) +к сч 6430(1), сда (5) +к по 5561(1), стоп 5556(1) +к слиа -1(5), цикл 35557(4) ; 5561 +к уиа -57(3), уиа 77(4) +к уиа 100(5), мода +к сч 6465(1), сда (4) +к счмр, сда (5) +к нтж 6440(1), по 5570(1) +к стоп 5562(1), мода +к слиа -1(4), слиа 1(5) ; 5570 +к цикл 35564(3), мода +к уиа -17(4), уиа 17(5) +к сч 6464(1), зп 6520(1) +к сч 6430(1), сда (5) +к счмр, нтж 6520(1) +к по 5577(1), стоп 5572(1) +к сч 6520(1), слц 6520(1) ; 5577 +к и 6464(1), зп 6520(1) +к слиа -1(5), цикл 35574(4) +к уиа -37(4), сч 6477(1) +к зп 6543(1), сч 6464(1) +к зп 6520(1), сда +к счмр, нтж 6543(1) +к по 5607(1), стоп 5604(1) +к сч 6543(1), слц 6543(1) ; 5607 +к слц 6500(1), зп 6543(1) +к сч 6520(1), слц 6520(1) +к цикл 35604(4), мода +к уиа 77640(3), уиа 20(4) +к сч 6460(1), сда (4) +к зп 7777, счмр +к слц 7777, нтж 6460(1) +к по 5620(1), стоп 5613(1) +к слиа 1(4), цикл 35614(3) ; 5620 +к уиа -60(4), уиа 100(3) +к сч 6440(1), сда (3) +к зп 6520(1), нтж 6430(1) +к сч 6520(1), нед +к уи 5, сли 5(4) +к слиа -1(3), пио 35630(5) +к стоп 5621(1), мода +к цикл 35622(4), мода +к уиа (7), уиа (3) +к уиа -5(11), мода +к уиа -21(10), мода +к мода 6002(1), сч (10) +к сда 100(7), нтж 6430(1) +к мода 6574(1), зп (10) +к цикл 35634(10), уиа -3(4) +к слиа -1(3), мода +к мода 6556(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35645(5), стоп 5641(1) +к цикл 35641(4), слиа -1(3) +к уиа -2(4), мода +к мода 6561(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35653(5), стоп 5647(1) +к цикл 35647(4), слиа -1(3) +к уиа -2(4), мода +к мода 6564(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35661(5), стоп 5655(1) +к цикл 35655(4), слиа -1(3) +к сч 6565(1), мода +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35666(5), стоп 5663(1) +к слиа -1(3), уиа -3(4) +к мода 6571(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35673(5), стоп 5666(1) +к цикл 35667(4), слиа -1(3) +к сч 6572(1), мода +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35700(5), стоп 5675(1) +к слиа -1(3), сч 6573(1) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35704(5), стоп 5700(1) +к слиа -1(3), сч 6574(1) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35710(5), стоп 5704(1) +к слиа 10(7), цикл 35633(11) +к уиа -17(10), мода +к мода 6022(1), сч (10) +к нтж 6430(1), мода 6572(1) +к зп (10), цикл 35712(10) +к уиа -3(4), уиа -1(3) +к мода 6556(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35722(5), стоп 5716(1) +к цикл 35716(4), уиа -2(4) +к слиа -10(3), мода +к мода 6561(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35730(5), стоп 5724(1) +к цикл 35724(4), уиа -2(4) +к слиа -10(3), мода +к мода 6564(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35736(5), стоп 5732(1) +к цикл 35732(4), слиа -10(3) +к мода 6565(1), сч +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35743(5), стоп 5737(1) +к уиа -1(4), слиа -10(3) +к мода 6567(1), сч (4) +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35750(5), стоп 5743(1) +к цикл 35744(4), слиа -10(3) +к мода 6570(1), сч +к нтж 6430(1), нед +к уи 5, сли 5(3) +к пио 35755(5), стоп 5751(1) +к мода 6571(1), сч +к нтж 6430(1), нед +к по 6022(1), стоп 5755(1) +к пб 6022(1), мода +с 6537777777777777 +с 5057777777777777 +с 4437777777777777 +с 4377777777777777 +с 3777777777777777 +с 3477777777777777 +с 2377777777777777 +с 1777777777777777 +с 1137777777777777 +с 1377777777777777 +с 0777777777777777 +с 0377777777777777 +с 0337777777777777 +с 0277777777777777 +с 0217777777777777 +с 0177777777777777 +с 0077777777777777 +с 0037777777777777 +с 7777740077600377 +с 7760037700000000 +с 7760000077600000 +с 7760000000177777 +с 0017777777777777 +с 0017777777600000 +с 0017740000177777 +с 0000037777777777 +с 0000037700000377 +с 0000037700177777 +с 0000000077777777 +с 0000000000177777 +с 0000000000177400 +с 0000000000000377 +с 0000000000000000 +к ржа 3, мода ; 6022 +к сч 6501(1), вчоб 6445(1) +к зп 6520(1), счмр 77 +к нтж 6456(1), по 6027(1) +к стоп 6023(1), мода +к сч 6520(1), нтж 6502(1) ; 6027 +к по 6031(1), стоп 6027(1) +к уиа -44(5), сч 6122(1) ; 6031 +к сда 77, зп 6520(1) +к сч 6123(1), зп 6521(1) +к сч 6520(1), вчоб 6445(1) +к нтж 6521(1), по 6037(1) +к стоп 6034(1), мода +к сч 6520(1), сда 77 ; 6037 +к зп 6520(1), сч 6521(1) +к сда 77, и 6503(1) +к зп 6521(1), цикл 36034(5) +к сч 6504(1), вчоб 6445(1) +к нтж 6505(1), по 6046(1) +к стоп 6043(1), мода +к сч 6462(1), вчоб 6445(1) ; 6046 +к нтж 6506(1), по 6051(1) +к стоп 6046(1), мода +к сч 6445(1), вч 6501(1) ; 6051 +к зп 6520(1), счмр 77 +к нтж 6456(1), по 6055(1) +к стоп 6051(1), мода +к сч 6520(1), нтж 6502(1) ; 6055 +к по 6057(1), стоп 6055(1) +к уиа -44(5), сч 6122(1) ; 6057 +к сда 77, зп 6520(1) +к сч 6123(1), зп 6521(1) +к сч 6445(1), вч 6520(1) +к нтж 6521(1), по 6065(1) +к стоп 6062(1), мода +к сч 6520(1), сда 77 ; 6065 +к зп 6520(1), сч 6521(1) +к сда 77, и 6503(1) +к зп 6521(1), цикл 36062(5) +к сч 6445(1), вч 6504(1) +к нтж 6505(1), по 6074(1) +к стоп 6071(1), мода +к сч 6445(1), вч 6462(1) ; 6074 +к нтж 6506(1), по 6077(1) +к стоп 6074(1), мода +к сч 6124(1), зп 6520(1) ; 6077 +к уиа -50(5), мода +к сч 6507(1), вчоб 6520(1) +к нтж 6520(1), по 6104(1) +к стоп 6101(1), мода +к сч 6520(1), сда 77 ; 6104 +к и 6503(1), зп 6520(1) +к цикл 36101(5), мода +к сч 6124(1), зп 6520(1) +к уиа -47(5), мода +к сч 6520(1), вч 6507(1) +к нтж 6520(1), по 6114(1) +к стоп 6111(1), мода +к сч 6520(1), сда 77 ; 6114 +к и 6503(1), зп 6520(1) +к цикл 36111(5), мода +к сч 6510(1), вч 6507(1) +к нтж 6510(1), по 6125(1) +к стоп 6117(1), пб 6125(1) +с 0000000000000003 +с 0077777777777775 +с 0040000000000001 +к уиа -47(5), сч 6436(1) ; 6125 +к зп 7776, мода +к сч 6511(1), умн 7776 +к зп 7777, счмр 100 +к слц 7777, нтж 6444(1) +к по 6133(1), стоп 6125(1) +к сч 7776, сда 77 ; 6133 +к зп 7776, цикл 36127(5) +к уиа -60(4), ржа +к сч 6460(1), сда 160(4) +к чед, уи 5 +к сли 5(4), пио 36142(5) +к стоп 6135(1), мода +к цикл 36136(4), мода +к сч 6443(1), уиа 77601(2) +к слпа 101, зп 7777 +к сч 6443(1), уиа 77601(5) +к слпа 101, зп 7776 +к сл 7777, зп 7775 +к сч 7777, сл 7776 +к нтж 7775, по 6154(1) +к стоп 6143(1), сч 7777 +к сч 7776, мода +к сч 7777, нтж 6512(1) ; 6154 +к пе 6157(1), сч 7776 +к нтж 6513(1), по 6161(1) +к сч 7776, цикл 36146(5) ; 6157 +к сч 7777, цикл 36144(2) +к уиа -57(4), уиа -60(5) ; 6161 +к сч 6462(1), зп 6520(1) +к счи 5, сда 27 +к сл 6462(1), нтж 6520(1) +к по 6166(1), стоп 6161(1) +к слиа 1(5), сч 6520(1) ; 6166 +к слпа 101, зп 6520(1) +к цикл 36163(4), мода +к ржа 3, уиа -47(4) +к сч 6440(1), зп 6520(1) +к сч 6454(1), зп 6521(1) +к сч, вч 6520(1) +к нтж 6521(1), по 6177(1) +к стоп 6171(1), мода +к сч 6520(1), слц 6520(1) ; 6177 +к зп 6520(1), сч 6521(1) +к слц 6521(1), и 6454(1) +к зп 6521(1), цикл 36174(4) +к уиа -46(4), сч 6440(1) +к зп 6520(1), сч 6503(1) +к зп 6521(1), мода +к сч 6445(1), вч 6520(1) ; 6206 +к нтж 6521(1), по 6211(1) +к стоп 6203(1), мода +к сч 6520(1), слц 6520(1) ; 6211 +к зп 6520(1), нтж 6452(1) +к по 6206(1), сч 6521(1) +к слц 6521(1), и 6503(1) +к зп 6521(1), цикл 36206(4) +к уиа -46(4), сч 6440(1) +к зп 6520(1), сч 6503(1) +к зп 6521(1), мода +к сч 6520(1), вчоб 6445(1) ; 6221 +к нтж 6521(1), по 6224(1) +к стоп 6216(1), мода +к сч 6520(1), слц 6520(1) ; 6224 +к зп 6520(1), нтж 6452(1) +к по 6221(1), сч 6521(1) +к слц 6521(1), и 6503(1) +к зп 6521(1), цикл 36221(4) +к ржа, мода +к уиа -1(4), уиа -17(3) +к уиа -67(5), сч 6464(1) +к зп 6777, пио 36236(4) +к зп 7067(5), пб 6240(1) +к нтж 7067(5), по 6240(1) +к стоп 6232(1), мода +к сч 6777, слц 6777 ; 6240 +к цикл 36234(5), цикл 36233(4) +к цикл 36233(3), мода +к сч -12, пе 6246(1) +к сч 6460(1), зп -12 +к сч 6514(1), зп 7767 +к уиа 77400(12), мода ; 6246 +к сч 7767, слц 6 +к зп 7777, сда 115 +к слц 7777, зп 7776 +к сч 7777, сда 63 +к слц 7776, слц 6440(1) +к зп 7777, зп 7767 +к сч 7777, нтж 6460(1) +к зп 7774, сч 7776 +к нтж 6460(1), или 7774 +к зп 7775, сч 7777 +к и 7776, нтж 6460(1) +к нтж 7775, по 6264(1) +к стоп 6255(1), мода +к сч 7777, слц 7776 ; 6264 +к зп 7775, сч 7777 +к нтж 6460(1), слц 7775 +к нтж 7776, по 6271(1) +к стоп 6264(1), мода +к сч 7777, сбр 7776 ; 6271 +к рзб 7776, зп 7775 +к сч 7776, нтж 6460(1) +к зп 7774, сч 7777 +к сбр 7774, рзб 7774 +к слц 7775, нтж 7777 +к по 6300(1), стоп 6271(1) +к сч 7777, чед ; 6300 +к зп 7775, уиа -57(5) +к сч, зп 7774 +к сч 7777, зп 7773 +к сч 7773, и 6440(1) +к слц 7774, зп 7774 +к сч 7773, сда 101 +к зп 7773, цикл 36304(5) +к сч 7775, нтж 7774 +к по 6312(1), стоп 6310(1) +к сч 7777, нед ; 6312 +к зп 7775, сч 7777 +к уиа 61(5), мода +к слиа -1(5), сда 101 ; 6315 +к пе 6315(1), счи 5 +к нтж 7775, по 6321(1) +к стоп 6312(1), мода +к сч 7777, знак 7776 ; 6321 +к знак 7776, вч 7777 +к нтж, по 6325(1) +к стоп 6321(1), мода +к сч 7777, вчп 7777 ; 6325 +к слп 7777, вч 7777 +к нтж, по 6331(1) +к стоп 6325(1), мода +к сч 7777, знак 6462(1) ; 6331 +к сл 7777, нтж +к по 6334(1), стоп 6331(1) +к сч 7777, вч 7777 ; 6334 +к нтж, по 6337(1) +к стоп 6334(1), мода +к сч 7777, вчоб 7777 ; 6337 +к нтж, по 6342(1) +к стоп 6337(1), мода +к сч 7777, вчаб 7777 ; 6342 +к нтж, по 6345(1) +к стоп 6342(1), мода +к сч 7777, вчпа 101 ; 6345 +к зп 7774, сч 7776 +к вчпа 101, зп 7773 +к сл 7774, зп 7775 +к сч 7774, сл 7773 +к знак 6462(1), сл 7775 +к нтж, по 6355(1) +к стоп 6345(1), мода +к сч 7777, и 6515(1) ; 6355 +к зп 7774, сч 7776 +к и 6515(1), зп 7773 +к умн 7774, зп 7775 +к сч 7774, умн 7773 +к нтж 7775, по 6364(1) +к стоп 6355(1), мода +к сч 7774, сл ; 6364 +к нтж, по 6375(1) +к зп 7772, сч 7773 +к сл, зп 7771 +к умн 7772, нтж +к по 6375(1), дел 7772 +к вчоб 7771, вчп 7771 +к слпа 145, пе 6375(1) +к стоп 6364(1), мода +к сч 7774, зп 7772 ; 6375 +к сч 7773, зп 7771 +к умн 7772, счмр 100 +к зп 7775, сч 7772 +к умн 7771, счмр 100 +к нтж 7775, по 6404(1) +к стоп 6375(1), мода +к сч 7776, сда 116 ; 6404 +к сда 21, сда 141 +к пе 6407(1), или 6516(1) +к или 7776, уи 17 ; 6407 +к и 6517(1), зп 7775 +к сч 7776, счм 7777 +к нтж 7777, по 6414(1) +к стоп 6404(1), мода +к мода -1, сч (17) ; 6414 +к нтж 7776, по 6417(1) +к стоп 6414(1), мода +к сч 7777, зпм 7774 ; 6417 +к нтж 7776, по 6422(1) +к стоп 6417(1), мода +к счи 17, нтж 7775 ; 6422 +к по 6424(1), стоп 6422(1) +к сч 7774, нтж 7777 ; 6424 +к по 6426(1), стоп 6424(1) +к цикл 36247(12), мода ; 6426 +к пб 32013, мода +с 7777777777777777 +с 0000000000036430 +с 0000000000036432 +с 0000000000036433 +с 0000000000034267 +с 0000000000034272 +с 0000000000000001 +с 0000000000000002 +с 0000000000000001 +с 3010000000000000 +с 3116000000000000 +с 0004000000000000 +с 0017777777777777 +с 0040000000000000 +с 0017777777777177 +с 3020000000000000 +с 0037740000000000 +с 0027777777777777 +с 0000000000000002 +с 0000000000000127 +с 0037777777777777 +с 4000000000000001 +с 0010000000000000 +с 2400000000000000 +с 7777777777777777 +с 7767777777777777 +с 0020000000000000 +с 7740000000000000 +с 7777777777777776 +с 4000000000000000 +с 4020000000000000 +с 3777777777777777 +с 0000077777777777 +с 7020000000000000 +с 0007777777777777 +с 3000000000000000 +с 3037777777777777 +с 4010000000000000 +с 7760000000000000 +с 7777777777400000 +с 0000000000177777 +с 0000000000000003 +с 0077777777777776 +с 0077777777777777 +с 0030000000000000 +с 0044000000000000 +с 0050000000000000 +с 0000000000000000 +с 0060000000000000 +с 4017777777777777 +с 7750000000000000 +с 7710000000000000 +с 3572414425543217 +с 5777777777777777 +с 0000000000037700 +с 0000000000077777 + +; Тест выполняет чтение данных по адресам вида 1< Date: Tue, 30 Dec 2014 11:42:52 -0800 Subject: [PATCH 03/41] BESM6: Removed tabs, reindented, removed GNU extensions. --- BESM6/besm6_arith.c | 622 ++++----- BESM6/besm6_cpu.c | 2934 ++++++++++++++++++++-------------------- BESM6/besm6_defs.h | 396 +++--- BESM6/besm6_disk.c | 806 +++++------ BESM6/besm6_drum.c | 464 +++---- BESM6/besm6_mmu.c | 800 +++++------ BESM6/besm6_panel.c | 720 +++++----- BESM6/besm6_printer.c | 355 +++-- BESM6/besm6_punch.c | 676 +++++---- BESM6/besm6_sys.c | 1006 +++++++------- BESM6/besm6_tty.c | 1850 ++++++++++++------------- BESM6/boot_dispak.b6 | 910 ++++++------- BESM6/formatdisk.c | 0 BESM6/test_pprog05.b6 | 18 +- BESM6/test_pprog05.ini | 1 - 15 files changed, 5776 insertions(+), 5782 deletions(-) mode change 100755 => 100644 BESM6/formatdisk.c diff --git a/BESM6/besm6_arith.c b/BESM6/besm6_arith.c index d88bdd6e..016c2c01 100644 --- a/BESM6/besm6_arith.c +++ b/BESM6/besm6_arith.c @@ -30,37 +30,37 @@ #include "besm6_defs.h" typedef struct { - t_uint64 mantissa; - unsigned exponent; /* offset by 64 */ -} alureg_t; /* ALU register type */ + t_uint64 mantissa; + unsigned exponent; /* offset by 64 */ +} alureg_t; /* ALU register type */ static alureg_t toalu (t_value val) { - alureg_t ret; + alureg_t ret; - ret.mantissa = val & BITS41; - ret.exponent = (val >> 41) & BITS(7); - if (ret.mantissa & BIT41) - ret.mantissa |= BIT42; - return ret; + ret.mantissa = val & BITS41; + ret.exponent = (val >> 41) & BITS(7); + if (ret.mantissa & BIT41) + ret.mantissa |= BIT42; + return ret; } static int inline is_negative (alureg_t *word) { - return (word->mantissa & BIT41) != 0; + return (word->mantissa & BIT41) != 0; } static void negate (alureg_t *val) { - if (is_negative (val)) - val->mantissa |= BIT42; - val->mantissa = (~val->mantissa + 1) & BITS42; - if (((val->mantissa >> 1) ^ val->mantissa) & BIT41) { - val->mantissa >>= 1; - ++val->exponent; - } - if (is_negative (val)) - val->mantissa |= BIT42; + if (is_negative (val)) + val->mantissa |= BIT42; + val->mantissa = (~val->mantissa + 1) & BITS42; + if (((val->mantissa >> 1) ^ val->mantissa) & BIT41) { + val->mantissa >>= 1; + ++val->exponent; + } + if (is_negative (val)) + val->mantissa |= BIT42; } /* @@ -70,15 +70,15 @@ static void negate (alureg_t *val) */ int besm6_highest_bit (t_value val) { - int n = 32, cnt = 0; - do { - t_value tmp = val; - if (tmp >>= n) { - cnt += n; - val = tmp; - } - } while (n >>= 1); - return 48 - cnt; + int n = 32, cnt = 0; + do { + t_value tmp = val; + if (tmp >>= n) { + cnt += n; + val = tmp; + } + } while (n >>= 1); + return 48 - cnt; } /* @@ -88,86 +88,86 @@ int besm6_highest_bit (t_value val) */ static void normalize_and_round (alureg_t acc, t_uint64 mr, int rnd_rq) { - t_uint64 rr = 0; - int i; - t_uint64 r; + t_uint64 rr = 0; + int i; + t_uint64 r; - if (RAU & RAU_NORM_DISABLE) - goto chk_rnd; - i = (acc.mantissa >> 39) & 3; - if (i == 0) { - r = acc.mantissa & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - r <<= cnt; - rr = mr >> (40 - cnt); - acc.mantissa = r | rr; - mr <<= cnt; - acc.exponent -= cnt; - goto chk_zero; - } - r = mr & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - rr = mr; - r <<= cnt; - acc.mantissa = r; - mr = 0; - acc.exponent -= 40 + cnt; - goto chk_zero; - } - goto zero; - } else if (i == 3) { - r = ~acc.mantissa & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - r = (r << cnt) | ((1LL << cnt) - 1); - rr = mr >> (40 - cnt); - acc.mantissa = BIT41 | (~r & BITS40) | rr; - mr <<= cnt; - acc.exponent -= cnt; - goto chk_zero; - } - r = ~mr & BITS40; - if (r) { - int cnt = besm6_highest_bit (r) - 9; - rr = mr; - r = (r << cnt) | ((1LL << cnt) - 1); - acc.mantissa = BIT41 | (~r & BITS40); - mr = 0; - acc.exponent -= 40 + cnt; - goto chk_zero; - } else { - rr = 1; - acc.mantissa = BIT41; - mr = 0; - acc.exponent -= 80; - goto chk_zero; - } - } -chk_zero: - if (rr) - rnd_rq = 0; -chk_rnd: - if (acc.exponent & 0x8000) - goto zero; - if (! (RAU & RAU_ROUND_DISABLE) && rnd_rq) - acc.mantissa |= 1; + if (RAU & RAU_NORM_DISABLE) + goto chk_rnd; + i = (acc.mantissa >> 39) & 3; + if (i == 0) { + r = acc.mantissa & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + r <<= cnt; + rr = mr >> (40 - cnt); + acc.mantissa = r | rr; + mr <<= cnt; + acc.exponent -= cnt; + goto chk_zero; + } + r = mr & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + rr = mr; + r <<= cnt; + acc.mantissa = r; + mr = 0; + acc.exponent -= 40 + cnt; + goto chk_zero; + } + goto zero; + } else if (i == 3) { + r = ~acc.mantissa & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + r = (r << cnt) | ((1LL << cnt) - 1); + rr = mr >> (40 - cnt); + acc.mantissa = BIT41 | (~r & BITS40) | rr; + mr <<= cnt; + acc.exponent -= cnt; + goto chk_zero; + } + r = ~mr & BITS40; + if (r) { + int cnt = besm6_highest_bit (r) - 9; + rr = mr; + r = (r << cnt) | ((1LL << cnt) - 1); + acc.mantissa = BIT41 | (~r & BITS40); + mr = 0; + acc.exponent -= 40 + cnt; + goto chk_zero; + } else { + rr = 1; + acc.mantissa = BIT41; + mr = 0; + acc.exponent -= 80; + goto chk_zero; + } + } + chk_zero: + if (rr) + rnd_rq = 0; + chk_rnd: + if (acc.exponent & 0x8000) + goto zero; + if (! (RAU & RAU_ROUND_DISABLE) && rnd_rq) + acc.mantissa |= 1; - if (! acc.mantissa && ! (RAU & RAU_NORM_DISABLE)) { -zero: ACC = 0; - RMR &= ~BITS40; - return; - } + if (! acc.mantissa && ! (RAU & RAU_NORM_DISABLE)) { + zero: ACC = 0; + RMR &= ~BITS40; + return; + } - ACC = (t_value) (acc.exponent & BITS(7)) << 41 | - (acc.mantissa & BITS41); - RMR = (RMR & ~BITS40) | (mr & BITS40); - /* При переполнении мантисса и младшие разряды порядка верны */ - if (acc.exponent & 0x80) { - if (! (RAU & RAU_OVF_DISABLE)) - longjmp (cpu_halt, STOP_OVFL); - } + ACC = (t_value) (acc.exponent & BITS(7)) << 41 | + (acc.mantissa & BITS41); + RMR = (RMR & ~BITS40) | (mr & BITS40); + /* При переполнении мантисса и младшие разряды порядка верны */ + if (acc.exponent & 0x80) { + if (! (RAU & RAU_OVF_DISABLE)) + longjmp (cpu_halt, STOP_OVFL); + } } /* @@ -177,80 +177,80 @@ zero: ACC = 0; */ void besm6_add (t_value val, int negate_acc, int negate_val) { - t_uint64 mr; - alureg_t acc, word, a1, a2; - int diff, neg, rnd_rq = 0; + t_uint64 mr; + alureg_t acc, word, a1, a2; + int diff, neg, rnd_rq = 0; - acc = toalu (ACC); - word = toalu (val); - if (! negate_acc) { - if (! negate_val) { - /* Сложение */ - } else { - /* Вычитание */ - negate (&word); - } - } else { - if (! negate_val) { - /* Обратное вычитание */ - negate (&acc); - } else { - /* Вычитание модулей */ - if (is_negative (&acc)) - negate (&acc); - if (! is_negative (&word)) - negate (&word); - } - } + acc = toalu (ACC); + word = toalu (val); + if (! negate_acc) { + if (! negate_val) { + /* Сложение */ + } else { + /* Вычитание */ + negate (&word); + } + } else { + if (! negate_val) { + /* Обратное вычитание */ + negate (&acc); + } else { + /* Вычитание модулей */ + if (is_negative (&acc)) + negate (&acc); + if (! is_negative (&word)) + negate (&word); + } + } - diff = acc.exponent - word.exponent; - if (diff < 0) { - diff = -diff; - a1 = acc; - a2 = word; - } else { - a1 = word; - a2 = acc; - } - mr = 0; - neg = is_negative (&a1); - if (diff == 0) { - /* Nothing to do. */ - } else if (diff <= 40) { - rnd_rq = (mr = (a1.mantissa << (40 - diff)) & BITS40) != 0; - a1.mantissa = ((a1.mantissa >> diff) | - (neg ? (~0ll << (40 - diff)) : 0)) & BITS42; - } else if (diff <= 80) { - diff -= 40; - rnd_rq = a1.mantissa != 0; - mr = ((a1.mantissa >> diff) | - (neg ? (~0ll << (40 - diff)) : 0)) & BITS40; - if (neg) { - a1.mantissa = BITS42; - } else - a1.mantissa = 0; - } else { - rnd_rq = a1.mantissa != 0; - if (neg) { - mr = BITS40; - a1.mantissa = BITS42; - } else - mr = a1.mantissa = 0; - } - acc.exponent = a2.exponent; - acc.mantissa = a1.mantissa + a2.mantissa; + diff = acc.exponent - word.exponent; + if (diff < 0) { + diff = -diff; + a1 = acc; + a2 = word; + } else { + a1 = word; + a2 = acc; + } + mr = 0; + neg = is_negative (&a1); + if (diff == 0) { + /* Nothing to do. */ + } else if (diff <= 40) { + rnd_rq = (mr = (a1.mantissa << (40 - diff)) & BITS40) != 0; + a1.mantissa = ((a1.mantissa >> diff) | + (neg ? (~0ll << (40 - diff)) : 0)) & BITS42; + } else if (diff <= 80) { + diff -= 40; + rnd_rq = a1.mantissa != 0; + mr = ((a1.mantissa >> diff) | + (neg ? (~0ll << (40 - diff)) : 0)) & BITS40; + if (neg) { + a1.mantissa = BITS42; + } else + a1.mantissa = 0; + } else { + rnd_rq = a1.mantissa != 0; + if (neg) { + mr = BITS40; + a1.mantissa = BITS42; + } else + mr = a1.mantissa = 0; + } + acc.exponent = a2.exponent; + acc.mantissa = a1.mantissa + a2.mantissa; - /* Если требуется нормализация вправо, биты 42:41 - * принимают значение 01 или 10. */ - switch ((acc.mantissa >> 40) & 3) { - case 2: - case 1: - rnd_rq |= acc.mantissa & 1; - mr = (mr >> 1) | ((acc.mantissa & 1) << 39); - acc.mantissa >>= 1; - ++acc.exponent; - } - normalize_and_round (acc, mr, rnd_rq); + /* Если требуется нормализация вправо, биты 42:41 + * принимают значение 01 или 10. */ + switch ((acc.mantissa >> 40) & 3) { + case 2: + case 1: + rnd_rq |= acc.mantissa & 1; + mr = (mr >> 1) | ((acc.mantissa & 1) << 39); + acc.mantissa >>= 1; + ++acc.exponent; + } + normalize_and_round (acc, mr, rnd_rq); } /* @@ -260,37 +260,37 @@ void besm6_add (t_value val, int negate_acc, int negate_val) #define INT64(x) ((x) & BIT41 ? (-1LL << 40) | (x) : x) static alureg_t nrdiv (alureg_t n, alureg_t d) { - t_int64 nn, dd, q, res; - alureg_t quot; + t_int64 nn, dd, q, res; + alureg_t quot; - /* to compensate for potential normalization to the right */ - nn = INT64(n.mantissa)*2; - dd = INT64(d.mantissa)*2; - res = 0, q = BIT41; + /* to compensate for potential normalization to the right */ + nn = INT64(n.mantissa)*2; + dd = INT64(d.mantissa)*2; + res = 0, q = BIT41; - if (ABS(nn) >= ABS(dd)) { - /* normalization to the right */ - nn/=2; - n.exponent++; - } - while (q > 1) { - if (nn == 0) - break; + if (ABS(nn) >= ABS(dd)) { + /* normalization to the right */ + nn/=2; + n.exponent++; + } + while (q > 1) { + if (nn == 0) + break; - if (ABS(nn) < BIT40) - nn *= 2; /* magic shortcut */ - else if ((nn > 0) ^ (dd > 0)) { - res -= q; - nn = 2*nn+dd; - } else { - res += q; - nn = 2*nn-dd; - } - q /= 2; - } - quot.mantissa = res/2; - quot.exponent = n.exponent-d.exponent+64; - return quot; + if (ABS(nn) < BIT40) + nn *= 2; /* magic shortcut */ + else if ((nn > 0) ^ (dd > 0)) { + res -= q; + nn = 2*nn+dd; + } else { + res += q; + nn = 2*nn-dd; + } + q /= 2; + } + quot.mantissa = res/2; + quot.exponent = n.exponent-d.exponent+64; + return quot; } /* @@ -300,19 +300,19 @@ static alureg_t nrdiv (alureg_t n, alureg_t d) */ void besm6_divide (t_value val) { - alureg_t acc; - alureg_t dividend, divisor; + alureg_t acc; + alureg_t dividend, divisor; - if (((val ^ (val << 1)) & BIT41) == 0) { - /* Ненормализованный делитель: деление на ноль. */ - longjmp (cpu_halt, STOP_DIVZERO); - } - dividend = toalu(ACC); - divisor = toalu(val); + if (((val ^ (val << 1)) & BIT41) == 0) { + /* Ненормализованный делитель: деление на ноль. */ + longjmp (cpu_halt, STOP_DIVZERO); + } + dividend = toalu(ACC); + divisor = toalu(val); - acc = nrdiv(dividend, divisor); + acc = nrdiv(dividend, divisor); - normalize_and_round (acc, 0, 0); + normalize_and_round (acc, 0, 0); } /* @@ -322,56 +322,56 @@ void besm6_divide (t_value val) */ void besm6_multiply (t_value val) { - uint8 neg = 0; - alureg_t acc, word, a, b; - t_uint64 mr, alo, blo, ahi, bhi; + uint8 neg = 0; + alureg_t acc, word, a, b; + t_uint64 mr, alo, blo, ahi, bhi; - register t_uint64 l; + register t_uint64 l; - if (! ACC || ! val) { - /* multiplication by zero is zero */ - ACC = 0; - RMR &= ~BITS40; - return; - } - acc = toalu (ACC); - word = toalu (val); + if (! ACC || ! val) { + /* multiplication by zero is zero */ + ACC = 0; + RMR &= ~BITS40; + return; + } + acc = toalu (ACC); + word = toalu (val); - a = acc; - b = word; - mr = 0; + a = acc; + b = word; + mr = 0; - if (is_negative (&a)) { - neg = 1; - negate (&a); - } - if (is_negative (&b)) { - neg ^= 1; - negate (&b); - } - acc.exponent = a.exponent + b.exponent - 64; + if (is_negative (&a)) { + neg = 1; + negate (&a); + } + if (is_negative (&b)) { + neg ^= 1; + negate (&b); + } + acc.exponent = a.exponent + b.exponent - 64; - alo = a.mantissa & BITS(20); - ahi = a.mantissa >> 20; + alo = a.mantissa & BITS(20); + ahi = a.mantissa >> 20; - blo = b.mantissa & BITS(20); - bhi = b.mantissa >> 20; + blo = b.mantissa & BITS(20); + bhi = b.mantissa >> 20; - l = alo * blo + ((alo * bhi + ahi * blo) << 20); + l = alo * blo + ((alo * bhi + ahi * blo) << 20); - mr = l & BITS40; - l >>= 40; + mr = l & BITS40; + l >>= 40; - acc.mantissa = l + ahi * bhi; + acc.mantissa = l + ahi * bhi; - if (neg) { - mr = (~mr & BITS40) + 1; - acc.mantissa = ((~acc.mantissa & BITS40) + (mr >> 40)) - | BIT41 | BIT42; - mr &= BITS40; - } + if (neg) { + mr = (~mr & BITS40) + 1; + acc.mantissa = ((~acc.mantissa & BITS40) + (mr >> 40)) + | BIT41 | BIT42; + mr &= BITS40; + } - normalize_and_round (acc, mr, mr != 0); + normalize_and_round (acc, mr, mr != 0); } /* @@ -380,13 +380,13 @@ void besm6_multiply (t_value val) */ void besm6_change_sign (int negate_acc) { - alureg_t acc; + alureg_t acc; - acc = toalu (ACC); - if (negate_acc) - negate (&acc); - RMR = 0; - normalize_and_round (acc, 0, 0); + acc = toalu (ACC); + if (negate_acc) + negate (&acc); + RMR = 0; + normalize_and_round (acc, 0, 0); } /* @@ -395,12 +395,12 @@ void besm6_change_sign (int negate_acc) */ void besm6_add_exponent (int val) { - alureg_t acc; + alureg_t acc; - acc = toalu (ACC); - acc.exponent += val; - RMR = 0; - normalize_and_round (acc, 0, 0); + acc = toalu (ACC); + acc.exponent += val; + RMR = 0; + normalize_and_round (acc, 0, 0); } /* @@ -408,16 +408,16 @@ void besm6_add_exponent (int val) */ t_value besm6_pack (t_value val, t_value mask) { - t_value result; + t_value result; - result = 0; - for (; mask; mask>>=1, val>>=1) - if (mask & 1) { - result >>= 1; - if (val & 1) - result |= BIT48; - } - return result; + result = 0; + for (; mask; mask>>=1, val>>=1) + if (mask & 1) { + result >>= 1; + if (val & 1) + result |= BIT48; + } + return result; } /* @@ -425,20 +425,20 @@ t_value besm6_pack (t_value val, t_value mask) */ t_value besm6_unpack (t_value val, t_value mask) { - t_value result; - int i; + t_value result; + int i; - result = 0; - for (i=0; i<48; ++i) { - result <<= 1; - if (mask & BIT48) { - if (val & BIT48) - result |= 1; - val <<= 1; - } - mask <<= 1; - } - return result; + result = 0; + for (i=0; i<48; ++i) { + result <<= 1; + if (mask & BIT48) { + if (val & BIT48) + result |= 1; + val <<= 1; + } + mask <<= 1; + } + return result; } /* @@ -446,11 +446,11 @@ t_value besm6_unpack (t_value val, t_value mask) */ int besm6_count_ones (t_value word) { - int c; + int c; - for (c=0; word; ++c) - word &= word-1; - return c; + for (c=0; word; ++c) + word &= word-1; + return c; } /* @@ -459,25 +459,25 @@ int besm6_count_ones (t_value word) */ void besm6_shift (int i) { - RMR = 0; - if (i > 0) { - /* Сдвиг вправо. */ - if (i < 48) { - RMR = (ACC << (48-i)) & BITS48; - ACC >>= i; - } else { - RMR = ACC >> (i-48); - ACC = 0; - } - } else if (i < 0) { - /* Сдвиг влево. */ - i = -i; - if (i < 48) { - RMR = ACC >> (48-i); - ACC = (ACC << i) & BITS48; - } else { - RMR = (ACC << (i-48)) & BITS48; - ACC = 0; - } - } + RMR = 0; + if (i > 0) { + /* Сдвиг вправо. */ + if (i < 48) { + RMR = (ACC << (48-i)) & BITS48; + ACC >>= i; + } else { + RMR = ACC >> (i-48); + ACC = 0; + } + } else if (i < 0) { + /* Сдвиг влево. */ + i = -i; + if (i < 48) { + RMR = ACC >> (48-i); + ACC = (ACC << i) & BITS48; + } else { + RMR = (ACC << (i-48)) & BITS48; + ACC = 0; + } + } } diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 4b782a1e..9da7c6be 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -98,189 +98,189 @@ t_stat cpu_reset (DEVICE *dptr); UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MEMSIZE) }; REG cpu_reg[] = { -{ "СчАС", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ -{ "РК", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ -{ "Аисп", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ -{ "СМ", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ -{ "РМР", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ -{ "РАУ", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ -{ "М1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ -{ "М2", &M[2], 8, 15, 0, 1 }, -{ "М3", &M[3], 8, 15, 0, 1 }, -{ "М4", &M[4], 8, 15, 0, 1 }, -{ "М5", &M[5], 8, 15, 0, 1 }, -{ "М6", &M[6], 8, 15, 0, 1 }, -{ "М7", &M[7], 8, 15, 0, 1 }, -{ "М10", &M[010], 8, 15, 0, 1 }, -{ "М11", &M[011], 8, 15, 0, 1 }, -{ "М12", &M[012], 8, 15, 0, 1 }, -{ "М13", &M[013], 8, 15, 0, 1 }, -{ "М14", &M[014], 8, 15, 0, 1 }, -{ "М15", &M[015], 8, 15, 0, 1 }, -{ "М16", &M[016], 8, 15, 0, 1 }, -{ "М17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ -{ "М20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ -{ "М21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ -{ "М27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ -{ "М32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ -{ "М33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ -{ "М34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ -{ "М35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ -{ "РУУ", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ -{ "ГРП", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ -{ "МГРП", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ -{ "ПРП", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ -{ "МПРП", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ -{ 0 } + { "СчАС", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ + { "РК", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ + { "Аисп", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ + { "СМ", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ + { "РМР", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ + { "РАУ", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ + { "М1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ + { "М2", &M[2], 8, 15, 0, 1 }, + { "М3", &M[3], 8, 15, 0, 1 }, + { "М4", &M[4], 8, 15, 0, 1 }, + { "М5", &M[5], 8, 15, 0, 1 }, + { "М6", &M[6], 8, 15, 0, 1 }, + { "М7", &M[7], 8, 15, 0, 1 }, + { "М10", &M[010], 8, 15, 0, 1 }, + { "М11", &M[011], 8, 15, 0, 1 }, + { "М12", &M[012], 8, 15, 0, 1 }, + { "М13", &M[013], 8, 15, 0, 1 }, + { "М14", &M[014], 8, 15, 0, 1 }, + { "М15", &M[015], 8, 15, 0, 1 }, + { "М16", &M[016], 8, 15, 0, 1 }, + { "М17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ + { "М20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ + { "М21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ + { "М27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ + { "М32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ + { "М33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ + { "М34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ + { "М35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ + { "РУУ", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ + { "ГРП", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ + { "МГРП", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ + { "ПРП", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ + { "МПРП", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ + { 0 } }; MTAB cpu_mod[] = { - { 0 } + { 0 } }; DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 17, 1, 8, 50, - &cpu_examine, &cpu_deposit, &cpu_reset, - NULL, NULL, NULL, NULL, - DEV_DEBUG + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 8, 17, 1, 8, 50, + &cpu_examine, &cpu_deposit, &cpu_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG }; /* * REG: псевдоустройство, содержащее латинские синонимы всех регистров. */ REG reg_reg[] = { -{ "PC", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ -{ "RK", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ -{ "Aex", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ -{ "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ -{ "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ -{ "RAU", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ -{ "M1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ -{ "M2", &M[2], 8, 15, 0, 1 }, -{ "M3", &M[3], 8, 15, 0, 1 }, -{ "M4", &M[4], 8, 15, 0, 1 }, -{ "M5", &M[5], 8, 15, 0, 1 }, -{ "M6", &M[6], 8, 15, 0, 1 }, -{ "M7", &M[7], 8, 15, 0, 1 }, -{ "M10", &M[010], 8, 15, 0, 1 }, -{ "M11", &M[011], 8, 15, 0, 1 }, -{ "M12", &M[012], 8, 15, 0, 1 }, -{ "M13", &M[013], 8, 15, 0, 1 }, -{ "M14", &M[014], 8, 15, 0, 1 }, -{ "M15", &M[015], 8, 15, 0, 1 }, -{ "M16", &M[016], 8, 15, 0, 1 }, -{ "M17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ -{ "M20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ -{ "M21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ -{ "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ -{ "M32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ -{ "M33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ -{ "M34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ -{ "M35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ -{ "RUU", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ -{ "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ -{ "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ -{ "PRP", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ -{ "MPRP", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ + { "PC", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ + { "RK", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ + { "Aex", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ + { "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ + { "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ + { "RAU", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ + { "M1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ + { "M2", &M[2], 8, 15, 0, 1 }, + { "M3", &M[3], 8, 15, 0, 1 }, + { "M4", &M[4], 8, 15, 0, 1 }, + { "M5", &M[5], 8, 15, 0, 1 }, + { "M6", &M[6], 8, 15, 0, 1 }, + { "M7", &M[7], 8, 15, 0, 1 }, + { "M10", &M[010], 8, 15, 0, 1 }, + { "M11", &M[011], 8, 15, 0, 1 }, + { "M12", &M[012], 8, 15, 0, 1 }, + { "M13", &M[013], 8, 15, 0, 1 }, + { "M14", &M[014], 8, 15, 0, 1 }, + { "M15", &M[015], 8, 15, 0, 1 }, + { "M16", &M[016], 8, 15, 0, 1 }, + { "M17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ + { "M20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ + { "M21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ + { "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ + { "M32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ + { "M33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ + { "M34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ + { "M35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ + { "RUU", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ + { "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ + { "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ + { "PRP", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ + { "MPRP", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ -{ "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BRZ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "BAZ0", &BAZ[0], 8, 16, 0, 1 }, -{ "BAZ1", &BAZ[1], 8, 16, 0, 1 }, -{ "BAZ2", &BAZ[2], 8, 16, 0, 1 }, -{ "BAZ3", &BAZ[3], 8, 16, 0, 1 }, -{ "BAZ4", &BAZ[4], 8, 16, 0, 1 }, -{ "BAZ5", &BAZ[5], 8, 16, 0, 1 }, -{ "BAZ6", &BAZ[6], 8, 16, 0, 1 }, -{ "BAZ7", &BAZ[7], 8, 16, 0, 1 }, -{ "TABST", &TABST, 8, 28, 0, 1 }, -{ "RP0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RP7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, -{ "RZ", &RZ, 8, 32, 0, 1 }, -{ "FP1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ "FP7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, -{ 0 } + { "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BRZ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "BAZ0", &BAZ[0], 8, 16, 0, 1 }, + { "BAZ1", &BAZ[1], 8, 16, 0, 1 }, + { "BAZ2", &BAZ[2], 8, 16, 0, 1 }, + { "BAZ3", &BAZ[3], 8, 16, 0, 1 }, + { "BAZ4", &BAZ[4], 8, 16, 0, 1 }, + { "BAZ5", &BAZ[5], 8, 16, 0, 1 }, + { "BAZ6", &BAZ[6], 8, 16, 0, 1 }, + { "BAZ7", &BAZ[7], 8, 16, 0, 1 }, + { "TABST", &TABST, 8, 28, 0, 1 }, + { "RP0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RP7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO }, + { "RZ", &RZ, 8, 32, 0, 1 }, + { "FP1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "FP2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "FP3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "FP4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "FP5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "FP6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { "FP7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, + { 0 } }; UNIT reg_unit = { - UDATA (NULL, 0, 8) + UDATA (NULL, 0, 8) }; DEVICE reg_dev = { - "REG", ®_unit, reg_reg, NULL, - 1, 8, 1, 1, 8, 50, + "REG", ®_unit, reg_reg, NULL, + 1, 8, 1, 1, 8, 50, }; /* * SCP data structures and interface routines * - * sim_name simulator name string - * sim_PC pointer to saved PC register descriptor - * sim_emax maximum number of words for examine/deposit - * sim_devices array of pointers to simulated devices - * sim_stop_messages array of pointers to stop messages - * sim_load binary loader + * sim_name simulator name string + * sim_PC pointer to saved PC register descriptor + * sim_emax maximum number of words for examine/deposit + * sim_devices array of pointers to simulated devices + * sim_stop_messages array of pointers to stop messages + * sim_load binary loader */ char sim_name[] = "БЭСМ-6"; REG *sim_PC = &cpu_reg[0]; -int32 sim_emax = 1; /* максимальное количество слов в машинной команде */ +int32 sim_emax = 1; /* максимальное количество слов в машинной команде */ DEVICE *sim_devices[] = { - &cpu_dev, - ®_dev, - &drum_dev, - &disk_dev, - &mmu_dev, - &clock_dev, - &printer_dev, - &fs_dev, - &tty_dev, /* терминалы - телетайпы, видеотоны, "Консулы" */ - 0 + &cpu_dev, + ®_dev, + &drum_dev, + &disk_dev, + &mmu_dev, + &clock_dev, + &printer_dev, + &fs_dev, + &tty_dev, /* терминалы - телетайпы, видеотоны, "Консулы" */ + 0 }; const char *sim_stop_messages[] = { - "Неизвестная ошибка", /* Unknown error */ - "Останов", /* STOP */ - "Точка останова", /* Emulator breakpoint */ - "Точка останова по считыванию", /* Emulator read watchpoint */ - "Точка останова по записи", /* Emulator write watchpoint */ - "Выход за пределы памяти", /* Run out end of memory */ - "Запрещенная команда", /* Invalid instruction */ - "Контроль команды", /* A data-tagged word fetched */ - "Команда в чужом листе", /* Paging error during fetch */ - "Число в чужом листе", /* Paging error during load/store */ - "Контроль числа МОЗУ", /* RAM parity error */ - "Контроль числа БРЗ", /* Write cache parity error */ - "Переполнение АУ", /* Arith. overflow */ - "Деление на нуль", /* Division by zero or denorm */ - "Двойное внутреннее прерывание", /* SIMH: Double internal interrupt */ - "Чтение неформатированного барабана", /* Reading unformatted drum */ - "Чтение неформатированного диска", /* Reading unformatted disk */ - "Останов по КРА", /* Hardware breakpoint */ - "Останов по считыванию", /* Load watchpoint */ - "Останов по записи", /* Store watchpoint */ - "Не реализовано", /* Unimplemented I/O or special reg. access */ + "Неизвестная ошибка", /* Unknown error */ + "Останов", /* STOP */ + "Точка останова", /* Emulator breakpoint */ + "Точка останова по считыванию", /* Emulator read watchpoint */ + "Точка останова по записи", /* Emulator write watchpoint */ + "Выход за пределы памяти", /* Run out end of memory */ + "Запрещенная команда", /* Invalid instruction */ + "Контроль команды", /* A data-tagged word fetched */ + "Команда в чужом листе", /* Paging error during fetch */ + "Число в чужом листе", /* Paging error during load/store */ + "Контроль числа МОЗУ", /* RAM parity error */ + "Контроль числа БРЗ", /* Write cache parity error */ + "Переполнение АУ", /* Arith. overflow */ + "Деление на нуль", /* Division by zero or denorm */ + "Двойное внутреннее прерывание", /* SIMH: Double internal interrupt */ + "Чтение неформатированного барабана", /* Reading unformatted drum */ + "Чтение неформатированного диска", /* Reading unformatted disk */ + "Останов по КРА", /* Hardware breakpoint */ + "Останов по считыванию", /* Load watchpoint */ + "Останов по записи", /* Store watchpoint */ + "Не реализовано", /* Unimplemented I/O or special reg. access */ }; /* @@ -288,15 +288,15 @@ const char *sim_stop_messages[] = { */ t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { - if (addr >= MEMSIZE) - return SCPE_NXM; - if (vptr) { - if (addr < 010) - *vptr = pult [addr]; - else - *vptr = memory [addr]; - } - return SCPE_OK; + if (addr >= MEMSIZE) + return SCPE_NXM; + if (vptr) { + if (addr < 010) + *vptr = pult [addr]; + else + *vptr = memory [addr]; + } + return SCPE_OK; } /* @@ -304,13 +304,13 @@ t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) */ t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw) { - if (addr >= MEMSIZE) - return SCPE_NXM; - if (addr < 010) - pult [addr] = SET_CONVOL (val, CONVOL_INSN); - else - memory [addr] = SET_CONVOL (val, CONVOL_INSN); - return SCPE_OK; + if (addr >= MEMSIZE) + return SCPE_NXM; + if (addr < 010) + pult [addr] = SET_CONVOL (val, CONVOL_INSN); + else + memory [addr] = SET_CONVOL (val, CONVOL_INSN); + return SCPE_OK; } /* @@ -318,26 +318,26 @@ t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw) */ static void cpu_sigalarm (int signum) { - static unsigned counter; + static unsigned counter; - ++counter; + ++counter; #ifndef SOFT_CLOCK - /* В 9-й части частота таймера 250 Гц (4 мс). */ - GRP |= GRP_TIMER; + /* В 9-й части частота таймера 250 Гц (4 мс). */ + GRP |= GRP_TIMER; - /* Медленный таймер: должен быть 16 Гц. - * Но от него почему-то зависит вывод на терминалы, - * поэтому ускорим. */ - if ((counter & 3) == 0) { - GRP |= GRP_SLOW_CLK; - } + /* Медленный таймер: должен быть 16 Гц. + * Но от него почему-то зависит вывод на терминалы, + * поэтому ускорим. */ + if ((counter & 3) == 0) { + GRP |= GRP_SLOW_CLK; + } #endif - /* Перерисовка панели каждые 64 миллисекунды. */ - if ((counter & 15) == 0) { - redraw_panel = 1; - } + /* Перерисовка панели каждые 64 миллисекунды. */ + if ((counter & 15) == 0) { + redraw_panel = 1; + } } /* @@ -345,44 +345,44 @@ static void cpu_sigalarm (int signum) */ t_stat cpu_reset (DEVICE *dptr) { - int i; + int i; - ACC = 0; - RMR = 0; - RAU = 0; - RUU = RUU_EXTRACODE | RUU_AVOST_DISABLE; - for (i=0; i> 6 | 0xc0, fout); - putc ((ch & 0x3f) | 0x80, fout); - return; - } - putc (ch >> 12 | 0xe0, fout); - putc (((ch >> 6) & 0x3f) | 0x80, fout); - putc ((ch & 0x3f) | 0x80, fout); + if (ch < 0x80) { + putc (ch, fout); + return; + } + if (ch < 0x800) { + putc (ch >> 6 | 0xc0, fout); + putc ((ch & 0x3f) | 0x80, fout); + return; + } + putc (ch >> 12 | 0xe0, fout); + putc (((ch >> 6) & 0x3f) | 0x80, fout); + putc ((ch & 0x3f) | 0x80, fout); } /* @@ -415,27 +415,27 @@ utf8_putc (unsigned ch, FILE *fout) */ void besm6_okno (const char *message) { - besm6_log_cont ("_%%%%%% %s: ", message); - if (sim_log) - besm6_fprint_cmd (sim_log, RK); - besm6_log ("_"); + besm6_log_cont ("_%%%%%% %s: ", message); + if (sim_log) + besm6_fprint_cmd (sim_log, RK); + besm6_log ("_"); - /* СчАС, системные индекс-регистры 020-035. */ - besm6_log ("_ СчАС:%05o 20:%05o 21:%05o 27:%05o 32:%05o 33:%05o 34:%05o 35:%05o", - PC, M[020], M[021], M[027], M[032], M[033], M[034], M[035]); - /* Индекс-регистры 1-7. */ - besm6_log ("_ 1:%05o 2:%05o 3:%05o 4:%05o 5:%05o 6:%05o 7:%05o", - M[1], M[2], M[3], M[4], M[5], M[6], M[7]); - /* Индекс-регистры 010-017. */ - besm6_log ("_ 10:%05o 11:%05o 12:%05o 13:%05o 14:%05o 15:%05o 16:%05o 17:%05o", - M[010], M[011], M[012], M[013], M[014], M[015], M[016], M[017]); - /* Сумматор, РМР, режимы АУ и УУ. */ - besm6_log ("_ СМ:%04o %04o %04o %04o РМР:%04o %04o %04o %04o РАУ:%02o РУУ:%03o", - (int) (ACC >> 36) & BITS(12), (int) (ACC >> 24) & BITS(12), - (int) (ACC >> 12) & BITS(12), (int) ACC & BITS(12), - (int) (RMR >> 36) & BITS(12), (int) (RMR >> 24) & BITS(12), - (int) (RMR >> 12) & BITS(12), (int) RMR & BITS(12), - RAU, RUU); + /* СчАС, системные индекс-регистры 020-035. */ + besm6_log ("_ СчАС:%05o 20:%05o 21:%05o 27:%05o 32:%05o 33:%05o 34:%05o 35:%05o", + PC, M[020], M[021], M[027], M[032], M[033], M[034], M[035]); + /* Индекс-регистры 1-7. */ + besm6_log ("_ 1:%05o 2:%05o 3:%05o 4:%05o 5:%05o 6:%05o 7:%05o", + M[1], M[2], M[3], M[4], M[5], M[6], M[7]); + /* Индекс-регистры 010-017. */ + besm6_log ("_ 10:%05o 11:%05o 12:%05o 13:%05o 14:%05o 15:%05o 16:%05o 17:%05o", + M[010], M[011], M[012], M[013], M[014], M[015], M[016], M[017]); + /* Сумматор, РМР, режимы АУ и УУ. */ + besm6_log ("_ СМ:%04o %04o %04o %04o РМР:%04o %04o %04o %04o РАУ:%02o РУУ:%03o", + (int) (ACC >> 36) & BITS(12), (int) (ACC >> 24) & BITS(12), + (int) (ACC >> 12) & BITS(12), (int) ACC & BITS(12), + (int) (RMR >> 36) & BITS(12), (int) (RMR >> 24) & BITS(12), + (int) (RMR >> 12) & BITS(12), (int) RMR & BITS(12), + RAU, RUU); } /* @@ -444,66 +444,72 @@ void besm6_okno (const char *message) static void cmd_002 () { #if 0 - besm6_debug ("*** рег %03o", Aex & 0377); + besm6_debug ("*** рег %03o", Aex & 0377); #endif - switch (Aex & 0377) { - case 0 ... 7: - /* Запись в БРЗ */ - mmu_setcache (Aex & 7, ACC); - break; - case 020 ... 027: - /* Запись в регистры приписки */ - mmu_setrp (Aex & 7, ACC); - break; - case 030 ... 033: - /* Запись в регистры защиты */ - mmu_setprotection (Aex & 3, ACC); - break; - case 036: - /* Запись в маску главного регистра прерываний */ - MGRP = ACC; - break; - case 037: - /* Гашение главного регистра прерываний */ - /* нехранящие биты невозможно погасить */ - GRP &= ACC | GRP_WIRED_BITS; - break; - case 0100 ... 0137: - /* Бит 1: управление блокировкой режима останова БРО. - * Биты 2 и 3 - признаки формирования контрольных - * разрядов (ПКП и ПКЛ). */ - if (Aex & 1) - RUU |= RUU_AVOST_DISABLE; - else - RUU &= ~RUU_AVOST_DISABLE; - if (Aex & 2) - RUU |= RUU_CONVOL_RIGHT; - else - RUU &= ~RUU_CONVOL_RIGHT; - if (Aex & 4) - RUU |= RUU_CONVOL_LEFT; - else - RUU &= ~RUU_CONVOL_LEFT; - break; - case 0140 ... 0177: - /* TODO: управление блокировкой схемы - * автоматического запуска */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0200 ... 0207: - /* Чтение БРЗ */ - ACC = mmu_getcache (Aex & 7); - break; - case 0237: - /* Чтение главного регистра прерываний */ - ACC = GRP; - break; - default: - /* Неиспользуемые адреса */ - besm6_debug ("*** %05o%s: РЕГ %o - неправильный адрес спец.регистра", - PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); - break; - } + switch (Aex & 0377) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* Запись в БРЗ */ + mmu_setcache (Aex & 7, ACC); + break; + case 020: case 021: case 022: case 023: + case 024: case 025: case 026: case 027: + /* Запись в регистры приписки */ + mmu_setrp (Aex & 7, ACC); + break; + case 030: case 031: case 032: case 033: + /* Запись в регистры защиты */ + mmu_setprotection (Aex & 3, ACC); + break; + case 036: + /* Запись в маску главного регистра прерываний */ + MGRP = ACC; + break; + case 037: + /* Гашение главного регистра прерываний */ + /* нехранящие биты невозможно погасить */ + GRP &= ACC | GRP_WIRED_BITS; + break; + case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: + case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: + case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: + case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: + /* 0100 - 0137: + * Бит 1: управление блокировкой режима останова БРО. + * Биты 2 и 3 - признаки формирования контрольных + * разрядов (ПКП и ПКЛ). */ + if (Aex & 1) + RUU |= RUU_AVOST_DISABLE; + else + RUU &= ~RUU_AVOST_DISABLE; + if (Aex & 2) + RUU |= RUU_CONVOL_RIGHT; + else + RUU &= ~RUU_CONVOL_RIGHT; + if (Aex & 4) + RUU |= RUU_CONVOL_LEFT; + else + RUU &= ~RUU_CONVOL_LEFT; + break; + case 0200: case 0201: case 0202: case 0203: + case 0204: case 0205: case 0206: case 0207: + /* Чтение БРЗ */ + ACC = mmu_getcache (Aex & 7); + break; + case 0237: + /* Чтение главного регистра прерываний */ + ACC = GRP; + break; + default: + if ((Aex & 0340) == 0140) { + /* TODO: управление блокировкой схемы + * автоматического запуска */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + } + /* Неиспользуемые адреса */ + besm6_debug ("*** %05o%s: РЕГ %o - неправильный адрес спец.регистра", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); + break; + } } /* @@ -512,278 +518,281 @@ static void cmd_002 () static void cmd_033 () { #if 0 - besm6_debug ("*** увв %04o, СМ[24:1]=%08o", - Aex & 04177, (uint32) ACC & BITS(24)); + besm6_debug ("*** увв %04o, СМ[24:1]=%08o", + Aex & 04177, (uint32) ACC & BITS(24)); #endif - switch (Aex & 04177) { - case 0: - /* Точно неизвестно, что это такое, но драйвер МД - * иногда выдает команду "увв 0". */ - break; - case 1 ... 2: - /* Управление обменом с магнитными барабанами */ - drum (Aex - 1, (uint32) ACC); - break; - case 3 ... 4: - /* Передача управляющего слова для обмена - * с магнитными дисками */ - disk_io (Aex - 3, (uint32) ACC); - break; - case 5 ... 7: - /* TODO: управление обменом с магнитными лентами */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 010 ... 011: - /* управление устройствами ввода с перфоленты */ - fs_control (Aex - 010, (uint32) (ACC & 07)); - break; - case 012 ... 013: - /* TODO: управление устройствами ввода с перфоленты по запаянной программе */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 014 ... 015: - /* Управление АЦПУ */ - printer_control (Aex - 014, (uint32) (ACC & 017)); - break; - case 023 ... 024: - /* Управление обменом с магнитными дисками */ - disk_ctl (Aex - 023, (uint32) ACC); - break; - case 030: - /* Гашение ПРП */ -/* besm6_debug(">>> гашение ПРП");*/ - PRP &= ACC | PRP_WIRED_BITS; - break; - case 031: - /* Имитация сигналов прерывания ГРП */ - /*besm6_debug ("*** %05o%s: имитация прерываний ГРП %016llo", - PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", ACC << 24);*/ - GRP |= (ACC & BITS(24)) << 24; - break; - case 032 ... 033: - /* TODO: имитация сигналов из КМБ в КВУ */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 034: - /* Запись в МПРП */ -/* besm6_debug(">>> запись в МПРП");*/ - MPRP = ACC & 077777777; - break; - case 035: - /* TODO: управление режимом имитации обмена - * с МБ и МЛ, имитация обмена */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 040 ... 057: - /* Управление молоточками АЦПУ */ - printer_hammer (Aex >= 050, Aex & 7, (uint32) (ACC & BITS(16))); - break; - case 0100 ... 0137: - /* Управление лентопротяжными механизмами - * и гашение разрядов регистров признаков - * окончания подвода зоны. Игнорируем. */ - break; - case 0140: - /* Запись в регистр телеграфных каналов */ - tty_send ((uint32) ACC & BITS(24)); - break; - case 0141: - /* TODO: управление разметкой магнитной ленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0142: - /* TODO: имитация сигналов прерывания ПРП */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0147: - /* Запись в регистр управления электропитанием, */ - /* не оказывает видимого эффекта на выполнение */ - break; - case 0150 ... 0151: - /* TODO: управление вводом с перфокарт */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0153: - /* гашение аппаратуры сопряжения с терминалами */ -/* besm6_debug(">>> гашение АС: %08o", (uint32) ACC & BITS(24));*/ - break; - case 0154 ... 0155: - /* TODO: управление выводом на перфокарты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0160 ... 0167: - /* TODO: управление электромагнитами пробивки перфокарт */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0170 ... 0171: - /* TODO: пробивка строки на перфоленте */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 0174 ... 0175: - /* Выдача кода в пульт оператора */ - consul_print (Aex & 1, (uint32) ACC & BITS(8)); - break; - case 0177: - /* управление табло ГПВЦ СО АН СССР */ -/* besm6_debug(">>> ТАБЛО: %08o", (uint32) ACC & BITS(24));*/ - break; - case 04001 ... 04002: - /* TODO: считывание слога в режиме имитации обмена */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04003 ... 04004: - /* Запрос статуса контроллера магнитных дисков */ - ACC = disk_state (Aex - 04003); - break; - case 04006: - /* TODO: считывание строки с устройства ввода - * с перфоленты в запаянной программе */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04007: - /* TODO: опрос синхроимпульса ненулевой строки - * в запаянной программе ввода с перфоленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04014 ... 04015: - /* считывание строки с устройства ввода с перфоленты */ - ACC = fs_read (Aex - 04014); - break; - case 04016 ... 04017: - /* TODO: считывание строки с устройства - * ввода с перфоленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04020 ... 04023: - /* TODO: считывание слога в режиме имитации - * внешнего обмена */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04030: - /* Чтение старшей половины ПРП */ - ACC = PRP & 077770000; - break; - case 04031: - /* Опрос сигналов готовности (АЦПУ и пр.) */ -/* besm6_debug("Reading READY");*/ - ACC = READY; - break; - case 04034: - /* Чтение младшей половины ПРП */ - ACC = (PRP & 07777) | 0377; - break; - case 04035: - /* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */ - ACC = drum_errors() | disk_errors(); - break; - case 04100: - /* Опрос телеграфных каналов связи */ - ACC = tty_query (); - break; - case 04102: - /* Опрос сигналов готовности перфокарт и перфолент */ -/* besm6_debug("Reading punchcard/punchtape READY @%05o", PC);*/ - ACC = READY2; - break; - case 04103 ... 04106: - /* Опрос состояния лентопротяжных механизмов. - * Все устройства не готовы. */ - ACC = BITS(24); - break; - case 04107: - /* TODO: опрос схемы контроля записи на МЛ */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04115: - /* Неизвестное обращение. ДИСПАК выдаёт эту команду - * группами по 8 штук каждые несколько секунд. */ - ACC = 0; - break; - case 04140 ... 04157: - /* TODO: считывание строки перфокарты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04160 ... 04167: - /* TODO: контрольное считывание строки перфокарты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04170 ... 04173: - /* TODO: считывание контрольного кода - * строки перфоленты */ - longjmp (cpu_halt, STOP_UNIMPLEMENTED); - break; - case 04174 ... 04175: - /* Считывание кода с пульта оператора */ - ACC = consul_read (Aex & 1); - break; - case 04177: - /* чтение табло ГПВЦ СО АН СССР */ - ACC = 0; - break; - default: - /* Неиспользуемые адреса */ -/* if (sim_deb && cpu_dev.dctrl)*/ - besm6_debug ("*** %05o%s: УВВ %o - неправильный адрес ввода-вывода", - PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); - ACC = 0; - break; - } + switch (Aex & 04177) { + case 0: + /* Точно неизвестно, что это такое, но драйвер МД + * иногда выдает команду "увв 0". */ + break; + case 1: case 2: + /* Управление обменом с магнитными барабанами */ + drum (Aex - 1, (uint32) ACC); + break; + case 3: case 4: + /* Передача управляющего слова для обмена + * с магнитными дисками */ + disk_io (Aex - 3, (uint32) ACC); + break; + case 5: case 6: case 7: + /* TODO: управление обменом с магнитными лентами */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 010: case 011: + /* управление устройствами ввода с перфоленты */ + fs_control (Aex - 010, (uint32) (ACC & 07)); + break; + case 012: case 013: + /* TODO: управление устройствами ввода с перфоленты по запаянной программе */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 014: case 015: + /* Управление АЦПУ */ + printer_control (Aex - 014, (uint32) (ACC & 017)); + break; + case 023: case 024: + /* Управление обменом с магнитными дисками */ + disk_ctl (Aex - 023, (uint32) ACC); + break; + case 030: + /* Гашение ПРП */ +/* besm6_debug(">>> гашение ПРП");*/ + PRP &= ACC | PRP_WIRED_BITS; + break; + case 031: + /* Имитация сигналов прерывания ГРП */ + /*besm6_debug ("*** %05o%s: имитация прерываний ГРП %016llo", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", ACC << 24);*/ + GRP |= (ACC & BITS(24)) << 24; + break; + case 032: case 033: + /* TODO: имитация сигналов из КМБ в КВУ */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 034: + /* Запись в МПРП */ +/* besm6_debug(">>> запись в МПРП");*/ + MPRP = ACC & 077777777; + break; + case 035: + /* TODO: управление режимом имитации обмена + * с МБ и МЛ, имитация обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 040: case 041: case 042: case 043: + case 044: case 045: case 046: case 047: + case 050: case 051: case 052: case 053: + case 054: case 055: case 056: case 057: + /* Управление молоточками АЦПУ */ + printer_hammer (Aex >= 050, Aex & 7, (uint32) (ACC & BITS(16))); + break; + case 0140: + /* Запись в регистр телеграфных каналов */ + tty_send ((uint32) ACC & BITS(24)); + break; + case 0141: + /* TODO: управление разметкой магнитной ленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0142: + /* TODO: имитация сигналов прерывания ПРП */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0147: + /* Запись в регистр управления электропитанием, */ + /* не оказывает видимого эффекта на выполнение */ + break; + case 0150: case 0151: + /* TODO: управление вводом с перфокарт */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0153: + /* гашение аппаратуры сопряжения с терминалами */ +/* besm6_debug(">>> гашение АС: %08o", (uint32) ACC & BITS(24));*/ + break; + case 0154: case 0155: + /* TODO: управление выводом на перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0160: case 0167: + /* TODO: управление электромагнитами пробивки перфокарт */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0170: case 0171: + /* TODO: пробивка строки на перфоленте */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 0174: case 0175: + /* Выдача кода в пульт оператора */ + consul_print (Aex & 1, (uint32) ACC & BITS(8)); + break; + case 0177: + /* управление табло ГПВЦ СО АН СССР */ +/* besm6_debug(">>> ТАБЛО: %08o", (uint32) ACC & BITS(24));*/ + break; + case 04001: case 04002: + /* TODO: считывание слога в режиме имитации обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04003: case 04004: + /* Запрос статуса контроллера магнитных дисков */ + ACC = disk_state (Aex - 04003); + break; + case 04006: + /* TODO: считывание строки с устройства ввода + * с перфоленты в запаянной программе */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04007: + /* TODO: опрос синхроимпульса ненулевой строки + * в запаянной программе ввода с перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04014: case 04015: + /* считывание строки с устройства ввода с перфоленты */ + ACC = fs_read (Aex - 04014); + break; + case 04016: case 04017: + /* TODO: считывание строки с устройства + * ввода с перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04020: case 04021: case 04022: case 04023: + /* TODO: считывание слога в режиме имитации + * внешнего обмена */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04030: + /* Чтение старшей половины ПРП */ + ACC = PRP & 077770000; + break; + case 04031: + /* Опрос сигналов готовности (АЦПУ и пр.) */ +/* besm6_debug("Reading READY");*/ + ACC = READY; + break; + case 04034: + /* Чтение младшей половины ПРП */ + ACC = (PRP & 07777) | 0377; + break; + case 04035: + /* Опрос триггера ОШМi - наличие ошибок при внешнем обмене. */ + ACC = drum_errors() | disk_errors(); + break; + case 04100: + /* Опрос телеграфных каналов связи */ + ACC = tty_query (); + break; + case 04102: + /* Опрос сигналов готовности перфокарт и перфолент */ +/* besm6_debug("Reading punchcard/punchtape READY @%05o", PC);*/ + ACC = READY2; + break; + case 04103: case 04104: case 04105: case 04106: + /* Опрос состояния лентопротяжных механизмов. + * Все устройства не готовы. */ + ACC = BITS(24); + break; + case 04107: + /* TODO: опрос схемы контроля записи на МЛ */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04115: + /* Неизвестное обращение. ДИСПАК выдаёт эту команду + * группами по 8 штук каждые несколько секунд. */ + ACC = 0; + break; + case 04170: case 04171: case 04172: case 04173: + /* TODO: считывание контрольного кода + * строки перфоленты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + break; + case 04174: case 04175: + /* Считывание кода с пульта оператора */ + ACC = consul_read (Aex & 1); + break; + case 04177: + /* чтение табло ГПВЦ СО АН СССР */ + ACC = 0; + break; + default: { + unsigned val = Aex & 04177; + if (0100 <= val && val <= 0137) { + /* Управление лентопротяжными механизмами + * и гашение разрядов регистров признаков + * окончания подвода зоны. Игнорируем. */ + } else if (04140 <= val && val <= 04157) { + /* TODO: считывание строки перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + } else if (04160 <= val && val <= 04167) { + /* TODO: контрольное считывание строки перфокарты */ + longjmp (cpu_halt, STOP_UNIMPLEMENTED); + } else { + /* Неиспользуемые адреса */ +/* if (sim_deb && cpu_dev.dctrl)*/ + besm6_debug ("*** %05o%s: УВВ %o - неправильный адрес ввода-вывода", + PC, (RUU & RUU_RIGHT_INSTR) ? "п" : "л", Aex); + ACC = 0; + } + } break; + } } void check_initial_setup () { - const int MGRP_COPY = 01455; /* OS version specific? */ - const int TAKEN = 0442; /* fixed? */ - const int YEAR = 0221; /* fixed */ + const int MGRP_COPY = 01455; /* OS version specific? */ + const int TAKEN = 0442; /* fixed? */ + const int YEAR = 0221; /* fixed */ - /* 47 р. яч. ЗАНЯТА - разр. приказы вообще */ - const t_value SETUP_REQS_ENABLED = 1LL << 46; + /* 47 р. яч. ЗАНЯТА - разр. приказы вообще */ + const t_value SETUP_REQS_ENABLED = 1LL << 46; - /* 7 р. яч. ЗАНЯТА - разр любые приказы */ - const t_value ALL_REQS_ENABLED = 1 << 6; + /* 7 р. яч. ЗАНЯТА - разр любые приказы */ + const t_value ALL_REQS_ENABLED = 1 << 6; - if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || - (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || - (MGRP & GRP_PANEL_REQ) == 0) { - /* Слишком рано, или уже не надо, или невовремя */ - return; - } + if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || + (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || + (MGRP & GRP_PANEL_REQ) == 0) { + /* Слишком рано, или уже не надо, или невовремя */ + return; + } - /* Выдаем приказы оператора СМЕ и ВРЕ, - * а дату корректируем непосредственно в памяти. - */ - /* Номер смены в 22-24 рр. МГРП: если еще не установлен, установить */ - if (((memory[MGRP_COPY] >> 21) & 3) == 0) { - /* приказ СМЕ: ТР6 = 010, ТР4 = 1, 22-24 р ТР5 - #смены */ - pult[6] = 010; - pult[4] = 1; - pult[5] = 1 << 21; - GRP |= GRP_PANEL_REQ; - } else { - /* Яч. ГОД обновляем самостоятельно */ - time_t t; - t_value date; - time(&t); - struct tm * d; - d = localtime(&t); - ++d->tm_mon; - date = (t_value) (d->tm_mday / 10) << 33 | - (t_value) (d->tm_mday % 10) << 29 | - (d->tm_mon / 10) << 28 | - (d->tm_mon % 10) << 24 | - (d->tm_year % 10) << 20 | - ((d->tm_year / 10) % 10) << 16 | - (memory[YEAR] & 7); - memory[YEAR] = SET_CONVOL (date, CONVOL_NUMBER); - /* приказ ВРЕ: ТР6 = 016, ТР5 = 9-14 р.-часы, 1-8 р.-минуты */ - pult[6] = 016; - pult[4] = 0; - pult[5] = (d->tm_hour / 10) << 12 | - (d->tm_hour % 10) << 8 | - (d->tm_min / 10) << 4 | - (d->tm_min % 10); - GRP |= GRP_PANEL_REQ; - } + /* Выдаем приказы оператора СМЕ и ВРЕ, + * а дату корректируем непосредственно в памяти. + */ + /* Номер смены в 22-24 рр. МГРП: если еще не установлен, установить */ + if (((memory[MGRP_COPY] >> 21) & 3) == 0) { + /* приказ СМЕ: ТР6 = 010, ТР4 = 1, 22-24 р ТР5 - #смены */ + pult[6] = 010; + pult[4] = 1; + pult[5] = 1 << 21; + GRP |= GRP_PANEL_REQ; + } else { + /* Яч. ГОД обновляем самостоятельно */ + time_t t; + t_value date; + time(&t); + struct tm * d; + d = localtime(&t); + ++d->tm_mon; + date = (t_value) (d->tm_mday / 10) << 33 | + (t_value) (d->tm_mday % 10) << 29 | + (d->tm_mon / 10) << 28 | + (d->tm_mon % 10) << 24 | + (d->tm_year % 10) << 20 | + ((d->tm_year / 10) % 10) << 16 | + (memory[YEAR] & 7); + memory[YEAR] = SET_CONVOL (date, CONVOL_NUMBER); + /* приказ ВРЕ: ТР6 = 016, ТР5 = 9-14 р.-часы, 1-8 р.-минуты */ + pult[6] = 016; + pult[4] = 0; + pult[5] = (d->tm_hour / 10) << 12 | + (d->tm_hour % 10) << 8 | + (d->tm_min / 10) << 4 | + (d->tm_min % 10); + GRP |= GRP_PANEL_REQ; + } } /* @@ -793,680 +802,685 @@ void check_initial_setup () */ void cpu_one_inst () { - int reg, opcode, addr, nextpc, next_mod; + int reg, opcode, addr, nextpc, next_mod; - corr_stack = 0; - t_value word = mmu_fetch (PC); - if (RUU & RUU_RIGHT_INSTR) - RK = word; /* get right instruction */ - else - RK = word >> 24; /* get left instruction */ + corr_stack = 0; + t_value word = mmu_fetch (PC); + if (RUU & RUU_RIGHT_INSTR) + RK = word; /* get right instruction */ + else + RK = word >> 24; /* get left instruction */ - RK &= BITS(24); + RK &= BITS(24); - reg = RK >> 20; - if (RK & BBIT(20)) { - addr = RK & BITS(15); - opcode = (RK >> 12) & 0370; - } else { - addr = RK & BITS(12); - if (RK & BBIT(19)) - addr |= 070000; - opcode = (RK >> 12) & 077; - } + reg = RK >> 20; + if (RK & BBIT(20)) { + addr = RK & BITS(15); + opcode = (RK >> 12) & 0370; + } else { + addr = RK & BITS(12); + if (RK & BBIT(19)) + addr |= 070000; + opcode = (RK >> 12) & 077; + } - if (sim_deb && cpu_dev.dctrl) { - fprintf (sim_deb, "*** %05o%s: ", PC, - (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); - besm6_fprint_cmd (sim_deb, RK); - fprintf (sim_deb, "\tСМ="); - fprint_sym (sim_deb, 0, &ACC, 0, 0); - fprintf (sim_deb, "\tРАУ=%02o", RAU); - if (reg) - fprintf (sim_deb, "\tМ[%o]=%05o", reg, M[reg]); - fprintf (sim_deb, "\n"); - } - nextpc = ADDR(PC + 1); - if (RUU & RUU_RIGHT_INSTR) { - PC += 1; /* increment PC */ - RUU &= ~RUU_RIGHT_INSTR; - } else { - mmu_prefetch(nextpc | (IS_SUPERVISOR(RUU) ? BBIT(16) : 0), 0); - RUU |= RUU_RIGHT_INSTR; - } + if (sim_deb && cpu_dev.dctrl) { + fprintf (sim_deb, "*** %05o%s: ", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); + besm6_fprint_cmd (sim_deb, RK); + fprintf (sim_deb, "\tСМ="); + fprint_sym (sim_deb, 0, &ACC, 0, 0); + fprintf (sim_deb, "\tРАУ=%02o", RAU); + if (reg) + fprintf (sim_deb, "\tМ[%o]=%05o", reg, M[reg]); + fprintf (sim_deb, "\n"); + } + nextpc = ADDR(PC + 1); + if (RUU & RUU_RIGHT_INSTR) { + PC += 1; /* increment PC */ + RUU &= ~RUU_RIGHT_INSTR; + } else { + mmu_prefetch(nextpc | (IS_SUPERVISOR(RUU) ? BBIT(16) : 0), 0); + RUU |= RUU_RIGHT_INSTR; + } - if (RUU & RUU_MOD_RK) { - addr = ADDR (addr + M[MOD]); - } - next_mod = 0; - delay = 0; + if (RUU & RUU_MOD_RK) { + addr = ADDR (addr + M[MOD]); + } + next_mod = 0; + delay = 0; - switch (opcode) { - case 000: /* зп, atx */ - Aex = ADDR (addr + M[reg]); - mmu_store (Aex, ACC); - if (! addr && reg == 017) - M[017] = ADDR (M[017] + 1); - delay = MEAN_TIME (3, 3); - break; - case 001: /* зпм, stx */ - Aex = ADDR (addr + M[reg]); - mmu_store (Aex, ACC); - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - ACC = mmu_load (M[017]); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (6, 6); - break; - case 002: /* рег, mod */ - Aex = ADDR (addr + M[reg]); - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - cmd_002 (); - /* Режим АУ - логический, если операция была "чтение" */ - if (Aex & 0200) - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 003: /* счм, xts */ - mmu_store (M[017], ACC); - M[017] = ADDR (M[017] + 1); - corr_stack = -1; - Aex = ADDR (addr + M[reg]); - ACC = mmu_load (Aex); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (6, 6); - break; - case 004: /* сл, a+x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 0, 0); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 005: /* вч, a-x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 0, 1); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 006: /* вчоб, x-a */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 1, 0); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 007: /* вчаб, amx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add (mmu_load (Aex), 1, 1); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 11); - break; - case 010: /* сч, xta */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = mmu_load (Aex); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 011: /* и, aax */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC &= mmu_load (Aex); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4); - break; - case 012: /* нтж, aex */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - RMR = ACC; - ACC ^= mmu_load (Aex); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 013: /* слц, arx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC += mmu_load (Aex); - if (ACC & BIT49) - ACC = (ACC + 1) & BITS48; - RMR = 0; - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 6); - break; - case 014: /* знак, avx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_change_sign (mmu_load (Aex) >> 40 & 1); - RAU = SET_ADDITIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 015: /* или, aox */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC |= mmu_load (Aex); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4); - break; - case 016: /* дел, a/x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_divide (mmu_load (Aex)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 50); - break; - case 017: /* умн, a*x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_multiply (mmu_load (Aex)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 18); - break; - case 020: /* сбр, apx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = besm6_pack (ACC, mmu_load (Aex)); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 53); - break; - case 021: /* рзб, aux */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = besm6_unpack (ACC, mmu_load (Aex)); - RMR = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 53); - break; - case 022: /* чед, acx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - ACC = besm6_count_ones (ACC) + mmu_load (Aex); - if (ACC & BIT49) - ACC = (ACC + 1) & BITS48; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 56); - break; - case 023: /* нед, anx */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - if (ACC) { - int n = besm6_highest_bit (ACC); + switch (opcode) { + case 000: /* зп, atx */ + Aex = ADDR (addr + M[reg]); + mmu_store (Aex, ACC); + if (! addr && reg == 017) + M[017] = ADDR (M[017] + 1); + delay = MEAN_TIME (3, 3); + break; + case 001: /* зпм, stx */ + Aex = ADDR (addr + M[reg]); + mmu_store (Aex, ACC); + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + ACC = mmu_load (M[017]); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (6, 6); + break; + case 002: /* рег, mod */ + Aex = ADDR (addr + M[reg]); + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + cmd_002 (); + /* Режим АУ - логический, если операция была "чтение" */ + if (Aex & 0200) + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 003: /* счм, xts */ + mmu_store (M[017], ACC); + M[017] = ADDR (M[017] + 1); + corr_stack = -1; + Aex = ADDR (addr + M[reg]); + ACC = mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (6, 6); + break; + case 004: /* сл, a+x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 0, 0); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 005: /* вч, a-x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 0, 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 006: /* вчоб, x-a */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 1, 0); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 007: /* вчаб, amx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add (mmu_load (Aex), 1, 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 11); + break; + case 010: /* сч, xta */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 011: /* и, aax */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC &= mmu_load (Aex); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4); + break; + case 012: /* нтж, aex */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + RMR = ACC; + ACC ^= mmu_load (Aex); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 013: /* слц, arx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC += mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + RMR = 0; + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 6); + break; + case 014: /* знак, avx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_change_sign (mmu_load (Aex) >> 40 & 1); + RAU = SET_ADDITIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 015: /* или, aox */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC |= mmu_load (Aex); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4); + break; + case 016: /* дел, a/x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_divide (mmu_load (Aex)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 50); + break; + case 017: /* умн, a*x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_multiply (mmu_load (Aex)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 18); + break; + case 020: /* сбр, apx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_pack (ACC, mmu_load (Aex)); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 53); + break; + case 021: /* рзб, aux */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_unpack (ACC, mmu_load (Aex)); + RMR = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 53); + break; + case 022: /* чед, acx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + ACC = besm6_count_ones (ACC) + mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 56); + break; + case 023: /* нед, anx */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + if (ACC) { + int n = besm6_highest_bit (ACC); - /* "Остаток" сумматора, исключая бит, - * номер которого определен, помещается в РМР, - * начиная со старшего бита РМР. */ - besm6_shift (48 - n); + /* "Остаток" сумматора, исключая бит, + * номер которого определен, помещается в РМР, + * начиная со старшего бита РМР. */ + besm6_shift (48 - n); - /* Циклическое сложение номера со словом по Аисп. */ - ACC = n + mmu_load (Aex); - if (ACC & BIT49) - ACC = (ACC + 1) & BITS48; - } else { - RMR = 0; - ACC = mmu_load (Aex); - } - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 32); - break; - case 024: /* слп, e+x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add_exponent ((mmu_load (Aex) >> 41) - 64); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 025: /* вчп, e-x */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - besm6_add_exponent (64 - (mmu_load (Aex) >> 41)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 026: { /* сд, asx */ - int n; - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - n = (mmu_load (Aex) >> 41) - 64; - besm6_shift (n); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4 + abs (n)); - break; - } - case 027: /* рж, xtr */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - RAU = (mmu_load (Aex) >> 41) & 077; - delay = MEAN_TIME (3, 3); - break; - case 030: /* счрж, rte */ - Aex = ADDR (addr + M[reg]); - ACC = (t_value) (RAU & Aex & 0177) << 41; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 3); - break; - case 031: /* счмр, yta */ - Aex = ADDR (addr + M[reg]); - if (IS_LOGICAL (RAU)) { - ACC = RMR; - } else { - t_value x = RMR; - ACC = (ACC & ~BITS41) | (RMR & BITS40); - besm6_add_exponent ((Aex & 0177) - 64); - RMR = x; - } - delay = MEAN_TIME (3, 5); - break; - case 032: /* э32, ext */ - /* Fall through... */ - case 033: /* увв, ext */ - Aex = ADDR (addr + M[reg]); - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - cmd_033 (); - /* Режим АУ - логический, если операция была "чтение" */ - if (Aex & 04000) - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 8); - break; - case 034: /* слпа, e+n */ - Aex = ADDR (addr + M[reg]); - besm6_add_exponent ((Aex & 0177) - 64); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 035: /* вчпа, e-n */ - Aex = ADDR (addr + M[reg]); - besm6_add_exponent (64 - (Aex & 0177)); - RAU = SET_MULTIPLICATIVE (RAU); - delay = MEAN_TIME (3, 5); - break; - case 036: { /* сда, asn */ - int n; - Aex = ADDR (addr + M[reg]); - n = (Aex & 0177) - 64; - besm6_shift (n); - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (3, 4 + abs (n)); - break; - } - case 037: /* ржа, ntr */ - Aex = ADDR (addr + M[reg]); - RAU = Aex & 077; - delay = MEAN_TIME (3, 3); - break; - case 040: /* уи, ati */ - Aex = ADDR (addr + M[reg]); - if (IS_SUPERVISOR (RUU)) { - int reg = Aex & 037; - M[reg] = ADDR (ACC); - /* breakpoint/watchpoint regs will match physical - * or virtual addresses depending on the current - * mapping mode. - */ - if ((M[PSW] & PSW_MMAP_DISABLE) && - (reg == IBP || reg == DWP)) - M[reg] |= BBIT(16); + /* Циклическое сложение номера со словом по Аисп. */ + ACC = n + mmu_load (Aex); + if (ACC & BIT49) + ACC = (ACC + 1) & BITS48; + } else { + RMR = 0; + ACC = mmu_load (Aex); + } + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 32); + break; + case 024: /* слп, e+x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add_exponent ((mmu_load (Aex) >> 41) - 64); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 025: /* вчп, e-x */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + besm6_add_exponent (64 - (mmu_load (Aex) >> 41)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 026: { /* сд, asx */ + int n; + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + n = (mmu_load (Aex) >> 41) - 64; + besm6_shift (n); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4 + abs (n)); + break; + } + case 027: /* рж, xtr */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + RAU = (mmu_load (Aex) >> 41) & 077; + delay = MEAN_TIME (3, 3); + break; + case 030: /* счрж, rte */ + Aex = ADDR (addr + M[reg]); + ACC = (t_value) (RAU & Aex & 0177) << 41; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 3); + break; + case 031: /* счмр, yta */ + Aex = ADDR (addr + M[reg]); + if (IS_LOGICAL (RAU)) { + ACC = RMR; + } else { + t_value x = RMR; + ACC = (ACC & ~BITS41) | (RMR & BITS40); + besm6_add_exponent ((Aex & 0177) - 64); + RMR = x; + } + delay = MEAN_TIME (3, 5); + break; + case 032: /* э32, ext */ + /* Fall through... */ + case 033: /* увв, ext */ + Aex = ADDR (addr + M[reg]); + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + cmd_033 (); + /* Режим АУ - логический, если операция была "чтение" */ + if (Aex & 04000) + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 8); + break; + case 034: /* слпа, e+n */ + Aex = ADDR (addr + M[reg]); + besm6_add_exponent ((Aex & 0177) - 64); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 035: /* вчпа, e-n */ + Aex = ADDR (addr + M[reg]); + besm6_add_exponent (64 - (Aex & 0177)); + RAU = SET_MULTIPLICATIVE (RAU); + delay = MEAN_TIME (3, 5); + break; + case 036: { /* сда, asn */ + int n; + Aex = ADDR (addr + M[reg]); + n = (Aex & 0177) - 64; + besm6_shift (n); + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (3, 4 + abs (n)); + break; + } + case 037: /* ржа, ntr */ + Aex = ADDR (addr + M[reg]); + RAU = Aex & 077; + delay = MEAN_TIME (3, 3); + break; + case 040: /* уи, ati */ + Aex = ADDR (addr + M[reg]); + if (IS_SUPERVISOR (RUU)) { + int reg = Aex & 037; + M[reg] = ADDR (ACC); + /* breakpoint/watchpoint regs will match physical + * or virtual addresses depending on the current + * mapping mode. + */ + if ((M[PSW] & PSW_MMAP_DISABLE) && + (reg == IBP || reg == DWP)) + M[reg] |= BBIT(16); - } else - M[Aex & 017] = ADDR (ACC); - M[0] = 0; - delay = MEAN_TIME (14, 3); - break; - case 041: { /* уим, sti */ - unsigned rg, ad; + } else + M[Aex & 017] = ADDR (ACC); + M[0] = 0; + delay = MEAN_TIME (14, 3); + break; + case 041: { /* уим, sti */ + unsigned rg, ad; - Aex = ADDR (addr + M[reg]); - rg = Aex & (IS_SUPERVISOR (RUU) ? 037 : 017); - ad = ADDR (ACC); - if (rg != 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - ACC = mmu_load (rg != 017 ? M[017] : ad); - M[rg] = ad; - if ((M[PSW] & PSW_MMAP_DISABLE) && (rg == IBP || rg == DWP)) - M[rg] |= BBIT(16); - M[0] = 0; - RAU = SET_LOGICAL (RAU); - delay = MEAN_TIME (14, 3); - break; - } - case 042: /* счи, ita */ - delay = MEAN_TIME (6, 3); -load_modifier: Aex = ADDR (addr + M[reg]); - ACC = ADDR(M[Aex & (IS_SUPERVISOR (RUU) ? 037 : 017)]); - RAU = SET_LOGICAL (RAU); - break; - case 043: /* счим, its */ - mmu_store (M[017], ACC); - M[017] = ADDR (M[017] + 1); - delay = MEAN_TIME (9, 6); - goto load_modifier; - case 044: /* уии, mtj */ - Aex = addr; - if (IS_SUPERVISOR (RUU)) { -transfer_modifier: M[Aex & 037] = M[reg]; - if ((M[PSW] & PSW_MMAP_DISABLE) && - ((Aex & 037) == IBP || (Aex & 037) == DWP)) - M[Aex & 037] |= BBIT(16); + Aex = ADDR (addr + M[reg]); + rg = Aex & (IS_SUPERVISOR (RUU) ? 037 : 017); + ad = ADDR (ACC); + if (rg != 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + ACC = mmu_load (rg != 017 ? M[017] : ad); + M[rg] = ad; + if ((M[PSW] & PSW_MMAP_DISABLE) && (rg == IBP || rg == DWP)) + M[rg] |= BBIT(16); + M[0] = 0; + RAU = SET_LOGICAL (RAU); + delay = MEAN_TIME (14, 3); + break; + } + case 042: /* счи, ita */ + delay = MEAN_TIME (6, 3); + load_modifier: Aex = ADDR (addr + M[reg]); + ACC = ADDR(M[Aex & (IS_SUPERVISOR (RUU) ? 037 : 017)]); + RAU = SET_LOGICAL (RAU); + break; + case 043: /* счим, its */ + mmu_store (M[017], ACC); + M[017] = ADDR (M[017] + 1); + delay = MEAN_TIME (9, 6); + goto load_modifier; + case 044: /* уии, mtj */ + Aex = addr; + if (IS_SUPERVISOR (RUU)) { + transfer_modifier: M[Aex & 037] = M[reg]; + if ((M[PSW] & PSW_MMAP_DISABLE) && + ((Aex & 037) == IBP || (Aex & 037) == DWP)) + M[Aex & 037] |= BBIT(16); - } else - M[Aex & 017] = M[reg]; - M[0] = 0; - delay = 6; - break; - case 045: /* сли, j+m */ - Aex = addr; - if ((Aex & 020) && IS_SUPERVISOR (RUU)) - goto transfer_modifier; - M[Aex & 017] = ADDR (M[Aex & 017] + M[reg]); - M[0] = 0; - delay = 6; - break; - case 046: /* э46, x46 */ - Aex = addr; - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - M[Aex & 017] = ADDR (Aex); - M[0] = 0; - delay = 6; - break; - case 047: /* э47, x47 */ - Aex = addr; - if (! IS_SUPERVISOR (RUU)) - longjmp (cpu_halt, STOP_BADCMD); - M[Aex & 017] = ADDR (M[Aex & 017] + Aex); - M[0] = 0; - delay = 6; - break; - case 050 ... 077: /* э50...э77 */ - case 0200: /* э20 */ - case 0210: /* э21 */ - stop_as_extracode: - Aex = ADDR (addr + M[reg]); - if (! sim_deb && sim_log && cpu_dev.dctrl && opcode != 075) { - /* Если включен console log и cpu debug, - * но нет console debug, то печатаем только экстракоды. - * Пропускаем э75, их обычно слишком много. */ - t_value word = mmu_load (Aex); - fprintf (sim_log, "*** %05o%s: ", PC, - (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); - besm6_fprint_cmd (sim_log, RK); - fprintf (sim_log, "\tАисп=%05o (=", Aex); - fprint_sym (sim_log, 0, &word, 0, 0); - fprintf (sim_log, ") СМ="); - fprint_sym (sim_log, 0, &ACC, 0, 0); - if (reg) - fprintf (sim_log, " М[%o]=%05o", reg, M[reg]); - fprintf (sim_log, "\n"); - } - /*besm6_okno ("экстракод");*/ - /* Адрес возврата из экстракода. */ - M[ERET] = nextpc; - /* Сохранённые режимы УУ. */ - M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); - /* Текущие режимы УУ. */ - M[PSW] = PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE | /*?*/ PSW_INTR_HALT; - M[14] = Aex; - RUU = SET_SUPERVISOR (RUU, SPSW_EXTRACODE); + } else + M[Aex & 017] = M[reg]; + M[0] = 0; + delay = 6; + break; + case 045: /* сли, j+m */ + Aex = addr; + if ((Aex & 020) && IS_SUPERVISOR (RUU)) + goto transfer_modifier; + M[Aex & 017] = ADDR (M[Aex & 017] + M[reg]); + M[0] = 0; + delay = 6; + break; + case 046: /* э46, x46 */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + M[Aex & 017] = ADDR (Aex); + M[0] = 0; + delay = 6; + break; + case 047: /* э47, x47 */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) + longjmp (cpu_halt, STOP_BADCMD); + M[Aex & 017] = ADDR (M[Aex & 017] + Aex); + M[0] = 0; + delay = 6; + break; + case 050: case 051: case 052: case 053: + case 054: case 055: case 056: case 057: + case 060: case 061: case 062: case 063: + case 064: case 065: case 066: case 067: + case 070: case 071: case 072: case 073: + case 074: case 075: case 076: case 077: /* э50...э77 */ + case 0200: /* э20 */ + case 0210: /* э21 */ + stop_as_extracode: + Aex = ADDR (addr + M[reg]); + if (! sim_deb && sim_log && cpu_dev.dctrl && opcode != 075) { + /* Если включен console log и cpu debug, + * но нет console debug, то печатаем только экстракоды. + * Пропускаем э75, их обычно слишком много. */ + t_value word = mmu_load (Aex); + fprintf (sim_log, "*** %05o%s: ", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л"); + besm6_fprint_cmd (sim_log, RK); + fprintf (sim_log, "\tАисп=%05o (=", Aex); + fprint_sym (sim_log, 0, &word, 0, 0); + fprintf (sim_log, ") СМ="); + fprint_sym (sim_log, 0, &ACC, 0, 0); + if (reg) + fprintf (sim_log, " М[%o]=%05o", reg, M[reg]); + fprintf (sim_log, "\n"); + } + /*besm6_okno ("экстракод");*/ + /* Адрес возврата из экстракода. */ + M[ERET] = nextpc; + /* Сохранённые режимы УУ. */ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + /* Текущие режимы УУ. */ + M[PSW] = PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE | /*?*/ PSW_INTR_HALT; + M[14] = Aex; + RUU = SET_SUPERVISOR (RUU, SPSW_EXTRACODE); - if (opcode <= 077) - PC = 0500 + opcode; /* э50-э77 */ - else - PC = 0540 + (opcode >> 3); /* э20, э21 */ - RUU &= ~RUU_RIGHT_INSTR; - delay = 7; - break; - case 0220: /* мода, utc */ - Aex = ADDR (addr + M[reg]); - next_mod = Aex; - delay = 4; - break; - case 0230: /* мод, wtc */ - if (! addr && reg == 017) { - M[017] = ADDR (M[017] - 1); - corr_stack = 1; - } - Aex = ADDR (addr + M[reg]); - next_mod = ADDR (mmu_load (Aex)); - delay = MEAN_TIME (13, 3); - break; - case 0240: /* уиа, vtm */ - Aex = addr; - M[reg] = addr; - M[0] = 0; - if (IS_SUPERVISOR (RUU) && reg == 0) { - M[PSW] &= ~(PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - M[PSW] |= addr & (PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - } - delay = 4; - break; - case 0250: /* слиа, utm */ - Aex = ADDR (addr + M[reg]); - M[reg] = Aex; - M[0] = 0; - if (IS_SUPERVISOR (RUU) && reg == 0) { - M[PSW] &= ~(PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - M[PSW] |= addr & (PSW_INTR_DISABLE | - PSW_MMAP_DISABLE | PSW_PROT_DISABLE); - } - delay = 4; - break; - case 0260: /* по, uza */ - Aex = ADDR (addr + M[reg]); - RMR = ACC; - delay = MEAN_TIME (12, 3); - if (IS_ADDITIVE (RAU)) { - if (ACC & BIT41) - break; - } else if (IS_MULTIPLICATIVE (RAU)) { - if (! (ACC & BIT48)) - break; - } else if (IS_LOGICAL (RAU)) { - if (ACC) - break; - } else - break; - PC = Aex; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - break; - case 0270: /* пе, u1a */ - Aex = ADDR (addr + M[reg]); - RMR = ACC; - delay = MEAN_TIME (12, 3); - if (IS_ADDITIVE (RAU)) { - if (! (ACC & BIT41)) - break; - } else if (IS_MULTIPLICATIVE (RAU)) { - if (ACC & BIT48) - break; - } else if (IS_LOGICAL (RAU)) { - if (! ACC) - break; - } else - /* fall thru, i.e. branch */; - PC = Aex; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - break; - case 0300: /* пб, uj */ - Aex = ADDR (addr + M[reg]); - PC = Aex; - RUU &= ~RUU_RIGHT_INSTR; - delay = 7; - break; - case 0310: /* пв, vjm */ - Aex = addr; - M[reg] = nextpc; - M[0] = 0; - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay = 7; - break; - case 0320: /* выпр, iret */ - Aex = addr; - if (! IS_SUPERVISOR (RUU)) { - longjmp (cpu_halt, STOP_BADCMD); - } - M[PSW] = (M[PSW] & PSW_WRITE_WATCH) | - (M[SPSW] & (SPSW_INTR_DISABLE | - SPSW_MMAP_DISABLE | SPSW_PROT_DISABLE)); - PC = M[(reg & 3) | 030]; - RUU &= ~RUU_RIGHT_INSTR; - if (M[SPSW] & SPSW_RIGHT_INSTR) - RUU |= RUU_RIGHT_INSTR; - else - RUU &= ~RUU_RIGHT_INSTR; - RUU = SET_SUPERVISOR (RUU, - M[SPSW] & (SPSW_EXTRACODE | SPSW_INTERRUPT)); - if (M[SPSW] & SPSW_MOD_RK) - next_mod = M[MOD]; - /*besm6_okno ("Выход из прерывания");*/ - delay = 7; - break; - case 0330: /* стоп, stop */ - Aex = ADDR (addr + M[reg]); - delay = 7; - if (! IS_SUPERVISOR(RUU)) { - if (M[PSW] & PSW_CHECK_HALT) - break; - else { - opcode = 063; - goto stop_as_extracode; - } - } - mmu_print_brz (); - longjmp (cpu_halt, STOP_STOP); - break; - case 0340: /* пио, vzm */ -branch_zero: Aex = addr; - delay = 4; - if (! M[reg]) { - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - } - break; - case 0350: /* пино, v1m */ - Aex = addr; - delay = 4; - if (M[reg]) { - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - } - break; - case 0360: /* э36, *36 */ - goto branch_zero; - case 0370: /* цикл, vlm */ - Aex = addr; - delay = 4; - if (! M[reg]) - break; - M[reg] = ADDR (M[reg] + 1); - PC = addr; - RUU &= ~RUU_RIGHT_INSTR; - delay += 3; - break; - default: - /* Unknown instruction - cannot happen. */ - longjmp (cpu_halt, STOP_STOP); - break; - } - if (next_mod) { - /* Модификация адреса следующей команды. */ - M[MOD] = next_mod; - RUU |= RUU_MOD_RK; - } else - RUU &= ~RUU_MOD_RK; + if (opcode <= 077) + PC = 0500 + opcode; /* э50-э77 */ + else + PC = 0540 + (opcode >> 3); /* э20, э21 */ + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0220: /* мода, utc */ + Aex = ADDR (addr + M[reg]); + next_mod = Aex; + delay = 4; + break; + case 0230: /* мод, wtc */ + if (! addr && reg == 017) { + M[017] = ADDR (M[017] - 1); + corr_stack = 1; + } + Aex = ADDR (addr + M[reg]); + next_mod = ADDR (mmu_load (Aex)); + delay = MEAN_TIME (13, 3); + break; + case 0240: /* уиа, vtm */ + Aex = addr; + M[reg] = addr; + M[0] = 0; + if (IS_SUPERVISOR (RUU) && reg == 0) { + M[PSW] &= ~(PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + M[PSW] |= addr & (PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + } + delay = 4; + break; + case 0250: /* слиа, utm */ + Aex = ADDR (addr + M[reg]); + M[reg] = Aex; + M[0] = 0; + if (IS_SUPERVISOR (RUU) && reg == 0) { + M[PSW] &= ~(PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + M[PSW] |= addr & (PSW_INTR_DISABLE | + PSW_MMAP_DISABLE | PSW_PROT_DISABLE); + } + delay = 4; + break; + case 0260: /* по, uza */ + Aex = ADDR (addr + M[reg]); + RMR = ACC; + delay = MEAN_TIME (12, 3); + if (IS_ADDITIVE (RAU)) { + if (ACC & BIT41) + break; + } else if (IS_MULTIPLICATIVE (RAU)) { + if (! (ACC & BIT48)) + break; + } else if (IS_LOGICAL (RAU)) { + if (ACC) + break; + } else + break; + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + case 0270: /* пе, u1a */ + Aex = ADDR (addr + M[reg]); + RMR = ACC; + delay = MEAN_TIME (12, 3); + if (IS_ADDITIVE (RAU)) { + if (! (ACC & BIT41)) + break; + } else if (IS_MULTIPLICATIVE (RAU)) { + if (ACC & BIT48) + break; + } else if (IS_LOGICAL (RAU)) { + if (! ACC) + break; + } else + /* fall thru, i.e. branch */; + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + case 0300: /* пб, uj */ + Aex = ADDR (addr + M[reg]); + PC = Aex; + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0310: /* пв, vjm */ + Aex = addr; + M[reg] = nextpc; + M[0] = 0; + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay = 7; + break; + case 0320: /* выпр, iret */ + Aex = addr; + if (! IS_SUPERVISOR (RUU)) { + longjmp (cpu_halt, STOP_BADCMD); + } + M[PSW] = (M[PSW] & PSW_WRITE_WATCH) | + (M[SPSW] & (SPSW_INTR_DISABLE | + SPSW_MMAP_DISABLE | SPSW_PROT_DISABLE)); + PC = M[(reg & 3) | 030]; + RUU &= ~RUU_RIGHT_INSTR; + if (M[SPSW] & SPSW_RIGHT_INSTR) + RUU |= RUU_RIGHT_INSTR; + else + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, + M[SPSW] & (SPSW_EXTRACODE | SPSW_INTERRUPT)); + if (M[SPSW] & SPSW_MOD_RK) + next_mod = M[MOD]; + /*besm6_okno ("Выход из прерывания");*/ + delay = 7; + break; + case 0330: /* стоп, stop */ + Aex = ADDR (addr + M[reg]); + delay = 7; + if (! IS_SUPERVISOR(RUU)) { + if (M[PSW] & PSW_CHECK_HALT) + break; + else { + opcode = 063; + goto stop_as_extracode; + } + } + mmu_print_brz (); + longjmp (cpu_halt, STOP_STOP); + break; + case 0340: /* пио, vzm */ + branch_zero: Aex = addr; + delay = 4; + if (! M[reg]) { + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + } + break; + case 0350: /* пино, v1m */ + Aex = addr; + delay = 4; + if (M[reg]) { + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + } + break; + case 0360: /* э36, *36 */ + goto branch_zero; + case 0370: /* цикл, vlm */ + Aex = addr; + delay = 4; + if (! M[reg]) + break; + M[reg] = ADDR (M[reg] + 1); + PC = addr; + RUU &= ~RUU_RIGHT_INSTR; + delay += 3; + break; + default: + /* Unknown instruction - cannot happen. */ + longjmp (cpu_halt, STOP_STOP); + break; + } + if (next_mod) { + /* Модификация адреса следующей команды. */ + M[MOD] = next_mod; + RUU |= RUU_MOD_RK; + } else + RUU &= ~RUU_MOD_RK; - /* Не находимся ли мы в цикле "ЖДУ" диспака? */ - if (RUU == 047 && PC == 04440 && RK == 067704440) { - /* Притормаживаем выполнение каждой команды холостого цикла, - * чтобы быстрее обрабатывались прерывания: ускоряются - * терминалы и АЦПУ. */ - delay = sim_interval; + /* Не находимся ли мы в цикле "ЖДУ" диспака? */ + if (RUU == 047 && PC == 04440 && RK == 067704440) { + /* Притормаживаем выполнение каждой команды холостого цикла, + * чтобы быстрее обрабатывались прерывания: ускоряются + * терминалы и АЦПУ. */ + delay = sim_interval; - /* Если периферия простаивает, освобождаем процессор - * до следующего тика таймера. */ - if (vt_is_idle() && - printer_is_idle() && fs_is_idle()) { - check_initial_setup (); - pause (); - } - } + /* Если периферия простаивает, освобождаем процессор + * до следующего тика таймера. */ + if (vt_is_idle() && + printer_is_idle() && fs_is_idle()) { + check_initial_setup (); + pause (); + } + } } /* @@ -1475,20 +1489,20 @@ branch_zero: Aex = addr; */ void op_int_1 (const char *msg) { - /*besm6_okno (msg);*/ - M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); - if (RUU & RUU_RIGHT_INSTR) - M[SPSW] |= SPSW_RIGHT_INSTR; - M[IRET] = PC; - M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; - if (RUU & RUU_MOD_RK) { - M[SPSW] |= SPSW_MOD_RK; - RUU &= ~RUU_MOD_RK; - } - PC = 0500; - RUU &= ~RUU_RIGHT_INSTR; - RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); + /*besm6_okno (msg);*/ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + if (RUU & RUU_RIGHT_INSTR) + M[SPSW] |= SPSW_RIGHT_INSTR; + M[IRET] = PC; + M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; + if (RUU & RUU_MOD_RK) { + M[SPSW] |= SPSW_MOD_RK; + RUU &= ~RUU_MOD_RK; + } + PC = 0500; + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); } /* @@ -1497,18 +1511,18 @@ void op_int_1 (const char *msg) */ void op_int_2 () { - /*besm6_okno ("Внешнее прерывание");*/ - M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | - PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); - M[IRET] = PC; - M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; - if (RUU & RUU_MOD_RK) { - M[SPSW] |= SPSW_MOD_RK; - RUU &= ~RUU_MOD_RK; - } - PC = 0501; - RUU &= ~RUU_RIGHT_INSTR; - RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); + /*besm6_okno ("Внешнее прерывание");*/ + M[SPSW] = (M[PSW] & (PSW_INTR_DISABLE | PSW_MMAP_DISABLE | + PSW_PROT_DISABLE)) | IS_SUPERVISOR (RUU); + M[IRET] = PC; + M[PSW] |= PSW_INTR_DISABLE | PSW_MMAP_DISABLE | PSW_PROT_DISABLE; + if (RUU & RUU_MOD_RK) { + M[SPSW] |= SPSW_MOD_RK; + RUU &= ~RUU_MOD_RK; + } + PC = 0501; + RUU &= ~RUU_RIGHT_INSTR; + RUU = SET_SUPERVISOR (RUU, SPSW_INTERRUPT); } /* @@ -1516,220 +1530,220 @@ void op_int_2 () */ t_stat sim_instr (void) { - t_stat r; - int iintr = 0; + t_stat r; + int iintr = 0; - /* Restore register state */ - PC = PC & BITS(15); /* mask PC */ - sim_cancel_step (); /* defang SCP step */ - mmu_setup (); /* copy RP to TLB */ + /* Restore register state */ + PC = PC & BITS(15); /* mask PC */ + sim_cancel_step (); /* defang SCP step */ + mmu_setup (); /* copy RP to TLB */ - /* An internal interrupt or user intervention */ - r = setjmp (cpu_halt); - if (r) { - M[017] += corr_stack; - if (cpu_dev.dctrl) { - const char *message = (r >= SCPE_BASE) ? - scp_errors [r - SCPE_BASE] : - sim_stop_messages [r]; - besm6_debug ("/// %05o%s: %s", PC, - (RUU & RUU_RIGHT_INSTR) ? "п" : "л", - message); - } + /* An internal interrupt or user intervention */ + r = setjmp (cpu_halt); + if (r) { + M[017] += corr_stack; + if (cpu_dev.dctrl) { + const char *message = (r >= SCPE_BASE) ? + scp_errors [r - SCPE_BASE] : + sim_stop_messages [r]; + besm6_debug ("/// %05o%s: %s", PC, + (RUU & RUU_RIGHT_INSTR) ? "п" : "л", + message); + } - /* - * ПоП и ПоК вызывают останов при любом внутреннем прерывании - * или прерывании по контролю, соответственно. - * Если произошёл останов по ПоП или ПоК, - * то продолжение выполнения начнётся с команды, следующей - * за вызвавшей прерывание. Как если бы кнопка "ТП" (тип - * перехода) была включена. Подробнее на странице 119 ТО9. - */ - switch (r) { - default: -ret: besm6_draw_panel(); - return r; - case STOP_RWATCH: - case STOP_WWATCH: - /* Step back one insn to reexecute it */ - if (! (RUU & RUU_RIGHT_INSTR)) { - --PC; - } - RUU ^= RUU_RIGHT_INSTR; - goto ret; - case STOP_BADCMD: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // SPSW_NEXT_RK is not important for this interrupt - GRP |= GRP_ILL_INSN; - break; - case STOP_INSN_CHECK: - if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // SPSW_NEXT_RK must be 0 for this interrupt; it is already - GRP |= GRP_INSN_CHECK; - break; - case STOP_INSN_PROT: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - // SPSW_NEXT_RK must be 1 for this interrupt - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_INSN_PROT; - break; - case STOP_OPERAND_PROT: + /* + * ПоП и ПоК вызывают останов при любом внутреннем прерывании + * или прерывании по контролю, соответственно. + * Если произошёл останов по ПоП или ПоК, + * то продолжение выполнения начнётся с команды, следующей + * за вызвавшей прерывание. Как если бы кнопка "ТП" (тип + * перехода) была включена. Подробнее на странице 119 ТО9. + */ + switch (r) { + default: + ret: besm6_draw_panel(); + return r; + case STOP_RWATCH: + case STOP_WWATCH: + /* Step back one insn to reexecute it */ + if (! (RUU & RUU_RIGHT_INSTR)) { + --PC; + } + RUU ^= RUU_RIGHT_INSTR; + goto ret; + case STOP_BADCMD: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK is not important for this interrupt + GRP |= GRP_ILL_INSN; + break; + case STOP_INSN_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK must be 0 for this interrupt; it is already + GRP |= GRP_INSN_CHECK; + break; + case STOP_INSN_PROT: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + // SPSW_NEXT_RK must be 1 for this interrupt + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_INSN_PROT; + break; + case STOP_OPERAND_PROT: #if 0 /* ДИСПАК держит признак ПоП установленным. * При запуске СЕРП возникает обращение к чужому листу. */ - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; #endif - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - // The offending virtual page is in bits 5-9 - GRP |= GRP_OPRND_PROT; - GRP = GRP_SET_PAGE (GRP, iintr_data); - break; - case STOP_RAM_CHECK: - if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // The offending interleaved block # is in bits 1-3. - GRP |= GRP_CHECK | GRP_RAM_CHECK; - GRP = GRP_SET_BLOCK (GRP, iintr_data); - break; - case STOP_CACHE_CHECK: - if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - // The offending BRZ # is in bits 1-3. - GRP |= GRP_CHECK; - GRP &= ~GRP_RAM_CHECK; - GRP = GRP_SET_BLOCK (GRP, iintr_data); - break; - case STOP_INSN_ADDR_MATCH: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_BREAKPOINT; - break; - case STOP_LOAD_ADDR_MATCH: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_WATCHPT_R; - break; - case STOP_STORE_ADDR_MATCH: - if (M[PSW] & PSW_INTR_HALT) /* ПоП */ - goto ret; - if (RUU & RUU_RIGHT_INSTR) { - ++PC; - } - RUU ^= RUU_RIGHT_INSTR; - op_int_1 (sim_stop_messages[r]); - M[SPSW] |= SPSW_NEXT_RK; - GRP |= GRP_WATCHPT_W; - break; - case STOP_OVFL: - /* Прерывание по АУ вызывает останов, если БРО=0 - * и установлен ПоП или ПоК. - * Страница 118 ТО9.*/ - if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ - ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ - (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - GRP |= GRP_OVERFLOW|GRP_RAM_CHECK; - break; - case STOP_DIVZERO: - if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ - ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ - (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ - goto ret; - op_int_1 (sim_stop_messages[r]); - GRP |= GRP_DIVZERO|GRP_RAM_CHECK; - break; - } - ++iintr; - } + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + // The offending virtual page is in bits 5-9 + GRP |= GRP_OPRND_PROT; + GRP = GRP_SET_PAGE (GRP, iintr_data); + break; + case STOP_RAM_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // The offending interleaved block # is in bits 1-3. + GRP |= GRP_CHECK | GRP_RAM_CHECK; + GRP = GRP_SET_BLOCK (GRP, iintr_data); + break; + case STOP_CACHE_CHECK: + if (M[PSW] & PSW_CHECK_HALT) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + // The offending BRZ # is in bits 1-3. + GRP |= GRP_CHECK; + GRP &= ~GRP_RAM_CHECK; + GRP = GRP_SET_BLOCK (GRP, iintr_data); + break; + case STOP_INSN_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_BREAKPOINT; + break; + case STOP_LOAD_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_WATCHPT_R; + break; + case STOP_STORE_ADDR_MATCH: + if (M[PSW] & PSW_INTR_HALT) /* ПоП */ + goto ret; + if (RUU & RUU_RIGHT_INSTR) { + ++PC; + } + RUU ^= RUU_RIGHT_INSTR; + op_int_1 (sim_stop_messages[r]); + M[SPSW] |= SPSW_NEXT_RK; + GRP |= GRP_WATCHPT_W; + break; + case STOP_OVFL: + /* Прерывание по АУ вызывает останов, если БРО=0 + * и установлен ПоП или ПоК. + * Страница 118 ТО9.*/ + if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ + ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ + (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + GRP |= GRP_OVERFLOW|GRP_RAM_CHECK; + break; + case STOP_DIVZERO: + if (! (RUU & RUU_AVOST_DISABLE) && /* ! БРО */ + ((M[PSW] & PSW_INTR_HALT) || /* ПоП */ + (M[PSW] & PSW_CHECK_HALT))) /* ПоК */ + goto ret; + op_int_1 (sim_stop_messages[r]); + GRP |= GRP_DIVZERO|GRP_RAM_CHECK; + break; + } + ++iintr; + } - if (iintr > 1) { - besm6_draw_panel(); - return STOP_DOUBLE_INTR; - } - /* Main instruction fetch/decode loop */ - for (;;) { - if (sim_interval <= 0) { /* check clock queue */ - r = sim_process_event (); - if (r) { - besm6_draw_panel(); - return r; - } - } + if (iintr > 1) { + besm6_draw_panel(); + return STOP_DOUBLE_INTR; + } + /* Main instruction fetch/decode loop */ + for (;;) { + if (sim_interval <= 0) { /* check clock queue */ + r = sim_process_event (); + if (r) { + besm6_draw_panel(); + return r; + } + } - if (PC > BITS(15)) { /* выход за пределы памяти */ - besm6_draw_panel(); - return STOP_RUNOUT; /* stop simulation */ - } + if (PC > BITS(15)) { /* выход за пределы памяти */ + besm6_draw_panel(); + return STOP_RUNOUT; /* stop simulation */ + } - if (sim_brk_summ & SWMASK('E') && /* breakpoint? */ - sim_brk_test (PC, SWMASK ('E'))) { - besm6_draw_panel(); - return STOP_IBKPT; /* stop simulation */ - } + if (sim_brk_summ & SWMASK('E') && /* breakpoint? */ + sim_brk_test (PC, SWMASK ('E'))) { + besm6_draw_panel(); + return STOP_IBKPT; /* stop simulation */ + } - if (PRP & MPRP) { - /* регистр хранящий, сбрасывается программно */ - GRP |= GRP_SLAVE; - } + if (PRP & MPRP) { + /* регистр хранящий, сбрасывается программно */ + GRP |= GRP_SLAVE; + } - if (! iintr && ! (RUU & RUU_RIGHT_INSTR) && - ! (M[PSW] & PSW_INTR_DISABLE) && (GRP & MGRP)) { - /* external interrupt */ - op_int_2(); - } - cpu_one_inst (); /* one instr */ - iintr = 0; - if (redraw_panel) { - besm6_draw_panel(); - redraw_panel = 0; - } + if (! iintr && ! (RUU & RUU_RIGHT_INSTR) && + ! (M[PSW] & PSW_INTR_DISABLE) && (GRP & MGRP)) { + /* external interrupt */ + op_int_2(); + } + cpu_one_inst (); /* one instr */ + iintr = 0; + if (redraw_panel) { + besm6_draw_panel(); + redraw_panel = 0; + } - if (delay < 1) - delay = 1; - sim_interval -= delay; /* count down delay */ - if (sim_step && (--sim_step <= 0)) { /* do step count */ - besm6_draw_panel(); - return SCPE_STOP; - } - } + if (delay < 1) + delay = 1; + sim_interval -= delay; /* count down delay */ + if (sim_step && (--sim_step <= 0)) { /* do step count */ + besm6_draw_panel(); + return SCPE_STOP; + } + } } t_stat slow_clk (UNIT * this) { - /*besm6_debug ("*** таймер 80 мсек");*/ - GRP |= GRP_SLOW_CLK; - return sim_activate (this, MSEC*125/2); + /*besm6_debug ("*** таймер 80 мсек");*/ + GRP |= GRP_SLOW_CLK; + return sim_activate (this, MSEC*125/2); } /* @@ -1738,31 +1752,31 @@ t_stat slow_clk (UNIT * this) */ t_stat fast_clk (UNIT * this) { - /*besm6_debug ("*** таймер 20 мсек");*/ - GRP |= GRP_TIMER; - return sim_activate (this, 20*MSEC); + /*besm6_debug ("*** таймер 20 мсек");*/ + GRP |= GRP_TIMER; + return sim_activate (this, 20*MSEC); } UNIT clocks[] = { - { UDATA(slow_clk, 0, 0) }, /* 10 р, 16 Гц */ - { UDATA(fast_clk, 0, 0) }, /* 40 р, 50 Гц */ + { UDATA(slow_clk, 0, 0) }, /* 10 р, 16 Гц */ + { UDATA(fast_clk, 0, 0) }, /* 40 р, 50 Гц */ }; t_stat clk_reset (DEVICE * dev) { - /* Схема автозапуска включается по нереализованной кнопке "МР" */ + /* Схема автозапуска включается по нереализованной кнопке "МР" */ #ifdef SOFT_CLOCK - sim_activate (&clocks[0], MSEC*125/2); - return sim_activate (&clocks[1], 20*MSEC); + sim_activate (&clocks[0], MSEC*125/2); + return sim_activate (&clocks[1], 20*MSEC); #else - return SCPE_OK; + return SCPE_OK; #endif } DEVICE clock_dev = { - "CLK", clocks, NULL, NULL, - 2, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, NULL, - DEV_DEBUG + "CLK", clocks, NULL, NULL, + 2, 0, 0, 0, 0, 0, + NULL, NULL, &clk_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG }; diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index 3da2fa62..faec0254 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -30,14 +30,15 @@ #ifndef _BESM6_DEFS_H_ #define _BESM6_DEFS_H_ 0 -#include "sim_defs.h" /* simulator defns */ +#include "sim_defs.h" /* simulator defns */ +#include "scp.h" #include /* * Memory. */ -#define NREGS 30 /* number of registers-modifiers */ -#define MEMSIZE (512 * 1024) /* memory size, words */ +#define NREGS 30 /* number of registers-modifiers */ +#define MEMSIZE (512 * 1024) /* memory size, words */ /* * Drums and disks. @@ -46,52 +47,52 @@ * Every word (t_value) is stored as 8-byte record, low byte first. * System data is stored first, then user data. */ -#define ZONE_SIZE (8 + 1024) /* 1kword zone size, words */ -#define DRUM_SIZE (256 * ZONE_SIZE) /* drum size per controller, words */ -#define DISK_SIZE (1024 * ZONE_SIZE) /* disk size per unit, words */ +#define ZONE_SIZE (8 + 1024) /* 1kword zone size, words */ +#define DRUM_SIZE (256 * ZONE_SIZE) /* drum size per controller, words */ +#define DISK_SIZE (1024 * ZONE_SIZE) /* disk size per unit, words */ /* * Simulator stop codes */ enum { - STOP_STOP = 1, /* STOP */ - STOP_IBKPT, /* SIMH breakpoint */ - STOP_RWATCH, /* SIMH read watchpoint */ - STOP_WWATCH, /* SIMH write watchpoint */ - STOP_RUNOUT, /* run out end of memory limits */ - STOP_BADCMD, /* invalid instruction */ - STOP_INSN_CHECK, /* not an instruction */ - STOP_INSN_PROT, /* fetch from blocked page */ - STOP_OPERAND_PROT, /* load from blocked page */ - STOP_RAM_CHECK, /* RAM parity error */ - STOP_CACHE_CHECK, /* data cache parity error */ - STOP_OVFL, /* arith. overflow */ - STOP_DIVZERO, /* division by 0 or denorm */ - STOP_DOUBLE_INTR, /* double internal interrupt */ - STOP_DRUMINVDATA, /* reading unformatted drum */ - STOP_DISKINVDATA, /* reading unformatted disk */ - STOP_INSN_ADDR_MATCH, /* fetch address matched breakpt reg */ - STOP_LOAD_ADDR_MATCH, /* load address matched watchpt reg */ - STOP_STORE_ADDR_MATCH, /* store address matched watchpt reg */ - STOP_UNIMPLEMENTED, /* unimplemented 033 or 002 insn feature */ + STOP_STOP = 1, /* STOP */ + STOP_IBKPT, /* SIMH breakpoint */ + STOP_RWATCH, /* SIMH read watchpoint */ + STOP_WWATCH, /* SIMH write watchpoint */ + STOP_RUNOUT, /* run out end of memory limits */ + STOP_BADCMD, /* invalid instruction */ + STOP_INSN_CHECK, /* not an instruction */ + STOP_INSN_PROT, /* fetch from blocked page */ + STOP_OPERAND_PROT, /* load from blocked page */ + STOP_RAM_CHECK, /* RAM parity error */ + STOP_CACHE_CHECK, /* data cache parity error */ + STOP_OVFL, /* arith. overflow */ + STOP_DIVZERO, /* division by 0 or denorm */ + STOP_DOUBLE_INTR, /* double internal interrupt */ + STOP_DRUMINVDATA, /* reading unformatted drum */ + STOP_DISKINVDATA, /* reading unformatted disk */ + STOP_INSN_ADDR_MATCH, /* fetch address matched breakpt reg */ + STOP_LOAD_ADDR_MATCH, /* load address matched watchpt reg */ + STOP_STORE_ADDR_MATCH, /* store address matched watchpt reg */ + STOP_UNIMPLEMENTED, /* unimplemented 033 or 002 insn feature */ }; /* * Разряды машинного слова, справа налево, начиная с 1. */ -#define BBIT(n) (1 << (n-1)) /* один бит, от 1 до 32 */ -#define BIT40 000010000000000000LL /* 40-й бит - старший разряд мантиссы */ -#define BIT41 000020000000000000LL /* 41-й бит - знак */ -#define BIT42 000040000000000000LL /* 42-й бит - дубль-знак в мантиссе */ -#define BIT48 004000000000000000LL /* 48-й бит - знак порядка */ -#define BIT49 010000000000000000LL /* бит 49 */ -#define BITS(n) (~0U >> (32-n)) /* маска битов n..1 */ -#define BITS40 00017777777777777LL /* биты 41..1 - мантисса */ -#define BITS41 00037777777777777LL /* биты 41..1 - мантисса и знак */ -#define BITS42 00077777777777777LL /* биты 42..1 - мантисса и оба знака */ -#define BITS48 07777777777777777LL /* биты 48..1 */ -#define BITS48_42 07740000000000000LL /* биты 48..42 - порядок */ -#define ADDR(x) ((x) & BITS(15)) /* адрес слова */ +#define BBIT(n) (1 << (n-1)) /* один бит, от 1 до 32 */ +#define BIT40 000010000000000000LL /* 40-й бит - старший разряд мантиссы */ +#define BIT41 000020000000000000LL /* 41-й бит - знак */ +#define BIT42 000040000000000000LL /* 42-й бит - дубль-знак в мантиссе */ +#define BIT48 004000000000000000LL /* 48-й бит - знак порядка */ +#define BIT49 010000000000000000LL /* бит 49 */ +#define BITS(n) (~0U >> (32-n)) /* маска битов n..1 */ +#define BITS40 00017777777777777LL /* биты 41..1 - мантисса */ +#define BITS41 00037777777777777LL /* биты 41..1 - мантисса и знак */ +#define BITS42 00077777777777777LL /* биты 42..1 - мантисса и оба знака */ +#define BITS48 07777777777777777LL /* биты 48..1 */ +#define BITS48_42 07740000000000000LL /* биты 48..42 - порядок */ +#define ADDR(x) ((x) & BITS(15)) /* адрес слова */ /* * Работа со сверткой. Значение разрядов свертки слова равно значению @@ -101,12 +102,12 @@ enum { * 11 - числовая свертка * В памяти биты свертки имитируют четность полуслов. */ -#define CONVOL_INSN 1 -#define CONVOL_NUMBER 2 -#define SET_CONVOL(x, c) (((x) & BITS48) | (((c) & 3LL) << 48)) -#define IS_INSN(x) (((x) >> 48) == CONVOL_INSN) -#define IS_NUMBER(x) (((x) >> 48) == CONVOL_INSN || \ - ((x) >> 48) == CONVOL_NUMBER) +#define CONVOL_INSN 1 +#define CONVOL_NUMBER 2 +#define SET_CONVOL(x, c) (((x) & BITS48) | (((c) & 3LL) << 48)) +#define IS_INSN(x) (((x) >> 48) == CONVOL_INSN) +#define IS_NUMBER(x) (((x) >> 48) == CONVOL_INSN || \ + ((x) >> 48) == CONVOL_NUMBER) /* * Вычисление правдоподобного времени выполнения команды, @@ -115,18 +116,13 @@ enum { * выполнения, поэтому суммируем большее и половину * от меньшего значения. */ -#define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y) +#define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y) /* * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. */ -#define USEC 10 /* одна микросекунда - десять тактов */ -#define MSEC (1000*USEC) /* одна миллисекунда */ - -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern int32 sim_interval, sim_step; -extern FILE *sim_deb, *sim_log; -extern int32 sim_switches; +#define USEC 10 /* одна микросекунда - десять тактов */ +#define MSEC (1000*USEC) /* одна миллисекунда */ extern UNIT cpu_unit; extern t_value memory [MEMSIZE]; @@ -168,131 +164,131 @@ extern jmp_buf cpu_halt; /* * Искусственный регистр режимов УУ, в реальной машине отсутствует. */ -#define RUU_CONVOL_RIGHT 000001 /* ПКП - признак контроля правой половины */ -#define RUU_CONVOL_LEFT 000002 /* ПКЛ - признак контроля левой половины */ -#define RUU_EXTRACODE 000004 /* РежЭ - режим экстракода */ -#define RUU_INTERRUPT 000010 /* РежПр - режим прерывания */ -#define RUU_MOD_RK 000020 /* ПрИК - модификация регистром М[16] */ -#define RUU_AVOST_DISABLE 000040 /* БРО - блокировка режима останова */ -#define RUU_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ +#define RUU_CONVOL_RIGHT 000001 /* ПКП - признак контроля правой половины */ +#define RUU_CONVOL_LEFT 000002 /* ПКЛ - признак контроля левой половины */ +#define RUU_EXTRACODE 000004 /* РежЭ - режим экстракода */ +#define RUU_INTERRUPT 000010 /* РежПр - режим прерывания */ +#define RUU_MOD_RK 000020 /* ПрИК - модификация регистром М[16] */ +#define RUU_AVOST_DISABLE 000040 /* БРО - блокировка режима останова */ +#define RUU_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ -#define IS_SUPERVISOR(x) ((x) & (RUU_EXTRACODE | RUU_INTERRUPT)) -#define SET_SUPERVISOR(x,m) (((x) & ~(RUU_EXTRACODE | RUU_INTERRUPT)) | (m)) +#define IS_SUPERVISOR(x) ((x) & (RUU_EXTRACODE | RUU_INTERRUPT)) +#define SET_SUPERVISOR(x,m) (((x) & ~(RUU_EXTRACODE | RUU_INTERRUPT)) | (m)) /* * Специальные регистры. */ -#define MOD 020 /* модификатор адреса */ -#define PSW 021 /* режимы УУ */ -#define SPSW 027 /* упрятывание режимов УУ */ -#define ERET 032 /* адрес возврата из экстракода */ -#define IRET 033 /* адрес возврата из прерывания */ -#define IBP 034 /* адрес прерывания по выполнению */ -#define DWP 035 /* адрес прерывания по чтению/записи */ +#define MOD 020 /* модификатор адреса */ +#define PSW 021 /* режимы УУ */ +#define SPSW 027 /* упрятывание режимов УУ */ +#define ERET 032 /* адрес возврата из экстракода */ +#define IRET 033 /* адрес возврата из прерывания */ +#define IBP 034 /* адрес прерывания по выполнению */ +#define DWP 035 /* адрес прерывания по чтению/записи */ /* * Регистр 021: режимы УУ. * PSW: program status word. */ -#define PSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ -#define PSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ -#define PSW_INTR_HALT 000004 /* ПоП - признак останова при - любом внутреннем прерывании */ -#define PSW_CHECK_HALT 000010 /* ПоК - признак останова при - прерывании по контролю */ -#define PSW_WRITE_WATCH 000020 /* Зп(М29) - признак совпадения адреса - операнда прии записи в память - с содержанием регистра М29 */ -#define PSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ -#define PSW_AUT_B 004000 /* АвтБ - признак режима Автомат Б */ +#define PSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ +#define PSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ +#define PSW_INTR_HALT 000004 /* ПоП - признак останова при + любом внутреннем прерывании */ +#define PSW_CHECK_HALT 000010 /* ПоК - признак останова при + прерывании по контролю */ +#define PSW_WRITE_WATCH 000020 /* Зп(М29) - признак совпадения адреса + операнда прии записи в память + с содержанием регистра М29 */ +#define PSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ +#define PSW_AUT_B 004000 /* АвтБ - признак режима Автомат Б */ /* * Регистр 027: сохранённые режимы УУ. * SPSW: saved program status word. */ -#define SPSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ -#define SPSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ -#define SPSW_EXTRACODE 000004 /* РежЭ - режим экстракода */ -#define SPSW_INTERRUPT 000010 /* РежПр - режим прерывания */ -#define SPSW_MOD_RK 000020 /* ПрИК(РК) - на регистр РК принята - команда, которая должна быть - модифицирована регистром М[16] */ -#define SPSW_MOD_RR 000040 /* ПрИК(РР) - на регистре РР находится - команда, выполненная с модификацией */ -#define SPSW_UNKNOWN 000100 /* НОК? вписано карандашом в 9 томе */ -#define SPSW_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ -#define SPSW_NEXT_RK 001000 /* ГД./ДК2 - на регистр РК принята - команда, следующая после вызвавшей - прерывание */ -#define SPSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ +#define SPSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */ +#define SPSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */ +#define SPSW_EXTRACODE 000004 /* РежЭ - режим экстракода */ +#define SPSW_INTERRUPT 000010 /* РежПр - режим прерывания */ +#define SPSW_MOD_RK 000020 /* ПрИК(РК) - на регистр РК принята + команда, которая должна быть + модифицирована регистром М[16] */ +#define SPSW_MOD_RR 000040 /* ПрИК(РР) - на регистре РР находится + команда, выполненная с модификацией */ +#define SPSW_UNKNOWN 000100 /* НОК? вписано карандашом в 9 томе */ +#define SPSW_RIGHT_INSTR 000400 /* ПрК - признак правой команды */ +#define SPSW_NEXT_RK 001000 /* ГД./ДК2 - на регистр РК принята + команда, следующая после вызвавшей + прерывание */ +#define SPSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */ /* * Кириллица Unicode. */ -#define CYRILLIC_CAPITAL_LETTER_A 0x0410 -#define CYRILLIC_CAPITAL_LETTER_BE 0x0411 -#define CYRILLIC_CAPITAL_LETTER_VE 0x0412 -#define CYRILLIC_CAPITAL_LETTER_GHE 0x0413 -#define CYRILLIC_CAPITAL_LETTER_DE 0x0414 -#define CYRILLIC_CAPITAL_LETTER_IE 0x0415 -#define CYRILLIC_CAPITAL_LETTER_ZHE 0x0416 -#define CYRILLIC_CAPITAL_LETTER_ZE 0x0417 -#define CYRILLIC_CAPITAL_LETTER_I 0x0418 -#define CYRILLIC_CAPITAL_LETTER_SHORT_I 0x0419 -#define CYRILLIC_CAPITAL_LETTER_KA 0x041a -#define CYRILLIC_CAPITAL_LETTER_EL 0x041b -#define CYRILLIC_CAPITAL_LETTER_EM 0x041c -#define CYRILLIC_CAPITAL_LETTER_EN 0x041d -#define CYRILLIC_CAPITAL_LETTER_O 0x041e -#define CYRILLIC_CAPITAL_LETTER_PE 0x041f -#define CYRILLIC_CAPITAL_LETTER_ER 0x0420 -#define CYRILLIC_CAPITAL_LETTER_ES 0x0421 -#define CYRILLIC_CAPITAL_LETTER_TE 0x0422 -#define CYRILLIC_CAPITAL_LETTER_U 0x0423 -#define CYRILLIC_CAPITAL_LETTER_EF 0x0424 -#define CYRILLIC_CAPITAL_LETTER_HA 0x0425 -#define CYRILLIC_CAPITAL_LETTER_TSE 0x0426 -#define CYRILLIC_CAPITAL_LETTER_CHE 0x0427 -#define CYRILLIC_CAPITAL_LETTER_SHA 0x0428 -#define CYRILLIC_CAPITAL_LETTER_SHCHA 0x0429 -#define CYRILLIC_CAPITAL_LETTER_HARD_SIGN 0x042a -#define CYRILLIC_CAPITAL_LETTER_YERU 0x042b -#define CYRILLIC_CAPITAL_LETTER_SOFT_SIGN 0x042c -#define CYRILLIC_CAPITAL_LETTER_E 0x042d -#define CYRILLIC_CAPITAL_LETTER_YU 0x042e -#define CYRILLIC_CAPITAL_LETTER_YA 0x042f -#define CYRILLIC_SMALL_LETTER_A 0x0430 -#define CYRILLIC_SMALL_LETTER_BE 0x0431 -#define CYRILLIC_SMALL_LETTER_VE 0x0432 -#define CYRILLIC_SMALL_LETTER_GHE 0x0433 -#define CYRILLIC_SMALL_LETTER_DE 0x0434 -#define CYRILLIC_SMALL_LETTER_IE 0x0435 -#define CYRILLIC_SMALL_LETTER_ZHE 0x0436 -#define CYRILLIC_SMALL_LETTER_ZE 0x0437 -#define CYRILLIC_SMALL_LETTER_I 0x0438 -#define CYRILLIC_SMALL_LETTER_SHORT_I 0x0439 -#define CYRILLIC_SMALL_LETTER_KA 0x043a -#define CYRILLIC_SMALL_LETTER_EL 0x043b -#define CYRILLIC_SMALL_LETTER_EM 0x043c -#define CYRILLIC_SMALL_LETTER_EN 0x043d -#define CYRILLIC_SMALL_LETTER_O 0x043e -#define CYRILLIC_SMALL_LETTER_PE 0x043f -#define CYRILLIC_SMALL_LETTER_ER 0x0440 -#define CYRILLIC_SMALL_LETTER_ES 0x0441 -#define CYRILLIC_SMALL_LETTER_TE 0x0442 -#define CYRILLIC_SMALL_LETTER_U 0x0443 -#define CYRILLIC_SMALL_LETTER_EF 0x0444 -#define CYRILLIC_SMALL_LETTER_HA 0x0445 -#define CYRILLIC_SMALL_LETTER_TSE 0x0446 -#define CYRILLIC_SMALL_LETTER_CHE 0x0447 -#define CYRILLIC_SMALL_LETTER_SHA 0x0448 -#define CYRILLIC_SMALL_LETTER_SHCHA 0x0449 -#define CYRILLIC_SMALL_LETTER_HARD_SIGN 0x044a -#define CYRILLIC_SMALL_LETTER_YERU 0x044b -#define CYRILLIC_SMALL_LETTER_SOFT_SIGN 0x044c -#define CYRILLIC_SMALL_LETTER_E 0x044d -#define CYRILLIC_SMALL_LETTER_YU 0x044e -#define CYRILLIC_SMALL_LETTER_YA 0x044f +#define CYRILLIC_CAPITAL_LETTER_A 0x0410 +#define CYRILLIC_CAPITAL_LETTER_BE 0x0411 +#define CYRILLIC_CAPITAL_LETTER_VE 0x0412 +#define CYRILLIC_CAPITAL_LETTER_GHE 0x0413 +#define CYRILLIC_CAPITAL_LETTER_DE 0x0414 +#define CYRILLIC_CAPITAL_LETTER_IE 0x0415 +#define CYRILLIC_CAPITAL_LETTER_ZHE 0x0416 +#define CYRILLIC_CAPITAL_LETTER_ZE 0x0417 +#define CYRILLIC_CAPITAL_LETTER_I 0x0418 +#define CYRILLIC_CAPITAL_LETTER_SHORT_I 0x0419 +#define CYRILLIC_CAPITAL_LETTER_KA 0x041a +#define CYRILLIC_CAPITAL_LETTER_EL 0x041b +#define CYRILLIC_CAPITAL_LETTER_EM 0x041c +#define CYRILLIC_CAPITAL_LETTER_EN 0x041d +#define CYRILLIC_CAPITAL_LETTER_O 0x041e +#define CYRILLIC_CAPITAL_LETTER_PE 0x041f +#define CYRILLIC_CAPITAL_LETTER_ER 0x0420 +#define CYRILLIC_CAPITAL_LETTER_ES 0x0421 +#define CYRILLIC_CAPITAL_LETTER_TE 0x0422 +#define CYRILLIC_CAPITAL_LETTER_U 0x0423 +#define CYRILLIC_CAPITAL_LETTER_EF 0x0424 +#define CYRILLIC_CAPITAL_LETTER_HA 0x0425 +#define CYRILLIC_CAPITAL_LETTER_TSE 0x0426 +#define CYRILLIC_CAPITAL_LETTER_CHE 0x0427 +#define CYRILLIC_CAPITAL_LETTER_SHA 0x0428 +#define CYRILLIC_CAPITAL_LETTER_SHCHA 0x0429 +#define CYRILLIC_CAPITAL_LETTER_HARD_SIGN 0x042a +#define CYRILLIC_CAPITAL_LETTER_YERU 0x042b +#define CYRILLIC_CAPITAL_LETTER_SOFT_SIGN 0x042c +#define CYRILLIC_CAPITAL_LETTER_E 0x042d +#define CYRILLIC_CAPITAL_LETTER_YU 0x042e +#define CYRILLIC_CAPITAL_LETTER_YA 0x042f +#define CYRILLIC_SMALL_LETTER_A 0x0430 +#define CYRILLIC_SMALL_LETTER_BE 0x0431 +#define CYRILLIC_SMALL_LETTER_VE 0x0432 +#define CYRILLIC_SMALL_LETTER_GHE 0x0433 +#define CYRILLIC_SMALL_LETTER_DE 0x0434 +#define CYRILLIC_SMALL_LETTER_IE 0x0435 +#define CYRILLIC_SMALL_LETTER_ZHE 0x0436 +#define CYRILLIC_SMALL_LETTER_ZE 0x0437 +#define CYRILLIC_SMALL_LETTER_I 0x0438 +#define CYRILLIC_SMALL_LETTER_SHORT_I 0x0439 +#define CYRILLIC_SMALL_LETTER_KA 0x043a +#define CYRILLIC_SMALL_LETTER_EL 0x043b +#define CYRILLIC_SMALL_LETTER_EM 0x043c +#define CYRILLIC_SMALL_LETTER_EN 0x043d +#define CYRILLIC_SMALL_LETTER_O 0x043e +#define CYRILLIC_SMALL_LETTER_PE 0x043f +#define CYRILLIC_SMALL_LETTER_ER 0x0440 +#define CYRILLIC_SMALL_LETTER_ES 0x0441 +#define CYRILLIC_SMALL_LETTER_TE 0x0442 +#define CYRILLIC_SMALL_LETTER_U 0x0443 +#define CYRILLIC_SMALL_LETTER_EF 0x0444 +#define CYRILLIC_SMALL_LETTER_HA 0x0445 +#define CYRILLIC_SMALL_LETTER_TSE 0x0446 +#define CYRILLIC_SMALL_LETTER_CHE 0x0447 +#define CYRILLIC_SMALL_LETTER_SHA 0x0448 +#define CYRILLIC_SMALL_LETTER_SHCHA 0x0449 +#define CYRILLIC_SMALL_LETTER_HARD_SIGN 0x044a +#define CYRILLIC_SMALL_LETTER_YERU 0x044b +#define CYRILLIC_SMALL_LETTER_SOFT_SIGN 0x044c +#define CYRILLIC_SMALL_LETTER_E 0x044d +#define CYRILLIC_SMALL_LETTER_YU 0x044e +#define CYRILLIC_SMALL_LETTER_YA 0x044f /* * Процедуры работы с памятью @@ -355,7 +351,7 @@ void besm6_log (const char *fmt, ...); void besm6_log_cont (const char *fmt, ...); void besm6_debug (const char *fmt, ...); t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); + UNIT *uptr, int32 sw); void besm6_draw_panel (void); /* @@ -377,48 +373,48 @@ t_value besm6_unpack (t_value val, t_value mask); * Разряды главного регистра прерываний (ГРП) * Внешние: */ -#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */ -#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */ -#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */ -#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */ -#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */ -#define GRP_FS1_SYNC 00040000000000000LL /* 42 */ -#define GRP_FS2_SYNC 00020000000000000LL /* 41 */ -#define GRP_TIMER 00010000000000000LL /* 40 */ -#define GRP_PRN1_ZERO 00004000000000000LL /* 39 */ -#define GRP_PRN2_ZERO 00002000000000000LL /* 38 */ -#define GRP_SLAVE 00001000000000000LL /* 37 */ -#define GRP_CHAN3_DONE 00000400000000000LL /* 36 */ -#define GRP_CHAN4_DONE 00000200000000000LL /* 35 */ -#define GRP_CHAN5_DONE 00000100000000000LL /* 34 */ -#define GRP_CHAN6_DONE 00000040000000000LL /* 33 */ -#define GRP_PANEL_REQ 00000020000000000LL /* 32 */ -#define GRP_TTY_START 00000010000000000LL /* 31 */ -#define GRP_IMITATION 00000004000000000LL /* 30 */ -#define GRP_CHAN3_FREE 00000002000000000LL /* 29 */ -#define GRP_CHAN4_FREE 00000001000000000LL /* 28 */ -#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ -#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ -#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ -#define GRP_WATCHDOG 00000000000002000LL /* 11 */ -#define GRP_SLOW_CLK 00000000000001000LL /* 10 */ +#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */ +#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */ +#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */ +#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */ +#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */ +#define GRP_FS1_SYNC 00040000000000000LL /* 42 */ +#define GRP_FS2_SYNC 00020000000000000LL /* 41 */ +#define GRP_TIMER 00010000000000000LL /* 40 */ +#define GRP_PRN1_ZERO 00004000000000000LL /* 39 */ +#define GRP_PRN2_ZERO 00002000000000000LL /* 38 */ +#define GRP_SLAVE 00001000000000000LL /* 37 */ +#define GRP_CHAN3_DONE 00000400000000000LL /* 36 */ +#define GRP_CHAN4_DONE 00000200000000000LL /* 35 */ +#define GRP_CHAN5_DONE 00000100000000000LL /* 34 */ +#define GRP_CHAN6_DONE 00000040000000000LL /* 33 */ +#define GRP_PANEL_REQ 00000020000000000LL /* 32 */ +#define GRP_TTY_START 00000010000000000LL /* 31 */ +#define GRP_IMITATION 00000004000000000LL /* 30 */ +#define GRP_CHAN3_FREE 00000002000000000LL /* 29 */ +#define GRP_CHAN4_FREE 00000001000000000LL /* 28 */ +#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ +#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ +#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ +#define GRP_WATCHDOG 00000000000002000LL /* 11 */ +#define GRP_SLOW_CLK 00000000000001000LL /* 10 */ /* Внутренние: */ -#define GRP_DIVZERO 00000000034000000LL /* 23-21 */ -#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */ -#define GRP_CHECK 00000000004000000LL /* 21 */ -#define GRP_OPRND_PROT 00000000002000000LL /* 20 */ -#define GRP_WATCHPT_W 00000000000200000LL /* 17 */ -#define GRP_WATCHPT_R 00000000000100000LL /* 16 */ -#define GRP_INSN_CHECK 00000000000040000LL /* 15 */ -#define GRP_INSN_PROT 00000000000020000LL /* 14 */ -#define GRP_ILL_INSN 00000000000010000LL /* 13 */ -#define GRP_BREAKPOINT 00000000000004000LL /* 12 */ -#define GRP_PAGE_MASK 00000000000000760LL /* 9-5 */ -#define GRP_RAM_CHECK 00000000000000010LL /* 4 */ -#define GRP_BLOCK_MASK 00000000000000007LL /* 3-1 */ +#define GRP_DIVZERO 00000000034000000LL /* 23-21 */ +#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */ +#define GRP_CHECK 00000000004000000LL /* 21 */ +#define GRP_OPRND_PROT 00000000002000000LL /* 20 */ +#define GRP_WATCHPT_W 00000000000200000LL /* 17 */ +#define GRP_WATCHPT_R 00000000000100000LL /* 16 */ +#define GRP_INSN_CHECK 00000000000040000LL /* 15 */ +#define GRP_INSN_PROT 00000000000020000LL /* 14 */ +#define GRP_ILL_INSN 00000000000010000LL /* 13 */ +#define GRP_BREAKPOINT 00000000000004000LL /* 12 */ +#define GRP_PAGE_MASK 00000000000000760LL /* 9-5 */ +#define GRP_RAM_CHECK 00000000000000010LL /* 4 */ +#define GRP_BLOCK_MASK 00000000000000007LL /* 3-1 */ -#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK)) -#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK)) +#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK)) +#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK)) /* Номер блока ОЗУ или номер страницы, вызвавших прерывание */ extern uint32 iintr_data; diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index 1ff0ed32..b5febae9 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -32,88 +32,88 @@ /* * Управляющее слово обмена с магнитным диском. */ -#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */ -#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */ -#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */ -#define DISK_READ 000400000 /* чтение с диска в память */ -#define DISK_PAGE 000370000 /* номер страницы памяти */ -#define DISK_HALFPAGE 000004000 /* выбор половины листа */ -#define DISK_UNIT 000001600 /* номер устройства */ -#define DISK_HALFZONE 000000001 /* выбор половины зоны */ +#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */ +#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */ +#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */ +#define DISK_READ 000400000 /* чтение с диска в память */ +#define DISK_PAGE 000370000 /* номер страницы памяти */ +#define DISK_HALFPAGE 000004000 /* выбор половины листа */ +#define DISK_UNIT 000001600 /* номер устройства */ +#define DISK_HALFZONE 000000001 /* выбор половины зоны */ /* * "Хороший" статус чтения/записи. * Вычислено по текстам ОС Дубна. * Диспак доволен. */ -#define STATUS_GOOD 014000400 +#define STATUS_GOOD 014000400 /* * Параметры обмена с внешним устройством. */ typedef struct { - int op; /* Условное слово обмена */ - int dev; /* Номер устройства, 0..7 */ - int zone; /* Номер зоны на диске */ - int track; /* Выбор половины зоны на диске */ - int memory; /* Начальный адрес памяти */ - int format; /* Флаг разметки */ - int status; /* Регистр состояния */ - t_value mask_grp; /* Маска готовности для ГРП */ - int mask_fail; /* Маска ошибки обмена */ - t_value *sysdata; /* Буфер системных данных */ + int op; /* Условное слово обмена */ + int dev; /* Номер устройства, 0..7 */ + int zone; /* Номер зоны на диске */ + int track; /* Выбор половины зоны на диске */ + int memory; /* Начальный адрес памяти */ + int format; /* Флаг разметки */ + int status; /* Регистр состояния */ + t_value mask_grp; /* Маска готовности для ГРП */ + int mask_fail; /* Маска ошибки обмена */ + t_value *sysdata; /* Буфер системных данных */ } KMD; -static KMD controller [2]; /* Две стойки КМД */ -int disk_fail; /* Маска ошибок по направлениям */ +static KMD controller [2]; /* Две стойки КМД */ +int disk_fail; /* Маска ошибок по направлениям */ t_stat disk_event (UNIT *u); /* * DISK data structures * - * disk_dev DISK device descriptor - * disk_unit DISK unit descriptor - * disk_reg DISK register list + * disk_dev DISK device descriptor + * disk_unit DISK unit descriptor + * disk_reg DISK register list */ UNIT disk_unit [16] = { - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, - { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, + { UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) }, }; REG disk_reg[] = { -{ "КУС_0", &controller[0].op, 8, 24, 0, 1 }, -{ "УСТР_0", &controller[0].dev, 8, 3, 0, 1 }, -{ "ЗОНА_0", &controller[0].zone, 8, 10, 0, 1 }, -{ "ДОРОЖКА_0", &controller[0].track, 8, 2, 0, 1 }, -{ "МОЗУ_0", &controller[0].memory, 8, 20, 0, 1 }, -{ "РС_0", &controller[0].status, 8, 24, 0, 1 }, -{ "КУС_1", &controller[1].op, 8, 24, 0, 1 }, -{ "УСТР_1", &controller[1].dev, 8, 3, 0, 1 }, -{ "ЗОНА_1", &controller[1].zone, 8, 10, 0, 1 }, -{ "ДОРОЖКА_1", &controller[1].track, 8, 2, 0, 1 }, -{ "МОЗУ_1", &controller[1].memory, 8, 20, 0, 1 }, -{ "РС_1", &controller[1].status, 8, 24, 0, 1 }, -{ "ОШ", &disk_fail, 8, 6, 0, 1 }, -{ 0 } + { "КУС_0", &controller[0].op, 8, 24, 0, 1 }, + { "УСТР_0", &controller[0].dev, 8, 3, 0, 1 }, + { "ЗОНА_0", &controller[0].zone, 8, 10, 0, 1 }, + { "ДОРОЖКА_0", &controller[0].track, 8, 2, 0, 1 }, + { "МОЗУ_0", &controller[0].memory, 8, 20, 0, 1 }, + { "РС_0", &controller[0].status, 8, 24, 0, 1 }, + { "КУС_1", &controller[1].op, 8, 24, 0, 1 }, + { "УСТР_1", &controller[1].dev, 8, 3, 0, 1 }, + { "ЗОНА_1", &controller[1].zone, 8, 10, 0, 1 }, + { "ДОРОЖКА_1", &controller[1].track, 8, 2, 0, 1 }, + { "МОЗУ_1", &controller[1].memory, 8, 20, 0, 1 }, + { "РС_1", &controller[1].status, 8, 24, 0, 1 }, + { "ОШ", &disk_fail, 8, 6, 0, 1 }, + { 0 } }; MTAB disk_mod[] = { - { 0 } + { 0 } }; t_stat disk_reset (DEVICE *dptr); @@ -121,10 +121,10 @@ t_stat disk_attach (UNIT *uptr, char *cptr); t_stat disk_detach (UNIT *uptr); DEVICE disk_dev = { - "DISK", disk_unit, disk_reg, disk_mod, - 16, 8, 21, 1, 8, 50, - NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach, - NULL, DEV_DISABLE | DEV_DEBUG + "DISK", disk_unit, disk_reg, disk_mod, + 16, 8, 21, 1, 8, 50, + NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach, + NULL, DEV_DISABLE | DEV_DEBUG }; /* @@ -132,10 +132,10 @@ DEVICE disk_dev = { */ static KMD *unit_to_ctlr (UNIT *u) { - if (u < &disk_unit[8]) - return &controller[0]; - else - return &controller[1]; + if (u < &disk_unit[8]) + return &controller[0]; + else + return &controller[1]; } /* @@ -143,45 +143,45 @@ static KMD *unit_to_ctlr (UNIT *u) */ t_stat disk_reset (DEVICE *dptr) { - int i; + int i; - memset (&controller, 0, sizeof (controller)); - controller[0].sysdata = &memory [030]; - controller[1].sysdata = &memory [040]; - controller[0].mask_grp = GRP_CHAN3_FREE; - controller[1].mask_grp = GRP_CHAN4_FREE; - controller[0].mask_fail = 020; - controller[1].mask_fail = 010; - for (i=0; i<16; ++i) - sim_cancel (&disk_unit[i]); - return SCPE_OK; + memset (&controller, 0, sizeof (controller)); + controller[0].sysdata = &memory [030]; + controller[1].sysdata = &memory [040]; + controller[0].mask_grp = GRP_CHAN3_FREE; + controller[1].mask_grp = GRP_CHAN4_FREE; + controller[0].mask_fail = 020; + controller[1].mask_fail = 010; + for (i=0; i<16; ++i) + sim_cancel (&disk_unit[i]); + return SCPE_OK; } t_stat disk_attach (UNIT *u, char *cptr) { - t_stat s; + t_stat s; - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; - return SCPE_OK; + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + return SCPE_OK; } t_stat disk_detach (UNIT *u) { - /* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */ - return detach_unit (u); + /* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */ + return detach_unit (u); } t_value spread (t_value val) { - int i, j; - t_value res = 0; + int i, j; + t_value res = 0; - for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) - if (val & (1LL<<(i+j*5))) - res |= 1LL << (i*9+j); - return res & BITS48; + for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) + if (val & (1LL<<(i+j*5))) + res |= 1LL << (i*9+j); + return res & BITS48; } /* @@ -189,21 +189,21 @@ t_value spread (t_value val) */ static void log_data (t_value *data, int nwords) { - int i; - t_value val; + int i; + t_value val; - for (i=0; i> 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"); + for (i=0; i> 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"); } /* @@ -211,14 +211,14 @@ static void log_data (t_value *data, int nwords) */ static unsigned sum_with_right_carry (unsigned a, unsigned b) { - unsigned c; + unsigned c; - while (b) { - c = a & b; - a ^= b; - b = c >> 1; - } - return a; + while (b) { + c = a & b; + a ^= b; + b = c >> 1; + } + return a; } /* @@ -226,32 +226,32 @@ static unsigned sum_with_right_carry (unsigned a, unsigned b) */ void disk_write (UNIT *u) { - KMD *c = unit_to_ctlr (u); + KMD *c = unit_to_ctlr (u); - if (disk_dev.dctrl) - besm6_debug ("::: запись МД %o зона %04o память %05o-%05o", - c->dev, c->zone, c->memory, c->memory + 1023); - fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); - sim_fwrite (c->sysdata, 8, 8, u->fileref); - sim_fwrite (&memory [c->memory], 8, 1024, u->fileref); - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); + if (disk_dev.dctrl) + besm6_debug ("::: запись МД %o зона %04o память %05o-%05o", + c->dev, c->zone, c->memory, c->memory + 1023); + fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); + sim_fwrite (c->sysdata, 8, 8, u->fileref); + sim_fwrite (&memory [c->memory], 8, 1024, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); } void disk_write_track (UNIT *u) { - KMD *c = unit_to_ctlr (u); + KMD *c = unit_to_ctlr (u); - if (disk_dev.dctrl) - besm6_debug ("::: запись МД %o полузона %04o.%d память %05o-%05o", - c->dev, c->zone, c->track, c->memory, c->memory + 511); - fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); - sim_fwrite (c->sysdata + 4*c->track, 8, 4, u->fileref); - fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, - SEEK_SET); - sim_fwrite (&memory [c->memory], 8, 512, u->fileref); - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); + if (disk_dev.dctrl) + besm6_debug ("::: запись МД %o полузона %04o.%d память %05o-%05o", + c->dev, c->zone, c->track, c->memory, c->memory + 511); + fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); + sim_fwrite (c->sysdata + 4*c->track, 8, 4, u->fileref); + fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, + SEEK_SET); + sim_fwrite (&memory [c->memory], 8, 512, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); } /* @@ -259,35 +259,35 @@ void disk_write_track (UNIT *u) */ void disk_format (UNIT *u) { - KMD *c = unit_to_ctlr (u); - t_value fmtbuf[5], *ptr; - int i; + KMD *c = unit_to_ctlr (u); + t_value fmtbuf[5], *ptr; + int i; - /* По сути, эмулятору ничего делать не надо. */ - if (! disk_dev.dctrl) - return; + /* По сути, эмулятору ничего делать не надо. */ + if (! disk_dev.dctrl) + return; - /* Находим начало записываемого заголовка. */ - ptr = &memory [c->memory]; - while ((*ptr & BITS48) == 0) - ptr++; + /* Находим начало записываемого заголовка. */ + ptr = &memory [c->memory]; + while ((*ptr & BITS48) == 0) + ptr++; - /* Декодируем из гребенки в нормальный вид. */ - for (i = 0; i < 5; i++) - fmtbuf[i] = spread (ptr[i]); + /* Декодируем из гребенки в нормальный вид. */ + for (i = 0; i < 5; i++) + fmtbuf[i] = spread (ptr[i]); - /* При первой попытке разметки адресный маркер начинается в старшем 5-разрядном слоге, - * пропускаем первый слог. */ - for (i=0; i<4; i++) - fmtbuf[i] = ((fmtbuf[i] & BITS48) << 5) | - ((fmtbuf[i+1] >> 40) & BITS(5)); + /* При первой попытке разметки адресный маркер начинается в старшем 5-разрядном слоге, + * пропускаем первый слог. */ + for (i=0; i<4; i++) + fmtbuf[i] = ((fmtbuf[i] & BITS48) << 5) | + ((fmtbuf[i+1] >> 40) & BITS(5)); - /* Печатаем идентификатор, адрес и контрольную сумму адреса. */ - besm6_debug ("::: формат МД %o полузона %04o.%d память %05o и-а-кса %010o %010o", - c->dev, c->zone, c->track, c->memory, - (int) (fmtbuf[0] >> 8 & BITS(30)), - (int) (fmtbuf[2] >> 14 & BITS(30))); - /* log_data (fmtbuf, 4); */ + /* Печатаем идентификатор, адрес и контрольную сумму адреса. */ + besm6_debug ("::: формат МД %o полузона %04o.%d память %05o и-а-кса %010o %010o", + c->dev, c->zone, c->track, c->memory, + (int) (fmtbuf[0] >> 8 & BITS(30)), + (int) (fmtbuf[2] >> 14 & BITS(30))); + /* log_data (fmtbuf, 4); */ } /* @@ -295,66 +295,66 @@ void disk_format (UNIT *u) */ void disk_read (UNIT *u) { - KMD *c = unit_to_ctlr (u); + KMD *c = unit_to_ctlr (u); - if (disk_dev.dctrl) - besm6_debug ((c->op & DISK_READ_SYSDATA) ? - "::: чтение МД %o зона %04o служебные слова" : - "::: чтение МД %o зона %04o память %05o-%05o", - c->dev, c->zone, c->memory, c->memory + 1023); - fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); - if (sim_fread (c->sysdata, 8, 8, u->fileref) != 8) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - if (! (c->op & DISK_READ_SYSDATA) && - sim_fread (&memory [c->memory], 8, 1024, u->fileref) != 1024) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); + if (disk_dev.dctrl) + besm6_debug ((c->op & DISK_READ_SYSDATA) ? + "::: чтение МД %o зона %04o служебные слова" : + "::: чтение МД %o зона %04o память %05o-%05o", + c->dev, c->zone, c->memory, c->memory + 1023); + fseek (u->fileref, ZONE_SIZE * c->zone * 8, SEEK_SET); + if (sim_fread (c->sysdata, 8, 8, u->fileref) != 8) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (! (c->op & DISK_READ_SYSDATA) && + sim_fread (&memory [c->memory], 8, 1024, u->fileref) != 1024) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); } t_value collect (t_value val) { - int i, j; - t_value res = 0; + int i, j; + t_value res = 0; - for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) - if (val & (1LL<<(i*9+j))) - res |= 1LL << (i+j*5); - return res & BITS48; + for (i = 0; i < 5; i++) for (j = 0; j < 9; j++) + if (val & (1LL<<(i*9+j))) + res |= 1LL << (i+j*5); + return res & BITS48; } void disk_read_track (UNIT *u) { - KMD *c = unit_to_ctlr (u); + KMD *c = unit_to_ctlr (u); - if (disk_dev.dctrl) - besm6_debug ((c->op & DISK_READ_SYSDATA) ? - "::: чтение МД %o полузона %04o.%d служебные слова" : - "::: чтение МД %o полузона %04o.%d память %05o-%05o", - c->dev, c->zone, c->track, c->memory, c->memory + 511); - fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); - if (sim_fread (c->sysdata + 4*c->track, 8, 4, u->fileref) != 4) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - if (! (c->op & DISK_READ_SYSDATA)) { - fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, - SEEK_SET); - if (sim_fread (&memory [c->memory], 8, 512, u->fileref) != 512) { - /* Чтение неинициализированного диска */ - disk_fail |= c->mask_fail; - return; - } - } - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); + if (disk_dev.dctrl) + besm6_debug ((c->op & DISK_READ_SYSDATA) ? + "::: чтение МД %o полузона %04o.%d служебные слова" : + "::: чтение МД %o полузона %04o.%d память %05o-%05o", + c->dev, c->zone, c->track, c->memory, c->memory + 511); + fseek (u->fileref, (ZONE_SIZE*c->zone + 4*c->track) * 8, SEEK_SET); + if (sim_fread (c->sysdata + 4*c->track, 8, 4, u->fileref) != 4) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + if (! (c->op & DISK_READ_SYSDATA)) { + fseek (u->fileref, (8 + ZONE_SIZE*c->zone + 512*c->track) * 8, + SEEK_SET); + if (sim_fread (&memory [c->memory], 8, 512, u->fileref) != 512) { + /* Чтение неинициализированного диска */ + disk_fail |= c->mask_fail; + return; + } + } + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); } /* @@ -362,34 +362,34 @@ void disk_read_track (UNIT *u) */ void disk_read_header (UNIT *u) { - KMD *c = unit_to_ctlr (u); - t_value *sysdata = c->sysdata + 4*c->track; - int iaksa, i, cyl, head; + KMD *c = unit_to_ctlr (u); + t_value *sysdata = c->sysdata + 4*c->track; + int iaksa, i, cyl, head; - /* Адрес: номер цилиндра и головки. */ - head = (c->zone << 1) + c->track; - cyl = head / 10; - head %= 10; - iaksa = (cyl << 20) | (head << 16); + /* Адрес: номер цилиндра и головки. */ + head = (c->zone << 1) + c->track; + cyl = head / 10; + head %= 10; + iaksa = (cyl << 20) | (head << 16); - /* Идентификатор дорожки замены. */ - if (c->zone >= 01750) - iaksa |= BBIT(30); + /* Идентификатор дорожки замены. */ + if (c->zone >= 01750) + iaksa |= BBIT(30); - /* Контрольная сумма адреса с переносом вправо. */ - iaksa |= BITS(12) & ~sum_with_right_carry (iaksa >> 12, iaksa >> 24); + /* Контрольная сумма адреса с переносом вправо. */ + iaksa |= BITS(12) & ~sum_with_right_carry (iaksa >> 12, iaksa >> 24); - /* Амиакса, 42 нуля, амиакса, много единиц. */ - sysdata[0] = 07404000000000000LL | (t_value) iaksa << 8; - sysdata[1] = 03740LL; - sysdata[2] = 00400000000037777LL | (t_value) iaksa << 14; - sysdata[3] = BITS48; - if (disk_dev.dctrl) - log_data (sysdata, 4); + /* Амиакса, 42 нуля, амиакса, много единиц. */ + sysdata[0] = 07404000000000000LL | (t_value) iaksa << 8; + sysdata[1] = 03740LL; + sysdata[2] = 00400000000037777LL | (t_value) iaksa << 14; + sysdata[3] = BITS48; + if (disk_dev.dctrl) + log_data (sysdata, 4); - /* Кодируем гребенку. */ - for (i=0; i<4; i++) - sysdata[i] = SET_CONVOL (collect (sysdata[i]), CONVOL_NUMBER); + /* Кодируем гребенку. */ + for (i=0; i<4; i++) + sysdata[i] = SET_CONVOL (collect (sysdata[i]), CONVOL_NUMBER); } /* @@ -398,26 +398,26 @@ void disk_read_header (UNIT *u) */ void disk_io (int ctlr, uint32 cmd) { - KMD *c = &controller [ctlr]; + KMD *c = &controller [ctlr]; - c->op = cmd; - c->format = 0; - if (c->op & DISK_PAGE_MODE) { - /* Обмен страницей */ - c->memory = (cmd & DISK_PAGE) >> 2 | (cmd & DISK_BLOCK) >> 8; - } else { - /* Обмен половиной страницы (дорожкой) */ - c->memory = (cmd & (DISK_PAGE | DISK_HALFPAGE)) >> 2 | (cmd & DISK_BLOCK) >> 8; - } + c->op = cmd; + c->format = 0; + if (c->op & DISK_PAGE_MODE) { + /* Обмен страницей */ + c->memory = (cmd & DISK_PAGE) >> 2 | (cmd & DISK_BLOCK) >> 8; + } else { + /* Обмен половиной страницы (дорожкой) */ + c->memory = (cmd & (DISK_PAGE | DISK_HALFPAGE)) >> 2 | (cmd & DISK_BLOCK) >> 8; + } #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: задание на %s %08o", ctlr + '3', - (c->op & DISK_READ) ? "чтение" : "запись", cmd); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: задание на %s %08o", ctlr + '3', + (c->op & DISK_READ) ? "чтение" : "запись", cmd); #endif - disk_fail &= ~c->mask_fail; + disk_fail &= ~c->mask_fail; - /* Гасим главный регистр прерываний. */ - GRP &= ~c->mask_grp; + /* Гасим главный регистр прерываний. */ + GRP &= ~c->mask_grp; } /* @@ -425,188 +425,188 @@ void disk_io (int ctlr, uint32 cmd) */ void disk_ctl (int ctlr, uint32 cmd) { - KMD *c = &controller [ctlr]; - UNIT *u = &disk_unit [c->dev]; + KMD *c = &controller [ctlr]; + UNIT *u = &disk_unit [c->dev]; - if (cmd & BBIT(12)) { - /* Выдача в КМД адреса дорожки. - * Здесь же выполняем обмен с диском. - * Номер дисковода к этому моменту уже известен. */ - if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { - /* Device not attached. */ - disk_fail |= c->mask_fail; - return; - } - c->zone = (cmd >> 1) & BITS(10); - c->track = cmd & 1; + if (cmd & BBIT(12)) { + /* Выдача в КМД адреса дорожки. + * Здесь же выполняем обмен с диском. + * Номер дисковода к этому моменту уже известен. */ + if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { + /* Device not attached. */ + disk_fail |= c->mask_fail; + return; + } + c->zone = (cmd >> 1) & BITS(10); + c->track = cmd & 1; #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: выдача адреса дорожки %04o.%d", - ctlr + '3', c->zone, c->track); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: выдача адреса дорожки %04o.%d", + ctlr + '3', c->zone, c->track); #endif - disk_fail &= ~c->mask_fail; - if (c->op & DISK_READ) { - if (c->op & DISK_PAGE_MODE) - disk_read (u); - else - disk_read_track (u); - } else { - if (u->flags & UNIT_RO) { - /* Read only. */ - /*longjmp (cpu_halt, SCPE_RO);*/ - disk_fail |= c->mask_fail; - return; - } - if (c->format) - disk_format (u); - else if (c->op & DISK_PAGE_MODE) - disk_write (u); - else - disk_write_track (u); - } + disk_fail &= ~c->mask_fail; + if (c->op & DISK_READ) { + if (c->op & DISK_PAGE_MODE) + disk_read (u); + else + disk_read_track (u); + } else { + if (u->flags & UNIT_RO) { + /* Read only. */ + /*longjmp (cpu_halt, SCPE_RO);*/ + disk_fail |= c->mask_fail; + return; + } + if (c->format) + disk_format (u); + else if (c->op & DISK_PAGE_MODE) + disk_write (u); + else + disk_write_track (u); + } - /* Ждём события от устройства. */ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + /* Ждём события от устройства. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ - } else if (cmd & BBIT(11)) { - /* Выбора номера устройства и занесение в регистр маски КМД. - * Бит 8 - устройство 0, бит 7 - устройство 1, ... бит 1 - устройство 7. - * Также установлен бит 9 - что он означает? */ - if (cmd & BBIT(8)) c->dev = 7; - else if (cmd & BBIT(7)) c->dev = 6; - else if (cmd & BBIT(6)) c->dev = 5; - else if (cmd & BBIT(5)) c->dev = 4; - else if (cmd & BBIT(4)) c->dev = 3; - else if (cmd & BBIT(3)) c->dev = 2; - else if (cmd & BBIT(2)) c->dev = 1; - else if (cmd & BBIT(1)) c->dev = 0; - else { - /* Неверная маска выбора устройства. */ - c->dev = -1; - return; - } - c->dev += ctlr << 3; - u = &disk_unit[c->dev]; + } else if (cmd & BBIT(11)) { + /* Выбора номера устройства и занесение в регистр маски КМД. + * Бит 8 - устройство 0, бит 7 - устройство 1, ... бит 1 - устройство 7. + * Также установлен бит 9 - что он означает? */ + if (cmd & BBIT(8)) c->dev = 7; + else if (cmd & BBIT(7)) c->dev = 6; + else if (cmd & BBIT(6)) c->dev = 5; + else if (cmd & BBIT(5)) c->dev = 4; + else if (cmd & BBIT(4)) c->dev = 3; + else if (cmd & BBIT(3)) c->dev = 2; + else if (cmd & BBIT(2)) c->dev = 1; + else if (cmd & BBIT(1)) c->dev = 0; + else { + /* Неверная маска выбора устройства. */ + c->dev = -1; + return; + } + c->dev += ctlr << 3; + u = &disk_unit[c->dev]; #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: выбор устройства %d", - ctlr + '3', c->dev); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: выбор устройства %d", + ctlr + '3', c->dev); #endif - if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { - /* Device not attached. */ - disk_fail |= c->mask_fail; - GRP &= ~c->mask_grp; - } - GRP |= c->mask_grp; + if ((disk_dev.flags & DEV_DIS) || ! (u->flags & UNIT_ATT)) { + /* Device not attached. */ + disk_fail |= c->mask_fail; + GRP &= ~c->mask_grp; + } + GRP |= c->mask_grp; - } else if (cmd & BBIT(9)) { - /* Проверка прерывания от КМД? */ + } else if (cmd & BBIT(9)) { + /* Проверка прерывания от КМД? */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: проверка готовности", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: проверка готовности", + ctlr + '3'); #endif - GRP |= c->mask_grp; + GRP |= c->mask_grp; - } else { - /* Команда, выдаваемая в КМД. */ - switch (cmd & 077) { - case 000: /* диспак выдаёт эту команду один раз в начале загрузки */ + } else { + /* Команда, выдаваемая в КМД. */ + switch (cmd & 077) { + case 000: /* диспак выдаёт эту команду один раз в начале загрузки */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: недокументированная команда 00", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: недокументированная команда 00", + ctlr + '3'); #endif - break; - case 001: /* сброс на 0 цилиндр */ + break; + case 001: /* сброс на 0 цилиндр */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: сброс на 0 цилиндр", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: сброс на 0 цилиндр", + ctlr + '3'); #endif - break; - case 002: /* подвод */ - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: подвод", ctlr + '3'); - break; - case 003: /* чтение (НСМД-МОЗУ) */ - case 043: /* резервной дорожки */ + break; + case 002: /* подвод */ + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: подвод", ctlr + '3'); + break; + case 003: /* чтение (НСМД-МОЗУ) */ + case 043: /* резервной дорожки */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: чтение", ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: чтение", ctlr + '3'); #endif - break; - case 004: /* запись (МОЗУ-НСМД) */ - case 044: /* резервной дорожки */ + break; + case 004: /* запись (МОЗУ-НСМД) */ + case 044: /* резервной дорожки */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: запись", ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: запись", ctlr + '3'); #endif - break; - case 005: /* разметка */ - c->format = 1; - break; - case 006: /* сравнение кодов (МОЗУ-НСМД) */ + break; + case 005: /* разметка */ + c->format = 1; + break; + case 006: /* сравнение кодов (МОЗУ-НСМД) */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: сравнение кодов", ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: сравнение кодов", ctlr + '3'); #endif - break; - case 007: /* чтение заголовка */ - case 047: /* резервной дорожки */ - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: чтение %s заголовка", ctlr + '3', - cmd & 040 ? "резервного" : ""); - disk_fail &= ~c->mask_fail; - disk_read_header (u); + break; + case 007: /* чтение заголовка */ + case 047: /* резервной дорожки */ + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: чтение %s заголовка", ctlr + '3', + cmd & 040 ? "резервного" : ""); + disk_fail &= ~c->mask_fail; + disk_read_header (u); - /* Ждём события от устройства. */ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ - break; - case 010: /* гашение PC */ + /* Ждём события от устройства. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + break; + case 010: /* гашение PC */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: гашение регистра состояния", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: гашение регистра состояния", + ctlr + '3'); #endif - c->status = 0; - break; - case 011: /* опрос 1÷12 разрядов PC */ + c->status = 0; + break; + case 011: /* опрос 1÷12 разрядов PC */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: опрос младших разрядов состояния", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос младших разрядов состояния", + ctlr + '3'); #endif - if (disk_unit[c->dev].flags & UNIT_ATT) - c->status = STATUS_GOOD & BITS(12); - else - c->status = 0; - break; - case 031: /* опрос 13÷24 разрядов РС */ + if (disk_unit[c->dev].flags & UNIT_ATT) + c->status = STATUS_GOOD & BITS(12); + else + c->status = 0; + break; + case 031: /* опрос 13÷24 разрядов РС */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: опрос старших разрядов состояния", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос старших разрядов состояния", + ctlr + '3'); #endif - if (disk_unit[c->dev].flags & UNIT_ATT) - c->status = (STATUS_GOOD >> 12) & BITS(12); - else - c->status = 0; - break; - case 050: /* освобождение НМД */ + if (disk_unit[c->dev].flags & UNIT_ATT) + c->status = (STATUS_GOOD >> 12) & BITS(12); + else + c->status = 0; + break; + case 050: /* освобождение НМД */ #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: освобождение накопителя", - ctlr + '3'); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: освобождение накопителя", + ctlr + '3'); #endif - break; - default: - besm6_debug ("::: КМД %c: неизвестная команда %02o", - ctlr + '3', cmd & 077); - GRP |= c->mask_grp; /* чтобы не зависало */ - break; - } - } + break; + default: + besm6_debug ("::: КМД %c: неизвестная команда %02o", + ctlr + '3', cmd & 077); + GRP |= c->mask_grp; /* чтобы не зависало */ + break; + } + } } /* @@ -614,13 +614,13 @@ void disk_ctl (int ctlr, uint32 cmd) */ int disk_state (int ctlr) { - KMD *c = &controller [ctlr]; + KMD *c = &controller [ctlr]; #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД %c: опрос состояния = %04o", - ctlr + '3', c->status); + if (disk_dev.dctrl) + besm6_debug ("::: КМД %c: опрос состояния = %04o", + ctlr + '3', c->status); #endif - return c->status; + return c->status; } /* @@ -629,10 +629,10 @@ int disk_state (int ctlr) */ t_stat disk_event (UNIT *u) { - KMD *c = unit_to_ctlr (u); + KMD *c = unit_to_ctlr (u); - GRP |= c->mask_grp; - return SCPE_OK; + GRP |= c->mask_grp; + return SCPE_OK; } /* @@ -641,8 +641,8 @@ t_stat disk_event (UNIT *u) int disk_errors () { #if 0 - if (disk_dev.dctrl) - besm6_debug ("::: КМД: опрос шкалы ошибок = %04o", disk_fail); + if (disk_dev.dctrl) + besm6_debug ("::: КМД: опрос шкалы ошибок = %04o", disk_fail); #endif - return disk_fail; + return disk_fail; } diff --git a/BESM6/besm6_drum.c b/BESM6/besm6_drum.c index 6dedcb5a..e29df468 100644 --- a/BESM6/besm6_drum.c +++ b/BESM6/besm6_drum.c @@ -31,54 +31,54 @@ /* * Управляющее слово обмена с магнитным барабаном. */ -#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 /* номер сектора */ +#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; /* Маска ошибок по направлениям */ +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 + * 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) }, + { 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[] = { -{ "УС", &drum_op, 8, 24, 0, 1 }, -{ "ЗОНА", &drum_zone, 8, 10, 0, 1 }, -{ "СЕКТОР", &drum_sector, 8, 2, 0, 1 }, -{ "МОЗУ", &drum_memory, 8, 15, 0, 1 }, -{ "СЧСЛОВ", &drum_nwords, 8, 11, 0, 1 }, -{ 0 } + { "УС", &drum_op, 8, 24, 0, 1 }, + { "ЗОНА", &drum_zone, 8, 10, 0, 1 }, + { "СЕКТОР", &drum_sector, 8, 2, 0, 1 }, + { "МОЗУ", &drum_memory, 8, 15, 0, 1 }, + { "СЧСЛОВ", &drum_nwords, 8, 11, 0, 1 }, + { 0 } }; MTAB drum_mod[] = { - { 0 } + { 0 } }; t_stat drum_reset (DEVICE *dptr); @@ -86,10 +86,10 @@ t_stat drum_attach (UNIT *uptr, 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 + "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 }; /* @@ -97,37 +97,37 @@ DEVICE drum_dev = { */ 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; + 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, char *cptr) { - t_stat s; + 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; + 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 (u == &drum_unit[0]) + GRP &= ~GRP_DRUM1_FREE; + else + GRP &= ~GRP_DRUM2_FREE; + return detach_unit (u); } /* @@ -136,37 +136,37 @@ t_stat drum_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); - } + 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); - 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); + ctlr = (u == &drum_unit[1]); + sysdata = ctlr ? &memory [020] : &memory [010]; + fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET); + 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; + int ctlr; + t_value *sysdata; - ctlr = (u == &drum_unit[1]); - sysdata = ctlr ? &memory [020] : &memory [010]; - fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, - SEEK_SET); - sim_fwrite (&sysdata [drum_sector*2], 8, 2, u->fileref); - fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, - SEEK_SET); - sim_fwrite (&memory [drum_memory], 8, 256, u->fileref); - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); + ctlr = (u == &drum_unit[1]); + sysdata = ctlr ? &memory [020] : &memory [010]; + fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, + SEEK_SET); + sim_fwrite (&sysdata [drum_sector*2], 8, 2, u->fileref); + fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, + SEEK_SET); + sim_fwrite (&memory [drum_memory], 8, 256, u->fileref); + if (ferror (u->fileref)) + longjmp (cpu_halt, SCPE_IOERR); } /* @@ -209,57 +209,57 @@ void drum_write_sector (UNIT *u) */ void drum_read (UNIT *u) { - int ctlr; - t_value *sysdata; + int ctlr; + t_value *sysdata; - ctlr = (u == &drum_unit[1]); - sysdata = ctlr ? &memory [020] : &memory [010]; - fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET); - if (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); + ctlr = (u == &drum_unit[1]); + sysdata = ctlr ? &memory [020] : &memory [010]; + fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET); + if (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; + int ctlr; + t_value *sysdata; - ctlr = (u == &drum_unit[1]); - sysdata = ctlr ? &memory [020] : &memory [010]; - fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, SEEK_SET); - if (sim_fread (&sysdata [drum_sector*2], 8, 2, u->fileref) != 2) { - /* Чтение неинициализированного барабана */ - drum_fail |= 0100 >> ctlr; - return; - } - if (! (drum_op & DRUM_READ_SYSDATA)) { - fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, - SEEK_SET); - if (sim_fread (&memory[drum_memory], 8, 256, u->fileref) != 256) { - /* Чтение неинициализированного барабана */ - drum_fail |= 0100 >> ctlr; - return; - } - } - if (ferror (u->fileref)) - longjmp (cpu_halt, SCPE_IOERR); + ctlr = (u == &drum_unit[1]); + sysdata = ctlr ? &memory [020] : &memory [010]; + fseek (u->fileref, (ZONE_SIZE*drum_zone + drum_sector*2) * 8, SEEK_SET); + if (sim_fread (&sysdata [drum_sector*2], 8, 2, u->fileref) != 2) { + /* Чтение неинициализированного барабана */ + drum_fail |= 0100 >> ctlr; + return; + } + if (! (drum_op & DRUM_READ_SYSDATA)) { + fseek (u->fileref, (ZONE_SIZE*drum_zone + 8 + drum_sector*256) * 8, + SEEK_SET); + if (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_CONVOL (0, CONVOL_NUMBER); + while (nwords-- > 0) + *p++ = SET_CONVOL (0, CONVOL_NUMBER); } /* @@ -267,87 +267,87 @@ static void clear_memory (t_value *p, int nwords) */ void drum (int ctlr, uint32 cmd) { - UNIT *u = &drum_unit[ctlr]; + 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);*/ + 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; + /* Гасим главный регистр прерываний. */ + 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); /* Ускорим для отладки. */ + /* Ждём события от устройства. + * Согласно данным из книжки Мазного Г.Л., + * даём 20 мсек на обмен, или 200 тыс.тактов. */ + /*sim_activate (u, 20*MSEC);*/ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ } /* @@ -356,11 +356,11 @@ void drum (int ctlr, uint32 cmd) */ t_stat drum_event (UNIT *u) { - if (u == &drum_unit[0]) - GRP |= GRP_DRUM1_FREE; - else - GRP |= GRP_DRUM2_FREE; - return SCPE_OK; + if (u == &drum_unit[0]) + GRP |= GRP_DRUM1_FREE; + else + GRP |= GRP_DRUM2_FREE; + return SCPE_OK; } /* @@ -368,5 +368,5 @@ t_stat drum_event (UNIT *u) */ int drum_errors () { - return drum_fail; + return drum_fail; } diff --git a/BESM6/besm6_mmu.c b/BESM6/besm6_mmu.c index c9d2c2e5..7428cb72 100644 --- a/BESM6/besm6_mmu.c +++ b/BESM6/besm6_mmu.c @@ -32,12 +32,12 @@ /* * MMU data structures * - * mmu_dev MMU device descriptor - * mmu_unit MMU unit descriptor - * mmu_reg MMU register list + * mmu_dev MMU device descriptor + * mmu_unit MMU unit descriptor + * mmu_reg MMU register list */ UNIT mmu_unit = { - UDATA (NULL, UNIT_FIX, 8) + UDATA (NULL, UNIT_FIX, 8) }; t_value BRZ[8]; @@ -56,80 +56,80 @@ uint32 BRSLRU; t_value RP[8]; uint32 TLB[32]; -unsigned iintr_data; /* protected page number or parity check location */ +unsigned iintr_data; /* protected page number or parity check location */ t_value pult[8]; REG mmu_reg[] = { -{ "БРЗ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры записи */ -{ "БРЗ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРЗ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БАЗ0", &BAZ[0], 8, 16, 0, 1 }, /* Буферные адреса записи */ -{ "БАЗ1", &BAZ[1], 8, 16, 0, 1 }, -{ "БАЗ2", &BAZ[2], 8, 16, 0, 1 }, -{ "БАЗ3", &BAZ[3], 8, 16, 0, 1 }, -{ "БАЗ4", &BAZ[4], 8, 16, 0, 1 }, -{ "БАЗ5", &BAZ[5], 8, 16, 0, 1 }, -{ "БАЗ6", &BAZ[6], 8, 16, 0, 1 }, -{ "БАЗ7", &BAZ[7], 8, 16, 0, 1 }, -{ "ТАБСТ", &TABST, 8, 28, 0, 1, NULL, NULL, REG_HIDDEN },/* Таблица старшинства БРЗ */ -{ "ЗпТР", &FLUSH, 8, 4, 0, 1, NULL, NULL, REG_HIDDEN },/* Признак выталкивания БРЗ */ -{ "Старш", &OLDEST, 8, 3, 0, 1 }, /* Номер вытолкнутого БРЗ */ -{ "РП0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* Регистры приписки, по 12 бит */ -{ "РП1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РП7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, -{ "РЗ", &RZ, 8, 32, 0, 1 }, /* Регистр защиты */ -{ "ТР1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Тумблерные регистры */ -{ "ТР2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "ТР7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРС0", &BRS[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры слов */ -{ "БРС1", &BRS[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРС2", &BRS[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БРС3", &BRS[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, -{ "БАС0", &BAS[0], 8, 16, 0, 1 }, /* Буферные адреса слов */ -{ "БАС1", &BAS[1], 8, 16, 0, 1 }, -{ "БАС2", &BAS[2], 8, 16, 0, 1 }, -{ "БАС3", &BAS[3], 8, 16, 0, 1 }, -{ "БРСст", &BRSLRU, 8, 6, 0, 1, NULL, NULL, REG_HIDDEN}, -{ 0 } + { "БРЗ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры записи */ + { "БРЗ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРЗ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРЗ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРЗ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРЗ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРЗ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРЗ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БАЗ0", &BAZ[0], 8, 16, 0, 1 }, /* Буферные адреса записи */ + { "БАЗ1", &BAZ[1], 8, 16, 0, 1 }, + { "БАЗ2", &BAZ[2], 8, 16, 0, 1 }, + { "БАЗ3", &BAZ[3], 8, 16, 0, 1 }, + { "БАЗ4", &BAZ[4], 8, 16, 0, 1 }, + { "БАЗ5", &BAZ[5], 8, 16, 0, 1 }, + { "БАЗ6", &BAZ[6], 8, 16, 0, 1 }, + { "БАЗ7", &BAZ[7], 8, 16, 0, 1 }, + { "ТАБСТ", &TABST, 8, 28, 0, 1, NULL, NULL, REG_HIDDEN },/* Таблица старшинства БРЗ */ + { "ЗпТР", &FLUSH, 8, 4, 0, 1, NULL, NULL, REG_HIDDEN },/* Признак выталкивания БРЗ */ + { "Старш", &OLDEST, 8, 3, 0, 1 }, /* Номер вытолкнутого БРЗ */ + { "РП0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* Регистры приписки, по 12 бит */ + { "РП1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РП2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РП3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РП4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РП5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РП6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РП7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, + { "РЗ", &RZ, 8, 32, 0, 1 }, /* Регистр защиты */ + { "ТР1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Тумблерные регистры */ + { "ТР2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "ТР3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "ТР4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "ТР5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "ТР6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "ТР7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРС0", &BRS[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры слов */ + { "БРС1", &BRS[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРС2", &BRS[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БРС3", &BRS[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, + { "БАС0", &BAS[0], 8, 16, 0, 1 }, /* Буферные адреса слов */ + { "БАС1", &BAS[1], 8, 16, 0, 1 }, + { "БАС2", &BAS[2], 8, 16, 0, 1 }, + { "БАС3", &BAS[3], 8, 16, 0, 1 }, + { "БРСст", &BRSLRU, 8, 6, 0, 1, NULL, NULL, REG_HIDDEN}, + { 0 } }; #define CACHE_ENB 1 MTAB mmu_mod[] = { - { 1, 0, "NOCACHE", "NOCACHE" }, - { 1, 1, "CACHE", "CACHE" }, - { 0 } + { 1, 0, "NOCACHE", "NOCACHE" }, + { 1, 1, "CACHE", "CACHE" }, + { 0 } }; t_stat mmu_reset (DEVICE *dptr); t_stat mmu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { - mmu_print_brz(); - return SCPE_NOFNC; + mmu_print_brz(); + return SCPE_NOFNC; } DEVICE mmu_dev = { - "MMU", &mmu_unit, mmu_reg, mmu_mod, - 1, 8, 3, 1, 8, 50, - &mmu_examine, NULL, &mmu_reset, - NULL, NULL, NULL, NULL, - DEV_DEBUG + "MMU", &mmu_unit, mmu_reg, mmu_mod, + 1, 8, 3, 1, 8, 50, + &mmu_examine, NULL, &mmu_reset, + NULL, NULL, NULL, NULL, + DEV_DEBUG }; /* @@ -137,23 +137,23 @@ DEVICE mmu_dev = { */ t_stat mmu_reset (DEVICE *dptr) { - int i; - for (i = 0; i < 8; ++i) { - BRZ[i] = BAZ[i] = RP[i] = 0; - } - TABST = 0; - OLDEST = 0; - FLUSH = 0; - RZ = 0; - /* - * Front panel switches survive the reset - */ - sim_cancel (&mmu_unit); - return SCPE_OK; + int i; + for (i = 0; i < 8; ++i) { + BRZ[i] = BAZ[i] = RP[i] = 0; + } + TABST = 0; + OLDEST = 0; + FLUSH = 0; + RZ = 0; + /* + * Front panel switches survive the reset + */ + sim_cancel (&mmu_unit); + return SCPE_OK; } -#define loses_to_all(i) ((TABST & win_mask[i]) == 0 && \ - (TABST & lose_mask[i]) == lose_mask[i]) +#define loses_to_all(i) ((TABST & win_mask[i]) == 0 && \ + (TABST & lose_mask[i]) == lose_mask[i]) /* * N wins over M if the bit is set @@ -169,86 +169,86 @@ t_stat mmu_reset (DEVICE *dptr) */ static unsigned win_mask[8] = { - 0177, - 0077 << 7, - 0037 << 13, - 0017 << 18, - 0007 << 22, - 0003 << 25, - 0001 << 27, - 0 + 0177, + 0077 << 7, + 0037 << 13, + 0017 << 18, + 0007 << 22, + 0003 << 25, + 0001 << 27, + 0 }; static unsigned lose_mask[8] = { - 0, - 1<<0, - 1<<1|1<<7, - 1<<2|1<<8|1<<13, - 1<<3|1<<9|1<<14|1<<18, - 1<<4|1<<10|1<<15|1<<19|1<<22, - 1<<5|1<<11|1<<16|1<<20|1<<23|1<<25, - 1<<6|1<<12|1<<17|1<<21|1<<24|1<<26|1<<27 + 0, + 1<<0, + 1<<1|1<<7, + 1<<2|1<<8|1<<13, + 1<<3|1<<9|1<<14|1<<18, + 1<<4|1<<10|1<<15|1<<19|1<<22, + 1<<5|1<<11|1<<16|1<<20|1<<23|1<<25, + 1<<6|1<<12|1<<17|1<<21|1<<24|1<<26|1<<27 }; #define set_wins(i) TABST = (TABST & ~lose_mask[i]) | win_mask[i] void mmu_protection_check (int addr) { - /* Защита блокируется в режиме супервизора для физических (!) адресов 1-7 (ТО-8) - WTF? */ - int tmp_prot_disabled = (M[PSW] & PSW_PROT_DISABLE) || - (IS_SUPERVISOR (RUU) && (M[PSW] & PSW_MMAP_DISABLE) && addr < 010); + /* Защита блокируется в режиме супервизора для физических (!) адресов 1-7 (ТО-8) - WTF? */ + int tmp_prot_disabled = (M[PSW] & PSW_PROT_DISABLE) || + (IS_SUPERVISOR (RUU) && (M[PSW] & PSW_MMAP_DISABLE) && addr < 010); - /* Защита не заблокирована, а лист закрыт */ - if (! tmp_prot_disabled && (RZ & (1 << (addr >> 10)))) { - iintr_data = addr >> 10; - if (mmu_dev.dctrl) - besm6_debug ("--- (%05o) защита числа", addr); - longjmp (cpu_halt, STOP_OPERAND_PROT); - } + /* Защита не заблокирована, а лист закрыт */ + if (! tmp_prot_disabled && (RZ & (1 << (addr >> 10)))) { + iintr_data = addr >> 10; + if (mmu_dev.dctrl) + besm6_debug ("--- (%05o) защита числа", addr); + longjmp (cpu_halt, STOP_OPERAND_PROT); + } } void mmu_flush (int idx) { - if (! BAZ[idx]) { - /* Был пуст после сброса или выталкивания */ - return; - } - /* Вычисляем физический адрес выталкиваемого БРЗ */ - int waddr = BAZ[idx]; - waddr = (waddr > 0100000) ? (waddr - 0100000) : - (waddr & 01777) | (TLB[waddr >> 10] << 10); - memory[waddr] = BRZ[idx]; - BAZ[idx] = 0; - if (sim_log && mmu_dev.dctrl) { - fprintf (sim_log, "--- (%05o) запись ", waddr); - fprint_sym (sim_log, 0, &BRZ[idx], 0, 0); - fprintf (sim_log, " из БРЗ[%d]\n", idx); - } + if (! BAZ[idx]) { + /* Был пуст после сброса или выталкивания */ + return; + } + /* Вычисляем физический адрес выталкиваемого БРЗ */ + int waddr = BAZ[idx]; + waddr = (waddr > 0100000) ? (waddr - 0100000) : + (waddr & 01777) | (TLB[waddr >> 10] << 10); + memory[waddr] = BRZ[idx]; + BAZ[idx] = 0; + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) запись ", waddr); + fprint_sym (sim_log, 0, &BRZ[idx], 0, 0); + fprintf (sim_log, " из БРЗ[%d]\n", idx); + } } void mmu_update_oldest () { - int i; + int i; - for (i = 0; i < 8; ++i) { - if (loses_to_all(i)) { - OLDEST = i; - // fprintf(stderr, "Oldest = %d\r\n", i); - return; - } - } + for (i = 0; i < 8; ++i) { + if (loses_to_all(i)) { + OLDEST = i; + // fprintf(stderr, "Oldest = %d\r\n", i); + return; + } + } } int mmu_match (int addr, int fail) { - int i; + int i; - for (i = 0; i < 8; ++i) { - if (addr == BAZ[i]) { - return i; - } - } - return fail; + for (i = 0; i < 8; ++i) { + if (addr == BAZ[i]) { + return i; + } + } + return fail; } /* @@ -258,39 +258,39 @@ int mmu_match (int addr, int fail) */ void mmu_flush_by_age() { - switch (FLUSH) { - case 0: - break; - case 1 ... 8: - set_wins (OLDEST); - mmu_update_oldest (); - mmu_flush (OLDEST); - if (FLUSH == 7) { - TABST = 0; - OLDEST = 0; - } - break; - } - ++FLUSH; + switch (FLUSH) { + case 0: + break; + case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: + set_wins (OLDEST); + mmu_update_oldest (); + mmu_flush (OLDEST); + if (FLUSH == 7) { + TABST = 0; + OLDEST = 0; + } + break; + } + ++FLUSH; } void mmu_flush_by_number() { - switch (FLUSH) { - case 0: - break; - case 1 ... 8: - mmu_flush (FLUSH-1); - set_wins (FLUSH-1); - if (FLUSH-1 == OLDEST) - mmu_update_oldest (); - if (FLUSH == 7) { - TABST = 0; - OLDEST = 0; - } - break; - } - ++FLUSH; + switch (FLUSH) { + case 0: + break; + case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: + mmu_flush (FLUSH-1); + set_wins (FLUSH-1); + if (FLUSH-1 == OLDEST) + mmu_update_oldest (); + if (FLUSH == 7) { + TABST = 0; + OLDEST = 0; + } + break; + } + ++FLUSH; } /* @@ -298,92 +298,92 @@ void mmu_flush_by_number() */ void mmu_store (int addr, t_value val) { - int matching; + int matching; - addr &= BITS(15); - if (addr == 0) - return; - if (sim_log && mmu_dev.dctrl) { - fprintf (sim_log, "--- (%05o) запись ", addr); - fprint_sym (sim_log, 0, &val, 0, 0); - fprintf (sim_log, "\n"); - } + addr &= BITS(15); + if (addr == 0) + return; + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) запись ", addr); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, "\n"); + } - mmu_protection_check (addr); + mmu_protection_check (addr); - /* Различаем адреса с припиской и без */ - if (M[PSW] & PSW_MMAP_DISABLE) - addr |= 0100000; + /* Различаем адреса с припиской и без */ + if (M[PSW] & PSW_MMAP_DISABLE) + addr |= 0100000; - /* ЗПСЧ: ЗП */ - if (M[DWP] == addr && (M[PSW] & PSW_WRITE_WATCH)) - longjmp(cpu_halt, STOP_STORE_ADDR_MATCH); + /* ЗПСЧ: ЗП */ + if (M[DWP] == addr && (M[PSW] & PSW_WRITE_WATCH)) + longjmp(cpu_halt, STOP_STORE_ADDR_MATCH); - if (sim_brk_summ & SWMASK('W') && - sim_brk_test (addr, SWMASK('W'))) - longjmp(cpu_halt, STOP_WWATCH); + if (sim_brk_summ & SWMASK('W') && + sim_brk_test (addr, SWMASK('W'))) + longjmp(cpu_halt, STOP_WWATCH); - if (!(mmu_unit.flags & CACHE_ENB)) { - static int roundrobin; - int faked = (++roundrobin ^ addr ^ val) & 7; + if (!(mmu_unit.flags & CACHE_ENB)) { + static int roundrobin; + int faked = (++roundrobin ^ addr ^ val) & 7; - if (addr > 0100000 && addr < 0100010) - return; + if (addr > 0100000 && addr < 0100010) + return; - BRZ[faked] = SET_CONVOL (val, RUU ^ CONVOL_INSN); - BAZ[faked] = addr; - mmu_flush (faked); - return; - } + BRZ[faked] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BAZ[faked] = addr; + mmu_flush (faked); + return; + } - /* Запись в тумблерные регистры - выталкивание БРЗ */ - if (addr > 0100000 && addr < 0100010) { - mmu_flush_by_age(); - return; - } else - FLUSH = 0; + /* Запись в тумблерные регистры - выталкивание БРЗ */ + if (addr > 0100000 && addr < 0100010) { + mmu_flush_by_age(); + return; + } else + FLUSH = 0; - matching = mmu_match(addr, OLDEST); + matching = mmu_match(addr, OLDEST); - BRZ[matching] = SET_CONVOL (val, RUU ^ CONVOL_INSN); - BAZ[matching] = addr; - set_wins (matching); + BRZ[matching] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BAZ[matching] = addr; + set_wins (matching); - if (matching == OLDEST) { - mmu_update_oldest (); - mmu_flush (OLDEST); - } + if (matching == OLDEST) { + mmu_update_oldest (); + mmu_flush (OLDEST); + } } t_value mmu_memaccess (int addr) { - t_value val; + t_value val; - /* Вычисляем физический адрес слова */ - addr = (addr > 0100000) ? (addr - 0100000) : - (addr & 01777) | (TLB[addr >> 10] << 10); - if (addr >= 010) { - /* Из памяти */ - val = memory[addr]; - } else { - /* С тумблерных регистров */ - if (mmu_dev.dctrl) - besm6_debug("--- (%05o) чтение ТР%o", PC, addr); - val = pult[addr]; - } - if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { - fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); - fprint_sym (sim_log, 0, &val, 0, 0); - fprintf (sim_log, "\n"); - } + /* Вычисляем физический адрес слова */ + addr = (addr > 0100000) ? (addr - 0100000) : + (addr & 01777) | (TLB[addr >> 10] << 10); + if (addr >= 010) { + /* Из памяти */ + val = memory[addr]; + } else { + /* С тумблерных регистров */ + if (mmu_dev.dctrl) + besm6_debug("--- (%05o) чтение ТР%o", PC, addr); + val = pult[addr]; + } + if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { + fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, "\n"); + } - /* На тумблерных регистрах контроля числа не бывает */ - if (addr >= 010 && ! IS_NUMBER (val)) { - iintr_data = addr & 7; - besm6_debug ("--- (%05o) контроль числа", addr); - longjmp (cpu_halt, STOP_RAM_CHECK); - } - return val; + /* На тумблерных регистрах контроля числа не бывает */ + if (addr >= 010 && ! IS_NUMBER (val)) { + iintr_data = addr & 7; + besm6_debug ("--- (%05o) контроль числа", addr); + longjmp (cpu_halt, STOP_RAM_CHECK); + } + return val; } /* @@ -391,59 +391,59 @@ t_value mmu_memaccess (int addr) */ t_value mmu_load (int addr) { - int matching = -1; - t_value val; + int matching = -1; + t_value val; - addr &= BITS(15); - if (addr == 0) - return 0; + addr &= BITS(15); + if (addr == 0) + return 0; - mmu_protection_check (addr); + mmu_protection_check (addr); - /* Различаем адреса с припиской и без */ - if (M[PSW] & PSW_MMAP_DISABLE) - addr |= 0100000; + /* Различаем адреса с припиской и без */ + if (M[PSW] & PSW_MMAP_DISABLE) + addr |= 0100000; - /* ЗПСЧ: СЧ */ - if (M[DWP] == addr && !(M[PSW] & PSW_WRITE_WATCH)) - longjmp(cpu_halt, STOP_LOAD_ADDR_MATCH); + /* ЗПСЧ: СЧ */ + if (M[DWP] == addr && !(M[PSW] & PSW_WRITE_WATCH)) + longjmp(cpu_halt, STOP_LOAD_ADDR_MATCH); - if (sim_brk_summ & SWMASK('R') && - sim_brk_test (addr, SWMASK('R'))) - longjmp(cpu_halt, STOP_RWATCH); + if (sim_brk_summ & SWMASK('R') && + sim_brk_test (addr, SWMASK('R'))) + longjmp(cpu_halt, STOP_RWATCH); - if (!(mmu_unit.flags & CACHE_ENB)) { - return mmu_memaccess (addr) & BITS48; - } + if (!(mmu_unit.flags & CACHE_ENB)) { + return mmu_memaccess (addr) & BITS48; + } - matching = mmu_match(addr, -1); + matching = mmu_match(addr, -1); - if (matching == -1) { - val = mmu_memaccess (addr); - } else { - /* старшинство обновляется, только если оно не затрагивает - * старший БРЗ (ТО-2). - */ - if (matching != OLDEST) - set_wins (matching); - val = BRZ[matching]; - if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { - fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); - fprint_sym (sim_log, 0, &val, 0, 0); - fprintf (sim_log, " из БРЗ\n"); - } - if (! IS_NUMBER (val)) { - iintr_data = matching; - besm6_debug ("--- (%05o) контроль числа БРЗ", addr); - longjmp (cpu_halt, STOP_CACHE_CHECK); - } - } - return val & BITS48; + if (matching == -1) { + val = mmu_memaccess (addr); + } else { + /* старшинство обновляется, только если оно не затрагивает + * старший БРЗ (ТО-2). + */ + if (matching != OLDEST) + set_wins (matching); + val = BRZ[matching]; + if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) { + fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15)); + fprint_sym (sim_log, 0, &val, 0, 0); + fprintf (sim_log, " из БРЗ\n"); + } + if (! IS_NUMBER (val)) { + iintr_data = matching; + besm6_debug ("--- (%05o) контроль числа БРЗ", addr); + longjmp (cpu_halt, STOP_CACHE_CHECK); + } + } + return val & BITS48; } /* A little BRS LRU table */ -#define brs_loses_to_all(i) ((BRSLRU & brs_win_mask[i]) == 0 && \ - (BRSLRU & brs_lose_mask[i]) == brs_lose_mask[i]) +#define brs_loses_to_all(i) ((BRSLRU & brs_win_mask[i]) == 0 && \ + (BRSLRU & brs_lose_mask[i]) == brs_lose_mask[i]) /* * N wins over M if the bit is set @@ -455,37 +455,37 @@ t_value mmu_load (int addr) */ static unsigned brs_win_mask[4] = { - 07, - 03 << 3, - 01 << 5, - 0 + 07, + 03 << 3, + 01 << 5, + 0 }; static unsigned brs_lose_mask[8] = { - 0, - 1<<0, - 1<<1|1<<3, - 1<<2|1<<4|1<<5 + 0, + 1<<0, + 1<<1|1<<3, + 1<<2|1<<4|1<<5 }; #define brs_set_wins(i) BRSLRU = (BRSLRU & ~brs_lose_mask[i]) | brs_win_mask[i] void mmu_fetch_check (int addr) { - /* В режиме супервизора защиты нет */ - if (! IS_SUPERVISOR(RUU)) { - int page = TLB[addr >> 10]; - /* - * Для команд в режиме пользователя признак защиты - - * 0 в регистре приписки. - */ - if (page == 0) { - iintr_data = addr >> 10; - if (mmu_dev.dctrl) - besm6_debug ("--- (%05o) защита команды", addr); - longjmp (cpu_halt, STOP_INSN_PROT); - } - } + /* В режиме супервизора защиты нет */ + if (! IS_SUPERVISOR(RUU)) { + int page = TLB[addr >> 10]; + /* + * Для команд в режиме пользователя признак защиты - + * 0 в регистре приписки. + */ + if (page == 0) { + iintr_data = addr >> 10; + if (mmu_dev.dctrl) + besm6_debug ("--- (%05o) защита команды", addr); + longjmp (cpu_halt, STOP_INSN_PROT); + } + } } /* @@ -493,50 +493,50 @@ void mmu_fetch_check (int addr) */ t_value mmu_prefetch (int addr, int actual) { - t_value val; - int i; + t_value val; + int i; - if (mmu_unit.flags & CACHE_ENB) { - for (i = 0; i < 4; ++i) { - if (BAS[i] == addr) { - if (actual) { - brs_set_wins (i); - } - return BRS[i]; - } - } + if (mmu_unit.flags & CACHE_ENB) { + for (i = 0; i < 4; ++i) { + if (BAS[i] == addr) { + if (actual) { + brs_set_wins (i); + } + return BRS[i]; + } + } - for (i = 0; i < 4; ++i) { - if (brs_loses_to_all (i)) { - BAS[i] = addr; - if (actual) { - brs_set_wins (i); - } - break; - } - } - } else if (!actual) { - return 0; - } else { - /* Чтобы лампочки мигали */ - i = addr & 3; - } + for (i = 0; i < 4; ++i) { + if (brs_loses_to_all (i)) { + BAS[i] = addr; + if (actual) { + brs_set_wins (i); + } + break; + } + } + } else if (!actual) { + return 0; + } else { + /* Чтобы лампочки мигали */ + i = addr & 3; + } - if (addr < 0100000) { - int page = TLB[addr >> 10]; + if (addr < 0100000) { + int page = TLB[addr >> 10]; - /* Вычисляем физический адрес слова */ - addr = (addr & 01777) | (page << 10); - } else { - addr = addr & BITS(15); - } + /* Вычисляем физический адрес слова */ + addr = (addr & 01777) | (page << 10); + } else { + addr = addr & BITS(15); + } - if (addr < 010) - val = pult[addr]; - else - val = memory[addr]; - BRS[i] = val; - return val; + if (addr < 010) + val = pult[addr]; + else + val = memory[addr]; + BRS[i] = val; + return val; } /* @@ -544,109 +544,109 @@ t_value mmu_prefetch (int addr, int actual) */ t_value mmu_fetch (int addr) { - t_value val; + t_value val; - if (addr == 0) { - if (mmu_dev.dctrl) - besm6_debug ("--- передача управления на 0"); - longjmp (cpu_halt, STOP_INSN_CHECK); - } + if (addr == 0) { + if (mmu_dev.dctrl) + besm6_debug ("--- передача управления на 0"); + longjmp (cpu_halt, STOP_INSN_CHECK); + } - mmu_fetch_check(addr); + mmu_fetch_check(addr); - /* Различаем адреса с припиской и без */ - if (IS_SUPERVISOR (RUU)) - addr |= 0100000; + /* Различаем адреса с припиской и без */ + if (IS_SUPERVISOR (RUU)) + addr |= 0100000; - /* КРА */ - if (M[IBP] == addr) - longjmp(cpu_halt, STOP_INSN_ADDR_MATCH); + /* КРА */ + if (M[IBP] == addr) + longjmp(cpu_halt, STOP_INSN_ADDR_MATCH); - val = mmu_prefetch(addr, 1); + val = mmu_prefetch(addr, 1); - if (sim_log && mmu_dev.dctrl) { - fprintf (sim_log, "--- (%05o) выборка ", addr); - fprint_sym (sim_log, 0, &val, 0, SWMASK ('I')); - fprintf (sim_log, "\n"); - } + if (sim_log && mmu_dev.dctrl) { + fprintf (sim_log, "--- (%05o) выборка ", addr); + fprint_sym (sim_log, 0, &val, 0, SWMASK ('I')); + fprintf (sim_log, "\n"); + } - /* Тумблерные регистры пока только с командной сверткой */ - if (addr >= 010 && ! IS_INSN (val)) { - besm6_debug ("--- (%05o) контроль команды", addr); - longjmp (cpu_halt, STOP_INSN_CHECK); - } - return val & BITS48; + /* Тумблерные регистры пока только с командной сверткой */ + if (addr >= 010 && ! IS_INSN (val)) { + besm6_debug ("--- (%05o) контроль команды", addr); + longjmp (cpu_halt, STOP_INSN_CHECK); + } + return val & BITS48; } void mmu_setrp (int idx, t_value val) { - uint32 p0, p1, p2, p3; - const uint32 mask = (MEMSIZE >> 10) - 1; + uint32 p0, p1, p2, p3; + const uint32 mask = (MEMSIZE >> 10) - 1; - /* Младшие 5 разрядов 4-х регистров приписки упакованы - * по 5 в 1-20 рр, 6-е разряды - в 29-32 рр, 7-е разряды - в 33-36 рр и т.п. - */ - p0 = (val & 037) | (((val>>28) & 1) << 5) | (((val>>32) & 1) << 6) | - (((val>>36) & 1) << 7) | (((val>>40) & 1) << 8) | (((val>>44) & 1) << 9); - p1 = ((val>>5) & 037) | (((val>>29) & 1) << 5) | (((val>>33) & 1) << 6) | - (((val>>37) & 1) << 7) | (((val>>41) & 1) << 8) | (((val>>45) & 1) << 9); - p2 = ((val>>10) & 037) | (((val>>30) & 1) << 5) | (((val>>34) & 1) << 6) | - (((val>>38) & 1) << 7) | (((val>>42) & 1) << 8) | (((val>>46) & 1) << 9); - p3 = ((val>>15) & 037) | (((val>>31) & 1) << 5) | (((val>>35) & 1) << 6) | - (((val>>39) & 1) << 7) | (((val>>43) & 1) << 8) | (((val>>47) & 1) << 9); + /* Младшие 5 разрядов 4-х регистров приписки упакованы + * по 5 в 1-20 рр, 6-е разряды - в 29-32 рр, 7-е разряды - в 33-36 рр и т.п. + */ + p0 = (val & 037) | (((val>>28) & 1) << 5) | (((val>>32) & 1) << 6) | + (((val>>36) & 1) << 7) | (((val>>40) & 1) << 8) | (((val>>44) & 1) << 9); + p1 = ((val>>5) & 037) | (((val>>29) & 1) << 5) | (((val>>33) & 1) << 6) | + (((val>>37) & 1) << 7) | (((val>>41) & 1) << 8) | (((val>>45) & 1) << 9); + p2 = ((val>>10) & 037) | (((val>>30) & 1) << 5) | (((val>>34) & 1) << 6) | + (((val>>38) & 1) << 7) | (((val>>42) & 1) << 8) | (((val>>46) & 1) << 9); + p3 = ((val>>15) & 037) | (((val>>31) & 1) << 5) | (((val>>35) & 1) << 6) | + (((val>>39) & 1) << 7) | (((val>>43) & 1) << 8) | (((val>>47) & 1) << 9); - p0 &= mask; - p1 &= mask; - p2 &= mask; - p3 &= mask; + p0 &= mask; + p1 &= mask; + p2 &= mask; + p3 &= mask; - RP[idx] = p0 | p1 << 12 | p2 << 24 | (t_value) p3 << 36; - TLB[idx*4] = p0; - TLB[idx*4+1] = p1; - TLB[idx*4+2] = p2; - TLB[idx*4+3] = p3; + RP[idx] = p0 | p1 << 12 | p2 << 24 | (t_value) p3 << 36; + TLB[idx*4] = p0; + TLB[idx*4+1] = p1; + TLB[idx*4+2] = p2; + TLB[idx*4+3] = p3; } void mmu_setup () { - const uint32 mask = (MEMSIZE >> 10) - 1; - int i; + const uint32 mask = (MEMSIZE >> 10) - 1; + int i; - /* Перепись РПi в TLBj. */ - for (i=0; i<8; ++i) { - TLB[i*4] = RP[i] & mask; - TLB[i*4+1] = RP[i] >> 12 & mask; - TLB[i*4+2] = RP[i] >> 24 & mask; - TLB[i*4+3] = RP[i] >> 36 & mask; - } + /* Перепись РПi в TLBj. */ + for (i=0; i<8; ++i) { + TLB[i*4] = RP[i] & mask; + TLB[i*4+1] = RP[i] >> 12 & mask; + TLB[i*4+2] = RP[i] >> 24 & mask; + TLB[i*4+3] = RP[i] >> 36 & mask; + } } void mmu_setprotection (int idx, t_value val) { - /* Разряды сумматора, записываемые в регистр защиты - 21-28 */ - int mask = 0xff << (idx * 8); - val = ((val >> 20) & 0xff) << (idx * 8); - RZ = (RZ & ~mask) | val; + /* Разряды сумматора, записываемые в регистр защиты - 21-28 */ + int mask = 0xff << (idx * 8); + val = ((val >> 20) & 0xff) << (idx * 8); + RZ = (RZ & ~mask) | val; } void mmu_setcache (int idx, t_value val) { - BRZ[idx] = SET_CONVOL (val, RUU ^ CONVOL_INSN); + BRZ[idx] = SET_CONVOL (val, RUU ^ CONVOL_INSN); } t_value mmu_getcache (int idx) { - return BRZ[idx] & BITS48; + return BRZ[idx] & BITS48; } void mmu_print_brz () { - int i, k; + int i, k; - for (i=7; i>=0; --i) { - besm6_log_cont ("БРЗ [%d] = '", i); - for (k=47; k>=0; --k) - besm6_log_cont ("%c", (BRZ[i] >> k & 1) ? '*' : ' '); - besm6_log ("'"); - } + for (i=7; i>=0; --i) { + besm6_log_cont ("БРЗ [%d] = '", i); + for (k=47; k>=0; --k) + besm6_log_cont ("%c", (BRZ[i] >> k & 1) ? '*' : ' '); + besm6_log ("'"); + } } diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c index 6b673ab1..e2bc2e73 100644 --- a/BESM6/besm6_panel.c +++ b/BESM6/besm6_panel.c @@ -37,17 +37,17 @@ /* * Use a 640x480 window with 32 bit pixels. */ -#define WIDTH 800 -#define HEIGHT 400 -#define DEPTH 32 +#define WIDTH 800 +#define HEIGHT 400 +#define DEPTH 32 -#define STEPX 14 -#define STEPY 16 +#define STEPX 14 +#define STEPY 16 -#define FONTNAME "LucidaSansRegular.ttf" -#define FONTPATH1 "/usr/share/fonts" -#define FONTPATH2 "/usr/lib/jvm" -#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions" +#define FONTNAME "LucidaSansRegular.ttf" +#define FONTPATH1 "/usr/share/fonts" +#define FONTPATH2 "/usr/lib/jvm" +#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions" #include #include @@ -66,8 +66,8 @@ static t_value old_BRZ [8], old_GRP [2]; static t_value old_M [NREGS]; static const int regnum[] = { - 013, 012, 011, 010, 7, 6, 5, 4, - 027, 016, 015, 014, 3, 2, 1, 020, + 013, 012, 011, 010, 7, 6, 5, 4, + 027, 016, 015, 014, 3, 2, 1, 020, }; static SDL_Surface *screen; @@ -79,51 +79,51 @@ static SDL_Surface *screen; */ static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message) { - SDL_Surface *text; - SDL_Rect area; + SDL_Surface *text; + SDL_Rect area; - /* Build image from text */ - text = TTF_RenderUTF8_Shaded (font, message, foreground, background); + /* Build image from text */ + text = TTF_RenderUTF8_Shaded (font, message, foreground, background); - area.x = x; - if (halign < 0) - area.x -= text->w; /* align left */ - else if (halign == 0) - area.x -= text->w / 2; /* center */ - area.y = y; - area.w = text->w; - area.h = text->h; + area.x = x; + if (halign < 0) + area.x -= text->w; /* align left */ + else if (halign == 0) + area.x -= text->w / 2; /* center */ + area.y = y; + area.w = text->w; + area.h = text->h; - /* Put text image to screen */ - SDL_BlitSurface (text, 0, screen, &area); - SDL_FreeSurface (text); + /* Put text image to screen */ + SDL_BlitSurface (text, 0, screen, &area); + SDL_FreeSurface (text); } static SDL_Surface *sprite_from_data (int width, int height, - const unsigned char *data) + const unsigned char *data) { - SDL_Surface *sprite, *optimized; - unsigned *s, r, g, b, y, x; + SDL_Surface *sprite, *optimized; + unsigned *s, r, g, b, y, x; - sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, - width, height, DEPTH, 0, 0, 0, 0); - /* - optimized = SDL_DisplayFormat (sprite); - SDL_FreeSurface (sprite); - sprite = optimized; - */ - SDL_LockSurface (sprite); - for (y=0; ypixels + y * sprite->pitch); - for (x=0; xformat, r, g, b); - } - } - SDL_UnlockSurface (sprite); - return sprite; + sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, + width, height, DEPTH, 0, 0, 0, 0); + /* + optimized = SDL_DisplayFormat (sprite); + SDL_FreeSurface (sprite); + sprite = optimized; + */ + SDL_LockSurface (sprite); + for (y=0; ypixels + y * sprite->pitch); + for (x=0; xformat, r, g, b); + } + } + SDL_UnlockSurface (sprite); + return sprite; } /* @@ -131,54 +131,54 @@ static SDL_Surface *sprite_from_data (int width, int height, */ static void draw_lamp (int left, int top, int on) { - /* Images created by GIMP: save as C file without alpha channel. */ - static const int lamp_width = 12; - static const int lamp_height = 12; - static const unsigned char lamp_on [12 * 12 * 3 + 1] = - "\0\0\0\0\0\0\0\0\0\13\2\2-\14\14e\31\31e\31\31-\14\14\13\2\2\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0D\20\20\313,,\377??\377CC\377CC\377DD\31333D\21\21\0\0" - "\0\0\0\0\0\0\0D\20\20\357LL\377\243\243\376~~\37699\376@@\376@@\377AA\357" - "<>\377@@\377@@\377AA\31333\13\2\2-\14\14\377??\376~~\377\356\356\377\321" - "\321\377<<\377??\377@@\377@@\376@@\377DD-\14\14e\31\31\377CC\37699\377NN" - "\377<<\377??\377@@\377@@\377@@\376??\377CCe\31\31e\31\31\377CC\376@@\377" - ">>\377??\377@@\377@@\377@@\377@@\376??\377CCe\31\31-\14\14\377DD\376@@\377" - "@@\377@@\377@@\377@@\377@@\377@@\376@@\377DD-\14\14\13\2\2\31333\377AA\377" - "@@\377@@\377@@\377@@\377@@\377@@\377AA\31333\13\2\2\0\0\0D\21\21\357<<\377" - "AA\376@@\376??\376??\376@@\377AA\357<>\377@@\377@@\377AA\31333\13\2\2-\14\14\377??\376~~\377\356\356\377\321" + "\321\377<<\377??\377@@\377@@\376@@\377DD-\14\14e\31\31\377CC\37699\377NN" + "\377<<\377??\377@@\377@@\377@@\376??\377CCe\31\31e\31\31\377CC\376@@\377" + ">>\377??\377@@\377@@\377@@\377@@\376??\377CCe\31\31-\14\14\377DD\376@@\377" + "@@\377@@\377@@\377@@\377@@\377@@\376@@\377DD-\14\14\13\2\2\31333\377AA\377" + "@@\377@@\377@@\377@@\377@@\377@@\377AA\31333\13\2\2\0\0\0D\21\21\357<<\377" + "AA\376@@\376??\376??\376@@\377AA\357<> (14-x) & 1); - } - } + for (y=0; y<8; ++y) { + reg = regnum [y + group*8]; + val = M [reg]; + if (val == old_M [reg]) + continue; + old_M [reg] = val; + for (x=0; x<15; ++x) { + draw_lamp (left+76 + x*STEPX, top+28 + y*STEPY, val >> (14-x) & 1); + } + } } /* @@ -205,18 +205,18 @@ static void draw_modifiers_periodic (int group, int left, int top) */ static void draw_grp_periodic (int top) { - int x, y; - t_value val; + int x, y; + t_value val; - for (y=0; y<2; ++y) { - val = y ? MGRP : GRP; - if (val == old_GRP [y]) - continue; - old_GRP [y] = val; - for (x=0; x<48; ++x) { - draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); - } - } + for (y=0; y<2; ++y) { + val = y ? MGRP : GRP; + if (val == old_GRP [y]) + continue; + old_GRP [y] = val; + for (x=0; x<48; ++x) { + draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); + } + } } /* @@ -224,18 +224,18 @@ static void draw_grp_periodic (int top) */ static void draw_brz_periodic (int top) { - int x, y; - t_value val; + int x, y; + t_value val; - for (y=0; y<8; ++y) { - val = BRZ [7-y]; - if (val == old_BRZ [7-y]) - continue; - old_BRZ [7-y] = val; - for (x=0; x<48; ++x) { - draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); - } - } + for (y=0; y<8; ++y) { + val = BRZ [7-y]; + if (val == old_BRZ [7-y]) + continue; + old_BRZ [7-y] = val; + for (x=0; x<48; ++x) { + draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1); + } + } } /* @@ -243,35 +243,35 @@ static void draw_brz_periodic (int top) */ static void draw_modifiers_static (int group, int left, int top) { - int x, y, color, reg; - char message [40]; - SDL_Rect area; + int x, y, color, reg; + char message [40]; + SDL_Rect area; - background = black; - foreground = cyan; + background = black; + foreground = cyan; - /* Оттеняем группы разрядов. */ - color = grey.r << 16 | grey.g << 8 | grey.b; - for (x=3; x<15; x+=3) { - area.x = left + 74 + x*STEPX; - area.y = top + 26; - area.w = 2; - area.h = 8*STEPY + 2; - SDL_FillRect (screen, &area, color); - } - /* Названия регистров. */ - for (y=0; y<8; ++y) { - reg = regnum [y + group*8]; - sprintf (message, "М%2o", reg); - render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message); - old_M [reg] = ~0; - } - /* Номера битов. */ - for (x=0; x<15; ++x) { - sprintf (message, "%d", 15-x); - render_utf8 (font_small, left+82 + x*STEPX, - (x & 1) ? top+4 : top+10, 0, message); - } + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<15; x+=3) { + area.x = left + 74 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 8*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=0; y<8; ++y) { + reg = regnum [y + group*8]; + sprintf (message, "М%2o", reg); + render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message); + old_M [reg] = ~0; + } + /* Номера битов. */ + for (x=0; x<15; ++x) { + sprintf (message, "%d", 15-x); + render_utf8 (font_small, left+82 + x*STEPX, + (x & 1) ? top+4 : top+10, 0, message); + } } /* @@ -279,33 +279,33 @@ static void draw_modifiers_static (int group, int left, int top) */ static void draw_grp_static (int top) { - int x, y, color; - char message [40]; - SDL_Rect area; + int x, y, color; + char message [40]; + SDL_Rect area; - background = black; - foreground = cyan; + background = black; + foreground = cyan; - /* Оттеняем группы разрядов. */ - color = grey.r << 16 | grey.g << 8 | grey.b; - for (x=3; x<48; x+=3) { - area.x = 98 + x*STEPX; - area.y = top + 26; - area.w = 2; - area.h = 2*STEPY + 2; - SDL_FillRect (screen, &area, color); - } - /* Названия регистров. */ - for (y=0; y<2; ++y) { - render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП"); - old_GRP[y] = ~0; - } - /* Номера битов. */ - for (x=0; x<48; ++x) { - sprintf (message, "%d", 48-x); - render_utf8 (font_small, 106 + x*STEPX, - (x & 1) ? top+10 : top+4, 0, message); - } + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<48; x+=3) { + area.x = 98 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 2*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=0; y<2; ++y) { + render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП"); + old_GRP[y] = ~0; + } + /* Номера битов. */ + for (x=0; x<48; ++x) { + sprintf (message, "%d", 48-x); + render_utf8 (font_small, 106 + x*STEPX, + (x & 1) ? top+10 : top+4, 0, message); + } } /* @@ -313,28 +313,28 @@ static void draw_grp_static (int top) */ static void draw_brz_static (int top) { - int x, y, color; - char message [40]; - SDL_Rect area; + int x, y, color; + char message [40]; + SDL_Rect area; - background = black; - foreground = cyan; + background = black; + foreground = cyan; - /* Оттеняем группы разрядов. */ - color = grey.r << 16 | grey.g << 8 | grey.b; - for (x=3; x<48; x+=3) { - area.x = 98 + x*STEPX; - area.y = top + 26; - area.w = 2; - area.h = 8*STEPY + 2; - SDL_FillRect (screen, &area, color); - } - /* Названия регистров. */ - for (y=7; y>=0; --y) { - sprintf (message, "БРЗ %d", 7-y); - render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message); - old_BRZ[y] = ~0; - } + /* Оттеняем группы разрядов. */ + color = grey.r << 16 | grey.g << 8 | grey.b; + for (x=3; x<48; x+=3) { + area.x = 98 + x*STEPX; + area.y = top + 26; + area.w = 2; + area.h = 8*STEPY + 2; + SDL_FillRect (screen, &area, color); + } + /* Названия регистров. */ + for (y=7; y>=0; --y) { + sprintf (message, "БРЗ %d", 7-y); + render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message); + old_BRZ[y] = ~0; + } } /* @@ -342,15 +342,15 @@ static void draw_brz_static (int top) */ static int probe_font (const char *path, const struct stat *st, int flag) { - const char *p; + const char *p; - if (flag != FTW_F) - return 0; - p = path + strlen (path) - strlen (FONTNAME); - if (p < path || strcmp (p, FONTNAME) != 0) - return 0; - font_path = strdup (path); - return 1; + if (flag != FTW_F) + return 0; + p = path + strlen (path) - strlen (FONTNAME); + if (p < path || strcmp (p, FONTNAME) != 0) + return 0; + font_path = strdup (path); + return 1; } /* @@ -358,11 +358,11 @@ static int probe_font (const char *path, const struct stat *st, int flag) */ void besm6_close_panel () { - if (! screen) - return; - TTF_Quit(); - SDL_Quit(); - screen = 0; + if (! screen) + return; + TTF_Quit(); + SDL_Quit(); + screen = 0; } #if SDL_MAJOR_VERSION == 2 @@ -377,81 +377,81 @@ static SDL_Texture *sdlTexture; */ static void init_panel () { - if (sim_switches & SWMASK('Q')) - return; + if (sim_switches & SWMASK('Q')) + return; - /* Initialize SDL subsystems - in this case, only video. */ - if (SDL_Init (SDL_INIT_VIDEO) < 0) { - fprintf (stderr, "SDL: unable to init: %s\n", - SDL_GetError ()); - exit (1); - } - sdlWindow = SDL_CreateWindow ("BESM-6 panel", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - WIDTH, HEIGHT, 0 /* regular window */); - if (! sdlWindow) { - fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", - WIDTH, HEIGHT, DEPTH, SDL_GetError ()); - exit (1); - } + /* Initialize SDL subsystems - in this case, only video. */ + if (SDL_Init (SDL_INIT_VIDEO) < 0) { + fprintf (stderr, "SDL: unable to init: %s\n", + SDL_GetError ()); + exit (1); + } + sdlWindow = SDL_CreateWindow ("BESM-6 panel", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + WIDTH, HEIGHT, 0 /* regular window */); + if (! sdlWindow) { + fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", + WIDTH, HEIGHT, DEPTH, SDL_GetError ()); + exit (1); + } - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); - /* Make black background */ - SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); - SDL_RenderClear(sdlRenderer); + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); + /* Make black background */ + SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); + SDL_RenderClear(sdlRenderer); - /* Initialize the TTF library */ - if (TTF_Init() < 0) { - fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", - SDL_GetError()); - SDL_Quit(); - exit (1); - } + /* Initialize the TTF library */ + if (TTF_Init() < 0) { + fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", + SDL_GetError()); + SDL_Quit(); + exit (1); + } - /* Find font file */ - if (ftw (FONTPATH1, probe_font, 255) <= 0 && - ftw (FONTPATH2, probe_font, 255) <= 0 && - ftw (FONTPATH3, probe_font, 255) <= 0) { - fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", - FONTNAME, FONTPATH1); - besm6_close_panel(); - exit (1); - } + /* Find font file */ + if (ftw (FONTPATH1, probe_font, 255) <= 0 && + ftw (FONTPATH2, probe_font, 255) <= 0 && + ftw (FONTPATH3, probe_font, 255) <= 0) { + fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", + FONTNAME, FONTPATH1); + besm6_close_panel(); + exit (1); + } - /* Open the font file with the requested point size */ - font_big = TTF_OpenFont (font_path, 16); - font_small = TTF_OpenFont (font_path, 9); - if (! font_big || ! font_small) { - fprintf(stderr, "SDL: couldn't load font %s: %s\n", - font_path, SDL_GetError()); - besm6_close_panel(); - exit (1); - } - atexit (besm6_close_panel); + /* Open the font file with the requested point size */ + font_big = TTF_OpenFont (font_path, 16); + font_small = TTF_OpenFont (font_path, 9); + if (! font_big || ! font_small) { + fprintf(stderr, "SDL: couldn't load font %s: %s\n", + font_path, SDL_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); - screen = SDL_CreateRGBSurface(0, WIDTH, HEIGHT, 32, - 0x00FF0000, - 0x0000FF00, - 0x000000FF, - 0xFF000000); + screen = SDL_CreateRGBSurface(0, WIDTH, HEIGHT, 32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); - sdlTexture = SDL_CreateTexture(sdlRenderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STATIC, - WIDTH, HEIGHT); + sdlTexture = SDL_CreateTexture(sdlRenderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, + WIDTH, HEIGHT); - /* Отрисовка статичной части панели БЭСМ-6. */ - draw_modifiers_static (0, 24, 10); - draw_modifiers_static (1, 400, 10); - draw_grp_static (180); - draw_brz_static (230); + /* Отрисовка статичной части панели БЭСМ-6. */ + draw_modifiers_static (0, 24, 10); + draw_modifiers_static (1, 400, 10); + draw_grp_static (180); + draw_brz_static (230); - /* Tell SDL to update the whole screen */ - SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - SDL_RenderPresent (sdlRenderer); + /* Tell SDL to update the whole screen */ + SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent (sdlRenderer); } void (*sim_vm_init)() = init_panel; @@ -461,25 +461,25 @@ void (*sim_vm_init)() = init_panel; */ void besm6_draw_panel () { - if (! screen) - return; + if (! screen) + return; - /* Периодическая отрисовка: мигание лампочек. */ - draw_modifiers_periodic (0, 24, 10); - draw_modifiers_periodic (1, 400, 10); - draw_grp_periodic (180); - draw_brz_periodic (230); + /* Периодическая отрисовка: мигание лампочек. */ + draw_modifiers_periodic (0, 24, 10); + draw_modifiers_periodic (1, 400, 10); + draw_grp_periodic (180); + draw_brz_periodic (230); - /* Tell SDL to update the whole screen */ - SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); - SDL_RenderClear(sdlRenderer); - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); - SDL_RenderPresent (sdlRenderer); + /* Tell SDL to update the whole screen */ + SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); + SDL_RenderClear(sdlRenderer); + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); + SDL_RenderPresent (sdlRenderer); - /* Exit SIMH when window closed.*/ - SDL_Event event; - if (SDL_PollEvent (&event) && event.type == SDL_QUIT) - longjmp (cpu_halt, SCPE_STOP); + /* Exit SIMH when window closed.*/ + SDL_Event event; + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); } #else @@ -489,59 +489,59 @@ void besm6_draw_panel () */ static void init_panel () { - if (sim_switches & SWMASK('Q')) - return; + if (sim_switches & SWMASK('Q')) + return; - /* Initialize SDL subsystems - in this case, only video. */ - if (SDL_Init (SDL_INIT_VIDEO) < 0) { - fprintf (stderr, "SDL: unable to init: %s\n", - SDL_GetError ()); - exit (1); - } - screen = SDL_SetVideoMode (WIDTH, HEIGHT, DEPTH, SDL_SWSURFACE); - if (! screen) { - fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", - WIDTH, HEIGHT, DEPTH, SDL_GetError ()); - exit (1); - } + /* Initialize SDL subsystems - in this case, only video. */ + if (SDL_Init (SDL_INIT_VIDEO) < 0) { + fprintf (stderr, "SDL: unable to init: %s\n", + SDL_GetError ()); + exit (1); + } + screen = SDL_SetVideoMode (WIDTH, HEIGHT, DEPTH, SDL_SWSURFACE); + if (! screen) { + fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n", + WIDTH, HEIGHT, DEPTH, SDL_GetError ()); + exit (1); + } - /* Initialize the TTF library */ - if (TTF_Init() < 0) { - fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", - SDL_GetError()); - SDL_Quit(); - exit (1); - } + /* Initialize the TTF library */ + if (TTF_Init() < 0) { + fprintf (stderr, "SDL: couldn't initialize TTF: %s\n", + SDL_GetError()); + SDL_Quit(); + exit (1); + } - /* Find font file */ - if (ftw (FONTPATH1, probe_font, 255) <= 0 && - ftw (FONTPATH2, probe_font, 255) <= 0 && - ftw (FONTPATH3, probe_font, 255) <= 0) { - fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", - FONTNAME, FONTPATH1); - besm6_close_panel(); - exit (1); - } + /* Find font file */ + if (ftw (FONTPATH1, probe_font, 255) <= 0 && + ftw (FONTPATH2, probe_font, 255) <= 0 && + ftw (FONTPATH3, probe_font, 255) <= 0) { + fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", + FONTNAME, FONTPATH1); + besm6_close_panel(); + exit (1); + } - /* Open the font file with the requested point size */ - font_big = TTF_OpenFont (font_path, 16); - font_small = TTF_OpenFont (font_path, 9); - if (! font_big || ! font_small) { - fprintf(stderr, "SDL: couldn't load font %s: %s\n", - FONTNAME, TTF_GetError()); - besm6_close_panel(); - exit (1); - } - atexit (besm6_close_panel); + /* Open the font file with the requested point size */ + font_big = TTF_OpenFont (font_path, 16); + font_small = TTF_OpenFont (font_path, 9); + if (! font_big || ! font_small) { + fprintf(stderr, "SDL: couldn't load font %s: %s\n", + FONTNAME, TTF_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); - /* Отрисовка статичной части панели БЭСМ-6. */ - draw_modifiers_static (0, 24, 10); - draw_modifiers_static (1, 400, 10); - draw_grp_static (180); - draw_brz_static (230); + /* Отрисовка статичной части панели БЭСМ-6. */ + draw_modifiers_static (0, 24, 10); + draw_modifiers_static (1, 400, 10); + draw_grp_static (180); + draw_brz_static (230); - /* Tell SDL to update the whole screen */ - SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); } void (*sim_vm_init)() = init_panel; @@ -551,27 +551,27 @@ void (*sim_vm_init)() = init_panel; */ void besm6_draw_panel () { - if (! screen) - return; + if (! screen) + return; - /* Периодическая отрисовка: мигание лампочек. */ - draw_modifiers_periodic (0, 24, 10); - draw_modifiers_periodic (1, 400, 10); - draw_grp_periodic (180); - draw_brz_periodic (230); + /* Периодическая отрисовка: мигание лампочек. */ + draw_modifiers_periodic (0, 24, 10); + draw_modifiers_periodic (1, 400, 10); + draw_grp_periodic (180); + draw_brz_periodic (230); - /* Tell SDL to update the whole screen */ - SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); - /* Exit SIMH when window closed.*/ - SDL_Event event; - if (SDL_PollEvent (&event) && event.type == SDL_QUIT) - longjmp (cpu_halt, SCPE_STOP); + /* Exit SIMH when window closed.*/ + SDL_Event event; + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); } -#if !defined(__WIN32__) && \ - !(defined(__MWERKS__) && !defined(__BEOS__)) && \ - !defined(__MACOS__) && !defined(__MACOSX__) && \ +#if !defined(__WIN32__) && \ + !(defined(__MWERKS__) && !defined(__BEOS__)) && \ + !defined(__MACOS__) && !defined(__MACOSX__) && \ !defined(__SYMBIAN32__) && !defined(QWS) #undef main @@ -580,9 +580,9 @@ void besm6_draw_panel () */ int main (int argc, char *argv[]) { - extern int SDL_main (int, char**); + extern int SDL_main (int, char**); - return SDL_main (argc, argv); + return SDL_main (argc, argv); } #endif #endif /* SDL_MAJOR_VERSION */ diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c index d6dee824..8cf88bf7 100644 --- a/BESM6/besm6_printer.c +++ b/BESM6/besm6_printer.c @@ -34,22 +34,22 @@ void offset_gost_write (int num, FILE *fout); /* * Printer data structures * - * printer_dev PRINTER device descriptor - * printer_unit PRINTER unit descriptor - * printer_reg PRINTER register list + * printer_dev PRINTER device descriptor + * printer_unit PRINTER unit descriptor + * printer_reg PRINTER register list */ UNIT printer_unit [] = { - { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, - { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, + { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, + { UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) }, }; #define MAX_STRIKES 10 struct acpu_t { - int curchar, feed, rampup; - int strikes; - int length; - unsigned char line[128][MAX_STRIKES]; + int curchar, feed, rampup; + int strikes; + int length; + unsigned char line[128][MAX_STRIKES]; } acpu[2]; int acpu_isatty[2]; @@ -61,18 +61,18 @@ int acpu_isatty[2]; #define PRN1_LINEFEED (1<<23) #define PRN2_LINEFEED (1<<22) -#define SLOW_START 100*MSEC -#define FAST_START 1*MSEC -#define LINEFEED_SYNC 1 /* Чтобы быстрее печатало; в жизни 20-25 мс/1.4 мс ~= 17 */ +#define SLOW_START 100*MSEC +#define FAST_START 1*MSEC +#define LINEFEED_SYNC 1 /* Чтобы быстрее печатало; в жизни 20-25 мс/1.4 мс ~= 17 */ REG printer_reg[] = { -{ "Готов", &READY, 2, 2, 18, 1 }, -{ "Прогон", &READY, 2, 2, 22, 1 }, -{ 0 } + { "Готов", &READY, 2, 2, 18, 1 }, + { "Прогон", &READY, 2, 2, 22, 1 }, + { 0 } }; MTAB printer_mod[] = { - { 0 } + { 0 } }; t_stat printer_reset (DEVICE *dptr); @@ -80,10 +80,10 @@ t_stat printer_attach (UNIT *uptr, char *cptr); t_stat printer_detach (UNIT *uptr); DEVICE printer_dev = { - "PRN", printer_unit, printer_reg, printer_mod, - 2, 8, 19, 1, 8, 50, - NULL, NULL, &printer_reset, NULL, &printer_attach, &printer_detach, - NULL, DEV_DISABLE | DEV_DEBUG + "PRN", printer_unit, printer_reg, printer_mod, + 2, 8, 19, 1, 8, 50, + NULL, NULL, &printer_reset, NULL, &printer_attach, &printer_detach, + NULL, DEV_DISABLE | DEV_DEBUG }; /* @@ -91,46 +91,46 @@ DEVICE printer_dev = { */ t_stat printer_reset (DEVICE *dptr) { - memset(acpu, 0, sizeof (acpu)); - acpu[0].rampup = acpu[1].rampup = SLOW_START; - sim_cancel (&printer_unit[0]); - sim_cancel (&printer_unit[1]); - READY |= PRN1_NOT_READY | PRN2_NOT_READY; - if (printer_unit[0].flags & UNIT_ATT) - READY &= ~PRN1_NOT_READY; - if (printer_unit[1].flags & UNIT_ATT) - READY &= ~PRN2_NOT_READY; - return SCPE_OK; + memset(acpu, 0, sizeof (acpu)); + acpu[0].rampup = acpu[1].rampup = SLOW_START; + sim_cancel (&printer_unit[0]); + sim_cancel (&printer_unit[1]); + READY |= PRN1_NOT_READY | PRN2_NOT_READY; + if (printer_unit[0].flags & UNIT_ATT) + READY &= ~PRN1_NOT_READY; + if (printer_unit[1].flags & UNIT_ATT) + READY &= ~PRN2_NOT_READY; + return SCPE_OK; } t_stat printer_attach (UNIT *u, char *cptr) { - t_stat s; - int num = u - printer_unit; + t_stat s; + int num = u - printer_unit; - if (u->flags & UNIT_ATT) { - /* Switching files cleanly */ - detach_unit (u); - } - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; + if (u->flags & UNIT_ATT) { + /* Switching files cleanly */ + detach_unit (u); + } + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; - acpu_isatty[num] = !strcmp(cptr, "/dev/tty"); - if (!acpu_isatty[num]) { - /* Write UTF-8 tag: zero width no-break space. */ - fputs ("\xEF\xBB\xBF", u->fileref); - } + acpu_isatty[num] = !strcmp(cptr, "/dev/tty"); + if (!acpu_isatty[num]) { + /* Write UTF-8 tag: zero width no-break space. */ + fputs ("\xEF\xBB\xBF", u->fileref); + } - READY &= ~(PRN1_NOT_READY >> num); - return SCPE_OK; + READY &= ~(PRN1_NOT_READY >> num); + return SCPE_OK; } t_stat printer_detach (UNIT *u) { - int num = u - printer_unit; - READY |= PRN1_NOT_READY >> num; - return detach_unit (u); + int num = u - printer_unit; + READY |= PRN1_NOT_READY >> num; + return detach_unit (u); } /* @@ -138,37 +138,37 @@ t_stat printer_detach (UNIT *u) */ void printer_control (int num, uint32 cmd) { - UNIT *u = &printer_unit[num]; - struct acpu_t * dev = acpu + num; + UNIT *u = &printer_unit[num]; + struct acpu_t * dev = acpu + num; - if (printer_dev.dctrl) - besm6_debug(">>> АЦПУ%d команда %o", num, cmd); - if (READY & (PRN1_NOT_READY >> num)) { - if (printer_dev.dctrl) - besm6_debug(">>> АЦПУ%d не готово", num, cmd); - return; - } - switch (cmd) { - case 1: /* linefeed */ - READY &= ~(PRN1_LINEFEED >> num); - offset_gost_write (num, u->fileref); - dev->feed = LINEFEED_SYNC; - break; - case 4: /* start */ - /* стартуем из состояния прогона для надежности */ - dev->feed = LINEFEED_SYNC; - READY &= ~(PRN1_LINEFEED >> num); - if (dev->rampup) - sim_activate (u, dev->rampup); - dev->rampup = 0; - break; - case 10: /* motor and ribbon off */ - case 8: /* motor off? (undocumented) */ - case 2: /* ribbon off */ - dev->rampup = cmd == 2 ? FAST_START : SLOW_START; - sim_cancel (u); - break; - } + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d команда %o", num, cmd); + if (READY & (PRN1_NOT_READY >> num)) { + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d не готово", num, cmd); + return; + } + switch (cmd) { + case 1: /* linefeed */ + READY &= ~(PRN1_LINEFEED >> num); + offset_gost_write (num, u->fileref); + dev->feed = LINEFEED_SYNC; + break; + case 4: /* start */ + /* стартуем из состояния прогона для надежности */ + dev->feed = LINEFEED_SYNC; + READY &= ~(PRN1_LINEFEED >> num); + if (dev->rampup) + sim_activate (u, dev->rampup); + dev->rampup = 0; + break; + case 10: /* motor and ribbon off */ + case 8: /* motor off? (undocumented) */ + case 2: /* ribbon off */ + dev->rampup = cmd == 2 ? FAST_START : SLOW_START; + sim_cancel (u); + break; + } } /* @@ -176,23 +176,23 @@ void printer_control (int num, uint32 cmd) */ void printer_hammer (int num, int pos, uint32 mask) { - struct acpu_t * dev = acpu + num; - while (mask) { - if (mask & 1) { - int strike = 0; - while (dev->line[pos][strike] && strike < MAX_STRIKES) - ++strike; - if (strike < MAX_STRIKES) { - dev->line[pos][strike] = dev->curchar; - if (pos + 1 > dev->length) - dev->length = pos + 1; - if (strike + 1 > dev->strikes) - dev->strikes = strike + 1; - } - } - mask >>= 1; - pos += 8; - } + struct acpu_t * dev = acpu + num; + while (mask) { + if (mask & 1) { + int strike = 0; + while (dev->line[pos][strike] && strike < MAX_STRIKES) + ++strike; + if (strike < MAX_STRIKES) { + dev->line[pos][strike] = dev->curchar; + if (pos + 1 > dev->length) + dev->length = pos + 1; + if (strike + 1 > dev->strikes) + dev->strikes = strike + 1; + } + } + mask >>= 1; + pos += 8; + } } /* @@ -201,30 +201,27 @@ void printer_hammer (int num, int pos, uint32 mask) */ t_stat printer_event (UNIT *u) { - int num = u - printer_unit; - struct acpu_t * dev = acpu + num; + int num = u - printer_unit; + struct acpu_t * dev = acpu + num; - switch (dev->curchar) { - case 0 ... 0137: - GRP |= GRP_PRN1_SYNC >> num; - ++dev->curchar; - /* For next char */ - sim_activate (u, 1400*USEC); - if (dev->feed && --dev->feed == 0) { - READY |= PRN1_LINEFEED >> num; - } - break; - case 0140: - /* For "zero" */ - dev->curchar = 0; - GRP |= GRP_PRN1_ZERO >> num; - if (printer_dev.dctrl) - besm6_debug(">>> АЦПУ%d 'ноль'", num); - /* For first sync after "zero" */ - sim_activate (u, 1000*USEC); - break; - } - return SCPE_OK; + if (dev->curchar < 0140) { + GRP |= GRP_PRN1_SYNC >> num; + ++dev->curchar; + /* For next char */ + sim_activate (u, 1400*USEC); + if (dev->feed && --dev->feed == 0) { + READY |= PRN1_LINEFEED >> num; + } + } else { + /* For "zero" */ + dev->curchar = 0; + GRP |= GRP_PRN1_ZERO >> num; + if (printer_dev.dctrl) + besm6_debug(">>> АЦПУ%d 'ноль'", num); + /* For first sync after "zero" */ + sim_activate (u, 1000*USEC); + } + return SCPE_OK; } int gost_latin = 0; /* default cyrillics */ @@ -234,33 +231,33 @@ int gost_latin = 0; /* default cyrillics */ * Documentation: http://en.wikipedia.org/wiki/GOST_10859 */ static const unsigned short gost_to_unicode_cyr [256] = { -/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, -/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, -/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, -/* 040-047 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, -/* 050-057 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, -/* 060-067 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, -/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, -/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, -/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, -/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, -/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, + /* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, + /* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, + /* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, + /* 040-047 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + /* 050-057 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + /* 060-067 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + /* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, + /* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, + /* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, + /* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, + /* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, }; static const unsigned short gost_to_unicode_lat [256] = { -/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, -/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, -/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, -/* 040-047 */ 0x41, 0x0411, 0x42, 0x0413, 0x0414, 0x45, 0x0416, 0x0417, -/* 050-057 */ 0x0418, 0x0419, 0x4b, 0x041b, 0x4d, 0x48, 0x4f, 0x041f, -/* 060-067 */ 0x50, 0x43, 0x54, 0x59, 0x0424, 0x58, 0x0426, 0x0427, -/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, -/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, -/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, -/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, -/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, + /* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423, + /* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b, + /* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a, + /* 040-047 */ 0x41, 0x0411, 0x42, 0x0413, 0x0414, 0x45, 0x0416, 0x0417, + /* 050-057 */ 0x0418, 0x0419, 0x4b, 0x041b, 0x4d, 0x48, 0x4f, 0x041f, + /* 060-067 */ 0x50, 0x43, 0x54, 0x59, 0x0424, 0x58, 0x0426, 0x0427, + /* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44, + /* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52, + /* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265, + /* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7, + /* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032, }; /* * Write Unicode symbol to file. @@ -272,25 +269,25 @@ static const unsigned short gost_to_unicode_lat [256] = { static void utf8_putc (unsigned short ch, FILE *fout) { - if (ch < 0x80) { - putc (ch, fout); - return; - } - if (ch < 0x800) { - putc (ch >> 6 | 0xc0, fout); - putc ((ch & 0x3f) | 0x80, fout); - return; - } - putc (ch >> 12 | 0xe0, fout); - putc (((ch >> 6) & 0x3f) | 0x80, fout); + if (ch < 0x80) { + putc (ch, fout); + return; + } + if (ch < 0x800) { + putc (ch >> 6 | 0xc0, fout); putc ((ch & 0x3f) | 0x80, fout); + return; + } + putc (ch >> 12 | 0xe0, fout); + putc (((ch >> 6) & 0x3f) | 0x80, fout); + putc ((ch & 0x3f) | 0x80, fout); } unsigned short gost_to_unicode (unsigned char ch) { - return gost_latin ? gost_to_unicode_lat [ch] : - gost_to_unicode_cyr [ch]; + return gost_latin ? gost_to_unicode_lat [ch] : + gost_to_unicode_cyr [ch]; } /* @@ -300,12 +297,12 @@ gost_to_unicode (unsigned char ch) void gost_putc (unsigned char ch, FILE *fout) { - unsigned short u; + unsigned short u; - u = gost_to_unicode (ch); - if (! u) - u = ' '; - utf8_putc (u, fout); + u = gost_to_unicode (ch); + if (! u) + u = ' '; + utf8_putc (u, fout); } /* @@ -314,22 +311,22 @@ gost_putc (unsigned char ch, FILE *fout) void offset_gost_write (int num, FILE *fout) { - struct acpu_t * dev = acpu + num; - int s, p; - for (s = 0; s < dev->strikes; ++s) { - if (s) - fputc ('\r', fout); - for (p = 0; p < dev->length; ++p) { - gost_putc (dev->line[p][s] - 1, fout); - } + struct acpu_t * dev = acpu + num; + int s, p; + for (s = 0; s < dev->strikes; ++s) { + if (s) + fputc ('\r', fout); + for (p = 0; p < dev->length; ++p) { + gost_putc (dev->line[p][s] - 1, fout); } + } - if (acpu_isatty[num]) - fputc('\r', fout); + if (acpu_isatty[num]) + fputc('\r', fout); - fputc ('\n', fout); - memset(dev->line, 0, sizeof (dev->line)); - dev->length = dev->strikes = 0; + fputc ('\n', fout); + memset(dev->line, 0, sizeof (dev->line)); + dev->length = dev->strikes = 0; } /* @@ -337,9 +334,9 @@ offset_gost_write (int num, FILE *fout) */ int printer_is_idle () { - if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0) - return 0; - if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0) - return 0; - return 1; + if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0) + return 0; + if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0) + return 0; + return 1; } diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c index 7f1a5235..42906b15 100644 --- a/BESM6/besm6_punch.c +++ b/BESM6/besm6_punch.c @@ -34,8 +34,8 @@ t_stat fs_event (UNIT *u); t_stat uvvk_event (UNIT *u); UNIT fs_unit [] = { - { UDATA (fs_event, UNIT_SEQ+UNIT_ATTABLE, 0) }, - { UDATA (fs_event, UNIT_SEQ+UNIT_ATTABLE, 0) }, + { UDATA (fs_event, UNIT_SEQ+UNIT_ATTABLE, 0) }, + { UDATA (fs_event, UNIT_SEQ+UNIT_ATTABLE, 0) }, }; int curchar[2], feed[2], isfifo[2]; @@ -47,33 +47,33 @@ char line[2][128]; /* #define NEGATIVE_RDY */ #ifndef NEGATIVE_RDY -#define ENB_RDY SET_RDY -#define DIS_RDY CLR_RDY -#define IS_RDY ISSET_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 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 +#define FS_RATE 1000*MSEC/1500 unsigned char FS[2]; REG fs_reg[] = { -{ "Готов", &READY, 2, 2, 14, 1 }, -{ "ФС1500-1", &FS[0], 8, 8, 0, 1 }, -{ "ФС1500-2", &FS[2], 8, 8, 0, 1 }, -{ 0 } + { "Готов", &READY, 2, 2, 14, 1 }, + { "ФС1500-1", &FS[0], 8, 8, 0, 1 }, + { "ФС1500-2", &FS[2], 8, 8, 0, 1 }, + { 0 } }; MTAB fs_mod[] = { - { 0 } + { 0 } }; t_stat fs_reset (DEVICE *dptr); @@ -81,25 +81,25 @@ t_stat fs_attach (UNIT *uptr, 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 + "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_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_IDLE, + FS_STARTING, + 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]; /* @@ -107,40 +107,40 @@ enum { */ 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; + 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; } t_stat fs_attach (UNIT *u, char *cptr) { - t_stat s; - int num = u - fs_unit; - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; - struct stat stbuf; - fstat (fileno(u->fileref), &stbuf); - isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0; - if (isfifo[num]) { - int flags = fcntl(fileno(u->fileref), F_GETFL, 0); - fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK); - } - ENB_RDY(FS1_READY >> num); - return SCPE_OK; + t_stat s; + int num = u - fs_unit; + s = attach_unit (u, cptr); + if (s != SCPE_OK) + return s; + struct stat stbuf; + fstat (fileno(u->fileref), &stbuf); + isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0; + if (isfifo[num]) { + int flags = fcntl(fileno(u->fileref), F_GETFL, 0); + fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK); + } + 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); + int num = u - fs_unit; + DIS_RDY(FS1_READY >> num); + return detach_unit (u); } /* @@ -148,49 +148,49 @@ t_stat fs_detach (UNIT *u) */ void fs_control (int num, uint32 cmd) { - UNIT *u = &fs_unit[num]; + 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); - } + 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); @@ -202,250 +202,238 @@ static int utf8_getc (FILE *fin); */ t_stat fs_event (UNIT *u) { - int num = u - fs_unit; -again: - switch (fs_state[num]) { - case FS_STARTING: - /* По первому прерыванию после запуска двигателя ничего не читаем */ - FS[num] = 0; - fs_state[num] = FS_RUNNING; - break; - case FS_RUNNING: { - int ch; - /* переводы строк игнорируются */ - while ((ch = utf8_getc (u->fileref)) == '\n'); - if (ch < 0) { - /* хвост ленты без пробивок */ - FS[num] = 0; - fs_state[num] = FS_TAIL; - } else if (ch == '\f') { - fs_state[num] = FS_IMAGE; - goto again; - } else { - ch = FS[num] = unicode_to_gost (ch); - ch = (ch & 0x55) + ((ch >> 1) & 0x55); - ch = (ch & 0x33) + ((ch >> 2) & 0x33); - ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); - if (ch & 1); else FS[num] |= 0x80; - } - break; - } - case FS_IMAGE ... FS_IMAGE_LAST: { - int ch = utf8_getc (u->fileref); - if (ch < 0) { - /* обрыв ленты */ - FS[num] = 0; - fs_state[num] = FS_TAIL; - } else if (ch == '\n') { - /* идем дополнять образ карты нулевыми байтами */ - fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE); - goto again; - } else if (ch == '\f') { - if (fs_state[num] != FS_IMAGE) - besm6_debug("<<< ENDA3 requested mid-card?"); - fs_state[num] = FS_ENDA3; - goto again; - } else { - ch = FS[num] = unicode_to_gost (ch); - ch = (ch & 0x55) + ((ch >> 1) & 0x55); - ch = (ch & 0x33) + ((ch >> 2) & 0x33); - ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); - if (ch & 1); else FS[num] |= 0x80; - ++fs_state[num]; - } - break; - } - case FS_TOOLONG: { - /* дочитываем до конца строки */ - int ch; - besm6_debug("<<< too long???"); - while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0); - if (ch < 0) { - /* хвост ленты без пробивок */ - FS[num] = 0; - fs_state[num] = FS_TAIL; - } else - goto again; - break; - } - case FS_FILLUP ... FS_FILLUP_LAST: - FS[num] = 0; - if (++fs_state[num] == FS_ENDA3) { - fs_state[num] = FS_IMAGE; - } - break; - case FS_ENDA3 ... 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; - } - break; - case FS_IDLE: - case FS_TAIL: - FS[num] = 0; - break; - } - GRP |= GRP_FS1_SYNC >> num; - return SCPE_OK; + int num = u - fs_unit; + again: + if (fs_state[num] == FS_STARTING) { + /* По первому прерыванию после запуска двигателя ничего не читаем */ + FS[num] = 0; + fs_state[num] = FS_RUNNING; + } else if (fs_state[num] == FS_RUNNING) { + int ch; + /* переводы строк игнорируются */ + while ((ch = utf8_getc (u->fileref)) == '\n'); + if (ch < 0) { + /* хвост ленты без пробивок */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else if (ch == '\f') { + fs_state[num] = FS_IMAGE; + goto again; + } else { + ch = FS[num] = unicode_to_gost (ch); + ch = (ch & 0x55) + ((ch >> 1) & 0x55); + ch = (ch & 0x33) + ((ch >> 2) & 0x33); + ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); + if (ch & 1); else FS[num] |= 0x80; + } + } else if (FS_IMAGE <= fs_state[num] && fs_state[num] <= FS_IMAGE_LAST) { + int ch = utf8_getc (u->fileref); + if (ch < 0) { + /* обрыв ленты */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else if (ch == '\n') { + /* идем дополнять образ карты нулевыми байтами */ + fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE); + goto again; + } else if (ch == '\f') { + if (fs_state[num] != FS_IMAGE) + besm6_debug("<<< ENDA3 requested mid-card?"); + fs_state[num] = FS_ENDA3; + goto again; + } else { + ch = FS[num] = unicode_to_gost (ch); + ch = (ch & 0x55) + ((ch >> 1) & 0x55); + ch = (ch & 0x33) + ((ch >> 2) & 0x33); + ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); + if (ch & 1); else FS[num] |= 0x80; + ++fs_state[num]; + } + } else if (fs_state[num] == FS_TOOLONG) { + /* дочитываем до конца строки */ + int ch; + besm6_debug("<<< too long???"); + while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0); + if (ch < 0) { + /* хвост ленты без пробивок */ + FS[num] = 0; + fs_state[num] = FS_TAIL; + } else + goto again; + } 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]; + if (fs_dev.dctrl) + besm6_debug("<<< ФС1500-%d: байт %03o", num, FS[num]); + + return FS[num]; } int fs_is_idle (void) { - return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE; + return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE; } 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, 0174, 017, 017, -/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017, -/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 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 0x25: - switch ((unsigned char) val) { - case 0xc7: return 0127; - case 0xca: return 0127; - } - break; - } - return 017; + static const unsigned char tab0 [256] = { + /* 00 - 07 */ 017, 017, 017, 017, 017, 017, 017, 017, + /* 08 - 0f */ 017, 017, 0214, 017, 017, 0174, 017, 017, + /* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017, + /* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 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 0x25: + switch ((unsigned char) val) { + case 0xc7: return 0127; + case 0xca: return 0127; + } + break; + } + return 017; } /* @@ -455,18 +443,18 @@ unicode_to_gost (unsigned short val) 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); + 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); } diff --git a/BESM6/besm6_sys.c b/BESM6/besm6_sys.c index 1c128938..01014aa2 100644 --- a/BESM6/besm6_sys.c +++ b/BESM6/besm6_sys.c @@ -16,46 +16,46 @@ * This file implements three essential functions: * * sim_load() - loading and dumping memory and CPU state - * in a way, specific for BESM-6 architecture + * in a way, specific for BESM-6 architecture * fprint_sym() - print a machune instruction using - * opcode mnemonic or in a digital format - * parse_sym() - scan a string and build an instruction - * word from it + * opcode mnemonic or in a digital format + * parse_sym() - scan a string and build an instruction + * word from it */ #include "besm6_defs.h" #include #include const char *opname_short_bemsh [64] = { - "зп", "зпм", "рег", "счм", "сл", "вч", "вчоб", "вчаб", - "сч", "и", "нтж", "слц", "знак", "или", "дел", "умн", - "сбр", "рзб", "чед", "нед", "слп", "вчп", "сд", "рж", - "счрж", "счмр", "э32", "увв", "слпа", "вчпа", "сда", "ржа", - "уи", "уим", "счи", "счим", "уии", "сли", "э46", "э47", - "э50", "э51", "э52", "э53", "э54", "э55", "э56", "э57", - "э60", "э61", "э62", "э63", "э64", "э65", "э66", "э67", - "э70", "э71", "э72", "э73", "э74", "э75", "э76", "э77", + "зп", "зпм", "рег", "счм", "сл", "вч", "вчоб","вчаб", + "сч", "и", "нтж", "слц", "знак","или", "дел", "умн", + "сбр", "рзб", "чед", "нед", "слп", "вчп", "сд", "рж", + "счрж","счмр","э32", "увв", "слпа","вчпа","сда", "ржа", + "уи", "уим", "счи", "счим","уии", "сли", "э46", "э47", + "э50", "э51", "э52", "э53", "э54", "э55", "э56", "э57", + "э60", "э61", "э62", "э63", "э64", "э65", "э66", "э67", + "э70", "э71", "э72", "э73", "э74", "э75", "э76", "э77", }; static const char *opname_long_bemsh [16] = { - "э20", "э21", "мода", "мод", "уиа", "слиа", "по", "пе", - "пб", "пв", "выпр", "стоп", "пио", "пино", "э36", "цикл", + "э20", "э21", "мода","мод", "уиа", "слиа","по", "пе", + "пб", "пв", "выпр","стоп","пио", "пино","э36", "цикл", }; const char *opname_short_madlen [64] = { - "atx", "stx", "mod", "xts", "a+x", "a-x", "x-a", "amx", - "xta", "aax", "aex", "arx", "avx", "aox", "a/x", "a*x", - "apx", "aux", "acx", "anx", "e+x", "e-x", "asx", "xtr", - "rte", "yta", "*32", "ext", "e+n", "e-n", "asn", "ntr", - "ati", "sti", "ita", "its", "mtj", "j+m", "*46", "*47", - "*50", "*51", "*52", "*53", "*54", "*55", "*56", "*57", - "*60", "*61", "*62", "*63", "*64", "*65", "*66", "*67", - "*70", "*71", "*72", "*73", "*74", "*75", "*76", "*77", + "atx", "stx", "mod", "xts", "a+x", "a-x", "x-a", "amx", + "xta", "aax", "aex", "arx", "avx", "aox", "a/x", "a*x", + "apx", "aux", "acx", "anx", "e+x", "e-x", "asx", "xtr", + "rte", "yta", "*32", "ext", "e+n", "e-n", "asn", "ntr", + "ati", "sti", "ita", "its", "mtj", "j+m", "*46", "*47", + "*50", "*51", "*52", "*53", "*54", "*55", "*56", "*57", + "*60", "*61", "*62", "*63", "*64", "*65", "*66", "*67", + "*70", "*71", "*72", "*73", "*74", "*75", "*76", "*77", }; static const char *opname_long_madlen [16] = { - "*20", "*21", "utc", "wtc", "vtm", "utm", "uza", "u1a", - "uj", "vjm", "ij", "stop", "vzm", "v1m", "*36", "vlm", + "*20", "*21", "utc", "wtc", "vtm", "utm", "uza", "u1a", + "uj", "vjm", "ij", "stop", "vzm", "v1m", "*36", "vlm", }; /* @@ -64,33 +64,33 @@ static const char *opname_long_madlen [16] = { */ const char *besm6_opname (int opcode) { - if (sim_switches & SWMASK ('L')) { - /* Latin mnemonics. */ - if (opcode & 0200) - return opname_long_madlen [(opcode >> 3) & 017]; - return opname_short_madlen [opcode]; - } - if (opcode & 0200) - return opname_long_bemsh [(opcode >> 3) & 017]; - return opname_short_bemsh [opcode]; -}; + if (sim_switches & SWMASK ('L')) { + /* Latin mnemonics. */ + if (opcode & 0200) + return opname_long_madlen [(opcode >> 3) & 017]; + return opname_short_madlen [opcode]; + } + if (opcode & 0200) + return opname_long_bemsh [(opcode >> 3) & 017]; + return opname_short_bemsh [opcode]; +} /* * Выдача кода инструкции по мнемонике (UTF-8). */ int besm6_opcode (char *instr) { - int i; + int i; - for (i=0; i<64; ++i) - if (strcmp (opname_short_bemsh[i], instr) == 0 || - strcmp (opname_short_madlen[i], instr) == 0) - return i; - for (i=0; i<16; ++i) - if (strcmp (opname_long_bemsh[i], instr) == 0 || - strcmp (opname_long_madlen[i], instr) == 0) - return (i << 3) | 0200; - return -1; + for (i=0; i<64; ++i) + if (strcmp (opname_short_bemsh[i], instr) == 0 || + strcmp (opname_short_madlen[i], instr) == 0) + return i; + for (i=0; i<16; ++i) + if (strcmp (opname_long_bemsh[i], instr) == 0 || + strcmp (opname_long_madlen[i], instr) == 0) + return (i << 3) | 0200; + return -1; } /* @@ -100,25 +100,25 @@ int besm6_opcode (char *instr) */ void besm6_log (const char *fmt, ...) { - va_list args; + va_list args; - if (*fmt == '_') - ++fmt; - else { - va_start (args, fmt); - vprintf (fmt, args); - printf ("\r\n"); - va_end (args); - } - if (sim_log) { - va_start (args, fmt); - vfprintf (sim_log, fmt, args); - if (sim_log == stdout) - fprintf (sim_log, "\r"); - fprintf (sim_log, "\n"); - fflush (sim_log); - va_end (args); - } + if (*fmt == '_') + ++fmt; + else { + va_start (args, fmt); + vprintf (fmt, args); + printf ("\r\n"); + va_end (args); + } + if (sim_log) { + va_start (args, fmt); + vfprintf (sim_log, fmt, args); + if (sim_log == stdout) + fprintf (sim_log, "\r"); + fprintf (sim_log, "\n"); + fflush (sim_log); + va_end (args); + } } /* @@ -126,21 +126,21 @@ void besm6_log (const char *fmt, ...) */ void besm6_log_cont (const char *fmt, ...) { - va_list args; + va_list args; - if (*fmt == '_') - ++fmt; - else { - va_start (args, fmt); - vprintf (fmt, args); - va_end (args); - } - if (sim_log) { - va_start (args, fmt); - vfprintf (sim_log, fmt, args); - fflush (sim_log); - va_end (args); - } + if (*fmt == '_') + ++fmt; + else { + va_start (args, fmt); + vprintf (fmt, args); + va_end (args); + } + if (sim_log) { + va_start (args, fmt); + vfprintf (sim_log, fmt, args); + fflush (sim_log); + va_end (args); + } } /* @@ -149,27 +149,27 @@ void besm6_log_cont (const char *fmt, ...) */ void besm6_debug (const char *fmt, ...) { - va_list args; + va_list args; - va_start (args, fmt); - vprintf (fmt, args); - printf ("\r\n"); - va_end (args); - if (sim_deb && sim_deb != stdout) { - va_start (args, fmt); - vfprintf (sim_deb, fmt, args); - fprintf (sim_deb, "\n"); - fflush (sim_deb); - va_end (args); - } + va_start (args, fmt); + vprintf (fmt, args); + printf ("\r\n"); + va_end (args); + if (sim_deb && sim_deb != stdout) { + va_start (args, fmt); + vfprintf (sim_deb, fmt, args); + fprintf (sim_deb, "\n"); + fflush (sim_deb); + va_end (args); + } } /* * Преобразование вещественного числа в формат БЭСМ-6. * * Представление чисел в IEEE 754 (double): - * 64 63———53 52————–1 - * знак порядок мантисса + * 64 63———53 52————–1 + * знак порядок мантисса * Старший (53-й) бит мантиссы не хранится и всегда равен 1. * * Представление чисел в БЭСМ-6: @@ -178,48 +178,48 @@ void besm6_debug (const char *fmt, ...) */ t_value ieee_to_besm6 (double d) { - t_value word; - int exponent; - int sign; + t_value word; + int exponent; + int sign; - sign = d < 0; - if (sign) - d = -d; - d = frexp (d, &exponent); - /* 0.5 <= d < 1.0 */ - d = ldexp (d, 40); - word = d; - if (d - word >= 0.5) - word += 1; /* Округление. */ - if (exponent < -64) - return 0LL; /* Близкое к нулю число */ - if (exponent > 63) { - return sign ? - 0xFEFFFFFFFFFFLL : /* Максимальное число */ - 0xFF0000000000LL; /* Минимальное число */ - } - if (sign) - word = 0x20000000000LL-word; /* Знак. */ - word |= ((t_value) (exponent + 64)) << 41; - return word; + sign = d < 0; + if (sign) + d = -d; + d = frexp (d, &exponent); + /* 0.5 <= d < 1.0 */ + d = ldexp (d, 40); + word = d; + if (d - word >= 0.5) + word += 1; /* Округление. */ + if (exponent < -64) + return 0LL; /* Близкое к нулю число */ + if (exponent > 63) { + return sign ? + 0xFEFFFFFFFFFFLL : /* Максимальное число */ + 0xFF0000000000LL; /* Минимальное число */ + } + if (sign) + word = 0x20000000000LL-word; /* Знак. */ + word |= ((t_value) (exponent + 64)) << 41; + return word; } double besm6_to_ieee (t_value word) { - double mantissa; + double mantissa; - /* Убираем свертку */ - word &= BITS48; + /* Убираем свертку */ + word &= BITS48; - /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; - * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. - */ - mantissa = (t_int64) word << (64 - 48 + 7); + /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; + * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. + */ + mantissa = (t_int64) word << (64 - 48 + 7); - int exponent = word >> 41; + int exponent = word >> 41; - /* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */ - return ldexp (mantissa, exponent - 64 - 63); + /* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */ + return ldexp (mantissa, exponent - 64 - 63); } /* @@ -227,18 +227,18 @@ double besm6_to_ieee (t_value word) */ char *skip_spaces (char *p) { - for (;;) { - if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) { - /* Skip zero width no-break space. */ - p += 3; - continue; - } - if (*p == ' ' || *p == '\t' || *p == '\r') { - ++p; - continue; - } - return p; - } + for (;;) { + if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) { + /* Skip zero width no-break space. */ + p += 3; + continue; + } + if (*p == ' ' || *p == '\t' || *p == '\r') { + ++p; + continue; + } + return p; + } } /* @@ -247,37 +247,37 @@ char *skip_spaces (char *p) */ int utf8_to_unicode (char **p) { - int c1, c2, c3; + int c1, c2, c3; - c1 = (unsigned char) *(*p)++; - if (! (c1 & 0x80)) - return c1; - c2 = (unsigned char) *(*p)++; - if (! (c1 & 0x20)) - return (c1 & 0x1f) << 6 | (c2 & 0x3f); - c3 = (unsigned char) *(*p)++; - return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f); + c1 = (unsigned char) *(*p)++; + if (! (c1 & 0x80)) + return c1; + c2 = (unsigned char) *(*p)++; + if (! (c1 & 0x20)) + return (c1 & 0x1f) << 6 | (c2 & 0x3f); + c3 = (unsigned char) *(*p)++; + return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f); } char *besm6_parse_octal (char *cptr, int *offset) { - char *eptr; + char *eptr; - *offset = strtol (cptr, &eptr, 8); - if (eptr == cptr) - return 0; - return eptr; + *offset = strtol (cptr, &eptr, 8); + if (eptr == cptr) + return 0; + return eptr; } static char *get_alnum (char *iptr, char *optr) { - while ((*iptr >= 'a' && *iptr<='z') || - (*iptr >= 'A' && *iptr<='Z') || - (*iptr >= '0' && *iptr<='9') || (*iptr & 0x80)) { - *optr++ = *iptr++; - } - *optr = 0; - return iptr; + while ((*iptr >= 'a' && *iptr<='z') || + (*iptr >= 'A' && *iptr<='Z') || + (*iptr >= '0' && *iptr<='9') || (*iptr & 0x80)) { + *optr++ = *iptr++; + } + *optr = 0; + return iptr; } /* @@ -286,92 +286,92 @@ static char *get_alnum (char *iptr, char *optr) */ char *parse_instruction (char *cptr, uint32 *val) { - int opcode, reg, addr, negate; - char gbuf[CBUFSIZE]; + int opcode, reg, addr, negate; + char gbuf[CBUFSIZE]; - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr >= '0' && *cptr <= '7') { - /* Восьмеричное представление. */ - cptr = besm6_parse_octal (cptr, ®); /* get register */ - if (! cptr || reg > 15) { - /*printf ("Bad register\n");*/ - return 0; - } - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr == '2' || *cptr == '3') { - /* Длинная команда. */ - cptr = besm6_parse_octal (cptr, &opcode); - if (! cptr || opcode < 020 || opcode > 037) { - /*printf ("Bad long opcode\n");*/ - return 0; - } - opcode <<= 3; - } else { - /* Короткая команда. */ - cptr = besm6_parse_octal (cptr, &opcode); - if (! cptr || opcode > 0177) { - /*printf ("Bad short opcode\n");*/ - return 0; - } - } - cptr = besm6_parse_octal (cptr, &addr); /* get address */ - if (! cptr || addr > BITS(15) || - (opcode <= 0177 && addr > BITS(12))) { - /*printf ("Bad address\n");*/ - return 0; - } - } else { - /* Мнемоническое представление команды. */ - cptr = get_alnum (cptr, gbuf); /* get opcode */ - opcode = besm6_opcode (gbuf); - if (opcode < 0) { - /*printf ("Bad opname: %s\n", gbuf);*/ - return 0; - } - negate = 0; - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr == '-') { /* negative offset */ - negate = 1; - cptr = skip_spaces (cptr + 1); /* absorb spaces */ - } - addr = 0; - if (*cptr >= '0' && *cptr <= '7') { - /* Восьмеричный адрес. */ - cptr = besm6_parse_octal (cptr, &addr); - if (! cptr || addr > BITS(15)) { - /*printf ("Bad address: %o\n", addr);*/ - return 0; - } - if (negate) - addr = (- addr) & BITS(15); - if (opcode <= 077 && addr > BITS(12)) { - if (addr < 070000) { - /*printf ("Bad short address: %o\n", addr);*/ - return 0; - } - opcode |= 0100; - addr &= BITS(12); - } - } - reg = 0; - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr == '(') { - /* Индекс-регистр в скобках. */ - cptr = besm6_parse_octal (cptr+1, ®); - if (! cptr || reg > 15) { - /*printf ("Bad register: %o\n", reg);*/ - return 0; - } - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr != ')') { - /*printf ("No closing brace\n");*/ - return 0; - } - ++cptr; - } - } - *val = reg << 20 | opcode << 12 | addr; - return cptr; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr >= '0' && *cptr <= '7') { + /* Восьмеричное представление. */ + cptr = besm6_parse_octal (cptr, ®); /* get register */ + if (! cptr || reg > 15) { + /*printf ("Bad register\n");*/ + return 0; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '2' || *cptr == '3') { + /* Длинная команда. */ + cptr = besm6_parse_octal (cptr, &opcode); + if (! cptr || opcode < 020 || opcode > 037) { + /*printf ("Bad long opcode\n");*/ + return 0; + } + opcode <<= 3; + } else { + /* Короткая команда. */ + cptr = besm6_parse_octal (cptr, &opcode); + if (! cptr || opcode > 0177) { + /*printf ("Bad short opcode\n");*/ + return 0; + } + } + cptr = besm6_parse_octal (cptr, &addr); /* get address */ + if (! cptr || addr > BITS(15) || + (opcode <= 0177 && addr > BITS(12))) { + /*printf ("Bad address\n");*/ + return 0; + } + } else { + /* Мнемоническое представление команды. */ + cptr = get_alnum (cptr, gbuf); /* get opcode */ + opcode = besm6_opcode (gbuf); + if (opcode < 0) { + /*printf ("Bad opname: %s\n", gbuf);*/ + return 0; + } + negate = 0; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '-') { /* negative offset */ + negate = 1; + cptr = skip_spaces (cptr + 1); /* absorb spaces */ + } + addr = 0; + if (*cptr >= '0' && *cptr <= '7') { + /* Восьмеричный адрес. */ + cptr = besm6_parse_octal (cptr, &addr); + if (! cptr || addr > BITS(15)) { + /*printf ("Bad address: %o\n", addr);*/ + return 0; + } + if (negate) + addr = (- addr) & BITS(15); + if (opcode <= 077 && addr > BITS(12)) { + if (addr < 070000) { + /*printf ("Bad short address: %o\n", addr);*/ + return 0; + } + opcode |= 0100; + addr &= BITS(12); + } + } + reg = 0; + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr == '(') { + /* Индекс-регистр в скобках. */ + cptr = besm6_parse_octal (cptr+1, ®); + if (! cptr || reg > 15) { + /*printf ("Bad register: %o\n", reg);*/ + return 0; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr != ')') { + /*printf ("No closing brace\n");*/ + return 0; + } + ++cptr; + } + } + *val = reg << 20 | opcode << 12 | addr; + return cptr; } /* @@ -379,26 +379,26 @@ char *parse_instruction (char *cptr, uint32 *val) */ t_stat parse_instruction_word (char *cptr, t_value *val) { - uint32 left, right; + uint32 left, right; - *val = 0; - cptr = parse_instruction (cptr, &left); - if (! cptr) - return SCPE_ARG; - right = 0; - cptr = skip_spaces (cptr); - if (*cptr == ',') { - cptr = parse_instruction (cptr + 1, &right); - if (! cptr) - return SCPE_ARG; - } - cptr = skip_spaces (cptr); /* absorb spaces */ - if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { - /*printf ("Extra symbols at eoln: %s\n", cptr);*/ - return SCPE_2MARG; - } - *val = (t_value) left << 24 | right; - return SCPE_OK; + *val = 0; + cptr = parse_instruction (cptr, &left); + if (! cptr) + return SCPE_ARG; + right = 0; + cptr = skip_spaces (cptr); + if (*cptr == ',') { + cptr = parse_instruction (cptr + 1, &right); + if (! cptr) + return SCPE_ARG; + } + cptr = skip_spaces (cptr); /* absorb spaces */ + if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { + /*printf ("Extra symbols at eoln: %s\n", cptr);*/ + return SCPE_2MARG; + } + *val = (t_value) left << 24 | right; + return SCPE_OK; } /* @@ -406,31 +406,31 @@ t_stat parse_instruction_word (char *cptr, t_value *val) */ void besm6_fprint_cmd (FILE *of, uint32 cmd) { - int reg, opcode, addr; + int reg, opcode, addr; - reg = (cmd >> 20) & 017; - if (cmd & BBIT(20)) { - opcode = (cmd >> 12) & 0370; - addr = cmd & BITS(15); - } else { - opcode = (cmd >> 12) & 077; - addr = cmd & 07777; - if (cmd & BBIT(19)) - addr |= 070000; - } - fprintf (of, "%s", besm6_opname (opcode)); - if (addr) { - fprintf (of, " "); - if (addr >= 077700) - fprintf (of, "-%o", (addr ^ 077777) + 1); - else - fprintf (of, "%o", addr); - } - if (reg) { - if (! addr) - fprintf (of, " "); - fprintf (of, "(%o)", reg); - } + reg = (cmd >> 20) & 017; + if (cmd & BBIT(20)) { + opcode = (cmd >> 12) & 0370; + addr = cmd & BITS(15); + } else { + opcode = (cmd >> 12) & 077; + addr = cmd & 07777; + if (cmd & BBIT(19)) + addr |= 070000; + } + fprintf (of, "%s", besm6_opname (opcode)); + if (addr) { + fprintf (of, " "); + if (addr >= 077700) + fprintf (of, "-%o", (addr ^ 077777) + 1); + else + fprintf (of, "%o", addr); + } + if (reg) { + if (! addr) + fprintf (of, " "); + fprintf (of, "(%o)", reg); + } } /* @@ -438,185 +438,185 @@ void besm6_fprint_cmd (FILE *of, uint32 cmd) */ void besm6_fprint_insn (FILE *of, uint32 insn) { - if (insn & BBIT(20)) - fprintf (of, "%02o %02o %05o ", - insn >> 20, (insn >> 15) & 037, insn & BITS(15)); - else - fprintf (of, "%02o %03o %04o ", - insn >> 20, (insn >> 12) & 0177, insn & 07777); + if (insn & BBIT(20)) + fprintf (of, "%02o %02o %05o ", + insn >> 20, (insn >> 15) & 037, insn & BITS(15)); + else + fprintf (of, "%02o %03o %04o ", + insn >> 20, (insn >> 12) & 0177, insn & 07777); } /* * Symbolic decode * * Inputs: - * *of = output stream - * addr = current PC - * *val = pointer to data - * *uptr = pointer to unit - * sw = switches + * *of = output stream + * addr = current PC + * *val = pointer to data + * *uptr = pointer to unit + * sw = switches * Outputs: - * return = status code + * return = status code */ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) + UNIT *uptr, int32 sw) { - t_value cmd; + t_value cmd; - if (uptr && (uptr != &cpu_unit)) /* must be CPU */ - return SCPE_ARG; + if (uptr && (uptr != &cpu_unit)) /* must be CPU */ + return SCPE_ARG; - cmd = val[0]; + cmd = val[0]; - if (sw & SWMASK ('M')) { /* symbolic decode? */ - if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR)) - fprintf (of, "-> "); - besm6_fprint_cmd (of, cmd >> 24); - if (sw & SIM_SW_STOP) /* stop point */ - fprintf (of, ", "); - else - fprintf (of, ",\n\t"); - if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR)) - fprintf (of, "-> "); - besm6_fprint_cmd (of, cmd & BITS(24)); + if (sw & SWMASK ('M')) { /* symbolic decode? */ + if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR)) + fprintf (of, "-> "); + besm6_fprint_cmd (of, cmd >> 24); + if (sw & SIM_SW_STOP) /* stop point */ + fprintf (of, ", "); + else + fprintf (of, ",\n\t"); + if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR)) + fprintf (of, "-> "); + besm6_fprint_cmd (of, cmd & BITS(24)); - } else if (sw & SWMASK ('I')) { - besm6_fprint_insn (of, (cmd >> 24) & BITS(24)); - besm6_fprint_insn (of, cmd & BITS(24)); - } else if (sw & SWMASK ('F')) { - fprintf (of, "%#.2g", besm6_to_ieee(cmd)); - } else if (sw & SWMASK ('B')) { - fprintf (of, "%03o %03o %03o %03o %03o %03o", - (int) (cmd >> 40) & 0377, - (int) (cmd >> 32) & 0377, - (int) (cmd >> 24) & 0377, - (int) (cmd >> 16) & 0377, - (int) (cmd >> 8) & 0377, - (int) cmd & 0377); - } else if (sw & SWMASK ('X')) { - fprintf (of, "%013llx", cmd); - } else - fprintf (of, "%04o %04o %04o %04o", - (int) (cmd >> 36) & 07777, - (int) (cmd >> 24) & 07777, - (int) (cmd >> 12) & 07777, - (int) cmd & 07777); - return SCPE_OK; + } else if (sw & SWMASK ('I')) { + besm6_fprint_insn (of, (cmd >> 24) & BITS(24)); + besm6_fprint_insn (of, cmd & BITS(24)); + } else if (sw & SWMASK ('F')) { + fprintf (of, "%#.2g", besm6_to_ieee(cmd)); + } else if (sw & SWMASK ('B')) { + fprintf (of, "%03o %03o %03o %03o %03o %03o", + (int) (cmd >> 40) & 0377, + (int) (cmd >> 32) & 0377, + (int) (cmd >> 24) & 0377, + (int) (cmd >> 16) & 0377, + (int) (cmd >> 8) & 0377, + (int) cmd & 0377); + } else if (sw & SWMASK ('X')) { + fprintf (of, "%013llx", cmd); + } else + fprintf (of, "%04o %04o %04o %04o", + (int) (cmd >> 36) & 07777, + (int) (cmd >> 24) & 07777, + (int) (cmd >> 12) & 07777, + (int) cmd & 07777); + return SCPE_OK; } /* * Symbolic input * * Inputs: - * *cptr = pointer to input string - * addr = current PC - * *uptr = pointer to unit - * *val = pointer to output values - * sw = switches + * *cptr = pointer to input string + * addr = current PC + * *uptr = pointer to unit + * *val = pointer to output values + * sw = switches * Outputs: - * status = error status + * status = error status */ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { - int32 i; + int32 i; - if (uptr && (uptr != &cpu_unit)) /* must be CPU */ - return SCPE_ARG; - if (! parse_instruction_word (cptr, val)) /* symbolic parse? */ - return SCPE_OK; + if (uptr && (uptr != &cpu_unit)) /* must be CPU */ + return SCPE_ARG; + if (! parse_instruction_word (cptr, val)) /* symbolic parse? */ + return SCPE_OK; - val[0] = 0; - for (i=0; i<16; i++) { - if (*cptr < '0' || *cptr > '7') - break; - val[0] = (val[0] << 3) | (*cptr - '0'); - cptr = skip_spaces (cptr+1); /* next char */ - } - if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { - /*printf ("Extra symbols at eoln: %s\n", cptr);*/ - return SCPE_2MARG; - } - return SCPE_OK; + val[0] = 0; + for (i=0; i<16; i++) { + if (*cptr < '0' || *cptr > '7') + break; + val[0] = (val[0] << 3) | (*cptr - '0'); + cptr = skip_spaces (cptr+1); /* next char */ + } + if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') { + /*printf ("Extra symbols at eoln: %s\n", cptr);*/ + return SCPE_2MARG; + } + return SCPE_OK; } /* * Чтение строки входного файла. * Форматы строк: - * п 76543 - адрес пуска - * в 12345 - адрес ввода - * ч -123.45e+6 - вещественное число - * с 0123 4567 0123 4567 - восьмеричное слово - * к 00 22 00000 00 010 0000 - команды + * п 76543 - адрес пуска + * в 12345 - адрес ввода + * ч -123.45e+6 - вещественное число + * с 0123 4567 0123 4567 - восьмеричное слово + * к 00 22 00000 00 010 0000 - команды */ t_stat besm6_read_line (FILE *input, int *type, t_value *val) { - char buf [512], *p; - int i, c; -again: - if (! fgets (buf, sizeof (buf), input)) { - *type = 0; - return SCPE_OK; - } - p = skip_spaces (buf); - if (*p == '\n' || *p == ';') - goto again; - c = utf8_to_unicode (&p); - if (c == CYRILLIC_SMALL_LETTER_VE || - c == CYRILLIC_CAPITAL_LETTER_VE || - c == 'b' || c == 'B') { - /* Адрес размещения данных. */ - *type = ':'; - *val = strtol (p, 0, 8); - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_PE || - c == CYRILLIC_CAPITAL_LETTER_PE || - c == 'p' || c == 'P') { - /* Стартовый адрес. */ - *type = '@'; - *val = strtol (p, 0, 8); - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_CHE || - c == CYRILLIC_CAPITAL_LETTER_CHE || - c == 'f' || c == 'F') { - /* Вещественное число. */ - *type = '='; - *val = ieee_to_besm6 (strtod (p, 0)); - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_ES || - c == CYRILLIC_CAPITAL_LETTER_ES || - c == 'c' || c == 'C') { - /* Восьмеричное слово. */ - *type = '='; - *val = 0; - for (i=0; i<16; ++i) { - p = skip_spaces (p); - if (*p < '0' || *p > '7') { - if (i == 0) { - /* слишком короткое слово */ - goto bad; - } - break; - } - *val = *val << 3 | (*p++ - '0'); - } - return SCPE_OK; - } - if (c == CYRILLIC_SMALL_LETTER_KA || - c == CYRILLIC_CAPITAL_LETTER_KA || - c == 'k' || c == 'K') { - /* Команда. */ - *type = '*'; - if (parse_instruction_word (p, val) != SCPE_OK) - goto bad; - return SCPE_OK; - } - /* Неверная строка входного файла */ -bad: besm6_log ("Invalid input line: %s", buf); - return SCPE_FMT; + char buf [512], *p; + int i, c; + again: + if (! fgets (buf, sizeof (buf), input)) { + *type = 0; + return SCPE_OK; + } + p = skip_spaces (buf); + if (*p == '\n' || *p == ';') + goto again; + c = utf8_to_unicode (&p); + if (c == CYRILLIC_SMALL_LETTER_VE || + c == CYRILLIC_CAPITAL_LETTER_VE || + c == 'b' || c == 'B') { + /* Адрес размещения данных. */ + *type = ':'; + *val = strtol (p, 0, 8); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_PE || + c == CYRILLIC_CAPITAL_LETTER_PE || + c == 'p' || c == 'P') { + /* Стартовый адрес. */ + *type = '@'; + *val = strtol (p, 0, 8); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_CHE || + c == CYRILLIC_CAPITAL_LETTER_CHE || + c == 'f' || c == 'F') { + /* Вещественное число. */ + *type = '='; + *val = ieee_to_besm6 (strtod (p, 0)); + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_ES || + c == CYRILLIC_CAPITAL_LETTER_ES || + c == 'c' || c == 'C') { + /* Восьмеричное слово. */ + *type = '='; + *val = 0; + for (i=0; i<16; ++i) { + p = skip_spaces (p); + if (*p < '0' || *p > '7') { + if (i == 0) { + /* слишком короткое слово */ + goto bad; + } + break; + } + *val = *val << 3 | (*p++ - '0'); + } + return SCPE_OK; + } + if (c == CYRILLIC_SMALL_LETTER_KA || + c == CYRILLIC_CAPITAL_LETTER_KA || + c == 'k' || c == 'K') { + /* Команда. */ + *type = '*'; + if (parse_instruction_word (p, val) != SCPE_OK) + goto bad; + return SCPE_OK; + } + /* Неверная строка входного файла */ + bad: besm6_log ("Invalid input line: %s", buf); + return SCPE_FMT; } /* @@ -624,44 +624,44 @@ bad: besm6_log ("Invalid input line: %s", buf); */ t_stat besm6_load (FILE *input) { - int addr, type; - t_value word; - t_stat err; + int addr, type; + t_value word; + t_stat err; - addr = 1; - PC = 1; - for (;;) { - err = besm6_read_line (input, &type, &word); - if (err) - return err; - switch (type) { - case 0: /* EOF */ - return SCPE_OK; - case ':': /* address */ - addr = word; - break; - case '=': /* word */ - if (addr < 010) - pult [addr] = SET_CONVOL (word, CONVOL_NUMBER); - else - memory [addr] = SET_CONVOL (word, CONVOL_NUMBER); - ++addr; - break; - case '*': /* instruction */ - if (addr < 010) - pult [addr] = SET_CONVOL (word, CONVOL_INSN); - else - memory [addr] = SET_CONVOL (word, CONVOL_INSN); - ++addr; - break; - case '@': /* start address */ - PC = word; - break; - } - if (addr > MEMSIZE) - return SCPE_FMT; - } - return SCPE_OK; + addr = 1; + PC = 1; + for (;;) { + err = besm6_read_line (input, &type, &word); + if (err) + return err; + switch (type) { + case 0: /* EOF */ + return SCPE_OK; + case ':': /* address */ + addr = word; + break; + case '=': /* word */ + if (addr < 010) + pult [addr] = SET_CONVOL (word, CONVOL_NUMBER); + else + memory [addr] = SET_CONVOL (word, CONVOL_NUMBER); + ++addr; + break; + case '*': /* instruction */ + if (addr < 010) + pult [addr] = SET_CONVOL (word, CONVOL_INSN); + else + memory [addr] = SET_CONVOL (word, CONVOL_INSN); + ++addr; + break; + case '@': /* start address */ + PC = word; + break; + } + if (addr > MEMSIZE) + return SCPE_FMT; + } + return SCPE_OK; } /* @@ -669,42 +669,42 @@ t_stat besm6_load (FILE *input) */ t_stat besm6_dump (FILE *of, char *fnam) { - int addr, last_addr = -1; - t_value word; + int addr, last_addr = -1; + t_value word; - fprintf (of, "; %s\n", fnam); - for (addr=1; addr> 24); - fprintf (of, ", "); - besm6_fprint_cmd (of, word & BITS(24)); - fprintf (of, "\t\t; %05o - ", addr); - fprintf (of, "%04o %04o %04o %04o\n", - (int) (word >> 36) & 07777, - (int) (word >> 24) & 07777, - (int) (word >> 12) & 07777, - (int) word & 07777); - } else { - fprintf (of, "с %04o %04o %04o %04o", - (int) (word >> 36) & 07777, - (int) (word >> 24) & 07777, - (int) (word >> 12) & 07777, - (int) word & 07777); - fprintf (of, "\t\t; %05o\n", addr); - } - } - return SCPE_OK; + fprintf (of, "; %s\n", fnam); + for (addr=1; addr> 24); + fprintf (of, ", "); + besm6_fprint_cmd (of, word & BITS(24)); + fprintf (of, "\t\t; %05o - ", addr); + fprintf (of, "%04o %04o %04o %04o\n", + (int) (word >> 36) & 07777, + (int) (word >> 24) & 07777, + (int) (word >> 12) & 07777, + (int) word & 07777); + } else { + fprintf (of, "с %04o %04o %04o %04o", + (int) (word >> 36) & 07777, + (int) (word >> 24) & 07777, + (int) (word >> 12) & 07777, + (int) word & 07777); + fprintf (of, "\t\t; %05o\n", addr); + } + } + return SCPE_OK; } /* @@ -712,8 +712,8 @@ t_stat besm6_dump (FILE *of, char *fnam) */ t_stat sim_load (FILE *fi, char *cptr, char *fnam, int dump_flag) { - if (dump_flag) - return besm6_dump (fi, fnam); + if (dump_flag) + return besm6_dump (fi, fnam); - return besm6_load (fi); + return besm6_load (fi); } diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 9d37e23f..14ea236e 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -19,41 +19,41 @@ #include "sim_tmxr.h" #include -#define TTY_MAX 24 /* Количество последовательных терминалов */ -#define LINES_MAX TTY_MAX + 2 /* Включая параллельные интерфейсы "Консулов" */ +#define TTY_MAX 24 /* Количество последовательных терминалов */ +#define LINES_MAX TTY_MAX + 2 /* Включая параллельные интерфейсы "Консулов" */ /* * Согласно таблице в http://ru.wikipedia.org/wiki/МТК-2 */ char * rus[] = { 0, "Т", "\r", "О", " ", "Х", "Н", "М", "\n", "Л", "Р", "Г", "И", "П", "Ц", "Ж", - "Е", "З", "Д", "Б", "С", "Ы", "Ф", "Ь", "А", "В", "Й", 0, "У", "Я", "К", 0 }; + "Е", "З", "Д", "Б", "С", "Ы", "Ф", "Ь", "А", "В", "Й", 0, "У", "Я", "К", 0 }; char * lat[] = { 0, "T", "\r", "O", " ", "H", "N", "M", "\n", "L", "R", "G", "I", "P", "C", "V", - "E", "Z", "D", "B", "S", "Y", "F", "X", "A", "W", "J", 0, "U", "Q", "K", 0 }; + "E", "Z", "D", "B", "S", "Y", "F", "X", "A", "W", "J", 0, "U", "Q", "K", 0 }; /* $ = Кто там? */ char * dig[] = { 0, "5", "\r", "9", " ", "Щ", ",", ".", "\n", ")", "4", "Ш", "8", "0", ":", "=", - "3", "+", "$", "?", "'", "6", "Э", "/", "-", "2", "Ю", 0, "7", "1", "(", 0 }; + "3", "+", "$", "?", "'", "6", "Э", "/", "-", "2", "Ю", 0, "7", "1", "(", 0 }; char ** reg = 0; char * process (int sym) { - /* Требуется инверсия */ - sym ^= 31; - switch (sym) { - case 0: - reg = rus; - break; - case 27: - reg = dig; - break; - case 31: - reg = lat; - break; - default: - return reg[sym]; - } - return ""; + /* Требуется инверсия */ + sym ^= 31; + switch (sym) { + case 0: + reg = rus; + break; + case 27: + reg = dig; + break; + case 31: + reg = lat; + break; + default: + return reg[sym]; + } + return ""; } /* Только для последовательных линий */ @@ -84,39 +84,39 @@ t_stat vt_clk(UNIT *); extern char *get_sim_sw (char *cptr); UNIT tty_unit [] = { - { UDATA (vt_clk, UNIT_DIS, 0) }, /* fake unit, clock */ - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - /* The next two units are parallel interface */ - { UDATA (NULL, UNIT_SEQ, 0) }, - { UDATA (NULL, UNIT_SEQ, 0) }, - { 0 } + { UDATA (vt_clk, UNIT_DIS, 0) }, /* fake unit, clock */ + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + /* The next two units are parallel interface */ + { UDATA (NULL, UNIT_SEQ, 0) }, + { UDATA (NULL, UNIT_SEQ, 0) }, + { 0 } }; REG tty_reg[] = { - { 0 } + { 0 } }; /* @@ -129,268 +129,268 @@ REG tty_reg[] = { * Для локальных терминалов оно равно 0. */ TMLN tty_line [LINES_MAX+1]; -TMXR tty_desc = { LINES_MAX+1, 0, 0, tty_line }; /* mux descriptor */ +TMXR tty_desc = { LINES_MAX+1, 0, 0, tty_line }; /* mux descriptor */ -#define TTY_UNICODE_CHARSET 0 -#define TTY_KOI7_JCUKEN_CHARSET (1<>= 1)) { - tt_print(); - /* Прием не реализован */ - clk_divider = 1<<29; - } + if (! (clk_divider >>= 1)) { + tt_print(); + /* Прием не реализован */ + clk_divider = 1<<29; + } - /* Есть новые сетевые подключения? */ - int num = tmxr_poll_conn (&tty_desc); - if (num > 0 && num <= LINES_MAX) { - char buf [80]; - TMLN *t = &tty_line [num]; - besm6_debug ("*** tty%d: новое подключение от %s", - num, t->ipad); - t->rcve = 1; - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_VT340_STATE; - if (num <= TTY_MAX) - vt_mask |= 1 << (TTY_MAX - num); + /* Есть новые сетевые подключения? */ + int num = tmxr_poll_conn (&tty_desc); + if (num > 0 && num <= LINES_MAX) { + char buf [80]; + TMLN *t = &tty_line [num]; + besm6_debug ("*** tty%d: новое подключение от %s", + num, t->ipad); + t->rcve = 1; + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_VT340_STATE; + if (num <= TTY_MAX) + vt_mask |= 1 << (TTY_MAX - num); - switch (tty_unit[num].flags & TTY_CHARSET_MASK) { - case TTY_KOI7_JCUKEN_CHARSET: - tmxr_linemsg (t, "Encoding is KOI-7 (jcuken)\r\n"); - break; - case TTY_KOI7_QWERTY_CHARSET: - tmxr_linemsg (t, "Encoding is KOI-7 (qwerty)\r\n"); - break; - case TTY_UNICODE_CHARSET: - tmxr_linemsg (t, "Encoding is UTF-8\r\n"); - break; - } - tty_idle_count[num] = 0; - tty_last_time[num] = time (0); - sprintf (buf, "%.24s from %s\r\n", - ctime (&tty_last_time[num]), - t->ipad); - tmxr_linemsg (t, buf); + switch (tty_unit[num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + tmxr_linemsg (t, "Encoding is KOI-7 (jcuken)\r\n"); + break; + case TTY_KOI7_QWERTY_CHARSET: + tmxr_linemsg (t, "Encoding is KOI-7 (qwerty)\r\n"); + break; + case TTY_UNICODE_CHARSET: + tmxr_linemsg (t, "Encoding is UTF-8\r\n"); + break; + } + tty_idle_count[num] = 0; + tty_last_time[num] = time (0); + sprintf (buf, "%.24s from %s\r\n", + ctime (&tty_last_time[num]), + t->ipad); + tmxr_linemsg (t, buf); - /* Ввод ^C, чтобы получить приглашение. */ - t->rxb [t->rxbpi++] = '\3'; - } + /* Ввод ^C, чтобы получить приглашение. */ + t->rxb [t->rxbpi++] = '\3'; + } - /* Опрашиваем сокеты на передачу. */ - tmxr_poll_tx (&tty_desc); + /* Опрашиваем сокеты на передачу. */ + tmxr_poll_tx (&tty_desc); - return sim_activate (this, 1000*MSEC/300); + return sim_activate (this, 1000*MSEC/300); } t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) { - int num = u - tty_unit; - TMLN *t = &tty_line [num]; - uint32 mask = 1 << (TTY_MAX - num); + int num = u - tty_unit; + TMLN *t = &tty_line [num]; + uint32 mask = 1 << (TTY_MAX - num); - switch (val & TTY_STATE_MASK) { - case TTY_OFFLINE_STATE: - if (t->conn) { - if (t->rcve) { - tmxr_reset_ln (t); - t->rcve = 0; - } else - t->conn = 0; - if (num <= TTY_MAX) { - tty_sym[num] = - tty_active[num] = - tty_typed[num] = - tty_instate[num] = 0; - vt_mask &= ~mask; - tt_mask &= ~mask; - } - } - break; - case TTY_TELETYPE_STATE: - if (num > TTY_MAX) - return SCPE_NXPAR; - t->conn = 1; - t->rcve = 0; - tt_mask |= mask; - vt_mask &= ~mask; - break; - case TTY_VT340_STATE: - t->conn = 1; - t->rcve = 0; - if (num <= TTY_MAX) { - vt_mask |= mask; - tt_mask &= ~mask; - } - break; - case TTY_CONSUL_STATE: - if (num <= TTY_MAX) - return SCPE_NXPAR; - t->conn = 1; - t->rcve = 0; - break; - } - return SCPE_OK; + switch (val & TTY_STATE_MASK) { + case TTY_OFFLINE_STATE: + if (t->conn) { + if (t->rcve) { + tmxr_reset_ln (t); + t->rcve = 0; + } else + t->conn = 0; + if (num <= TTY_MAX) { + tty_sym[num] = + tty_active[num] = + tty_typed[num] = + tty_instate[num] = 0; + vt_mask &= ~mask; + tt_mask &= ~mask; + } + } + break; + case TTY_TELETYPE_STATE: + if (num > TTY_MAX) + return SCPE_NXPAR; + t->conn = 1; + t->rcve = 0; + tt_mask |= mask; + vt_mask &= ~mask; + break; + case TTY_VT340_STATE: + t->conn = 1; + t->rcve = 0; + if (num <= TTY_MAX) { + vt_mask |= mask; + tt_mask &= ~mask; + } + break; + case TTY_CONSUL_STATE: + if (num <= TTY_MAX) + return SCPE_NXPAR; + t->conn = 1; + t->rcve = 0; + break; + } + return SCPE_OK; } /* * Разрешение подключения к терминалам через telnet. * Делается командой: - * attach tty <порт> + * attach tty <порт> * Здесь <порт> - номер порта telnet, например 4199. */ t_stat tty_attach (UNIT *u, char *cptr) { - int num = u - tty_unit; - int r, m, n; + int num = u - tty_unit; + int r, m, n; - if (*cptr >= '0' && *cptr <= '9') { - /* Сохраняем и восстанавливаем все .conn, - * так как tmxr_attach() их обнуляет. */ - for (m=0, n=1; n<=LINES_MAX; ++n) - if (tty_line[n].conn) - m |= 1 << (LINES_MAX-n); - /* Неважно, какой номер порта указывать в команде задания - * порта telnet. Можно tty, можно tty1 - без разницы. */ - r = tmxr_attach (&tty_desc, &tty_unit[0], cptr); - for (n=1; n<=LINES_MAX; ++n) - if (m >> (LINES_MAX-n) & 1) - tty_line[n].conn = 1; - return r; - } - if (strcmp (cptr, "/dev/tty") == 0) { - /* Консоль. */ - u->flags &= ~TTY_STATE_MASK; - u->flags |= TTY_VT340_STATE; - tty_line[num].conn = 1; - tty_line[num].rcve = 0; - if (num <= TTY_MAX) - vt_mask |= 1 << (TTY_MAX - num); - besm6_debug ("*** консоль на T%03o", num); - return 0; - } - if (strcmp (cptr, "/dev/null") == 0) { - /* Запрещаем терминал. */ - tty_line[num].conn = 1; - tty_line[num].rcve = 0; - if (num <= TTY_MAX) { - vt_mask &= ~(1 << (TTY_MAX - num)); - tt_mask &= ~(1 << (TTY_MAX - num)); - } - besm6_debug ("*** отключение терминала T%03o", num); - return 0; - } - return SCPE_ALATT; + if (*cptr >= '0' && *cptr <= '9') { + /* Сохраняем и восстанавливаем все .conn, + * так как tmxr_attach() их обнуляет. */ + for (m=0, n=1; n<=LINES_MAX; ++n) + if (tty_line[n].conn) + m |= 1 << (LINES_MAX-n); + /* Неважно, какой номер порта указывать в команде задания + * порта telnet. Можно tty, можно tty1 - без разницы. */ + r = tmxr_attach (&tty_desc, &tty_unit[0], cptr); + for (n=1; n<=LINES_MAX; ++n) + if (m >> (LINES_MAX-n) & 1) + tty_line[n].conn = 1; + return r; + } + if (strcmp (cptr, "/dev/tty") == 0) { + /* Консоль. */ + u->flags &= ~TTY_STATE_MASK; + u->flags |= TTY_VT340_STATE; + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) + vt_mask |= 1 << (TTY_MAX - num); + besm6_debug ("*** консоль на T%03o", num); + return 0; + } + if (strcmp (cptr, "/dev/null") == 0) { + /* Запрещаем терминал. */ + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) { + vt_mask &= ~(1 << (TTY_MAX - num)); + tt_mask &= ~(1 << (TTY_MAX - num)); + } + besm6_debug ("*** отключение терминала T%03o", num); + return 0; + } + return SCPE_ALATT; } t_stat tty_detach (UNIT *u) { - return tmxr_detach (&tty_desc, &tty_unit[0]); + return tmxr_detach (&tty_desc, &tty_unit[0]); } /* * Управление терминалами. - * set ttyN unicode - выбор кодировки UTF-8 - * set ttyN jcuken - выбор кодировки КОИ-7, раскладка йцукен - * set ttyN qwerty - выбор кодировки КОИ-7, раскладка яверты - * set ttyN off - отключение - * set ttyN tt - установка типа терминала "Телетайп" - * set ttyN vt - установка типа терминала "Видеотон-340" - * set ttyN consul - установка типа терминала "Consul-254" - * set ttyN destrbs - "стирающий" backspace - * set ttyN authbs - классический backspace - * set tty disconnect=N - принудительное завершение сеанса telnet - * show tty - просмотр режимов терминалов - * show tty connections - просмотр IP-адресов и времени соединений - * show tty statistics - просмотр счетчиков переданных и принятых байтов + * set ttyN unicode - выбор кодировки UTF-8 + * set ttyN jcuken - выбор кодировки КОИ-7, раскладка йцукен + * set ttyN qwerty - выбор кодировки КОИ-7, раскладка яверты + * set ttyN off - отключение + * set ttyN tt - установка типа терминала "Телетайп" + * set ttyN vt - установка типа терминала "Видеотон-340" + * set ttyN consul - установка типа терминала "Consul-254" + * set ttyN destrbs - "стирающий" backspace + * set ttyN authbs - классический backspace + * set tty disconnect=N - принудительное завершение сеанса telnet + * show tty - просмотр режимов терминалов + * show tty connections - просмотр IP-адресов и времени соединений + * show tty statistics - просмотр счетчиков переданных и принятых байтов */ MTAB tty_mod[] = { - { TTY_CHARSET_MASK, TTY_UNICODE_CHARSET, "UTF-8 input", - "UNICODE" }, - { TTY_CHARSET_MASK, TTY_KOI7_JCUKEN_CHARSET, "KOI7 (jcuken) input", - "JCUKEN" }, - { TTY_CHARSET_MASK, TTY_KOI7_QWERTY_CHARSET, "KOI7 (qwerty) input", - "QWERTY" }, - { TTY_STATE_MASK, TTY_OFFLINE_STATE, "offline", - "OFF", &tty_setmode }, - { TTY_STATE_MASK, TTY_TELETYPE_STATE, "Teletype", - "TT", &tty_setmode }, - { TTY_STATE_MASK, TTY_VT340_STATE, "Videoton-340", - "VT", &tty_setmode }, - { TTY_STATE_MASK, TTY_CONSUL_STATE, "Consul-254", - "CONSUL", &tty_setmode }, - { TTY_BSPACE_MASK, TTY_DESTRUCTIVE_BSPACE, "destructive backspace", - "DESTRBS" }, - { TTY_BSPACE_MASK, TTY_AUTHENTIC_BSPACE, NULL, - "AUTHBS" }, - { MTAB_XTD | MTAB_VDV, 1, NULL, - "DISCONNECT", &tmxr_dscln, NULL, (void*) &tty_desc }, - { UNIT_ATT, UNIT_ATT, "connections", - NULL, NULL, &tmxr_show_summ, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", - NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", - NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, - "LOG", &tmxr_set_log, &tmxr_show_log, (void*) &tty_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, - "NOLOG", &tmxr_set_nolog, NULL, (void*) &tty_desc }, - { 0 } + { TTY_CHARSET_MASK, TTY_UNICODE_CHARSET, "UTF-8 input", + "UNICODE" }, + { TTY_CHARSET_MASK, TTY_KOI7_JCUKEN_CHARSET, "KOI7 (jcuken) input", + "JCUKEN" }, + { TTY_CHARSET_MASK, TTY_KOI7_QWERTY_CHARSET, "KOI7 (qwerty) input", + "QWERTY" }, + { TTY_STATE_MASK, TTY_OFFLINE_STATE, "offline", + "OFF", &tty_setmode }, + { TTY_STATE_MASK, TTY_TELETYPE_STATE, "Teletype", + "TT", &tty_setmode }, + { TTY_STATE_MASK, TTY_VT340_STATE, "Videoton-340", + "VT", &tty_setmode }, + { TTY_STATE_MASK, TTY_CONSUL_STATE, "Consul-254", + "CONSUL", &tty_setmode }, + { TTY_BSPACE_MASK, TTY_DESTRUCTIVE_BSPACE, "destructive backspace", + "DESTRBS" }, + { TTY_BSPACE_MASK, TTY_AUTHENTIC_BSPACE, NULL, + "AUTHBS" }, + { MTAB_XTD | MTAB_VDV, 1, NULL, + "DISCONNECT", &tmxr_dscln, NULL, (void*) &tty_desc }, + { UNIT_ATT, UNIT_ATT, "connections", + NULL, NULL, &tmxr_show_summ, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", + NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", + NULL, NULL, &tmxr_show_cstat, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, + "LOG", &tmxr_set_log, &tmxr_show_log, (void*) &tty_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, + "NOLOG", &tmxr_set_nolog, NULL, (void*) &tty_desc }, + { 0 } }; DEVICE tty_dev = { - "TTY", tty_unit, tty_reg, tty_mod, - 27, 2, 1, 1, 2, 1, - NULL, NULL, &tty_reset, NULL, &tty_attach, &tty_detach, - NULL, DEV_NET|DEV_DEBUG + "TTY", tty_unit, tty_reg, tty_mod, + 27, 2, 1, 1, 2, 1, + NULL, NULL, &tty_reset, NULL, &tty_attach, &tty_detach, + NULL, DEV_NET|DEV_DEBUG }; void tty_send (uint32 mask) { - /* besm6_debug ("*** телетайпы: передача %08o", mask); */ + /* besm6_debug ("*** телетайпы: передача %08o", mask); */ - TTY_OUT = mask; + TTY_OUT = mask; } /* @@ -398,23 +398,23 @@ void tty_send (uint32 mask) */ void vt_putc (int num, int c) { - TMLN *t = &tty_line [num]; + TMLN *t = &tty_line [num]; - if (! t->conn) - return; - if (t->rcve) { - /* Передача через telnet. */ - tmxr_putc_ln (t, c); - } else { - /* Вывод на консоль. */ - if (t->txlog) { /* log if available */ - fputc (c, t->txlog); - if (c == '\n') - fflush (t->txlog); - } - fputc (c, stdout); - fflush (stdout); - } + if (! t->conn) + return; + if (t->rcve) { + /* Передача через telnet. */ + tmxr_putc_ln (t, c); + } else { + /* Вывод на консоль. */ + if (t->txlog) { /* log if available */ + fputc (c, t->txlog); + if (c == '\n') + fflush (t->txlog); + } + fputc (c, stdout); + fflush (stdout); + } } /* @@ -422,98 +422,98 @@ void vt_putc (int num, int c) */ void vt_puts (int num, const char *s) { - TMLN *t = &tty_line [num]; + TMLN *t = &tty_line [num]; - if (! t->conn) - return; - if (t->rcve) { - /* Передача через telnet. */ - tmxr_linemsg (t, (char*) s); - } else { - /* Вывод на консоль. */ - if (t->txlog) /* log if available */ - fputs (s, t->txlog); - fputs (s, stdout); - fflush (stdout); - } + if (! t->conn) + return; + if (t->rcve) { + /* Передача через telnet. */ + tmxr_linemsg (t, (char*) s); + } else { + /* Вывод на консоль. */ + if (t->txlog) /* log if available */ + fputs (s, t->txlog); + fputs (s, stdout); + fflush (stdout); + } } const char * koi7_rus_to_unicode [32] = { - "Ю", "А", "Б", "Ц", "Д", "Е", "Ф", "Г", - "Х", "И", "Й", "К", "Л", "М", "Н", "О", - "П", "Я", "Р", "С", "Т", "У", "Ж", "В", - "Ь", "Ы", "З", "Ш", "Э", "Щ", "Ч", "\0x7f", + "Ю", "А", "Б", "Ц", "Д", "Е", "Ф", "Г", + "Х", "И", "Й", "К", "Л", "М", "Н", "О", + "П", "Я", "Р", "С", "Т", "У", "Ж", "В", + "Ь", "Ы", "З", "Ш", "Э", "Щ", "Ч", "\0x7f", }; void vt_send(int num, uint32 sym, int destructive_bs) { - if (sym < 0x60) { - switch (sym) { - case '\031': - /* Up */ - vt_puts (num, "\033["); - sym = 'A'; - break; - case '\032': - /* Down */ - vt_puts (num, "\033["); - sym = 'B'; - break; - case '\030': - /* Right */ - vt_puts (num, "\033["); - sym = 'C'; - break; - case '\b': - /* Left */ - vt_puts (num, "\033["); - if (destructive_bs) { - /* Стираем предыдущий символ. */ - vt_puts (num, "D \033["); - } - sym = 'D'; - break; - case '\v': - case '\033': - case '\0': - /* Выдаём управляющий символ. */ - break; - case '\037': - /* Очистка экрана */ - vt_puts (num, "\033[H\033["); - sym = 'J'; - break; - case '\n': - /* На VDT-340 также возвращал курсор в 1-ю позицию */ - vt_putc (num, '\r'); - sym = '\n'; - break; - case '\f': - /* Сообщение ERR при нажатии некоторых управляющих - * клавиш выдается с использованием reverse wraparound. - */ - vt_puts(num, "\033["); - sym = 'H'; - break; - case '\r': - case '\003': - /* Неотображаемые символы */ - sym = 0; - break; - default: - if (sym < ' ') { - /* Нефункциональные ctrl-символы были видны в половинной яркости */ - vt_puts (num, "\033[2m"); - vt_putc (num, sym | 0x40); - vt_puts (num, "\033["); - /* Завершаем ESC-последовательность */ - sym = 'm'; - } - } - if (sym) - vt_putc (num, sym); - } else - vt_puts (num, koi7_rus_to_unicode[sym - 0x60]); + if (sym < 0x60) { + switch (sym) { + case '\031': + /* Up */ + vt_puts (num, "\033["); + sym = 'A'; + break; + case '\032': + /* Down */ + vt_puts (num, "\033["); + sym = 'B'; + break; + case '\030': + /* Right */ + vt_puts (num, "\033["); + sym = 'C'; + break; + case '\b': + /* Left */ + vt_puts (num, "\033["); + if (destructive_bs) { + /* Стираем предыдущий символ. */ + vt_puts (num, "D \033["); + } + sym = 'D'; + break; + case '\v': + case '\033': + case '\0': + /* Выдаём управляющий символ. */ + break; + case '\037': + /* Очистка экрана */ + vt_puts (num, "\033[H\033["); + sym = 'J'; + break; + case '\n': + /* На VDT-340 также возвращал курсор в 1-ю позицию */ + vt_putc (num, '\r'); + sym = '\n'; + break; + case '\f': + /* Сообщение ERR при нажатии некоторых управляющих + * клавиш выдается с использованием reverse wraparound. + */ + vt_puts(num, "\033["); + sym = 'H'; + break; + case '\r': + case '\003': + /* Неотображаемые символы */ + sym = 0; + break; + default: + if (sym < ' ') { + /* Нефункциональные ctrl-символы были видны в половинной яркости */ + vt_puts (num, "\033[2m"); + vt_putc (num, sym | 0x40); + vt_puts (num, "\033["); + /* Завершаем ESC-последовательность */ + sym = 'm'; + } + } + if (sym) + vt_putc (num, sym); + } else + vt_puts (num, koi7_rus_to_unicode[sym - 0x60]); } /* @@ -521,47 +521,47 @@ void vt_send(int num, uint32 sym, int destructive_bs) */ void vt_print() { - uint32 workset = (TTY_OUT & vt_mask) | vt_sending; - int num; + uint32 workset = (TTY_OUT & vt_mask) | vt_sending; + int num; - if (workset == 0) { - ++vt_idle; - return; - } - for (num = besm6_highest_bit (workset) - TTY_MAX; - workset; num = besm6_highest_bit (workset) - TTY_MAX) { - int mask = 1 << (TTY_MAX - num); - int c = (TTY_OUT & mask) != 0; - switch (tty_active[num]*2+c) { - case 0: /* idle */ - besm6_debug ("Warning: inactive ttys should have been screened"); - continue; - case 1: /* start bit */ - vt_sending |= mask; - tty_active[num] = 1; - break; - case 18: /* stop bit */ - tty_sym[num] = ~tty_sym[num] & 0x7f; - vt_send (num, tty_sym[num], - (tty_unit[num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); - tty_active[num] = 0; - tty_sym[num] = 0; - vt_sending &= ~mask; - break; - case 19: /* framing error */ - vt_putc (num, '#'); - break; - default: - /* little endian ordering */ - if (c) { - tty_sym[num] |= 1 << (tty_active[num]-1); - } - ++tty_active[num]; - break; - } - workset &= ~mask; - } - vt_idle = 0; + if (workset == 0) { + ++vt_idle; + return; + } + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + int mask = 1 << (TTY_MAX - num); + int c = (TTY_OUT & mask) != 0; + switch (tty_active[num]*2+c) { + case 0: /* idle */ + besm6_debug ("Warning: inactive ttys should have been screened"); + continue; + case 1: /* start bit */ + vt_sending |= mask; + tty_active[num] = 1; + break; + case 18: /* stop bit */ + tty_sym[num] = ~tty_sym[num] & 0x7f; + vt_send (num, tty_sym[num], + (tty_unit[num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); + tty_active[num] = 0; + tty_sym[num] = 0; + vt_sending &= ~mask; + break; + case 19: /* framing error */ + vt_putc (num, '#'); + break; + default: + /* little endian ordering */ + if (c) { + tty_sym[num] |= 1 << (tty_active[num]-1); + } + ++tty_active[num]; + break; + } + workset &= ~mask; + } + vt_idle = 0; } /* Ввод с телетайпа не реализован; вывод работает только при использовании @@ -569,44 +569,44 @@ void vt_print() */ void tt_print() { - uint32 workset = (TTY_OUT & tt_mask) | tt_sending; - int num; + uint32 workset = (TTY_OUT & tt_mask) | tt_sending; + int num; - if (workset == 0) { - return; - } + if (workset == 0) { + return; + } - for (num = besm6_highest_bit (workset) - TTY_MAX; - workset; num = besm6_highest_bit (workset) - TTY_MAX) { - int mask = 1 << (TTY_MAX - num); - int c = (TTY_OUT & mask) != 0; - switch (tty_active[num]*2+c) { - case 0: /* idle */ - break; - case 1: /* start bit */ - tt_sending |= mask; - tty_active[num] = 1; - break; - case 12: /* stop bit */ - vt_puts (num, process (tty_sym[num])); - tty_active[num] = 0; - tty_sym[num] = 0; - tt_sending &= ~mask; - break; - case 13: /* framing error */ - vt_putc (num, '#'); - break; - default: - /* big endian ordering */ - if (c) { - tty_sym[num] |= 1 << (5-tty_active[num]); - } - ++tty_active[num]; - break; - } - workset &= ~mask; - } - vt_idle = 0; + for (num = besm6_highest_bit (workset) - TTY_MAX; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + int mask = 1 << (TTY_MAX - num); + int c = (TTY_OUT & mask) != 0; + switch (tty_active[num]*2+c) { + case 0: /* idle */ + break; + case 1: /* start bit */ + tt_sending |= mask; + tty_active[num] = 1; + break; + case 12: /* stop bit */ + vt_puts (num, process (tty_sym[num])); + tty_active[num] = 0; + tty_sym[num] = 0; + tt_sending &= ~mask; + break; + case 13: /* framing error */ + vt_putc (num, '#'); + break; + default: + /* big endian ordering */ + if (c) { + tty_sym[num] |= 1 << (5-tty_active[num]); + } + ++tty_active[num]; + break; + } + workset &= ~mask; + } + vt_idle = 0; } /* @@ -615,43 +615,43 @@ void tt_print() */ static int unicode_to_koi7 (unsigned val) { - switch (val) { - case '\0'... '_': return val; - case 'a' ... 'z': return val + 'Z' - 'z'; - case 0x007f: return 0x7f; - case 0x0410: case 0x0430: return 0x61; - case 0x0411: case 0x0431: return 0x62; - case 0x0412: case 0x0432: return 0x77; - case 0x0413: case 0x0433: return 0x67; - case 0x0414: case 0x0434: return 0x64; - case 0x0415: case 0x0435: return 0x65; - case 0x0416: case 0x0436: return 0x76; - case 0x0417: case 0x0437: return 0x7a; - case 0x0418: case 0x0438: return 0x69; - case 0x0419: case 0x0439: return 0x6a; - case 0x041a: case 0x043a: return 0x6b; - case 0x041b: case 0x043b: return 0x6c; - case 0x041c: case 0x043c: return 0x6d; - case 0x041d: case 0x043d: return 0x6e; - case 0x041e: case 0x043e: return 0x6f; - case 0x041f: case 0x043f: return 0x70; - case 0x0420: case 0x0440: return 0x72; - case 0x0421: case 0x0441: return 0x73; - case 0x0422: case 0x0442: return 0x74; - case 0x0423: case 0x0443: return 0x75; - case 0x0424: case 0x0444: return 0x66; - case 0x0425: case 0x0445: return 0x68; - case 0x0426: case 0x0446: return 0x63; - case 0x0427: case 0x0447: return 0x7e; - case 0x0428: case 0x0448: return 0x7b; - case 0x0429: case 0x0449: return 0x7d; - case 0x042b: case 0x044b: return 0x79; - case 0x042c: case 0x044c: return 0x78; - case 0x042d: case 0x044d: return 0x7c; - case 0x042e: case 0x044e: return 0x60; - case 0x042f: case 0x044f: return 0x71; - } - return -1; + if ('_' <= val) return val; + else if ('a' <= val && val <= 'z') return val + 'Z' - 'z'; + else switch (val) { + case 0x007f: return 0x7f; + case 0x0410: case 0x0430: return 0x61; + case 0x0411: case 0x0431: return 0x62; + case 0x0412: case 0x0432: return 0x77; + case 0x0413: case 0x0433: return 0x67; + case 0x0414: case 0x0434: return 0x64; + case 0x0415: case 0x0435: return 0x65; + case 0x0416: case 0x0436: return 0x76; + case 0x0417: case 0x0437: return 0x7a; + case 0x0418: case 0x0438: return 0x69; + case 0x0419: case 0x0439: return 0x6a; + case 0x041a: case 0x043a: return 0x6b; + case 0x041b: case 0x043b: return 0x6c; + case 0x041c: case 0x043c: return 0x6d; + case 0x041d: case 0x043d: return 0x6e; + case 0x041e: case 0x043e: return 0x6f; + case 0x041f: case 0x043f: return 0x70; + case 0x0420: case 0x0440: return 0x72; + case 0x0421: case 0x0441: return 0x73; + case 0x0422: case 0x0442: return 0x74; + case 0x0423: case 0x0443: return 0x75; + case 0x0424: case 0x0444: return 0x66; + case 0x0425: case 0x0445: return 0x68; + case 0x0426: case 0x0446: return 0x63; + case 0x0427: case 0x0447: return 0x7e; + case 0x0428: case 0x0448: return 0x7b; + case 0x0429: case 0x0449: return 0x7d; + case 0x042b: case 0x044b: return 0x79; + case 0x042c: case 0x044c: return 0x78; + case 0x042d: case 0x044d: return 0x7c; + case 0x042e: case 0x044e: return 0x60; + case 0x042f: case 0x044f: return 0x71; + } + return -1; } /* @@ -659,47 +659,47 @@ static int unicode_to_koi7 (unsigned val) */ static t_stat cmd_set (int32 num, char *cptr) { - char gbuf [CBUFSIZE]; - int len; + char gbuf [CBUFSIZE]; + int len; - cptr = get_sim_sw (cptr); - if (! cptr) - return SCPE_INVSW; - if (! *cptr) - return SCPE_NOPARAM; - cptr = get_glyph (cptr, gbuf, 0); - if (*cptr) - return SCPE_2MARG; + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) + return SCPE_NOPARAM; + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; - len = strlen (gbuf); - if (strncmp ("UNICODE", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_CHARSET_MASK; - tty_unit[num].flags |= TTY_UNICODE_CHARSET; - } else if (strncmp ("JCUKEN", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_CHARSET_MASK; - tty_unit[num].flags |= TTY_KOI7_JCUKEN_CHARSET; - } else if (strncmp ("QWERTY", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_CHARSET_MASK; - tty_unit[num].flags |= TTY_KOI7_QWERTY_CHARSET; - } else if (strncmp ("TT", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_TELETYPE_STATE; - } else if (strncmp ("VT", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_VT340_STATE; - } else if (strncmp ("CONSUL", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_STATE_MASK; - tty_unit[num].flags |= TTY_CONSUL_STATE; - } else if (strncmp ("DESTRBS", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_BSPACE_MASK; - tty_unit[num].flags |= TTY_DESTRUCTIVE_BSPACE; - } else if (strncmp ("AUTHBS", gbuf, len) == 0) { - tty_unit[num].flags &= ~TTY_BSPACE_MASK; - tty_unit[num].flags |= TTY_AUTHENTIC_BSPACE; - } else { - return SCPE_NXPAR; - } - return SCPE_OK; + len = strlen (gbuf); + if (strncmp ("UNICODE", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_UNICODE_CHARSET; + } else if (strncmp ("JCUKEN", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_KOI7_JCUKEN_CHARSET; + } else if (strncmp ("QWERTY", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_CHARSET_MASK; + tty_unit[num].flags |= TTY_KOI7_QWERTY_CHARSET; + } else if (strncmp ("TT", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_TELETYPE_STATE; + } else if (strncmp ("VT", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_VT340_STATE; + } else if (strncmp ("CONSUL", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_STATE_MASK; + tty_unit[num].flags |= TTY_CONSUL_STATE; + } else if (strncmp ("DESTRBS", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_BSPACE_MASK; + tty_unit[num].flags |= TTY_DESTRUCTIVE_BSPACE; + } else if (strncmp ("AUTHBS", gbuf, len) == 0) { + tty_unit[num].flags &= ~TTY_BSPACE_MASK; + tty_unit[num].flags |= TTY_AUTHENTIC_BSPACE; + } else { + return SCPE_NXPAR; + } + return SCPE_OK; } /* @@ -707,44 +707,44 @@ static t_stat cmd_set (int32 num, char *cptr) */ static t_stat cmd_show (int32 num, char *cptr) { - TMLN *t = &tty_line [num]; - char gbuf [CBUFSIZE]; - MTAB *m; - int len; + TMLN *t = &tty_line [num]; + char gbuf [CBUFSIZE]; + MTAB *m; + int len; - cptr = get_sim_sw (cptr); - if (! cptr) - return SCPE_INVSW; - if (! *cptr) { - sprintf (gbuf, "TTY%d", num); - tmxr_linemsg (t, gbuf); - for (m=tty_mod; m->mask; m++) { - if (m->pstring && - (tty_unit[num].flags & m->mask) == m->match) { - tmxr_linemsg (t, ", "); - tmxr_linemsg (t, m->pstring); - } - } - if (t->txlog) - tmxr_linemsg (t, ", log"); - tmxr_linemsg (t, "\r\n"); - return SCPE_OK; - } - cptr = get_glyph (cptr, gbuf, 0); - if (*cptr) - return SCPE_2MARG; + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) { + sprintf (gbuf, "TTY%d", num); + tmxr_linemsg (t, gbuf); + for (m=tty_mod; m->mask; m++) { + if (m->pstring && + (tty_unit[num].flags & m->mask) == m->match) { + tmxr_linemsg (t, ", "); + tmxr_linemsg (t, m->pstring); + } + } + if (t->txlog) + tmxr_linemsg (t, ", log"); + tmxr_linemsg (t, "\r\n"); + return SCPE_OK; + } + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; - len = strlen (gbuf); - if (strncmp ("STATISTICS", gbuf, len) == 0) { - sprintf (gbuf, "line %d: input queued/total = %d/%d, " - "output queued/total = %d/%d\r\n", num, - t->rxbpi - t->rxbpr, t->rxcnt, - t->txbpi - t->txbpr, t->txcnt); - tmxr_linemsg (t, gbuf); - } else { - return SCPE_NXPAR; - } - return SCPE_OK; + len = strlen (gbuf); + if (strncmp ("STATISTICS", gbuf, len) == 0) { + sprintf (gbuf, "line %d: input queued/total = %d/%d, " + "output queued/total = %d/%d\r\n", num, + t->rxbpi - t->rxbpr, t->rxcnt, + t->txbpi - t->txbpr, t->txcnt); + tmxr_linemsg (t, gbuf); + } else { + return SCPE_NXPAR; + } + return SCPE_OK; } /* @@ -752,38 +752,38 @@ static t_stat cmd_show (int32 num, char *cptr) */ static t_stat cmd_exit (int32 num, char *cptr) { - return SCPE_EXIT; + return SCPE_EXIT; } static t_stat cmd_help (int32 num, char *cptr); static CTAB cmd_table[] = { - { "SET", &cmd_set, 0, - "set unicode select UTF-8 encoding\r\n" - "set jcuken select KOI7 encoding, 'jcuken' keymap\r\n" - "set qwerty select KOI7 encoding, 'qwerty' keymap\r\n" - "set tt use Teletype mode\r\n" - "set vt use Videoton-340 mode\r\n" - "set consul use Consul-254 mode\r\n" - "set destrbs destructive backspace\r\n" - "set authbs authentic backspace\r\n" - }, - { "SHOW", &cmd_show, 0, - "sh{ow} show modes of the terminal\r\n" - "sh{ow} s{tatistics} show network statistics\r\n" - }, - { "EXIT", &cmd_exit, 0, - "exi{t} | q{uit} | by{e} exit from simulation\r\n" - }, - { "QUIT", &cmd_exit, 0, NULL - }, - { "BYE", &cmd_exit, 0, NULL - }, - { "HELP", &cmd_help, 0, - "h{elp} type this message\r\n" - "h{elp} type help for command\r\n" - }, - { 0 } + { "SET", &cmd_set, 0, + "set unicode select UTF-8 encoding\r\n" + "set jcuken select KOI7 encoding, 'jcuken' keymap\r\n" + "set qwerty select KOI7 encoding, 'qwerty' keymap\r\n" + "set tt use Teletype mode\r\n" + "set vt use Videoton-340 mode\r\n" + "set consul use Consul-254 mode\r\n" + "set destrbs destructive backspace\r\n" + "set authbs authentic backspace\r\n" + }, + { "SHOW", &cmd_show, 0, + "sh{ow} show modes of the terminal\r\n" + "sh{ow} s{tatistics} show network statistics\r\n" + }, + { "EXIT", &cmd_exit, 0, + "exi{t} | q{uit} | by{e} exit from simulation\r\n" + }, + { "QUIT", &cmd_exit, 0, NULL + }, + { "BYE", &cmd_exit, 0, NULL + }, + { "HELP", &cmd_help, 0, + "h{elp} type this message\r\n" + "h{elp} type help for command\r\n" + }, + { 0 } }; /* @@ -791,15 +791,15 @@ static CTAB cmd_table[] = { */ static CTAB *lookup_cmd (char *command) { - CTAB *c; - int len; + CTAB *c; + int len; - len = strlen (command); - for (c=cmd_table; c->name; c++) { - if (strncmp (command, c->name, len) == 0) - return c; - } - return 0; + len = strlen (command); + for (c=cmd_table; c->name; c++) { + if (strncmp (command, c->name, len) == 0) + return c; + } + return 0; } /* @@ -807,30 +807,30 @@ static CTAB *lookup_cmd (char *command) */ static t_stat cmd_help (int32 num, char *cptr) { - TMLN *t = &tty_line [num]; - char gbuf [CBUFSIZE]; - CTAB *c; + TMLN *t = &tty_line [num]; + char gbuf [CBUFSIZE]; + CTAB *c; - cptr = get_sim_sw (cptr); - if (! cptr) - return SCPE_INVSW; - if (! *cptr) { - /* Список всех команд. */ - tmxr_linemsg (t, "Commands may be abbreviated. Commands are:\r\n\r\n"); - for (c=cmd_table; c && c->name; c++) - if (c->help) - tmxr_linemsg (t, c->help); - return SCPE_OK; - } - cptr = get_glyph (cptr, gbuf, 0); - if (*cptr) - return SCPE_2MARG; - c = lookup_cmd (gbuf); - if (! c) - return SCPE_ARG; - /* Описание конкретной команды. */ - tmxr_linemsg (t, c->help); - return SCPE_OK; + cptr = get_sim_sw (cptr); + if (! cptr) + return SCPE_INVSW; + if (! *cptr) { + /* Список всех команд. */ + tmxr_linemsg (t, "Commands may be abbreviated. Commands are:\r\n\r\n"); + for (c=cmd_table; c && c->name; c++) + if (c->help) + tmxr_linemsg (t, c->help); + return SCPE_OK; + } + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) + return SCPE_2MARG; + c = lookup_cmd (gbuf); + if (! c) + return SCPE_ARG; + /* Описание конкретной команды. */ + tmxr_linemsg (t, c->help); + return SCPE_OK; } /* @@ -838,27 +838,27 @@ static t_stat cmd_help (int32 num, char *cptr) */ void vt_cmd_exec (int num) { - TMLN *t = &tty_line [num]; - char *cptr, gbuf [CBUFSIZE]; - CTAB *cmdp; - t_stat err; - extern char *scp_errors[]; + TMLN *t = &tty_line [num]; + char *cptr, gbuf [CBUFSIZE]; + CTAB *cmdp; + t_stat err; + extern char *scp_errors[]; - cptr = get_glyph (vt_cbuf [num], gbuf, 0); /* get command glyph */ - cmdp = lookup_cmd (gbuf); /* lookup command */ - if (! cmdp) { - tmxr_linemsg (t, scp_errors[SCPE_UNK - SCPE_BASE]); - tmxr_linemsg (t, "\r\n"); - return; - } - err = cmdp->action (num, cptr); /* if found, exec */ - if (err >= SCPE_BASE) { /* error? */ - tmxr_linemsg (t, scp_errors [err - SCPE_BASE]); - tmxr_linemsg (t, "\r\n"); - } - if (err == SCPE_EXIT) { /* close telnet session */ - tmxr_reset_ln (t); - } + cptr = get_glyph (vt_cbuf [num], gbuf, 0); /* get command glyph */ + cmdp = lookup_cmd (gbuf); /* lookup command */ + if (! cmdp) { + tmxr_linemsg (t, scp_errors[SCPE_UNK - SCPE_BASE]); + tmxr_linemsg (t, "\r\n"); + return; + } + err = cmdp->action (num, cptr); /* if found, exec */ + if (err >= SCPE_BASE) { /* error? */ + tmxr_linemsg (t, scp_errors [err - SCPE_BASE]); + tmxr_linemsg (t, "\r\n"); + } + if (err == SCPE_EXIT) { /* close telnet session */ + tmxr_reset_ln (t); + } } /* @@ -866,70 +866,70 @@ void vt_cmd_exec (int num) */ void vt_cmd_loop (int num, int c) { - TMLN *t = &tty_line [num]; - char *cbuf, **cptr; + TMLN *t = &tty_line [num]; + char *cbuf, **cptr; - cbuf = vt_cbuf [num]; - cptr = &vt_cptr [num]; + cbuf = vt_cbuf [num]; + cptr = &vt_cptr [num]; - switch (c) { - case '\r': - case '\n': - tmxr_linemsg (t, "\r\n"); - if (*cptr <= cbuf) { - /* Пустая строка - возврат в обычный режим. */ - tty_unit[num].flags &= ~TTY_CMDLINE_MASK; - break; - } - /* Выполнение. */ - **cptr = 0; - vt_cmd_exec (num); - tmxr_linemsg (t, "sim>"); - *cptr = vt_cbuf[num]; - break; - case '\b': - case 0177: - /* Стирание предыдущего символа. */ - if (*cptr <= cbuf) - break; - tmxr_linemsg (t, "\b \b"); - while (*cptr > cbuf) { - --*cptr; - if (! (**cptr & 0x80)) - break; - } - break; - case 'U' & 037: - /* Стирание всей строки. */ -erase_line: while (*cptr > cbuf) { - --*cptr; - if (! (**cptr & 0x80)) - tmxr_linemsg (t, "\b \b"); - } - break; - case 033: - /* Escape [ X. */ - if (tmxr_getc_ln (t) != '[' + TMXR_VALID) - break; - switch (tmxr_getc_ln (t) - TMXR_VALID) { - case 'A': /* стрелка вверх */ - if (*cptr <= cbuf) { - *cptr = cbuf + strlen (cbuf); - if (*cptr > cbuf) - tmxr_linemsg (t, cbuf); - } - break; - case 'B': /* стрелка вниз */ - goto erase_line; - } - break; - default: - if (c < ' ' || *cptr > cbuf+CBUFSIZE-5) - break; - *(*cptr)++ = c; - tmxr_putc_ln (t, c); - break; - } + switch (c) { + case '\r': + case '\n': + tmxr_linemsg (t, "\r\n"); + if (*cptr <= cbuf) { + /* Пустая строка - возврат в обычный режим. */ + tty_unit[num].flags &= ~TTY_CMDLINE_MASK; + break; + } + /* Выполнение. */ + **cptr = 0; + vt_cmd_exec (num); + tmxr_linemsg (t, "sim>"); + *cptr = vt_cbuf[num]; + break; + case '\b': + case 0177: + /* Стирание предыдущего символа. */ + if (*cptr <= cbuf) + break; + tmxr_linemsg (t, "\b \b"); + while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + break; + } + break; + case 'U' & 037: + /* Стирание всей строки. */ + erase_line: while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + tmxr_linemsg (t, "\b \b"); + } + break; + case 033: + /* Escape [ X. */ + if (tmxr_getc_ln (t) != '[' + TMXR_VALID) + break; + switch (tmxr_getc_ln (t) - TMXR_VALID) { + case 'A': /* стрелка вверх */ + if (*cptr <= cbuf) { + *cptr = cbuf + strlen (cbuf); + if (*cptr > cbuf) + tmxr_linemsg (t, cbuf); + } + break; + case 'B': /* стрелка вниз */ + goto erase_line; + } + break; + default: + if (c < ' ' || *cptr > cbuf+CBUFSIZE-5) + break; + *(*cptr)++ = c; + tmxr_putc_ln (t, c); + break; + } } /* @@ -939,64 +939,64 @@ erase_line: while (*cptr > cbuf) { */ int vt_getc (int num) { - TMLN *t = &tty_line [num]; - extern int32 sim_int_char; - int c; - time_t now; + TMLN *t = &tty_line [num]; + extern int32 sim_int_char; + int c; + time_t now; - if (! t->conn) { - /* Пользователь отключился. */ - if (t->ipad) { - besm6_debug ("*** tty%d: отключение %s", - num, - t->ipad); - t->ipad = NULL; - } - tty_setmode (tty_unit+num, TTY_OFFLINE_STATE, 0, 0); - tty_unit[num].flags &= ~TTY_STATE_MASK; - return -1; - } - if (t->rcve) { - /* Приём через telnet. */ - c = tmxr_getc_ln (t); - if (! (c & TMXR_VALID)) { - now = time (0); - if (now > tty_last_time[num] + 5*60) { - ++tty_idle_count[num]; - if (tty_idle_count[num] > 3) { - tmxr_linemsg (t, "\r\nКОНЕЦ СЕАНСА\r\n"); - tmxr_reset_ln (t); - return -1; - } - tmxr_linemsg (t, "\r\nНЕ СПАТЬ!\r\n"); - tty_last_time[num] = now; - } - return -1; - } - tty_idle_count[num] = 0; - tty_last_time[num] = time (0); + if (! t->conn) { + /* Пользователь отключился. */ + if (t->ipad) { + besm6_debug ("*** tty%d: отключение %s", + num, + t->ipad); + t->ipad = NULL; + } + tty_setmode (tty_unit+num, TTY_OFFLINE_STATE, 0, 0); + tty_unit[num].flags &= ~TTY_STATE_MASK; + return -1; + } + if (t->rcve) { + /* Приём через telnet. */ + c = tmxr_getc_ln (t); + if (! (c & TMXR_VALID)) { + now = time (0); + if (now > tty_last_time[num] + 5*60) { + ++tty_idle_count[num]; + if (tty_idle_count[num] > 3) { + tmxr_linemsg (t, "\r\nКОНЕЦ СЕАНСА\r\n"); + tmxr_reset_ln (t); + return -1; + } + tmxr_linemsg (t, "\r\nНЕ СПАТЬ!\r\n"); + tty_last_time[num] = now; + } + return -1; + } + tty_idle_count[num] = 0; + tty_last_time[num] = time (0); - if (tty_unit[num].flags & TTY_CMDLINE_MASK) { - /* Продолжение режима управляющей командной строки. */ - vt_cmd_loop (num, c & 0377); - return -1; - } - if ((c & 0377) == sim_int_char) { - /* Вход в режим управляющей командной строки. */ - tty_unit[num].flags |= TTY_CMDLINE_MASK; - tmxr_linemsg (t, "sim>"); - vt_cptr[num] = vt_cbuf[num]; - return -1; - } - } else { - /* Ввод с клавиатуры. */ - c = sim_poll_kbd(); - if (c == SCPE_STOP) - return 0400; /* прерывание */ - if (! (c & SCPE_KFLAG)) - return -1; - } - return c & 0377; + if (tty_unit[num].flags & TTY_CMDLINE_MASK) { + /* Продолжение режима управляющей командной строки. */ + vt_cmd_loop (num, c & 0377); + return -1; + } + if ((c & 0377) == sim_int_char) { + /* Вход в режим управляющей командной строки. */ + tty_unit[num].flags |= TTY_CMDLINE_MASK; + tmxr_linemsg (t, "sim>"); + vt_cptr[num] = vt_cbuf[num]; + return -1; + } + } else { + /* Ввод с клавиатуры. */ + c = sim_poll_kbd(); + if (c == SCPE_STOP) + return 0400; /* прерывание */ + if (! (c & SCPE_KFLAG)) + return -1; + } + return c & 0377; } /* @@ -1008,32 +1008,32 @@ int vt_getc (int num) */ static int vt_kbd_input_unicode (int num) { - int c1, c2, c3, r; -again: - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - c1 = r & 0377; - if (! (c1 & 0x80)) - return unicode_to_koi7 (c1); + int c1, c2, c3, r; + again: + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c1 = r & 0377; + if (! (c1 & 0x80)) + return unicode_to_koi7 (c1); - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - c2 = r & 0377; - if (! (c1 & 0x20)) - return unicode_to_koi7 ((c1 & 0x1f) << 6 | (c2 & 0x3f)); + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c2 = r & 0377; + if (! (c1 & 0x20)) + return unicode_to_koi7 ((c1 & 0x1f) << 6 | (c2 & 0x3f)); - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - c3 = r & 0377; - if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) { - /* Skip zero width no-break space. */ - goto again; - } - return unicode_to_koi7 ((c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | - (c3 & 0x3f)); + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + c3 = r & 0377; + if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) { + /* Skip zero width no-break space. */ + goto again; + } + return unicode_to_koi7 ((c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | + (c3 & 0x3f)); } /* @@ -1043,62 +1043,62 @@ again: */ static int vt_kbd_input_koi7 (int num) { - int r; + int r; - r = vt_getc (num); - if (r < 0 || r > 0377) - return r; - r &= 0377; - switch (r) { - case '\r': return '\003'; - case 'q': return 'j'; - case 'w': return 'c'; - case 'e': return 'u'; - case 'r': return 'k'; - case 't': return 'e'; - case 'y': return 'n'; - case 'u': return 'g'; - case 'i': return '{'; - case 'o': return '}'; - case 'p': return 'z'; - case '[': return 'h'; - case '{': return '['; - case 'a': return 'f'; - case 's': return 'y'; - case 'd': return 'w'; - case 'f': return 'a'; - case 'g': return 'p'; - case 'h': return 'r'; - case 'j': return 'o'; - case 'k': return 'l'; - case 'l': return 'd'; - case ';': return 'v'; - case '}': return ';'; - case '\'': return '|'; - case '|': return '\''; - case 'z': return 'q'; - case 'x': return '~'; - case 'c': return 's'; - case 'v': return 'm'; - case 'b': return 'i'; - case 'n': return 't'; - case 'm': return 'x'; - case ',': return 'b'; - case '<': return ','; - case '.': return '`'; - case '>': return '.'; - case '~': return '>'; - case '`': return '<'; - default: return r; - } + r = vt_getc (num); + if (r < 0 || r > 0377) + return r; + r &= 0377; + switch (r) { + case '\r': return '\003'; + case 'q': return 'j'; + case 'w': return 'c'; + case 'e': return 'u'; + case 'r': return 'k'; + case 't': return 'e'; + case 'y': return 'n'; + case 'u': return 'g'; + case 'i': return '{'; + case 'o': return '}'; + case 'p': return 'z'; + case '[': return 'h'; + case '{': return '['; + case 'a': return 'f'; + case 's': return 'y'; + case 'd': return 'w'; + case 'f': return 'a'; + case 'g': return 'p'; + case 'h': return 'r'; + case 'j': return 'o'; + case 'k': return 'l'; + case 'l': return 'd'; + case ';': return 'v'; + case '}': return ';'; + case '\'': return '|'; + case '|': return '\''; + case 'z': return 'q'; + case 'x': return '~'; + case 'c': return 's'; + case 'v': return 'm'; + case 'b': return 'i'; + case 'n': return 't'; + case 'm': return 'x'; + case ',': return 'b'; + case '<': return ','; + case '.': return '`'; + case '>': return '.'; + case '~': return '>'; + case '`': return '<'; + default: return r; + } } int odd_parity(unsigned char c) { - c = (c & 0x55) + ((c >> 1) & 0x55); - c = (c & 0x33) + ((c >> 2) & 0x33); - c = (c & 0x0F) + ((c >> 4) & 0x0F); - return c & 1; + c = (c & 0x55) + ((c >> 1) & 0x55); + c = (c & 0x33) + ((c >> 2) & 0x33); + c = (c & 0x0F) + ((c >> 4) & 0x0F); + return c & 1; } /* @@ -1111,63 +1111,63 @@ void vt_receive() TTY_IN = 0; for (num = besm6_highest_bit (workset) - TTY_MAX; - workset; num = besm6_highest_bit (workset) - TTY_MAX) { - uint32 mask = 1 << (TTY_MAX - num); - switch (tty_instate[num]) { - case 0: - switch (tty_unit[num].flags & TTY_CHARSET_MASK) { - case TTY_KOI7_JCUKEN_CHARSET: - tty_typed[num] = vt_kbd_input_koi7 (num); - break; - case TTY_KOI7_QWERTY_CHARSET: - tty_typed[num] = vt_getc (num); - break; - case TTY_UNICODE_CHARSET: - tty_typed[num] = vt_kbd_input_unicode (num); - break; - default: - tty_typed[num] = '?'; - break; - } - if (tty_typed[num] < 0) { - /* TODO: обработать исключение от "неоператорского" терминала */ - sim_interval = 0; - break; - } - if (tty_typed[num] <= 0177) { - if (tty_typed[num] == '\r' || tty_typed[num] == '\n') - tty_typed[num] = 3; /* ^C - конец строки */ - if (tty_typed[num] == '\177') - tty_typed[num] = '\b'; /* ASCII DEL -> BS */ - tty_instate[num] = 1; - TTY_IN |= mask; /* start bit */ - GRP |= GRP_TTY_START; /* не используется ? */ - MGRP |= BBIT(19); /* для терминалов по методу МГУ */ - vt_receiving |= mask; - } - break; - case 1 ... 7: - /* need inverted byte */ - TTY_IN |= (tty_typed[num] & (1 << (tty_instate[num]-1))) ? 0 : mask; - tty_instate[num]++; - break; - case 8: - TTY_IN |= odd_parity(tty_typed[num]) ? 0 : mask; /* even parity of inverted */ - tty_instate[num]++; - break; - case 9 ... 11: - /* stop bits are 0 */ - tty_instate[num]++; - break; - case 12: - tty_instate[num] = 0; /* ready for the next char */ - vt_receiving &= ~mask; - break; - } - workset &= ~mask; + workset; num = besm6_highest_bit (workset) - TTY_MAX) { + uint32 mask = 1 << (TTY_MAX - num); + switch (tty_instate[num]) { + case 0: + switch (tty_unit[num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + tty_typed[num] = vt_kbd_input_koi7 (num); + break; + case TTY_KOI7_QWERTY_CHARSET: + tty_typed[num] = vt_getc (num); + break; + case TTY_UNICODE_CHARSET: + tty_typed[num] = vt_kbd_input_unicode (num); + break; + default: + tty_typed[num] = '?'; + break; + } + if (tty_typed[num] < 0) { + /* TODO: обработать исключение от "неоператорского" терминала */ + sim_interval = 0; + break; + } + if (tty_typed[num] <= 0177) { + if (tty_typed[num] == '\r' || tty_typed[num] == '\n') + tty_typed[num] = 3; /* ^C - конец строки */ + if (tty_typed[num] == '\177') + tty_typed[num] = '\b'; /* ASCII DEL -> BS */ + tty_instate[num] = 1; + TTY_IN |= mask; /* start bit */ + GRP |= GRP_TTY_START; /* не используется ? */ + MGRP |= BBIT(19); /* для терминалов по методу МГУ */ + vt_receiving |= mask; + } + break; + case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* need inverted byte */ + TTY_IN |= (tty_typed[num] & (1 << (tty_instate[num]-1))) ? 0 : mask; + tty_instate[num]++; + break; + case 8: + TTY_IN |= odd_parity(tty_typed[num]) ? 0 : mask; /* even parity of inverted */ + tty_instate[num]++; + break; + case 9: case 10: case 11: + /* stop bits are 0 */ + tty_instate[num]++; + break; + case 12: + tty_instate[num] = 0; /* ready for the next char */ + vt_receiving &= ~mask; + break; + } + workset &= ~mask; } if (vt_receiving) - vt_idle = 0; + vt_idle = 0; } /* @@ -1175,69 +1175,69 @@ void vt_receive() */ int vt_is_idle () { - return (tt_mask ? vt_idle > 300 : vt_idle > 10); + return (tt_mask ? vt_idle > 300 : vt_idle > 10); } int tty_query () { -/* besm6_debug ("*** телетайпы: приём");*/ - return TTY_IN; + /* besm6_debug ("*** телетайпы: приём");*/ + return TTY_IN; } void consul_print (int dev_num, uint32 cmd) { - int line_num = dev_num + TTY_MAX + 1; - if (tty_dev.dctrl) - besm6_debug(">>> CONSUL%o: %03o", line_num, cmd & 0377); - cmd &= 0177; - switch (tty_unit[line_num].flags & TTY_STATE_MASK) { - case TTY_VT340_STATE: - vt_send (line_num, cmd, - (tty_unit[line_num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); - break; - case TTY_CONSUL_STATE: - besm6_debug(">>> CONSUL%o: Native charset not implemented", line_num); - break; - } - // PRP |= CONS_CAN_PRINT[dev_num]; - vt_idle = 0; + int line_num = dev_num + TTY_MAX + 1; + if (tty_dev.dctrl) + besm6_debug(">>> CONSUL%o: %03o", line_num, cmd & 0377); + cmd &= 0177; + switch (tty_unit[line_num].flags & TTY_STATE_MASK) { + case TTY_VT340_STATE: + vt_send (line_num, cmd, + (tty_unit[line_num].flags & TTY_BSPACE_MASK) == TTY_DESTRUCTIVE_BSPACE); + break; + case TTY_CONSUL_STATE: + besm6_debug(">>> CONSUL%o: Native charset not implemented", line_num); + break; + } + // PRP |= CONS_CAN_PRINT[dev_num]; + vt_idle = 0; } void consul_receive () { - int c, line_num, dev_num; + int c, line_num, dev_num; - for (dev_num = 0; dev_num < 2; ++dev_num){ - line_num = dev_num + TTY_MAX + 1; - if (! tty_line[line_num].conn) - continue; - switch (tty_unit[line_num].flags & TTY_CHARSET_MASK) { - case TTY_KOI7_JCUKEN_CHARSET: - c = vt_kbd_input_koi7 (line_num); - break; - case TTY_KOI7_QWERTY_CHARSET: - c = vt_getc (line_num); - break; - case TTY_UNICODE_CHARSET: - c = vt_kbd_input_unicode (line_num); - break; - default: - c = '?'; - break; - } - if (c >= 0 && c <= 0177) { - CONSUL_IN[dev_num] = odd_parity(c) ? c | 0200 : c; - if (c == '\r' || c == '\n') - CONSUL_IN[dev_num] = 3; - PRP |= CONS_HAS_INPUT[dev_num]; - vt_idle = 0; - } - } + for (dev_num = 0; dev_num < 2; ++dev_num){ + line_num = dev_num + TTY_MAX + 1; + if (! tty_line[line_num].conn) + continue; + switch (tty_unit[line_num].flags & TTY_CHARSET_MASK) { + case TTY_KOI7_JCUKEN_CHARSET: + c = vt_kbd_input_koi7 (line_num); + break; + case TTY_KOI7_QWERTY_CHARSET: + c = vt_getc (line_num); + break; + case TTY_UNICODE_CHARSET: + c = vt_kbd_input_unicode (line_num); + break; + default: + c = '?'; + break; + } + if (c >= 0 && c <= 0177) { + CONSUL_IN[dev_num] = odd_parity(c) ? c | 0200 : c; + if (c == '\r' || c == '\n') + CONSUL_IN[dev_num] = 3; + PRP |= CONS_HAS_INPUT[dev_num]; + vt_idle = 0; + } + } } uint32 consul_read (int num) { - if (tty_dev.dctrl) - besm6_debug("<<< CONSUL%o: %03o", num+TTY_MAX+1, CONSUL_IN[num]); - return CONSUL_IN[num]; + if (tty_dev.dctrl) + besm6_debug("<<< CONSUL%o: %03o", num+TTY_MAX+1, CONSUL_IN[num]); + return CONSUL_IN[num]; } diff --git a/BESM6/boot_dispak.b6 b/BESM6/boot_dispak.b6 index 7c3c74a6..57f5a627 100644 --- a/BESM6/boot_dispak.b6 +++ b/BESM6/boot_dispak.b6 @@ -19,466 +19,466 @@ с 0 в 02000 -к рег 101, уиа 2260(2) ; 02000 - 0002 0101 1240 2260 -к уиа 2502(12), уиа -56(6) ; 02001 - 5240 2502 3247 7722 -к сч 2537, зп 2605 ; 02002 - 0010 2537 0000 2605 -к сда 101, зп 2664(6) ; 02003 - 0036 0101 3000 2664 -к цикл 2003(6), уиа -2(1) ; 02004 - 3370 2003 0647 7776 -к сч 2521(1), зп 502(1) ; 02005 - 0410 2521 0400 0502 -к цикл 2005(1), уиа -2(6) ; 02006 - 0770 2005 3247 7776 -к уиа (13), сч ; 02007 - 5640 0000 0010 0000 -к слц 2546(6), цикл 2010(6) ; 02010 - 3013 2546 3370 2010 -к нтж, по 2070 ; 02011 - 0012 0000 0260 2070 -к уиа 2444(5), пв 2346(10) ; 02012 - 2640 2444 4310 2346 -к нтж 2543, пе 2345 ; 02013 - 0012 2543 0270 2345 -к сч 2, пб 3000 ; 02014 - 0010 0002 0300 3000 -к сда 136, и 2427 ; 02015 - 0036 0136 0011 2427 -к по 2017, вч 2664 ; 02016 - 0260 2017 0005 2664 -к уи 16, уии 3(16) ; 02017 - 0040 0016 7044 0003 -к сли 16(16), сли 16(3) ; 02020 - 7045 0016 1445 0016 -к уиа -2(3), мода ; 02021 - 1647 7776 0220 0000 -к мода (16), сч 2546(3) ; 02022 - 7220 0000 1410 2546 -к зп 1777(3), цикл 2022(3) ; 02023 - 1400 1777 1770 2022 -к уиа -1(3), мода ; 02024 - 1647 7777 0220 0000 -к сч 1776, пио 2027(3) ; 02025 - 0010 1776 1740 2027 -к сда 110, мода ; 02026 - 0036 0110 0220 0000 -к сда 50, зп 1033(3) ; 02027 - 0036 0050 1400 1033 -к сч 1775, сда 115 ; 02030 - 0010 1775 0036 0115 -к пио 2032(3), сда 120 ; 02031 - 1740 2032 0036 0120 -к и 2540, сда 70 ; 02032 - 0011 2540 0036 0070 -к или 1033(3), зп 1033(3) ; 02033 - 1415 1033 1400 1033 -к сч 1777, пио 2036(3) ; 02034 - 0010 1777 1740 2036 -к сда 110, мода ; 02035 - 0036 0110 0220 0000 -к и 2541, или 1033(3) ; 02036 - 0011 2541 1415 1033 -к зп 1033(3), цикл 2025(3) ; 02037 - 1400 1033 1770 2025 -к уиа 3(16), уиа -1(3) ; 02040 - 7240 0003 1647 7777 -к сч, зп 1773 ; 02041 - 0010 0000 0000 1773 -к уиа 10(7), мода ; 02042 - 3640 0010 0220 0000 -к уиа -1(15), уиа -7(14) ; 02043 - 6647 7777 6247 7771 -к сч 1777(3), слиа 1(15) ; 02044 - 1410 1777 6650 0001 -к сда 140(7), и 2655(15) ; 02045 - 3436 0140 6411 2655 -к по 2060, счи 15 ; 02046 - 0260 2060 0042 0015 -к нтж 2415, уи 17 ; 02047 - 0012 2415 0040 0017 -к сда 71, или 2532 ; 02050 - 0036 0071 0015 2532 -к зп 1774, сч 1773 ; 02051 - 0000 1774 0010 1773 -к сда 33, или 1774 ; 02052 - 0036 0033 0015 1774 -к зп 1774, пв 2126(11) ; 02053 - 0000 1774 4710 2126 -к сч 2534, и 2615 ; 02054 - 0010 2534 0011 2615 -к по 2074, сч 2534 ; 02055 - 0260 2074 0010 2534 -к сда 114, нтж 1775 ; 02056 - 0036 0114 0012 1775 -к и 2423, по 2076 ; 02057 - 0011 2423 0260 2076 -к цикл 2044(14), слиа -10(7) ; 02060 - 6370 2044 3657 7770 -к сч 1773, слц 2664 ; 02061 - 0010 1773 0013 2664 -к зп 1773, сда 102 ; 02062 - 0000 1773 0036 0102 -к по 2043, пио 2066(3) ; 02063 - 0260 2043 1740 2066 -к уиа 4(16), уиа (3) ; 02064 - 7240 0004 1640 0000 -к пб 2041, мода ; 02065 - 0300 2041 0220 0000 -к уиа 2502(5), пв 2367(7) ; 02066 - 2640 2502 3710 2367 -к стоп, пб 2040 ; 02067 - 0330 0000 0300 2040 -к уиа -35(16), уиа 1(13) ; 02070 - 7247 7743 5640 0001 -к сч 72035(16), зп 2601(16) ; 02071 - 7110 2035 7000 2601 -к цикл 2071(16), пв 2346(10) ; 02072 - 7370 2071 4310 2346 -к зп 2543, пб 2014 ; 02073 - 0000 2543 0300 2014 -к сч 2534, нтж 1775 ; 02074 - 0010 2534 0012 1775 -к и 2423, пе 2060 ; 02075 - 0011 2423 0270 2060 -к счи 17, сда 71 ; 02076 - 0042 0017 0036 0071 -к или 2420, зп 1774 ; 02077 - 0015 2420 0000 1774 -к счи 16, сда 76 ; 02100 - 0042 0016 0036 0076 -к слц 1773, сда 33 ; 02101 - 0013 1773 0036 0033 -к или 1774, пб 2105 ; 02102 - 0015 1774 0300 2105 -к уиа 2257(11), мода ; 02103 - 4640 2257 0220 0000 -к уиа 2106(2), сч 1027 ; 02104 - 1240 2106 0010 1027 -к зп 1774, пб (2) ; 02105 - 0000 1774 1300 0000 -к сч 1774, сда 147 ; 02106 - 0010 1774 0036 0147 -к уи 16, сч 1774 ; 02107 - 0040 0016 0010 1774 -к сда 107, и 2415 ; 02110 - 0036 0107 0011 2415 -к уи 17, нтж 2415 ; 02111 - 0040 0017 0012 2415 -к уи 15, сч 1774 ; 02112 - 0040 0015 0010 1774 -к сда 145, и 2416 ; 02113 - 0036 0145 0011 2416 -к сда 75, уи 6 ; 02114 - 0036 0075 0040 0006 -к сли 6(17), сч 1027(16) ; 02115 - 7445 0006 7010 1027 -к и 2625(6), уиа (1) ; 02116 - 3011 2625 0640 0000 -к по 2120, уиа 2(1) ; 02117 - 0260 2120 0640 0002 -к сч 1775, мода ; 02120 - 0010 1775 0220 0000 -к сда 130, слц 2531 ; 02121 - 0036 0130 0013 2531 -к и 2526, мода ; 02122 - 0011 2526 0220 0000 -к сда 77(1), зп 2527 ; 02123 - 0436 0077 0000 2527 -к счмр, сда 146 ; 02124 - 0031 0000 0036 0146 -к и 2653, зп 2604 ; 02125 - 0011 2653 0000 2604 -к сч, рег 37 ; 02126 - 0010 0000 0002 0037 -к сч 2417, увв 20(16) ; 02127 - 0010 2417 7033 0020 -к уи, сч 1774 ; 02130 - 0040 0000 0010 1774 -к сда 145, и 2416 ; 02131 - 0036 0145 0011 2416 -к или 2654, или 2653 ; 02132 - 0015 2654 0015 2653 -к увв 20(16), уи ; 02133 - 7033 0020 0040 0000 -к рег 237, и 2625(16) ; 02134 - 0002 0237 7011 2625 -к по 2134, сч 2661 ; 02135 - 0260 2134 0010 2661 -к увв 20(16), уи ; 02136 - 7033 0020 0040 0000 -к уи, рег 37 ; 02137 - 0040 0000 0002 0037 -к уиа 2147(6), уиа 11(4) ; 02140 - 3240 2147 2240 0011 -к сч 2655(15), пио 2143(1) ; 02141 - 6410 2655 0740 2143 -к или 2604, мода ; 02142 - 0015 2604 0220 0000 -к или 2421, увв 20(16) ; 02143 - 0015 2421 7033 0020 -к уи, счи 4 ; 02144 - 0040 0000 0042 0004 -к увв 20(16), уи ; 02145 - 7033 0020 0040 0000 -к увв 4000(16), пб (6) ; 02146 - 7033 4000 3300 0000 -к и 2654, уиа 2430(5) ; 02147 - 0011 2654 2640 2430 -к по 2412, уиа -7(6) ; 02150 - 0260 2412 3247 7771 -к сч, мода ; 02151 - 0010 0000 0220 0000 -к мод 2521(16), зп 7(6) ; 02152 - 7230 2521 3000 0007 -к цикл 2152(6), уиа -7(6) ; 02153 - 3370 2152 3247 7771 -к зп 1, цикл 2154(6) ; 02154 - 0000 0001 3370 2154 -к сч 1774, увв (16) ; 02155 - 0010 1774 7033 0000 -к сч 2416, или 2422 ; 02156 - 0010 2416 0015 2422 -к увв 20(16), уи ; 02157 - 7033 0020 0040 0000 -к сч 2527, или 2651 ; 02160 - 0010 2527 0015 2651 -к уи, увв 20(16) ; 02161 - 0040 0000 7033 0020 -к уи, увв ; 02162 - 0040 0000 0033 0000 -к уиа -50(6), мода ; 02163 - 3247 7730 0220 0000 -к зп 1, цикл 2164(6) ; 02164 - 0000 0001 3370 2164 -к сч, уи ; 02165 - 0010 0000 0040 0000 -к рег 37, уиа 76030(6) ; 02166 - 0002 0037 3247 6030 -к уиа 77540(10), мода ; 02167 - 4247 7540 0220 0000 -к сбр, рег 237 ; 02170 - 0020 0000 0002 0237 -к и 2625(16), пе 2175 ; 02171 - 7011 2625 0270 2175 -к цикл 2170(10), цикл 2167(6) ; 02172 - 4370 2170 3370 2167 -к стоп, уиа 2126(7) ; 02173 - 0330 0000 3640 2126 -к уиа 2474(5), пб 2366 ; 02174 - 2640 2474 0300 2366 -к уиа 11(4), пв 2144(6) ; 02175 - 2240 0011 3310 2144 -к зп 2533, и 2651 ; 02176 - 0000 2533 0011 2651 -к пе 2351, увв 4035 ; 02177 - 0270 2351 0033 4035 -к и 2655(16), уиа 2436(5) ; 02200 - 7011 2655 2640 2436 -к пе 2412, уиа 1(10) ; 02201 - 0270 2412 4240 0001 -к уиа 2206(6), уиа 2206(5) ; 02202 - 3240 2206 2640 2206 -к сч 2424, уи 21 ; 02203 - 0010 2424 0040 0021 -к мод 2521(16), сч (10) ; 02204 - 7230 2521 4010 0000 -к уи, пб (6) ; 02205 - 0040 0000 3300 0000 -к зп 2534, и 2535 ; 02206 - 0000 2534 0011 2535 -к нтж 2536, уиа 2460(5) ; 02207 - 0012 2536 2640 2460 -к пе 2412, сч 1774 ; 02210 - 0270 2412 0010 1774 -к и 2660, пе 2302 ; 02211 - 0011 2660 0270 2302 -к сч 2533, и 2652 ; 02212 - 0010 2533 0011 2652 -к уиа 2444(5), пе 2366 ; 02213 - 2640 2444 0270 2366 -к уиа -3(4), уиа (12) ; 02214 - 2247 7775 5240 0000 -к счи 11, нтж 2530 ; 02215 - 0042 0011 0012 2530 -к пе 2217, слиа 2000(12) ; 02216 - 0270 2217 5250 2000 -к сч 2534, и 2614 ; 02217 - 0010 2534 0011 2614 -к пе 2240, уиа -1(10) ; 02220 - 0270 2240 4247 7777 -к уиа 2411(5), сч 2424 ; 02221 - 2640 2411 0010 2424 -к уи 21, уиа 77401(6) ; 02222 - 0040 0021 3247 7401 -к слиа 2(10), сч ; 02223 - 4250 0002 0010 0000 -к мода 70000(12), слц 377(6) ; 02224 - 5227 0000 3013 0377 -к цикл 2224(6), зп 2534 ; 02225 - 3370 2224 0000 2534 -к уиа 2227(5), пв 2203(6) ; 02226 - 2640 2227 3310 2203 -к зп 2533, нтж 2534 ; 02227 - 0000 2533 0012 2534 -к и 2423, пе 2250 ; 02230 - 0011 2423 0270 2250 -к сч 2533, и 2615 ; 02231 - 0010 2533 0011 2615 -к уиа 2444(5), по 2366 ; 02232 - 2640 2444 0260 2366 -к слиа 400(12), мода ; 02233 - 5250 0400 0220 0000 -к цикл 2221(4), уиа 2255(6) ; 02234 - 2370 2221 3240 2255 -к сч 2425, уи 21 ; 02235 - 0010 2425 0040 0021 -к сч 2417, увв 20(16) ; 02236 - 0010 2417 7033 0020 -к уи, пб (6) ; 02237 - 0040 0000 3300 0000 -к уиа 2411(5), сч 2424 ; 02240 - 2640 2411 0010 2424 -к уи 21, уиа 76001(6) ; 02241 - 0040 0021 3247 6001 -к сч, уиа 3(10) ; 02242 - 0010 0000 4240 0003 -к мода 70000(12), слц 1777(6) ; 02243 - 5227 0000 3013 1777 -к цикл 2243(6), зп 2534 ; 02244 - 3370 2243 0000 2534 -к уиа 2246(5), пв 2203(6) ; 02245 - 2640 2246 3310 2203 -к нтж 2534, пе 2213 ; 02246 - 0012 2534 0270 2213 -к уиа 2255(6), пб 2235 ; 02247 - 3240 2255 0300 2235 -к слиа -1(10), уиа 2252(5) ; 02250 - 4257 7777 2640 2252 -к мода, пв 2203(6) ; 02251 - 0220 0000 3310 2203 -к нтж 2534, и 2423 ; 02252 - 0012 2534 0011 2423 -к пе 2213, слиа 1(10) ; 02253 - 0270 2213 4250 0001 -к слиа 400(12), пб 2234 ; 02254 - 5250 0400 0300 2234 -к сч, уи ; 02255 - 0010 0000 0040 0000 -к рег 37, пб (11) ; 02256 - 0002 0037 4700 0000 -к уиа 1(14), пб 2335 ; 02257 - 6240 0001 0300 2335 -к зп 1027, сч 2516 ; 02260 - 0000 1027 0010 2516 -к или 1775, зп 1775 ; 02261 - 0015 1775 0000 1775 -к уиа 2265(11), пб 2104 ; 02262 - 4640 2265 0300 2104 -к слиа 40(4), цикл 2272(14) ; 02263 - 2250 0040 6370 2272 -к уиа 2466(5), пв 2367(7) ; 02264 - 2640 2466 3710 2367 -к сч 2, сда 130 ; 02265 - 0010 0002 0036 0130 -к и 2427, уиа -17(14) ; 02266 - 0011 2427 6247 7761 -к уиа (2), уиа (4) ; 02267 - 1240 0000 2240 0000 -к по 2271, вч 2664 ; 02270 - 0260 2271 0005 2664 -к зп 2542, мода ; 02271 - 0000 2542 0220 0000 -к уиа -37(7), сч 1775 ; 02272 - 3647 7741 0010 1775 -к нтж 70000(4), и 2423 ; 02273 - 2112 0000 0011 2423 -к пе 2263, сч 1775 ; 02274 - 0270 2263 0010 1775 -к сда 155, нтж 70016(4) ; 02275 - 0036 0155 2112 0016 -к и 2415, пе 2263 ; 02276 - 0011 2415 0270 2263 -к счи 2, нтж 2542 ; 02277 - 0042 0002 0012 2542 -к по 2303, слиа 1(2) ; 02300 - 0260 2303 1250 0001 -к пб 2263, мода ; 02301 - 0300 2263 0220 0000 -к уии 6(11), пб 2235 ; 02302 - 4444 0006 0300 2235 -к мода (4), сч 70037(7) ; 02303 - 2220 0000 3510 0037 -к зп 3537(7), цикл 2303(7) ; 02304 - 3400 3537 3770 2303 -к сч 3502, зп 1775 ; 02305 - 0010 3502 0000 1775 -к мода, пв 2040(2) ; 02306 - 0220 0000 1310 2040 -к зп 1030, сч 3500 ; 02307 - 0000 1030 0010 3500 -к зп 1775, сч 3 ; 02310 - 0000 1775 0010 0003 -к и 2660, пб 2103 ; 02311 - 0011 2660 0300 2103 -к уиа -2(14), сч 3515 ; 02312 - 6247 7776 0010 3515 -к сда 117, зп 1775 ; 02313 - 0036 0117 0000 1775 -к и 2423, по 2103 ; 02314 - 0011 2423 0260 2103 -к сч 2663, пв 2123(11) ; 02315 - 0010 2663 4710 2123 -к сч 3516, и 2415 ; 02316 - 0010 3516 0011 2415 -к сда 75, уи 6 ; 02317 - 0036 0075 0040 0006 -к сч 70000(6), нтж 3516 ; 02320 - 3110 0000 0012 3516 -к и 2415, пе 2103 ; 02321 - 0011 2415 0270 2103 -к мода (6), сч 70002(14) ; 02322 - 3220 0000 6110 0002 -к зп 2604(14), цикл 2322(14) ; 02323 - 6000 2604 6370 2322 -к уиа 2510(12), пв 2040(2) ; 02324 - 5240 2510 1310 2040 -к уиа -2(14), пв 2126(11) ; 02325 - 6247 7776 4710 2126 -к сч 70002(14), нтж 2604(14) ; 02326 - 6110 0002 6012 2604 -к уиа 2257(11), пе 2103 ; 02327 - 4640 2257 0270 2103 -к цикл 2326(14), уиа -22(14) ; 02330 - 6370 2326 6247 7756 -к сч 70026(14), зп 1026(14) ; 02331 - 6110 0026 6000 1026 -к цикл 2331(14), уиа 2335(11) ; 02332 - 6370 2331 4640 2335 -к сч 1774, зп 1031 ; 02333 - 0010 1774 0000 1031 -к пб 2104, мода ; 02334 - 0300 2104 0220 0000 -к сч 1774, слц 2650 ; 02335 - 0010 1774 0013 2650 -к зп 1774, сч 1775 ; 02336 - 0000 1774 0010 1775 -к слц 2634, пв 2121(11) ; 02337 - 0013 2634 4710 2121 -к сч 2522, зп 502 ; 02340 - 0010 2522 0000 0502 -к уиа -37(6), мода ; 02341 - 3247 7741 0220 0000 -к сч 3537(6), зп 71777(6) ; 02342 - 3010 3537 3100 1777 -к цикл 2342(6), сч ; 02343 - 3370 2342 0010 0000 -к зп 72000, пб 70000 ; 02344 - 0100 2000 0307 0000 -к уиа 2345(7), пб 2367 ; 02345 - 3640 2345 0300 2367 -к уиа -2(3), сч ; 02346 - 1647 7776 0010 0000 -к слц 2546(3), цикл 2347(3) ; 02347 - 1413 2546 1770 2347 -к пб (10), мода ; 02350 - 4300 0000 0220 0000 -к сч 1774, и 2660 ; 02351 - 0010 1774 0011 2660 -к пе 2060, уиа 31(4) ; 02352 - 0270 2060 2240 0031 -к мода, пв 2144(6) ; 02353 - 0220 0000 3310 2144 -к зп 2534, сч 2533 ; 02354 - 0000 2534 0010 2533 -к и 2654, по 2402 ; 02355 - 0011 2654 0260 2402 -к сч 2534, и 2662 ; 02356 - 0010 2534 0011 2662 -к уиа 2452(5), пе 2404 ; 02357 - 2640 2452 0270 2404 -к сч 2534, и 2660 ; 02360 - 0010 2534 0011 2660 -к уиа 2466(5), пе 2366 ; 02361 - 2640 2466 0270 2366 -к сч 2534, и 2661 ; 02362 - 0010 2534 0011 2661 -к пе 2410, сч 2534 ; 02363 - 0270 2410 0010 2534 -к и 2652, уиа 2452(5) ; 02364 - 0011 2652 2640 2452 -к пе 2366, уиа 2452(5) ; 02365 - 0270 2366 2640 2452 -к уиа 2126(7), пв 2235(6) ; 02366 - 3640 2126 3310 2235 -к уиа -10(10), мода ; 02367 - 4247 7770 0220 0000 -к зп 1, цикл 2370(10) ; 02370 - 0000 0001 4370 2370 -к сч, рег ; 02371 - 0010 0000 0002 0000 -к уиа -5(10), мода ; 02372 - 4247 7773 0220 0000 -к мода (5), сч 5(10) ; 02373 - 2620 0000 4010 0005 -к рег 6(10), цикл 2373(10) ; 02374 - 4002 0006 4370 2373 -к сч, рег 7 ; 02375 - 0010 0000 0002 0007 -к уиа 76030(10), мода ; 02376 - 4247 6030 0220 0000 -к уиа 77526(3), мода ; 02377 - 1647 7526 0220 0000 -к сбр, цикл 2400(3) ; 02400 - 0020 0000 1770 2400 -к цикл 2377(10), пб (7) ; 02401 - 4370 2377 3700 0000 -к сч 2533, уиа 2430(5) ; 02402 - 0010 2533 2640 2430 -к и 2653, по 2366 ; 02403 - 0011 2653 0260 2366 -к уиа 1(4), пв 2144(6) ; 02404 - 2240 0001 3310 2144 -к мода, пв 2235(6) ; 02405 - 0220 0000 3310 2235 -к уиа 76030(10), пв 2377(7) ; 02406 - 4247 6030 3710 2377 -к уиа 2126(7), пб 2367 ; 02407 - 3640 2126 0300 2367 -к уиа 2452(5), пб 2366 ; 02410 - 2640 2452 0300 2366 -к уиа 2126(6), пб 2235 ; 02411 - 3240 2126 0300 2235 -к сч 1774, и 2660 ; 02412 - 0010 1774 0011 2660 -к по 2366, пв 2235(6) ; 02413 - 0260 2366 3310 2235 -к пб 2060, мода ; 02414 - 0300 2060 0220 0000 +к рег 101, уиа 2260(2) ; 02000 - 0002 0101 1240 2260 +к уиа 2502(12), уиа -56(6) ; 02001 - 5240 2502 3247 7722 +к сч 2537, зп 2605 ; 02002 - 0010 2537 0000 2605 +к сда 101, зп 2664(6) ; 02003 - 0036 0101 3000 2664 +к цикл 2003(6), уиа -2(1) ; 02004 - 3370 2003 0647 7776 +к сч 2521(1), зп 502(1) ; 02005 - 0410 2521 0400 0502 +к цикл 2005(1), уиа -2(6) ; 02006 - 0770 2005 3247 7776 +к уиа (13), сч ; 02007 - 5640 0000 0010 0000 +к слц 2546(6), цикл 2010(6) ; 02010 - 3013 2546 3370 2010 +к нтж, по 2070 ; 02011 - 0012 0000 0260 2070 +к уиа 2444(5), пв 2346(10) ; 02012 - 2640 2444 4310 2346 +к нтж 2543, пе 2345 ; 02013 - 0012 2543 0270 2345 +к сч 2, пб 3000 ; 02014 - 0010 0002 0300 3000 +к сда 136, и 2427 ; 02015 - 0036 0136 0011 2427 +к по 2017, вч 2664 ; 02016 - 0260 2017 0005 2664 +к уи 16, уии 3(16) ; 02017 - 0040 0016 7044 0003 +к сли 16(16), сли 16(3) ; 02020 - 7045 0016 1445 0016 +к уиа -2(3), мода ; 02021 - 1647 7776 0220 0000 +к мода (16), сч 2546(3) ; 02022 - 7220 0000 1410 2546 +к зп 1777(3), цикл 2022(3) ; 02023 - 1400 1777 1770 2022 +к уиа -1(3), мода ; 02024 - 1647 7777 0220 0000 +к сч 1776, пио 2027(3) ; 02025 - 0010 1776 1740 2027 +к сда 110, мода ; 02026 - 0036 0110 0220 0000 +к сда 50, зп 1033(3) ; 02027 - 0036 0050 1400 1033 +к сч 1775, сда 115 ; 02030 - 0010 1775 0036 0115 +к пио 2032(3), сда 120 ; 02031 - 1740 2032 0036 0120 +к и 2540, сда 70 ; 02032 - 0011 2540 0036 0070 +к или 1033(3), зп 1033(3) ; 02033 - 1415 1033 1400 1033 +к сч 1777, пио 2036(3) ; 02034 - 0010 1777 1740 2036 +к сда 110, мода ; 02035 - 0036 0110 0220 0000 +к и 2541, или 1033(3) ; 02036 - 0011 2541 1415 1033 +к зп 1033(3), цикл 2025(3) ; 02037 - 1400 1033 1770 2025 +к уиа 3(16), уиа -1(3) ; 02040 - 7240 0003 1647 7777 +к сч, зп 1773 ; 02041 - 0010 0000 0000 1773 +к уиа 10(7), мода ; 02042 - 3640 0010 0220 0000 +к уиа -1(15), уиа -7(14) ; 02043 - 6647 7777 6247 7771 +к сч 1777(3), слиа 1(15) ; 02044 - 1410 1777 6650 0001 +к сда 140(7), и 2655(15) ; 02045 - 3436 0140 6411 2655 +к по 2060, счи 15 ; 02046 - 0260 2060 0042 0015 +к нтж 2415, уи 17 ; 02047 - 0012 2415 0040 0017 +к сда 71, или 2532 ; 02050 - 0036 0071 0015 2532 +к зп 1774, сч 1773 ; 02051 - 0000 1774 0010 1773 +к сда 33, или 1774 ; 02052 - 0036 0033 0015 1774 +к зп 1774, пв 2126(11) ; 02053 - 0000 1774 4710 2126 +к сч 2534, и 2615 ; 02054 - 0010 2534 0011 2615 +к по 2074, сч 2534 ; 02055 - 0260 2074 0010 2534 +к сда 114, нтж 1775 ; 02056 - 0036 0114 0012 1775 +к и 2423, по 2076 ; 02057 - 0011 2423 0260 2076 +к цикл 2044(14), слиа -10(7) ; 02060 - 6370 2044 3657 7770 +к сч 1773, слц 2664 ; 02061 - 0010 1773 0013 2664 +к зп 1773, сда 102 ; 02062 - 0000 1773 0036 0102 +к по 2043, пио 2066(3) ; 02063 - 0260 2043 1740 2066 +к уиа 4(16), уиа (3) ; 02064 - 7240 0004 1640 0000 +к пб 2041, мода ; 02065 - 0300 2041 0220 0000 +к уиа 2502(5), пв 2367(7) ; 02066 - 2640 2502 3710 2367 +к стоп, пб 2040 ; 02067 - 0330 0000 0300 2040 +к уиа -35(16), уиа 1(13) ; 02070 - 7247 7743 5640 0001 +к сч 72035(16), зп 2601(16) ; 02071 - 7110 2035 7000 2601 +к цикл 2071(16), пв 2346(10) ; 02072 - 7370 2071 4310 2346 +к зп 2543, пб 2014 ; 02073 - 0000 2543 0300 2014 +к сч 2534, нтж 1775 ; 02074 - 0010 2534 0012 1775 +к и 2423, пе 2060 ; 02075 - 0011 2423 0270 2060 +к счи 17, сда 71 ; 02076 - 0042 0017 0036 0071 +к или 2420, зп 1774 ; 02077 - 0015 2420 0000 1774 +к счи 16, сда 76 ; 02100 - 0042 0016 0036 0076 +к слц 1773, сда 33 ; 02101 - 0013 1773 0036 0033 +к или 1774, пб 2105 ; 02102 - 0015 1774 0300 2105 +к уиа 2257(11), мода ; 02103 - 4640 2257 0220 0000 +к уиа 2106(2), сч 1027 ; 02104 - 1240 2106 0010 1027 +к зп 1774, пб (2) ; 02105 - 0000 1774 1300 0000 +к сч 1774, сда 147 ; 02106 - 0010 1774 0036 0147 +к уи 16, сч 1774 ; 02107 - 0040 0016 0010 1774 +к сда 107, и 2415 ; 02110 - 0036 0107 0011 2415 +к уи 17, нтж 2415 ; 02111 - 0040 0017 0012 2415 +к уи 15, сч 1774 ; 02112 - 0040 0015 0010 1774 +к сда 145, и 2416 ; 02113 - 0036 0145 0011 2416 +к сда 75, уи 6 ; 02114 - 0036 0075 0040 0006 +к сли 6(17), сч 1027(16) ; 02115 - 7445 0006 7010 1027 +к и 2625(6), уиа (1) ; 02116 - 3011 2625 0640 0000 +к по 2120, уиа 2(1) ; 02117 - 0260 2120 0640 0002 +к сч 1775, мода ; 02120 - 0010 1775 0220 0000 +к сда 130, слц 2531 ; 02121 - 0036 0130 0013 2531 +к и 2526, мода ; 02122 - 0011 2526 0220 0000 +к сда 77(1), зп 2527 ; 02123 - 0436 0077 0000 2527 +к счмр, сда 146 ; 02124 - 0031 0000 0036 0146 +к и 2653, зп 2604 ; 02125 - 0011 2653 0000 2604 +к сч, рег 37 ; 02126 - 0010 0000 0002 0037 +к сч 2417, увв 20(16) ; 02127 - 0010 2417 7033 0020 +к уи, сч 1774 ; 02130 - 0040 0000 0010 1774 +к сда 145, и 2416 ; 02131 - 0036 0145 0011 2416 +к или 2654, или 2653 ; 02132 - 0015 2654 0015 2653 +к увв 20(16), уи ; 02133 - 7033 0020 0040 0000 +к рег 237, и 2625(16) ; 02134 - 0002 0237 7011 2625 +к по 2134, сч 2661 ; 02135 - 0260 2134 0010 2661 +к увв 20(16), уи ; 02136 - 7033 0020 0040 0000 +к уи, рег 37 ; 02137 - 0040 0000 0002 0037 +к уиа 2147(6), уиа 11(4) ; 02140 - 3240 2147 2240 0011 +к сч 2655(15), пио 2143(1) ; 02141 - 6410 2655 0740 2143 +к или 2604, мода ; 02142 - 0015 2604 0220 0000 +к или 2421, увв 20(16) ; 02143 - 0015 2421 7033 0020 +к уи, счи 4 ; 02144 - 0040 0000 0042 0004 +к увв 20(16), уи ; 02145 - 7033 0020 0040 0000 +к увв 4000(16), пб (6) ; 02146 - 7033 4000 3300 0000 +к и 2654, уиа 2430(5) ; 02147 - 0011 2654 2640 2430 +к по 2412, уиа -7(6) ; 02150 - 0260 2412 3247 7771 +к сч, мода ; 02151 - 0010 0000 0220 0000 +к мод 2521(16), зп 7(6) ; 02152 - 7230 2521 3000 0007 +к цикл 2152(6), уиа -7(6) ; 02153 - 3370 2152 3247 7771 +к зп 1, цикл 2154(6) ; 02154 - 0000 0001 3370 2154 +к сч 1774, увв (16) ; 02155 - 0010 1774 7033 0000 +к сч 2416, или 2422 ; 02156 - 0010 2416 0015 2422 +к увв 20(16), уи ; 02157 - 7033 0020 0040 0000 +к сч 2527, или 2651 ; 02160 - 0010 2527 0015 2651 +к уи, увв 20(16) ; 02161 - 0040 0000 7033 0020 +к уи, увв ; 02162 - 0040 0000 0033 0000 +к уиа -50(6), мода ; 02163 - 3247 7730 0220 0000 +к зп 1, цикл 2164(6) ; 02164 - 0000 0001 3370 2164 +к сч, уи ; 02165 - 0010 0000 0040 0000 +к рег 37, уиа 76030(6) ; 02166 - 0002 0037 3247 6030 +к уиа 77540(10), мода ; 02167 - 4247 7540 0220 0000 +к сбр, рег 237 ; 02170 - 0020 0000 0002 0237 +к и 2625(16), пе 2175 ; 02171 - 7011 2625 0270 2175 +к цикл 2170(10), цикл 2167(6) ; 02172 - 4370 2170 3370 2167 +к стоп, уиа 2126(7) ; 02173 - 0330 0000 3640 2126 +к уиа 2474(5), пб 2366 ; 02174 - 2640 2474 0300 2366 +к уиа 11(4), пв 2144(6) ; 02175 - 2240 0011 3310 2144 +к зп 2533, и 2651 ; 02176 - 0000 2533 0011 2651 +к пе 2351, увв 4035 ; 02177 - 0270 2351 0033 4035 +к и 2655(16), уиа 2436(5) ; 02200 - 7011 2655 2640 2436 +к пе 2412, уиа 1(10) ; 02201 - 0270 2412 4240 0001 +к уиа 2206(6), уиа 2206(5) ; 02202 - 3240 2206 2640 2206 +к сч 2424, уи 21 ; 02203 - 0010 2424 0040 0021 +к мод 2521(16), сч (10) ; 02204 - 7230 2521 4010 0000 +к уи, пб (6) ; 02205 - 0040 0000 3300 0000 +к зп 2534, и 2535 ; 02206 - 0000 2534 0011 2535 +к нтж 2536, уиа 2460(5) ; 02207 - 0012 2536 2640 2460 +к пе 2412, сч 1774 ; 02210 - 0270 2412 0010 1774 +к и 2660, пе 2302 ; 02211 - 0011 2660 0270 2302 +к сч 2533, и 2652 ; 02212 - 0010 2533 0011 2652 +к уиа 2444(5), пе 2366 ; 02213 - 2640 2444 0270 2366 +к уиа -3(4), уиа (12) ; 02214 - 2247 7775 5240 0000 +к счи 11, нтж 2530 ; 02215 - 0042 0011 0012 2530 +к пе 2217, слиа 2000(12) ; 02216 - 0270 2217 5250 2000 +к сч 2534, и 2614 ; 02217 - 0010 2534 0011 2614 +к пе 2240, уиа -1(10) ; 02220 - 0270 2240 4247 7777 +к уиа 2411(5), сч 2424 ; 02221 - 2640 2411 0010 2424 +к уи 21, уиа 77401(6) ; 02222 - 0040 0021 3247 7401 +к слиа 2(10), сч ; 02223 - 4250 0002 0010 0000 +к мода 70000(12), слц 377(6) ; 02224 - 5227 0000 3013 0377 +к цикл 2224(6), зп 2534 ; 02225 - 3370 2224 0000 2534 +к уиа 2227(5), пв 2203(6) ; 02226 - 2640 2227 3310 2203 +к зп 2533, нтж 2534 ; 02227 - 0000 2533 0012 2534 +к и 2423, пе 2250 ; 02230 - 0011 2423 0270 2250 +к сч 2533, и 2615 ; 02231 - 0010 2533 0011 2615 +к уиа 2444(5), по 2366 ; 02232 - 2640 2444 0260 2366 +к слиа 400(12), мода ; 02233 - 5250 0400 0220 0000 +к цикл 2221(4), уиа 2255(6) ; 02234 - 2370 2221 3240 2255 +к сч 2425, уи 21 ; 02235 - 0010 2425 0040 0021 +к сч 2417, увв 20(16) ; 02236 - 0010 2417 7033 0020 +к уи, пб (6) ; 02237 - 0040 0000 3300 0000 +к уиа 2411(5), сч 2424 ; 02240 - 2640 2411 0010 2424 +к уи 21, уиа 76001(6) ; 02241 - 0040 0021 3247 6001 +к сч, уиа 3(10) ; 02242 - 0010 0000 4240 0003 +к мода 70000(12), слц 1777(6) ; 02243 - 5227 0000 3013 1777 +к цикл 2243(6), зп 2534 ; 02244 - 3370 2243 0000 2534 +к уиа 2246(5), пв 2203(6) ; 02245 - 2640 2246 3310 2203 +к нтж 2534, пе 2213 ; 02246 - 0012 2534 0270 2213 +к уиа 2255(6), пб 2235 ; 02247 - 3240 2255 0300 2235 +к слиа -1(10), уиа 2252(5) ; 02250 - 4257 7777 2640 2252 +к мода, пв 2203(6) ; 02251 - 0220 0000 3310 2203 +к нтж 2534, и 2423 ; 02252 - 0012 2534 0011 2423 +к пе 2213, слиа 1(10) ; 02253 - 0270 2213 4250 0001 +к слиа 400(12), пб 2234 ; 02254 - 5250 0400 0300 2234 +к сч, уи ; 02255 - 0010 0000 0040 0000 +к рег 37, пб (11) ; 02256 - 0002 0037 4700 0000 +к уиа 1(14), пб 2335 ; 02257 - 6240 0001 0300 2335 +к зп 1027, сч 2516 ; 02260 - 0000 1027 0010 2516 +к или 1775, зп 1775 ; 02261 - 0015 1775 0000 1775 +к уиа 2265(11), пб 2104 ; 02262 - 4640 2265 0300 2104 +к слиа 40(4), цикл 2272(14) ; 02263 - 2250 0040 6370 2272 +к уиа 2466(5), пв 2367(7) ; 02264 - 2640 2466 3710 2367 +к сч 2, сда 130 ; 02265 - 0010 0002 0036 0130 +к и 2427, уиа -17(14) ; 02266 - 0011 2427 6247 7761 +к уиа (2), уиа (4) ; 02267 - 1240 0000 2240 0000 +к по 2271, вч 2664 ; 02270 - 0260 2271 0005 2664 +к зп 2542, мода ; 02271 - 0000 2542 0220 0000 +к уиа -37(7), сч 1775 ; 02272 - 3647 7741 0010 1775 +к нтж 70000(4), и 2423 ; 02273 - 2112 0000 0011 2423 +к пе 2263, сч 1775 ; 02274 - 0270 2263 0010 1775 +к сда 155, нтж 70016(4) ; 02275 - 0036 0155 2112 0016 +к и 2415, пе 2263 ; 02276 - 0011 2415 0270 2263 +к счи 2, нтж 2542 ; 02277 - 0042 0002 0012 2542 +к по 2303, слиа 1(2) ; 02300 - 0260 2303 1250 0001 +к пб 2263, мода ; 02301 - 0300 2263 0220 0000 +к уии 6(11), пб 2235 ; 02302 - 4444 0006 0300 2235 +к мода (4), сч 70037(7) ; 02303 - 2220 0000 3510 0037 +к зп 3537(7), цикл 2303(7) ; 02304 - 3400 3537 3770 2303 +к сч 3502, зп 1775 ; 02305 - 0010 3502 0000 1775 +к мода, пв 2040(2) ; 02306 - 0220 0000 1310 2040 +к зп 1030, сч 3500 ; 02307 - 0000 1030 0010 3500 +к зп 1775, сч 3 ; 02310 - 0000 1775 0010 0003 +к и 2660, пб 2103 ; 02311 - 0011 2660 0300 2103 +к уиа -2(14), сч 3515 ; 02312 - 6247 7776 0010 3515 +к сда 117, зп 1775 ; 02313 - 0036 0117 0000 1775 +к и 2423, по 2103 ; 02314 - 0011 2423 0260 2103 +к сч 2663, пв 2123(11) ; 02315 - 0010 2663 4710 2123 +к сч 3516, и 2415 ; 02316 - 0010 3516 0011 2415 +к сда 75, уи 6 ; 02317 - 0036 0075 0040 0006 +к сч 70000(6), нтж 3516 ; 02320 - 3110 0000 0012 3516 +к и 2415, пе 2103 ; 02321 - 0011 2415 0270 2103 +к мода (6), сч 70002(14) ; 02322 - 3220 0000 6110 0002 +к зп 2604(14), цикл 2322(14) ; 02323 - 6000 2604 6370 2322 +к уиа 2510(12), пв 2040(2) ; 02324 - 5240 2510 1310 2040 +к уиа -2(14), пв 2126(11) ; 02325 - 6247 7776 4710 2126 +к сч 70002(14), нтж 2604(14) ; 02326 - 6110 0002 6012 2604 +к уиа 2257(11), пе 2103 ; 02327 - 4640 2257 0270 2103 +к цикл 2326(14), уиа -22(14) ; 02330 - 6370 2326 6247 7756 +к сч 70026(14), зп 1026(14) ; 02331 - 6110 0026 6000 1026 +к цикл 2331(14), уиа 2335(11) ; 02332 - 6370 2331 4640 2335 +к сч 1774, зп 1031 ; 02333 - 0010 1774 0000 1031 +к пб 2104, мода ; 02334 - 0300 2104 0220 0000 +к сч 1774, слц 2650 ; 02335 - 0010 1774 0013 2650 +к зп 1774, сч 1775 ; 02336 - 0000 1774 0010 1775 +к слц 2634, пв 2121(11) ; 02337 - 0013 2634 4710 2121 +к сч 2522, зп 502 ; 02340 - 0010 2522 0000 0502 +к уиа -37(6), мода ; 02341 - 3247 7741 0220 0000 +к сч 3537(6), зп 71777(6) ; 02342 - 3010 3537 3100 1777 +к цикл 2342(6), сч ; 02343 - 3370 2342 0010 0000 +к зп 72000, пб 70000 ; 02344 - 0100 2000 0307 0000 +к уиа 2345(7), пб 2367 ; 02345 - 3640 2345 0300 2367 +к уиа -2(3), сч ; 02346 - 1647 7776 0010 0000 +к слц 2546(3), цикл 2347(3) ; 02347 - 1413 2546 1770 2347 +к пб (10), мода ; 02350 - 4300 0000 0220 0000 +к сч 1774, и 2660 ; 02351 - 0010 1774 0011 2660 +к пе 2060, уиа 31(4) ; 02352 - 0270 2060 2240 0031 +к мода, пв 2144(6) ; 02353 - 0220 0000 3310 2144 +к зп 2534, сч 2533 ; 02354 - 0000 2534 0010 2533 +к и 2654, по 2402 ; 02355 - 0011 2654 0260 2402 +к сч 2534, и 2662 ; 02356 - 0010 2534 0011 2662 +к уиа 2452(5), пе 2404 ; 02357 - 2640 2452 0270 2404 +к сч 2534, и 2660 ; 02360 - 0010 2534 0011 2660 +к уиа 2466(5), пе 2366 ; 02361 - 2640 2466 0270 2366 +к сч 2534, и 2661 ; 02362 - 0010 2534 0011 2661 +к пе 2410, сч 2534 ; 02363 - 0270 2410 0010 2534 +к и 2652, уиа 2452(5) ; 02364 - 0011 2652 2640 2452 +к пе 2366, уиа 2452(5) ; 02365 - 0270 2366 2640 2452 +к уиа 2126(7), пв 2235(6) ; 02366 - 3640 2126 3310 2235 +к уиа -10(10), мода ; 02367 - 4247 7770 0220 0000 +к зп 1, цикл 2370(10) ; 02370 - 0000 0001 4370 2370 +к сч, рег ; 02371 - 0010 0000 0002 0000 +к уиа -5(10), мода ; 02372 - 4247 7773 0220 0000 +к мода (5), сч 5(10) ; 02373 - 2620 0000 4010 0005 +к рег 6(10), цикл 2373(10) ; 02374 - 4002 0006 4370 2373 +к сч, рег 7 ; 02375 - 0010 0000 0002 0007 +к уиа 76030(10), мода ; 02376 - 4247 6030 0220 0000 +к уиа 77526(3), мода ; 02377 - 1647 7526 0220 0000 +к сбр, цикл 2400(3) ; 02400 - 0020 0000 1770 2400 +к цикл 2377(10), пб (7) ; 02401 - 4370 2377 3700 0000 +к сч 2533, уиа 2430(5) ; 02402 - 0010 2533 2640 2430 +к и 2653, по 2366 ; 02403 - 0011 2653 0260 2366 +к уиа 1(4), пв 2144(6) ; 02404 - 2240 0001 3310 2144 +к мода, пв 2235(6) ; 02405 - 0220 0000 3310 2235 +к уиа 76030(10), пв 2377(7) ; 02406 - 4247 6030 3710 2377 +к уиа 2126(7), пб 2367 ; 02407 - 3640 2126 0300 2367 +к уиа 2452(5), пб 2366 ; 02410 - 2640 2452 0300 2366 +к уиа 2126(6), пб 2235 ; 02411 - 3240 2126 0300 2235 +к сч 1774, и 2660 ; 02412 - 0010 1774 0011 2660 +к по 2366, пв 2235(6) ; 02413 - 0260 2366 3310 2235 +к пб 2060, мода ; 02414 - 0300 2060 0220 0000 в 02415 -с 0000 0000 0000 0007 ; 02415 -с 0000 0000 0000 0003 ; 02416 -с 0000 0000 0000 1050 ; 02417 -с 0000 0000 0174 0000 ; 02420 -с 0000 0000 0000 2400 ; 02421 -с 0000 0000 0000 0000 ; 02422 -с 0000 0000 0000 7777 ; 02423 -с 0000 0000 0000 2003 ; 02424 -с 0000 0000 0000 2013 ; 02425 -с 0000 0000 0000 0000 ; 02426 -с 0000 0000 0000 0017 ; 02427 -с 2236 0400 4176 2000 ; 02430 -с 2220 0400 4044 0000 ; 02431 -с 2220 0400 4044 0000 ; 02432 -с 3636 0400 4044 0000 ; 02433 -с 2220 0400 4044 0000 ; 02434 -с 2236 3700 7434 0000 ; 02435 -с 0003 4376 2022 0000 ; 02436 -с 0004 2222 2220 0000 ; 02437 -с 0004 2222 2220 0000 ; 02440 -с 0004 2222 2220 0000 ; 02441 -с 0004 2222 2520 0000 ; 02442 -с 0003 4222 3060 0000 ; 02443 -с 3476 2046 3440 4000 ; 02444 -с 4252 0044 4244 4000 ; 02445 -с 4252 0044 4044 4000 ; 02446 -с 4252 0070 4044 4000 ; 02447 -с 4252 0044 4252 4000 ; 02450 -с 3452 0046 3461 4000 ; 02451 -с 0000 0021 0740 0000 ; 02452 -с 0000 0021 0420 0000 ; 02453 -с 0000 0037 0420 0000 ; 02454 -с 0000 0021 0740 0000 ; 02455 -с 0000 0021 0420 0000 ; 02456 -с 0000 0017 0740 0000 ; 02457 -с 2236 0046 6247 0040 ; 02460 -с 2220 0044 2250 4040 ; 02461 -с 2220 0044 2250 4040 ; 02462 -с 3636 0070 2270 4740 ; 02463 -с 2220 0044 2250 4440 ; 02464 -с 2236 0046 1647 0440 ; 02465 -с 0022 3604 0070 4440 ; 02466 -с 0022 2004 0044 4440 ; 02467 -с 0022 2004 0044 4470 ; 02470 -с 0036 3604 0072 7444 ; 02471 -с 0022 2004 0044 4444 ; 02472 -с 0022 3637 0070 3470 ; 02473 -с 2236 0400 3470 4044 ; 02474 -с 2220 0400 4244 4440 ; 02475 -с 2220 0400 4244 4440 ; 02476 -с 3636 0400 4270 4440 ; 02477 -с 2220 0400 4240 5240 ; 02500 -с 2236 3700 3474 6140 ; 02501 -с 4561 0213 7462 2422 ; 02502 -с 4501 0211 1112 2420 ; 02503 -с 4501 0251 1013 6434 ; 02504 -с 7561 0251 1022 2422 ; 02505 -с 4501 0251 1112 2422 ; 02506 -с 4567 6330 7061 6734 ; 02507 -с 0456 1021 3716 2240 ; 02510 -с 0450 1021 1101 2240 ; 02511 -с 0450 1025 1107 2270 ; 02512 -с 0756 1025 1111 2244 ; 02513 -с 0450 1025 1111 2244 ; 02514 -с 0456 7633 0711 3670 ; 02515 -с 0000 0757 0000 0000 ; 02516 -с 0000 2523 0000 0000 ; 02517 -с 0010 2425 0040 0021 ; 02520 -с 0010 2523 2700 0000 ; 02521 -с 0010 2523 1700 0000 ; 02522 -с 0000 0000 0000 0000 ; 02523 -с 0000 0000 0000 0030 ; 02524 -с 0000 0000 0000 0040 ; 02525 -с 0000 0000 0003 7777 ; 02526 -с 0000 0000 0000 1334 ; 02527 -с 0000 0000 0000 2340 ; 02530 -с 0000 0000 0007 7775 ; 02531 -с 0000 0000 0440 0020 ; 02532 -с 0017 0707 4005 0513 ; 02533 -с 1646 5273 4157 0513 ; 02534 -с 0007 7777 0000 0000 ; 02535 -с 0007 0707 0000 0000 ; 02536 -с 4000 0000 0000 0000 ; 02537 -с 0000 0000 0017 7777 ; 02540 -с 0000 0000 0000 0377 ; 02541 -с 0000 0000 0000 0000 ; 02542 -с 2740 0000 0000 4007 ; 02543 -с 3000 0000 0000 4005 ; 02544 -с 7760 0000 0000 0000 ; 02545 -с 7760 0000 0000 0000 ; 02546 -с 3000 0000 0000 4005 ; 02547 -с 7777 7400 0000 0000 ; 02550 -с 7760 0000 0000 0000 ; 02551 -с 3000 0000 0000 4005 ; 02552 -с 7777 7400 0000 0000 ; 02553 -с 0000 0000 0000 0000 ; 02554 +с 0000 0000 0000 0007 ; 02415 +с 0000 0000 0000 0003 ; 02416 +с 0000 0000 0000 1050 ; 02417 +с 0000 0000 0174 0000 ; 02420 +с 0000 0000 0000 2400 ; 02421 +с 0000 0000 0000 0000 ; 02422 +с 0000 0000 0000 7777 ; 02423 +с 0000 0000 0000 2003 ; 02424 +с 0000 0000 0000 2013 ; 02425 +с 0000 0000 0000 0000 ; 02426 +с 0000 0000 0000 0017 ; 02427 +с 2236 0400 4176 2000 ; 02430 +с 2220 0400 4044 0000 ; 02431 +с 2220 0400 4044 0000 ; 02432 +с 3636 0400 4044 0000 ; 02433 +с 2220 0400 4044 0000 ; 02434 +с 2236 3700 7434 0000 ; 02435 +с 0003 4376 2022 0000 ; 02436 +с 0004 2222 2220 0000 ; 02437 +с 0004 2222 2220 0000 ; 02440 +с 0004 2222 2220 0000 ; 02441 +с 0004 2222 2520 0000 ; 02442 +с 0003 4222 3060 0000 ; 02443 +с 3476 2046 3440 4000 ; 02444 +с 4252 0044 4244 4000 ; 02445 +с 4252 0044 4044 4000 ; 02446 +с 4252 0070 4044 4000 ; 02447 +с 4252 0044 4252 4000 ; 02450 +с 3452 0046 3461 4000 ; 02451 +с 0000 0021 0740 0000 ; 02452 +с 0000 0021 0420 0000 ; 02453 +с 0000 0037 0420 0000 ; 02454 +с 0000 0021 0740 0000 ; 02455 +с 0000 0021 0420 0000 ; 02456 +с 0000 0017 0740 0000 ; 02457 +с 2236 0046 6247 0040 ; 02460 +с 2220 0044 2250 4040 ; 02461 +с 2220 0044 2250 4040 ; 02462 +с 3636 0070 2270 4740 ; 02463 +с 2220 0044 2250 4440 ; 02464 +с 2236 0046 1647 0440 ; 02465 +с 0022 3604 0070 4440 ; 02466 +с 0022 2004 0044 4440 ; 02467 +с 0022 2004 0044 4470 ; 02470 +с 0036 3604 0072 7444 ; 02471 +с 0022 2004 0044 4444 ; 02472 +с 0022 3637 0070 3470 ; 02473 +с 2236 0400 3470 4044 ; 02474 +с 2220 0400 4244 4440 ; 02475 +с 2220 0400 4244 4440 ; 02476 +с 3636 0400 4270 4440 ; 02477 +с 2220 0400 4240 5240 ; 02500 +с 2236 3700 3474 6140 ; 02501 +с 4561 0213 7462 2422 ; 02502 +с 4501 0211 1112 2420 ; 02503 +с 4501 0251 1013 6434 ; 02504 +с 7561 0251 1022 2422 ; 02505 +с 4501 0251 1112 2422 ; 02506 +с 4567 6330 7061 6734 ; 02507 +с 0456 1021 3716 2240 ; 02510 +с 0450 1021 1101 2240 ; 02511 +с 0450 1025 1107 2270 ; 02512 +с 0756 1025 1111 2244 ; 02513 +с 0450 1025 1111 2244 ; 02514 +с 0456 7633 0711 3670 ; 02515 +с 0000 0757 0000 0000 ; 02516 +с 0000 2523 0000 0000 ; 02517 +с 0010 2425 0040 0021 ; 02520 +с 0010 2523 2700 0000 ; 02521 +с 0010 2523 1700 0000 ; 02522 +с 0000 0000 0000 0000 ; 02523 +с 0000 0000 0000 0030 ; 02524 +с 0000 0000 0000 0040 ; 02525 +с 0000 0000 0003 7777 ; 02526 +с 0000 0000 0000 1334 ; 02527 +с 0000 0000 0000 2340 ; 02530 +с 0000 0000 0007 7775 ; 02531 +с 0000 0000 0440 0020 ; 02532 +с 0017 0707 4005 0513 ; 02533 +с 1646 5273 4157 0513 ; 02534 +с 0007 7777 0000 0000 ; 02535 +с 0007 0707 0000 0000 ; 02536 +с 4000 0000 0000 0000 ; 02537 +с 0000 0000 0017 7777 ; 02540 +с 0000 0000 0000 0377 ; 02541 +с 0000 0000 0000 0000 ; 02542 +с 2740 0000 0000 4007 ; 02543 +с 3000 0000 0000 4005 ; 02544 +с 7760 0000 0000 0000 ; 02545 +с 7760 0000 0000 0000 ; 02546 +с 3000 0000 0000 4005 ; 02547 +с 7777 7400 0000 0000 ; 02550 +с 7760 0000 0000 0000 ; 02551 +с 3000 0000 0000 4005 ; 02552 +с 7777 7400 0000 0000 ; 02553 +с 0000 0000 0000 0000 ; 02554 в 02600 -с 0000 0000 0000 0000 ; 02600 -с 0000 0000 0000 0037 ; 02601 -с 0000 0000 0742 1025 ; 02602 -с 0000 0000 0021 0000 ; 02603 -с 0000 0000 0000 0000 ; 02604 -с 4000 0000 0000 0000 ; 02605 -с 2000 0000 0000 0000 ; 02606 -с 1000 0000 0000 0000 ; 02607 -с 0400 0000 0000 0000 ; 02610 -с 0200 0000 0000 0000 ; 02611 -с 0100 0000 0000 0000 ; 02612 -с 0040 0000 0000 0000 ; 02613 -с 0020 0000 0000 0000 ; 02614 -с 0010 0000 0000 0000 ; 02615 -с 0004 0000 0000 0000 ; 02616 -с 0002 0000 0000 0000 ; 02617 -с 0001 0000 0000 0000 ; 02620 -с 0000 4000 0000 0000 ; 02621 -с 0000 2000 0000 0000 ; 02622 -с 0000 1000 0000 0000 ; 02623 -с 0000 0400 0000 0000 ; 02624 -с 0000 0200 0000 0000 ; 02625 -с 0000 0100 0000 0000 ; 02626 -с 0000 0040 0000 0000 ; 02627 -с 0000 0020 0000 0000 ; 02630 -с 0000 0010 0000 0000 ; 02631 -с 0000 0004 0000 0000 ; 02632 -с 0000 0002 0000 0000 ; 02633 -с 0000 0001 0000 0000 ; 02634 -с 0000 0000 4000 0000 ; 02635 -с 0000 0000 2000 0000 ; 02636 -с 0000 0000 1000 0000 ; 02637 -с 0000 0000 0400 0000 ; 02640 -с 0000 0000 0200 0000 ; 02641 -с 0000 0000 0100 0000 ; 02642 -с 0000 0000 0040 0000 ; 02643 -с 0000 0000 0020 0000 ; 02644 -с 0000 0000 0010 0000 ; 02645 -с 0000 0000 0004 0000 ; 02646 -с 0000 0000 0002 0000 ; 02647 -с 0000 0000 0001 0000 ; 02650 -с 0000 0000 0000 4000 ; 02651 -с 0000 0000 0000 2000 ; 02652 -с 0000 0000 0000 1000 ; 02653 -с 0000 0000 0000 0400 ; 02654 -с 0000 0000 0000 0200 ; 02655 -с 0000 0000 0000 0100 ; 02656 -с 0000 0000 0000 0040 ; 02657 -с 0000 0000 0000 0020 ; 02660 -с 0000 0000 0000 0010 ; 02661 -с 0000 0000 0000 0004 ; 02662 -с 0000 0000 0000 0002 ; 02663 -с 0000 0000 0000 0001 ; 02664 +с 0000 0000 0000 0000 ; 02600 +с 0000 0000 0000 0037 ; 02601 +с 0000 0000 0742 1025 ; 02602 +с 0000 0000 0021 0000 ; 02603 +с 0000 0000 0000 0000 ; 02604 +с 4000 0000 0000 0000 ; 02605 +с 2000 0000 0000 0000 ; 02606 +с 1000 0000 0000 0000 ; 02607 +с 0400 0000 0000 0000 ; 02610 +с 0200 0000 0000 0000 ; 02611 +с 0100 0000 0000 0000 ; 02612 +с 0040 0000 0000 0000 ; 02613 +с 0020 0000 0000 0000 ; 02614 +с 0010 0000 0000 0000 ; 02615 +с 0004 0000 0000 0000 ; 02616 +с 0002 0000 0000 0000 ; 02617 +с 0001 0000 0000 0000 ; 02620 +с 0000 4000 0000 0000 ; 02621 +с 0000 2000 0000 0000 ; 02622 +с 0000 1000 0000 0000 ; 02623 +с 0000 0400 0000 0000 ; 02624 +с 0000 0200 0000 0000 ; 02625 +с 0000 0100 0000 0000 ; 02626 +с 0000 0040 0000 0000 ; 02627 +с 0000 0020 0000 0000 ; 02630 +с 0000 0010 0000 0000 ; 02631 +с 0000 0004 0000 0000 ; 02632 +с 0000 0002 0000 0000 ; 02633 +с 0000 0001 0000 0000 ; 02634 +с 0000 0000 4000 0000 ; 02635 +с 0000 0000 2000 0000 ; 02636 +с 0000 0000 1000 0000 ; 02637 +с 0000 0000 0400 0000 ; 02640 +с 0000 0000 0200 0000 ; 02641 +с 0000 0000 0100 0000 ; 02642 +с 0000 0000 0040 0000 ; 02643 +с 0000 0000 0020 0000 ; 02644 +с 0000 0000 0010 0000 ; 02645 +с 0000 0000 0004 0000 ; 02646 +с 0000 0000 0002 0000 ; 02647 +с 0000 0000 0001 0000 ; 02650 +с 0000 0000 0000 4000 ; 02651 +с 0000 0000 0000 2000 ; 02652 +с 0000 0000 0000 1000 ; 02653 +с 0000 0000 0000 0400 ; 02654 +с 0000 0000 0000 0200 ; 02655 +с 0000 0000 0000 0100 ; 02656 +с 0000 0000 0000 0040 ; 02657 +с 0000 0000 0000 0020 ; 02660 +с 0000 0000 0000 0010 ; 02661 +с 0000 0000 0000 0004 ; 02662 +с 0000 0000 0000 0002 ; 02663 +с 0000 0000 0000 0001 ; 02664 в 03000 -к по 3002, мода ; 03000 - 0260 3002 0220 0000 -к ржа 3, пб 2015 ; 03001 - 0037 0003 0300 2015 -к уиа 3004(7), уиа 2466(5) ; 03002 - 3640 3004 2640 2466 -к пб 2367, мода ; 03003 - 0300 2367 0220 0000 -к слиа 1(1), пб 3004 ; 03004 - 0650 0001 0300 3004 +к по 3002, мода ; 03000 - 0260 3002 0220 0000 +к ржа 3, пб 2015 ; 03001 - 0037 0003 0300 2015 +к уиа 3004(7), уиа 2466(5) ; 03002 - 3640 3004 2640 2466 +к пб 2367, мода ; 03003 - 0300 2367 0220 0000 +к слиа 1(1), пб 3004 ; 03004 - 0650 0001 0300 3004 в 03500 -с 0000 0560 0000 4005 ; 03500 -с 4000 0000 0000 4005 ; 03501 -с 0000 0000 0000 4005 ; 03502 -с 0000 0000 0000 4005 ; 03503 -с 0000 0000 0000 0006 ; 03504 -с 4000 0000 0000 0000 ; 03505 -с 0000 0000 0000 3320 ; 03506 -с 0000 0000 0000 0022 ; 03507 -с 0000 0000 0000 0021 ; 03510 -с 7760 0000 3760 0000 ; 03511 -с 0000 0000 0000 0000 ; 03512 -с 0000 0000 0000 0000 ; 03513 -с 0000 0000 0000 0000 ; 03514 -с 4000 0070 0004 0310 ; 03515 -с 1770 0000 0000 0003 ; 03516 -с 0000 0000 1600 4227 ; 03517 -с 3722 1066 0361 6435 ; 03520 -с 0000 0000 0000 0000 ; 03521 -с 7760 0000 0000 0000 ; 03522 -с 7760 0000 0000 3220 ; 03523 -с 0000 0000 1022 4005 ; 03524 -с 1240 0000 0000 0000 ; 03525 -с 1313 1413 1413 1413 ; 03526 -с 7777 4000 6000 0000 ; 03527 -с 7403 0000 0000 0000 ; 03530 -с 7777 7777 7777 7777 ; 03531 -с 0000 0017 7760 0000 ; 03532 -с 0000 0000 0000 0000 ; 03533 -с 0000 0000 0000 0000 ; 03534 -с 0000 0000 0000 0000 ; 03535 -с 0000 0000 7760 0000 ; 03536 -с 0000 0000 0000 0000 ; 03537 +с 0000 0560 0000 4005 ; 03500 +с 4000 0000 0000 4005 ; 03501 +с 0000 0000 0000 4005 ; 03502 +с 0000 0000 0000 4005 ; 03503 +с 0000 0000 0000 0006 ; 03504 +с 4000 0000 0000 0000 ; 03505 +с 0000 0000 0000 3320 ; 03506 +с 0000 0000 0000 0022 ; 03507 +с 0000 0000 0000 0021 ; 03510 +с 7760 0000 3760 0000 ; 03511 +с 0000 0000 0000 0000 ; 03512 +с 0000 0000 0000 0000 ; 03513 +с 0000 0000 0000 0000 ; 03514 +с 4000 0070 0004 0310 ; 03515 +с 1770 0000 0000 0003 ; 03516 +с 0000 0000 1600 4227 ; 03517 +с 3722 1066 0361 6435 ; 03520 +с 0000 0000 0000 0000 ; 03521 +с 7760 0000 0000 0000 ; 03522 +с 7760 0000 0000 3220 ; 03523 +с 0000 0000 1022 4005 ; 03524 +с 1240 0000 0000 0000 ; 03525 +с 1313 1413 1413 1413 ; 03526 +с 7777 4000 6000 0000 ; 03527 +с 7403 0000 0000 0000 ; 03530 +с 7777 7777 7777 7777 ; 03531 +с 0000 0017 7760 0000 ; 03532 +с 0000 0000 0000 0000 ; 03533 +с 0000 0000 0000 0000 ; 03534 +с 0000 0000 0000 0000 ; 03535 +с 0000 0000 7760 0000 ; 03536 +с 0000 0000 0000 0000 ; 03537 diff --git a/BESM6/formatdisk.c b/BESM6/formatdisk.c old mode 100755 new mode 100644 diff --git a/BESM6/test_pprog05.b6 b/BESM6/test_pprog05.b6 index e136bf5a..12b9e778 100644 --- a/BESM6/test_pprog05.b6 +++ b/BESM6/test_pprog05.b6 @@ -22,16 +22,16 @@ ; (110000 – порядок числа). ; в 1 -к сл 7, зп 11 ; код := т.рег.7 -к вчп 11, зп 10 ; в эталон -к умн 10, дел 10 -к вч 10, слпа 145 ; 64+37 -к пе 6, стоп +к сл 7, зп 11 ; код := т.рег.7 +к вчп 11, зп 10 ; в эталон +к умн 10, дел 10 +к вч 10, слпа 145 ; 64+37 +к пе 6, стоп в 6 -к сч 11, пб 1 ; если хорошо +к сч 11, пб 1 ; если хорошо в 7 -ч 1.0 ; тумб.регистр 7 -с 0 ; эталон -с 0 ; код +ч 1.0 ; тумб.регистр 7 +с 0 ; эталон +с 0 ; код п 1 diff --git a/BESM6/test_pprog05.ini b/BESM6/test_pprog05.ini index f809d939..024c235d 100644 --- a/BESM6/test_pprog05.ini +++ b/BESM6/test_pprog05.ini @@ -7,7 +7,6 @@ load test_pprog05.b6 ex -ml 1-6 ex 7-11 echo -go echo Должно быть четыре останова с числами на сумматоре: 1.0 2.0 3.0 4.0. br 2 go From 54ec99f95eaf0abb553bc69ae2683ff73539a7bd Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 30 Dec 2014 13:43:27 -0800 Subject: [PATCH 04/41] Visual Studio Projects: Added BESM6 project --- Visual Studio Projects/BESM6.vcproj | 343 ++++++++++++++++++++++++++++ Visual Studio Projects/Simh.sln | 6 + 2 files changed, 349 insertions(+) create mode 100644 Visual Studio Projects/BESM6.vcproj diff --git a/Visual Studio Projects/BESM6.vcproj b/Visual Studio Projects/BESM6.vcproj new file mode 100644 index 00000000..99ff13d2 --- /dev/null +++ b/Visual Studio Projects/BESM6.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index 8e362321..86f38e95 100644 --- a/Visual Studio Projects/Simh.sln +++ b/Visual Studio Projects/Simh.sln @@ -113,6 +113,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SAGE", "SAGE.vcproj", "{9D0 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDQ3", "PDQ3.vcproj", "{D4F5761A-B543-40ED-9892-12A0255C2B6D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BESM6", "BESM6.vcproj", "{A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -283,6 +285,10 @@ Global {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Debug|Win32.Build.0 = Debug|Win32 {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.ActiveCfg = Release|Win32 {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.Build.0 = Release|Win32 + {A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}.Debug|Win32.ActiveCfg = Debug|Win32 + {A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}.Debug|Win32.Build.0 = Debug|Win32 + {A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}.Release|Win32.ActiveCfg = Release|Win32 + {A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 2819ff634e0b2d2a74e69a2c1269d3fc4a89866b Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 30 Dec 2014 17:49:36 -0800 Subject: [PATCH 05/41] BESM6: FIx makefile conditional logic detecting available SDL components --- makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 162a954f..9e92b82c 100644 --- a/makefile +++ b/makefile @@ -1175,10 +1175,12 @@ FORMATDISK = ${BESM6D}/formatdisk.c ifeq (,${VIDEO_LDFLAGS}) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 -else ifneq (,$(and $(findstring,SDL2,${VIDEO_LDFLAGS})),$(and($(find_include, SDL2/SDL_ttf),$(find_lib,SDL2_ttf)))) +else ifneq (,$(and $(findstring SDL2,${VIDEO_LDFLAGS}),$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf))) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf -else ifneq (,$(and $(find_include, SDL/SDL_ttf),$(find_lib,SDL_ttf))) +else ifneq (,$(and $(call find_include,SDL/SDL_ttf),$(call find_lib,SDL_ttf))) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf +else + BESM6_OPT = -I ${BESM6D} -DUSE_INT64 endif ### From 76dd31ae027d4216749b070783a6404622def965 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 30 Dec 2014 17:52:13 -0800 Subject: [PATCH 06/41] BESM6: Compiler suggested cleanups (MSVC). --- BESM6/besm6_arith.c | 2 +- BESM6/besm6_cpu.c | 8 ++++---- BESM6/besm6_mmu.c | 7 ++++--- BESM6/besm6_sys.c | 16 ++++++++-------- BESM6/besm6_tty.c | 4 +++- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/BESM6/besm6_arith.c b/BESM6/besm6_arith.c index 016c2c01..082078c3 100644 --- a/BESM6/besm6_arith.c +++ b/BESM6/besm6_arith.c @@ -45,7 +45,7 @@ static alureg_t toalu (t_value val) return ret; } -static int inline is_negative (alureg_t *word) +static int SIM_INLINE is_negative (alureg_t *word) { return (word->mantissa & BIT41) != 0; } diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 9da7c6be..f1e6fc31 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -54,9 +54,7 @@ #include #include #include -#include #include -#include #include #include @@ -769,11 +767,12 @@ void check_initial_setup () pult[5] = 1 << 21; GRP |= GRP_PANEL_REQ; } else { + struct tm * d; + /* Яч. ГОД обновляем самостоятельно */ time_t t; t_value date; time(&t); - struct tm * d; d = localtime(&t); ++d->tm_mon; date = (t_value) (d->tm_mday / 10) << 33 | @@ -803,9 +802,10 @@ void check_initial_setup () void cpu_one_inst () { int reg, opcode, addr, nextpc, next_mod; + t_value word; corr_stack = 0; - t_value word = mmu_fetch (PC); + word = mmu_fetch (PC); if (RUU & RUU_RIGHT_INSTR) RK = word; /* get right instruction */ else diff --git a/BESM6/besm6_mmu.c b/BESM6/besm6_mmu.c index 7428cb72..486f4e45 100644 --- a/BESM6/besm6_mmu.c +++ b/BESM6/besm6_mmu.c @@ -139,7 +139,7 @@ t_stat mmu_reset (DEVICE *dptr) { int i; for (i = 0; i < 8; ++i) { - BRZ[i] = BAZ[i] = RP[i] = 0; + BRZ[i] = RP[i] = BAZ[i] = 0; } TABST = 0; OLDEST = 0; @@ -209,12 +209,13 @@ void mmu_protection_check (int addr) void mmu_flush (int idx) { + int waddr = BAZ[idx]; + if (! BAZ[idx]) { /* Был пуст после сброса или выталкивания */ return; } /* Вычисляем физический адрес выталкиваемого БРЗ */ - int waddr = BAZ[idx]; waddr = (waddr > 0100000) ? (waddr - 0100000) : (waddr & 01777) | (TLB[waddr >> 10] << 10); memory[waddr] = BRZ[idx]; @@ -626,7 +627,7 @@ void mmu_setprotection (int idx, t_value val) /* Разряды сумматора, записываемые в регистр защиты - 21-28 */ int mask = 0xff << (idx * 8); val = ((val >> 20) & 0xff) << (idx * 8); - RZ = (RZ & ~mask) | val; + RZ = (uint32)((RZ & ~mask) | val); } void mmu_setcache (int idx, t_value val) diff --git a/BESM6/besm6_sys.c b/BESM6/besm6_sys.c index 01014aa2..86cfe8cb 100644 --- a/BESM6/besm6_sys.c +++ b/BESM6/besm6_sys.c @@ -24,7 +24,6 @@ */ #include "besm6_defs.h" #include -#include const char *opname_short_bemsh [64] = { "зп", "зпм", "рег", "счм", "сл", "вч", "вчоб","вчаб", @@ -188,7 +187,7 @@ t_value ieee_to_besm6 (double d) d = frexp (d, &exponent); /* 0.5 <= d < 1.0 */ d = ldexp (d, 40); - word = d; + word = (t_value)d; if (d - word >= 0.5) word += 1; /* Округление. */ if (exponent < -64) @@ -207,6 +206,7 @@ t_value ieee_to_besm6 (double d) double besm6_to_ieee (t_value word) { double mantissa; + int exponent; /* Убираем свертку */ word &= BITS48; @@ -214,9 +214,9 @@ double besm6_to_ieee (t_value word) /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. */ - mantissa = (t_int64) word << (64 - 48 + 7); + mantissa = (double)(((t_int64) word) << (64 - 48 + 7)); - int exponent = word >> 41; + exponent = word >> 41; /* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */ return ldexp (mantissa, exponent - 64 - 63); @@ -472,7 +472,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, if (sw & SWMASK ('M')) { /* symbolic decode? */ if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR)) fprintf (of, "-> "); - besm6_fprint_cmd (of, cmd >> 24); + besm6_fprint_cmd (of, (uint32)(cmd >> 24)); if (sw & SIM_SW_STOP) /* stop point */ fprintf (of, ", "); else @@ -638,7 +638,7 @@ t_stat besm6_load (FILE *input) case 0: /* EOF */ return SCPE_OK; case ':': /* address */ - addr = word; + addr = (int)word; break; case '=': /* word */ if (addr < 010) @@ -655,7 +655,7 @@ t_stat besm6_load (FILE *input) ++addr; break; case '@': /* start address */ - PC = word; + PC = (uint32)word; break; } if (addr > MEMSIZE) @@ -686,7 +686,7 @@ t_stat besm6_dump (FILE *of, char *fnam) last_addr = addr; if (IS_INSN (word)) { fprintf (of, "к "); - besm6_fprint_cmd (of, word >> 24); + besm6_fprint_cmd (of, (uint32)(word >> 24)); fprintf (of, ", "); besm6_fprint_cmd (of, word & BITS(24)); fprintf (of, "\t\t; %05o - ", addr); diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 14ea236e..ad80ec56 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -166,6 +166,8 @@ t_stat tty_reset (DEVICE *dptr) /* 19 р ГРП, 300 Гц */ t_stat vt_clk (UNIT * this) { + int num; + /* Телетайпы работают на 10 бод */ static int clk_divider = 1<<29; GRP |= MGRP & BBIT(19); @@ -184,7 +186,7 @@ t_stat vt_clk (UNIT * this) } /* Есть новые сетевые подключения? */ - int num = tmxr_poll_conn (&tty_desc); + num = tmxr_poll_conn (&tty_desc); if (num > 0 && num <= LINES_MAX) { char buf [80]; TMLN *t = &tty_line [num]; From 82d5b01f84ce8a53e7efc668b50a516fefe10e29 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 30 Dec 2014 18:56:09 -0800 Subject: [PATCH 07/41] BESM6: besm6_punch migrate to use sim_fio API to set a fifo to non-blocking --- BESM6/besm6_punch.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c index 42906b15..c160bf3b 100644 --- a/BESM6/besm6_punch.c +++ b/BESM6/besm6_punch.c @@ -28,7 +28,6 @@ */ #include "besm6_defs.h" #include -#include t_stat fs_event (UNIT *u); t_stat uvvk_event (UNIT *u); @@ -125,13 +124,7 @@ t_stat fs_attach (UNIT *u, char *cptr) s = attach_unit (u, cptr); if (s != SCPE_OK) return s; - struct stat stbuf; - fstat (fileno(u->fileref), &stbuf); - isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0; - if (isfifo[num]) { - int flags = fcntl(fileno(u->fileref), F_GETFL, 0); - fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK); - } + isfifo[num] = (0 == sim_set_fifo_nonblock (u->fileref)); ENB_RDY(FS1_READY >> num); return SCPE_OK; } From 8a5d22bd60c132fbc9b1c9034daefd3e36e97e53 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Tue, 30 Dec 2014 18:56:41 -0800 Subject: [PATCH 08/41] BESM6: No need for the SDL_main trick in SDL1. --- BESM6/besm6_panel.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c index e2bc2e73..2fcbab6a 100644 --- a/BESM6/besm6_panel.c +++ b/BESM6/besm6_panel.c @@ -569,22 +569,6 @@ void besm6_draw_panel () longjmp (cpu_halt, SCPE_STOP); } -#if !defined(__WIN32__) && \ - !(defined(__MWERKS__) && !defined(__BEOS__)) && \ - !defined(__MACOS__) && !defined(__MACOSX__) && \ - !defined(__SYMBIAN32__) && !defined(QWS) -#undef main - -/* - * Вот так всё непросто. - */ -int main (int argc, char *argv[]) -{ - extern int SDL_main (int, char**); - - return SDL_main (argc, argv); -} -#endif #endif /* SDL_MAJOR_VERSION */ #else /* HAVE_LIBSDL */ From 871b19cf8bc39acd4a666214d84ae07e52013179 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Wed, 31 Dec 2014 00:49:43 -0800 Subject: [PATCH 09/41] BESM6: Moved 'formatdisk' functionality to disk_attach(), fixed a typo in TTY input processing. --- BESM6/besm6_disk.c | 59 ++++++++++++++++++++++++++++++++++++++++--- BESM6/besm6_tty.c | 2 +- BESM6/dispak.ini | 3 +-- BESM6/formatdisk.c | 63 ---------------------------------------------- makefile | 8 +----- 5 files changed, 59 insertions(+), 76 deletions(-) delete mode 100644 BESM6/formatdisk.c diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index b5febae9..40e5065c 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -28,6 +28,7 @@ * authorization from Leonid Broukhis and Serge Vakulenko. */ #include "besm6_defs.h" +#include /* * Управляющее слово обмена с магнитным диском. @@ -48,6 +49,11 @@ */ #define STATUS_GOOD 014000400 +/* + * Total size of a disk in blocks, including hidden blocks + */ +#define DISK_TOTBLK 01767 + /* * Параметры обмена с внешним устройством. */ @@ -160,10 +166,57 @@ t_stat disk_reset (DEVICE *dptr) t_stat disk_attach (UNIT *u, char *cptr) { t_stat s; + int32 saved_switches = sim_switches; + sim_switches |= SWMASK ('E'); - s = attach_unit (u, cptr); - if (s != SCPE_OK) - return s; + while (1) { + s = attach_unit (u, cptr); + if ((s == SCPE_OK) && (sim_switches & SWMASK ('N'))) { + t_value control[4]; /* block (zone) number, key, userid, checksum */ + int diskno, blkno, word; + char *pos; + /* Using the rightmost sequence of digits within the filename + * as a volume number, e.g. "/var/tmp/besm6/2052.bin" -> 2052 + */ + pos = cptr + strlen(cptr); + while (pos > cptr && !isdigit(*--pos)); + while (pos > cptr && isdigit(*pos)) --pos; + if (!isdigit(*pos)) ++pos; + diskno = atoi(pos); + if (diskno < 2048 || diskno > 4095) { + if (diskno == 0) + sim_printf ("%s: filename must contain volume number 2048..4095\n", sim_uname(u)); + else + sim_printf ("%s: disk volume %d from filename %s invalid (must be 2048..4095)\n", + sim_uname (u), diskno, cptr); + /* unlink (cptr); ??? */ + return SCPE_ARG; + } + if (!sim_quiet && !(sim_switches & SWMASK ('Q'))) + sim_printf ("%s: formatting disk volume %d\n", sim_uname (u), diskno); + + control[1] = SET_CONVOL(0, CONVOL_NUMBER); + control[2] = SET_CONVOL(0, CONVOL_NUMBER); + control[3] = SET_CONVOL(0, CONVOL_NUMBER); + + control[1] |= 01370707LL << 24; /* Magic mark */ + control[1] |= diskno << 12; + + for (blkno = 0; blkno < DISK_TOTBLK; ++blkno) { + control[0] = SET_CONVOL((t_value)(2*blkno) << 36, CONVOL_NUMBER); + fwrite(control, sizeof(t_value), 4, u->fileref); + control[0] = SET_CONVOL((t_value)(2*blkno+1) << 36, CONVOL_NUMBER); + fwrite(control, sizeof(t_value), 4, u->fileref); + for (word = 0; word < 02000; ++word) { + fwrite(control+2, sizeof(t_value), 1, u->fileref); + } + } + return SCPE_OK; + } + if (saved_switches & SWMASK ('E')) + return s; + sim_switches |= SWMASK ('N'); + } return SCPE_OK; } diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index ad80ec56..f260fe8b 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -617,7 +617,7 @@ void tt_print() */ static int unicode_to_koi7 (unsigned val) { - if ('_' <= val) return val; + if (val <= '_') return val; else if ('a' <= val && val <= 'z') return val + 'Z' - 'z'; else switch (val) { case 0x007f: return 0x7f; diff --git a/BESM6/dispak.ini b/BESM6/dispak.ini index d182d028..c812b662 100644 --- a/BESM6/dispak.ini +++ b/BESM6/dispak.ini @@ -16,13 +16,12 @@ attach drum1 drum2x.bin ; ; Создаем рабочий диск. ; -! ./formatdisk 2052 > 2052.bin +attach -n disk6 2052.bin ; ; Подключаем диски. ; attach -e disk7 sbor2053.bin -attach -e disk6 2052.bin attach -e disk5 krab2063.bin attach -e disk0 sbor2048.bin attach -e disk1 svs2048.bin diff --git a/BESM6/formatdisk.c b/BESM6/formatdisk.c deleted file mode 100644 index b72c7b86..00000000 --- a/BESM6/formatdisk.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * formatdisk.c - A utility to produce blank BESM-6 disk images. - * - * Copyright (c) 2014 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 -#include -#include -#include "besm6_defs.h" - -#define TOTBLK 01767 - -int main(int argc, char ** argv) { - t_value control[4]; /* block (zone) number, key, userid, checksum */ - int diskno, blkno, word; - - if (argc != 2 || (diskno = atoi(argv[1])) < 2048 || diskno > 4095) { - fprintf(stderr, "Usage: formatdisk NNNN > diskNNNN.bin, where 2048 <= NNNN <= 4095\n"); - exit(1); - } - - control[1] = SET_CONVOL(0, CONVOL_NUMBER); - control[2] = SET_CONVOL(0, CONVOL_NUMBER); - control[3] = SET_CONVOL(0, CONVOL_NUMBER); - - control[1] |= 01370707LL << 24; /* Magic */ - control[1] |= diskno << 12; - - for (blkno = 0; blkno < TOTBLK; ++blkno) { - control[0] = SET_CONVOL((t_value)(2*blkno) << 36, CONVOL_NUMBER); - fwrite(control, sizeof(t_value), 4, stdout); - control[0] = SET_CONVOL((t_value)(2*blkno+1) << 36, CONVOL_NUMBER); - fwrite(control, sizeof(t_value), 4, stdout); - for (word = 0; word < 02000; ++word) { - fwrite(control+2, sizeof(t_value), 1, stdout); - } - } - exit(0); -} diff --git a/makefile b/makefile index 9e92b82c..0ac02237 100644 --- a/makefile +++ b/makefile @@ -1171,8 +1171,6 @@ BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \ ${BESM6D}/besm6_tty.c ${BESM6D}/besm6_panel.c ${BESM6D}/besm6_printer.c \ ${BESM6D}/besm6_punch.c -FORMATDISK = ${BESM6D}/formatdisk.c - ifeq (,${VIDEO_LDFLAGS}) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 else ifneq (,$(and $(findstring SDL2,${VIDEO_LDFLAGS}),$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf))) @@ -1486,16 +1484,12 @@ ${BIN}ssem${EXE} : ${SSEM} ${SIM} ${MKDIRBIN} ${CC} ${SSEM} ${SIM} ${SSEM_OPT} $(CC_OUTSPEC) ${LDFLAGS} -besm6 : ${BIN}besm6${EXE} ${BIN}formatdisk${EXE} +besm6 : ${BIN}besm6${EXE} ${BIN}besm6${EXE} : ${BESM6} ${SIM} ${MKDIRBIN} ${CC} ${BESM6} ${SIM} ${BESM6_OPT} $(CC_OUTSPEC) ${LDFLAGS} -${BIN}formatdisk${EXE} : ${FORMATDISK} - ${MKDIRBIN} - ${CC} ${FORMATDISK} ${BESM6_OPT} $(CC_OUTSPEC) - sigma : ${BIN}sigma${EXE} ${BIN}sigma${EXE} : ${SIGMA} ${SIM} From aa60cc72ad9038a7856b94bbd28fbe137c585c10 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 31 Dec 2014 08:08:02 -0800 Subject: [PATCH 10/41] BESM6: Added makefile display of SDL_ttf components being used --- makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/makefile b/makefile index 0ac02237..f2eb6907 100644 --- a/makefile +++ b/makefile @@ -1174,8 +1174,10 @@ BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \ ifeq (,${VIDEO_LDFLAGS}) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 else ifneq (,$(and $(findstring SDL2,${VIDEO_LDFLAGS}),$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf))) + $(info using libSDL2_ttf: $(call find_lib,SDL2_ttf) $(call find_include,SDL2/SDL_ttf)) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf else ifneq (,$(and $(call find_include,SDL/SDL_ttf),$(call find_lib,SDL_ttf))) + $(info using libSDL_ttf: $(call find_lib,SDL_ttf) $(call find_include,SDL/SDL_ttf)) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf else BESM6_OPT = -I ${BESM6D} -DUSE_INT64 From db44518808033e11bf53a6e9d9603c55f2ef672c Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 31 Dec 2014 08:39:40 -0800 Subject: [PATCH 11/41] BESM6: Convert to simh calibrated clocks and idling --- BESM6/besm6_cpu.c | 102 +++++++++++++++--------------------------- BESM6/besm6_defs.h | 4 +- BESM6/besm6_disk.c | 4 +- BESM6/besm6_drum.c | 4 +- BESM6/besm6_printer.c | 10 ++--- BESM6/besm6_punch.c | 3 +- BESM6/besm6_tty.c | 7 +-- 7 files changed, 52 insertions(+), 82 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index f1e6fc31..3e52ecbf 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -53,18 +53,15 @@ #include "besm6_defs.h" #include #include -#include -#include -#include #include -#undef SOFT_CLOCK t_value memory [MEMSIZE]; uint32 PC, RK, Aex, M [NREGS], RAU, RUU; t_value ACC, RMR, GRP, MGRP; uint32 PRP, MPRP; uint32 READY, READY2; /* ready flags of various devices */ +int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ extern const char *scp_errors[]; @@ -133,6 +130,8 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle, NULL, "Display idle detection mode" }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL, "Disables idle detection" }, { 0 } }; @@ -311,33 +310,6 @@ t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw) return SCPE_OK; } -/* - * Функция вызывается каждые 4 миллисекунды реального времени. - */ -static void cpu_sigalarm (int signum) -{ - static unsigned counter; - - ++counter; - -#ifndef SOFT_CLOCK - /* В 9-й части частота таймера 250 Гц (4 мс). */ - GRP |= GRP_TIMER; - - /* Медленный таймер: должен быть 16 Гц. - * Но от него почему-то зависит вывод на терминалы, - * поэтому ускорим. */ - if ((counter & 3) == 0) { - GRP |= GRP_SLOW_CLK; - } -#endif - - /* Перерисовка панели каждые 64 миллисекунды. */ - if ((counter & 15) == 0) { - redraw_panel = 1; - } -} - /* * Reset routine */ @@ -367,19 +339,6 @@ t_stat cpu_reset (DEVICE *dptr) sim_brk_types = SWMASK ('E') | SWMASK('R') | SWMASK('W'); sim_brk_dflt = SWMASK ('E'); - struct itimerval itv; - - /* Чтобы ход часов в ДИСПАКе соответствал реальному времени, - * используем сигналы от системного таймера. */ - signal (SIGALRM, cpu_sigalarm); - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 4000; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 4000; - if (setitimer (ITIMER_REAL, &itv, 0) < 0) { - perror ("setitimer"); - return SCPE_TIMER; - } return SCPE_OK; } @@ -807,9 +766,9 @@ void cpu_one_inst () corr_stack = 0; word = mmu_fetch (PC); if (RUU & RUU_RIGHT_INSTR) - RK = word; /* get right instruction */ + RK = (uint32)word; /* get right instruction */ else - RK = word >> 24; /* get left instruction */ + RK = (uint32)(word >> 24);/* get left instruction */ RK &= BITS(24); @@ -1475,11 +1434,7 @@ void cpu_one_inst () /* Если периферия простаивает, освобождаем процессор * до следующего тика таймера. */ - if (vt_is_idle() && - printer_is_idle() && fs_is_idle()) { - check_initial_setup (); - pause (); - } + sim_idle (0, TRUE); } } @@ -1739,43 +1694,56 @@ t_stat sim_instr (void) } } -t_stat slow_clk (UNIT * this) -{ - /*besm6_debug ("*** таймер 80 мсек");*/ - GRP |= GRP_SLOW_CLK; - return sim_activate (this, MSEC*125/2); -} - /* * В 9-й части частота таймера 250 Гц (4 мс), * в жизни - 50 Гц (20 мс). */ t_stat fast_clk (UNIT * this) { + static unsigned counter; + + ++counter; + /*besm6_debug ("*** таймер 20 мсек");*/ GRP |= GRP_TIMER; - return sim_activate (this, 20*MSEC); + + /* Медленный таймер: должен быть 16 Гц. + * Но от него почему-то зависит вывод на терминалы, + * поэтому ускорим. */ + if ((counter & 3) == 0) { + /*besm6_debug ("*** таймер 80 мсек");*/ + GRP |= GRP_SLOW_CLK; + } + + /* Перерисовка панели каждые 64 миллисекунды. */ + if ((counter & 15) == 0) { + redraw_panel = 1; + } + + tmr_poll = sim_rtcn_calb (CLK_TPS, 0); /* calibrate clock */ + return sim_activate_after (this, 1000000/CLK_TPS); /* reactivate unit */ } UNIT clocks[] = { - { UDATA(slow_clk, 0, 0) }, /* 10 р, 16 Гц */ - { UDATA(fast_clk, 0, 0) }, /* 40 р, 50 Гц */ + { UDATA(fast_clk, 0, 0), CLK_DELAY }, /* 40 р, 50 Гц */ }; t_stat clk_reset (DEVICE * dev) { + sim_register_clock_unit (&clocks[0]); + /* Схема автозапуска включается по нереализованной кнопке "МР" */ -#ifdef SOFT_CLOCK - sim_activate (&clocks[0], MSEC*125/2); - return sim_activate (&clocks[1], 20*MSEC); -#else + + if (!sim_is_running) { /* RESET (not IORESET)? */ + tmr_poll = sim_rtcn_init (clocks[0].wait, 0); /* init timer */ + sim_activate (&clocks[0], tmr_poll); /* activate unit */ + } return SCPE_OK; -#endif } DEVICE clock_dev = { "CLK", clocks, NULL, NULL, - 2, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, NULL, NULL, NULL, NULL, DEV_DEBUG diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index faec0254..c1110a87 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -121,8 +121,10 @@ enum { /* * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. */ -#define USEC 10 /* одна микросекунда - десять тактов */ +#define USEC 1 /* одна микросекунда - десять тактов */ #define MSEC (1000*USEC) /* одна миллисекунда */ +#define CLK_TPS 250 /* Fast Clock Ticks Per Second (every 4ms) */ +#define CLK_DELAY 4000 /* Uncalibrated instructions per clock tick */ extern UNIT cpu_unit; extern t_value memory [MEMSIZE]; diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index 40e5065c..22a870c1 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -519,7 +519,7 @@ void disk_ctl (int ctlr, uint32 cmd) } /* Ждём события от устройства. */ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + sim_activate_after (u, 20*USEC); /* Ускорим для отладки. */ } else if (cmd & BBIT(11)) { /* Выбора номера устройства и занесение в регистр маски КМД. @@ -614,7 +614,7 @@ void disk_ctl (int ctlr, uint32 cmd) disk_read_header (u); /* Ждём события от устройства. */ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + sim_activate_after (u, 20*USEC); /* Ускорим для отладки. */ break; case 010: /* гашение PC */ #if 0 diff --git a/BESM6/besm6_drum.c b/BESM6/besm6_drum.c index e29df468..6bbb02ed 100644 --- a/BESM6/besm6_drum.c +++ b/BESM6/besm6_drum.c @@ -346,8 +346,8 @@ void drum (int ctlr, uint32 cmd) /* Ждём события от устройства. * Согласно данным из книжки Мазного Г.Л., * даём 20 мсек на обмен, или 200 тыс.тактов. */ - /*sim_activate (u, 20*MSEC);*/ - sim_activate (u, 20*USEC); /* Ускорим для отладки. */ + /*sim_activate_after (u, 20*MSEC);*/ + sim_activate_after (u, 20*USEC); /* Ускорим для отладки. */ } /* diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c index 8cf88bf7..6270e486 100644 --- a/BESM6/besm6_printer.c +++ b/BESM6/besm6_printer.c @@ -159,7 +159,7 @@ void printer_control (int num, uint32 cmd) dev->feed = LINEFEED_SYNC; READY &= ~(PRN1_LINEFEED >> num); if (dev->rampup) - sim_activate (u, dev->rampup); + sim_activate_after (u, dev->rampup); dev->rampup = 0; break; case 10: /* motor and ribbon off */ @@ -208,7 +208,7 @@ t_stat printer_event (UNIT *u) GRP |= GRP_PRN1_SYNC >> num; ++dev->curchar; /* For next char */ - sim_activate (u, 1400*USEC); + sim_activate_after (u, 1400*USEC); if (dev->feed && --dev->feed == 0) { READY |= PRN1_LINEFEED >> num; } @@ -219,7 +219,7 @@ t_stat printer_event (UNIT *u) if (printer_dev.dctrl) besm6_debug(">>> АЦПУ%d 'ноль'", num); /* For first sync after "zero" */ - sim_activate (u, 1000*USEC); + sim_activate_after (u, 1000*USEC); } return SCPE_OK; } @@ -334,9 +334,9 @@ offset_gost_write (int num, FILE *fout) */ int printer_is_idle () { - if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0) + if (sim_is_active(&printer_unit[0])) return 0; - if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0) + if (sim_is_active(&printer_unit[1])) return 0; return 1; } diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c index c160bf3b..e1b65705 100644 --- a/BESM6/besm6_punch.c +++ b/BESM6/besm6_punch.c @@ -27,7 +27,6 @@ * authorization from Leonid Broukhis and Serge Vakulenko. */ #include "besm6_defs.h" -#include t_stat fs_event (UNIT *u); t_stat uvvk_event (UNIT *u); @@ -169,7 +168,7 @@ void fs_control (int num, uint32 cmd) if (fs_state[num] == FS_IDLE) besm6_debug("<<< ФС1500-%d протяжка без мотора", num); else if (fs_state[num] != FS_TAIL) { - sim_activate (u, FS_RATE); + sim_activate_after (u, FS_RATE); bytecnt++; } else { if (! isfifo[num]) { diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index f260fe8b..d2d77f5c 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -82,9 +82,10 @@ void tt_print(); void consul_receive(); t_stat vt_clk(UNIT *); extern char *get_sim_sw (char *cptr); +extern int32 tmr_poll; /* calibrated clock timer poll */ UNIT tty_unit [] = { - { UDATA (vt_clk, UNIT_DIS, 0) }, /* fake unit, clock */ + { UDATA (vt_clk, UNIT_DIS|UNIT_IDLE, 0) }, /* fake unit, clock */ { UDATA (NULL, UNIT_SEQ, 0) }, { UDATA (NULL, UNIT_SEQ, 0) }, { UDATA (NULL, UNIT_SEQ, 0) }, @@ -160,7 +161,7 @@ t_stat tty_reset (DEVICE *dptr) /* Готовность устройства в READY2 инверсная, а устройство всегда готово */ /* Провоцируем передачу */ PRP |= CONS_CAN_PRINT[0] | CONS_CAN_PRINT[1]; - return sim_activate (tty_unit, 1000*MSEC/300); + return sim_clock_coschedule (tty_unit, 5*tmr_poll); } /* 19 р ГРП, 300 Гц */ @@ -223,7 +224,7 @@ t_stat vt_clk (UNIT * this) /* Опрашиваем сокеты на передачу. */ tmxr_poll_tx (&tty_desc); - return sim_activate (this, 1000*MSEC/300); + return sim_clock_coschedule (this, 5*tmr_poll); } t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) From 3ddb9e992921b5051a75504f4f0c98e286b19b97 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Wed, 31 Dec 2014 17:26:34 -0800 Subject: [PATCH 12/41] BESM6: Reverted IO scheduling to model time; the time unit is 100 ns. --- BESM6/besm6_cpu.c | 6 +++++- BESM6/besm6_defs.h | 2 +- BESM6/besm6_disk.c | 4 ++-- BESM6/besm6_drum.c | 4 ++-- BESM6/besm6_printer.c | 6 +++--- BESM6/besm6_punch.c | 2 +- BESM6/besm6_tty.c | 6 ++++-- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 3e52ecbf..0b0aad80 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -1434,7 +1434,11 @@ void cpu_one_inst () /* Если периферия простаивает, освобождаем процессор * до следующего тика таймера. */ - sim_idle (0, TRUE); + if (vt_is_idle() && + printer_is_idle() && fs_is_idle()) { + check_initial_setup (); + sim_idle (0, TRUE); + } } } diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index c1110a87..96fb27cb 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -121,7 +121,7 @@ enum { /* * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. */ -#define USEC 1 /* одна микросекунда - десять тактов */ +#define USEC 10 /* одна микросекунда - десять тактов */ #define MSEC (1000*USEC) /* одна миллисекунда */ #define CLK_TPS 250 /* Fast Clock Ticks Per Second (every 4ms) */ #define CLK_DELAY 4000 /* Uncalibrated instructions per clock tick */ diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index 22a870c1..40e5065c 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -519,7 +519,7 @@ void disk_ctl (int ctlr, uint32 cmd) } /* Ждём события от устройства. */ - sim_activate_after (u, 20*USEC); /* Ускорим для отладки. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ } else if (cmd & BBIT(11)) { /* Выбора номера устройства и занесение в регистр маски КМД. @@ -614,7 +614,7 @@ void disk_ctl (int ctlr, uint32 cmd) disk_read_header (u); /* Ждём события от устройства. */ - sim_activate_after (u, 20*USEC); /* Ускорим для отладки. */ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ break; case 010: /* гашение PC */ #if 0 diff --git a/BESM6/besm6_drum.c b/BESM6/besm6_drum.c index 6bbb02ed..e29df468 100644 --- a/BESM6/besm6_drum.c +++ b/BESM6/besm6_drum.c @@ -346,8 +346,8 @@ void drum (int ctlr, uint32 cmd) /* Ждём события от устройства. * Согласно данным из книжки Мазного Г.Л., * даём 20 мсек на обмен, или 200 тыс.тактов. */ - /*sim_activate_after (u, 20*MSEC);*/ - sim_activate_after (u, 20*USEC); /* Ускорим для отладки. */ + /*sim_activate (u, 20*MSEC);*/ + sim_activate (u, 20*USEC); /* Ускорим для отладки. */ } /* diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c index 6270e486..79cf647e 100644 --- a/BESM6/besm6_printer.c +++ b/BESM6/besm6_printer.c @@ -159,7 +159,7 @@ void printer_control (int num, uint32 cmd) dev->feed = LINEFEED_SYNC; READY &= ~(PRN1_LINEFEED >> num); if (dev->rampup) - sim_activate_after (u, dev->rampup); + sim_activate (u, dev->rampup); dev->rampup = 0; break; case 10: /* motor and ribbon off */ @@ -208,7 +208,7 @@ t_stat printer_event (UNIT *u) GRP |= GRP_PRN1_SYNC >> num; ++dev->curchar; /* For next char */ - sim_activate_after (u, 1400*USEC); + sim_activate (u, 1400*USEC); if (dev->feed && --dev->feed == 0) { READY |= PRN1_LINEFEED >> num; } @@ -219,7 +219,7 @@ t_stat printer_event (UNIT *u) if (printer_dev.dctrl) besm6_debug(">>> АЦПУ%d 'ноль'", num); /* For first sync after "zero" */ - sim_activate_after (u, 1000*USEC); + sim_activate (u, 1000*USEC); } return SCPE_OK; } diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c index e1b65705..1051430f 100644 --- a/BESM6/besm6_punch.c +++ b/BESM6/besm6_punch.c @@ -168,7 +168,7 @@ void fs_control (int num, uint32 cmd) if (fs_state[num] == FS_IDLE) besm6_debug("<<< ФС1500-%d протяжка без мотора", num); else if (fs_state[num] != FS_TAIL) { - sim_activate_after (u, FS_RATE); + sim_activate (u, FS_RATE); bytecnt++; } else { if (! isfifo[num]) { diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index d2d77f5c..c59d2f5a 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -161,7 +161,8 @@ t_stat tty_reset (DEVICE *dptr) /* Готовность устройства в READY2 инверсная, а устройство всегда готово */ /* Провоцируем передачу */ PRP |= CONS_CAN_PRINT[0] | CONS_CAN_PRINT[1]; - return sim_clock_coschedule (tty_unit, 5*tmr_poll); + return sim_activate (tty_unit, 1000*MSEC/300); + // return sim_clock_coschedule (tty_unit, 5*tmr_poll); } /* 19 р ГРП, 300 Гц */ @@ -224,7 +225,8 @@ t_stat vt_clk (UNIT * this) /* Опрашиваем сокеты на передачу. */ tmxr_poll_tx (&tty_desc); - return sim_clock_coschedule (this, 5*tmr_poll); + return sim_activate (tty_unit, 1000*MSEC/300); + // return sim_clock_coschedule (this, 5*tmr_poll); } t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) From a50bd68ce529e1078c8b1b1f83d9c98bb9649e9b Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Wed, 31 Dec 2014 10:50:21 -0800 Subject: [PATCH 13/41] BESM6: Using sim_fwrite for formatting. --- BESM6/besm6_disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index 40e5065c..3bb713c6 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -204,11 +204,11 @@ t_stat disk_attach (UNIT *u, char *cptr) for (blkno = 0; blkno < DISK_TOTBLK; ++blkno) { control[0] = SET_CONVOL((t_value)(2*blkno) << 36, CONVOL_NUMBER); - fwrite(control, sizeof(t_value), 4, u->fileref); + sim_fwrite(control, sizeof(t_value), 4, u->fileref); control[0] = SET_CONVOL((t_value)(2*blkno+1) << 36, CONVOL_NUMBER); - fwrite(control, sizeof(t_value), 4, u->fileref); + sim_fwrite(control, sizeof(t_value), 4, u->fileref); for (word = 0; word < 02000; ++word) { - fwrite(control+2, sizeof(t_value), 1, u->fileref); + sim_fwrite(control+2, sizeof(t_value), 1, u->fileref); } } return SCPE_OK; From 76cdf0fd108fd619013169126cec5046fc8d49fa Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Thu, 1 Jan 2015 15:05:07 -0800 Subject: [PATCH 14/41] BESM6: Got rid of ftw(); the font file should be provided as a build option. --- BESM6/besm6_panel.c | 41 ++++++----------------------------------- makefile | 11 ++++++++--- 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c index 2fcbab6a..a2052f64 100644 --- a/BESM6/besm6_panel.c +++ b/BESM6/besm6_panel.c @@ -32,7 +32,6 @@ #include "besm6_defs.h" #include -#include /* * Use a 640x480 window with 32 bit pixels. @@ -44,14 +43,12 @@ #define STEPX 14 #define STEPY 16 -#define FONTNAME "LucidaSansRegular.ttf" -#define FONTPATH1 "/usr/share/fonts" -#define FONTPATH2 "/usr/lib/jvm" -#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions" - #include #include +#define _QUOTE(x) #x +#define QUOTE(x) _QUOTE(x) + /* Data and functions that don't depend on SDL version */ static char *font_path; static TTF_Font *font_big; @@ -337,22 +334,6 @@ static void draw_brz_static (int top) } } -/* - * Поиск файла шрифта по имени. - */ -static int probe_font (const char *path, const struct stat *st, int flag) -{ - const char *p; - - if (flag != FTW_F) - return 0; - p = path + strlen (path) - strlen (FONTNAME); - if (p < path || strcmp (p, FONTNAME) != 0) - return 0; - font_path = strdup (path); - return 1; -} - /* * Закрываем графическое окно. */ @@ -409,22 +390,12 @@ static void init_panel () exit (1); } - /* Find font file */ - if (ftw (FONTPATH1, probe_font, 255) <= 0 && - ftw (FONTPATH2, probe_font, 255) <= 0 && - ftw (FONTPATH3, probe_font, 255) <= 0) { - fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", - FONTNAME, FONTPATH1); - besm6_close_panel(); - exit (1); - } - /* Open the font file with the requested point size */ - font_big = TTF_OpenFont (font_path, 16); - font_small = TTF_OpenFont (font_path, 9); + font_big = TTF_OpenFont (QUOTE(FONTFILE), 16); + font_small = TTF_OpenFont (QUOTE(FONTFILE), 9); if (! font_big || ! font_small) { fprintf(stderr, "SDL: couldn't load font %s: %s\n", - font_path, SDL_GetError()); + QUOTE(FONTFILE), SDL_GetError()); besm6_close_panel(); exit (1); } diff --git a/makefile b/makefile index f2eb6907..f536e0e6 100644 --- a/makefile +++ b/makefile @@ -1171,14 +1171,19 @@ BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \ ${BESM6D}/besm6_tty.c ${BESM6D}/besm6_panel.c ${BESM6D}/besm6_printer.c \ ${BESM6D}/besm6_punch.c -ifeq (,${VIDEO_LDFLAGS}) +ifeq (,$(and ${VIDEO_LDFLAGS}, ${FONTFILE})) + ifneq (,$(and ${VIDEO_LDFLAGS}, $(findstring besm6,$(MAKECMDGOALS)))) + $(info ***) + $(info *** BESM-6 video not used: please specify a font file with FONTFILE=pathname to enable the panel display) + $(info ***) + endif BESM6_OPT = -I ${BESM6D} -DUSE_INT64 else ifneq (,$(and $(findstring SDL2,${VIDEO_LDFLAGS}),$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf))) $(info using libSDL2_ttf: $(call find_lib,SDL2_ttf) $(call find_include,SDL2/SDL_ttf)) - BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf + BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf else ifneq (,$(and $(call find_include,SDL/SDL_ttf),$(call find_lib,SDL_ttf))) $(info using libSDL_ttf: $(call find_lib,SDL_ttf) $(call find_include,SDL/SDL_ttf)) - BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf + BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf else BESM6_OPT = -I ${BESM6D} -DUSE_INT64 endif From bd50637b18bb5e35c8c07016cbfc9905654d4abb Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 1 Jan 2015 20:08:23 -0800 Subject: [PATCH 15/41] BESM6: Working calibrated clock which also supports idling BESM6: Single instruction calibration and step cleanup --- BESM6/besm6_cpu.c | 11 ++--------- BESM6/besm6_defs.h | 2 +- BESM6/besm6_tty.c | 13 +++++++------ BESM6/dispak.ini | 10 ++++------ 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 0b0aad80..dc1ffd12 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -1494,7 +1494,6 @@ t_stat sim_instr (void) /* Restore register state */ PC = PC & BITS(15); /* mask PC */ - sim_cancel_step (); /* defang SCP step */ mmu_setup (); /* copy RP to TLB */ /* An internal interrupt or user intervention */ @@ -1688,13 +1687,7 @@ t_stat sim_instr (void) redraw_panel = 0; } - if (delay < 1) - delay = 1; - sim_interval -= delay; /* count down delay */ - if (sim_step && (--sim_step <= 0)) { /* do step count */ - besm6_draw_panel(); - return SCPE_STOP; - } + sim_interval -= 1; /* count down instructions */ } } @@ -1729,7 +1722,7 @@ t_stat fast_clk (UNIT * this) } UNIT clocks[] = { - { UDATA(fast_clk, 0, 0), CLK_DELAY }, /* 40 р, 50 Гц */ + { UDATA(fast_clk, UNIT_IDLE, 0), CLK_DELAY }, /* 40 р, 50 Гц */ }; t_stat clk_reset (DEVICE * dev) diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index 96fb27cb..a933664a 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -121,7 +121,7 @@ enum { /* * Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. */ -#define USEC 10 /* одна микросекунда - десять тактов */ +#define USEC 1 /* одна микросекунда - десять тактов */ #define MSEC (1000*USEC) /* одна миллисекунда */ #define CLK_TPS 250 /* Fast Clock Ticks Per Second (every 4ms) */ #define CLK_DELAY 4000 /* Uncalibrated instructions per clock tick */ diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index c59d2f5a..729fb714 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -161,8 +161,8 @@ t_stat tty_reset (DEVICE *dptr) /* Готовность устройства в READY2 инверсная, а устройство всегда готово */ /* Провоцируем передачу */ PRP |= CONS_CAN_PRINT[0] | CONS_CAN_PRINT[1]; - return sim_activate (tty_unit, 1000*MSEC/300); - // return sim_clock_coschedule (tty_unit, 5*tmr_poll); + //return sim_activate_after (tty_unit, 1000*MSEC/300); + return sim_clock_coschedule (tty_unit, tmr_poll); } /* 19 р ГРП, 300 Гц */ @@ -225,8 +225,8 @@ t_stat vt_clk (UNIT * this) /* Опрашиваем сокеты на передачу. */ tmxr_poll_tx (&tty_desc); - return sim_activate (tty_unit, 1000*MSEC/300); - // return sim_clock_coschedule (this, 5*tmr_poll); + // return sim_activate_after (tty_unit, 1000*MSEC/300); + return sim_clock_coschedule (this, tmr_poll); } t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) @@ -996,8 +996,9 @@ int vt_getc (int num) } else { /* Ввод с клавиатуры. */ c = sim_poll_kbd(); - if (c == SCPE_STOP) + if (c == SCPE_STOP) { return 0400; /* прерывание */ + } if (! (c & SCPE_KFLAG)) return -1; } @@ -1136,7 +1137,7 @@ void vt_receive() } if (tty_typed[num] < 0) { /* TODO: обработать исключение от "неоператорского" терминала */ - sim_interval = 0; +// sim_interval = 0; break; } if (tty_typed[num] <= 0177) { diff --git a/BESM6/dispak.ini b/BESM6/dispak.ini index c812b662..078a6c12 100644 --- a/BESM6/dispak.ini +++ b/BESM6/dispak.ini @@ -1,5 +1,4 @@ -! rm -f log.txt -set console log=log.txt +set -n console log=log.txt set console debug=log ;set cpu debug ;set mmu debug @@ -9,9 +8,8 @@ set console debug=log ; ; Приводим барабаны в исходное состояние. ; -! rm -f drum1x.bin drum2x.bin -attach drum0 drum1x.bin -attach drum1 drum2x.bin +attach -n drum0 drum1x.bin +attach -n drum1 drum2x.bin ; ; Создаем рабочий диск. @@ -43,7 +41,7 @@ attach tty1 /dev/tty ; ;set tty1 jcuken,authbs set tty1 authbs -set tty1 log=tty1.txt +set -n tty1 log=tty1.txt ; ; Разрешаем подключение пользователей по telnet, порт 4199. From 8d11de76c11c8699321cce2b933df24f87bfd413 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 31 Dec 2014 13:25:49 -0800 Subject: [PATCH 16/41] VAX: Properly inline memory reference functions for performance. Fix #169 --- PDP11/pdp11_hk.c | 4 +- VAX/vax610_defs.h | 20 +- VAX/vax610_sysdev.c | 3 - VAX/vax630_defs.h | 20 +- VAX/vax630_sysdev.c | 3 - VAX/vax730_defs.h | 20 +- VAX/vax730_sys.c | 4 +- VAX/vax750_cmi.c | 4 +- VAX/vax750_defs.h | 20 +- VAX/vax780_defs.h | 20 +- VAX/vax780_sbi.c | 4 +- VAX/vax860_abus.c | 4 +- VAX/vax860_defs.h | 20 +- VAX/vax_cpu.c | 4 +- VAX/vax_mmu.c | 360 +------------------- VAX/vax_mmu.h | 434 ++++++++++++++++++++++++ VAX/vax_sysdev.c | 3 - VAX/vaxmod_defs.h | 20 +- Visual Studio Projects/MicroVAX1.vcproj | 4 + Visual Studio Projects/MicroVAX2.vcproj | 10 +- Visual Studio Projects/VAX.vcproj | 8 +- Visual Studio Projects/VAX730.vcproj | 8 +- Visual Studio Projects/VAX750.vcproj | 8 +- Visual Studio Projects/VAX780.vcproj | 8 +- Visual Studio Projects/VAX8600.vcproj | 8 +- Visual Studio Projects/rtVAX1000.vcproj | 8 +- 26 files changed, 519 insertions(+), 510 deletions(-) create mode 100644 VAX/vax_mmu.h diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index 3163cc83..4ada5a28 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -68,8 +68,6 @@ extern uint32 cpu_opt; #endif -extern uint16 *M; - #define HK_NUMDR 8 /* #drives */ #define HK_NUMCY6 411 /* cyl/drive */ #define HK_NUMCY7 815 /* cyl/drive */ @@ -1569,6 +1567,8 @@ return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); #if defined (VM_PDP11) +extern uint16 *M; + /* Device bootstrap - does not clear CSR when done */ #define BOOT_START 02000 /* start */ diff --git a/VAX/vax610_defs.h b/VAX/vax610_defs.h index 990f2a2b..41b18070 100644 --- a/VAX/vax610_defs.h +++ b/VAX/vax610_defs.h @@ -322,22 +322,6 @@ typedef struct { extern int32 sys_model; -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -356,4 +340,8 @@ t_stat cpu_show_leds (FILE *st, UNIT *uptr, int32 val, void *desc); #include "pdp11_io_lib.h" +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/VAX/vax610_sysdev.c b/VAX/vax610_sysdev.c index b597d735..a9072c05 100644 --- a/VAX/vax610_sysdev.c +++ b/VAX/vax610_sysdev.c @@ -60,9 +60,6 @@ extern DEVICE vc_dev, lk_dev, vs_dev; int32 conisp, conpc, conpsl; /* console reg */ int32 sys_model = 0; /* MicroVAX or VAXstation */ char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ -static const int32 insert[4] = { - 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF - }; static struct boot_dev boot_tab[] = { { "RQ", "DUA", 0x00415544 }, /* DUAn */ diff --git a/VAX/vax630_defs.h b/VAX/vax630_defs.h index 26c05007..0898b954 100644 --- a/VAX/vax630_defs.h +++ b/VAX/vax630_defs.h @@ -374,22 +374,6 @@ typedef struct { #define LOG_CPU_R 0x2 /* REI */ #define LOG_CPU_P 0x4 /* context */ -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -412,4 +396,8 @@ extern t_stat sysd_show_leds (FILE *st, UNIT *uptr, int32 val, void *desc); #include "pdp11_io_lib.h" +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/VAX/vax630_sysdev.c b/VAX/vax630_sysdev.c index e3804ae2..faca7c67 100644 --- a/VAX/vax630_sysdev.c +++ b/VAX/vax630_sysdev.c @@ -149,9 +149,6 @@ int32 ka_mser = 0; /* KA630 mem sys err */ int32 ka_cear = 0; /* KA630 cpu err */ int32 ka_dear = 0; /* KA630 dma err */ static uint32 rom_delay = 0; -static const int32 insert[4] = { - 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF - }; t_bool ka_diag_full = FALSE; t_bool ka_hltenab = TRUE; /* Halt Enable / Autoboot flag */ diff --git a/VAX/vax730_defs.h b/VAX/vax730_defs.h index 258aaac3..4ee98617 100644 --- a/VAX/vax730_defs.h +++ b/VAX/vax730_defs.h @@ -342,22 +342,6 @@ typedef struct { #define BOOT_TK 18 #define BOOT_TD 64 -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -379,4 +363,8 @@ void sbi_set_errcnf (void); #include "pdp11_io_lib.h" +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/VAX/vax730_sys.c b/VAX/vax730_sys.c index 0d641ba4..17b465a1 100644 --- a/VAX/vax730_sys.c +++ b/VAX/vax730_sys.c @@ -382,7 +382,7 @@ return; longword of data */ -int32 ReadReg (int32 pa, int32 lnt) +int32 ReadReg (uint32 pa, int32 lnt) { int32 nexus, val; @@ -408,7 +408,7 @@ return 0; none */ -void WriteReg (int32 pa, int32 val, int32 lnt) +void WriteReg (uint32 pa, int32 val, int32 lnt) { int32 nexus; diff --git a/VAX/vax750_cmi.c b/VAX/vax750_cmi.c index bac47aa6..c96ee652 100644 --- a/VAX/vax750_cmi.c +++ b/VAX/vax750_cmi.c @@ -446,7 +446,7 @@ return; longword of data */ -int32 ReadReg (int32 pa, int32 lnt) +int32 ReadReg (uint32 pa, int32 lnt) { int32 nexus, val; @@ -473,7 +473,7 @@ return 0; none */ -void WriteReg (int32 pa, int32 val, int32 lnt) +void WriteReg (uint32 pa, int32 val, int32 lnt) { int32 nexus; diff --git a/VAX/vax750_defs.h b/VAX/vax750_defs.h index e3c57104..75893301 100644 --- a/VAX/vax750_defs.h +++ b/VAX/vax750_defs.h @@ -388,22 +388,6 @@ typedef struct { #define BOOT_CI 32 #define BOOT_TD 64 -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -435,4 +419,8 @@ void sbi_set_errcnf (void); #include "pdp11_io_lib.h" +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index 1c1bf9ee..1d093971 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -401,22 +401,6 @@ typedef struct { #define BOOT_TK 18 #define BOOT_CS 64 -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -448,4 +432,8 @@ void sbi_set_errcnf (void); #include "pdp11_io_lib.h" +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/VAX/vax780_sbi.c b/VAX/vax780_sbi.c index 02e56bb4..a8a99085 100644 --- a/VAX/vax780_sbi.c +++ b/VAX/vax780_sbi.c @@ -502,7 +502,7 @@ return; longword of data */ -int32 ReadReg (int32 pa, int32 lnt) +int32 ReadReg (uint32 pa, int32 lnt) { int32 nexus, val; @@ -529,7 +529,7 @@ return 0; none */ -void WriteReg (int32 pa, int32 val, int32 lnt) +void WriteReg (uint32 pa, int32 val, int32 lnt) { int32 nexus; diff --git a/VAX/vax860_abus.c b/VAX/vax860_abus.c index 60284a9c..c359014f 100644 --- a/VAX/vax860_abus.c +++ b/VAX/vax860_abus.c @@ -587,7 +587,7 @@ return; longword of data */ -int32 ReadReg (int32 pa, int32 lnt) +int32 ReadReg (uint32 pa, int32 lnt) { int32 val; @@ -610,7 +610,7 @@ return 0; none */ -void WriteReg (int32 pa, int32 val, int32 lnt) +void WriteReg (uint32 pa, int32 val, int32 lnt) { if (ADDR_IS_SBIA (pa)) { /* SBI adapter space? */ sbia_wr (pa, val, lnt); diff --git a/VAX/vax860_defs.h b/VAX/vax860_defs.h index b7f833bc..96849184 100644 --- a/VAX/vax860_defs.h +++ b/VAX/vax860_defs.h @@ -434,22 +434,6 @@ typedef struct { #define BOOT_TK 18 #define BOOT_CS 64 -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -481,4 +465,8 @@ void sbi_set_errcnf (void); #include "pdp11_io_lib.h" +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 1d98cb5b..92c20a7b 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -397,7 +397,7 @@ t_stat cpu_set_idle (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); char *cpu_description (DEVICE *dptr); int32 cpu_get_vsw (int32 sw); -SIM_INLINE int32 get_istr (int32 lnt, int32 acc); +static SIM_INLINE int32 get_istr (int32 lnt, int32 acc); int32 ReadOcta (int32 va, int32 *opnd, int32 j, int32 acc); t_bool cpu_show_opnd (FILE *st, InstHistory *h, int32 line); t_stat cpu_idle_svc (UNIT *uptr); @@ -3133,7 +3133,7 @@ for ( ;; ) { so any translation errors are real. */ -SIM_INLINE int32 get_istr (int32 lnt, int32 acc) +static SIM_INLINE int32 get_istr (int32 lnt, int32 acc) { int32 bo = PC & 3; int32 sc, val, t; diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index d9550335..20f2763c 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -50,13 +50,9 @@ */ #include "vax_defs.h" +#include "vax_mmu.h" #include -typedef struct { - int32 tag; /* tag */ - int32 pte; /* pte */ - } TLBENT; - extern uint32 *M; extern int32 PSL; extern int32 mapen; @@ -66,16 +62,11 @@ extern int32 P1BR, P1LR; extern int32 SBR, SLR; extern int32 SISR; extern jmp_buf save_env; -extern UNIT cpu_unit; int32 d_p0br, d_p0lr; /* dynamic copies */ int32 d_p1br, d_p1lr; /* altered per ucode */ int32 d_sbr, d_slr; -extern int32 mchk_va, mchk_ref; /* for mcheck */ TLBENT stlb[VA_TBSIZE], ptlb[VA_TBSIZE]; -static const int32 insert[4] = { - 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF - }; static const int32 cvtacc[16] = { 0, 0, TLB_ACCW (KERN)+TLB_ACCR (KERN), TLB_ACCR (KERN), @@ -136,355 +127,6 @@ DEVICE tlb_dev = { &tlb_description }; -/* Read and write virtual - - These routines logically fall into three phases: - - 1. Look up the virtual address in the translation buffer, calling - the fill routine on a tag mismatch or access mismatch (invalid - tlb entries have access = 0 and thus always mismatch). The - fill routine handles all errors. If the resulting physical - address is aligned, do an aligned physical read or write. - 2. Test for unaligned across page boundaries. If cross page, look - up the physical address of the second page. If not cross page, - the second physical address is the same as the first. - 3. Using the two physical addresses, do an unaligned read or - write, with three cases: unaligned long, unaligned word within - a longword, unaligned word crossing a longword boundary. - - Note that these routines do not handle quad or octa references. -*/ - -/* Read virtual - - Inputs: - va = virtual address - lnt = length code (BWL) - acc = access code (KESU) - Output: - returned data, right justified in 32b longword -*/ - -int32 Read (uint32 va, int32 lnt, int32 acc) -{ -int32 vpn, off, tbi, pa; -int32 pa1, bo, sc, wl, wh; -TLBENT xpte; - -mchk_va = va; -if (mapen) { /* mapping on? */ - vpn = VA_GETVPN (va); /* get vpn, offset */ - off = VA_GETOFF (va); - tbi = VA_GETTBI (vpn); - xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ - if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || - ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) - xpte = fill (va, lnt, acc, NULL); /* fill if needed */ - pa = (xpte.pte & TLB_PFN) | off; /* get phys addr */ - } -else { - pa = va & PAMASK; - off = 0; - } -if ((pa & (lnt - 1)) == 0) { /* aligned? */ - if (lnt >= L_LONG) /* long, quad? */ - return ReadL (pa); - if (lnt == L_WORD) /* word? */ - return ReadW (pa); - return ReadB (pa); /* byte */ - } -if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { /* cross page? */ - vpn = VA_GETVPN (va + lnt); /* vpn 2nd page */ - tbi = VA_GETTBI (vpn); - xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ - if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || - ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) - xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */ - pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; - } -else pa1 = ((pa + 4) & PAMASK) & ~03; /* not cross page */ -bo = pa & 3; -if (lnt >= L_LONG) { /* lw unaligned? */ - sc = bo << 3; - wl = ReadU (pa, L_LONG - bo); /* read both fragments */ - wh = ReadU (pa1, bo); /* extract */ - return ((wl | (wh << (32 - sc))) & LMASK); - } -else if (bo == 1) /* read within lw */ - return ReadU (pa, L_WORD); -else { - wl = ReadU (pa, L_BYTE); /* word cross lw */ - wh = ReadU (pa1, L_BYTE); /* read, extract */ - return (wl | (wh << 8)); - } -} - -/* Write virtual - - Inputs: - va = virtual address - val = data to be written, right justified in 32b lw - lnt = length code (BWL) - acc = access code (KESU) - Output: - none -*/ - -void Write (uint32 va, int32 val, int32 lnt, int32 acc) -{ -int32 vpn, off, tbi, pa; -int32 pa1, bo, sc; -TLBENT xpte; - -mchk_va = va; -if (mapen) { - vpn = VA_GETVPN (va); - off = VA_GETOFF (va); - tbi = VA_GETTBI (vpn); - xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ - if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || - ((xpte.pte & TLB_M) == 0)) - xpte = fill (va, lnt, acc, NULL); - pa = (xpte.pte & TLB_PFN) | off; - } -else { - pa = va & PAMASK; - off = 0; - } -if ((pa & (lnt - 1)) == 0) { /* aligned? */ - if (lnt >= L_LONG) /* long, quad? */ - WriteL (pa, val); - else if (lnt == L_WORD) /* word? */ - WriteW (pa, val); - else WriteB (pa, val); /* byte */ - return; - } -if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { - vpn = VA_GETVPN (va + 4); - tbi = VA_GETTBI (vpn); - xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ - if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || - ((xpte.pte & TLB_M) == 0)) - xpte = fill (va + lnt, lnt, acc, NULL); - pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; - } -else pa1 = ((pa + 4) & PAMASK) & ~03; -bo = pa & 3; -if (lnt >= L_LONG) { - sc = bo << 3; - WriteU (pa, val & insert[L_LONG - bo], L_LONG - bo); - WriteU (pa1, (val >> (32 - sc)) & insert[bo], bo); - } -else if (bo == 1) /* read within lw */ - WriteU (pa, val & WMASK, L_WORD); -else { /* word cross lw */ - WriteU (pa, val & BMASK, L_BYTE); - WriteU (pa1, (val >> 8) & BMASK, L_BYTE); - } -return; -} - -/* Test access to a byte (VAX PROBEx) */ - -int32 Test (uint32 va, int32 acc, int32 *status) -{ -int32 vpn, off, tbi; -TLBENT xpte; - -*status = PR_OK; /* assume ok */ -if (mapen) { /* mapping on? */ - vpn = VA_GETVPN (va); /* get vpn, off */ - off = VA_GETOFF (va); - tbi = VA_GETTBI (vpn); - xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ - if ((xpte.pte & acc) && (xpte.tag == vpn)) /* TB hit, acc ok? */ - return (xpte.pte & TLB_PFN) | off; - xpte = fill (va, L_BYTE, acc, status); /* fill TB */ - if (*status == PR_OK) - return (xpte.pte & TLB_PFN) | off; - else return -1; - } -return va & PAMASK; /* ret phys addr */ -} - -/* Read aligned physical (in virtual context, unless indicated) - - Inputs: - pa = physical address, naturally aligned - Output: - returned data, right justified in 32b longword -*/ - -SIM_INLINE int32 ReadB (uint32 pa) -{ -int32 dat; - -if (ADDR_IS_MEM (pa)) - dat = M[pa >> 2]; -else { - mchk_ref = REF_V; - if (ADDR_IS_IO (pa)) - dat = ReadIO (pa, L_BYTE); - else dat = ReadReg (pa, L_BYTE); - } -return ((dat >> ((pa & 3) << 3)) & BMASK); -} - -SIM_INLINE int32 ReadW (uint32 pa) -{ -int32 dat; - -if (ADDR_IS_MEM (pa)) - dat = M[pa >> 2]; -else { - mchk_ref = REF_V; - if (ADDR_IS_IO (pa)) - dat = ReadIO (pa, L_WORD); - else dat = ReadReg (pa, L_WORD); - } -return ((dat >> ((pa & 2)? 16: 0)) & WMASK); -} - -SIM_INLINE int32 ReadL (uint32 pa) -{ -if (ADDR_IS_MEM (pa)) - return M[pa >> 2]; -mchk_ref = REF_V; -if (ADDR_IS_IO (pa)) - return ReadIO (pa, L_LONG); -return ReadReg (pa, L_LONG); -} - -SIM_INLINE int32 ReadLP (uint32 pa) -{ -if (ADDR_IS_MEM (pa)) - return M[pa >> 2]; -mchk_va = pa; -mchk_ref = REF_P; -if (ADDR_IS_IO (pa)) - return ReadIO (pa, L_LONG); -return ReadReg (pa, L_LONG); -} - -/* Read unaligned physical (in virtual context) - - Inputs: - pa = physical address - lnt = length in bytes (1, 2, or 3) - Output: - returned data -*/ - -int32 ReadU (uint32 pa, int32 lnt) -{ -int32 dat; -int32 sc = (pa & 3) << 3; -if (ADDR_IS_MEM (pa)) - dat = M[pa >> 2]; -else { - mchk_ref = REF_V; - if (ADDR_IS_IO (pa)) - dat = ReadIOU (pa, lnt); - else dat = ReadRegU (pa, lnt); - } -return ((dat >> sc) & insert[lnt]); -} - -/* Write aligned physical (in virtual context, unless indicated) - - Inputs: - pa = physical address, naturally aligned - val = data to be written, right justified in 32b longword - Output: - none -*/ - -SIM_INLINE void WriteB (uint32 pa, int32 val) -{ -if (ADDR_IS_MEM (pa)) { - int32 id = pa >> 2; - int32 sc = (pa & 3) << 3; - int32 mask = 0xFF << sc; - M[id] = (M[id] & ~mask) | (val << sc); - } -else { - mchk_ref = REF_V; - if (ADDR_IS_IO (pa)) - WriteIO (pa, val, L_BYTE); - else WriteReg (pa, val, L_BYTE); - } -return; -} - -SIM_INLINE void WriteW (uint32 pa, int32 val) -{ -if (ADDR_IS_MEM (pa)) { - int32 id = pa >> 2; - M[id] = (pa & 2)? (M[id] & 0xFFFF) | (val << 16): - (M[id] & ~0xFFFF) | val; - } -else { - mchk_ref = REF_V; - if (ADDR_IS_IO (pa)) - WriteIO (pa, val, L_WORD); - else WriteReg (pa, val, L_WORD); - } -return; -} - -SIM_INLINE void WriteL (uint32 pa, int32 val) -{ -if (ADDR_IS_MEM (pa)) - M[pa >> 2] = val; -else { - mchk_ref = REF_V; - if (ADDR_IS_IO (pa)) - WriteIO (pa, val, L_LONG); - else WriteReg (pa, val, L_LONG); - } -return; -} - -void WriteLP (uint32 pa, int32 val) -{ -if (ADDR_IS_MEM (pa)) - M[pa >> 2] = val; -else { - mchk_va = pa; - mchk_ref = REF_P; - if (ADDR_IS_IO (pa)) - WriteIO (pa, val, L_LONG); - else WriteReg (pa, val, L_LONG); - } -return; -} - -/* Write unaligned physical (in virtual context) - - Inputs: - pa = physical address - val = data to be written, right justified in 32b longword - lnt = length (1, 2, or 3 bytes) - Output: - none -*/ - -void WriteU (uint32 pa, int32 val, int32 lnt) -{ -if (ADDR_IS_MEM (pa)) { - int32 bo = pa & 3; - int32 sc = bo << 3; - M[pa >> 2] = (M[pa >> 2] & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc); - } -else { - mchk_ref = REF_V; - if ADDR_IS_IO (pa) - WriteIOU (pa, val, lnt); - else WriteRegU (pa, val, lnt); - } -return; -} - /* TLB fill diff --git a/VAX/vax_mmu.h b/VAX/vax_mmu.h new file mode 100644 index 00000000..5122b84b --- /dev/null +++ b/VAX/vax_mmu.h @@ -0,0 +1,434 @@ +/* vax_mmu.h - VAX memory management (inlined) + + Copyright (c) 1998-2013, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 29-Nov-13 RMS Reworked unaligned flows + 24-Oct-12 MB Added support for KA620 virtual addressing + 21-Jul-08 RMS Removed inlining support + 28-May-08 RMS Inlined physical memory routines + 29-Apr-07 RMS Added address masking for system page table reads + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) + 30-Sep-04 RMS Comment and formating changes + 19-Sep-03 RMS Fixed upper/lower case linkage problems on VMS + 01-Jun-03 RMS Fixed compilation problem with USE_ADDR64 + + This module contains the instruction simulators for + + Read - read virtual + Write - write virtual + ReadL(P) - read aligned physical longword (physical context) + WriteL(P) - write aligned physical longword (physical context) + ReadB(W) - read aligned physical byte (word) + WriteB(W) - write aligned physical byte (word) + Test - test acccess + +*/ + +#ifndef VAX_MMU_H_ +#define VAX_MMU_H_ 1 + +#include "vax_defs.h" +#include + +typedef struct { + int32 tag; /* tag */ + int32 pte; /* pte */ + } TLBENT; + +extern uint32 *M; +extern int32 mapen; +extern UNIT cpu_unit; + +extern int32 mchk_va, mchk_ref; /* for mcheck */ +extern TLBENT stlb[VA_TBSIZE], ptlb[VA_TBSIZE]; + +static const int32 insert[4] = { + 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF + }; + +extern int32 ReadIO (uint32 pa, int32 lnt); +extern void WriteIO (uint32 pa, int32 val, int32 lnt); +extern int32 ReadReg (uint32 pa, int32 lnt); +extern void WriteReg (uint32 pa, int32 val, int32 lnt); +extern TLBENT fill (uint32 va, int32 lnt, int32 acc, int32 *stat); +static SIM_INLINE int32 ReadU (uint32 pa, int32 lnt); +static SIM_INLINE void WriteU (uint32 pa, int32 val, int32 lnt); +static SIM_INLINE int32 ReadB (uint32 pa); +static SIM_INLINE int32 ReadW (uint32 pa); +static SIM_INLINE int32 ReadL (uint32 pa); +static SIM_INLINE int32 ReadLP (uint32 pa); +static SIM_INLINE void WriteB (uint32 pa, int32 val); +static SIM_INLINE void WriteW (uint32 pa, int32 val); +static SIM_INLINE void WriteL (uint32 pa, int32 val); + +/* Read and write virtual + + These routines logically fall into three phases: + + 1. Look up the virtual address in the translation buffer, calling + the fill routine on a tag mismatch or access mismatch (invalid + tlb entries have access = 0 and thus always mismatch). The + fill routine handles all errors. If the resulting physical + address is aligned, do an aligned physical read or write. + 2. Test for unaligned across page boundaries. If cross page, look + up the physical address of the second page. If not cross page, + the second physical address is the same as the first. + 3. Using the two physical addresses, do an unaligned read or + write, with three cases: unaligned long, unaligned word within + a longword, unaligned word crossing a longword boundary. + + Note that these routines do not handle quad or octa references. +*/ + +/* Read virtual + + Inputs: + va = virtual address + lnt = length code (BWL) + acc = access code (KESU) + Output: + returned data, right justified in 32b longword +*/ + +static SIM_INLINE int32 Read (uint32 va, int32 lnt, int32 acc) +{ +int32 vpn, off, tbi, pa; +int32 pa1, bo, sc, wl, wh; +TLBENT xpte; + +mchk_va = va; +if (mapen) { /* mapping on? */ + vpn = VA_GETVPN (va); /* get vpn, offset */ + off = VA_GETOFF (va); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) + xpte = fill (va, lnt, acc, NULL); /* fill if needed */ + pa = (xpte.pte & TLB_PFN) | off; /* get phys addr */ + } +else { + pa = va & PAMASK; + off = 0; + } +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt >= L_LONG) /* long, quad? */ + return ReadL (pa); + if (lnt == L_WORD) /* word? */ + return ReadW (pa); + return ReadB (pa); /* byte */ + } +if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { /* cross page? */ + vpn = VA_GETVPN (va + lnt); /* vpn 2nd page */ + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((acc & TLB_WACC) && ((xpte.pte & TLB_M) == 0))) + xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */ + pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; + } +else pa1 = ((pa + 4) & PAMASK) & ~03; /* not cross page */ +bo = pa & 3; +if (lnt >= L_LONG) { /* lw unaligned? */ + sc = bo << 3; + wl = ReadU (pa, L_LONG - bo); /* read both fragments */ + wh = ReadU (pa1, bo); /* extract */ + return ((wl | (wh << (32 - sc))) & LMASK); + } +else if (bo == 1) /* read within lw */ + return ReadU (pa, L_WORD); +else { + wl = ReadU (pa, L_BYTE); /* word cross lw */ + wh = ReadU (pa1, L_BYTE); /* read, extract */ + return (wl | (wh << 8)); + } +} + +/* Write virtual + + Inputs: + va = virtual address + val = data to be written, right justified in 32b lw + lnt = length code (BWL) + acc = access code (KESU) + Output: + none +*/ + +static SIM_INLINE void Write (uint32 va, int32 val, int32 lnt, int32 acc) +{ +int32 vpn, off, tbi, pa; +int32 pa1, bo, sc; +TLBENT xpte; + +mchk_va = va; +if (mapen) { + vpn = VA_GETVPN (va); + off = VA_GETOFF (va); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((xpte.pte & TLB_M) == 0)) + xpte = fill (va, lnt, acc, NULL); + pa = (xpte.pte & TLB_PFN) | off; + } +else { + pa = va & PAMASK; + off = 0; + } +if ((pa & (lnt - 1)) == 0) { /* aligned? */ + if (lnt >= L_LONG) /* long, quad? */ + WriteL (pa, val); + else if (lnt == L_WORD) /* word? */ + WriteW (pa, val); + else WriteB (pa, val); /* byte */ + return; + } +if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { + vpn = VA_GETVPN (va + 4); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if (((xpte.pte & acc) == 0) || (xpte.tag != vpn) || + ((xpte.pte & TLB_M) == 0)) + xpte = fill (va + lnt, lnt, acc, NULL); + pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; + } +else pa1 = ((pa + 4) & PAMASK) & ~03; +bo = pa & 3; +if (lnt >= L_LONG) { + sc = bo << 3; + WriteU (pa, val & insert[L_LONG - bo], L_LONG - bo); + WriteU (pa1, (val >> (32 - sc)) & insert[bo], bo); + } +else if (bo == 1) /* read within lw */ + WriteU (pa, val & WMASK, L_WORD); +else { /* word cross lw */ + WriteU (pa, val & BMASK, L_BYTE); + WriteU (pa1, (val >> 8) & BMASK, L_BYTE); + } +return; +} + +/* Test access to a byte (VAX PROBEx) */ + +static SIM_INLINE int32 Test (uint32 va, int32 acc, int32 *status) +{ +int32 vpn, off, tbi; +TLBENT xpte; + +*status = PR_OK; /* assume ok */ +if (mapen) { /* mapping on? */ + vpn = VA_GETVPN (va); /* get vpn, off */ + off = VA_GETOFF (va); + tbi = VA_GETTBI (vpn); + xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ + if ((xpte.pte & acc) && (xpte.tag == vpn)) /* TB hit, acc ok? */ + return (xpte.pte & TLB_PFN) | off; + xpte = fill (va, L_BYTE, acc, status); /* fill TB */ + if (*status == PR_OK) + return (xpte.pte & TLB_PFN) | off; + else return -1; + } +return va & PAMASK; /* ret phys addr */ +} + +/* Read aligned physical (in virtual context, unless indicated) + + Inputs: + pa = physical address, naturally aligned + Output: + returned data, right justified in 32b longword +*/ + +static SIM_INLINE int32 ReadB (uint32 pa) +{ +int32 dat; + +if (ADDR_IS_MEM (pa)) + dat = M[pa >> 2]; +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + dat = ReadIO (pa, L_BYTE); + else dat = ReadReg (pa, L_BYTE); + } +return ((dat >> ((pa & 3) << 3)) & BMASK); +} + +static SIM_INLINE int32 ReadW (uint32 pa) +{ +int32 dat; + +if (ADDR_IS_MEM (pa)) + dat = M[pa >> 2]; +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + dat = ReadIO (pa, L_WORD); + else dat = ReadReg (pa, L_WORD); + } +return ((dat >> ((pa & 2)? 16: 0)) & WMASK); +} + +static SIM_INLINE int32 ReadL (uint32 pa) +{ +if (ADDR_IS_MEM (pa)) + return M[pa >> 2]; +mchk_ref = REF_V; +if (ADDR_IS_IO (pa)) + return ReadIO (pa, L_LONG); +return ReadReg (pa, L_LONG); +} + +static SIM_INLINE int32 ReadLP (uint32 pa) +{ +if (ADDR_IS_MEM (pa)) + return M[pa >> 2]; +mchk_va = pa; +mchk_ref = REF_P; +if (ADDR_IS_IO (pa)) + return ReadIO (pa, L_LONG); +return ReadReg (pa, L_LONG); +} + +/* Read unaligned physical (in virtual context) + + Inputs: + pa = physical address + lnt = length in bytes (1, 2, or 3) + Output: + returned data +*/ + +static SIM_INLINE int32 ReadU (uint32 pa, int32 lnt) +{ +int32 dat; +int32 sc = (pa & 3) << 3; +if (ADDR_IS_MEM (pa)) + dat = M[pa >> 2]; +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + dat = ReadIOU (pa, lnt); + else dat = ReadRegU (pa, lnt); + } +return ((dat >> sc) & insert[lnt]); +} + +/* Write aligned physical (in virtual context, unless indicated) + + Inputs: + pa = physical address, naturally aligned + val = data to be written, right justified in 32b longword + Output: + none +*/ + +static SIM_INLINE void WriteB (uint32 pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) { + int32 id = pa >> 2; + int32 sc = (pa & 3) << 3; + int32 mask = 0xFF << sc; + M[id] = (M[id] & ~mask) | (val << sc); + } +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + WriteIO (pa, val, L_BYTE); + else WriteReg (pa, val, L_BYTE); + } +return; +} + +static SIM_INLINE void WriteW (uint32 pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) { + int32 id = pa >> 2; + M[id] = (pa & 2)? (M[id] & 0xFFFF) | (val << 16): + (M[id] & ~0xFFFF) | val; + } +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + WriteIO (pa, val, L_WORD); + else WriteReg (pa, val, L_WORD); + } +return; +} + +static SIM_INLINE void WriteL (uint32 pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) + M[pa >> 2] = val; +else { + mchk_ref = REF_V; + if (ADDR_IS_IO (pa)) + WriteIO (pa, val, L_LONG); + else WriteReg (pa, val, L_LONG); + } +return; +} + +static SIM_INLINE void WriteLP (uint32 pa, int32 val) +{ +if (ADDR_IS_MEM (pa)) + M[pa >> 2] = val; +else { + mchk_va = pa; + mchk_ref = REF_P; + if (ADDR_IS_IO (pa)) + WriteIO (pa, val, L_LONG); + else WriteReg (pa, val, L_LONG); + } +return; +} + +/* Write unaligned physical (in virtual context) + + Inputs: + pa = physical address + val = data to be written, right justified in 32b longword + lnt = length (1, 2, or 3 bytes) + Output: + none +*/ + +static SIM_INLINE void WriteU (uint32 pa, int32 val, int32 lnt) +{ +if (ADDR_IS_MEM (pa)) { + int32 bo = pa & 3; + int32 sc = bo << 3; + M[pa >> 2] = (M[pa >> 2] & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc); + } +else { + mchk_ref = REF_V; + if ADDR_IS_IO (pa) + WriteIOU (pa, val, lnt); + else WriteRegU (pa, val, lnt); + } +return; +} + +#endif /* VAX_MMU_H_ */ diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index a3622841..c006919b 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -233,9 +233,6 @@ int32 ssc_adsm[2] = { 0 }; /* addr strobes */ int32 ssc_adsk[2] = { 0 }; int32 cdg_dat[CDASIZE >> 2]; /* cache data */ static uint32 rom_delay = 0; -static const int32 insert[4] = { - 0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF - }; t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index d06a4341..bc491b08 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -410,22 +410,6 @@ typedef struct { #define LOG_CPU_R 0x2 /* REI */ #define LOG_CPU_P 0x4 /* context */ -/* Function prototypes for virtual memory interface */ - -int32 Read (uint32 va, int32 lnt, int32 acc); -void Write (uint32 va, int32 val, int32 lnt, int32 acc); - -/* Function prototypes for physical memory interface (inlined) */ - -SIM_INLINE int32 ReadB (uint32 pa); -SIM_INLINE int32 ReadW (uint32 pa); -SIM_INLINE int32 ReadL (uint32 pa); -SIM_INLINE int32 ReadLP (uint32 pa); -SIM_INLINE void WriteB (uint32 pa, int32 val); -SIM_INLINE void WriteW (uint32 pa, int32 val); -SIM_INLINE void WriteL (uint32 pa, int32 val); -void WriteLP (uint32 pa, int32 val); - /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); @@ -445,4 +429,8 @@ int32 ReadRegU (uint32 pa, int32 lnt); void WriteIOU (uint32 pa, int32 val, int32 lnt); void WriteRegU (uint32 pa, int32 val, int32 lnt); +/* Function prototypes for virtual and physical memory interface (inlined) */ + +#include "vax_mmu.h" + #endif diff --git a/Visual Studio Projects/MicroVAX1.vcproj b/Visual Studio Projects/MicroVAX1.vcproj index a6a94f09..670a57de 100644 --- a/Visual Studio Projects/MicroVAX1.vcproj +++ b/Visual Studio Projects/MicroVAX1.vcproj @@ -466,6 +466,10 @@ RelativePath="..\VAX\vax_defs.h" > + + - @@ -120,9 +117,6 @@ - @@ -472,6 +466,10 @@ RelativePath="..\VAX\vax_defs.h" > + + + + diff --git a/Visual Studio Projects/VAX730.vcproj b/Visual Studio Projects/VAX730.vcproj index e4393d77..e5966337 100644 --- a/Visual Studio Projects/VAX730.vcproj +++ b/Visual Studio Projects/VAX730.vcproj @@ -153,10 +153,10 @@ AdditionalLibraryDirectories="../../winpcap/Wpdpack/Lib/;"../../pthreads/Pre-built.2/lib/";"../../windows-build/PCRE/lib/"" GenerateDebugInformation="false" SubSystem="1" - OptimizeReferences="2" - EnableCOMDATFolding="2" StackReserveSize="10485760" StackCommitSize="10485760" + OptimizeReferences="2" + EnableCOMDATFolding="2" RandomizedBaseAddress="1" DataExecutionPrevention="0" TargetMachine="1" @@ -452,6 +452,10 @@ RelativePath="..\VAX\vax_defs.h" > + + + + + + + + + + Date: Wed, 31 Dec 2014 13:53:48 -0800 Subject: [PATCH 17/41] TAPE: Simplify range expression to avoid cast size reduction --- sim_tape.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sim_tape.c b/sim_tape.c index c495d27b..c63d9660 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -884,8 +884,9 @@ switch (f) { /* the read method depen break; } - else if (uptr->pos < bufcap * sizeof (t_mtrlnt)) /* if less than a full buffer remains */ - bufcap = (uint32)(uptr->pos / sizeof (t_mtrlnt));/* then reduce the capacity accordingly */ + else if (uptr->pos < sizeof (buffer)) /* if less than a full buffer remains */ + bufcap = (uint32) uptr->pos /* then reduce the capacity accordingly */ + / sizeof (t_mtrlnt); sim_fseek (uptr->fileref, /* seek back to the location */ uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */ From 3fe61c53a5d7e417489c86401ef858239f7e9941 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 31 Dec 2014 14:32:10 -0800 Subject: [PATCH 18/41] SCP: Provide an API to display alternate error message text while returning SCPE status. --- scp.c | 172 +++++++++++++++++++++++++++++++++++++++------------------- scp.h | 1 + 2 files changed, 117 insertions(+), 56 deletions(-) diff --git a/scp.c b/scp.c index b4cc29e5..2bb3a500 100644 --- a/scp.c +++ b/scp.c @@ -504,6 +504,7 @@ int32 sim_do_depth = 0; static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE]; +static char *sim_do_ocptr[MAX_DO_NEST_LVL+1]; static char *sim_do_label[MAX_DO_NEST_LVL+1]; static t_stat sim_last_cmd_stat; /* Command Status */ @@ -1980,6 +1981,8 @@ while (stat != SCPE_EXIT) { /* in case exit */ sim_sub_args (cbuf, sizeof(cbuf), argv); if (sim_log) /* log cmd */ fprintf (sim_log, "%s%s\n", sim_prompt, cptr); + if (sim_deb && (sim_deb != sim_log)) + fprintf (sim_deb, "%s%s\n", sim_prompt, cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ if ((cmdp = find_cmd (gbuf))) /* lookup command */ @@ -2612,7 +2615,6 @@ int32 saved_sim_do_echo = sim_do_echo, saved_sim_quiet = sim_quiet; t_bool staying; t_stat stat, stat_nomessage; -char *ocptr; stat = SCPE_OK; staying = TRUE; @@ -2694,9 +2696,9 @@ if (errabort) /* -e flag? */ set_on (1, NULL); /* equivalent to ON ERROR RETURN */ do { - ocptr = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */ - if (!ocptr) { /* no pending action? */ - ocptr = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */ + sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */ + if (!sim_do_ocptr[sim_do_depth]) { /* no pending action? */ + sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */ sim_goto_line[sim_do_depth] += 1; } sim_sub_args (cbuf, sizeof(cbuf), do_arg); /* substitute args */ @@ -2759,12 +2761,12 @@ do { if (!echo && !sim_quiet && /* report if not echoing */ !stat_nomessage && /* and not suppressing messages */ !(cmdp && cmdp->message)) { /* and not handling them specially */ - sim_printf("%s> %s\n", do_position(), ocptr); + sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]); } } if (!stat_nomessage) { /* report error if not suppressed */ if (cmdp && cmdp->message) /* special message handler */ - cmdp->message ((!echo && !sim_quiet) ? ocptr : NULL, stat); + cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat); else if (stat >= SCPE_BASE) /* report error if not suppressed */ sim_printf ("%s\n", sim_error_text (stat)); @@ -3186,10 +3188,8 @@ if (*cptr == '"') { /* quoted string compari for (optr = compare_ops; optr->op; optr++) if (0 == strcmp (op, optr->op)) break; - if (!optr->op) { - sim_printf ("Invalid operator: %s\n", op); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if (!optr->op) + return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op); cptr += strlen (op); while (isspace (*cptr)) /* skip spaces */ ++cptr; @@ -3330,20 +3330,16 @@ else while (*cptr) { if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) { delay = (uint32)get_uint (&gbuf[6], 10, 10000000, &r); - if (r != SCPE_OK) { - sim_printf ("Invalid Delay Value\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if (r != SCPE_OK) + return sim_messagef (SCPE_ARG, "Invalid Delay Value\n"); cptr = tptr; tptr = get_glyph (cptr, gbuf, ','); continue; } if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) { after = (uint32)get_uint (&gbuf[6], 10, 10000000, &r); - if (r != SCPE_OK) { - sim_printf ("Invalid After Value\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if (r != SCPE_OK) + return sim_messagef (SCPE_ARG, "Invalid After Value\n"); cptr = tptr; tptr = get_glyph (cptr, gbuf, ','); continue; @@ -3353,18 +3349,14 @@ while (*cptr) { return SCPE_ARG; } if (*cptr) { - if ((*cptr != '"') && (*cptr != '\'')) { - sim_printf ("String must be quote delimited\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if ((*cptr != '"') && (*cptr != '\'')) + return sim_messagef (SCPE_ARG, "String must be quote delimited\n"); cptr = get_glyph_quoted (cptr, gbuf, 0); if (*cptr != '\0') return SCPE_2MARG; /* No more arguments */ - if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize)) { - sim_printf ("Invalid String\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize)) + return sim_messagef (SCPE_ARG, "Invalid String\n"); } if ((dsize == 0) && (delay == 0) && (after == 0)) return SCPE_2FARG; @@ -4586,10 +4578,8 @@ if (sim_is_running) if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; sim_trim_endspc(cptr); -if (chdir(cptr) != 0) { - sim_printf("Unable to directory change to: %s\n", cptr); - return SCPE_IOERR & SCPE_NOMESSAGE; - } +if (chdir(cptr) != 0) + return sim_messagef(SCPE_IOERR, "Unable to directory change to: %s\n", cptr); return SCPE_OK; } @@ -8739,10 +8729,8 @@ if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; if (*cptr == '[') { cnt = (int32) strtotv (cptr + 1, &c1ptr, 10); - if ((cptr == c1ptr) || (*c1ptr != ']')) { - sim_printf ("Invalid Repeat count specification\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if ((cptr == c1ptr) || (*c1ptr != ']')) + return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n"); cptr = (char *)(c1ptr + 1); while (isspace(*cptr)) ++cptr; @@ -8750,16 +8738,12 @@ if (*cptr == '[') { tptr = get_glyph (cptr, gbuf, ','); if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) { after = (uint32)get_uint (&gbuf[10], 10, 100000000, &r); - if (r != SCPE_OK) { - sim_printf ("Invalid Halt After Value\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } + if (r != SCPE_OK) + return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n"); cptr = tptr; } -if ((*cptr != '"') && (*cptr != '\'')) { - sim_printf ("String must be quote delimited\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } +if ((*cptr != '"') && (*cptr != '\'')) + return sim_messagef (SCPE_ARG, "String must be quote delimited\n"); cptr = get_glyph_quoted (cptr, gbuf, 0); return sim_exp_set (exp, gbuf, cnt, (after ? after : exp->after), sim_switches, cptr); @@ -8773,10 +8757,8 @@ char gbuf[CBUFSIZE]; if (!cptr || !*cptr) return sim_exp_clrall (exp); /* clear all rules */ -if ((*cptr != '"') && (*cptr != '\'')) { - sim_printf ("String must be quote delimited\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } +if ((*cptr != '"') && (*cptr != '\'')) + return sim_messagef (SCPE_ARG, "String must be quote delimited\n"); cptr = get_glyph_quoted (cptr, gbuf, 0); if (*cptr != '\0') return SCPE_2MARG; /* No more arguments */ @@ -8864,8 +8846,7 @@ if (!match_buf) if (switches & EXP_TYP_REGEX) { #if !defined (USE_REGEX) free (match_buf); - sim_printf ("RegEx support not available\n"); - return SCPE_ARG|SCPE_NOMESSAGE; /* RegEx not available */ + return sim_messagef (SCPE_ARG, "RegEx support not available\n"); } #else /* USE_REGEX */ int res; @@ -8880,7 +8861,7 @@ if (switches & EXP_TYP_REGEX) { char *err_buf = calloc (err_size+1, 1); regerror (res, &re, err_buf, err_size); - sim_printf ("Regular Expression Error: %s\n", err_buf); + sim_messagef (SCPE_ARG, "Regular Expression Error: %s\n", err_buf); free (err_buf); free (match_buf); return SCPE_ARG|SCPE_NOMESSAGE; @@ -8891,22 +8872,20 @@ if (switches & EXP_TYP_REGEX) { #endif else { if (switches & EXP_TYP_REGEX_I) { - sim_printf ("Case independed matching is only valid for RegEx expect rules\n"); - return SCPE_ARG|SCPE_NOMESSAGE; + free (match_buf); + return sim_messagef (SCPE_ARG, "Case independed matching is only valid for RegEx expect rules\n"); } if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) { free (match_buf); - return SCPE_ARG; + return sim_messagef (SCPE_ARG, "Invalid quoted string\n"); } } free (match_buf); ep = sim_exp_fnd (exp, match); /* present? */ if (ep) /* no, allocate */ sim_exp_clr_tab (exp, ep); /* clear it */ -if (after && exp->size) { - sim_printf ("Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n"); - return SCPE_ARG|SCPE_NOMESSAGE; - } +if (after && exp->size) + return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n"); exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1)); ep = &exp->rules[exp->size]; exp->size += 1; @@ -9490,6 +9469,87 @@ if (buf != stackbuf) free (buf); } +/* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */ +t_stat sim_messagef (t_stat stat, const char* fmt, ...) +{ +char stackbuf[STACKBUFSIZE]; +int32 bufsize = sizeof(stackbuf); +char *buf = stackbuf; +int32 len; +va_list arglist; +t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE)); + +while (1) { /* format passed string, args */ + va_start (arglist, fmt); +#if defined(NO_vsnprintf) +#if defined(HAS_vsprintf_void) + +/* Note, this could blow beyond the buffer, and we couldn't tell */ +/* That is a limitation of the C runtime library available on this platform */ + + vsprintf (buf, fmt, arglist); + for (len = 0; len < bufsize-1; len++) + if (buf[len] == 0) break; +#else + len = vsprintf (buf, fmt, arglist); +#endif /* HAS_vsprintf_void */ +#else /* NO_vsnprintf */ +#if defined(HAS_vsnprintf_void) + vsnprintf (buf, bufsize-1, fmt, arglist); + for (len = 0; len < bufsize-1; len++) + if (buf[len] == 0) break; +#else + len = vsnprintf (buf, bufsize-1, fmt, arglist); +#endif /* HAS_vsnprintf_void */ +#endif /* NO_vsnprintf */ + va_end (arglist); + +/* If the formatted result didn't fit into the buffer, then grow the buffer and try again */ + + if ((len < 0) || (len >= bufsize-1)) { + if (buf != stackbuf) + free (buf); + bufsize = bufsize * 2; + buf = (char *) malloc (bufsize); + if (buf == NULL) /* out of memory */ + return SCPE_MEM; + buf[bufsize-1] = '\0'; + continue; + } + break; + } + +if (sim_do_ocptr[sim_do_depth]) { + if (!sim_do_echo && !sim_quiet && !inhibit_message) + sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]); + else { + if (sim_deb) /* Always put context in debug output */ + fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]); + } + } +if (sim_is_running && !inhibit_message) { + char *c, *remnant = buf; + + while ((c = strchr(remnant, '\n'))) { + printf("%.*s\r\n", (int)(c-remnant), remnant); + remnant = c + 1; + } + printf("%s", remnant); + } +else { + if (!inhibit_message) + printf("%s", buf); + } +if (sim_log && (sim_log != stdout) && !inhibit_message) + fprintf (sim_log, "%s", buf); +if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */ + fprintf (sim_deb, "%s", buf); + +if (buf != stackbuf) + free (buf); +return stat | SCPE_NOMESSAGE; +} + /* Inline debugging - will print debug message if debug file is set and the bitmask matches the current device debug options. Extra returns are added for un*x systems, since the output diff --git a/scp.h b/scp.h index 9e5151a3..9fa05d27 100644 --- a/scp.h +++ b/scp.h @@ -178,6 +178,7 @@ const char *sim_error_text (t_stat stat); t_stat sim_string_to_stat (char *cptr, t_stat *cond); t_stat sim_cancel_step (void); void sim_printf (const char* fmt, ...); +t_stat sim_messagef (t_stat stat, const char* fmt, ...); void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason); void sim_debug_bits (uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs, uint32 before, uint32 after, int terminate); From d615bd0f586e83d3adedbcaf23a7159e3ec9948f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 31 Dec 2014 15:04:52 -0800 Subject: [PATCH 19/41] SCP: Only report DO file context when run_cmd completes if the completion status is not a simulator specific error code and not due to a STEP, EXPECT or STOP completion. The commands which operate through run_cmd (GO, STEP, CONTINUE, BOOT, RUN) will all exit with a status which is NOT SCPE_OK. Most of the exit status values will be 100% normal and not indicative of a true error, so producing error message context is not necessary or desired. --- scp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scp.c b/scp.c index 2bb3a500..4e0ae424 100644 --- a/scp.c +++ b/scp.c @@ -5978,7 +5978,7 @@ run_cmd_message (const char *unechoed_cmdline, t_stat r) #if defined (VMS) printf ("\n"); #endif -if (unechoed_cmdline) +if (unechoed_cmdline && (r >= SCPE_BASE) && (r != SCPE_STEP) && (r != SCPE_STOP) && (r != SCPE_EXPECT)) sim_printf("%s> %s\n", do_position(), unechoed_cmdline); fprint_stopped (stdout, r); /* print msg */ if (sim_log && (sim_log != stdout)) /* log if enabled */ From 8659281aafe16c5663f99208f1cf79c4355eda6f Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 1 Jan 2015 17:05:41 -0800 Subject: [PATCH 20/41] SCP: Changed sim_poll_kbd() to set the global stop_cpu when the WRU character has been received. Thus behaving consistently with platforms which learn about the WRU character by the delivery of a SIGINT. --- sim_console.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sim_console.c b/sim_console.c index 327dbb88..3c325d00 100644 --- a/sim_console.c +++ b/sim_console.c @@ -1769,9 +1769,12 @@ if (sim_send_poll_data (&sim_con_send, &c)) /* injected input charac return c; if (!sim_rem_master_mode) { c = sim_os_poll_kbd (); /* get character */ - if ((c == SCPE_STOP) || /* ^E or not Telnet? */ - ((sim_con_tmxr.master == 0) && /* and not serial? */ - (sim_con_ldsc.serport == 0))) + if (c == SCPE_STOP) { /* ^E */ + stop_cpu = 1; /* Force a stop (which is picked up by sim_process_event */ + return SCPE_OK; + } + if ((sim_con_tmxr.master == 0) && /* not Telnet? */ + (sim_con_ldsc.serport == 0)) /* and not serial? */ return c; /* in-window */ if (!sim_con_ldsc.conn) { /* no telnet or serial connection? */ if (!sim_con_ldsc.txbfd) /* unbuffered? */ From 3b4bc61fdfee0617017b51b5a7156ba933a8f724 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 2 Jan 2015 04:37:11 -0800 Subject: [PATCH 21/41] MicroVAX1, MicroVAX2: Compiler/Linker suggested cleanup --- VAX/vax_vc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAX/vax_vc.c b/VAX/vax_vc.c index 07f59fbb..70a224e4 100644 --- a/VAX/vax_vc.c +++ b/VAX/vax_vc.c @@ -648,7 +648,7 @@ for (scrln = 0; scrln < 1024; scrln++) { vc_buf[rg] = nval; } -SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2) +static SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2) { uint32 ln; for (ln = y1; ln < y2; ln++) From 567e81188e5a2294ccb3ee7e36fbfcce19e071e4 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 2 Jan 2015 05:01:32 -0800 Subject: [PATCH 22/41] =?UTF-8?q?ETHER:=20Fix=20compile=20when=20threaded?= =?UTF-8?q?=20network=20I/O=20is=20disabled=20on=20OS=20X=20(found=20by=20?= =?UTF-8?q?Martin=20Vorl=C3=A4nder)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sim_ether.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index 059f7ac3..f5d9b8cb 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1934,7 +1934,7 @@ else #if !defined (USE_READER_THREAD) #ifdef USE_SETNONBLOCK /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */ - if (pcap_setnonblock (dev->handle, 1, errbuf) == -1) { + if (pcap_setnonblock (*handle, 1, errbuf) == -1) { sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf); } #endif @@ -1946,7 +1946,7 @@ else * the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110 */ int v = 1; - ioctl(pcap_fileno(dev->handle), BIOCIMMEDIATE, &v); + ioctl(pcap_fileno(*handle), BIOCIMMEDIATE, &v); } #endif /* defined (__APPLE__) */ #endif /* !defined (USE_READER_THREAD) */ From c2975c8e0e3bc4e3a0b9ce97734d6fa10df259e8 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Sat, 3 Jan 2015 16:57:12 -0800 Subject: [PATCH 23/41] BESM6: No need to check for printing to console. --- BESM6/besm6_printer.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c index 79cf647e..dbfe4ec3 100644 --- a/BESM6/besm6_printer.c +++ b/BESM6/besm6_printer.c @@ -52,8 +52,6 @@ struct acpu_t { unsigned char line[128][MAX_STRIKES]; } acpu[2]; -int acpu_isatty[2]; - #define PRN1_NOT_READY (1<<19) #define PRN2_NOT_READY (1<<18) @@ -116,12 +114,6 @@ t_stat printer_attach (UNIT *u, char *cptr) if (s != SCPE_OK) return s; - acpu_isatty[num] = !strcmp(cptr, "/dev/tty"); - if (!acpu_isatty[num]) { - /* Write UTF-8 tag: zero width no-break space. */ - fputs ("\xEF\xBB\xBF", u->fileref); - } - READY &= ~(PRN1_NOT_READY >> num); return SCPE_OK; } @@ -321,9 +313,6 @@ offset_gost_write (int num, FILE *fout) } } - if (acpu_isatty[num]) - fputc('\r', fout); - fputc ('\n', fout); memset(dev->line, 0, sizeof (dev->line)); dev->length = dev->strikes = 0; From a7f05ac40c22923837e30da1c4f039dee4f2186c Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Sun, 4 Jan 2015 02:28:07 -0800 Subject: [PATCH 24/41] BESM6: Added TTY interrupt insertion in the idle loop. --- BESM6/besm6_cpu.c | 8 +++----- BESM6/besm6_defs.h | 2 ++ BESM6/besm6_tty.c | 5 ++--- BESM6/dispak.ini | 3 ++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index dc1ffd12..aa60cbc2 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -1427,17 +1427,15 @@ void cpu_one_inst () /* Не находимся ли мы в цикле "ЖДУ" диспака? */ if (RUU == 047 && PC == 04440 && RK == 067704440) { - /* Притормаживаем выполнение каждой команды холостого цикла, - * чтобы быстрее обрабатывались прерывания: ускоряются - * терминалы и АЦПУ. */ - delay = sim_interval; - /* Если периферия простаивает, освобождаем процессор * до следующего тика таймера. */ if (vt_is_idle() && printer_is_idle() && fs_is_idle()) { check_initial_setup (); sim_idle (0, TRUE); + } else if (sim_activate_time(tty_unit) > 1000*MSEC/300) { + /* Insert a TTY interrupt if a regular one is too far away */ + sim_activate_abs(tty_unit, 0); } } } diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index a933664a..55a2f4fc 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -127,6 +127,7 @@ enum { #define CLK_DELAY 4000 /* Uncalibrated instructions per clock tick */ extern UNIT cpu_unit; +extern UNIT tty_unit[]; extern t_value memory [MEMSIZE]; extern t_value pult [8]; extern uint32 PC, RAU, RUU; @@ -398,6 +399,7 @@ t_value besm6_unpack (t_value val, t_value mask); #define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ #define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ #define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ +#define GRP_SERIAL 00000000001000000LL /* 19 */ #define GRP_WATCHDOG 00000000000002000LL /* 11 */ #define GRP_SLOW_CLK 00000000000001000LL /* 10 */ /* Внутренние: */ diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 729fb714..0d7f598f 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -172,7 +172,7 @@ t_stat vt_clk (UNIT * this) /* Телетайпы работают на 10 бод */ static int clk_divider = 1<<29; - GRP |= MGRP & BBIT(19); + GRP |= MGRP & GRP_SERIAL; /* Опрашиваем сокеты на приём. */ tmxr_poll_rx (&tty_desc); @@ -1137,7 +1137,6 @@ void vt_receive() } if (tty_typed[num] < 0) { /* TODO: обработать исключение от "неоператорского" терминала */ -// sim_interval = 0; break; } if (tty_typed[num] <= 0177) { @@ -1148,7 +1147,7 @@ void vt_receive() tty_instate[num] = 1; TTY_IN |= mask; /* start bit */ GRP |= GRP_TTY_START; /* не используется ? */ - MGRP |= BBIT(19); /* для терминалов по методу МГУ */ + MGRP |= GRP_SERIAL; /* для терминалов по методу МГУ */ vt_receiving |= mask; } break; diff --git a/BESM6/dispak.ini b/BESM6/dispak.ini index 078a6c12..f62f8095 100644 --- a/BESM6/dispak.ini +++ b/BESM6/dispak.ini @@ -1,5 +1,6 @@ set -n console log=log.txt set console debug=log +set cpu idle ;set cpu debug ;set mmu debug ;set drum debug @@ -40,7 +41,7 @@ attach tty1 /dev/tty ; Режимы по вкусу ; ;set tty1 jcuken,authbs -set tty1 authbs +set tty1 qwerty,authbs set -n tty1 log=tty1.txt ; From aa16857edc5801cdd969bbe543192b07cee199c7 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Sun, 4 Jan 2015 23:14:51 -0800 Subject: [PATCH 25/41] BESM6: Updated licenses missed before, TTYs use sim_putchar(), translated comments in besm6_tty.c; using "console" instead of "/dev/tty". --- BESM6/besm6_cpu.c | 3 +- BESM6/besm6_sys.c | 30 ++++-- BESM6/besm6_tty.c | 270 +++++++++++++++++++++++----------------------- BESM6/dispak.ini | 2 +- 4 files changed, 162 insertions(+), 143 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index aa60cbc2..d0f0dae4 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -1429,8 +1429,7 @@ void cpu_one_inst () if (RUU == 047 && PC == 04440 && RK == 067704440) { /* Если периферия простаивает, освобождаем процессор * до следующего тика таймера. */ - if (vt_is_idle() && - printer_is_idle() && fs_is_idle()) { + if (vt_is_idle()) { check_initial_setup (); sim_idle (0, TRUE); } else if (sim_activate_time(tty_unit) > 1000*MSEC/300) { diff --git a/BESM6/besm6_sys.c b/BESM6/besm6_sys.c index 86cfe8cb..c342174c 100644 --- a/BESM6/besm6_sys.c +++ b/BESM6/besm6_sys.c @@ -4,14 +4,28 @@ * Copyright (c) 2009, Serge Vakulenko * Copyright (c) 2009, Leonid Broukhis * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You can redistribute this program and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation; - * either version 2 of the License, or (at your discretion) any later version. - * See the accompanying file "COPYING" for more details. + * 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. * * This file implements three essential functions: * diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 0d7f598f..dd5855b1 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -3,15 +3,28 @@ * * Copyright (c) 2009, Leo Broukhis * Copyright (c) 2009, Serge Vakulenko - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - * - * You can redistribute this program and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation; - * either version 2 of the License, or (at your discretion) any later version. - * See the accompanying file "COPYING" for more details. + * 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" @@ -19,10 +32,10 @@ #include "sim_tmxr.h" #include -#define TTY_MAX 24 /* Количество последовательных терминалов */ -#define LINES_MAX TTY_MAX + 2 /* Включая параллельные интерфейсы "Консулов" */ +#define TTY_MAX 24 /* Serial TTY lines */ +#define LINES_MAX TTY_MAX + 2 /* Including parallel "Consul" typewriters */ /* - * Согласно таблице в http://ru.wikipedia.org/wiki/МТК-2 + * According to a table in http://ru.wikipedia.org/wiki/МТК-2 */ char * rus[] = { 0, "Т", "\r", "О", " ", "Х", "Н", "М", "\n", "Л", "Р", "Г", "И", "П", "Ц", "Ж", "Е", "З", "Д", "Б", "С", "Ы", "Ф", "Ь", "А", "В", "Й", 0, "У", "Я", "К", 0 }; @@ -38,7 +51,7 @@ char ** reg = 0; char * process (int sym) { - /* Требуется инверсия */ + /* Inversion is required for Baudot TTYs */ sym ^= 31; switch (sym) { case 0: @@ -56,7 +69,7 @@ char * process (int sym) return ""; } -/* Только для последовательных линий */ +/* For serial lines */ int tty_active [TTY_MAX+1], tty_sym [TTY_MAX+1]; int tty_typed [TTY_MAX+1], tty_instate [TTY_MAX+1]; time_t tty_last_time [TTY_MAX+1]; @@ -74,7 +87,7 @@ uint32 CONSUL_IN[2]; uint32 CONS_CAN_PRINT[2] = { 01000, 00400 }; uint32 CONS_HAS_INPUT[2] = { 04000, 02000 }; -/* Буфера командных строк для режима telnet. */ +/* Command line buffers for TELNET mode. */ char vt_cbuf [CBUFSIZE] [LINES_MAX+1]; char *vt_cptr [LINES_MAX+1]; @@ -121,13 +134,13 @@ REG tty_reg[] = { }; /* - * Дескрипторы линий для мультиплексора TMXR. - * Поле .conn содержит номер сокета и означает занятую линию. - * Для локальных терминалов делаем .conn = 1. - * Чтобы нумерация линий совпадала с нумерацией терминалов - * (с единицы), нулевую линию держим занятой (.conn = 1). - * Поле .rcve устанавливается в 1 для сетевых соединений. - * Для локальных терминалов оно равно 0. + * Line descriptors for the TMXR multiplexor. + * The .conn field contains the socket number and denotes a used line. + * For local terminals, .conn = 1. + * To match line indexes with TTY numbers (1-based), + * line 0 is kept used (.conn = 1). + * The .rcve field is set to 1 for network connections. + * For local connections, it is 0. */ TMLN tty_line [LINES_MAX+1]; TMXR tty_desc = { LINES_MAX+1, 0, 0, tty_line }; /* mux descriptor */ @@ -158,23 +171,24 @@ t_stat tty_reset (DEVICE *dptr) reg = rus; vt_idle = 1; tty_line[0].conn = 1; /* faked, always busy */ - /* Готовность устройства в READY2 инверсная, а устройство всегда готово */ - /* Провоцируем передачу */ + /* In the READY2 register the ready flag for typewriters is inverted (0 means ready), + * and the device is always ready. */ + /* Forcing a ready interrupt. */ PRP |= CONS_CAN_PRINT[0] | CONS_CAN_PRINT[1]; //return sim_activate_after (tty_unit, 1000*MSEC/300); return sim_clock_coschedule (tty_unit, tmr_poll); } -/* 19 р ГРП, 300 Гц */ +/* Bit 19 of GRP, should be 300 Hz */ t_stat vt_clk (UNIT * this) { int num; - /* Телетайпы работают на 10 бод */ + /* Baudot TTYs work at 10 baud */ static int clk_divider = 1<<29; GRP |= MGRP & GRP_SERIAL; - /* Опрашиваем сокеты на приём. */ + /* Polling receiving from sockets */ tmxr_poll_rx (&tty_desc); vt_print(); @@ -183,16 +197,16 @@ t_stat vt_clk (UNIT * this) if (! (clk_divider >>= 1)) { tt_print(); - /* Прием не реализован */ + /* Input from Baudot TTYs not implemented */ clk_divider = 1<<29; } - /* Есть новые сетевые подключения? */ + /* Are there any new network connections? */ num = tmxr_poll_conn (&tty_desc); if (num > 0 && num <= LINES_MAX) { char buf [80]; TMLN *t = &tty_line [num]; - besm6_debug ("*** tty%d: новое подключение от %s", + besm6_debug ("*** tty%d: a new connection from %s", num, t->ipad); t->rcve = 1; tty_unit[num].flags &= ~TTY_STATE_MASK; @@ -218,14 +232,17 @@ t_stat vt_clk (UNIT * this) t->ipad); tmxr_linemsg (t, buf); - /* Ввод ^C, чтобы получить приглашение. */ + /* Entering ^C (ETX) to get a prompt. */ t->rxb [t->rxbpi++] = '\3'; } - /* Опрашиваем сокеты на передачу. */ + /* Polling sockets for transmission. */ tmxr_poll_tx (&tty_desc); - // return sim_activate_after (tty_unit, 1000*MSEC/300); + /* We'll get a guaranteed interrupt rate of 250 Hz (wallclock) + * plus additional interrupts during the idle loop for speedup + * (see besm6_cpu.c). + */ return sim_clock_coschedule (this, tmr_poll); } @@ -280,10 +297,9 @@ t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) } /* - * Разрешение подключения к терминалам через telnet. - * Делается командой: - * attach tty <порт> - * Здесь <порт> - номер порта telnet, например 4199. + * Allowing telnet connections is done with + * attach tty + * Where is the port number for telnet, e.g. 4199. */ t_stat tty_attach (UNIT *u, char *cptr) { @@ -291,39 +307,40 @@ t_stat tty_attach (UNIT *u, char *cptr) int r, m, n; if (*cptr >= '0' && *cptr <= '9') { - /* Сохраняем и восстанавливаем все .conn, - * так как tmxr_attach() их обнуляет. */ + /* Saving and restoring all .conn, + * because tmxr_attach() zeroes them. */ for (m=0, n=1; n<=LINES_MAX; ++n) if (tty_line[n].conn) m |= 1 << (LINES_MAX-n); - /* Неважно, какой номер порта указывать в команде задания - * порта telnet. Можно tty, можно tty1 - без разницы. */ + /* The unit number is ignored for the port assignment */ r = tmxr_attach (&tty_desc, &tty_unit[0], cptr); for (n=1; n<=LINES_MAX; ++n) if (m >> (LINES_MAX-n) & 1) tty_line[n].conn = 1; return r; } - if (strcmp (cptr, "/dev/tty") == 0) { - /* Консоль. */ + + if (strcmp (cptr, "console") == 0) { + /* Attaching SIMH console to a particular terminal. */ u->flags &= ~TTY_STATE_MASK; u->flags |= TTY_VT340_STATE; tty_line[num].conn = 1; tty_line[num].rcve = 0; if (num <= TTY_MAX) vt_mask |= 1 << (TTY_MAX - num); - besm6_debug ("*** консоль на T%03o", num); + besm6_debug ("*** console on T%03o", num); return 0; } - if (strcmp (cptr, "/dev/null") == 0) { - /* Запрещаем терминал. */ + /* Disallowing future connections to a line */ + if (strcmp (cptr, "none") == 0) { + /* Marking the TTY as unusable. */ tty_line[num].conn = 1; tty_line[num].rcve = 0; if (num <= TTY_MAX) { vt_mask &= ~(1 << (TTY_MAX - num)); tt_mask &= ~(1 << (TTY_MAX - num)); } - besm6_debug ("*** отключение терминала T%03o", num); + besm6_debug ("*** turning off T%03o", num); return 0; } return SCPE_ALATT; @@ -335,20 +352,20 @@ t_stat tty_detach (UNIT *u) } /* - * Управление терминалами. - * set ttyN unicode - выбор кодировки UTF-8 - * set ttyN jcuken - выбор кодировки КОИ-7, раскладка йцукен - * set ttyN qwerty - выбор кодировки КОИ-7, раскладка яверты - * set ttyN off - отключение - * set ttyN tt - установка типа терминала "Телетайп" - * set ttyN vt - установка типа терминала "Видеотон-340" - * set ttyN consul - установка типа терминала "Consul-254" - * set ttyN destrbs - "стирающий" backspace - * set ttyN authbs - классический backspace - * set tty disconnect=N - принудительное завершение сеанса telnet - * show tty - просмотр режимов терминалов - * show tty connections - просмотр IP-адресов и времени соединений - * show tty statistics - просмотр счетчиков переданных и принятых байтов + * TTY control: + * set ttyN unicode - selecting UTF-8 encoding + * set ttyN jcuken - selecting KOI-7 encoding, JCUKEN layout + * set ttyN qwerty - selecting KOI-7 encoding, QWERTY layout + * set ttyN off - disconnecting a line + * set ttyN tt - a Baudot TTY + * set ttyN vt - a Videoton-340 terminal + * set ttyN consul - a "Consul-254" typewriter + * set ttyN destrbs - destructive (erasing) backspace + * set ttyN authbs - authentic backspace (cursor left) + * set tty disconnect=N - forceful termination of a telnet connection + * show tty - showing modes and types + * show tty connections - showing IP-addresses and connection times + * show tty statistics - showing TX/RX byte counts */ MTAB tty_mod[] = { { TTY_CHARSET_MASK, TTY_UNICODE_CHARSET, "UTF-8 input", @@ -393,13 +410,13 @@ DEVICE tty_dev = { void tty_send (uint32 mask) { - /* besm6_debug ("*** телетайпы: передача %08o", mask); */ + /* besm6_debug ("*** TTY: transmit %08o", mask); */ TTY_OUT = mask; } /* - * Выдача символа на терминал с указанным номером. + * Sending a character to a terminal with the given number. */ void vt_putc (int num, int c) { @@ -408,38 +425,29 @@ void vt_putc (int num, int c) if (! t->conn) return; if (t->rcve) { - /* Передача через telnet. */ + /* A telnet connection. */ tmxr_putc_ln (t, c); } else { - /* Вывод на консоль. */ - if (t->txlog) { /* log if available */ - fputc (c, t->txlog); - if (c == '\n') - fflush (t->txlog); - } - fputc (c, stdout); - fflush (stdout); + /* Console output. */ + sim_putchar(c); } } /* - * Выдача строки на терминал с указанным номером. + * Sending a string to a terminal with the given number. */ -void vt_puts (int num, const char *s) +void vt_puts (int num, const unsigned char *s) { TMLN *t = &tty_line [num]; if (! t->conn) return; if (t->rcve) { - /* Передача через telnet. */ + /* A telnet connection. */ tmxr_linemsg (t, (char*) s); } else { - /* Вывод на консоль. */ - if (t->txlog) /* log if available */ - fputs (s, t->txlog); - fputs (s, stdout); - fflush (stdout); + /* Console output. */ + while (*s) sim_putchar(*s++); } } @@ -450,6 +458,7 @@ const char * koi7_rus_to_unicode [32] = { "Ь", "Ы", "З", "Ш", "Э", "Щ", "Ч", "\0x7f", }; +/* Videoton-340 employed single byte control codes rather than ESC sequences. */ void vt_send(int num, uint32 sym, int destructive_bs) { if (sym < 0x60) { @@ -473,7 +482,7 @@ void vt_send(int num, uint32 sym, int destructive_bs) /* Left */ vt_puts (num, "\033["); if (destructive_bs) { - /* Стираем предыдущий символ. */ + /* Erasing the previous char. */ vt_puts (num, "D \033["); } sym = 'D'; @@ -481,37 +490,35 @@ void vt_send(int num, uint32 sym, int destructive_bs) case '\v': case '\033': case '\0': - /* Выдаём управляющий символ. */ + /* Sending the actual char */ break; case '\037': - /* Очистка экрана */ + /* Clear screen */ vt_puts (num, "\033[H\033["); sym = 'J'; break; case '\n': - /* На VDT-340 также возвращал курсор в 1-ю позицию */ + /* Also does carriage return */ vt_putc (num, '\r'); sym = '\n'; break; case '\f': - /* Сообщение ERR при нажатии некоторых управляющих - * клавиш выдается с использованием reverse wraparound. - */ + /* Home */ vt_puts(num, "\033["); sym = 'H'; break; case '\r': case '\003': - /* Неотображаемые символы */ + /* Not displayed */ sym = 0; break; default: if (sym < ' ') { - /* Нефункциональные ctrl-символы были видны в половинной яркости */ + /* Other control chars were displayed as dimmed. */ vt_puts (num, "\033[2m"); vt_putc (num, sym | 0x40); vt_puts (num, "\033["); - /* Завершаем ESC-последовательность */ + /* Terminating the ESC sequence */ sym = 'm'; } } @@ -522,7 +529,7 @@ void vt_send(int num, uint32 sym, int destructive_bs) } /* - * Обработка выдачи на все подключенные терминалы. + * Handling output to all connected terminals. */ void vt_print() { @@ -569,8 +576,7 @@ void vt_print() vt_idle = 0; } -/* Ввод с телетайпа не реализован; вывод работает только при использовании - * модельного времени. +/* Input from Baudot TTYs not implemented. Output may require some additional work. */ void tt_print() { @@ -615,8 +621,8 @@ void tt_print() } /* - * Перекодировка из Unicode в КОИ-7. - * Если нет соответствия, возвращает -1. + * Converting from Unicode to KOI-7. + * Returns -1 if unsuccessful. */ static int unicode_to_koi7 (unsigned val) { @@ -820,7 +826,7 @@ static t_stat cmd_help (int32 num, char *cptr) if (! cptr) return SCPE_INVSW; if (! *cptr) { - /* Список всех команд. */ + /* Listing all commands. */ tmxr_linemsg (t, "Commands may be abbreviated. Commands are:\r\n\r\n"); for (c=cmd_table; c && c->name; c++) if (c->help) @@ -833,13 +839,13 @@ static t_stat cmd_help (int32 num, char *cptr) c = lookup_cmd (gbuf); if (! c) return SCPE_ARG; - /* Описание конкретной команды. */ + /* Describing a command. */ tmxr_linemsg (t, c->help); return SCPE_OK; } /* - * Выполнение командной строки. + * Executing a command. */ void vt_cmd_exec (int num) { @@ -867,7 +873,7 @@ void vt_cmd_exec (int num) } /* - * Режим управляющей командной строки. + * Command line interface mode. */ void vt_cmd_loop (int num, int c) { @@ -882,11 +888,11 @@ void vt_cmd_loop (int num, int c) case '\n': tmxr_linemsg (t, "\r\n"); if (*cptr <= cbuf) { - /* Пустая строка - возврат в обычный режим. */ + /* An empty line - returning to terminal emulation. */ tty_unit[num].flags &= ~TTY_CMDLINE_MASK; break; } - /* Выполнение. */ + /* Executing. */ **cptr = 0; vt_cmd_exec (num); tmxr_linemsg (t, "sim>"); @@ -894,7 +900,7 @@ void vt_cmd_loop (int num, int c) break; case '\b': case 0177: - /* Стирание предыдущего символа. */ + /* Backspace. */ if (*cptr <= cbuf) break; tmxr_linemsg (t, "\b \b"); @@ -905,7 +911,7 @@ void vt_cmd_loop (int num, int c) } break; case 'U' & 037: - /* Стирание всей строки. */ + /* Erase line. */ erase_line: while (*cptr > cbuf) { --*cptr; if (! (**cptr & 0x80)) @@ -917,14 +923,14 @@ void vt_cmd_loop (int num, int c) if (tmxr_getc_ln (t) != '[' + TMXR_VALID) break; switch (tmxr_getc_ln (t) - TMXR_VALID) { - case 'A': /* стрелка вверх */ + case 'A': /* Up arrow */ if (*cptr <= cbuf) { *cptr = cbuf + strlen (cbuf); if (*cptr > cbuf) tmxr_linemsg (t, cbuf); } break; - case 'B': /* стрелка вниз */ + case 'B': /* Down arrow */ goto erase_line; } break; @@ -938,9 +944,8 @@ void vt_cmd_loop (int num, int c) } /* - * Ввод символа с терминала с указанным номером. - * Если нет приёма, возвращает -1. - * В случае прерывания возвращает 0400 (только для консоли). + * Getting a char from a terminal with the given number. + * Returns -1 if there is no char to input. */ int vt_getc (int num) { @@ -952,7 +957,7 @@ int vt_getc (int num) if (! t->conn) { /* Пользователь отключился. */ if (t->ipad) { - besm6_debug ("*** tty%d: отключение %s", + besm6_debug ("*** tty%d: disconnecting %s", num, t->ipad); t->ipad = NULL; @@ -962,18 +967,18 @@ int vt_getc (int num) return -1; } if (t->rcve) { - /* Приём через telnet. */ + /* A telnet line. */ c = tmxr_getc_ln (t); if (! (c & TMXR_VALID)) { now = time (0); if (now > tty_last_time[num] + 5*60) { ++tty_idle_count[num]; if (tty_idle_count[num] > 3) { - tmxr_linemsg (t, "\r\nКОНЕЦ СЕАНСА\r\n"); + tmxr_linemsg (t, "\r\nSIMH: END OF SESSION\r\n"); tmxr_reset_ln (t); return -1; } - tmxr_linemsg (t, "\r\nНЕ СПАТЬ!\r\n"); + tmxr_linemsg (t, "\r\nSIMH: WAKE UP!\r\n"); tty_last_time[num] = now; } return -1; @@ -982,23 +987,23 @@ int vt_getc (int num) tty_last_time[num] = time (0); if (tty_unit[num].flags & TTY_CMDLINE_MASK) { - /* Продолжение режима управляющей командной строки. */ + /* Continuing CLI mode. */ vt_cmd_loop (num, c & 0377); return -1; } if ((c & 0377) == sim_int_char) { - /* Вход в режим управляющей командной строки. */ + /* Entering CLI mode. */ tty_unit[num].flags |= TTY_CMDLINE_MASK; tmxr_linemsg (t, "sim>"); vt_cptr[num] = vt_cbuf[num]; return -1; } } else { - /* Ввод с клавиатуры. */ + /* Console (keyboard) input. */ c = sim_poll_kbd(); if (c == SCPE_STOP) { - return 0400; /* прерывание */ - } + stop_cpu = 1; /* just in case */ + } if (! (c & SCPE_KFLAG)) return -1; } @@ -1006,11 +1011,9 @@ int vt_getc (int num) } /* - * Ввод символа с клавиатуры. - * Перекодировка из UTF-8 в КОИ-7. - * Полученный символ находится в диапазоне 0..0177. - * Если нет ввода, возвращает -1. - * В случае прерывания (^E) возвращает 0400. + * Reading UTF-8, returning KOI-7. + * The resulting char is in the range 0..0177. + * If no input, returns -1. */ static int vt_kbd_input_unicode (int num) { @@ -1043,9 +1046,9 @@ static int vt_kbd_input_unicode (int num) } /* - * Альтернативный вариант ввода, не требующий переключения на русскую клавиатуру. - * Символы "точка" и "запятая" вводятся через shift, "больше-меньше" - "тильда-гравис". - * "точка с запятой" - "закр. фиг. скобка", "апостроф" - "верт. черта". + * Alternatively, entering Cyrillics can be done without switching keyboard layouts. + * Period and comma are entered with shift, less-than and greater-than are mapped to tilde-grave. + * Semicolon is }, quote is |. */ static int vt_kbd_input_koi7 (int num) { @@ -1108,7 +1111,7 @@ int odd_parity(unsigned char c) } /* - * Обработка ввода со всех подключенных терминалов. + * Handling input from all connected terminals. */ void vt_receive() { @@ -1136,18 +1139,20 @@ void vt_receive() break; } if (tty_typed[num] < 0) { - /* TODO: обработать исключение от "неоператорского" терминала */ break; } if (tty_typed[num] <= 0177) { if (tty_typed[num] == '\r' || tty_typed[num] == '\n') - tty_typed[num] = 3; /* ^C - конец строки */ + tty_typed[num] = 3; /* ETX is used as Enter */ if (tty_typed[num] == '\177') tty_typed[num] = '\b'; /* ASCII DEL -> BS */ tty_instate[num] = 1; TTY_IN |= mask; /* start bit */ - GRP |= GRP_TTY_START; /* не используется ? */ - MGRP |= GRP_SERIAL; /* для терминалов по методу МГУ */ + GRP |= GRP_TTY_START; /* not used ? */ + /* auto-enabling the interrupt just in case + * (seems to be unneeded as the interrupt is never disabled) + */ + MGRP |= GRP_SERIAL; vt_receiving |= mask; } break; @@ -1176,7 +1181,8 @@ void vt_receive() } /* - * Выясняем, остановлены ли терминалы. Нужно для входа в "спящий" режим. + * Checking if all terminals are idle. + * SIMH should not enter idle mode until they are. */ int vt_is_idle () { @@ -1185,7 +1191,7 @@ int vt_is_idle () int tty_query () { - /* besm6_debug ("*** телетайпы: приём");*/ + /* besm6_debug ("*** TTY: query");*/ return TTY_IN; } diff --git a/BESM6/dispak.ini b/BESM6/dispak.ini index f62f8095..581f94ec 100644 --- a/BESM6/dispak.ini +++ b/BESM6/dispak.ini @@ -35,7 +35,7 @@ attach prn0 /dev/tty ; Активируем операторский терминал, ; на который идут сообщения. ; -attach tty1 /dev/tty +attach tty1 console ; ; Режимы по вкусу From bd260dd523f40e0b6cf2b36c4db4f301d56940fd Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Tue, 6 Jan 2015 01:37:43 -0800 Subject: [PATCH 26/41] BESM6: Schedule the serial line timer by instruction count when I/O is pending, and by wallclock time otherwise. This achieves a good TTY output rate even when the CPU is busy with a user process. --- BESM6/besm6_cpu.c | 17 ++++++++--------- BESM6/besm6_defs.h | 3 +-- BESM6/besm6_printer.c | 12 ------------ BESM6/besm6_punch.c | 5 ----- BESM6/besm6_tty.c | 17 ++++++++++++----- BESM6/dispak.ini | 2 +- 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index d0f0dae4..841b20d2 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -708,6 +708,12 @@ void check_initial_setup () /* 7 р. яч. ЗАНЯТА - разр любые приказы */ const t_value ALL_REQS_ENABLED = 1 << 6; + if (!vt_is_idle()) { + /* Avoid sending setup requests while the OS + * is still printing boot-up messages. + */ + return; + } if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || (MGRP & GRP_PANEL_REQ) == 0) { @@ -1427,15 +1433,8 @@ void cpu_one_inst () /* Не находимся ли мы в цикле "ЖДУ" диспака? */ if (RUU == 047 && PC == 04440 && RK == 067704440) { - /* Если периферия простаивает, освобождаем процессор - * до следующего тика таймера. */ - if (vt_is_idle()) { - check_initial_setup (); - sim_idle (0, TRUE); - } else if (sim_activate_time(tty_unit) > 1000*MSEC/300) { - /* Insert a TTY interrupt if a regular one is too far away */ - sim_activate_abs(tty_unit, 0); - } + check_initial_setup (); + sim_idle(0, TRUE); } } diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index 55a2f4fc..385a0130 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -128,6 +128,7 @@ enum { extern UNIT cpu_unit; extern UNIT tty_unit[]; +extern UNIT clocks[]; extern t_value memory [MEMSIZE]; extern t_value pult [8]; extern uint32 PC, RAU, RUU; @@ -326,7 +327,6 @@ int disk_errors (void); */ void printer_control (int num, uint32 cmd); void printer_hammer (int num, int pos, uint32 mask); -int printer_is_idle (void); /* * Терминалы (телетайпы, видеотоны, "Консулы"). @@ -344,7 +344,6 @@ int vt_is_idle (void); */ void fs_control (int num, uint32 cmd); int fs_read (int num); -int fs_is_idle (void); /* * Отладочная выдача. diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c index dbfe4ec3..89bd11f5 100644 --- a/BESM6/besm6_printer.c +++ b/BESM6/besm6_printer.c @@ -317,15 +317,3 @@ offset_gost_write (int num, FILE *fout) memset(dev->line, 0, sizeof (dev->line)); dev->length = dev->strikes = 0; } - -/* - * Выясняем, остановлены ли АЦПУ. Нужно для входа в "спящий" режим. - */ -int printer_is_idle () -{ - if (sim_is_active(&printer_unit[0])) - return 0; - if (sim_is_active(&printer_unit[1])) - return 0; - return 1; -} diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c index 1051430f..add2d5bb 100644 --- a/BESM6/besm6_punch.c +++ b/BESM6/besm6_punch.c @@ -279,11 +279,6 @@ int fs_read(int num) { return FS[num]; } -int fs_is_idle (void) -{ - return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE; -} - unsigned char unicode_to_gost (unsigned short val) { diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index dd5855b1..44ca5591 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -238,12 +238,19 @@ t_stat vt_clk (UNIT * this) /* Polling sockets for transmission. */ tmxr_poll_tx (&tty_desc); - - /* We'll get a guaranteed interrupt rate of 250 Hz (wallclock) - * plus additional interrupts during the idle loop for speedup - * (see besm6_cpu.c). + /* If the TTY system is not idle, schedule the next interrupt + * by instruction count using the target interrupt rate of 300 Hz; + * otherwise we can wait for a roughly equivalent wallclock time period, + * e.g. until the next 250 Hz wallclock interrupt, but making sure + * that the model time interval between GRP_SERIAL interrupts + * is never less than expected. + * Using sim_activate_after() would be more straightforward (no need for a check + * as the host is faster than the target), but likely less efficient for idling. */ - return sim_clock_coschedule (this, tmr_poll); + if (vt_is_idle() && sim_activate_time(clocks) > 1000*MSEC/300) + return sim_clock_coschedule (this, tmr_poll); + else + return sim_activate(this, 1000*MSEC/300); } t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) diff --git a/BESM6/dispak.ini b/BESM6/dispak.ini index 581f94ec..ac2170c2 100644 --- a/BESM6/dispak.ini +++ b/BESM6/dispak.ini @@ -29,7 +29,7 @@ attach -e disk2 alt2048.bin ; ; Подключаем АЦПУ. ; -attach prn0 /dev/tty +attach prn0 output.txt ; ; Активируем операторский терминал, From 703c5697be92da703f24e57e34a1b11b397a79cb Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 06:48:59 -0800 Subject: [PATCH 27/41] BESM6: Have makefile search for one of several potential FONTNAME fonts in several potential FONTPATH directories. Fix besm6_panel to use FONTFILE when building with SDL 1.2, Fix besm6_panel compile issues on Windows Provide FONTFILE name via either -DFONTFILE OR via a #define in a generated besm6_panel_font.h --- BESM6/besm6_panel.c | 47 +++++++++++++++++++++++---------------------- makefile | 40 ++++++++++++++++++++++++++------------ 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c index a2052f64..66cc7fcf 100644 --- a/BESM6/besm6_panel.c +++ b/BESM6/besm6_panel.c @@ -28,6 +28,16 @@ * the sale, use or other dealings in this Software without prior written * authorization from Leonid Broukhis and Serge Vakulenko. */ + +#if defined (HAVE_LIBSDL) +#if !defined (FONTFILE) +#include "besm6_panel_font.h" +#endif /* !defined (FONTFILE) */ +#if !defined (FONTFILE) +#undef HAVE_LIBSDL +#endif /* !defined (FONTFILE) */ +#endif /* defined (HAVE_LIBSDL) */ + #ifdef HAVE_LIBSDL #include "besm6_defs.h" @@ -50,7 +60,6 @@ #define QUOTE(x) _QUOTE(x) /* Data and functions that don't depend on SDL version */ -static char *font_path; static TTF_Font *font_big; static TTF_Font *font_small; static SDL_Color foreground; @@ -99,13 +108,14 @@ static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message static SDL_Surface *sprite_from_data (int width, int height, const unsigned char *data) { - SDL_Surface *sprite, *optimized; - unsigned *s, r, g, b, y, x; + SDL_Surface *sprite; + unsigned *s, r, g, b; + int y, x; sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, width, height, DEPTH, 0, 0, 0, 0); /* - optimized = SDL_DisplayFormat (sprite); + SDL_Surface *optimized = SDL_DisplayFormat (sprite); SDL_FreeSurface (sprite); sprite = optimized; */ @@ -337,7 +347,7 @@ static void draw_brz_static (int top) /* * Закрываем графическое окно. */ -void besm6_close_panel () +void besm6_close_panel (void) { if (! screen) return; @@ -356,7 +366,7 @@ static SDL_Texture *sdlTexture; /* * Начальная инициализация графического окна и шрифтов. */ -static void init_panel () +static void init_panel (void) { if (sim_switches & SWMASK('Q')) return; @@ -430,8 +440,10 @@ void (*sim_vm_init)() = init_panel; /* * Обновляем графическое окно. */ -void besm6_draw_panel () +void besm6_draw_panel (void) { + SDL_Event event; + if (! screen) return; @@ -448,7 +460,6 @@ void besm6_draw_panel () SDL_RenderPresent (sdlRenderer); /* Exit SIMH when window closed.*/ - SDL_Event event; if (SDL_PollEvent (&event) && event.type == SDL_QUIT) longjmp (cpu_halt, SCPE_STOP); } @@ -458,7 +469,7 @@ void besm6_draw_panel () /* * Начальная инициализация графического окна и шрифтов. */ -static void init_panel () +static void init_panel (void) { if (sim_switches & SWMASK('Q')) return; @@ -484,22 +495,12 @@ static void init_panel () exit (1); } - /* Find font file */ - if (ftw (FONTPATH1, probe_font, 255) <= 0 && - ftw (FONTPATH2, probe_font, 255) <= 0 && - ftw (FONTPATH3, probe_font, 255) <= 0) { - fprintf(stderr, "SDL: couldn't find font %s in directory %s\n", - FONTNAME, FONTPATH1); - besm6_close_panel(); - exit (1); - } - /* Open the font file with the requested point size */ - font_big = TTF_OpenFont (font_path, 16); - font_small = TTF_OpenFont (font_path, 9); + font_big = TTF_OpenFont (QUOTE(FONTFILE), 16); + font_small = TTF_OpenFont (QUOTE(FONTFILE), 9); if (! font_big || ! font_small) { fprintf(stderr, "SDL: couldn't load font %s: %s\n", - FONTNAME, TTF_GetError()); + QUOTE(FONTFILE), TTF_GetError()); besm6_close_panel(); exit (1); } @@ -543,7 +544,7 @@ void besm6_draw_panel () #endif /* SDL_MAJOR_VERSION */ #else /* HAVE_LIBSDL */ -void besm6_draw_panel () +void besm6_draw_panel (void) { } #endif /* HAVE_LIBSDL */ diff --git a/makefile b/makefile index f536e0e6..19465914 100644 --- a/makefile +++ b/makefile @@ -1167,25 +1167,41 @@ SSEM_OPT = -I ${SSEMD} BESM6D = 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_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 -ifeq (,$(and ${VIDEO_LDFLAGS}, ${FONTFILE})) - ifneq (,$(and ${VIDEO_LDFLAGS}, $(findstring besm6,$(MAKECMDGOALS)))) - $(info ***) - $(info *** BESM-6 video not used: please specify a font file with FONTFILE=pathname to enable the panel display) - $(info ***) +ifneq (,${VIDEO_LDFLAGS}) + ifeq (,${FONTFILE}) + FONTPATH += /usr/share/fonts /usr/share/fonts/truetype /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions + FONTNAME += LucidaSansRegular.ttf FreeSans.ttf + $(info font paths are: $(FONTPATH)) + $(info font names are: $(FONTNAME)) + find_fontfile = $(strip $(firstword $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/$(1))$(wildcard $(dir)/*/$(1))$(wildcard $(dir)/*/*/$(1))$(wildcard $(dir)/*/*/*/$(1))))) + find_font = $(strip $(firstword $(foreach font,$(strip $(FONTNAME)),$(call find_fontfile,$(font))))) + ifneq (,$(call find_font)) + FONTFILE=$(call find_font) + else + $(info ***) + $(info *** BESM-6 video panel disabled.) + $(info *** To enable the panel display please specify one of:) + $(info *** a font path with FONTNAME=path) + $(info *** a font name with FONTNAME=fontname.ttf) + $(info *** a font file with FONTFILE=path/fontname.ttf) + $(info ***) + endif endif - BESM6_OPT = -I ${BESM6D} -DUSE_INT64 +endif +ifeq (,$(and ${VIDEO_LDFLAGS}, ${FONTFILE})) + BESM6_OPT = -I ${BESM6D} -DUSE_INT64 else ifneq (,$(and $(findstring SDL2,${VIDEO_LDFLAGS}),$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf))) $(info using libSDL2_ttf: $(call find_lib,SDL2_ttf) $(call find_include,SDL2/SDL_ttf)) - BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf + BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf else ifneq (,$(and $(call find_include,SDL/SDL_ttf),$(call find_lib,SDL_ttf))) $(info using libSDL_ttf: $(call find_lib,SDL_ttf) $(call find_include,SDL/SDL_ttf)) - BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf + BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf else - BESM6_OPT = -I ${BESM6D} -DUSE_INT64 + BESM6_OPT = -I ${BESM6D} -DUSE_INT64 endif ### From b4dbb76bfc3028b418ab7882b365e56df18377ea Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 4 Jan 2015 06:59:56 -0800 Subject: [PATCH 28/41] SCP: Allow command files to contain UTF-8 data. - Ignore a UTF_BOM sequence at the beginning of command files. - Provide a sim_isspace() which makes sure that isspace only considers the character being examined as an unsigned char. --- scp.c | 53 ++++++++++++++++++++++++++++++----------------------- scp.h | 1 + 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/scp.c b/scp.c index 4e0ae424..2ab84847 100644 --- a/scp.c +++ b/scp.c @@ -2629,7 +2629,7 @@ errabort = sim_switches & SWMASK ('E'); /* -e means abort on err c = fcptr; do_arg[10] = NULL; /* make sure the argument list always ends with a NULL */ for (nargs = 0; nargs < 10; ) { /* extract arguments */ - while (isspace (*c)) /* skip blanks */ + while (sim_isspace (*c)) /* skip blanks */ c++; if (*c == 0) /* all done? */ do_arg [nargs++] = NULL; /* null argument */ @@ -2638,7 +2638,7 @@ for (nargs = 0; nargs < 10; ) { /* extract arguments */ quote = *c++; else quote = 0; do_arg[nargs++] = c; /* save start */ - while (*c && (quote ? (*c != quote) : !isspace (*c))) + while (*c && (quote ? (*c != quote) : !sim_isspace (*c))) c++; if (*c) /* term at quote/spc */ *c++ = 0; @@ -2867,7 +2867,7 @@ tmnow = localtime(&now); tmpbuf = (char *)malloc(instr_size); op = tmpbuf; oend = tmpbuf + instr_size - 2; -while (isspace (*ip)) /* skip leading spaces */ +while (sim_isspace (*ip)) /* skip leading spaces */ *op++ = *ip++; istart = ip; for (; *ip && (op < oend); ) { @@ -3182,7 +3182,7 @@ if (*cptr == '"') { /* quoted string compari if (!*tptr) return SCPE_2FARG; cptr += strlen (gbuf); - while (isspace (*cptr)) /* skip spaces */ + while (sim_isspace (*cptr)) /* skip spaces */ ++cptr; get_glyph (cptr, op, '"'); for (optr = compare_ops; optr->op; optr++) @@ -3191,7 +3191,7 @@ if (*cptr == '"') { /* quoted string compari if (!optr->op) return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op); cptr += strlen (op); - while (isspace (*cptr)) /* skip spaces */ + while (sim_isspace (*cptr)) /* skip spaces */ ++cptr; cptr = (char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');/* get second string */ if (*cptr) { /* more? */ @@ -3454,7 +3454,7 @@ while (1) { if (*cptr == 0) continue; /* ignore blank */ if (*cptr != ':') continue; /* ignore non-labels */ ++cptr; /* skip : */ - while (isspace (*cptr)) ++cptr; /* skip blanks */ + while (sim_isspace (*cptr)) ++cptr; /* skip blanks */ cptr = get_glyph (cptr, gbuf, 0); /* get label glyph */ if (0 == strcmp(gbuf, gbuf1)) { sim_brk_clract (); /* goto defangs current actions */ @@ -3735,7 +3735,7 @@ else { if (mptr->mstring && (MATCH_CMD (gbuf, mptr->mstring) == 0)) { dptr = sim_dflt_dev; cptr = svptr; - while (isspace(*cptr)) + while (sim_isspace(*cptr)) ++cptr; break; } @@ -4002,7 +4002,7 @@ else { dptr = sim_dflt_dev; lvl = MTAB_VDV; /* device match */ cptr = svptr; - while (isspace(*cptr)) + while (sim_isspace(*cptr)) ++cptr; break; } @@ -4685,7 +4685,7 @@ if (*cptr == '\0') cptr = "./*"; strcpy (WildName, cptr); cptr = WildName; -while (strlen(WildName) && isspace(WildName[strlen(WildName)-1])) +while (strlen(WildName) && sim_isspace(WildName[strlen(WildName)-1])) WildName[strlen(WildName)-1] = '\0'; if ((!stat (WildName, &filestat)) && (filestat.st_mode & S_IFDIR)) strcat (WildName, "/*"); @@ -4697,7 +4697,7 @@ if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../" #endif strcat (WholeName, "/"); strcat (WholeName, cptr); - while (strlen(WholeName) && isspace(WholeName[strlen(WholeName)-1])) + while (strlen(WholeName) && sim_isspace(WholeName[strlen(WholeName)-1])) WholeName[strlen(WholeName)-1] = '\0'; } while ((c = strstr (WholeName, "/./"))) @@ -6814,7 +6814,9 @@ for (tptr = cptr; tptr < (cptr + size); tptr++) { /* remove cr or nl */ break; } } -while (isspace (*cptr)) /* trim leading spc */ +if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3)) /* Skip/ignore UTF8_BOM */ + memmove (cptr, cptr + 3, strlen (cptr + 3)); +while (sim_isspace (*cptr)) /* trim leading spc */ cptr++; if ((*cptr == ';') || (*cptr == '#')) { /* ignore comment */ if (sim_do_echo) /* echo comments if -v */ @@ -6854,7 +6856,7 @@ t_bool escaping = FALSE; char quote_char = 0; while ((*iptr != 0) && - ((quote && quoting) || ((isspace (*iptr) == 0) && (*iptr != mchar)))) { + ((quote && quoting) || ((sim_isspace (*iptr) == 0) && (*iptr != mchar)))) { if (quote) { if (quoting) { if (!escaping) { @@ -6882,7 +6884,7 @@ while ((*iptr != 0) && *optr = 0; if (mchar && (*iptr == mchar)) /* skip terminator */ iptr++; -while (isspace (*iptr)) /* absorb spaces */ +while (sim_isspace (*iptr)) /* absorb spaces */ iptr++; return iptr; } @@ -6915,11 +6917,16 @@ char *sim_trim_endspc (char *cptr) char *tptr; tptr = cptr + strlen (cptr); -while ((--tptr >= cptr) && isspace (*tptr)) +while ((--tptr >= cptr) && sim_isspace (*tptr)) *tptr = 0; return cptr; } +int sim_isspace (char c) +{ +return isspace ((unsigned char)c); +} + /* get_yn yes/no question Inputs: @@ -6963,7 +6970,7 @@ val = strtotv (cptr, &tptr, radix); if ((cptr == tptr) || (val > max)) *status = SCPE_ARG; else { - while (isspace (*tptr)) tptr++; + while (sim_isspace (*tptr)) tptr++; if (*tptr != 0) *status = SCPE_ARG; } @@ -7477,7 +7484,7 @@ int32 sw; if (*cptr != '-') return 0; sw = 0; -for (cptr++; (isspace (*cptr) == 0) && (*cptr != 0); cptr++) { +for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) { if (isalpha (*cptr) == 0) return -1; sw = sw | SWMASK (toupper (*cptr)); @@ -7868,7 +7875,7 @@ uint32 c, digit; *endptr = (char *)inptr; /* assume fails */ if ((radix < 2) || (radix > 36)) return 0; -while (isspace (*inptr)) /* bypass white space */ +while (sim_isspace (*inptr)) /* bypass white space */ inptr++; val = 0; nodigit = 1; @@ -8607,7 +8614,7 @@ size_t lnt; if (sim_brk_act[sim_do_depth] == NULL) /* any action? */ return NULL; -while (isspace (*sim_brk_act[sim_do_depth])) /* skip spaces */ +while (sim_isspace (*sim_brk_act[sim_do_depth])) /* skip spaces */ sim_brk_act[sim_do_depth]++; if (*sim_brk_act[sim_do_depth] == 0) { /* now empty? */ return sim_brk_clract (); @@ -8732,7 +8739,7 @@ if (*cptr == '[') { if ((cptr == c1ptr) || (*c1ptr != ']')) return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n"); cptr = (char *)(c1ptr + 1); - while (isspace(*cptr)) + while (sim_isspace(*cptr)) ++cptr; } tptr = get_glyph (cptr, gbuf, ','); @@ -8920,7 +8927,7 @@ if (ep->act) { /* replace old action? * free (ep->act); /* deallocate */ ep->act = NULL; /* now no action */ } -if (act) while (isspace(*act)) ++act; /* skip leading spaces in action string */ +if (act) while (sim_isspace(*act)) ++act; /* skip leading spaces in action string */ if ((act != NULL) && (*act != 0)) { /* new action? */ char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */ if (newp == NULL) /* mem err? */ @@ -9803,7 +9810,7 @@ for (hblock = astrings; (htext = *hblock) != NULL; hblock++) { const char *start; help_where.line++; - if (isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */ + if (sim_isspace (*htext) || *htext == '+') {/* Topic text, indented topic text */ if (excluded) { /* Excluded topic text */ while (*htext && *htext != '\n') htext++; @@ -9820,7 +9827,7 @@ for (hblock = astrings; (htext = *hblock) != NULL; hblock++) { htext++; } } - while (*htext && *htext != '\n' && isspace (*htext)) + while (*htext && *htext != '\n' && sim_isspace (*htext)) htext++; if (!*htext) /* Empty after removing leading spaces */ break; @@ -9922,7 +9929,7 @@ for (hblock = astrings; (htext = *hblock) != NULL; hblock++) { FAIL (SCPE_ARG, Level not contiguous, htext); /* E.g. 1 3, not reasonable */ } } - while (*htext && (*htext != '\n') && isspace (*htext)) + while (*htext && (*htext != '\n') && sim_isspace (*htext)) htext++; if (!*htext || (*htext == '\n')) { /* Name missing */ FAIL (SCPE_ARG, Missing topic name, htext); diff --git a/scp.h b/scp.h index 9fa05d27..ed559b33 100644 --- a/scp.h +++ b/scp.h @@ -125,6 +125,7 @@ t_stat reset_all_p (uint32 start_device); char *sim_dname (DEVICE *dptr); char *sim_uname (UNIT *dptr); t_stat get_yn (char *ques, t_stat deflt); +int sim_isspace (char c); char *get_sim_opt (int32 opt, char *cptr, t_stat *st); char *get_glyph (const char *iptr, char *optr, char mchar); char *get_glyph_nc (const char *iptr, char *optr, char mchar); From 5f786a0de40849045c6e162dd7463654dd9d0b2d Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 5 Jan 2015 14:08:03 -0800 Subject: [PATCH 29/41] SCP: More allow command files to contain UTF-8 data. - Provide a sim_islower(), sim_isalpha(), sim_isprinit(), sim_isdigit(), sim_isgraph(), sim_isalnum() which make sure that the character being examined as an unsigned char. --- scp.c | 80 ++++++++++++++++++++++++++++++++++++++++------------------- scp.h | 6 +++++ 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/scp.c b/scp.c index 2ab84847..98d8bd9d 100644 --- a/scp.c +++ b/scp.c @@ -2878,7 +2878,7 @@ for (; *ip && (op < oend); ) { } else if ((*ip == '%') && - (isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) { /* sub? */ + (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */ if ((ip[1] >= '0') && (ip[1] <= ('9'))) { /* %n = sub */ ap = do_arg[ip[1] - '0']; for (i=0; iop; optr++) @@ -3191,7 +3191,7 @@ if (*cptr == '"') { /* quoted string compari if (!optr->op) return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op); cptr += strlen (op); - while (sim_isspace (*cptr)) /* skip spaces */ + while (sim_isspace (*cptr)) /* skip spaces */ ++cptr; cptr = (char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');/* get second string */ if (*cptr) { /* more? */ @@ -3317,7 +3317,7 @@ SEND *snd; GET_SWITCHES (cptr); /* get switches */ tptr = get_glyph (cptr, gbuf, ','); -if (isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { +if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_send (gbuf, &snd); if (r != SCPE_OK) return r; @@ -3370,7 +3370,7 @@ t_stat r; SEND *snd; tptr = get_glyph (cptr, gbuf, ','); -if (isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { +if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_send (gbuf, &snd); if (r != SCPE_OK) return r; @@ -3391,7 +3391,7 @@ EXPECT *exp; GET_SWITCHES (cptr); /* get switches */ tptr = get_glyph (cptr, gbuf, ','); -if (isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { +if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_expect (gbuf, &exp); if (r != SCPE_OK) return r; @@ -3412,7 +3412,7 @@ t_stat r; EXPECT *exp; tptr = get_glyph (cptr, gbuf, ','); -if (isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { +if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_expect (gbuf, &exp); if (r != SCPE_OK) return r; @@ -3454,7 +3454,7 @@ while (1) { if (*cptr == 0) continue; /* ignore blank */ if (*cptr != ':') continue; /* ignore non-labels */ ++cptr; /* skip : */ - while (sim_isspace (*cptr)) ++cptr; /* skip blanks */ + while (sim_isspace (*cptr)) ++cptr; /* skip blanks */ cptr = get_glyph (cptr, gbuf, 0); /* get label glyph */ if (0 == strcmp(gbuf, gbuf1)) { sim_brk_clract (); /* goto defangs current actions */ @@ -6816,7 +6816,7 @@ for (tptr = cptr; tptr < (cptr + size); tptr++) { /* remove cr or nl */ } if (0 == memcmp (cptr, "\xEF\xBB\xBF", 3)) /* Skip/ignore UTF8_BOM */ memmove (cptr, cptr + 3, strlen (cptr + 3)); -while (sim_isspace (*cptr)) /* trim leading spc */ +while (sim_isspace (*cptr)) /* trim leading spc */ cptr++; if ((*cptr == ';') || (*cptr == '#')) { /* ignore comment */ if (sim_do_echo) /* echo comments if -v */ @@ -6876,7 +6876,7 @@ while ((*iptr != 0) && } } } - if (islower (*iptr) && uc) + if (sim_islower (*iptr) && uc) *optr = (char)toupper (*iptr); else *optr = *iptr; iptr++; optr++; @@ -6884,7 +6884,7 @@ while ((*iptr != 0) && *optr = 0; if (mchar && (*iptr == mchar)) /* skip terminator */ iptr++; -while (sim_isspace (*iptr)) /* absorb spaces */ +while (sim_isspace (*iptr)) /* absorb spaces */ iptr++; return iptr; } @@ -6927,6 +6927,36 @@ int sim_isspace (char c) return isspace ((unsigned char)c); } +int sim_islower (char c) +{ +return islower ((unsigned char)c); +} + +int sim_isalpha (char c) +{ +return isalpha ((unsigned char)c); +} + +int sim_isprint (char c) +{ +return isprint ((unsigned char)c); +} + +int sim_isdigit (char c) +{ +return isdigit ((unsigned char)c); +} + +int sim_isgraph (char c) +{ +return isgraph ((unsigned char)c); +} + +int sim_isalnum (char c) +{ +return isalnum ((unsigned char)c); +} + /* get_yn yes/no question Inputs: @@ -7237,7 +7267,7 @@ while (size--) { if (quote == *iptr) *tptr++ = '\\'; default: - if (isprint (*iptr)) + if (sim_isprint (*iptr)) *tptr++ = *iptr; else { sprintf (tptr, "\\%03o", *iptr); @@ -7326,7 +7356,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ ((nptr = dptr->lname) && (strncmp (cptr, nptr, strlen (nptr)) == 0)))) { tptr = cptr + strlen (nptr); - if (isdigit (*tptr)) { + if (sim_isdigit (*tptr)) { if (qdisable (dptr)) /* disabled? */ return NULL; u = (uint32) get_uint (tptr, 10, dptr->numunits - 1, &r); @@ -7455,7 +7485,7 @@ if ((cptr == NULL) || (dptr == NULL) || (dptr->registers == NULL)) tptr = cptr; do { tptr++; - } while (isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.')); + } while (sim_isalnum (*tptr) || (*tptr == '*') || (*tptr == '_') || (*tptr == '.')); slnt = tptr - cptr; for (rptr = dptr->registers; rptr->name != NULL; rptr++) { if ((slnt == strlen (rptr->name)) && @@ -7485,7 +7515,7 @@ if (*cptr != '-') return 0; sw = 0; for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) { - if (isalpha (*cptr) == 0) + if (sim_isalpha (*cptr) == 0) return -1; sw = sw | SWMASK (toupper (*cptr)); } @@ -7879,10 +7909,10 @@ while (sim_isspace (*inptr)) /* bypass white spac inptr++; val = 0; nodigit = 1; -for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */ - if (islower (c)) +for (c = *inptr; sim_isalnum(c); c = *++inptr) { /* loop through char */ + if (sim_islower (c)) c = toupper (c); - if (isdigit (c)) /* digit? */ + if (sim_isdigit (c)) /* digit? */ digit = c - (uint32) '0'; else if (radix <= 10) /* stop if not expected */ break; @@ -9227,7 +9257,7 @@ if (snd && (snd->extoff < snd->insoff)) { /* pending input charact *stat = snd->buffer[snd->extoff++] | SCPE_KFLAG;/* get one */ snd->next_time = sim_gtime() + snd->delay; - if (isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' ')) + if (sim_isgraph(*stat & 0xFF) || ((*stat & 0xFF) == ' ')) sprintf (dstr, " '%c'", *stat & 0xFF); sim_debug (snd->dbit, snd->dptr, "Byte value: 0x%02X%s injected\n", *stat & 0xFF, dstr); } @@ -9675,7 +9705,7 @@ if (sim_deb && (dptr->dctrl & reason)) { outbuf[oidx++] = ' '; outbuf[oidx++] = hex[(data[i+sidx]>>4)&0xf]; outbuf[oidx++] = hex[data[i+sidx]&0xf]; - if (isprint (data[i+sidx])) + if (sim_isprint (data[i+sidx])) strbuf[sidx] = data[i+sidx]; else strbuf[sidx] = '.'; @@ -9859,9 +9889,9 @@ for (hblock = astrings; (htext = *hblock) != NULL; hblock++) { appendText (topic, "+", 1); break; default: /* Check for vararg # */ - if (isdigit (*htext)) { + if (sim_isdigit (*htext)) { n = 0; - while (isdigit (*htext)) + while (sim_isdigit (*htext)) n += (n * 10) + (*htext++ - '0'); if (( *htext != 'H' && *htext != 's') || n == 0 || n >= VSMAX) @@ -9908,14 +9938,14 @@ for (hblock = astrings; (htext = *hblock) != NULL; hblock++) { } continue; } /* topic text line */ - if (isdigit (*htext)) { /* Topic heading */ + if (sim_isdigit (*htext)) { /* Topic heading */ TOPIC **children; TOPIC *newt; char nbuf[100]; n = 0; start = htext; - while (isdigit (*htext)) + while (sim_isdigit (*htext)) n += (n * 10) + (*htext++ - '0'); if ((htext == start) || !n) { FAIL (SCPE_ARG, Invalid topic heading, htext); @@ -9944,7 +9974,7 @@ for (hblock = astrings; (htext = *hblock) != NULL; hblock++) { if (*start == '?') { /* Conditional topic? */ size_t n = 0; start++; - while (isdigit (*start)) /* Get param # */ + while (sim_isdigit (*start)) /* Get param # */ n += (n * 10) + (*start++ - '0'); if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) FAIL (SCPE_ARG, Invalid parameter number, start); diff --git a/scp.h b/scp.h index ed559b33..80bfe084 100644 --- a/scp.h +++ b/scp.h @@ -126,6 +126,12 @@ char *sim_dname (DEVICE *dptr); char *sim_uname (UNIT *dptr); t_stat get_yn (char *ques, t_stat deflt); int sim_isspace (char c); +int sim_islower (char c); +int sim_isalpha (char c); +int sim_isprint (char c); +int sim_isdigit (char c); +int sim_isgraph (char c); +int sim_isalnum (char c); char *get_sim_opt (int32 opt, char *cptr, t_stat *st); char *get_glyph (const char *iptr, char *optr, char mchar); char *get_glyph_nc (const char *iptr, char *optr, char mchar); From 184bb3f9049530217d8de71ee8052676b9a803c4 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 5 Jan 2015 16:53:54 -0800 Subject: [PATCH 30/41] SCP: better parsing support for command files which contain UTF-8 data in SEND/EXPECT strings --- scp.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scp.c b/scp.c index 98d8bd9d..ddceaeed 100644 --- a/scp.c +++ b/scp.c @@ -6924,37 +6924,37 @@ return cptr; int sim_isspace (char c) { -return isspace ((unsigned char)c); +return (c & 0x80) ? 0 : isspace (c); } int sim_islower (char c) { -return islower ((unsigned char)c); +return (c & 0x80) ? 0 : islower (c); } int sim_isalpha (char c) { -return isalpha ((unsigned char)c); +return (c & 0x80) ? 0 : isalpha (c); } int sim_isprint (char c) { -return isprint ((unsigned char)c); +return (c & 0x80) ? 0 : isprint (c); } int sim_isdigit (char c) { -return isdigit ((unsigned char)c); +return (c & 0x80) ? 0 : isdigit (c); } int sim_isgraph (char c) { -return isgraph ((unsigned char)c); +return (c & 0x80) ? 0 : isgraph (c); } int sim_isalnum (char c) { -return isalnum ((unsigned char)c); +return (c & 0x80) ? 0 : isalnum (c); } /* get_yn yes/no question @@ -7105,6 +7105,7 @@ uint8 *ostart = optr; *osize = 0; if ((strlen(iptr) == 1) || + (iptr[0] != iptr[strlen(iptr)-1]) || ((iptr[strlen(iptr)-1] != '"') && (iptr[strlen(iptr)-1] != '\''))) return SCPE_ARG; /* String must be quote delimited */ quote_char = *iptr++; /* Save quote character */ @@ -7195,9 +7196,6 @@ return SCPE_OK; Outputs optr = pointer to output buffer - the output buffer must be allocated by the caller - and to avoid overrunat it must be at least as big - as the input string. the output buffer must be freed by the caller The input data will be encoded into a simply printable form. @@ -8912,6 +8910,7 @@ else { free (match_buf); return sim_messagef (SCPE_ARG, "Case independed matching is only valid for RegEx expect rules\n"); } + sim_data_trace(exp->dptr, exp->dptr->units, (uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit); if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) { free (match_buf); return sim_messagef (SCPE_ARG, "Invalid quoted string\n"); @@ -8947,6 +8946,7 @@ if (switches & EXP_TYP_REGEX) { match_buf = NULL; } else { + sim_data_trace(exp->dptr, exp->dptr->units, (uint8 *)match, "", strlen(match)+1, "Expect Match String", exp->dbit); sim_decode_quoted_string (match, match_buf, &match_size); ep->match = match_buf; ep->size = match_size; From 5d9aee0d145b1765663ebf40c36294073b6fd7b0 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 06:31:05 -0800 Subject: [PATCH 31/41] SCP: EXPECT debug fix to avoid invalid memory reference if a expect structure doesn have a device pointer. Corrected comments. From Mark Emmer. --- scp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scp.c b/scp.c index ddceaeed..9f60071c 100644 --- a/scp.c +++ b/scp.c @@ -8713,7 +8713,7 @@ return; breakpoint package. Expect rules are stored in tables associated with each port which can use this - facility. An expect rule consists of a four entry structure: + facility. An expect rule consists of a five entry structure: match the expect match string size the number of bytes in the match string @@ -8721,11 +8721,11 @@ return; cnt number of iterations before match is declared action command string to be executed when match occurs - An expect rule is contained in an expect match context structure. + All active expect rules are contained in an expect match context structure. rules the match rules size the count of match rules - buf the buffer of output data which has produced + buf the buffer of output data which has been produced buf_ins the buffer insertion point for the next output data buf_size the buffer size @@ -8829,9 +8829,9 @@ free (ep->act); /* deallocate action */ if (ep->switches & EXP_TYP_REGEX) regfree (&ep->regex); /* release compiled regex */ #endif +exp->size -= 1; /* decrement count */ for (i=ep-exp->rules; isize; i++) /* shuffle up remaining rules */ exp->rules[i] = exp->rules[i+1]; -exp->size -= 1; /* decrement count */ if (exp->size == 0) { /* No rules left? */ free (exp->rules); exp->rules = NULL; @@ -9070,7 +9070,7 @@ for (i=0; i < exp->size; i++) { } ++regex_checks; matches = calloc ((ep->regex.re_nsub + 1), sizeof(*matches)); - if (sim_deb && (exp->dptr->dctrl & exp->dbit)) { + if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins); sim_debug (exp->dbit, exp->dptr, "Checking String: %s\n", estr); sim_debug (exp->dbit, exp->dptr, "Against RegEx Match Rule: %s\n", ep->match_pattern); @@ -9105,7 +9105,7 @@ for (i=0; i < exp->size; i++) { } else { if (exp->buf_ins < ep->size) { - if (sim_deb && (exp->dptr->dctrl & exp->dbit)) { + if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins); char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins); @@ -9116,7 +9116,7 @@ for (i=0; i < exp->size; i++) { } if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins)) continue; - if (sim_deb && (exp->dptr->dctrl & exp->dbit)) { + if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins); char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins); @@ -9130,7 +9130,7 @@ for (i=0; i < exp->size; i++) { break; } else { - if (sim_deb && (exp->dptr->dctrl & exp->dbit)) { + if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size); char *mstr = sim_encode_quoted_string (ep->match, ep->size); @@ -9177,7 +9177,7 @@ if (i != exp->size) { /* Found? */ sim_debug (exp->dbit, exp->dptr, "No actions specified, stopping...\n"); } sim_brk_setact (ep->act); /* set up actions */ - if (ep->switches & EXP_TYP_CLEARALL) /* One shot expect rule? */ + if (ep->switches & EXP_TYP_CLEARALL) /* Clear-all expect rule? */ sim_exp_clrall (exp); /* delete all rules */ else { if (!(ep->switches & EXP_TYP_PERSIST)) /* One shot expect rule? */ From 7ab9f020bdb85c326d8db10f55afec203b125140 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 08:24:44 -0800 Subject: [PATCH 32/41] TMXR: Add default debug bits for SEND/EXPECT operations --- sim_tmxr.c | 9 +++++++++ sim_tmxr.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/sim_tmxr.c b/sim_tmxr.c index 0801991c..096937f6 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -3289,6 +3289,7 @@ return SCPE_OK; t_stat tmxr_attach_ex (TMXR *mp, UNIT *uptr, char *cptr, t_bool async) { t_stat r; +int32 i; r = tmxr_open_master (mp, cptr); /* open master socket */ if (r != SCPE_OK) /* error? */ @@ -3312,6 +3313,14 @@ uptr->dynflags |= TMUF_NOASYNCH; /* tag as no asynch */ if (mp->dptr == NULL) /* has device been set? */ mp->dptr = find_dev_from_unit (uptr); /* no, so set device now */ +if (mp->dptr) { + for (i=0; ilines; i++) { + mp->ldsc[i].expect.dptr = mp->dptr; + mp->ldsc[i].expect.dbit = TMXR_DBG_EXP; + mp->ldsc[i].send.dptr = mp->dptr; + mp->ldsc[i].send.dbit = TMXR_DBG_SEND; + } + } tmxr_add_to_open_list (mp); return SCPE_OK; } diff --git a/sim_tmxr.h b/sim_tmxr.h index 46c3e002..f0f56d71 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -75,6 +75,8 @@ typedef int SERHANDLE; #define TMXR_DBG_TRC 0x0400000 /* Debug trace routine calls */ #define TMXR_DBG_PXMT 0x0800000 /* Debug Transmit Packet Data */ #define TMXR_DBG_PRCV 0x1000000 /* Debug Received Packet Data */ +#define TMXR_DBG_EXP 0x2000000 /* Debug Expect Activities */ +#define TMXR_DBG_SEND 0x4000000 /* Debug Send Activities */ /* Modem Control Bits */ From 91f465d7807ea7030ab7fe2c21c1a21815dc6d77 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 08:27:03 -0800 Subject: [PATCH 33/41] SCP: Add info displayed in SHOW EXPECT and SHOW SEND to advise how SEND & EXPECT debugging is enabled --- scp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scp.c b/scp.c index 9f60071c..bbd04dc4 100644 --- a/scp.c +++ b/scp.c @@ -399,7 +399,7 @@ void sim_brk_npc (uint32 cnt); BRKTAB *sim_brk_new (t_addr loc); FILE *stdnul; -/* Commands support routines */ +/* Command support routines */ SCHTAB *get_rsearch (const char *cptr, int32 radix, SCHTAB *schptr); SCHTAB *get_asearch (const char *cptr, int32 radix, SCHTAB *schptr); @@ -453,6 +453,8 @@ void int_handler (int signal); t_stat set_prompt (int32 flag, char *cptr); t_stat sim_set_asynch (int32 flag, char *cptr); t_stat sim_set_environment (int32 flag, char *cptr); +static char *get_dbg_verb (uint32 dbits, DEVICE* dptr); + /* Global data */ DEVICE *sim_dflt_dev = NULL; @@ -3912,7 +3914,7 @@ DEBTAB *dep; if ((dptr->flags & DEV_DEBUG) == 0) return SCPE_NOFNC; if (cptr == NULL) { /* no arguments? */ - dptr->dctrl = flag; /* disable/enable w/o table */ + dptr->dctrl = flag ? (dptr->debflags ? flag : 0xFFFFFFFF) : 0;/* disable/enable w/o table */ if (flag && dptr->debflags) { /* enable with table? */ for (dep = dptr->debflags; dep->name != NULL; dep++) dptr->dctrl = dptr->dctrl | dep->mask; /* set all */ @@ -9014,6 +9016,8 @@ if (exp->buf_size) { } if (exp->after) fprintf (st, "Halt After: %d instructions\n", exp->after); +if (exp->dptr && exp->dbit) + fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(exp->dptr), exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : ""); if (!*match) return sim_exp_showall (st, exp); if (!ep) @@ -9240,6 +9244,8 @@ else if ((snd->next_time - sim_gtime()) > 0) fprintf (st, "Minimum of %d instructions befor sending first character\n", (int)(snd->next_time - sim_gtime())); fprintf (st, "Minimum of %d instructions between characters\n", (int)snd->delay); +if (snd->dptr && snd->dbit) + fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(snd->dptr), snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : ""); return SCPE_OK; } @@ -9316,10 +9322,10 @@ int32 debug_unterm = 0; /* Finds debug phrase matching bitmask from from device DEBTAB table */ -static char* get_dbg_verb (uint32 dbits, DEVICE* dptr) +static char *get_dbg_verb (uint32 dbits, DEVICE* dptr) { -static char* debtab_none = "DEBTAB_ISNULL"; -static char* debtab_nomatch = "DEBTAB_NOMATCH"; +static char *debtab_none = "DEBTAB_ISNULL"; +static char *debtab_nomatch = "DEBTAB_NOMATCH"; int32 offset = 0; if (dptr->debflags == 0) From e84c798d1cfa91e1ae6a77c46f410318be039d27 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 11:25:55 -0800 Subject: [PATCH 34/41] SCP: Fix EXPECT matching logic for non-regex strings to have enough room to buffer all of potential match data plus a NUL byte. --- scp.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/scp.c b/scp.c index bbd04dc4..6eac8056 100644 --- a/scp.c +++ b/scp.c @@ -1983,7 +1983,7 @@ while (stat != SCPE_EXIT) { /* in case exit */ sim_sub_args (cbuf, sizeof(cbuf), argv); if (sim_log) /* log cmd */ fprintf (sim_log, "%s%s\n", sim_prompt, cptr); - if (sim_deb && (sim_deb != sim_log)) + if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout)) fprintf (sim_deb, "%s%s\n", sim_prompt, cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ @@ -8967,12 +8967,12 @@ if ((act != NULL) && (*act != 0)) { /* new action? */ strcpy (newp, act); /* copy action */ ep->act = newp; /* set pointer */ } -/* Make sure that the production buffer is large enough to detect a match for all rules */ +/* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */ for (i=0; isize; i++) { uint32 compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size; - if (compare_size > exp->buf_size) { - exp->buf = (uint8 *)realloc (exp->buf, compare_size+1); /* Extra byte to null terminate regex compares */ - exp->buf_size = compare_size; + if (compare_size >= exp->buf_size) { + exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */ + exp->buf_size = compare_size + 1; } } return SCPE_OK; @@ -9108,23 +9108,29 @@ for (i=0; i < exp->size; i++) { #endif } else { - if (exp->buf_ins < ep->size) { - if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { - char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins); - char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins); + if (exp->buf_ins < ep->size) { /* Match stradle end of buffer */ + /* + * First compare the newly deposited data at the beginning + * of buffer with the end of the match string + */ + if (exp->buf_ins) { + if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { + char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins); + char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins); - sim_debug (exp->dbit, exp->dptr, "Checking String: %s\n", estr); - sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); - free (estr); - free (mstr); + sim_debug (exp->dbit, exp->dptr, "Checking String[0:%d]: %s\n", exp->buf_ins, estr); + sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); + free (estr); + free (mstr); + } + if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins)) + continue; } - if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins)) - continue; if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins); char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins); - sim_debug (exp->dbit, exp->dptr, "Checking String: %s\n", estr); + sim_debug (exp->dbit, exp->dptr, "Checking String[%d:%d]: %s\n", exp->buf_size-(ep->size-exp->buf_ins), ep->size-exp->buf_ins, estr); sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); free (estr); free (mstr); @@ -9138,7 +9144,7 @@ for (i=0; i < exp->size; i++) { char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size); char *mstr = sim_encode_quoted_string (ep->match, ep->size); - sim_debug (exp->dbit, exp->dptr, "Checking String: %s\n", estr); + sim_debug (exp->dbit, exp->dptr, "Checking String[%d:%d]: %s\n", exp->buf_ins-ep->size, ep->size, estr); sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); free (estr); free (mstr); From 5fd8b63cf4117aa39d40e53d4dc37191f8c8f268 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 12:44:24 -0800 Subject: [PATCH 35/41] SCP: Fix debug setup info displayed by SHOW SEND and SHOW EXPECT --- scp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scp.c b/scp.c index 6eac8056..e2261b32 100644 --- a/scp.c +++ b/scp.c @@ -9017,7 +9017,7 @@ if (exp->buf_size) { if (exp->after) fprintf (st, "Halt After: %d instructions\n", exp->after); if (exp->dptr && exp->dbit) - fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(exp->dptr), exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : ""); + fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "", exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : ""); if (!*match) return sim_exp_showall (st, exp); if (!ep) @@ -9251,7 +9251,7 @@ if ((snd->next_time - sim_gtime()) > 0) fprintf (st, "Minimum of %d instructions befor sending first character\n", (int)(snd->next_time - sim_gtime())); fprintf (st, "Minimum of %d instructions between characters\n", (int)snd->delay); if (snd->dptr && snd->dbit) - fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(snd->dptr), snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : ""); + fprintf (st, "Debugging via: SET %s DEBUG%s%s\n", sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "", snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : ""); return SCPE_OK; } From 0f1e2333668d1c6aea61ebddf29c4c83ee90e345 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 6 Jan 2015 19:20:36 -0800 Subject: [PATCH 36/41] BESM6: Cleanup for build on OS X, --- BESM6/besm6_tty.c | 2 +- makefile | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 44ca5591..bc1a9850 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -443,7 +443,7 @@ void vt_putc (int num, int c) /* * Sending a string to a terminal with the given number. */ -void vt_puts (int num, const unsigned char *s) +void vt_puts (int num, const char *s) { TMLN *t = &tty_line [num]; diff --git a/makefile b/makefile index 19465914..0b07b7b3 100644 --- a/makefile +++ b/makefile @@ -68,7 +68,7 @@ ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS VIDEO_USEFUL = true DISPLAY_USEFUL = true endif -else ifeq ($(MAKECMDGOALS),besm6) +else ifneq (,$(findstring besm6,$(MAKECMDGOALS))) VIDEO_USEFUL = true else ifeq ($(MAKECMDGOALS),) @@ -300,8 +300,8 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif $(info lib paths are: $(LIBPATH)) $(info include paths are: $(INCPATH)) - find_lib = $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))) - find_include = $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h)))) + find_lib = $(abspath $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT)))))) + find_include = $(abspath $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h))))) need_search = $(strip $(shell ld -l$(1) /dev/null 2>&1 | grep $(1) | sed s/$(1)//)) LD_SEARCH_NEEDED := $(call need_search,ZzzzzzzZ) ifneq (,$(call find_lib,m)) @@ -1173,17 +1173,19 @@ BESM6 = ${BESM6D}/besm6_cpu.c ${BESM6D}/besm6_sys.c ${BESM6D}/besm6_mmu.c \ ifneq (,${VIDEO_LDFLAGS}) ifeq (,${FONTFILE}) - FONTPATH += /usr/share/fonts /usr/share/fonts/truetype /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions + FONTPATH += /usr/share/fonts /Library/Fonts /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions + FONTPATH := $(dir $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/.))) FONTNAME += LucidaSansRegular.ttf FreeSans.ttf $(info font paths are: $(FONTPATH)) $(info font names are: $(FONTNAME)) find_fontfile = $(strip $(firstword $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/$(1))$(wildcard $(dir)/*/$(1))$(wildcard $(dir)/*/*/$(1))$(wildcard $(dir)/*/*/*/$(1))))) - find_font = $(strip $(firstword $(foreach font,$(strip $(FONTNAME)),$(call find_fontfile,$(font))))) + find_font = $(abspath $(strip $(firstword $(foreach font,$(strip $(FONTNAME)),$(call find_fontfile,$(font)))))) ifneq (,$(call find_font)) FONTFILE=$(call find_font) else $(info ***) - $(info *** BESM-6 video panel disabled.) + $(info *** No font file available, BESM-6 video panel disabled.) + $(info ***) $(info *** To enable the panel display please specify one of:) $(info *** a font path with FONTNAME=path) $(info *** a font name with FONTNAME=fontname.ttf) From d6d13a8c0891ec2259e9339c79a859be9cfb3cc3 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Wed, 7 Jan 2015 02:03:32 -0800 Subject: [PATCH 37/41] BESM6: Output to Baudot TTYs works; fixed attaching of disks without -e; added DejaVu font option. --- BESM6/besm6_cpu.c | 10 ++++++++++ BESM6/besm6_defs.h | 1 + BESM6/besm6_disk.c | 4 +++- BESM6/besm6_tty.c | 8 -------- makefile | 2 +- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 841b20d2..5f60bbd4 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -1694,8 +1694,10 @@ t_stat sim_instr (void) t_stat fast_clk (UNIT * this) { static unsigned counter; + static unsigned tty_counter; ++counter; + ++tty_counter; /*besm6_debug ("*** таймер 20 мсек");*/ GRP |= GRP_TIMER; @@ -1713,6 +1715,14 @@ t_stat fast_clk (UNIT * this) redraw_panel = 1; } + /* Baudot TTYs are synchronised to the main timer rather than the + * serial line clock. Their baud rate is 50. + */ + if (tty_counter == CLK_TPS/50) { + tt_print(); + tty_counter = 0; + } + tmr_poll = sim_rtcn_calb (CLK_TPS, 0); /* calibrate clock */ return sim_activate_after (this, 1000000/CLK_TPS); /* reactivate unit */ } diff --git a/BESM6/besm6_defs.h b/BESM6/besm6_defs.h index 385a0130..52b4ecf2 100644 --- a/BESM6/besm6_defs.h +++ b/BESM6/besm6_defs.h @@ -334,6 +334,7 @@ void printer_hammer (int num, int pos, uint32 mask); void tty_send (uint32 mask); int tty_query (void); void vt_print (void); +void tt_print (void); void vt_receive (void); void consul_print (int num, uint32 cmd); uint32 consul_read (int num); diff --git a/BESM6/besm6_disk.c b/BESM6/besm6_disk.c index 3bb713c6..062a0f07 100644 --- a/BESM6/besm6_disk.c +++ b/BESM6/besm6_disk.c @@ -213,7 +213,9 @@ t_stat disk_attach (UNIT *u, char *cptr) } return SCPE_OK; } - if (saved_switches & SWMASK ('E')) + if (s == SCPE_OK || + (saved_switches & SWMASK ('E')) || + (sim_switches & SWMASK('N'))) return s; sim_switches |= SWMASK ('N'); } diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index bc1a9850..515b3452 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -184,8 +184,6 @@ t_stat vt_clk (UNIT * this) { int num; - /* Baudot TTYs work at 10 baud */ - static int clk_divider = 1<<29; GRP |= MGRP & GRP_SERIAL; /* Polling receiving from sockets */ @@ -195,12 +193,6 @@ t_stat vt_clk (UNIT * this) vt_receive(); consul_receive(); - if (! (clk_divider >>= 1)) { - tt_print(); - /* Input from Baudot TTYs not implemented */ - clk_divider = 1<<29; - } - /* Are there any new network connections? */ num = tmxr_poll_conn (&tty_desc); if (num > 0 && num <= LINES_MAX) { diff --git a/makefile b/makefile index 0b07b7b3..56c3a440 100644 --- a/makefile +++ b/makefile @@ -1175,7 +1175,7 @@ ifneq (,${VIDEO_LDFLAGS}) ifeq (,${FONTFILE}) FONTPATH += /usr/share/fonts /Library/Fonts /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions FONTPATH := $(dir $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/.))) - FONTNAME += LucidaSansRegular.ttf FreeSans.ttf + FONTNAME += DejaVuSans.ttf LucidaSansRegular.ttf FreeSans.ttf $(info font paths are: $(FONTPATH)) $(info font names are: $(FONTNAME)) find_fontfile = $(strip $(firstword $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/$(1))$(wildcard $(dir)/*/$(1))$(wildcard $(dir)/*/*/$(1))$(wildcard $(dir)/*/*/*/$(1))))) From 8dea6828fe16058f828379e85fc1450cdede3936 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Wed, 7 Jan 2015 02:34:27 -0800 Subject: [PATCH 38/41] BESM6: All arguments of "attach tty" but the magic word "console" are passed to tmxr_attach(). BESM6: Fix windows compile to support "console" besm6_tty attach . --- BESM6/besm6_tty.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index 515b3452..c3ddefd9 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -303,9 +303,14 @@ t_stat tty_setmode (UNIT *u, int32 val, char *cptr, void *desc) t_stat tty_attach (UNIT *u, char *cptr) { int num = u - tty_unit; + char gbuf[CBUFSIZE]; int r, m, n; - if (*cptr >= '0' && *cptr <= '9') { + /* All arguments but the magic word "console" are passed + * to tmxr_attach(). + */ + get_glyph (cptr, gbuf, 0); + if (strcmp (gbuf, "CONSOLE")) { /* Saving and restoring all .conn, * because tmxr_attach() zeroes them. */ for (m=0, n=1; n<=LINES_MAX; ++n) @@ -317,9 +322,7 @@ t_stat tty_attach (UNIT *u, char *cptr) if (m >> (LINES_MAX-n) & 1) tty_line[n].conn = 1; return r; - } - - if (strcmp (cptr, "console") == 0) { + } else { /* Attaching SIMH console to a particular terminal. */ u->flags &= ~TTY_STATE_MASK; u->flags |= TTY_VT340_STATE; @@ -331,7 +334,7 @@ t_stat tty_attach (UNIT *u, char *cptr) return 0; } /* Disallowing future connections to a line */ - if (strcmp (cptr, "none") == 0) { + if (strcmp (gbuf, "NONE") == 0) { /* Marking the TTY as unusable. */ tty_line[num].conn = 1; tty_line[num].rcve = 0; From 178794729946fe7e82a7bfce6c7453d86d1cc4be Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Wed, 7 Jan 2015 20:58:06 -0800 Subject: [PATCH 39/41] BESM6: Translated comments in besm6_panel.c --- BESM6/besm6_panel.c | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/BESM6/besm6_panel.c b/BESM6/besm6_panel.c index 66cc7fcf..c080a860 100644 --- a/BESM6/besm6_panel.c +++ b/BESM6/besm6_panel.c @@ -79,9 +79,9 @@ static const int regnum[] = { static SDL_Surface *screen; /* - * Рисование текста в кодировке UTF-8, с антиалиасингом. - * Параметр halign задаёт выравнивание по горизонтали. - * Цвета заданы глобальными переменными foreground и background. + * Drawing antialiased text in UTF-8 encoding. + * The halign parameter controls horizontal alignment. + * Foreground/background colors are taken from global variables. */ static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message) { @@ -134,7 +134,7 @@ static SDL_Surface *sprite_from_data (int width, int height, } /* - * Рисуем неонку. + * Drawing a neon light. */ static void draw_lamp (int left, int top, int on) { @@ -189,7 +189,7 @@ static void draw_lamp (int left, int top, int on) } /* - * Отрисовка лампочек БРЗ. + * Drawing index (modifier) registers. They form two groups. */ static void draw_modifiers_periodic (int group, int left, int top) { @@ -208,7 +208,7 @@ static void draw_modifiers_periodic (int group, int left, int top) } /* - * Отрисовка лампочек ГРП и МГРП. + * Drawing the main interrupt register and its mask. */ static void draw_grp_periodic (int top) { @@ -227,7 +227,7 @@ static void draw_grp_periodic (int top) } /* - * Отрисовка лампочек БРЗ. + * Drawing the data cache registers. */ static void draw_brz_periodic (int top) { @@ -246,7 +246,7 @@ static void draw_brz_periodic (int top) } /* - * Отрисовка статичной части регистров-модификаторов. + * Drawing the static part of the modifier register area. */ static void draw_modifiers_static (int group, int left, int top) { @@ -257,7 +257,7 @@ static void draw_modifiers_static (int group, int left, int top) background = black; foreground = cyan; - /* Оттеняем группы разрядов. */ + /* Visually separating groups of bits */ color = grey.r << 16 | grey.g << 8 | grey.b; for (x=3; x<15; x+=3) { area.x = left + 74 + x*STEPX; @@ -266,14 +266,14 @@ static void draw_modifiers_static (int group, int left, int top) area.h = 8*STEPY + 2; SDL_FillRect (screen, &area, color); } - /* Названия регистров. */ + /* Register names */ for (y=0; y<8; ++y) { reg = regnum [y + group*8]; sprintf (message, "М%2o", reg); render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message); old_M [reg] = ~0; } - /* Номера битов. */ + /* Bit numbers */ for (x=0; x<15; ++x) { sprintf (message, "%d", 15-x); render_utf8 (font_small, left+82 + x*STEPX, @@ -282,7 +282,7 @@ static void draw_modifiers_static (int group, int left, int top) } /* - * Отрисовка статичной части регистров ГРП и МГРП. + * Drawing the static part of the interrupt register area. */ static void draw_grp_static (int top) { @@ -293,7 +293,7 @@ static void draw_grp_static (int top) background = black; foreground = cyan; - /* Оттеняем группы разрядов. */ + /* Visually separating groups of bits */ color = grey.r << 16 | grey.g << 8 | grey.b; for (x=3; x<48; x+=3) { area.x = 98 + x*STEPX; @@ -302,12 +302,12 @@ static void draw_grp_static (int top) area.h = 2*STEPY + 2; SDL_FillRect (screen, &area, color); } - /* Названия регистров. */ + /* Register names */ for (y=0; y<2; ++y) { render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП"); old_GRP[y] = ~0; } - /* Номера битов. */ + /* Bit numbers */ for (x=0; x<48; ++x) { sprintf (message, "%d", 48-x); render_utf8 (font_small, 106 + x*STEPX, @@ -316,7 +316,7 @@ static void draw_grp_static (int top) } /* - * Отрисовка статичной части регистров БРЗ. + * Drawing the static part of the cache register area */ static void draw_brz_static (int top) { @@ -327,7 +327,7 @@ static void draw_brz_static (int top) background = black; foreground = cyan; - /* Оттеняем группы разрядов. */ + /* Visually separating groups of bits */ color = grey.r << 16 | grey.g << 8 | grey.b; for (x=3; x<48; x+=3) { area.x = 98 + x*STEPX; @@ -336,7 +336,7 @@ static void draw_brz_static (int top) area.h = 8*STEPY + 2; SDL_FillRect (screen, &area, color); } - /* Названия регистров. */ + /* Register names */ for (y=7; y>=0; --y) { sprintf (message, "БРЗ %d", 7-y); render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message); @@ -345,7 +345,7 @@ static void draw_brz_static (int top) } /* - * Закрываем графическое окно. + * Closing the graphical window. */ void besm6_close_panel (void) { @@ -364,7 +364,7 @@ static SDL_Texture *sdlTexture; /* - * Начальная инициализация графического окна и шрифтов. + * Initializing of the graphical window and the fonts. */ static void init_panel (void) { @@ -422,7 +422,7 @@ static void init_panel (void) SDL_TEXTUREACCESS_STATIC, WIDTH, HEIGHT); - /* Отрисовка статичной части панели БЭСМ-6. */ + /* Drawing the static part of the BESM-6 panel */ draw_modifiers_static (0, 24, 10); draw_modifiers_static (1, 400, 10); draw_grp_static (180); @@ -438,7 +438,7 @@ static void init_panel (void) void (*sim_vm_init)() = init_panel; /* - * Обновляем графическое окно. + * Refreshing the window. */ void besm6_draw_panel (void) { @@ -447,7 +447,7 @@ void besm6_draw_panel (void) if (! screen) return; - /* Периодическая отрисовка: мигание лампочек. */ + /* Do the blinkenlights */ draw_modifiers_periodic (0, 24, 10); draw_modifiers_periodic (1, 400, 10); draw_grp_periodic (180); @@ -467,7 +467,7 @@ void besm6_draw_panel (void) #else /* - * Начальная инициализация графического окна и шрифтов. + * Initializing of the graphical window and the fonts. */ static void init_panel (void) { @@ -506,7 +506,7 @@ static void init_panel (void) } atexit (besm6_close_panel); - /* Отрисовка статичной части панели БЭСМ-6. */ + /* Drawing the static part of the BESM-6 panel */ draw_modifiers_static (0, 24, 10); draw_modifiers_static (1, 400, 10); draw_grp_static (180); @@ -519,14 +519,14 @@ static void init_panel (void) void (*sim_vm_init)() = init_panel; /* - * Обновляем графическое окно. + * Refreshing the window */ void besm6_draw_panel () { if (! screen) return; - /* Периодическая отрисовка: мигание лампочек. */ + /* Do the blinkenlights */ draw_modifiers_periodic (0, 24, 10); draw_modifiers_periodic (1, 400, 10); draw_grp_periodic (180); From 3ac8c82951e0a53443eb99096622e32eeccdc091 Mon Sep 17 00:00:00 2001 From: Leo Broukhis Date: Thu, 8 Jan 2015 01:43:35 -0800 Subject: [PATCH 40/41] BESM6: Implemented SET CPU REQ, added an example of a batch task run. --- BESM6/besm6_cpu.c | 13 +++++++++++- BESM6/besm6_tty.c | 28 ++++++++++++------------- BESM6/expect.ini | 30 +++++++++++++++++++++++++++ BESM6/input.txt | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 15 deletions(-) create mode 100755 BESM6/expect.ini create mode 100644 BESM6/input.txt diff --git a/BESM6/besm6_cpu.c b/BESM6/besm6_cpu.c index 5f60bbd4..75d13947 100644 --- a/BESM6/besm6_cpu.c +++ b/BESM6/besm6_cpu.c @@ -80,6 +80,7 @@ jmp_buf cpu_halt; t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_deposit (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_req (UNIT *u, int32 val, char *cptr, void *desc); /* * CPU data structures @@ -131,7 +132,8 @@ REG cpu_reg[] = { MTAB cpu_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle, NULL, "Display idle detection mode" }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL, "Disables idle detection" }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL, "Disables idle detection" }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "REQ", &cpu_req, NULL, NULL, "Sends a request interrupt" }, { 0 } }; @@ -342,6 +344,15 @@ t_stat cpu_reset (DEVICE *dptr) return SCPE_OK; } +/* + * Request routine + */ +t_stat cpu_req (UNIT *u, int32 val, char *cptr, void *desc) +{ + GRP |= GRP_PANEL_REQ; + return SCPE_OK; +} + /* * Write Unicode symbol to file. * Convert to UTF-8 encoding: diff --git a/BESM6/besm6_tty.c b/BESM6/besm6_tty.c index c3ddefd9..418f257b 100644 --- a/BESM6/besm6_tty.c +++ b/BESM6/besm6_tty.c @@ -306,10 +306,22 @@ t_stat tty_attach (UNIT *u, char *cptr) char gbuf[CBUFSIZE]; int r, m, n; - /* All arguments but the magic word "console" are passed + /* All arguments but the magic words "console" and "none" are passed * to tmxr_attach(). */ get_glyph (cptr, gbuf, 0); + /* Disallowing future connections to a line */ + if (strcmp (gbuf, "NONE") == 0) { + /* Marking the TTY as unusable. */ + tty_line[num].conn = 1; + tty_line[num].rcve = 0; + if (num <= TTY_MAX) { + vt_mask &= ~(1 << (TTY_MAX - num)); + tt_mask &= ~(1 << (TTY_MAX - num)); + } + besm6_debug ("*** turning off T%03o", num); + return SCPE_OK; + } if (strcmp (gbuf, "CONSOLE")) { /* Saving and restoring all .conn, * because tmxr_attach() zeroes them. */ @@ -331,19 +343,7 @@ t_stat tty_attach (UNIT *u, char *cptr) if (num <= TTY_MAX) vt_mask |= 1 << (TTY_MAX - num); besm6_debug ("*** console on T%03o", num); - return 0; - } - /* Disallowing future connections to a line */ - if (strcmp (gbuf, "NONE") == 0) { - /* Marking the TTY as unusable. */ - tty_line[num].conn = 1; - tty_line[num].rcve = 0; - if (num <= TTY_MAX) { - vt_mask &= ~(1 << (TTY_MAX - num)); - tt_mask &= ~(1 << (TTY_MAX - num)); - } - besm6_debug ("*** turning off T%03o", num); - return 0; + return SCPE_OK; } return SCPE_ALATT; } diff --git a/BESM6/expect.ini b/BESM6/expect.ini new file mode 100755 index 00000000..368ba9cb --- /dev/null +++ b/BESM6/expect.ini @@ -0,0 +1,30 @@ +# Attaching the input device +at fs0 input.txt +# Waiting for the end of initial setup +expect -r "ДATA.*\n" +do dispak.ini +# Now we're ready to send commands from the front panel +echo Requesting input from the punch tape reader (FS8) +d 6 1 +d 5 10 +set cpu req +expect -r "Л0.*\n" +go + +# The process had been started, check state every 10 model seconds +send after=1000000 "WCPP\r" +expect -p -r "4199.*\n" send after=10000000 "WCPP\r"; go +expect -c "HET\r\n" step 10000 +go +echo Enabling the printer (ONL A0) +d 6 10 +d 5 1 +set cpu req +expect -r "ECT.*\n" +go +echo Checking for the printing to finish +send "HOMB\r" +expect -p -r "4199.*\n" send "HOMB\r"; go +expect -c "HET\r\n" +go +echo Done diff --git a/BESM6/input.txt b/BESM6/input.txt new file mode 100644 index 00000000..708c9a92 --- /dev/null +++ b/BESM6/input.txt @@ -0,0 +1,53 @@ +ШИФР 419999 ЗС5^ +EEВ1А3 + *NAME PRIME NUMBERS +* The ^L char before *NAME is important +* NO LIST Disable source listing by removing spaces between * and NO +*NO LOAD LIST Enable loader listing by adding 5 spaces between * and NO +* Disabling fanfold page alignment +*CALL NOTLIS +*ASSEM + ETIME: ,NAME, +c Get time of day in jiffies + ,*53 , 010B +c OR the integer exponent + ,AOX , =6400000000000000 +c F.p. divide by 50 + ,A/X , =R50.0 +c Return + 13 ,UJ , + ,END , +*FTN + PROGRAM MAIN + PRINT 1000 +1000 FORMAT(' Computing prime numbers the dumb way') + TIME0 = ETIME(0) + CALL PRIMES + TIME1 = ETIME(0) + NTIME = TIME1 - TIME0 + PRINT 2000, NTIME + STOP +2000 FORMAT (' Time, seconds =', i6) + end + + SUBROUTINE PRIMES + T=0 + DO 10 N=1001, 100000, 2 + MAXK=SQRT(N+0.0)+1 + DO 20 K=3, MAXK, 2 + M = (N / K) * K + IF (N .EQ. M) GOTO 10 +20 CONTINUE +c------ Printing every 1000th prime number + T=T+1 + IF (T .LT. 1000) GOTO 10 + PRINT 1000, N + T=0 +10 CONTINUE + RETURN +1000 FORMAT (1X, I9) + END +*EXECUTE +* The ^L char after *END FILE is important +*END FILE + ЕКОНЕЦ From f572f255772f289405d6c697d1d19f6876ebac6d Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 8 Jan 2015 06:21:11 -0800 Subject: [PATCH 41/41] BESM6: Add AppleGothic.ttf as a font for the panel which is generally found on OS X. --- makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 56c3a440..03bce142 100644 --- a/makefile +++ b/makefile @@ -1175,7 +1175,7 @@ ifneq (,${VIDEO_LDFLAGS}) ifeq (,${FONTFILE}) FONTPATH += /usr/share/fonts /Library/Fonts /usr/lib/jvm /System/Library/Frameworks/JavaVM.framework/Versions FONTPATH := $(dir $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/.))) - FONTNAME += DejaVuSans.ttf LucidaSansRegular.ttf FreeSans.ttf + FONTNAME += DejaVuSans.ttf LucidaSansRegular.ttf FreeSans.ttf AppleGothic.ttf $(info font paths are: $(FONTPATH)) $(info font names are: $(FONTNAME)) find_fontfile = $(strip $(firstword $(foreach dir,$(strip $(FONTPATH)),$(wildcard $(dir)/$(1))$(wildcard $(dir)/*/$(1))$(wildcard $(dir)/*/*/$(1))$(wildcard $(dir)/*/*/*/$(1))))) @@ -1198,9 +1198,11 @@ ifeq (,$(and ${VIDEO_LDFLAGS}, ${FONTFILE})) BESM6_OPT = -I ${BESM6D} -DUSE_INT64 else ifneq (,$(and $(findstring SDL2,${VIDEO_LDFLAGS}),$(call find_include,SDL2/SDL_ttf),$(call find_lib,SDL2_ttf))) $(info using libSDL2_ttf: $(call find_lib,SDL2_ttf) $(call find_include,SDL2/SDL_ttf)) + $(info ***) BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf else ifneq (,$(and $(call find_include,SDL/SDL_ttf),$(call find_lib,SDL_ttf))) $(info using libSDL_ttf: $(call find_lib,SDL_ttf) $(call find_include,SDL/SDL_ttf)) + $(info ***) BESM6_OPT = -I ${BESM6D} -DFONTFILE=${FONTFILE} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf else BESM6_OPT = -I ${BESM6D} -DUSE_INT64