BESM6: Addition of BESM-6 Simulator written by Leo Broukhis and Serge Vakulenko

This commit is contained in:
Mark Pizzolato 2015-01-09 08:53:10 -08:00
commit 483a969837
23 changed files with 11284 additions and 2 deletions

483
BESM6/besm6_arith.c Normal file
View file

@ -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 <math.h>
#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;
}
}
}

1764
BESM6/besm6_cpu.c Normal file

File diff suppressed because it is too large Load diff

426
BESM6/besm6_defs.h Normal file
View file

@ -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 <setjmp.h>
/*
* 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

703
BESM6/besm6_disk.c Normal file
View file

@ -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 <ctype.h>
/*
* Управляющее слово обмена с магнитным диском.
*/
#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */
#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */
#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */
#define DISK_READ 000400000 /* чтение с диска в память */
#define DISK_PAGE 000370000 /* номер страницы памяти */
#define DISK_HALFPAGE 000004000 /* выбор половины листа */
#define DISK_UNIT 000001600 /* номер устройства */
#define DISK_HALFZONE 000000001 /* выбор половины зоны */
/*
* "Хороший" статус чтения/записи.
* Вычислено по текстам ОС Дубна.
* Диспак доволен.
*/
#define STATUS_GOOD 014000400
/*
* 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<nwords; ++i) {
val = data[i];
fprintf (sim_log, " %04o-%04o-%04o-%04o",
(int) (val >> 36) & 07777,
(int) (val >> 24) & 07777,
(int) (val >> 12) & 07777,
(int) val & 07777);
if ((i & 3) == 3)
fprintf (sim_log, "\n");
}
if ((i & 3) != 0)
fprintf (sim_log, "\n");
}
/*
* Сложение с переносом вправо.
*/
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;
}

372
BESM6/besm6_drum.c Normal file
View file

@ -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; i<drum_nwords; ++i)
print_word (data[i]);
}
fprintf (sim_log, "\n");
}
#endif
/*
* Запись на барабан.
*/
void drum_write (UNIT *u)
{
int ctlr;
t_value *sysdata;
ctlr = (u == &drum_unit[1]);
sysdata = ctlr ? &memory [020] : &memory [010];
fseek (u->fileref, ZONE_SIZE * drum_zone * 8, SEEK_SET);
sim_fwrite (sysdata, 8, 8, u->fileref);
sim_fwrite (&memory [drum_memory], 8, 1024, u->fileref);
if (ferror (u->fileref))
longjmp (cpu_halt, SCPE_IOERR);
}
void drum_write_sector (UNIT *u)
{
int ctlr;
t_value *sysdata;
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;
}

653
BESM6/besm6_mmu.c Normal file
View file

@ -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 ("'");
}
}

550
BESM6/besm6_panel.c Normal file
View file

