diff --git a/BESM6/besm6_arith.c b/BESM6/besm6_arith.c new file mode 100644 index 00000000..082078c3 --- /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 SIM_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..75d13947 --- /dev/null +++ b/BESM6/besm6_cpu.c @@ -0,0 +1,1764 @@ +/* + * 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 + + +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[]; + +/* нехранящие биты ГРП должны сбрасываться путем обнуления тех регистров, + * сборкой которых они являются + */ +#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); +t_stat cpu_req (UNIT *u, int32 val, char *cptr, void *desc); + +/* + * 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[] = { + { 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, "REQ", &cpu_req, NULL, NULL, "Sends a request interrupt" }, + { 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; +} + +/* + * 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: 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; + } +} + +/* + * Команда "увв" + */ +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: 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 */ + + /* 47 р. яч. ЗАНЯТА - разр. приказы вообще */ + const t_value SETUP_REQS_ENABLED = 1LL << 46; + + /* 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) { + /* Слишком рано, или уже не надо, или невовремя */ + 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 { + struct tm * d; + + /* Яч. ГОД обновляем самостоятельно */ + time_t t; + t_value date; + time(&t); + 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; + t_value word; + + corr_stack = 0; + word = mmu_fetch (PC); + if (RUU & RUU_RIGHT_INSTR) + RK = (uint32)word; /* get right instruction */ + else + RK = (uint32)(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: 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 (RUU == 047 && PC == 04440 && RK == 067704440) { + check_initial_setup (); + sim_idle(0, TRUE); + } +} + +/* + * Операция прерывания 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 */ + 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; + } + + sim_interval -= 1; /* count down instructions */ + } +} + +/* + * В 9-й части частота таймера 250 Гц (4 мс), + * в жизни - 50 Гц (20 мс). + */ +t_stat fast_clk (UNIT * this) +{ + static unsigned counter; + static unsigned tty_counter; + + ++counter; + ++tty_counter; + + /*besm6_debug ("*** таймер 20 мсек");*/ + GRP |= GRP_TIMER; + + /* Медленный таймер: должен быть 16 Гц. + * Но от него почему-то зависит вывод на терминалы, + * поэтому ускорим. */ + if ((counter & 3) == 0) { + /*besm6_debug ("*** таймер 80 мсек");*/ + GRP |= GRP_SLOW_CLK; + } + + /* Перерисовка панели каждые 64 миллисекунды. */ + if ((counter & 15) == 0) { + 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 */ +} + +UNIT clocks[] = { + { UDATA(fast_clk, UNIT_IDLE, 0), CLK_DELAY }, /* 40 р, 50 Гц */ +}; + +t_stat clk_reset (DEVICE * dev) +{ + sim_register_clock_unit (&clocks[0]); + + /* Схема автозапуска включается по нереализованной кнопке "МР" */ + + 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; +} + +DEVICE clock_dev = { + "CLK", clocks, NULL, NULL, + 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 new file mode 100644 index 00000000..52b4ecf2 --- /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 "scp.h" +#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 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 UNIT tty_unit[]; +extern UNIT clocks[]; +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); + +/* + * Терминалы (телетайпы, видеотоны, "Консулы"). + */ +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); +int vt_is_idle (void); + +/* + * Ввод с перфоленты. + */ +void fs_control (int num, uint32 cmd); +int fs_read (int num); + +/* + * Отладочная выдача. + */ +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_SERIAL 00000000001000000LL /* 19 */ +#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..062a0f07 --- /dev/null +++ b/BESM6/besm6_disk.c @@ -0,0 +1,703 @@ +/* + * 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" +#include + +/* + * Управляющее слово обмена с магнитным диском. + */ +#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 + +/* + * Total size of a disk in blocks, including hidden blocks + */ +#define DISK_TOTBLK 01767 + +/* + * Параметры обмена с внешним устройством. + */ +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; + int32 saved_switches = sim_switches; + sim_switches |= SWMASK ('E'); + + 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); + sim_fwrite(control, sizeof(t_value), 4, u->fileref); + control[0] = SET_CONVOL((t_value)(2*blkno+1) << 36, CONVOL_NUMBER); + sim_fwrite(control, sizeof(t_value), 4, u->fileref); + for (word = 0; word < 02000; ++word) { + sim_fwrite(control+2, sizeof(t_value), 1, u->fileref); + } + } + return SCPE_OK; + } + if (s == SCPE_OK || + (saved_switches & SWMASK ('E')) || + (sim_switches & SWMASK('N'))) + return s; + sim_switches |= SWMASK ('N'); + } + 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..e29df468 --- /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..486f4e45 --- /dev/null +++ b/BESM6/besm6_mmu.c @@ -0,0 +1,653 @@ +/* + * 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] = RP[i] = BAZ[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) +{ + int waddr = BAZ[idx]; + + if (! BAZ[idx]) { + /* Был пуст после сброса или выталкивания */ + return; + } + /* Вычисляем физический адрес выталкиваемого БРЗ */ + 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: 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: 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; +} + +/* + * Запись слова в память + */ +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 = (uint32)((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..c080a860 --- /dev/null +++ b/BESM6/besm6_panel.c @@ -0,0 +1,550 @@ +/* + * 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. + */ + +#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" +#include + +/* + * Use a 640x480 window with 32 bit pixels. + */ +#define WIDTH 800 +#define HEIGHT 400 +#define DEPTH 32 + +#define STEPX 14 +#define STEPY 16 + +#include +#include + +#define _QUOTE(x) #x +#define QUOTE(x) _QUOTE(x) + +/* Data and functions that don't depend on SDL version */ +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; + +/* + * 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) +{ + 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; + unsigned *s, r, g, b; + int y, x; + + sprite = SDL_CreateRGBSurface (SDL_SWSURFACE, + width, height, DEPTH, 0, 0, 0, 0); + /* + SDL_Surface *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; +} + +/* + * Drawing a neon light. + */ +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); + } + } +} + +/* + * Drawing the main interrupt register and its mask. + */ +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); + } + } +} + +/* + * Drawing the data cache registers. + */ +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); + } + } +} + +/* + * Drawing the static part of the modifier register area. + */ +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; + + /* 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; + area.y = top + 26; + area.w = 2; + 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, + (x & 1) ? top+4 : top+10, 0, message); + } +} + +/* + * Drawing the static part of the interrupt register area. + */ +static void draw_grp_static (int top) +{ + int x, y, color; + char message [40]; + SDL_Rect area; + + 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; + area.y = top + 26; + area.w = 2; + 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, + (x & 1) ? top+10 : top+4, 0, message); + } +} + +/* + * Drawing the static part of the cache register area + */ +static void draw_brz_static (int top) +{ + int x, y, color; + char message [40]; + SDL_Rect area; + + 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; + area.y = top + 26; + area.w = 2; + 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); + old_BRZ[y] = ~0; + } +} + +/* + * Closing the graphical window. + */ +void besm6_close_panel (void) +{ + 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; + + +/* + * Initializing of the graphical window and the fonts. + */ +static void init_panel (void) +{ + 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); + } + + /* Open the font file with the requested point size */ + 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", + QUOTE(FONTFILE), 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); + + /* 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); + 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; + +/* + * Refreshing the window. + */ +void besm6_draw_panel (void) +{ + SDL_Event event; + + if (! screen) + return; + + /* Do the blinkenlights */ + 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.*/ + if (SDL_PollEvent (&event) && event.type == SDL_QUIT) + longjmp (cpu_halt, SCPE_STOP); +} + +#else + +/* + * Initializing of the graphical window and the fonts. + */ +static void init_panel (void) +{ + 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); + } + + /* Open the font file with the requested point size */ + 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", + QUOTE(FONTFILE), TTF_GetError()); + besm6_close_panel(); + exit (1); + } + atexit (besm6_close_panel); + + /* 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); + draw_brz_static (230); + + /* Tell SDL to update the whole screen */ + SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT); +} + +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); + 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); +} + +#endif /* SDL_MAJOR_VERSION */ + +#else /* HAVE_LIBSDL */ +void besm6_draw_panel (void) +{ +} +#endif /* HAVE_LIBSDL */ diff --git a/BESM6/besm6_printer.c b/BESM6/besm6_printer.c new file mode 100644 index 00000000..89bd11f5 --- /dev/null +++ b/BESM6/besm6_printer.c @@ -0,0 +1,319 @@ +/* + * 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]; + +#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; + + 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; + + 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 */ + +/* + * 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); + } + } + + fputc ('\n', fout); + memset(dev->line, 0, sizeof (dev->line)); + dev->length = dev->strikes = 0; +} diff --git a/BESM6/besm6_punch.c b/BESM6/besm6_punch.c new file mode 100644 index 00000000..add2d5bb --- /dev/null +++ b/BESM6/besm6_punch.c @@ -0,0 +1,447 @@ +/* + * 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" + +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; + isfifo[num] = (0 == sim_set_fifo_nonblock (u->fileref)); + ENB_RDY(FS1_READY >> num); + return SCPE_OK; +} + +t_stat fs_detach (UNIT *u) +{ + int num = u - fs_unit; + DIS_RDY(FS1_READY >> num); + return detach_unit (u); +} + +/* + * Управление двигателем, лампой, протяжкой + */ +void fs_control (int num, uint32 cmd) +{ + UNIT *u = &fs_unit[num]; + + static int bytecnt = 0; + if (fs_dev.dctrl) + besm6_debug("<<< ФС1500-%d команда %o", num, cmd); + if (! IS_RDY(FS1_READY >> num)) { + if (fs_dev.dctrl) + besm6_debug("<<< ФС1500-%d не готово", num, cmd); + return; + } + switch (cmd) { + case 0: /* полное выключение */ + sim_cancel (u); + fs_state[num] = FS_IDLE; + if (fs_dev.dctrl) + besm6_debug("<<<ФС1500-%d ВЫКЛ..", num); + bytecnt = 0; + break; + case 4: /* двигатель без протяжки */ + fs_state[num] = FS_STARTING; + if (fs_dev.dctrl) + besm6_debug("<<<ФС1500-%d ВКЛ.", num); + sim_cancel (u); + break; + case 5: /* протяжка */ + if (fs_state[num] == FS_IDLE) + besm6_debug("<<< ФС1500-%d протяжка без мотора", num); + else if (fs_state[num] != FS_TAIL) { + sim_activate (u, FS_RATE); + bytecnt++; + } else { + if (! isfifo[num]) { + fs_detach(u); + fs_state[num] = FS_IDLE; + } + } + break; + default: + besm6_debug ("<<< ФС1500-%d неизвестная команда %o", num, cmd); + } + if (cmd && fs_dev.dctrl) { + besm6_debug("<<<ФС1500-%d: %d симв.", num, bytecnt); + } +} + +unsigned char unicode_to_gost (unsigned short val); +static int utf8_getc (FILE *fin); + +/* + * Событие: читаем очередной символ с перфоленты в регистр. + * Устанавливаем флаг прерывания. + */ +t_stat fs_event (UNIT *u) +{ + 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]; +} + +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..c342174c --- /dev/null +++ b/BESM6/besm6_sys.c @@ -0,0 +1,733 @@ +/* + * besm6_sys.c: BESM-6 simulator interface + * + * 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. + * + * 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 + +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 = (t_value)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; + int exponent; + + /* Убираем свертку */ + word &= BITS48; + + /* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого; + * таким образом, mantissa равно исходной мантиссе, умноженной на 2**63. + */ + mantissa = (double)(((t_int64) word) << (64 - 48 + 7)); + + 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, (uint32)(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 = (int)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 = (uint32)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..418f257b --- /dev/null +++ b/BESM6/besm6_tty.c @@ -0,0 +1,1256 @@ +/* + * besm6_tty.c: BESM-6 teletype device + * + * Copyright (c) 2009, Leo 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 "besm6_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#define TTY_MAX 24 /* Serial TTY lines */ +#define LINES_MAX TTY_MAX + 2 /* Including parallel "Consul" typewriters */ +/* + * According to a table in 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) +{ + /* Inversion is required for Baudot TTYs */ + sym ^= 31; + switch (sym) { + case 0: + reg = rus; + break; + case 27: + reg = dig; + break; + case 31: + reg = lat; + break; + default: + return reg[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]; +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 }; + +/* Command line buffers for TELNET mode. */ +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); +extern int32 tmr_poll; /* calibrated clock timer poll */ + +UNIT tty_unit [] = { + { 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) }, + { 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 } +}; + +/* + * 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 */ + +#define TTY_UNICODE_CHARSET 0 +#define TTY_KOI7_JCUKEN_CHARSET (1< 0 && num <= LINES_MAX) { + char buf [80]; + TMLN *t = &tty_line [num]; + besm6_debug ("*** tty%d: a new connection from %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); + + /* Entering ^C (ETX) to get a prompt. */ + t->rxb [t->rxbpi++] = '\3'; + } + + /* Polling sockets for transmission. */ + tmxr_poll_tx (&tty_desc); + /* 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. + */ + 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) +{ + 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; +} + +/* + * 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) +{ + int num = u - tty_unit; + char gbuf[CBUFSIZE]; + int r, m, n; + + /* 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. */ + for (m=0, n=1; n<=LINES_MAX; ++n) + if (tty_line[n].conn) + m |= 1 << (LINES_MAX-n); + /* 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; + } else { + /* 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 ("*** console on T%03o", num); + return SCPE_OK; + } + return SCPE_ALATT; +} + +t_stat tty_detach (UNIT *u) +{ + return tmxr_detach (&tty_desc, &tty_unit[0]); +} + +/* + * 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", + "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 ("*** TTY: transmit %08o", mask); */ + + TTY_OUT = mask; +} + +/* + * Sending a character to a terminal with the given number. + */ +void vt_putc (int num, int c) +{ + TMLN *t = &tty_line [num]; + + if (! t->conn) + return; + if (t->rcve) { + /* A telnet connection. */ + tmxr_putc_ln (t, c); + } else { + /* Console output. */ + sim_putchar(c); + } +} + +/* + * Sending a string to a terminal with the given number. + */ +void vt_puts (int num, const char *s) +{ + TMLN *t = &tty_line [num]; + + if (! t->conn) + return; + if (t->rcve) { + /* A telnet connection. */ + tmxr_linemsg (t, (char*) s); + } else { + /* Console output. */ + while (*s) sim_putchar(*s++); + } +} + +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) { + 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) { + /* Erasing the previous char. */ + vt_puts (num, "D \033["); + } + sym = 'D'; + break; + 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': + /* Also does carriage return */ + vt_putc (num, '\r'); + sym = '\n'; + break; + case '\f': + /* Home */ + vt_puts(num, "\033["); + sym = 'H'; + break; + case '\r': + case '\003': + /* Not displayed */ + sym = 0; + break; + default: + if (sym < ' ') { + /* Other control chars were displayed as dimmed. */ + vt_puts (num, "\033[2m"); + vt_putc (num, sym | 0x40); + vt_puts (num, "\033["); + /* Terminating the ESC sequence */ + sym = 'm'; + } + } + if (sym) + vt_putc (num, sym); + } else + vt_puts (num, koi7_rus_to_unicode[sym - 0x60]); +} + +/* + * Handling output to all connected terminals. + */ +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; +} + +/* Input from Baudot TTYs not implemented. Output may require some additional work. + */ +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; +} + +/* + * Converting from Unicode to KOI-7. + * Returns -1 if unsuccessful. + */ +static int unicode_to_koi7 (unsigned val) +{ + 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; +} + +/* + * 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) { + /* 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) + 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; + /* Describing a command. */ + tmxr_linemsg (t, c->help); + return SCPE_OK; +} + +/* + * Executing a command. + */ +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); + } +} + +/* + * Command line interface mode. + */ +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) { + /* 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>"); + *cptr = vt_cbuf[num]; + break; + case '\b': + case 0177: + /* Backspace. */ + if (*cptr <= cbuf) + break; + tmxr_linemsg (t, "\b \b"); + while (*cptr > cbuf) { + --*cptr; + if (! (**cptr & 0x80)) + break; + } + break; + case 'U' & 037: + /* Erase line. */ + 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': /* Up arrow */ + if (*cptr <= cbuf) { + *cptr = cbuf + strlen (cbuf); + if (*cptr > cbuf) + tmxr_linemsg (t, cbuf); + } + break; + case 'B': /* Down arrow */ + goto erase_line; + } + break; + default: + if (c < ' ' || *cptr > cbuf+CBUFSIZE-5) + break; + *(*cptr)++ = c; + tmxr_putc_ln (t, c); + break; + } +} + +/* + * Getting a char from a terminal with the given number. + * Returns -1 if there is no char to input. + */ +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: disconnecting %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) { + /* 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\nSIMH: END OF SESSION\r\n"); + tmxr_reset_ln (t); + return -1; + } + tmxr_linemsg (t, "\r\nSIMH: WAKE UP!\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) { + /* 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) { + stop_cpu = 1; /* just in case */ + } + if (! (c & SCPE_KFLAG)) + return -1; + } + return c & 0377; +} + +/* + * 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) +{ + 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)); +} + +/* + * 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) +{ + 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; +} + +/* + * Handling input from all connected terminals. + */ +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) { + break; + } + if (tty_typed[num] <= 0177) { + if (tty_typed[num] == '\r' || tty_typed[num] == '\n') + 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; /* 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; + 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; +} + +/* + * Checking if all terminals are idle. + * SIMH should not enter idle mode until they are. + */ +int vt_is_idle () +{ + return (tt_mask ? vt_idle > 300 : vt_idle > 10); +} + +int tty_query () +{ + /* besm6_debug ("*** TTY: query");*/ + 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..57f5a627 --- /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..ac2170c2 --- /dev/null +++ b/BESM6/dispak.ini @@ -0,0 +1,90 @@ +set -n console log=log.txt +set console debug=log +set cpu idle +;set cpu debug +;set mmu debug +;set drum debug +;set disk debug + +; +; Приводим барабаны в исходное состояние. +; +attach -n drum0 drum1x.bin +attach -n drum1 drum2x.bin + +; +; Создаем рабочий диск. +; +attach -n disk6 2052.bin + +; +; Подключаем диски. +; +attach -e disk7 sbor2053.bin +attach -e disk5 krab2063.bin +attach -e disk0 sbor2048.bin +attach -e disk1 svs2048.bin +attach -e disk2 alt2048.bin + +; +; Подключаем АЦПУ. +; +attach prn0 output.txt + +; +; Активируем операторский терминал, +; на который идут сообщения. +; +attach tty1 console + +; +; Режимы по вкусу +; +;set tty1 jcuken,authbs +set tty1 qwerty,authbs +set -n 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/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 + ЕКОНЕЦ 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< + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 diff --git a/makefile b/makefile index 871cea54..03bce142 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 ifneq (,$(findstring besm6,$(MAKECMDGOALS))) + VIDEO_USEFUL = true else ifeq ($(MAKECMDGOALS),) # default target is all @@ -298,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)) @@ -1159,6 +1161,53 @@ 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 + +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 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))))) + find_font = $(abspath $(strip $(firstword $(foreach font,$(strip $(FONTNAME)),$(call find_fontfile,$(font)))))) + ifneq (,$(call find_font)) + FONTFILE=$(call find_font) + else + $(info ***) + $(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) + $(info *** a font file with FONTFILE=path/fontname.ttf) + $(info ***) + endif + endif +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)) + $(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 +endif + ### ### Unsupported/Incomplete simulators ### @@ -1462,6 +1511,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}