BESM6: Added target 'besm6' to makefile; added new files in the BESM6 subdirectory.
This commit is contained in:
parent
de9fc84fd4
commit
659600ff59
12 changed files with 7748 additions and 0 deletions
483
BESM6/besm6_arith.c
Normal file
483
BESM6/besm6_arith.c
Normal 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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1768
BESM6/besm6_cpu.c
Normal file
1768
BESM6/besm6_cpu.c
Normal file
File diff suppressed because it is too large
Load diff
426
BESM6/besm6_defs.h
Normal file
426
BESM6/besm6_defs.h
Normal 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 <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 10 /* одна микросекунда - десять тактов */
|
||||||
|
#define MSEC (1000*USEC) /* одна миллисекунда */
|
||||||
|
|
||||||
|
extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
|
||||||
|
extern int32 sim_interval, sim_step;
|
||||||
|
extern FILE *sim_deb, *sim_log;
|
||||||
|
extern int32 sim_switches;
|
||||||
|
|
||||||
|
extern UNIT cpu_unit;
|
||||||
|
extern t_value memory [MEMSIZE];
|
||||||
|
extern t_value pult [8];
|
||||||
|
extern uint32 PC, RAU, RUU;
|
||||||
|
extern uint32 M[NREGS];
|
||||||
|
extern t_value BRZ[8], RP[8], GRP, MGRP;
|
||||||
|
extern uint32 PRP, MPRP;
|
||||||
|
extern t_value ACC, RMR;
|
||||||
|
extern uint32 BAZ[8], TABST, RZ;
|
||||||
|
extern uint32 READY; /* read by ext 4031 */
|
||||||
|
extern uint32 READY2; /* read by ext 4102 */
|
||||||
|
extern DEVICE cpu_dev, drum_dev, mmu_dev, disk_dev;
|
||||||
|
extern DEVICE clock_dev;
|
||||||
|
extern DEVICE printer_dev;
|
||||||
|
extern DEVICE tty_dev;
|
||||||
|
extern DEVICE fs_dev;
|
||||||
|
extern jmp_buf cpu_halt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Разряды режима АУ.
|
||||||
|
*/
|
||||||
|
#define RAU_NORM_DISABLE 001 /* блокировка нормализации */
|
||||||
|
#define RAU_ROUND_DISABLE 002 /* блокировка округления */
|
||||||
|
#define RAU_LOG 004 /* признак логической группы */
|
||||||
|
#define RAU_MULT 010 /* признак группы умножения */
|
||||||
|
#define RAU_ADD 020 /* признак группы слодения */
|
||||||
|
#define RAU_OVF_DISABLE 040 /* блокировка переполнения */
|
||||||
|
|
||||||
|
#define RAU_MODE (RAU_LOG | RAU_MULT | RAU_ADD)
|
||||||
|
#define SET_MODE(x,m) (((x) & ~RAU_MODE) | (m))
|
||||||
|
#define SET_LOGICAL(x) (((x) & ~RAU_MODE) | RAU_LOG)
|
||||||
|
#define SET_MULTIPLICATIVE(x) (((x) & ~RAU_MODE) | RAU_MULT)
|
||||||
|
#define SET_ADDITIVE(x) (((x) & ~RAU_MODE) | RAU_ADD)
|
||||||
|
#define IS_LOGICAL(x) (((x) & RAU_MODE) == RAU_LOG)
|
||||||
|
#define IS_MULTIPLICATIVE(x) (((x) & (RAU_ADD | RAU_MULT)) == RAU_MULT)
|
||||||
|
#define IS_ADDITIVE(x) ((x) & RAU_ADD)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Искусственный регистр режимов УУ, в реальной машине отсутствует.
|
||||||
|
*/
|
||||||
|
#define RUU_CONVOL_RIGHT 000001 /* ПКП - признак контроля правой половины */
|
||||||
|
#define RUU_CONVOL_LEFT 000002 /* ПКЛ - признак контроля левой половины */
|
||||||
|
#define RUU_EXTRACODE 000004 /* РежЭ - режим экстракода */
|
||||||
|
#define RUU_INTERRUPT 000010 /* РежПр - режим прерывания */
|
||||||
|
#define RUU_MOD_RK 000020 /* ПрИК - модификация регистром М[16] */
|
||||||
|
#define RUU_AVOST_DISABLE 000040 /* БРО - блокировка режима останова */
|
||||||
|
#define RUU_RIGHT_INSTR 000400 /* ПрК - признак правой команды */
|
||||||
|
|
||||||
|
#define IS_SUPERVISOR(x) ((x) & (RUU_EXTRACODE | RUU_INTERRUPT))
|
||||||
|
#define SET_SUPERVISOR(x,m) (((x) & ~(RUU_EXTRACODE | RUU_INTERRUPT)) | (m))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Специальные регистры.
|
||||||
|
*/
|
||||||
|
#define MOD 020 /* модификатор адреса */
|
||||||
|
#define PSW 021 /* режимы УУ */
|
||||||
|
#define SPSW 027 /* упрятывание режимов УУ */
|
||||||
|
#define ERET 032 /* адрес возврата из экстракода */
|
||||||
|
#define IRET 033 /* адрес возврата из прерывания */
|
||||||
|
#define IBP 034 /* адрес прерывания по выполнению */
|
||||||
|
#define DWP 035 /* адрес прерывания по чтению/записи */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Регистр 021: режимы УУ.
|
||||||
|
* PSW: program status word.
|
||||||
|
*/
|
||||||
|
#define PSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */
|
||||||
|
#define PSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */
|
||||||
|
#define PSW_INTR_HALT 000004 /* ПоП - признак останова при
|
||||||
|
любом внутреннем прерывании */
|
||||||
|
#define PSW_CHECK_HALT 000010 /* ПоК - признак останова при
|
||||||
|
прерывании по контролю */
|
||||||
|
#define PSW_WRITE_WATCH 000020 /* Зп(М29) - признак совпадения адреса
|
||||||
|
операнда прии записи в память
|
||||||
|
с содержанием регистра М29 */
|
||||||
|
#define PSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */
|
||||||
|
#define PSW_AUT_B 004000 /* АвтБ - признак режима Автомат Б */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Регистр 027: сохранённые режимы УУ.
|
||||||
|
* SPSW: saved program status word.
|
||||||
|
*/
|
||||||
|
#define SPSW_MMAP_DISABLE 000001 /* БлП - блокировка приписки */
|
||||||
|
#define SPSW_PROT_DISABLE 000002 /* БлЗ - блокировка защиты */
|
||||||
|
#define SPSW_EXTRACODE 000004 /* РежЭ - режим экстракода */
|
||||||
|
#define SPSW_INTERRUPT 000010 /* РежПр - режим прерывания */
|
||||||
|
#define SPSW_MOD_RK 000020 /* ПрИК(РК) - на регистр РК принята
|
||||||
|
команда, которая должна быть
|
||||||
|
модифицирована регистром М[16] */
|
||||||
|
#define SPSW_MOD_RR 000040 /* ПрИК(РР) - на регистре РР находится
|
||||||
|
команда, выполненная с модификацией */
|
||||||
|
#define SPSW_UNKNOWN 000100 /* НОК? вписано карандашом в 9 томе */
|
||||||
|
#define SPSW_RIGHT_INSTR 000400 /* ПрК - признак правой команды */
|
||||||
|
#define SPSW_NEXT_RK 001000 /* ГД./ДК2 - на регистр РК принята
|
||||||
|
команда, следующая после вызвавшей
|
||||||
|
прерывание */
|
||||||
|
#define SPSW_INTR_DISABLE 002000 /* БлПр - блокировка внешнего прерывания */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Кириллица Unicode.
|
||||||
|
*/
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_A 0x0410
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_BE 0x0411
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_VE 0x0412
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_GHE 0x0413
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_DE 0x0414
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_IE 0x0415
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_ZHE 0x0416
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_ZE 0x0417
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_I 0x0418
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_SHORT_I 0x0419
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_KA 0x041a
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_EL 0x041b
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_EM 0x041c
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_EN 0x041d
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_O 0x041e
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_PE 0x041f
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_ER 0x0420
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_ES 0x0421
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_TE 0x0422
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_U 0x0423
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_EF 0x0424
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_HA 0x0425
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_TSE 0x0426
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_CHE 0x0427
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_SHA 0x0428
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_SHCHA 0x0429
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_HARD_SIGN 0x042a
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_YERU 0x042b
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_SOFT_SIGN 0x042c
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_E 0x042d
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_YU 0x042e
|
||||||
|
#define CYRILLIC_CAPITAL_LETTER_YA 0x042f
|
||||||
|
#define CYRILLIC_SMALL_LETTER_A 0x0430
|
||||||
|
#define CYRILLIC_SMALL_LETTER_BE 0x0431
|
||||||
|
#define CYRILLIC_SMALL_LETTER_VE 0x0432
|
||||||
|
#define CYRILLIC_SMALL_LETTER_GHE 0x0433
|
||||||
|
#define CYRILLIC_SMALL_LETTER_DE 0x0434
|
||||||
|
#define CYRILLIC_SMALL_LETTER_IE 0x0435
|
||||||
|
#define CYRILLIC_SMALL_LETTER_ZHE 0x0436
|
||||||
|
#define CYRILLIC_SMALL_LETTER_ZE 0x0437
|
||||||
|
#define CYRILLIC_SMALL_LETTER_I 0x0438
|
||||||
|
#define CYRILLIC_SMALL_LETTER_SHORT_I 0x0439
|
||||||
|
#define CYRILLIC_SMALL_LETTER_KA 0x043a
|
||||||
|
#define CYRILLIC_SMALL_LETTER_EL 0x043b
|
||||||
|
#define CYRILLIC_SMALL_LETTER_EM 0x043c
|
||||||
|
#define CYRILLIC_SMALL_LETTER_EN 0x043d
|
||||||
|
#define CYRILLIC_SMALL_LETTER_O 0x043e
|
||||||
|
#define CYRILLIC_SMALL_LETTER_PE 0x043f
|
||||||
|
#define CYRILLIC_SMALL_LETTER_ER 0x0440
|
||||||
|
#define CYRILLIC_SMALL_LETTER_ES 0x0441
|
||||||
|
#define CYRILLIC_SMALL_LETTER_TE 0x0442
|
||||||
|
#define CYRILLIC_SMALL_LETTER_U 0x0443
|
||||||
|
#define CYRILLIC_SMALL_LETTER_EF 0x0444
|
||||||
|
#define CYRILLIC_SMALL_LETTER_HA 0x0445
|
||||||
|
#define CYRILLIC_SMALL_LETTER_TSE 0x0446
|
||||||
|
#define CYRILLIC_SMALL_LETTER_CHE 0x0447
|
||||||
|
#define CYRILLIC_SMALL_LETTER_SHA 0x0448
|
||||||
|
#define CYRILLIC_SMALL_LETTER_SHCHA 0x0449
|
||||||
|
#define CYRILLIC_SMALL_LETTER_HARD_SIGN 0x044a
|
||||||
|
#define CYRILLIC_SMALL_LETTER_YERU 0x044b
|
||||||
|
#define CYRILLIC_SMALL_LETTER_SOFT_SIGN 0x044c
|
||||||
|
#define CYRILLIC_SMALL_LETTER_E 0x044d
|
||||||
|
#define CYRILLIC_SMALL_LETTER_YU 0x044e
|
||||||
|
#define CYRILLIC_SMALL_LETTER_YA 0x044f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Процедуры работы с памятью
|
||||||
|
*/
|
||||||
|
extern void mmu_store (int addr, t_value word);
|
||||||
|
extern t_value mmu_load (int addr);
|
||||||
|
extern t_value mmu_fetch (int addr);
|
||||||
|
extern t_value mmu_prefetch (int addr, int actual);
|
||||||
|
extern void mmu_setcache (int idx, t_value word);
|
||||||
|
extern t_value mmu_getcache (int idx);
|
||||||
|
extern void mmu_setrp (int idx, t_value word);
|
||||||
|
extern void mmu_setup (void);
|
||||||
|
extern void mmu_setprotection (int idx, t_value word);
|
||||||
|
extern void mmu_print_brz (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Выполнение обращения к барабану.
|
||||||
|
*/
|
||||||
|
void drum (int ctlr, uint32 cmd);
|
||||||
|
int drum_errors (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Обращение к дискам.
|
||||||
|
*/
|
||||||
|
void disk_io (int ctlr, uint32 cmd);
|
||||||
|
void disk_ctl (int ctlr, uint32 cmd);
|
||||||
|
int disk_state (int ctlr);
|
||||||
|
int disk_errors (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Печать на АЦПУ.
|
||||||
|
*/
|
||||||
|
void printer_control (int num, uint32 cmd);
|
||||||
|
void printer_hammer (int num, int pos, uint32 mask);
|
||||||
|
int printer_is_idle (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Терминалы (телетайпы, видеотоны, "Консулы").
|
||||||
|
*/
|
||||||
|
void tty_send (uint32 mask);
|
||||||
|
int tty_query (void);
|
||||||
|
void vt_print (void);
|
||||||
|
void vt_receive (void);
|
||||||
|
void consul_print (int num, uint32 cmd);
|
||||||
|
uint32 consul_read (int num);
|
||||||
|
int vt_is_idle (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ввод с перфоленты.
|
||||||
|
*/
|
||||||
|
void fs_control (int num, uint32 cmd);
|
||||||
|
int fs_read (int num);
|
||||||
|
int fs_is_idle (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отладочная выдача.
|
||||||
|
*/
|
||||||
|
void besm6_fprint_cmd (FILE *of, uint32 cmd);
|
||||||
|
void besm6_log (const char *fmt, ...);
|
||||||
|
void besm6_log_cont (const char *fmt, ...);
|
||||||
|
void besm6_debug (const char *fmt, ...);
|
||||||
|
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||||
|
UNIT *uptr, int32 sw);
|
||||||
|
void besm6_draw_panel (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Арифметика.
|
||||||
|
*/
|
||||||
|
double besm6_to_ieee (t_value word);
|
||||||
|
void besm6_add (t_value val, int negate_acc, int negate_val);
|
||||||
|
void besm6_divide (t_value val);
|
||||||
|
void besm6_multiply (t_value val);
|
||||||
|
void besm6_change_sign (int sign);
|
||||||
|
void besm6_add_exponent (int val);
|
||||||
|
int besm6_highest_bit (t_value val);
|
||||||
|
void besm6_shift (int toright);
|
||||||
|
int besm6_count_ones (t_value word);
|
||||||
|
t_value besm6_pack (t_value val, t_value mask);
|
||||||
|
t_value besm6_unpack (t_value val, t_value mask);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Разряды главного регистра прерываний (ГРП)
|
||||||
|
* Внешние:
|
||||||
|
*/
|
||||||
|
#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */
|
||||||
|
#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */
|
||||||
|
#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */
|
||||||
|
#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */
|
||||||
|
#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */
|
||||||
|
#define GRP_FS1_SYNC 00040000000000000LL /* 42 */
|
||||||
|
#define GRP_FS2_SYNC 00020000000000000LL /* 41 */
|
||||||
|
#define GRP_TIMER 00010000000000000LL /* 40 */
|
||||||
|
#define GRP_PRN1_ZERO 00004000000000000LL /* 39 */
|
||||||
|
#define GRP_PRN2_ZERO 00002000000000000LL /* 38 */
|
||||||
|
#define GRP_SLAVE 00001000000000000LL /* 37 */
|
||||||
|
#define GRP_CHAN3_DONE 00000400000000000LL /* 36 */
|
||||||
|
#define GRP_CHAN4_DONE 00000200000000000LL /* 35 */
|
||||||
|
#define GRP_CHAN5_DONE 00000100000000000LL /* 34 */
|
||||||
|
#define GRP_CHAN6_DONE 00000040000000000LL /* 33 */
|
||||||
|
#define GRP_PANEL_REQ 00000020000000000LL /* 32 */
|
||||||
|
#define GRP_TTY_START 00000010000000000LL /* 31 */
|
||||||
|
#define GRP_IMITATION 00000004000000000LL /* 30 */
|
||||||
|
#define GRP_CHAN3_FREE 00000002000000000LL /* 29 */
|
||||||
|
#define GRP_CHAN4_FREE 00000001000000000LL /* 28 */
|
||||||
|
#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */
|
||||||
|
#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */
|
||||||
|
#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */
|
||||||
|
#define GRP_WATCHDOG 00000000000002000LL /* 11 */
|
||||||
|
#define GRP_SLOW_CLK 00000000000001000LL /* 10 */
|
||||||
|
/* Внутренние: */
|
||||||
|
#define GRP_DIVZERO 00000000034000000LL /* 23-21 */
|
||||||
|
#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */
|
||||||
|
#define GRP_CHECK 00000000004000000LL /* 21 */
|
||||||
|
#define GRP_OPRND_PROT 00000000002000000LL /* 20 */
|
||||||
|
#define GRP_WATCHPT_W 00000000000200000LL /* 17 */
|
||||||
|
#define GRP_WATCHPT_R 00000000000100000LL /* 16 */
|
||||||
|
#define GRP_INSN_CHECK 00000000000040000LL /* 15 */
|
||||||
|
#define GRP_INSN_PROT 00000000000020000LL /* 14 */
|
||||||
|
#define GRP_ILL_INSN 00000000000010000LL /* 13 */
|
||||||
|
#define GRP_BREAKPOINT 00000000000004000LL /* 12 */
|
||||||
|
#define GRP_PAGE_MASK 00000000000000760LL /* 9-5 */
|
||||||
|
#define GRP_RAM_CHECK 00000000000000010LL /* 4 */
|
||||||
|
#define GRP_BLOCK_MASK 00000000000000007LL /* 3-1 */
|
||||||
|
|
||||||
|
#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK))
|
||||||
|
#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK))
|
||||||
|
|
||||||
|
/* Номер блока ОЗУ или номер страницы, вызвавших прерывание */
|
||||||
|
extern uint32 iintr_data;
|
||||||
|
|
||||||
|
#endif
|
648
BESM6/besm6_disk.c
Normal file
648
BESM6/besm6_disk.c
Normal file
|
@ -0,0 +1,648 @@
|
||||||
|
/*
|
||||||
|
* BESM-6 magnetic disk device
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Serge Vakulenko
|
||||||
|
* Copyright (c) 2009, Leonid Broukhis
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||||
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||||
|
* OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
* Except as contained in this notice, the name of Leonid Broukhis or
|
||||||
|
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||||||
|
* the sale, use or other dealings in this Software without prior written
|
||||||
|
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||||||
|
*/
|
||||||
|
#include "besm6_defs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Управляющее слово обмена с магнитным диском.
|
||||||
|
*/
|
||||||
|
#define DISK_BLOCK 0740000000 /* номер блока памяти - 27-24 рр */
|
||||||
|
#define DISK_READ_SYSDATA 004000000 /* считывание только служебных слов */
|
||||||
|
#define DISK_PAGE_MODE 001000000 /* обмен целой страницей */
|
||||||
|
#define DISK_READ 000400000 /* чтение с диска в память */
|
||||||
|
#define DISK_PAGE 000370000 /* номер страницы памяти */
|
||||||
|
#define DISK_HALFPAGE 000004000 /* выбор половины листа */
|
||||||
|
#define DISK_UNIT 000001600 /* номер устройства */
|
||||||
|
#define DISK_HALFZONE 000000001 /* выбор половины зоны */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Хороший" статус чтения/записи.
|
||||||
|
* Вычислено по текстам ОС Дубна.
|
||||||
|
* Диспак доволен.
|
||||||
|
*/
|
||||||
|
#define STATUS_GOOD 014000400
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Параметры обмена с внешним устройством.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int op; /* Условное слово обмена */
|
||||||
|
int dev; /* Номер устройства, 0..7 */
|
||||||
|
int zone; /* Номер зоны на диске */
|
||||||
|
int track; /* Выбор половины зоны на диске */
|
||||||
|
int memory; /* Начальный адрес памяти */
|
||||||
|
int format; /* Флаг разметки */
|
||||||
|
int status; /* Регистр состояния */
|
||||||
|
t_value mask_grp; /* Маска готовности для ГРП */
|
||||||
|
int mask_fail; /* Маска ошибки обмена */
|
||||||
|
t_value *sysdata; /* Буфер системных данных */
|
||||||
|
} KMD;
|
||||||
|
|
||||||
|
static KMD controller [2]; /* Две стойки КМД */
|
||||||
|
int disk_fail; /* Маска ошибок по направлениям */
|
||||||
|
|
||||||
|
t_stat disk_event (UNIT *u);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DISK data structures
|
||||||
|
*
|
||||||
|
* disk_dev DISK device descriptor
|
||||||
|
* disk_unit DISK unit descriptor
|
||||||
|
* disk_reg DISK register list
|
||||||
|
*/
|
||||||
|
UNIT disk_unit [16] = {
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
{ UDATA (disk_event, UNIT_FIX+UNIT_ATTABLE+UNIT_ROABLE, DISK_SIZE) },
|
||||||
|
};
|
||||||
|
|
||||||
|
REG disk_reg[] = {
|
||||||
|
{ "КУС_0", &controller[0].op, 8, 24, 0, 1 },
|
||||||
|
{ "УСТР_0", &controller[0].dev, 8, 3, 0, 1 },
|
||||||
|
{ "ЗОНА_0", &controller[0].zone, 8, 10, 0, 1 },
|
||||||
|
{ "ДОРОЖКА_0", &controller[0].track, 8, 2, 0, 1 },
|
||||||
|
{ "МОЗУ_0", &controller[0].memory, 8, 20, 0, 1 },
|
||||||
|
{ "РС_0", &controller[0].status, 8, 24, 0, 1 },
|
||||||
|
{ "КУС_1", &controller[1].op, 8, 24, 0, 1 },
|
||||||
|
{ "УСТР_1", &controller[1].dev, 8, 3, 0, 1 },
|
||||||
|
{ "ЗОНА_1", &controller[1].zone, 8, 10, 0, 1 },
|
||||||
|
{ "ДОРОЖКА_1", &controller[1].track, 8, 2, 0, 1 },
|
||||||
|
{ "МОЗУ_1", &controller[1].memory, 8, 20, 0, 1 },
|
||||||
|
{ "РС_1", &controller[1].status, 8, 24, 0, 1 },
|
||||||
|
{ "ОШ", &disk_fail, 8, 6, 0, 1 },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB disk_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat disk_reset (DEVICE *dptr);
|
||||||
|
t_stat disk_attach (UNIT *uptr, char *cptr);
|
||||||
|
t_stat disk_detach (UNIT *uptr);
|
||||||
|
|
||||||
|
DEVICE disk_dev = {
|
||||||
|
"DISK", disk_unit, disk_reg, disk_mod,
|
||||||
|
16, 8, 21, 1, 8, 50,
|
||||||
|
NULL, NULL, &disk_reset, NULL, &disk_attach, &disk_detach,
|
||||||
|
NULL, DEV_DISABLE | DEV_DEBUG
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Определение контроллера по устройству.
|
||||||
|
*/
|
||||||
|
static KMD *unit_to_ctlr (UNIT *u)
|
||||||
|
{
|
||||||
|
if (u < &disk_unit[8])
|
||||||
|
return &controller[0];
|
||||||
|
else
|
||||||
|
return &controller[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset routine
|
||||||
|
*/
|
||||||
|
t_stat disk_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset (&controller, 0, sizeof (controller));
|
||||||
|
controller[0].sysdata = &memory [030];
|
||||||
|
controller[1].sysdata = &memory [040];
|
||||||
|
controller[0].mask_grp = GRP_CHAN3_FREE;
|
||||||
|
controller[1].mask_grp = GRP_CHAN4_FREE;
|
||||||
|
controller[0].mask_fail = 020;
|
||||||
|
controller[1].mask_fail = 010;
|
||||||
|
for (i=0; i<16; ++i)
|
||||||
|
sim_cancel (&disk_unit[i]);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat disk_attach (UNIT *u, char *cptr)
|
||||||
|
{
|
||||||
|
t_stat s;
|
||||||
|
|
||||||
|
s = attach_unit (u, cptr);
|
||||||
|
if (s != SCPE_OK)
|
||||||
|
return s;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat disk_detach (UNIT *u)
|
||||||
|
{
|
||||||
|
/* TODO: сброс бита ГРП готовности направления при отключении последнего диска. */
|
||||||
|
return detach_unit (u);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_value spread (t_value val)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
t_value res = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 5; i++) for (j = 0; j < 9; j++)
|
||||||
|
if (val & (1LL<<(i+j*5)))
|
||||||
|
res |= 1LL << (i*9+j);
|
||||||
|
return res & BITS48;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отладочная печать массива данных обмена.
|
||||||
|
*/
|
||||||
|
static void log_data (t_value *data, int nwords)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
t_value val;
|
||||||
|
|
||||||
|
for (i=0; i<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
372
BESM6/besm6_drum.c
Normal 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;
|
||||||
|
}
|
652
BESM6/besm6_mmu.c
Normal file
652
BESM6/besm6_mmu.c
Normal file
|
@ -0,0 +1,652 @@
|
||||||
|
/*
|
||||||
|
* besm6_mmu.c: BESM-6 fast write cache and TLB registers
|
||||||
|
*(стойка БРУС)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Leonid Broukhis
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||||
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||||
|
* OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
* Except as contained in this notice, the name of Leonid Broukhis or
|
||||||
|
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||||||
|
* the sale, use or other dealings in this Software without prior written
|
||||||
|
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||||||
|
*/
|
||||||
|
#include "besm6_defs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MMU data structures
|
||||||
|
*
|
||||||
|
* mmu_dev MMU device descriptor
|
||||||
|
* mmu_unit MMU unit descriptor
|
||||||
|
* mmu_reg MMU register list
|
||||||
|
*/
|
||||||
|
UNIT mmu_unit = {
|
||||||
|
UDATA (NULL, UNIT_FIX, 8)
|
||||||
|
};
|
||||||
|
|
||||||
|
t_value BRZ[8];
|
||||||
|
uint32 BAZ[8], TABST, RZ, OLDEST, FLUSH;
|
||||||
|
|
||||||
|
t_value BRS[4];
|
||||||
|
uint32 BAS[4];
|
||||||
|
uint32 BRSLRU;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 64-битные регистры RP0-RP7 - для отображения регистров приписки,
|
||||||
|
* группами по 4 ради компактности, 12 бит на страницу.
|
||||||
|
* TLB0-TLB31 - постраничные регистры приписки, копии RPi.
|
||||||
|
* Обращение к памяти должно вестись через TLBi.
|
||||||
|
*/
|
||||||
|
t_value RP[8];
|
||||||
|
uint32 TLB[32];
|
||||||
|
|
||||||
|
unsigned iintr_data; /* protected page number or parity check location */
|
||||||
|
|
||||||
|
t_value pult[8];
|
||||||
|
|
||||||
|
REG mmu_reg[] = {
|
||||||
|
{ "БРЗ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры записи */
|
||||||
|
{ "БРЗ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРЗ2", &BRZ[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРЗ3", &BRZ[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРЗ4", &BRZ[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРЗ5", &BRZ[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРЗ6", &BRZ[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРЗ7", &BRZ[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БАЗ0", &BAZ[0], 8, 16, 0, 1 }, /* Буферные адреса записи */
|
||||||
|
{ "БАЗ1", &BAZ[1], 8, 16, 0, 1 },
|
||||||
|
{ "БАЗ2", &BAZ[2], 8, 16, 0, 1 },
|
||||||
|
{ "БАЗ3", &BAZ[3], 8, 16, 0, 1 },
|
||||||
|
{ "БАЗ4", &BAZ[4], 8, 16, 0, 1 },
|
||||||
|
{ "БАЗ5", &BAZ[5], 8, 16, 0, 1 },
|
||||||
|
{ "БАЗ6", &BAZ[6], 8, 16, 0, 1 },
|
||||||
|
{ "БАЗ7", &BAZ[7], 8, 16, 0, 1 },
|
||||||
|
{ "ТАБСТ", &TABST, 8, 28, 0, 1, NULL, NULL, REG_HIDDEN },/* Таблица старшинства БРЗ */
|
||||||
|
{ "ЗпТР", &FLUSH, 8, 4, 0, 1, NULL, NULL, REG_HIDDEN },/* Признак выталкивания БРЗ */
|
||||||
|
{ "Старш", &OLDEST, 8, 3, 0, 1 }, /* Номер вытолкнутого БРЗ */
|
||||||
|
{ "РП0", &RP[0], 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* Регистры приписки, по 12 бит */
|
||||||
|
{ "РП1", &RP[1], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РП2", &RP[2], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РП3", &RP[3], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РП4", &RP[4], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РП5", &RP[5], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РП6", &RP[6], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РП7", &RP[7], 8, 48, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "РЗ", &RZ, 8, 32, 0, 1 }, /* Регистр защиты */
|
||||||
|
{ "ТР1", &pult[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Тумблерные регистры */
|
||||||
|
{ "ТР2", &pult[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "ТР3", &pult[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "ТР4", &pult[4], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "ТР5", &pult[5], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "ТР6", &pult[6], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "ТР7", &pult[7], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРС0", &BRS[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO}, /* Буферные регистры слов */
|
||||||
|
{ "БРС1", &BRS[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРС2", &BRS[2], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БРС3", &BRS[3], 8, 50, 0, 1, NULL, NULL, REG_VMIO},
|
||||||
|
{ "БАС0", &BAS[0], 8, 16, 0, 1 }, /* Буферные адреса слов */
|
||||||
|
{ "БАС1", &BAS[1], 8, 16, 0, 1 },
|
||||||
|
{ "БАС2", &BAS[2], 8, 16, 0, 1 },
|
||||||
|
{ "БАС3", &BAS[3], 8, 16, 0, 1 },
|
||||||
|
{ "БРСст", &BRSLRU, 8, 6, 0, 1, NULL, NULL, REG_HIDDEN},
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CACHE_ENB 1
|
||||||
|
|
||||||
|
MTAB mmu_mod[] = {
|
||||||
|
{ 1, 0, "NOCACHE", "NOCACHE" },
|
||||||
|
{ 1, 1, "CACHE", "CACHE" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat mmu_reset (DEVICE *dptr);
|
||||||
|
|
||||||
|
t_stat mmu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||||
|
{
|
||||||
|
mmu_print_brz();
|
||||||
|
return SCPE_NOFNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE mmu_dev = {
|
||||||
|
"MMU", &mmu_unit, mmu_reg, mmu_mod,
|
||||||
|
1, 8, 3, 1, 8, 50,
|
||||||
|
&mmu_examine, NULL, &mmu_reset,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
DEV_DEBUG
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset routine
|
||||||
|
*/
|
||||||
|
t_stat mmu_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
BRZ[i] = BAZ[i] = RP[i] = 0;
|
||||||
|
}
|
||||||
|
TABST = 0;
|
||||||
|
OLDEST = 0;
|
||||||
|
FLUSH = 0;
|
||||||
|
RZ = 0;
|
||||||
|
/*
|
||||||
|
* Front panel switches survive the reset
|
||||||
|
*/
|
||||||
|
sim_cancel (&mmu_unit);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define loses_to_all(i) ((TABST & win_mask[i]) == 0 && \
|
||||||
|
(TABST & lose_mask[i]) == lose_mask[i])
|
||||||
|
|
||||||
|
/*
|
||||||
|
* N wins over M if the bit is set
|
||||||
|
* M=1 2 3 4 5 6 7
|
||||||
|
* N -------------------------
|
||||||
|
* 0| 0 1 2 3 4 5 6
|
||||||
|
* 1| 7 8 9 10 11 12
|
||||||
|
* 2| 13 14 15 16 17
|
||||||
|
* 3| 18 19 20 21
|
||||||
|
* 4| 22 23 24
|
||||||
|
* 5| 25 26
|
||||||
|
* 6| 27
|
||||||
|
*/
|
||||||
|
|
||||||
|
static unsigned win_mask[8] = {
|
||||||
|
0177,
|
||||||
|
0077 << 7,
|
||||||
|
0037 << 13,
|
||||||
|
0017 << 18,
|
||||||
|
0007 << 22,
|
||||||
|
0003 << 25,
|
||||||
|
0001 << 27,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned lose_mask[8] = {
|
||||||
|
0,
|
||||||
|
1<<0,
|
||||||
|
1<<1|1<<7,
|
||||||
|
1<<2|1<<8|1<<13,
|
||||||
|
1<<3|1<<9|1<<14|1<<18,
|
||||||
|
1<<4|1<<10|1<<15|1<<19|1<<22,
|
||||||
|
1<<5|1<<11|1<<16|1<<20|1<<23|1<<25,
|
||||||
|
1<<6|1<<12|1<<17|1<<21|1<<24|1<<26|1<<27
|
||||||
|
};
|
||||||
|
|
||||||
|
#define set_wins(i) TABST = (TABST & ~lose_mask[i]) | win_mask[i]
|
||||||
|
|
||||||
|
void mmu_protection_check (int addr)
|
||||||
|
{
|
||||||
|
/* Защита блокируется в режиме супервизора для физических (!) адресов 1-7 (ТО-8) - WTF? */
|
||||||
|
int tmp_prot_disabled = (M[PSW] & PSW_PROT_DISABLE) ||
|
||||||
|
(IS_SUPERVISOR (RUU) && (M[PSW] & PSW_MMAP_DISABLE) && addr < 010);
|
||||||
|
|
||||||
|
/* Защита не заблокирована, а лист закрыт */
|
||||||
|
if (! tmp_prot_disabled && (RZ & (1 << (addr >> 10)))) {
|
||||||
|
iintr_data = addr >> 10;
|
||||||
|
if (mmu_dev.dctrl)
|
||||||
|
besm6_debug ("--- (%05o) защита числа", addr);
|
||||||
|
longjmp (cpu_halt, STOP_OPERAND_PROT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_flush (int idx)
|
||||||
|
{
|
||||||
|
if (! BAZ[idx]) {
|
||||||
|
/* Был пуст после сброса или выталкивания */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Вычисляем физический адрес выталкиваемого БРЗ */
|
||||||
|
int waddr = BAZ[idx];
|
||||||
|
waddr = (waddr > 0100000) ? (waddr - 0100000) :
|
||||||
|
(waddr & 01777) | (TLB[waddr >> 10] << 10);
|
||||||
|
memory[waddr] = BRZ[idx];
|
||||||
|
BAZ[idx] = 0;
|
||||||
|
if (sim_log && mmu_dev.dctrl) {
|
||||||
|
fprintf (sim_log, "--- (%05o) запись ", waddr);
|
||||||
|
fprint_sym (sim_log, 0, &BRZ[idx], 0, 0);
|
||||||
|
fprintf (sim_log, " из БРЗ[%d]\n", idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_update_oldest ()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (loses_to_all(i)) {
|
||||||
|
OLDEST = i;
|
||||||
|
// fprintf(stderr, "Oldest = %d\r\n", i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mmu_match (int addr, int fail)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (addr == BAZ[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Разнообразные алгоритмы выталкивания БРЗ путем записи
|
||||||
|
* по адресам пультовых регистров. Тест УУ проходит дальше всего
|
||||||
|
* с mmu_flush_by_age().
|
||||||
|
*/
|
||||||
|
void mmu_flush_by_age()
|
||||||
|
{
|
||||||
|
switch (FLUSH) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1 ... 8:
|
||||||
|
set_wins (OLDEST);
|
||||||
|
mmu_update_oldest ();
|
||||||
|
mmu_flush (OLDEST);
|
||||||
|
if (FLUSH == 7) {
|
||||||
|
TABST = 0;
|
||||||
|
OLDEST = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++FLUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_flush_by_number()
|
||||||
|
{
|
||||||
|
switch (FLUSH) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1 ... 8:
|
||||||
|
mmu_flush (FLUSH-1);
|
||||||
|
set_wins (FLUSH-1);
|
||||||
|
if (FLUSH-1 == OLDEST)
|
||||||
|
mmu_update_oldest ();
|
||||||
|
if (FLUSH == 7) {
|
||||||
|
TABST = 0;
|
||||||
|
OLDEST = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++FLUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Запись слова в память
|
||||||
|
*/
|
||||||
|
void mmu_store (int addr, t_value val)
|
||||||
|
{
|
||||||
|
int matching;
|
||||||
|
|
||||||
|
addr &= BITS(15);
|
||||||
|
if (addr == 0)
|
||||||
|
return;
|
||||||
|
if (sim_log && mmu_dev.dctrl) {
|
||||||
|
fprintf (sim_log, "--- (%05o) запись ", addr);
|
||||||
|
fprint_sym (sim_log, 0, &val, 0, 0);
|
||||||
|
fprintf (sim_log, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
mmu_protection_check (addr);
|
||||||
|
|
||||||
|
/* Различаем адреса с припиской и без */
|
||||||
|
if (M[PSW] & PSW_MMAP_DISABLE)
|
||||||
|
addr |= 0100000;
|
||||||
|
|
||||||
|
/* ЗПСЧ: ЗП */
|
||||||
|
if (M[DWP] == addr && (M[PSW] & PSW_WRITE_WATCH))
|
||||||
|
longjmp(cpu_halt, STOP_STORE_ADDR_MATCH);
|
||||||
|
|
||||||
|
if (sim_brk_summ & SWMASK('W') &&
|
||||||
|
sim_brk_test (addr, SWMASK('W')))
|
||||||
|
longjmp(cpu_halt, STOP_WWATCH);
|
||||||
|
|
||||||
|
if (!(mmu_unit.flags & CACHE_ENB)) {
|
||||||
|
static int roundrobin;
|
||||||
|
int faked = (++roundrobin ^ addr ^ val) & 7;
|
||||||
|
|
||||||
|
if (addr > 0100000 && addr < 0100010)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BRZ[faked] = SET_CONVOL (val, RUU ^ CONVOL_INSN);
|
||||||
|
BAZ[faked] = addr;
|
||||||
|
mmu_flush (faked);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Запись в тумблерные регистры - выталкивание БРЗ */
|
||||||
|
if (addr > 0100000 && addr < 0100010) {
|
||||||
|
mmu_flush_by_age();
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
FLUSH = 0;
|
||||||
|
|
||||||
|
matching = mmu_match(addr, OLDEST);
|
||||||
|
|
||||||
|
BRZ[matching] = SET_CONVOL (val, RUU ^ CONVOL_INSN);
|
||||||
|
BAZ[matching] = addr;
|
||||||
|
set_wins (matching);
|
||||||
|
|
||||||
|
if (matching == OLDEST) {
|
||||||
|
mmu_update_oldest ();
|
||||||
|
mmu_flush (OLDEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_value mmu_memaccess (int addr)
|
||||||
|
{
|
||||||
|
t_value val;
|
||||||
|
|
||||||
|
/* Вычисляем физический адрес слова */
|
||||||
|
addr = (addr > 0100000) ? (addr - 0100000) :
|
||||||
|
(addr & 01777) | (TLB[addr >> 10] << 10);
|
||||||
|
if (addr >= 010) {
|
||||||
|
/* Из памяти */
|
||||||
|
val = memory[addr];
|
||||||
|
} else {
|
||||||
|
/* С тумблерных регистров */
|
||||||
|
if (mmu_dev.dctrl)
|
||||||
|
besm6_debug("--- (%05o) чтение ТР%o", PC, addr);
|
||||||
|
val = pult[addr];
|
||||||
|
}
|
||||||
|
if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) {
|
||||||
|
fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15));
|
||||||
|
fprint_sym (sim_log, 0, &val, 0, 0);
|
||||||
|
fprintf (sim_log, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* На тумблерных регистрах контроля числа не бывает */
|
||||||
|
if (addr >= 010 && ! IS_NUMBER (val)) {
|
||||||
|
iintr_data = addr & 7;
|
||||||
|
besm6_debug ("--- (%05o) контроль числа", addr);
|
||||||
|
longjmp (cpu_halt, STOP_RAM_CHECK);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Чтение операнда
|
||||||
|
*/
|
||||||
|
t_value mmu_load (int addr)
|
||||||
|
{
|
||||||
|
int matching = -1;
|
||||||
|
t_value val;
|
||||||
|
|
||||||
|
addr &= BITS(15);
|
||||||
|
if (addr == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mmu_protection_check (addr);
|
||||||
|
|
||||||
|
/* Различаем адреса с припиской и без */
|
||||||
|
if (M[PSW] & PSW_MMAP_DISABLE)
|
||||||
|
addr |= 0100000;
|
||||||
|
|
||||||
|
/* ЗПСЧ: СЧ */
|
||||||
|
if (M[DWP] == addr && !(M[PSW] & PSW_WRITE_WATCH))
|
||||||
|
longjmp(cpu_halt, STOP_LOAD_ADDR_MATCH);
|
||||||
|
|
||||||
|
if (sim_brk_summ & SWMASK('R') &&
|
||||||
|
sim_brk_test (addr, SWMASK('R')))
|
||||||
|
longjmp(cpu_halt, STOP_RWATCH);
|
||||||
|
|
||||||
|
if (!(mmu_unit.flags & CACHE_ENB)) {
|
||||||
|
return mmu_memaccess (addr) & BITS48;
|
||||||
|
}
|
||||||
|
|
||||||
|
matching = mmu_match(addr, -1);
|
||||||
|
|
||||||
|
if (matching == -1) {
|
||||||
|
val = mmu_memaccess (addr);
|
||||||
|
} else {
|
||||||
|
/* старшинство обновляется, только если оно не затрагивает
|
||||||
|
* старший БРЗ (ТО-2).
|
||||||
|
*/
|
||||||
|
if (matching != OLDEST)
|
||||||
|
set_wins (matching);
|
||||||
|
val = BRZ[matching];
|
||||||
|
if (sim_log && (mmu_dev.dctrl || (cpu_dev.dctrl && sim_deb))) {
|
||||||
|
fprintf (sim_log, "--- (%05o) чтение ", addr & BITS(15));
|
||||||
|
fprint_sym (sim_log, 0, &val, 0, 0);
|
||||||
|
fprintf (sim_log, " из БРЗ\n");
|
||||||
|
}
|
||||||
|
if (! IS_NUMBER (val)) {
|
||||||
|
iintr_data = matching;
|
||||||
|
besm6_debug ("--- (%05o) контроль числа БРЗ", addr);
|
||||||
|
longjmp (cpu_halt, STOP_CACHE_CHECK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val & BITS48;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A little BRS LRU table */
|
||||||
|
#define brs_loses_to_all(i) ((BRSLRU & brs_win_mask[i]) == 0 && \
|
||||||
|
(BRSLRU & brs_lose_mask[i]) == brs_lose_mask[i])
|
||||||
|
|
||||||
|
/*
|
||||||
|
* N wins over M if the bit is set
|
||||||
|
* M=1 2 3
|
||||||
|
* N ---------
|
||||||
|
* 0| 0 1 2
|
||||||
|
* 1| 3 4
|
||||||
|
* 2| 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
static unsigned brs_win_mask[4] = {
|
||||||
|
07,
|
||||||
|
03 << 3,
|
||||||
|
01 << 5,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned brs_lose_mask[8] = {
|
||||||
|
0,
|
||||||
|
1<<0,
|
||||||
|
1<<1|1<<3,
|
||||||
|
1<<2|1<<4|1<<5
|
||||||
|
};
|
||||||
|
|
||||||
|
#define brs_set_wins(i) BRSLRU = (BRSLRU & ~brs_lose_mask[i]) | brs_win_mask[i]
|
||||||
|
|
||||||
|
void mmu_fetch_check (int addr)
|
||||||
|
{
|
||||||
|
/* В режиме супервизора защиты нет */
|
||||||
|
if (! IS_SUPERVISOR(RUU)) {
|
||||||
|
int page = TLB[addr >> 10];
|
||||||
|
/*
|
||||||
|
* Для команд в режиме пользователя признак защиты -
|
||||||
|
* 0 в регистре приписки.
|
||||||
|
*/
|
||||||
|
if (page == 0) {
|
||||||
|
iintr_data = addr >> 10;
|
||||||
|
if (mmu_dev.dctrl)
|
||||||
|
besm6_debug ("--- (%05o) защита команды", addr);
|
||||||
|
longjmp (cpu_halt, STOP_INSN_PROT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Предвыборка команды на БРС
|
||||||
|
*/
|
||||||
|
t_value mmu_prefetch (int addr, int actual)
|
||||||
|
{
|
||||||
|
t_value val;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (mmu_unit.flags & CACHE_ENB) {
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
if (BAS[i] == addr) {
|
||||||
|
if (actual) {
|
||||||
|
brs_set_wins (i);
|
||||||
|
}
|
||||||
|
return BRS[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
if (brs_loses_to_all (i)) {
|
||||||
|
BAS[i] = addr;
|
||||||
|
if (actual) {
|
||||||
|
brs_set_wins (i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!actual) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/* Чтобы лампочки мигали */
|
||||||
|
i = addr & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr < 0100000) {
|
||||||
|
int page = TLB[addr >> 10];
|
||||||
|
|
||||||
|
/* Вычисляем физический адрес слова */
|
||||||
|
addr = (addr & 01777) | (page << 10);
|
||||||
|
} else {
|
||||||
|
addr = addr & BITS(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr < 010)
|
||||||
|
val = pult[addr];
|
||||||
|
else
|
||||||
|
val = memory[addr];
|
||||||
|
BRS[i] = val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Выборка команды
|
||||||
|
*/
|
||||||
|
t_value mmu_fetch (int addr)
|
||||||
|
{
|
||||||
|
t_value val;
|
||||||
|
|
||||||
|
if (addr == 0) {
|
||||||
|
if (mmu_dev.dctrl)
|
||||||
|
besm6_debug ("--- передача управления на 0");
|
||||||
|
longjmp (cpu_halt, STOP_INSN_CHECK);
|
||||||
|
}
|
||||||
|
|
||||||
|
mmu_fetch_check(addr);
|
||||||
|
|
||||||
|
/* Различаем адреса с припиской и без */
|
||||||
|
if (IS_SUPERVISOR (RUU))
|
||||||
|
addr |= 0100000;
|
||||||
|
|
||||||
|
/* КРА */
|
||||||
|
if (M[IBP] == addr)
|
||||||
|
longjmp(cpu_halt, STOP_INSN_ADDR_MATCH);
|
||||||
|
|
||||||
|
val = mmu_prefetch(addr, 1);
|
||||||
|
|
||||||
|
if (sim_log && mmu_dev.dctrl) {
|
||||||
|
fprintf (sim_log, "--- (%05o) выборка ", addr);
|
||||||
|
fprint_sym (sim_log, 0, &val, 0, SWMASK ('I'));
|
||||||
|
fprintf (sim_log, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Тумблерные регистры пока только с командной сверткой */
|
||||||
|
if (addr >= 010 && ! IS_INSN (val)) {
|
||||||
|
besm6_debug ("--- (%05o) контроль команды", addr);
|
||||||
|
longjmp (cpu_halt, STOP_INSN_CHECK);
|
||||||
|
}
|
||||||
|
return val & BITS48;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_setrp (int idx, t_value val)
|
||||||
|
{
|
||||||
|
uint32 p0, p1, p2, p3;
|
||||||
|
const uint32 mask = (MEMSIZE >> 10) - 1;
|
||||||
|
|
||||||
|
/* Младшие 5 разрядов 4-х регистров приписки упакованы
|
||||||
|
* по 5 в 1-20 рр, 6-е разряды - в 29-32 рр, 7-е разряды - в 33-36 рр и т.п.
|
||||||
|
*/
|
||||||
|
p0 = (val & 037) | (((val>>28) & 1) << 5) | (((val>>32) & 1) << 6) |
|
||||||
|
(((val>>36) & 1) << 7) | (((val>>40) & 1) << 8) | (((val>>44) & 1) << 9);
|
||||||
|
p1 = ((val>>5) & 037) | (((val>>29) & 1) << 5) | (((val>>33) & 1) << 6) |
|
||||||
|
(((val>>37) & 1) << 7) | (((val>>41) & 1) << 8) | (((val>>45) & 1) << 9);
|
||||||
|
p2 = ((val>>10) & 037) | (((val>>30) & 1) << 5) | (((val>>34) & 1) << 6) |
|
||||||
|
(((val>>38) & 1) << 7) | (((val>>42) & 1) << 8) | (((val>>46) & 1) << 9);
|
||||||
|
p3 = ((val>>15) & 037) | (((val>>31) & 1) << 5) | (((val>>35) & 1) << 6) |
|
||||||
|
(((val>>39) & 1) << 7) | (((val>>43) & 1) << 8) | (((val>>47) & 1) << 9);
|
||||||
|
|
||||||
|
p0 &= mask;
|
||||||
|
p1 &= mask;
|
||||||
|
p2 &= mask;
|
||||||
|
p3 &= mask;
|
||||||
|
|
||||||
|
RP[idx] = p0 | p1 << 12 | p2 << 24 | (t_value) p3 << 36;
|
||||||
|
TLB[idx*4] = p0;
|
||||||
|
TLB[idx*4+1] = p1;
|
||||||
|
TLB[idx*4+2] = p2;
|
||||||
|
TLB[idx*4+3] = p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_setup ()
|
||||||
|
{
|
||||||
|
const uint32 mask = (MEMSIZE >> 10) - 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Перепись РПi в TLBj. */
|
||||||
|
for (i=0; i<8; ++i) {
|
||||||
|
TLB[i*4] = RP[i] & mask;
|
||||||
|
TLB[i*4+1] = RP[i] >> 12 & mask;
|
||||||
|
TLB[i*4+2] = RP[i] >> 24 & mask;
|
||||||
|
TLB[i*4+3] = RP[i] >> 36 & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_setprotection (int idx, t_value val)
|
||||||
|
{
|
||||||
|
/* Разряды сумматора, записываемые в регистр защиты - 21-28 */
|
||||||
|
int mask = 0xff << (idx * 8);
|
||||||
|
val = ((val >> 20) & 0xff) << (idx * 8);
|
||||||
|
RZ = (RZ & ~mask) | val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_setcache (int idx, t_value val)
|
||||||
|
{
|
||||||
|
BRZ[idx] = SET_CONVOL (val, RUU ^ CONVOL_INSN);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_value mmu_getcache (int idx)
|
||||||
|
{
|
||||||
|
return BRZ[idx] & BITS48;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_print_brz ()
|
||||||
|
{
|
||||||
|
int i, k;
|
||||||
|
|
||||||
|
for (i=7; i>=0; --i) {
|
||||||
|
besm6_log_cont ("БРЗ [%d] = '", i);
|
||||||
|
for (k=47; k>=0; --k)
|
||||||
|
besm6_log_cont ("%c", (BRZ[i] >> k & 1) ? '*' : ' ');
|
||||||
|
besm6_log ("'");
|
||||||
|
}
|
||||||
|
}
|
594
BESM6/besm6_panel.c
Normal file
594
BESM6/besm6_panel.c
Normal file
|
@ -0,0 +1,594 @@
|
||||||
|
/*
|
||||||
|
* Panel of BESM-6, displayed as a graphics window.
|
||||||
|
* Using libSDL for graphics and libSDL_ttf for fonts.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Serge Vakulenko
|
||||||
|
* Copyright (c) 2014, Leonid Broukhis
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||||
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||||
|
* OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
* Except as contained in this notice, the name of Leonid Broukhis or
|
||||||
|
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||||||
|
* the sale, use or other dealings in this Software without prior written
|
||||||
|
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_LIBSDL
|
||||||
|
|
||||||
|
#include "besm6_defs.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use a 640x480 window with 32 bit pixels.
|
||||||
|
*/
|
||||||
|
#define WIDTH 800
|
||||||
|
#define HEIGHT 400
|
||||||
|
#define DEPTH 32
|
||||||
|
|
||||||
|
#define STEPX 14
|
||||||
|
#define STEPY 16
|
||||||
|
|
||||||
|
#define FONTNAME "LucidaSansRegular.ttf"
|
||||||
|
#define FONTPATH1 "/usr/share/fonts"
|
||||||
|
#define FONTPATH2 "/usr/lib/jvm"
|
||||||
|
#define FONTPATH3 "/System/Library/Frameworks/JavaVM.framework/Versions"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_ttf.h>
|
||||||
|
|
||||||
|
/* Data and functions that don't depend on SDL version */
|
||||||
|
static char *font_path;
|
||||||
|
static TTF_Font *font_big;
|
||||||
|
static TTF_Font *font_small;
|
||||||
|
static SDL_Color foreground;
|
||||||
|
static SDL_Color background;
|
||||||
|
static const SDL_Color white = { 255, 255, 255 };
|
||||||
|
static const SDL_Color black = { 0, 0, 0 };
|
||||||
|
static const SDL_Color cyan = { 0, 128, 128 };
|
||||||
|
static const SDL_Color grey = { 64, 64, 64 };
|
||||||
|
static t_value old_BRZ [8], old_GRP [2];
|
||||||
|
static t_value old_M [NREGS];
|
||||||
|
|
||||||
|
static const int regnum[] = {
|
||||||
|
013, 012, 011, 010, 7, 6, 5, 4,
|
||||||
|
027, 016, 015, 014, 3, 2, 1, 020,
|
||||||
|
};
|
||||||
|
|
||||||
|
static SDL_Surface *screen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Рисование текста в кодировке UTF-8, с антиалиасингом.
|
||||||
|
* Параметр halign задаёт выравнивание по горизонтали.
|
||||||
|
* Цвета заданы глобальными переменными foreground и background.
|
||||||
|
*/
|
||||||
|
static void render_utf8 (TTF_Font *font, int x, int y, int halign, char *message)
|
||||||
|
{
|
||||||
|
SDL_Surface *text;
|
||||||
|
SDL_Rect area;
|
||||||
|
|
||||||
|
/* Build image from text */
|
||||||
|
text = TTF_RenderUTF8_Shaded (font, message, foreground, background);
|
||||||
|
|
||||||
|
area.x = x;
|
||||||
|
if (halign < 0)
|
||||||
|
area.x -= text->w; /* align left */
|
||||||
|
else if (halign == 0)
|
||||||
|
area.x -= text->w / 2; /* center */
|
||||||
|
area.y = y;
|
||||||
|
area.w = text->w;
|
||||||
|
area.h = text->h;
|
||||||
|
|
||||||
|
/* Put text image to screen */
|
||||||
|
SDL_BlitSurface (text, 0, screen, &area);
|
||||||
|
SDL_FreeSurface (text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_Surface *sprite_from_data (int width, int height,
|
||||||
|
const unsigned char *data)
|
||||||
|
{
|
||||||
|
SDL_Surface *sprite, *optimized;
|
||||||
|
unsigned *s, r, g, b, y, x;
|
||||||
|
|
||||||
|
sprite = SDL_CreateRGBSurface (SDL_SWSURFACE,
|
||||||
|
width, height, DEPTH, 0, 0, 0, 0);
|
||||||
|
/*
|
||||||
|
optimized = SDL_DisplayFormat (sprite);
|
||||||
|
SDL_FreeSurface (sprite);
|
||||||
|
sprite = optimized;
|
||||||
|
*/
|
||||||
|
SDL_LockSurface (sprite);
|
||||||
|
for (y=0; y<height; ++y) {
|
||||||
|
s = (unsigned*) (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Рисуем неонку.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отрисовка лампочек БРЗ.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отрисовка лампочек ГРП и МГРП.
|
||||||
|
*/
|
||||||
|
static void draw_grp_periodic (int top)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
t_value val;
|
||||||
|
|
||||||
|
for (y=0; y<2; ++y) {
|
||||||
|
val = y ? MGRP : GRP;
|
||||||
|
if (val == old_GRP [y])
|
||||||
|
continue;
|
||||||
|
old_GRP [y] = val;
|
||||||
|
for (x=0; x<48; ++x) {
|
||||||
|
draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отрисовка лампочек БРЗ.
|
||||||
|
*/
|
||||||
|
static void draw_brz_periodic (int top)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
t_value val;
|
||||||
|
|
||||||
|
for (y=0; y<8; ++y) {
|
||||||
|
val = BRZ [7-y];
|
||||||
|
if (val == old_BRZ [7-y])
|
||||||
|
continue;
|
||||||
|
old_BRZ [7-y] = val;
|
||||||
|
for (x=0; x<48; ++x) {
|
||||||
|
draw_lamp (100 + x*STEPX, top+28 + y*STEPY, val >> (47-x) & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отрисовка статичной части регистров-модификаторов.
|
||||||
|
*/
|
||||||
|
static void draw_modifiers_static (int group, int left, int top)
|
||||||
|
{
|
||||||
|
int x, y, color, reg;
|
||||||
|
char message [40];
|
||||||
|
SDL_Rect area;
|
||||||
|
|
||||||
|
background = black;
|
||||||
|
foreground = cyan;
|
||||||
|
|
||||||
|
/* Оттеняем группы разрядов. */
|
||||||
|
color = grey.r << 16 | grey.g << 8 | grey.b;
|
||||||
|
for (x=3; x<15; x+=3) {
|
||||||
|
area.x = left + 74 + x*STEPX;
|
||||||
|
area.y = top + 26;
|
||||||
|
area.w = 2;
|
||||||
|
area.h = 8*STEPY + 2;
|
||||||
|
SDL_FillRect (screen, &area, color);
|
||||||
|
}
|
||||||
|
/* Названия регистров. */
|
||||||
|
for (y=0; y<8; ++y) {
|
||||||
|
reg = regnum [y + group*8];
|
||||||
|
sprintf (message, "М%2o", reg);
|
||||||
|
render_utf8 (font_big, left, top + 24 + y*STEPY, 1, message);
|
||||||
|
old_M [reg] = ~0;
|
||||||
|
}
|
||||||
|
/* Номера битов. */
|
||||||
|
for (x=0; x<15; ++x) {
|
||||||
|
sprintf (message, "%d", 15-x);
|
||||||
|
render_utf8 (font_small, left+82 + x*STEPX,
|
||||||
|
(x & 1) ? top+4 : top+10, 0, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отрисовка статичной части регистров ГРП и МГРП.
|
||||||
|
*/
|
||||||
|
static void draw_grp_static (int top)
|
||||||
|
{
|
||||||
|
int x, y, color;
|
||||||
|
char message [40];
|
||||||
|
SDL_Rect area;
|
||||||
|
|
||||||
|
background = black;
|
||||||
|
foreground = cyan;
|
||||||
|
|
||||||
|
/* Оттеняем группы разрядов. */
|
||||||
|
color = grey.r << 16 | grey.g << 8 | grey.b;
|
||||||
|
for (x=3; x<48; x+=3) {
|
||||||
|
area.x = 98 + x*STEPX;
|
||||||
|
area.y = top + 26;
|
||||||
|
area.w = 2;
|
||||||
|
area.h = 2*STEPY + 2;
|
||||||
|
SDL_FillRect (screen, &area, color);
|
||||||
|
}
|
||||||
|
/* Названия регистров. */
|
||||||
|
for (y=0; y<2; ++y) {
|
||||||
|
render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, y ? "МГРП" : "ГРП");
|
||||||
|
old_GRP[y] = ~0;
|
||||||
|
}
|
||||||
|
/* Номера битов. */
|
||||||
|
for (x=0; x<48; ++x) {
|
||||||
|
sprintf (message, "%d", 48-x);
|
||||||
|
render_utf8 (font_small, 106 + x*STEPX,
|
||||||
|
(x & 1) ? top+10 : top+4, 0, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Отрисовка статичной части регистров БРЗ.
|
||||||
|
*/
|
||||||
|
static void draw_brz_static (int top)
|
||||||
|
{
|
||||||
|
int x, y, color;
|
||||||
|
char message [40];
|
||||||
|
SDL_Rect area;
|
||||||
|
|
||||||
|
background = black;
|
||||||
|
foreground = cyan;
|
||||||
|
|
||||||
|
/* Оттеняем группы разрядов. */
|
||||||
|
color = grey.r << 16 | grey.g << 8 | grey.b;
|
||||||
|
for (x=3; x<48; x+=3) {
|
||||||
|
area.x = 98 + x*STEPX;
|
||||||
|
area.y = top + 26;
|
||||||
|
area.w = 2;
|
||||||
|
area.h = 8*STEPY + 2;
|
||||||
|
SDL_FillRect (screen, &area, color);
|
||||||
|
}
|
||||||
|
/* Названия регистров. */
|
||||||
|
for (y=7; y>=0; --y) {
|
||||||
|
sprintf (message, "БРЗ %d", 7-y);
|
||||||
|
render_utf8 (font_big, 24, top + 24 + y*STEPY, 1, message);
|
||||||
|
old_BRZ[y] = ~0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Поиск файла шрифта по имени.
|
||||||
|
*/
|
||||||
|
static int probe_font (const char *path, const struct stat *st, int flag)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if (flag != FTW_F)
|
||||||
|
return 0;
|
||||||
|
p = path + strlen (path) - strlen (FONTNAME);
|
||||||
|
if (p < path || strcmp (p, FONTNAME) != 0)
|
||||||
|
return 0;
|
||||||
|
font_path = strdup (path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Закрываем графическое окно.
|
||||||
|
*/
|
||||||
|
void besm6_close_panel ()
|
||||||
|
{
|
||||||
|
if (! screen)
|
||||||
|
return;
|
||||||
|
TTF_Quit();
|
||||||
|
SDL_Quit();
|
||||||
|
screen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION == 2
|
||||||
|
|
||||||
|
static SDL_Window *sdlWindow;
|
||||||
|
static SDL_Renderer *sdlRenderer;
|
||||||
|
static SDL_Texture *sdlTexture;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Начальная инициализация графического окна и шрифтов.
|
||||||
|
*/
|
||||||
|
static void init_panel ()
|
||||||
|
{
|
||||||
|
if (sim_switches & SWMASK('Q'))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Initialize SDL subsystems - in this case, only video. */
|
||||||
|
if (SDL_Init (SDL_INIT_VIDEO) < 0) {
|
||||||
|
fprintf (stderr, "SDL: unable to init: %s\n",
|
||||||
|
SDL_GetError ());
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
sdlWindow = SDL_CreateWindow ("BESM-6 panel",
|
||||||
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
WIDTH, HEIGHT, 0 /* regular window */);
|
||||||
|
if (! sdlWindow) {
|
||||||
|
fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n",
|
||||||
|
WIDTH, HEIGHT, DEPTH, SDL_GetError ());
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
|
||||||
|
/* Make black background */
|
||||||
|
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(sdlRenderer);
|
||||||
|
|
||||||
|
/* Initialize the TTF library */
|
||||||
|
if (TTF_Init() < 0) {
|
||||||
|
fprintf (stderr, "SDL: couldn't initialize TTF: %s\n",
|
||||||
|
SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find font file */
|
||||||
|
if (ftw (FONTPATH1, probe_font, 255) <= 0 &&
|
||||||
|
ftw (FONTPATH2, probe_font, 255) <= 0 &&
|
||||||
|
ftw (FONTPATH3, probe_font, 255) <= 0) {
|
||||||
|
fprintf(stderr, "SDL: couldn't find font %s in directory %s\n",
|
||||||
|
FONTNAME, FONTPATH1);
|
||||||
|
besm6_close_panel();
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the font file with the requested point size */
|
||||||
|
font_big = TTF_OpenFont (font_path, 16);
|
||||||
|
font_small = TTF_OpenFont (font_path, 9);
|
||||||
|
if (! font_big || ! font_small) {
|
||||||
|
fprintf(stderr, "SDL: couldn't load font %s: %s\n",
|
||||||
|
font_path, SDL_GetError());
|
||||||
|
besm6_close_panel();
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
atexit (besm6_close_panel);
|
||||||
|
|
||||||
|
screen = SDL_CreateRGBSurface(0, WIDTH, HEIGHT, 32,
|
||||||
|
0x00FF0000,
|
||||||
|
0x0000FF00,
|
||||||
|
0x000000FF,
|
||||||
|
0xFF000000);
|
||||||
|
|
||||||
|
sdlTexture = SDL_CreateTexture(sdlRenderer,
|
||||||
|
SDL_PIXELFORMAT_ARGB8888,
|
||||||
|
SDL_TEXTUREACCESS_STATIC,
|
||||||
|
WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
/* Отрисовка статичной части панели БЭСМ-6. */
|
||||||
|
draw_modifiers_static (0, 24, 10);
|
||||||
|
draw_modifiers_static (1, 400, 10);
|
||||||
|
draw_grp_static (180);
|
||||||
|
draw_brz_static (230);
|
||||||
|
|
||||||
|
/* Tell SDL to update the whole screen */
|
||||||
|
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
|
||||||
|
SDL_RenderClear(sdlRenderer);
|
||||||
|
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
|
||||||
|
SDL_RenderPresent (sdlRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*sim_vm_init)() = init_panel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Обновляем графическое окно.
|
||||||
|
*/
|
||||||
|
void besm6_draw_panel ()
|
||||||
|
{
|
||||||
|
if (! screen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Периодическая отрисовка: мигание лампочек. */
|
||||||
|
draw_modifiers_periodic (0, 24, 10);
|
||||||
|
draw_modifiers_periodic (1, 400, 10);
|
||||||
|
draw_grp_periodic (180);
|
||||||
|
draw_brz_periodic (230);
|
||||||
|
|
||||||
|
/* Tell SDL to update the whole screen */
|
||||||
|
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
|
||||||
|
SDL_RenderClear(sdlRenderer);
|
||||||
|
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
|
||||||
|
SDL_RenderPresent (sdlRenderer);
|
||||||
|
|
||||||
|
/* Exit SIMH when window closed.*/
|
||||||
|
SDL_Event event;
|
||||||
|
if (SDL_PollEvent (&event) && event.type == SDL_QUIT)
|
||||||
|
longjmp (cpu_halt, SCPE_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Начальная инициализация графического окна и шрифтов.
|
||||||
|
*/
|
||||||
|
static void init_panel ()
|
||||||
|
{
|
||||||
|
if (sim_switches & SWMASK('Q'))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Initialize SDL subsystems - in this case, only video. */
|
||||||
|
if (SDL_Init (SDL_INIT_VIDEO) < 0) {
|
||||||
|
fprintf (stderr, "SDL: unable to init: %s\n",
|
||||||
|
SDL_GetError ());
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
screen = SDL_SetVideoMode (WIDTH, HEIGHT, DEPTH, SDL_SWSURFACE);
|
||||||
|
if (! screen) {
|
||||||
|
fprintf (stderr, "SDL: unable to set %dx%dx%d mode: %s\n",
|
||||||
|
WIDTH, HEIGHT, DEPTH, SDL_GetError ());
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the TTF library */
|
||||||
|
if (TTF_Init() < 0) {
|
||||||
|
fprintf (stderr, "SDL: couldn't initialize TTF: %s\n",
|
||||||
|
SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find font file */
|
||||||
|
if (ftw (FONTPATH1, probe_font, 255) <= 0 &&
|
||||||
|
ftw (FONTPATH2, probe_font, 255) <= 0 &&
|
||||||
|
ftw (FONTPATH3, probe_font, 255) <= 0) {
|
||||||
|
fprintf(stderr, "SDL: couldn't find font %s in directory %s\n",
|
||||||
|
FONTNAME, FONTPATH1);
|
||||||
|
besm6_close_panel();
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the font file with the requested point size */
|
||||||
|
font_big = TTF_OpenFont (font_path, 16);
|
||||||
|
font_small = TTF_OpenFont (font_path, 9);
|
||||||
|
if (! font_big || ! font_small) {
|
||||||
|
fprintf(stderr, "SDL: couldn't load font %s: %s\n",
|
||||||
|
FONTNAME, TTF_GetError());
|
||||||
|
besm6_close_panel();
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
atexit (besm6_close_panel);
|
||||||
|
|
||||||
|
/* Отрисовка статичной части панели БЭСМ-6. */
|
||||||
|
draw_modifiers_static (0, 24, 10);
|
||||||
|
draw_modifiers_static (1, 400, 10);
|
||||||
|
draw_grp_static (180);
|
||||||
|
draw_brz_static (230);
|
||||||
|
|
||||||
|
/* Tell SDL to update the whole screen */
|
||||||
|
SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*sim_vm_init)() = init_panel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Обновляем графическое окно.
|
||||||
|
*/
|
||||||
|
void besm6_draw_panel ()
|
||||||
|
{
|
||||||
|
if (! screen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Периодическая отрисовка: мигание лампочек. */
|
||||||
|
draw_modifiers_periodic (0, 24, 10);
|
||||||
|
draw_modifiers_periodic (1, 400, 10);
|
||||||
|
draw_grp_periodic (180);
|
||||||
|
draw_brz_periodic (230);
|
||||||
|
|
||||||
|
/* Tell SDL to update the whole screen */
|
||||||
|
SDL_UpdateRect (screen, 0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
/* Exit SIMH when window closed.*/
|
||||||
|
SDL_Event event;
|
||||||
|
if (SDL_PollEvent (&event) && event.type == SDL_QUIT)
|
||||||
|
longjmp (cpu_halt, SCPE_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(__WIN32__) && \
|
||||||
|
!(defined(__MWERKS__) && !defined(__BEOS__)) && \
|
||||||
|
!defined(__MACOS__) && !defined(__MACOSX__) && \
|
||||||
|
!defined(__SYMBIAN32__) && !defined(QWS)
|
||||||
|
#undef main
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Вот так всё непросто.
|
||||||
|
*/
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
extern int SDL_main (int, char**);
|
||||||
|
|
||||||
|
return SDL_main (argc, argv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_MAJOR_VERSION */
|
||||||
|
|
||||||
|
#else /* HAVE_LIBSDL */
|
||||||
|
void besm6_draw_panel ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LIBSDL */
|
345
BESM6/besm6_printer.c
Normal file
345
BESM6/besm6_printer.c
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
/*
|
||||||
|
* besm6_printer.c: BESM-6 line printer device
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Leonid Broukhis
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||||
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||||
|
* OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
* Except as contained in this notice, the name of Leonid Broukhis or
|
||||||
|
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||||||
|
* the sale, use or other dealings in this Software without prior written
|
||||||
|
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||||||
|
*/
|
||||||
|
#include "besm6_defs.h"
|
||||||
|
|
||||||
|
t_stat printer_event (UNIT *u);
|
||||||
|
void offset_gost_write (int num, FILE *fout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printer data structures
|
||||||
|
*
|
||||||
|
* printer_dev PRINTER device descriptor
|
||||||
|
* printer_unit PRINTER unit descriptor
|
||||||
|
* printer_reg PRINTER register list
|
||||||
|
*/
|
||||||
|
UNIT printer_unit [] = {
|
||||||
|
{ UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) },
|
||||||
|
{ UDATA (printer_event, UNIT_ATTABLE+UNIT_SEQ, 0) },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_STRIKES 10
|
||||||
|
struct acpu_t {
|
||||||
|
int curchar, feed, rampup;
|
||||||
|
int strikes;
|
||||||
|
int length;
|
||||||
|
unsigned char line[128][MAX_STRIKES];
|
||||||
|
} acpu[2];
|
||||||
|
|
||||||
|
int acpu_isatty[2];
|
||||||
|
|
||||||
|
#define PRN1_NOT_READY (1<<19)
|
||||||
|
#define PRN2_NOT_READY (1<<18)
|
||||||
|
|
||||||
|
/* 1 = можно пользоваться молоточками, 0 - бумага в процессе протяжки */
|
||||||
|
#define PRN1_LINEFEED (1<<23)
|
||||||
|
#define PRN2_LINEFEED (1<<22)
|
||||||
|
|
||||||
|
#define SLOW_START 100*MSEC
|
||||||
|
#define FAST_START 1*MSEC
|
||||||
|
#define LINEFEED_SYNC 1 /* Чтобы быстрее печатало; в жизни 20-25 мс/1.4 мс ~= 17 */
|
||||||
|
|
||||||
|
REG printer_reg[] = {
|
||||||
|
{ "Готов", &READY, 2, 2, 18, 1 },
|
||||||
|
{ "Прогон", &READY, 2, 2, 22, 1 },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB printer_mod[] = {
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat printer_reset (DEVICE *dptr);
|
||||||
|
t_stat printer_attach (UNIT *uptr, char *cptr);
|
||||||
|
t_stat printer_detach (UNIT *uptr);
|
||||||
|
|
||||||
|
DEVICE printer_dev = {
|
||||||
|
"PRN", printer_unit, printer_reg, printer_mod,
|
||||||
|
2, 8, 19, 1, 8, 50,
|
||||||
|
NULL, NULL, &printer_reset, NULL, &printer_attach, &printer_detach,
|
||||||
|
NULL, DEV_DISABLE | DEV_DEBUG
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset routine
|
||||||
|
*/
|
||||||
|
t_stat printer_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
memset(acpu, 0, sizeof (acpu));
|
||||||
|
acpu[0].rampup = acpu[1].rampup = SLOW_START;
|
||||||
|
sim_cancel (&printer_unit[0]);
|
||||||
|
sim_cancel (&printer_unit[1]);
|
||||||
|
READY |= PRN1_NOT_READY | PRN2_NOT_READY;
|
||||||
|
if (printer_unit[0].flags & UNIT_ATT)
|
||||||
|
READY &= ~PRN1_NOT_READY;
|
||||||
|
if (printer_unit[1].flags & UNIT_ATT)
|
||||||
|
READY &= ~PRN2_NOT_READY;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat printer_attach (UNIT *u, char *cptr)
|
||||||
|
{
|
||||||
|
t_stat s;
|
||||||
|
int num = u - printer_unit;
|
||||||
|
|
||||||
|
if (u->flags & UNIT_ATT) {
|
||||||
|
/* Switching files cleanly */
|
||||||
|
detach_unit (u);
|
||||||
|
}
|
||||||
|
s = attach_unit (u, cptr);
|
||||||
|
if (s != SCPE_OK)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
acpu_isatty[num] = !strcmp(cptr, "/dev/tty");
|
||||||
|
if (!acpu_isatty[num]) {
|
||||||
|
/* Write UTF-8 tag: zero width no-break space. */
|
||||||
|
fputs ("\xEF\xBB\xBF", u->fileref);
|
||||||
|
}
|
||||||
|
|
||||||
|
READY &= ~(PRN1_NOT_READY >> num);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat printer_detach (UNIT *u)
|
||||||
|
{
|
||||||
|
int num = u - printer_unit;
|
||||||
|
READY |= PRN1_NOT_READY >> num;
|
||||||
|
return detach_unit (u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Управление двигателями, прогон
|
||||||
|
*/
|
||||||
|
void printer_control (int num, uint32 cmd)
|
||||||
|
{
|
||||||
|
UNIT *u = &printer_unit[num];
|
||||||
|
struct acpu_t * dev = acpu + num;
|
||||||
|
|
||||||
|
if (printer_dev.dctrl)
|
||||||
|
besm6_debug(">>> АЦПУ%d команда %o", num, cmd);
|
||||||
|
if (READY & (PRN1_NOT_READY >> num)) {
|
||||||
|
if (printer_dev.dctrl)
|
||||||
|
besm6_debug(">>> АЦПУ%d не готово", num, cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (cmd) {
|
||||||
|
case 1: /* linefeed */
|
||||||
|
READY &= ~(PRN1_LINEFEED >> num);
|
||||||
|
offset_gost_write (num, u->fileref);
|
||||||
|
dev->feed = LINEFEED_SYNC;
|
||||||
|
break;
|
||||||
|
case 4: /* start */
|
||||||
|
/* стартуем из состояния прогона для надежности */
|
||||||
|
dev->feed = LINEFEED_SYNC;
|
||||||
|
READY &= ~(PRN1_LINEFEED >> num);
|
||||||
|
if (dev->rampup)
|
||||||
|
sim_activate (u, dev->rampup);
|
||||||
|
dev->rampup = 0;
|
||||||
|
break;
|
||||||
|
case 10: /* motor and ribbon off */
|
||||||
|
case 8: /* motor off? (undocumented) */
|
||||||
|
case 2: /* ribbon off */
|
||||||
|
dev->rampup = cmd == 2 ? FAST_START : SLOW_START;
|
||||||
|
sim_cancel (u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Управление молоточками
|
||||||
|
*/
|
||||||
|
void printer_hammer (int num, int pos, uint32 mask)
|
||||||
|
{
|
||||||
|
struct acpu_t * dev = acpu + num;
|
||||||
|
while (mask) {
|
||||||
|
if (mask & 1) {
|
||||||
|
int strike = 0;
|
||||||
|
while (dev->line[pos][strike] && strike < MAX_STRIKES)
|
||||||
|
++strike;
|
||||||
|
if (strike < MAX_STRIKES) {
|
||||||
|
dev->line[pos][strike] = dev->curchar;
|
||||||
|
if (pos + 1 > dev->length)
|
||||||
|
dev->length = pos + 1;
|
||||||
|
if (strike + 1 > dev->strikes)
|
||||||
|
dev->strikes = strike + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mask >>= 1;
|
||||||
|
pos += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Событие: вращение барабана АЦПУ.
|
||||||
|
* Устанавливаем флаг прерывания.
|
||||||
|
*/
|
||||||
|
t_stat printer_event (UNIT *u)
|
||||||
|
{
|
||||||
|
int num = u - printer_unit;
|
||||||
|
struct acpu_t * dev = acpu + num;
|
||||||
|
|
||||||
|
switch (dev->curchar) {
|
||||||
|
case 0 ... 0137:
|
||||||
|
GRP |= GRP_PRN1_SYNC >> num;
|
||||||
|
++dev->curchar;
|
||||||
|
/* For next char */
|
||||||
|
sim_activate (u, 1400*USEC);
|
||||||
|
if (dev->feed && --dev->feed == 0) {
|
||||||
|
READY |= PRN1_LINEFEED >> num;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0140:
|
||||||
|
/* For "zero" */
|
||||||
|
dev->curchar = 0;
|
||||||
|
GRP |= GRP_PRN1_ZERO >> num;
|
||||||
|
if (printer_dev.dctrl)
|
||||||
|
besm6_debug(">>> АЦПУ%d 'ноль'", num);
|
||||||
|
/* For first sync after "zero" */
|
||||||
|
sim_activate (u, 1000*USEC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gost_latin = 0; /* default cyrillics */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GOST-10859 encoding.
|
||||||
|
* Documentation: http://en.wikipedia.org/wiki/GOST_10859
|
||||||
|
*/
|
||||||
|
static const unsigned short gost_to_unicode_cyr [256] = {
|
||||||
|
/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||||
|
/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423,
|
||||||
|
/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b,
|
||||||
|
/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a,
|
||||||
|
/* 040-047 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
|
||||||
|
/* 050-057 */ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
|
||||||
|
/* 060-067 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
|
||||||
|
/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44,
|
||||||
|
/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52,
|
||||||
|
/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265,
|
||||||
|
/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7,
|
||||||
|
/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned short gost_to_unicode_lat [256] = {
|
||||||
|
/* 000-007 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||||
|
/* 010-017 */ 0x38, 0x39, 0x2b, 0x2d, 0x2f, 0x2c, 0x2e, 0x2423,
|
||||||
|
/* 020-027 */ 0x65, 0x2191, 0x28, 0x29, 0xd7, 0x3d, 0x3b, 0x5b,
|
||||||
|
/* 030-037 */ 0x5d, 0x2a, 0x2018, 0x2019, 0x2260, 0x3c, 0x3e, 0x3a,
|
||||||
|
/* 040-047 */ 0x41, 0x0411, 0x42, 0x0413, 0x0414, 0x45, 0x0416, 0x0417,
|
||||||
|
/* 050-057 */ 0x0418, 0x0419, 0x4b, 0x041b, 0x4d, 0x48, 0x4f, 0x041f,
|
||||||
|
/* 060-067 */ 0x50, 0x43, 0x54, 0x59, 0x0424, 0x58, 0x0426, 0x0427,
|
||||||
|
/* 070-077 */ 0x0428, 0x0429, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x44,
|
||||||
|
/* 100-107 */ 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4e, 0x51, 0x52,
|
||||||
|
/* 110-117 */ 0x53, 0x55, 0x56, 0x57, 0x5a, 0x203e, 0x2264, 0x2265,
|
||||||
|
/* 120-127 */ 0x2228, 0x2227, 0x2283, 0xac, 0xf7, 0x2261, 0x25, 0x25c7,
|
||||||
|
/* 130-137 */ 0x7c, 0x2015, 0x5f, 0x21, 0x22, 0x042a, 0xb0, 0x2032,
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* Write Unicode symbol to file.
|
||||||
|
* Convert to UTF-8 encoding:
|
||||||
|
* 00000000.0xxxxxxx -> 0xxxxxxx
|
||||||
|
* 00000xxx.xxyyyyyy -> 110xxxxx, 10yyyyyy
|
||||||
|
* xxxxyyyy.yyzzzzzz -> 1110xxxx, 10yyyyyy, 10zzzzzz
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
utf8_putc (unsigned short ch, FILE *fout)
|
||||||
|
{
|
||||||
|
if (ch < 0x80) {
|
||||||
|
putc (ch, fout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ch < 0x800) {
|
||||||
|
putc (ch >> 6 | 0xc0, fout);
|
||||||
|
putc ((ch & 0x3f) | 0x80, fout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
putc (ch >> 12 | 0xe0, fout);
|
||||||
|
putc (((ch >> 6) & 0x3f) | 0x80, fout);
|
||||||
|
putc ((ch & 0x3f) | 0x80, fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short
|
||||||
|
gost_to_unicode (unsigned char ch)
|
||||||
|
{
|
||||||
|
return gost_latin ? gost_to_unicode_lat [ch] :
|
||||||
|
gost_to_unicode_cyr [ch];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write GOST-10859 symbol to file.
|
||||||
|
* Convert to local encoding (UTF-8, KOI8-R, CP-1251, CP-866).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gost_putc (unsigned char ch, FILE *fout)
|
||||||
|
{
|
||||||
|
unsigned short u;
|
||||||
|
|
||||||
|
u = gost_to_unicode (ch);
|
||||||
|
if (! u)
|
||||||
|
u = ' ';
|
||||||
|
utf8_putc (u, fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write GOST-10859 string with overprint to file in UTF-8.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
offset_gost_write (int num, FILE *fout)
|
||||||
|
{
|
||||||
|
struct acpu_t * dev = acpu + num;
|
||||||
|
int s, p;
|
||||||
|
for (s = 0; s < dev->strikes; ++s) {
|
||||||
|
if (s)
|
||||||
|
fputc ('\r', fout);
|
||||||
|
for (p = 0; p < dev->length; ++p) {
|
||||||
|
gost_putc (dev->line[p][s] - 1, fout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acpu_isatty[num])
|
||||||
|
fputc('\r', fout);
|
||||||
|
|
||||||
|
fputc ('\n', fout);
|
||||||
|
memset(dev->line, 0, sizeof (dev->line));
|
||||||
|
dev->length = dev->strikes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Выясняем, остановлены ли АЦПУ. Нужно для входа в "спящий" режим.
|
||||||
|
*/
|
||||||
|
int printer_is_idle ()
|
||||||
|
{
|
||||||
|
if ((printer_unit[0].flags & UNIT_ATT) && acpu[0].rampup == 0)
|
||||||
|
return 0;
|
||||||
|
if ((printer_unit[1].flags & UNIT_ATT) && acpu[1].rampup == 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
472
BESM6/besm6_punch.c
Normal file
472
BESM6/besm6_punch.c
Normal file
|
@ -0,0 +1,472 @@
|
||||||
|
/*
|
||||||
|
* besm6_punch.c: BESM-6 punchcard/punchtape devices
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Leonid Broukhis
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||||
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||||
|
* OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
* Except as contained in this notice, the name of Leonid Broukhis or
|
||||||
|
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||||||
|
* the sale, use or other dealings in this Software without prior written
|
||||||
|
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||||||
|
*/
|
||||||
|
#include "besm6_defs.h"
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/fcntl.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;
|
||||||
|
struct stat stbuf;
|
||||||
|
fstat (fileno(u->fileref), &stbuf);
|
||||||
|
isfifo[num] = (stbuf.st_mode & S_IFIFO) != 0;
|
||||||
|
if (isfifo[num]) {
|
||||||
|
int flags = fcntl(fileno(u->fileref), F_GETFL, 0);
|
||||||
|
fcntl(fileno(u->fileref), F_SETFL, flags | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
ENB_RDY(FS1_READY >> num);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat fs_detach (UNIT *u)
|
||||||
|
{
|
||||||
|
int num = u - fs_unit;
|
||||||
|
DIS_RDY(FS1_READY >> num);
|
||||||
|
return detach_unit (u);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Управление двигателем, лампой, протяжкой
|
||||||
|
*/
|
||||||
|
void fs_control (int num, uint32 cmd)
|
||||||
|
{
|
||||||
|
UNIT *u = &fs_unit[num];
|
||||||
|
|
||||||
|
static int bytecnt = 0;
|
||||||
|
if (fs_dev.dctrl)
|
||||||
|
besm6_debug("<<< ФС1500-%d команда %o", num, cmd);
|
||||||
|
if (! IS_RDY(FS1_READY >> num)) {
|
||||||
|
if (fs_dev.dctrl)
|
||||||
|
besm6_debug("<<< ФС1500-%d не готово", num, cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (cmd) {
|
||||||
|
case 0: /* полное выключение */
|
||||||
|
sim_cancel (u);
|
||||||
|
fs_state[num] = FS_IDLE;
|
||||||
|
if (fs_dev.dctrl)
|
||||||
|
besm6_debug("<<<ФС1500-%d ВЫКЛ..", num);
|
||||||
|
bytecnt = 0;
|
||||||
|
break;
|
||||||
|
case 4: /* двигатель без протяжки */
|
||||||
|
fs_state[num] = FS_STARTING;
|
||||||
|
if (fs_dev.dctrl)
|
||||||
|
besm6_debug("<<<ФС1500-%d ВКЛ.", num);
|
||||||
|
sim_cancel (u);
|
||||||
|
break;
|
||||||
|
case 5: /* протяжка */
|
||||||
|
if (fs_state[num] == FS_IDLE)
|
||||||
|
besm6_debug("<<< ФС1500-%d протяжка без мотора", num);
|
||||||
|
else if (fs_state[num] != FS_TAIL) {
|
||||||
|
sim_activate (u, FS_RATE);
|
||||||
|
bytecnt++;
|
||||||
|
} else {
|
||||||
|
if (! isfifo[num]) {
|
||||||
|
fs_detach(u);
|
||||||
|
fs_state[num] = FS_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
besm6_debug ("<<< ФС1500-%d неизвестная команда %o", num, cmd);
|
||||||
|
}
|
||||||
|
if (cmd && fs_dev.dctrl) {
|
||||||
|
besm6_debug("<<<ФС1500-%d: %d симв.", num, bytecnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char unicode_to_gost (unsigned short val);
|
||||||
|
static int utf8_getc (FILE *fin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Событие: читаем очередной символ с перфоленты в регистр.
|
||||||
|
* Устанавливаем флаг прерывания.
|
||||||
|
*/
|
||||||
|
t_stat fs_event (UNIT *u)
|
||||||
|
{
|
||||||
|
int num = u - fs_unit;
|
||||||
|
again:
|
||||||
|
switch (fs_state[num]) {
|
||||||
|
case FS_STARTING:
|
||||||
|
/* По первому прерыванию после запуска двигателя ничего не читаем */
|
||||||
|
FS[num] = 0;
|
||||||
|
fs_state[num] = FS_RUNNING;
|
||||||
|
break;
|
||||||
|
case FS_RUNNING: {
|
||||||
|
int ch;
|
||||||
|
/* переводы строк игнорируются */
|
||||||
|
while ((ch = utf8_getc (u->fileref)) == '\n');
|
||||||
|
if (ch < 0) {
|
||||||
|
/* хвост ленты без пробивок */
|
||||||
|
FS[num] = 0;
|
||||||
|
fs_state[num] = FS_TAIL;
|
||||||
|
} else if (ch == '\f') {
|
||||||
|
fs_state[num] = FS_IMAGE;
|
||||||
|
goto again;
|
||||||
|
} else {
|
||||||
|
ch = FS[num] = unicode_to_gost (ch);
|
||||||
|
ch = (ch & 0x55) + ((ch >> 1) & 0x55);
|
||||||
|
ch = (ch & 0x33) + ((ch >> 2) & 0x33);
|
||||||
|
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
|
||||||
|
if (ch & 1); else FS[num] |= 0x80;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FS_IMAGE ... FS_IMAGE_LAST: {
|
||||||
|
int ch = utf8_getc (u->fileref);
|
||||||
|
if (ch < 0) {
|
||||||
|
/* обрыв ленты */
|
||||||
|
FS[num] = 0;
|
||||||
|
fs_state[num] = FS_TAIL;
|
||||||
|
} else if (ch == '\n') {
|
||||||
|
/* идем дополнять образ карты нулевыми байтами */
|
||||||
|
fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE);
|
||||||
|
goto again;
|
||||||
|
} else if (ch == '\f') {
|
||||||
|
if (fs_state[num] != FS_IMAGE)
|
||||||
|
besm6_debug("<<< ENDA3 requested mid-card?");
|
||||||
|
fs_state[num] = FS_ENDA3;
|
||||||
|
goto again;
|
||||||
|
} else {
|
||||||
|
ch = FS[num] = unicode_to_gost (ch);
|
||||||
|
ch = (ch & 0x55) + ((ch >> 1) & 0x55);
|
||||||
|
ch = (ch & 0x33) + ((ch >> 2) & 0x33);
|
||||||
|
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
|
||||||
|
if (ch & 1); else FS[num] |= 0x80;
|
||||||
|
++fs_state[num];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FS_TOOLONG: {
|
||||||
|
/* дочитываем до конца строки */
|
||||||
|
int ch;
|
||||||
|
besm6_debug("<<< too long???");
|
||||||
|
while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0);
|
||||||
|
if (ch < 0) {
|
||||||
|
/* хвост ленты без пробивок */
|
||||||
|
FS[num] = 0;
|
||||||
|
fs_state[num] = FS_TAIL;
|
||||||
|
} else
|
||||||
|
goto again;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FS_FILLUP ... FS_FILLUP_LAST:
|
||||||
|
FS[num] = 0;
|
||||||
|
if (++fs_state[num] == FS_ENDA3) {
|
||||||
|
fs_state[num] = FS_IMAGE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FS_ENDA3 ... FS_ENDA3_LAST:
|
||||||
|
if ((fs_state[num] - FS_ENDA3) % 5 == 0)
|
||||||
|
FS[num] = 0200;
|
||||||
|
else
|
||||||
|
FS[num] = 0;
|
||||||
|
if (++fs_state[num] == FS_TAIL) {
|
||||||
|
fs_state[num] = FS_RUNNING;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FS_IDLE:
|
||||||
|
case FS_TAIL:
|
||||||
|
FS[num] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GRP |= GRP_FS1_SYNC >> num;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_read(int num) {
|
||||||
|
if (fs_dev.dctrl)
|
||||||
|
besm6_debug("<<< ФС1500-%d: байт %03o", num, FS[num]);
|
||||||
|
|
||||||
|
return FS[num];
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_is_idle (void)
|
||||||
|
{
|
||||||
|
return fs_state[0] == FS_IDLE && fs_state[1] == FS_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
unicode_to_gost (unsigned short val)
|
||||||
|
{
|
||||||
|
static const unsigned char tab0 [256] = {
|
||||||
|
/* 00 - 07 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* 08 - 0f */ 017, 017, 0214, 017, 017, 0174, 017, 017,
|
||||||
|
/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* !"#$%&' */ 0017, 0133, 0134, 0034, 0127, 0126, 0121, 0033,
|
||||||
|
/* ()*+,-./ */ 0022, 0023, 0031, 0012, 0015, 0013, 0016, 0014,
|
||||||
|
/* 01234567 */ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
|
||||||
|
/* 89:;<=>? */ 0010, 0011, 0037, 0026, 0035, 0025, 0036, 0136,
|
||||||
|
/* @ABCDEFG */ 0021, 0040, 0042, 0061, 0077, 0045, 0100, 0101,
|
||||||
|
/* HIJKLMNO */ 0055, 0102, 0103, 0052, 0104, 0054, 0105, 0056,
|
||||||
|
/* PQRSTUVW */ 0060, 0106, 0107, 0110, 0062, 0111, 0112, 0113,
|
||||||
|
/* XYZ[\]^_ */ 0065, 0063, 0114, 0027, 017, 0030, 0115, 0132,
|
||||||
|
/* `abcdefg */ 0032, 0040, 0042, 0061, 0077, 0045, 0100, 0101,
|
||||||
|
/* hijklmno */ 0055, 0102, 0103, 0052, 0104, 0054, 0105, 0056,
|
||||||
|
/* pqrstuvw */ 0060, 0106, 0107, 0110, 0062, 0111, 0112, 0113,
|
||||||
|
/* xyz{|}~ */ 0065, 0063, 0114, 017, 0130, 017, 0123, 017,
|
||||||
|
/* 80 - 87 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* 88 - 8f */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* 90 - 97 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* 98 - 9f */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* a0 - a7 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* a8 - af */ 017, 017, 017, 017, 0123, 017, 017, 017,
|
||||||
|
/* b0 - b7 */ 0136, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* b8 - bf */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* c0 - c7 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* c8 - cf */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* d0 - d7 */ 017, 017, 017, 017, 017, 017, 017, 0024,
|
||||||
|
/* d8 - df */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* e0 - e7 */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* e8 - ef */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
/* f0 - f7 */ 017, 017, 017, 017, 017, 017, 017, 0124,
|
||||||
|
/* f8 - ff */ 017, 017, 017, 017, 017, 017, 017, 017,
|
||||||
|
};
|
||||||
|
switch (val >> 8) {
|
||||||
|
case 0x00:
|
||||||
|
return tab0 [val];
|
||||||
|
case 0x04:
|
||||||
|
switch ((unsigned char) val) {
|
||||||
|
case 0x10: return 0040;
|
||||||
|
case 0x11: return 0041;
|
||||||
|
case 0x12: return 0042;
|
||||||
|
case 0x13: return 0043;
|
||||||
|
case 0x14: return 0044;
|
||||||
|
case 0x15: return 0045;
|
||||||
|
case 0x16: return 0046;
|
||||||
|
case 0x17: return 0047;
|
||||||
|
case 0x18: return 0050;
|
||||||
|
case 0x19: return 0051;
|
||||||
|
case 0x1a: return 0052;
|
||||||
|
case 0x1b: return 0053;
|
||||||
|
case 0x1c: return 0054;
|
||||||
|
case 0x1d: return 0055;
|
||||||
|
case 0x1e: return 0056;
|
||||||
|
case 0x1f: return 0057;
|
||||||
|
case 0x20: return 0060;
|
||||||
|
case 0x21: return 0061;
|
||||||
|
case 0x22: return 0062;
|
||||||
|
case 0x23: return 0063;
|
||||||
|
case 0x24: return 0064;
|
||||||
|
case 0x25: return 0065;
|
||||||
|
case 0x26: return 0066;
|
||||||
|
case 0x27: return 0067;
|
||||||
|
case 0x28: return 0070;
|
||||||
|
case 0x29: return 0071;
|
||||||
|
case 0x2a: return 0135;
|
||||||
|
case 0x2b: return 0072;
|
||||||
|
case 0x2c: return 0073;
|
||||||
|
case 0x2d: return 0074;
|
||||||
|
case 0x2e: return 0075;
|
||||||
|
case 0x2f: return 0076;
|
||||||
|
case 0x30: return 0040;
|
||||||
|
case 0x31: return 0041;
|
||||||
|
case 0x32: return 0042;
|
||||||
|
case 0x33: return 0043;
|
||||||
|
case 0x34: return 0044;
|
||||||
|
case 0x35: return 0045;
|
||||||
|
case 0x36: return 0046;
|
||||||
|
case 0x37: return 0047;
|
||||||
|
case 0x38: return 0050;
|
||||||
|
case 0x39: return 0051;
|
||||||
|
case 0x3a: return 0052;
|
||||||
|
case 0x3b: return 0053;
|
||||||
|
case 0x3c: return 0054;
|
||||||
|
case 0x3d: return 0055;
|
||||||
|
case 0x3e: return 0056;
|
||||||
|
case 0x3f: return 0057;
|
||||||
|
case 0x40: return 0060;
|
||||||
|
case 0x41: return 0061;
|
||||||
|
case 0x42: return 0062;
|
||||||
|
case 0x43: return 0063;
|
||||||
|
case 0x44: return 0064;
|
||||||
|
case 0x45: return 0065;
|
||||||
|
case 0x46: return 0066;
|
||||||
|
case 0x47: return 0067;
|
||||||
|
case 0x48: return 0070;
|
||||||
|
case 0x49: return 0071;
|
||||||
|
case 0x4a: return 0135;
|
||||||
|
case 0x4b: return 0072;
|
||||||
|
case 0x4c: return 0073;
|
||||||
|
case 0x4d: return 0074;
|
||||||
|
case 0x4e: return 0075;
|
||||||
|
case 0x4f: return 0076;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
switch ((unsigned char) val) {
|
||||||
|
case 0x15: return 0131;
|
||||||
|
case 0x18: return 0032;
|
||||||
|
case 0x19: return 0033;
|
||||||
|
case 0x32: return 0137;
|
||||||
|
case 0x3e: return 0115;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
switch ((unsigned char) val) {
|
||||||
|
case 0x2f: return 0020;
|
||||||
|
case 0x91: return 0021;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
switch ((unsigned char) val) {
|
||||||
|
case 0x27: return 0121;
|
||||||
|
case 0x28: return 0120;
|
||||||
|
case 0x60: return 0034;
|
||||||
|
case 0x61: return 0125;
|
||||||
|
case 0x64: return 0116;
|
||||||
|
case 0x65: return 0117;
|
||||||
|
case 0x83: return 0122;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x25:
|
||||||
|
switch ((unsigned char) val) {
|
||||||
|
case 0xc7: return 0127;
|
||||||
|
case 0xca: return 0127;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 017;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read Unicode symbol from file.
|
||||||
|
* Convert from UTF-8 encoding.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
utf8_getc (FILE *fin)
|
||||||
|
{
|
||||||
|
int c1, c2, c3;
|
||||||
|
again:
|
||||||
|
c1 = getc (fin);
|
||||||
|
if (c1 < 0 || ! (c1 & 0x80))
|
||||||
|
return c1;
|
||||||
|
c2 = getc (fin);
|
||||||
|
if (! (c1 & 0x20))
|
||||||
|
return (c1 & 0x1f) << 6 | (c2 & 0x3f);
|
||||||
|
c3 = getc (fin);
|
||||||
|
if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
|
||||||
|
/* Skip zero width no-break space. */
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f);
|
||||||
|
}
|
719
BESM6/besm6_sys.c
Normal file
719
BESM6/besm6_sys.c
Normal file
|
@ -0,0 +1,719 @@
|
||||||
|
/*
|
||||||
|
* besm6_sys.c: BESM-6 simulator interface
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, Serge Vakulenko
|
||||||
|
* Copyright (c) 2009, Leonid Broukhis
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You can redistribute this program and/or modify it under the terms of
|
||||||
|
* the GNU General Public License as published by the Free Software Foundation;
|
||||||
|
* either version 2 of the License, or (at your discretion) any later version.
|
||||||
|
* See the accompanying file "COPYING" for more details.
|
||||||
|
*
|
||||||
|
* This file implements three essential functions:
|
||||||
|
*
|
||||||
|
* sim_load() - loading and dumping memory and CPU state
|
||||||
|
* in a way, specific for BESM-6 architecture
|
||||||
|
* fprint_sym() - print a machune instruction using
|
||||||
|
* opcode mnemonic or in a digital format
|
||||||
|
* parse_sym() - scan a string and build an instruction
|
||||||
|
* word from it
|
||||||
|
*/
|
||||||
|
#include "besm6_defs.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.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 63———53 52————–1
|
||||||
|
* знак порядок мантисса
|
||||||
|
* Старший (53-й) бит мантиссы не хранится и всегда равен 1.
|
||||||
|
*
|
||||||
|
* Представление чисел в БЭСМ-6:
|
||||||
|
* 48——–42 41 40————————————————–1
|
||||||
|
* порядок знак мантисса в доп. коде
|
||||||
|
*/
|
||||||
|
t_value ieee_to_besm6 (double d)
|
||||||
|
{
|
||||||
|
t_value word;
|
||||||
|
int exponent;
|
||||||
|
int sign;
|
||||||
|
|
||||||
|
sign = d < 0;
|
||||||
|
if (sign)
|
||||||
|
d = -d;
|
||||||
|
d = frexp (d, &exponent);
|
||||||
|
/* 0.5 <= d < 1.0 */
|
||||||
|
d = ldexp (d, 40);
|
||||||
|
word = d;
|
||||||
|
if (d - word >= 0.5)
|
||||||
|
word += 1; /* Округление. */
|
||||||
|
if (exponent < -64)
|
||||||
|
return 0LL; /* Близкое к нулю число */
|
||||||
|
if (exponent > 63) {
|
||||||
|
return sign ?
|
||||||
|
0xFEFFFFFFFFFFLL : /* Максимальное число */
|
||||||
|
0xFF0000000000LL; /* Минимальное число */
|
||||||
|
}
|
||||||
|
if (sign)
|
||||||
|
word = 0x20000000000LL-word; /* Знак. */
|
||||||
|
word |= ((t_value) (exponent + 64)) << 41;
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
double besm6_to_ieee (t_value word)
|
||||||
|
{
|
||||||
|
double mantissa;
|
||||||
|
|
||||||
|
/* Убираем свертку */
|
||||||
|
word &= BITS48;
|
||||||
|
|
||||||
|
/* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого;
|
||||||
|
* таким образом, mantissa равно исходной мантиссе, умноженной на 2**63.
|
||||||
|
*/
|
||||||
|
mantissa = (t_int64) word << (64 - 48 + 7);
|
||||||
|
|
||||||
|
int exponent = word >> 41;
|
||||||
|
|
||||||
|
/* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */
|
||||||
|
return ldexp (mantissa, exponent - 64 - 63);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Пропуск пробелов.
|
||||||
|
*/
|
||||||
|
char *skip_spaces (char *p)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) {
|
||||||
|
/* Skip zero width no-break space. */
|
||||||
|
p += 3;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*p == ' ' || *p == '\t') {
|
||||||
|
++p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch Unicode symbol from UTF-8 string.
|
||||||
|
* Advance string pointer.
|
||||||
|
*/
|
||||||
|
int utf8_to_unicode (char **p)
|
||||||
|
{
|
||||||
|
int c1, c2, c3;
|
||||||
|
|
||||||
|
c1 = (unsigned char) *(*p)++;
|
||||||
|
if (! (c1 & 0x80))
|
||||||
|
return c1;
|
||||||
|
c2 = (unsigned char) *(*p)++;
|
||||||
|
if (! (c1 & 0x20))
|
||||||
|
return (c1 & 0x1f) << 6 | (c2 & 0x3f);
|
||||||
|
c3 = (unsigned char) *(*p)++;
|
||||||
|
return (c1 & 0x0f) << 12 | (c2 & 0x3f) << 6 | (c3 & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *besm6_parse_octal (char *cptr, int *offset)
|
||||||
|
{
|
||||||
|
char *eptr;
|
||||||
|
|
||||||
|
*offset = strtol (cptr, &eptr, 8);
|
||||||
|
if (eptr == cptr)
|
||||||
|
return 0;
|
||||||
|
return eptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_alnum (char *iptr, char *optr)
|
||||||
|
{
|
||||||
|
while ((*iptr >= 'a' && *iptr<='z') ||
|
||||||
|
(*iptr >= 'A' && *iptr<='Z') ||
|
||||||
|
(*iptr >= '0' && *iptr<='9') || (*iptr & 0x80)) {
|
||||||
|
*optr++ = *iptr++;
|
||||||
|
}
|
||||||
|
*optr = 0;
|
||||||
|
return iptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse single instruction (half word).
|
||||||
|
* Allow mnemonics or octal code.
|
||||||
|
*/
|
||||||
|
char *parse_instruction (char *cptr, uint32 *val)
|
||||||
|
{
|
||||||
|
int opcode, reg, addr, negate;
|
||||||
|
char gbuf[CBUFSIZE];
|
||||||
|
|
||||||
|
cptr = skip_spaces (cptr); /* absorb spaces */
|
||||||
|
if (*cptr >= '0' && *cptr <= '7') {
|
||||||
|
/* Восьмеричное представление. */
|
||||||
|
cptr = besm6_parse_octal (cptr, ®); /* get register */
|
||||||
|
if (! cptr || reg > 15) {
|
||||||
|
/*printf ("Bad register\n");*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cptr = skip_spaces (cptr); /* absorb spaces */
|
||||||
|
if (*cptr == '2' || *cptr == '3') {
|
||||||
|
/* Длинная команда. */
|
||||||
|
cptr = besm6_parse_octal (cptr, &opcode);
|
||||||
|
if (! cptr || opcode < 020 || opcode > 037) {
|
||||||
|
/*printf ("Bad long opcode\n");*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
opcode <<= 3;
|
||||||
|
} else {
|
||||||
|
/* Короткая команда. */
|
||||||
|
cptr = besm6_parse_octal (cptr, &opcode);
|
||||||
|
if (! cptr || opcode > 0177) {
|
||||||
|
/*printf ("Bad short opcode\n");*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cptr = besm6_parse_octal (cptr, &addr); /* get address */
|
||||||
|
if (! cptr || addr > BITS(15) ||
|
||||||
|
(opcode <= 0177 && addr > BITS(12))) {
|
||||||
|
/*printf ("Bad address\n");*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Мнемоническое представление команды. */
|
||||||
|
cptr = get_alnum (cptr, gbuf); /* get opcode */
|
||||||
|
opcode = besm6_opcode (gbuf);
|
||||||
|
if (opcode < 0) {
|
||||||
|
/*printf ("Bad opname: %s\n", gbuf);*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
negate = 0;
|
||||||
|
cptr = skip_spaces (cptr); /* absorb spaces */
|
||||||
|
if (*cptr == '-') { /* negative offset */
|
||||||
|
negate = 1;
|
||||||
|
cptr = skip_spaces (cptr + 1); /* absorb spaces */
|
||||||
|
}
|
||||||
|
addr = 0;
|
||||||
|
if (*cptr >= '0' && *cptr <= '7') {
|
||||||
|
/* Восьмеричный адрес. */
|
||||||
|
cptr = besm6_parse_octal (cptr, &addr);
|
||||||
|
if (! cptr || addr > BITS(15)) {
|
||||||
|
/*printf ("Bad address: %o\n", addr);*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (negate)
|
||||||
|
addr = (- addr) & BITS(15);
|
||||||
|
if (opcode <= 077 && addr > BITS(12)) {
|
||||||
|
if (addr < 070000) {
|
||||||
|
/*printf ("Bad short address: %o\n", addr);*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
opcode |= 0100;
|
||||||
|
addr &= BITS(12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reg = 0;
|
||||||
|
cptr = skip_spaces (cptr); /* absorb spaces */
|
||||||
|
if (*cptr == '(') {
|
||||||
|
/* Индекс-регистр в скобках. */
|
||||||
|
cptr = besm6_parse_octal (cptr+1, ®);
|
||||||
|
if (! cptr || reg > 15) {
|
||||||
|
/*printf ("Bad register: %o\n", reg);*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cptr = skip_spaces (cptr); /* absorb spaces */
|
||||||
|
if (*cptr != ')') {
|
||||||
|
/*printf ("No closing brace\n");*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
++cptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*val = reg << 20 | opcode << 12 | addr;
|
||||||
|
return cptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Instruction parse: two commands per word.
|
||||||
|
*/
|
||||||
|
t_stat parse_instruction_word (char *cptr, t_value *val)
|
||||||
|
{
|
||||||
|
uint32 left, right;
|
||||||
|
|
||||||
|
*val = 0;
|
||||||
|
cptr = parse_instruction (cptr, &left);
|
||||||
|
if (! cptr)
|
||||||
|
return SCPE_ARG;
|
||||||
|
right = 0;
|
||||||
|
cptr = skip_spaces (cptr);
|
||||||
|
if (*cptr == ',') {
|
||||||
|
cptr = parse_instruction (cptr + 1, &right);
|
||||||
|
if (! cptr)
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
cptr = skip_spaces (cptr); /* absorb spaces */
|
||||||
|
if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') {
|
||||||
|
/*printf ("Extra symbols at eoln: %s\n", cptr);*/
|
||||||
|
return SCPE_2MARG;
|
||||||
|
}
|
||||||
|
*val = (t_value) left << 24 | right;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Печать машинной инструкции с мнемоникой.
|
||||||
|
*/
|
||||||
|
void besm6_fprint_cmd (FILE *of, uint32 cmd)
|
||||||
|
{
|
||||||
|
int reg, opcode, addr;
|
||||||
|
|
||||||
|
reg = (cmd >> 20) & 017;
|
||||||
|
if (cmd & BBIT(20)) {
|
||||||
|
opcode = (cmd >> 12) & 0370;
|
||||||
|
addr = cmd & BITS(15);
|
||||||
|
} else {
|
||||||
|
opcode = (cmd >> 12) & 077;
|
||||||
|
addr = cmd & 07777;
|
||||||
|
if (cmd & BBIT(19))
|
||||||
|
addr |= 070000;
|
||||||
|
}
|
||||||
|
fprintf (of, "%s", besm6_opname (opcode));
|
||||||
|
if (addr) {
|
||||||
|
fprintf (of, " ");
|
||||||
|
if (addr >= 077700)
|
||||||
|
fprintf (of, "-%o", (addr ^ 077777) + 1);
|
||||||
|
else
|
||||||
|
fprintf (of, "%o", addr);
|
||||||
|
}
|
||||||
|
if (reg) {
|
||||||
|
if (! addr)
|
||||||
|
fprintf (of, " ");
|
||||||
|
fprintf (of, "(%o)", reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Печать машинной инструкции в восьмеричном виде.
|
||||||
|
*/
|
||||||
|
void besm6_fprint_insn (FILE *of, uint32 insn)
|
||||||
|
{
|
||||||
|
if (insn & BBIT(20))
|
||||||
|
fprintf (of, "%02o %02o %05o ",
|
||||||
|
insn >> 20, (insn >> 15) & 037, insn & BITS(15));
|
||||||
|
else
|
||||||
|
fprintf (of, "%02o %03o %04o ",
|
||||||
|
insn >> 20, (insn >> 12) & 0177, insn & 07777);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Symbolic decode
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* *of = output stream
|
||||||
|
* addr = current PC
|
||||||
|
* *val = pointer to data
|
||||||
|
* *uptr = pointer to unit
|
||||||
|
* sw = switches
|
||||||
|
* Outputs:
|
||||||
|
* return = status code
|
||||||
|
*/
|
||||||
|
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||||
|
UNIT *uptr, int32 sw)
|
||||||
|
{
|
||||||
|
t_value cmd;
|
||||||
|
|
||||||
|
if (uptr && (uptr != &cpu_unit)) /* must be CPU */
|
||||||
|
return SCPE_ARG;
|
||||||
|
|
||||||
|
cmd = val[0];
|
||||||
|
|
||||||
|
|
||||||
|
if (sw & SWMASK ('M')) { /* symbolic decode? */
|
||||||
|
if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR))
|
||||||
|
fprintf (of, "-> ");
|
||||||
|
besm6_fprint_cmd (of, cmd >> 24);
|
||||||
|
if (sw & SIM_SW_STOP) /* stop point */
|
||||||
|
fprintf (of, ", ");
|
||||||
|
else
|
||||||
|
fprintf (of, ",\n\t");
|
||||||
|
if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR))
|
||||||
|
fprintf (of, "-> ");
|
||||||
|
besm6_fprint_cmd (of, cmd & BITS(24));
|
||||||
|
|
||||||
|
} else if (sw & SWMASK ('I')) {
|
||||||
|
besm6_fprint_insn (of, (cmd >> 24) & BITS(24));
|
||||||
|
besm6_fprint_insn (of, cmd & BITS(24));
|
||||||
|
} else if (sw & SWMASK ('F')) {
|
||||||
|
fprintf (of, "%#.2g", besm6_to_ieee(cmd));
|
||||||
|
} else if (sw & SWMASK ('B')) {
|
||||||
|
fprintf (of, "%03o %03o %03o %03o %03o %03o",
|
||||||
|
(int) (cmd >> 40) & 0377,
|
||||||
|
(int) (cmd >> 32) & 0377,
|
||||||
|
(int) (cmd >> 24) & 0377,
|
||||||
|
(int) (cmd >> 16) & 0377,
|
||||||
|
(int) (cmd >> 8) & 0377,
|
||||||
|
(int) cmd & 0377);
|
||||||
|
} else if (sw & SWMASK ('X')) {
|
||||||
|
fprintf (of, "%013llx", cmd);
|
||||||
|
} else
|
||||||
|
fprintf (of, "%04o %04o %04o %04o",
|
||||||
|
(int) (cmd >> 36) & 07777,
|
||||||
|
(int) (cmd >> 24) & 07777,
|
||||||
|
(int) (cmd >> 12) & 07777,
|
||||||
|
(int) cmd & 07777);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Symbolic input
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* *cptr = pointer to input string
|
||||||
|
* addr = current PC
|
||||||
|
* *uptr = pointer to unit
|
||||||
|
* *val = pointer to output values
|
||||||
|
* sw = switches
|
||||||
|
* Outputs:
|
||||||
|
* status = error status
|
||||||
|
*/
|
||||||
|
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
if (uptr && (uptr != &cpu_unit)) /* must be CPU */
|
||||||
|
return SCPE_ARG;
|
||||||
|
if (! parse_instruction_word (cptr, val)) /* symbolic parse? */
|
||||||
|
return SCPE_OK;
|
||||||
|
|
||||||
|
val[0] = 0;
|
||||||
|
for (i=0; i<16; i++) {
|
||||||
|
if (*cptr < '0' || *cptr > '7')
|
||||||
|
break;
|
||||||
|
val[0] = (val[0] << 3) | (*cptr - '0');
|
||||||
|
cptr = skip_spaces (cptr+1); /* next char */
|
||||||
|
}
|
||||||
|
if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') {
|
||||||
|
/*printf ("Extra symbols at eoln: %s\n", cptr);*/
|
||||||
|
return SCPE_2MARG;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Чтение строки входного файла.
|
||||||
|
* Форматы строк:
|
||||||
|
* п 76543 - адрес пуска
|
||||||
|
* в 12345 - адрес ввода
|
||||||
|
* ч -123.45e+6 - вещественное число
|
||||||
|
* с 0123 4567 0123 4567 - восьмеричное слово
|
||||||
|
* к 00 22 00000 00 010 0000 - команды
|
||||||
|
*/
|
||||||
|
t_stat besm6_read_line (FILE *input, int *type, t_value *val)
|
||||||
|
{
|
||||||
|
char buf [512], *p;
|
||||||
|
int i, c;
|
||||||
|
again:
|
||||||
|
if (! fgets (buf, sizeof (buf), input)) {
|
||||||
|
*type = 0;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
p = skip_spaces (buf);
|
||||||
|
if (*p == '\n' || *p == ';')
|
||||||
|
goto again;
|
||||||
|
c = utf8_to_unicode (&p);
|
||||||
|
if (c == CYRILLIC_SMALL_LETTER_VE ||
|
||||||
|
c == CYRILLIC_CAPITAL_LETTER_VE ||
|
||||||
|
c == 'b' || c == 'B') {
|
||||||
|
/* Адрес размещения данных. */
|
||||||
|
*type = ':';
|
||||||
|
*val = strtol (p, 0, 8);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (c == CYRILLIC_SMALL_LETTER_PE ||
|
||||||
|
c == CYRILLIC_CAPITAL_LETTER_PE ||
|
||||||
|
c == 'p' || c == 'P') {
|
||||||
|
/* Стартовый адрес. */
|
||||||
|
*type = '@';
|
||||||
|
*val = strtol (p, 0, 8);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (c == CYRILLIC_SMALL_LETTER_CHE ||
|
||||||
|
c == CYRILLIC_CAPITAL_LETTER_CHE ||
|
||||||
|
c == 'f' || c == 'F') {
|
||||||
|
/* Вещественное число. */
|
||||||
|
*type = '=';
|
||||||
|
*val = ieee_to_besm6 (strtod (p, 0));
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (c == CYRILLIC_SMALL_LETTER_ES ||
|
||||||
|
c == CYRILLIC_CAPITAL_LETTER_ES ||
|
||||||
|
c == 'c' || c == 'C') {
|
||||||
|
/* Восьмеричное слово. */
|
||||||
|
*type = '=';
|
||||||
|
*val = 0;
|
||||||
|
for (i=0; i<16; ++i) {
|
||||||
|
p = skip_spaces (p);
|
||||||
|
if (*p < '0' || *p > '7') {
|
||||||
|
if (i == 0) {
|
||||||
|
/* слишком короткое слово */
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*val = *val << 3 | (*p++ - '0');
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (c == CYRILLIC_SMALL_LETTER_KA ||
|
||||||
|
c == CYRILLIC_CAPITAL_LETTER_KA ||
|
||||||
|
c == 'k' || c == 'K') {
|
||||||
|
/* Команда. */
|
||||||
|
*type = '*';
|
||||||
|
if (parse_instruction_word (p, val) != SCPE_OK)
|
||||||
|
goto bad;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
/* Неверная строка входного файла */
|
||||||
|
bad: besm6_log ("Invalid input line: %s", buf);
|
||||||
|
return SCPE_FMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load memory from file.
|
||||||
|
*/
|
||||||
|
t_stat besm6_load (FILE *input)
|
||||||
|
{
|
||||||
|
int addr, type;
|
||||||
|
t_value word;
|
||||||
|
t_stat err;
|
||||||
|
|
||||||
|
addr = 1;
|
||||||
|
PC = 1;
|
||||||
|
for (;;) {
|
||||||
|
err = besm6_read_line (input, &type, &word);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
switch (type) {
|
||||||
|
case 0: /* EOF */
|
||||||
|
return SCPE_OK;
|
||||||
|
case ':': /* address */
|
||||||
|
addr = word;
|
||||||
|
break;
|
||||||
|
case '=': /* word */
|
||||||
|
if (addr < 010)
|
||||||
|
pult [addr] = SET_CONVOL (word, CONVOL_NUMBER);
|
||||||
|
else
|
||||||
|
memory [addr] = SET_CONVOL (word, CONVOL_NUMBER);
|
||||||
|
++addr;
|
||||||
|
break;
|
||||||
|
case '*': /* instruction */
|
||||||
|
if (addr < 010)
|
||||||
|
pult [addr] = SET_CONVOL (word, CONVOL_INSN);
|
||||||
|
else
|
||||||
|
memory [addr] = SET_CONVOL (word, CONVOL_INSN);
|
||||||
|
++addr;
|
||||||
|
break;
|
||||||
|
case '@': /* start address */
|
||||||
|
PC = word;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (addr > MEMSIZE)
|
||||||
|
return SCPE_FMT;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump memory to file.
|
||||||
|
*/
|
||||||
|
t_stat besm6_dump (FILE *of, char *fnam)
|
||||||
|
{
|
||||||
|
int addr, last_addr = -1;
|
||||||
|
t_value word;
|
||||||
|
|
||||||
|
fprintf (of, "; %s\n", fnam);
|
||||||
|
for (addr=1; addr<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, 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);
|
||||||
|
}
|
1243
BESM6/besm6_tty.c
Normal file
1243
BESM6/besm6_tty.c
Normal file
File diff suppressed because it is too large
Load diff
26
makefile
26
makefile
|
@ -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 ifeq ($(MAKECMDGOALS),besm6)
|
||||||
|
VIDEO_USEFUL = true
|
||||||
else
|
else
|
||||||
ifeq ($(MAKECMDGOALS),)
|
ifeq ($(MAKECMDGOALS),)
|
||||||
# default target is all
|
# default target is all
|
||||||
|
@ -1159,6 +1161,24 @@ 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
|
||||||
|
|
||||||
|
ifeq (,${VIDEO_LDFLAGS})
|
||||||
|
BESM6_OPT = -I ${BESM6D} -DUSE_INT64
|
||||||
|
else ifneq (,$(and $(findstring,SDL2,${VIDEO_LDFLAGS})),$(and($(find_include, SDL2/SDL_ttf),$(find_lib,SDL2_ttf))))
|
||||||
|
BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL2_ttf
|
||||||
|
else ifneq (,$(and $(find_include, SDL/SDL_ttf),$(find_lib,SDL_ttf)))
|
||||||
|
BESM6_OPT = -I ${BESM6D} -DUSE_INT64 ${VIDEO_CCDEFS} ${VIDEO_LDFLAGS} -lSDL_ttf
|
||||||
|
endif
|
||||||
|
|
||||||
###
|
###
|
||||||
### Unsupported/Incomplete simulators
|
### Unsupported/Incomplete simulators
|
||||||
###
|
###
|
||||||
|
@ -1462,6 +1482,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}
|
||||||
|
|
Loading…
Add table
Reference in a new issue