@ -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 <stdlib.h>
/*
* Use a 640x480 window with 32 bit pixels.
*/
#define WIDTH 800
#define HEIGHT 400
#define DEPTH 32
#define STEPX 14
#define STEPY 16
#include <SDL.h>
#include <SDL_ttf.h>
#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; y<height; ++y) {
s = (unsigned*) ((char*)sprite->pixels + y * sprite->pitch);
for (x=0; x<width; ++x) {
r = *data++;
g = *data++;
b = *data++;
*s++ = SDL_MapRGB (sprite->format, 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"
"<<D\21\21\0\0\0\13\2\2\313,,\377\243\243\377\373\373\377\356\356\377NN\377"
">>\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<<D\21\21\0\0\0\0\0\0\0\0\0D\21\21\313"
"33\377DD\377CC\377CC\377DD\31333D\21\21\0\0\0\0\0\0\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";
static const unsigned char lamp_off [12 * 12 * 3 + 1] =
"\0\0\0\0\0\0\0\0\0\0\0\0\14\2\2\14\2\2\14\2\2\14\2\2\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\25\5\5A\21\21h\32\32c\30\30c\30\30h\32\32A\21\21\25\5\5"
"\0\0\0\0\0\0\0\0\0\25\5\5\\\30\30""8\16\16\0\0\0\0\0\0\0\0\0\0\0\0""8\16"
"\16\\\30\30\25\5\5\0\0\0\0\0\0A\21\21""8\16\16\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0""8\16\16A\21\21\0\0\0\14\2\2h\32\32\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0h\32\32\14\2\2\14\2\2c\30\30\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0c\30\30\14\2\2\14\2\2c\30\30\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0c\30\30\14\2\2\14\2\2h\32\32\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0h\32\32\14\2\2\0\0\0A\21\21""8\16\16\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\16\16A\21\21\0\0\0\0\0\0\25\5\5\\\30"
"\30""8\16\16\0\0\0\0\0\0\0\0\0\0\0\0""8\16\16\\\30\30\25\5\5\0\0\0\0\0\0"
"\0\0\0\25\5\5A\21\21h\32\32c\30\30c\30\30h\32\32A\21\21\25\5\5\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\14\2\2\14\2\2\14\2\2\14\2\2\0\0\0\0\0\0\0\0\0"
"\0\0\0";
static SDL_Surface *sprite_on, *sprite_off;
SDL_Rect area;
if (! sprite_on) {
sprite_on = sprite_from_data (lamp_width, lamp_height,
lamp_on);
}
if (! sprite_off) {
sprite_off = sprite_from_data (lamp_width, lamp_height,
lamp_off);
}
area.x = left;
area.y = top;
area.w = lamp_width;
area.h = lamp_height;
SDL_BlitSurface (on ? sprite_on : sprite_off, 0, screen, &area);
}
/*
* Drawing index (modifier) registers. They form two groups.
*/
static void draw_modifiers_periodic (int group, int left, int top)
{
int x, y, reg, val;
for (y=0; y<8; ++y) {
reg = regnum [y + group*8];
val = M [reg];
if (val == old_M [reg])
continue;
old_M [reg] = val;
for (x=0; x<15; ++x) {
draw_lamp (left+76 + x*STEPX, top+28 + y*STEPY, val >> (14-x) & 1);
}
}
}
/*
* 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 */

319
BESM6/besm6_printer.c Normal file
View file

@ -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;
}

447
BESM6/besm6_punch.c Normal file
View file

@ -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);
}

733
BESM6/besm6_sys.c Normal file
View file

@ -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 <math.h>
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 6353 521
* знак порядок мантисса
* Старший (53-й) бит мантиссы не хранится и всегда равен 1.
*
* Представление чисел в БЭСМ-6:
* 4842 41 401
* порядок знак мантисса в доп. коде
*/
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, &reg); /* 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, &reg);
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<MEMSIZE; ++addr) {
if (addr < 010)
word = pult [addr];
else
word = memory [addr];
if (word == 0)
continue;
if (addr != last_addr+1) {
fprintf (of, "\nв %05o\n", addr);
}
last_addr = addr;
if (IS_INSN (word)) {
fprintf (of, "к ");
besm6_fprint_cmd (of, (uint32)(word >> 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);
}

1256
BESM6/besm6_tty.c Normal file

File diff suppressed because it is too large Load diff

484
BESM6/boot_dispak.b6 Normal file
View file

@ -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

90
BESM6/dispak.ini Normal file
View file

@ -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

30
BESM6/expect.ini Executable file
View file

@ -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

53
BESM6/input.txt Normal file
View file

@ -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
ЕКОНЕЦ

2425
BESM6/test_alu.b6 Normal file

File diff suppressed because it is too large Load diff

16
BESM6/test_alu.ini Normal file
View file

@ -0,0 +1,16 @@
! rm -f log.txt
;set console log=log.txt
;set console debug=log
;set cpu debug
;set mmu debug
set mmu cache
load test_alu.b6
echo Должно быть три останова подряд на адресе 32013.
br 32013
go 32000
go
go
;quit

16
BESM6/test_cu.ini Normal file
View file

@ -0,0 +1,16 @@
! rm -f log.txt
set console log=log.txt
set console debug=log
;set cpu debug
;set mmu debug
load test_cu.b6
;echo Должно быть три останова подряд на адресе 1015.
;br 1015
go 10
go
go
;s 4000000
;quit

37
BESM6/test_pprog05.b6 Normal file
View file

@ -0,0 +1,37 @@
;
; Пультовая программа #5: тест умножения-деления.
; Проверка основных массовых цепей АУ и операций сложения,
; умножения, деления на переменном коде.
;
; Образование переменного кода арифметическим сложением.
; Получение нулевого порядка (100000) для увеличения диапазона
; используемых чисел.
; Умножение на эталон, деление на эталон и вычитание эталона
; дают в результате некоторое число с отрицательным порядком,
; которое должно быть меньше чем 2**-37 (37-десятичное число).
; Увеличение порядка на 37(10) не должно изменить нулевого знака
; порядка, если операции умножения и деления выполнены верно;
; т.к. операция СЛПА относится к группе умножения, то по нулю
; знака порядка операция ПЕ осуществляет передачу управления
; на начало теста.
;
; Переменный код получается в тесте с помощью операции СЛ.
; Поэтому, чтобы тест шел достаточно долго, необходимо
; на 7 тумблерном регистре набирать не слишком большие
; нормализованные числа, не более 2**48
; (110000 порядок числа).
;
в 1
к сл 7, зп 11 ; код := т.рег.7
к вчп 11, зп 10 ; в эталон
к умн 10, дел 10
к вч 10, слпа 145 ; 64+37
к пе 6, стоп
в 6
к сч 11, пб 1 ; если хорошо
в 7
ч 1.0 ; тумб.регистр 7
с 0 ; эталон
с 0 ; код
п 1

21
BESM6/test_pprog05.ini Normal file
View file

@ -0,0 +1,21 @@
! rm -f log.txt
;set console log=log.txt
;set console debug=log
;set cpu debug
load test_pprog05.b6
ex -ml 1-6
ex 7-11
echo
echo Должно быть четыре останова с числами на сумматоре: 1.0 2.0 3.0 4.0.
br 2
go
ex -f ACC
go
ex -f ACC
go
ex -f ACC
go
ex -f ACC
quit

View file

@ -0,0 +1,343 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="BESM6"
ProjectGUID="{A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}"
RootNamespace="BESM6"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="..\BIN\NT\$(PlatformName)-$(ConfigurationName)"
IntermediateDirectory="..\BIN\NT\Project\simh\$(ProjectName)\$(PlatformName)-$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
Description="Check for required build dependencies &amp; git commit id"
CommandLine="Pre-Build-Event.cmd LIBPCRE"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="./;../;../BESM6/;&quot;../../windows-build/PCRE/include/&quot;"
PreprocessorDefinitions="USE_INT64;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCREPOSIX_H;PCRE_STATIC"
KeepComments="false"
MinimalRebuild="true"
BasicRuntimeChecks="0"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
CompileAs="1"
ShowIncludes="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wsock32.lib winmm.lib pcrestaticd.lib pcreposixstaticd.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="../../windows-build/PCRE/lib/"
GenerateDebugInformation="true"
SubSystem="1"
StackReserveSize="10485760"
StackCommitSize="10485760"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="..\BIN\NT\$(PlatformName)-$(ConfigurationName)"
IntermediateDirectory="..\BIN\NT\Project\simh\$(ProjectName)\$(PlatformName)-$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
Description="Check for required build dependencies &amp; git commit id"
CommandLine="Pre-Build-Event.cmd LIBPCRE"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="true"
AdditionalIncludeDirectories="./;../;../BESM6/;&quot;../../windows-build/PCRE/include/&quot;"
PreprocessorDefinitions="USE_INT64;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;SIM_NEED_GIT_COMMIT_ID;HAVE_PCREPOSIX_H;PCRE_STATIC"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
CompileAs="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wsock32.lib winmm.lib pcrestatic.lib pcreposixstatic.lib"
LinkIncremental="1"
AdditionalLibraryDirectories="../../windows-build/PCRE/lib/"
GenerateDebugInformation="false"
SubSystem="1"
StackReserveSize="10485760"
StackCommitSize="10485760"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<File
RelativePath="..\BESM6\besm6_arith.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_cpu.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_disk.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_drum.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_mmu.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_panel.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_printer.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_punch.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_sys.c"
>
</File>
<File
RelativePath="..\BESM6\besm6_tty.c"
>
</File>
<File
RelativePath="..\scp.c"
>
</File>
<File
RelativePath="..\sim_console.c"
>
</File>
<File
RelativePath="..\sim_disk.c"
>
</File>
<File
RelativePath="..\sim_ether.c"
>
</File>
<File
RelativePath="..\sim_fio.c"
>
</File>
<File
RelativePath="..\sim_serial.c"
>
</File>
<File
RelativePath="..\sim_sock.c"
>
</File>
<File
RelativePath="..\sim_tape.c"
>
</File>
<File
RelativePath="..\sim_timer.c"
>
</File>
<File
RelativePath="..\sim_tmxr.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
<File
RelativePath="..\BESM6\besm6_defs.h"
>
</File>
<File
RelativePath="..\scp.h"
>
</File>
<File
RelativePath="..\sim_console.h"
>
</File>
<File
RelativePath="..\sim_defs.h"
>
</File>
<File
RelativePath="..\sim_disk.h"
>
</File>
<File
RelativePath="..\sim_ether.h"
>
</File>
<File
RelativePath="..\sim_fio.h"
>
</File>
<File
RelativePath="..\sim_rev.h"
>
</File>
<File
RelativePath="..\sim_serial.h"
>
</File>
<File
RelativePath="..\sim_sock.h"
>
</File>
<File
RelativePath="..\sim_tape.h"
>
</File>
<File
RelativePath="..\sim_timer.h"
>
</File>
<File
RelativePath="..\sim_tmxr.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -113,6 +113,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SAGE", "SAGE.vcproj", "{9D0
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDQ3", "PDQ3.vcproj", "{D4F5761A-B543-40ED-9892-12A0255C2B6D}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDQ3", "PDQ3.vcproj", "{D4F5761A-B543-40ED-9892-12A0255C2B6D}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BESM6", "BESM6.vcproj", "{A8D46C10-8F3F-47CA-AD5F-E3BB7C4A3678}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 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}.Debug|Win32.Build.0 = Debug|Win32
{D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.ActiveCfg = Release|Win32 {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.ActiveCfg = Release|Win32
{D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -68,6 +68,8 @@ ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS
VIDEO_USEFUL = true VIDEO_USEFUL = true
DISPLAY_USEFUL = true DISPLAY_USEFUL = true
endif endif
else ifneq (,$(findstring besm6,$(MAKECMDGOALS)))
VIDEO_USEFUL = true
else else
ifeq ($(MAKECMDGOALS),) ifeq ($(MAKECMDGOALS),)
# default target is all # default target is all
@ -298,8 +300,8 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
endif endif
$(info lib paths are: $(LIBPATH)) $(info lib paths are: $(LIBPATH))
$(info include paths are: $(INCPATH)) $(info include paths are: $(INCPATH))
find_lib = $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))) find_lib = $(abspath $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))))
find_include = $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h)))) 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)//)) need_search = $(strip $(shell ld -l$(1) /dev/null 2>&1 | grep $(1) | sed s/$(1)//))
LD_SEARCH_NEEDED := $(call need_search,ZzzzzzzZ) LD_SEARCH_NEEDED := $(call need_search,ZzzzzzzZ)
ifneq (,$(call find_lib,m)) ifneq (,$(call find_lib,m))
@ -1159,6 +1161,53 @@ SSEMD = SSEM
SSEM = ${SSEMD}/ssem_cpu.c ${SSEMD}/ssem_sys.c SSEM = ${SSEMD}/ssem_cpu.c ${SSEMD}/ssem_sys.c
SSEM_OPT = -I ${SSEMD} 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 ### Unsupported/Incomplete simulators
### ###
@ -1462,6 +1511,12 @@ ${BIN}ssem${EXE} : ${SSEM} ${SIM}
${MKDIRBIN} ${MKDIRBIN}
${CC} ${SSEM} ${SIM} ${SSEM_OPT} $(CC_OUTSPEC) ${LDFLAGS} ${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} sigma : ${BIN}sigma${EXE}
${BIN}sigma${EXE} : ${SIGMA} ${SIM} ${BIN}sigma${EXE} : ${SIGMA} ${SIM}