734 lines
23 KiB
C
734 lines
23 KiB
C
/*
|
||
* besm6_sys.c: BESM-6 simulator interface
|
||
*
|
||
* Copyright (c) 2009, Serge Vakulenko
|
||
* Copyright (c) 2009, Leonid Broukhis
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||
* copy of this software and associated documentation files (the "Software"),
|
||
* to deal in the Software without restriction, including without limitation
|
||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
* and/or sell copies of the Software, and to permit persons to whom the
|
||
* Software is furnished to do so, subject to the following conditions:
|
||
|
||
* The above copyright notice and this permission notice shall be included in
|
||
* all copies or substantial portions of the Software.
|
||
|
||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
* SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||
* OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
* Except as contained in this notice, the name of Leonid Broukhis or
|
||
* Serge Vakulenko shall not be used in advertising or otherwise to promote
|
||
* the sale, use or other dealings in this Software without prior written
|
||
* authorization from Leonid Broukhis and Serge Vakulenko.
|
||
*
|
||
* This file implements three essential functions:
|
||
*
|
||
* sim_load() - loading and dumping memory and CPU state
|
||
* in a way, specific for BESM-6 architecture
|
||
* fprint_sym() - print a machune instruction using
|
||
* opcode mnemonic or in a digital format
|
||
* parse_sym() - scan a string and build an instruction
|
||
* word from it
|
||
*/
|
||
#include "besm6_defs.h"
|
||
#include <math.h>
|
||
|
||
const char *opname_short_bemsh [64] = {
|
||
"зп", "зпм", "рег", "счм", "сл", "вч", "вчоб","вчаб",
|
||
"сч", "и", "нтж", "слц", "знак","или", "дел", "умн",
|
||
"сбр", "рзб", "чед", "нед", "слп", "вчп", "сд", "рж",
|
||
"счрж","счмр","э32", "увв", "слпа","вчпа","сда", "ржа",
|
||
"уи", "уим", "счи", "счим","уии", "сли", "э46", "э47",
|
||
"э50", "э51", "э52", "э53", "э54", "э55", "э56", "э57",
|
||
"э60", "э61", "э62", "э63", "э64", "э65", "э66", "э67",
|
||
"э70", "э71", "э72", "э73", "э74", "э75", "э76", "э77",
|
||
};
|
||
|
||
static const char *opname_long_bemsh [16] = {
|
||
"э20", "э21", "мода","мод", "уиа", "слиа","по", "пе",
|
||
"пб", "пв", "выпр","стоп","пио", "пино","э36", "цикл",
|
||
};
|
||
|
||
const char *opname_short_madlen [64] = {
|
||
"atx", "stx", "mod", "xts", "a+x", "a-x", "x-a", "amx",
|
||
"xta", "aax", "aex", "arx", "avx", "aox", "a/x", "a*x",
|
||
"apx", "aux", "acx", "anx", "e+x", "e-x", "asx", "xtr",
|
||
"rte", "yta", "*32", "ext", "e+n", "e-n", "asn", "ntr",
|
||
"ati", "sti", "ita", "its", "mtj", "j+m", "*46", "*47",
|
||
"*50", "*51", "*52", "*53", "*54", "*55", "*56", "*57",
|
||
"*60", "*61", "*62", "*63", "*64", "*65", "*66", "*67",
|
||
"*70", "*71", "*72", "*73", "*74", "*75", "*76", "*77",
|
||
};
|
||
|
||
static const char *opname_long_madlen [16] = {
|
||
"*20", "*21", "utc", "wtc", "vtm", "utm", "uza", "u1a",
|
||
"uj", "vjm", "ij", "stop", "vzm", "v1m", "*36", "vlm",
|
||
};
|
||
|
||
/*
|
||
* Выдача мнемоники по коду инструкции.
|
||
* Код должен быть в диапазоне 000..077 или 0200..0370.
|
||
*/
|
||
const char *besm6_opname (int opcode)
|
||
{
|
||
if (sim_switches & SWMASK ('L')) {
|
||
/* Latin mnemonics. */
|
||
if (opcode & 0200)
|
||
return opname_long_madlen [(opcode >> 3) & 017];
|
||
return opname_short_madlen [opcode];
|
||
}
|
||
if (opcode & 0200)
|
||
return opname_long_bemsh [(opcode >> 3) & 017];
|
||
return opname_short_bemsh [opcode];
|
||
}
|
||
|
||
/*
|
||
* Выдача кода инструкции по мнемонике (UTF-8).
|
||
*/
|
||
int besm6_opcode (char *instr)
|
||
{
|
||
int i;
|
||
|
||
for (i=0; i<64; ++i)
|
||
if (strcmp (opname_short_bemsh[i], instr) == 0 ||
|
||
strcmp (opname_short_madlen[i], instr) == 0)
|
||
return i;
|
||
for (i=0; i<16; ++i)
|
||
if (strcmp (opname_long_bemsh[i], instr) == 0 ||
|
||
strcmp (opname_long_madlen[i], instr) == 0)
|
||
return (i << 3) | 0200;
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* Выдача на консоль и в файл протокола.
|
||
* Если первый символ формата - подчерк, на консоль не печатаем.
|
||
* Добавляет перевод строки.
|
||
*/
|
||
void besm6_log (const char *fmt, ...)
|
||
{
|
||
va_list args;
|
||
|
||
if (*fmt == '_')
|
||
++fmt;
|
||
else {
|
||
va_start (args, fmt);
|
||
vprintf (fmt, args);
|
||
printf ("\r\n");
|
||
va_end (args);
|
||
}
|
||
if (sim_log) {
|
||
va_start (args, fmt);
|
||
vfprintf (sim_log, fmt, args);
|
||
if (sim_log == stdout)
|
||
fprintf (sim_log, "\r");
|
||
fprintf (sim_log, "\n");
|
||
fflush (sim_log);
|
||
va_end (args);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Не добавляет перевод строки.
|
||
*/
|
||
void besm6_log_cont (const char *fmt, ...)
|
||
{
|
||
va_list args;
|
||
|
||
if (*fmt == '_')
|
||
++fmt;
|
||
else {
|
||
va_start (args, fmt);
|
||
vprintf (fmt, args);
|
||
va_end (args);
|
||
}
|
||
if (sim_log) {
|
||
va_start (args, fmt);
|
||
vfprintf (sim_log, fmt, args);
|
||
fflush (sim_log);
|
||
va_end (args);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Выдача на консоль и в файл отладки: если включён режим "cpu debug".
|
||
* Добавляет перевод строки.
|
||
*/
|
||
void besm6_debug (const char *fmt, ...)
|
||
{
|
||
va_list args;
|
||
|
||
va_start (args, fmt);
|
||
vprintf (fmt, args);
|
||
printf ("\r\n");
|
||
va_end (args);
|
||
if (sim_deb && sim_deb != stdout) {
|
||
va_start (args, fmt);
|
||
vfprintf (sim_deb, fmt, args);
|
||
fprintf (sim_deb, "\n");
|
||
fflush (sim_deb);
|
||
va_end (args);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Преобразование вещественного числа в формат БЭСМ-6.
|
||
*
|
||
* Представление чисел в IEEE 754 (double):
|
||
* 64 63———53 52————–1
|
||
* знак порядок мантисса
|
||
* Старший (53-й) бит мантиссы не хранится и всегда равен 1.
|
||
*
|
||
* Представление чисел в БЭСМ-6:
|
||
* 48——–42 41 40————————————————–1
|
||
* порядок знак мантисса в доп. коде
|
||
*/
|
||
t_value ieee_to_besm6 (double d)
|
||
{
|
||
t_value word;
|
||
int exponent;
|
||
int sign;
|
||
|
||
sign = d < 0;
|
||
if (sign)
|
||
d = -d;
|
||
d = frexp (d, &exponent);
|
||
/* 0.5 <= d < 1.0 */
|
||
d = ldexp (d, 40);
|
||
word = (t_value)d;
|
||
if (d - word >= 0.5)
|
||
word += 1; /* Округление. */
|
||
if (exponent < -64)
|
||
return 0LL; /* Близкое к нулю число */
|
||
if (exponent > 63) {
|
||
return sign ?
|
||
0xFEFFFFFFFFFFLL : /* Максимальное число */
|
||
0xFF0000000000LL; /* Минимальное число */
|
||
}
|
||
if (sign)
|
||
word = 0x20000000000LL-word; /* Знак. */
|
||
word |= ((t_value) (exponent + 64)) << 41;
|
||
return word;
|
||
}
|
||
|
||
double besm6_to_ieee (t_value word)
|
||
{
|
||
double mantissa;
|
||
int exponent;
|
||
|
||
/* Убираем свертку */
|
||
word &= BITS48;
|
||
|
||
/* Сдвигаем так, чтобы знак мантиссы пришелся на знак целого;
|
||
* таким образом, mantissa равно исходной мантиссе, умноженной на 2**63.
|
||
*/
|
||
mantissa = (double)(((t_int64) word) << (64 - 48 + 7));
|
||
|
||
exponent = word >> 41;
|
||
|
||
/* Порядок смещен вверх на 64, и мантиссу нужно скорректировать */
|
||
return ldexp (mantissa, exponent - 64 - 63);
|
||
}
|
||
|
||
/*
|
||
* Пропуск пробелов.
|
||
*/
|
||
CONST char *skip_spaces (CONST char *p)
|
||
{
|
||
for (;;) {
|
||
if (*p == (char) 0xEF && p[1] == (char) 0xBB && p[2] == (char) 0xBF) {
|
||
/* Skip zero width no-break space. */
|
||
p += 3;
|
||
continue;
|
||
}
|
||
if (*p == ' ' || *p == '\t' || *p == '\r') {
|
||
++p;
|
||
continue;
|
||
}
|
||
return p;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Fetch Unicode symbol from UTF-8 string.
|
||
* Advance string pointer.
|
||
*/
|
||
int utf8_to_unicode (CONST 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 (const char *cptr, int *offset)
|
||
{
|
||
char *eptr;
|
||
|
||
*offset = strtol (cptr, &eptr, 8);
|
||
if (eptr == cptr)
|
||
return 0;
|
||
return eptr;
|
||
}
|
||
|
||
static CONST char *get_alnum (CONST 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.
|
||
*/
|
||
CONST char *parse_instruction (CONST 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 (CONST char *cptr, t_value *val)
|
||
{
|
||
uint32 left, right;
|
||
|
||
*val = 0;
|
||
cptr = parse_instruction (cptr, &left);
|
||
if (! cptr)
|
||
return SCPE_ARG;
|
||
right = 0;
|
||
cptr = skip_spaces (cptr);
|
||
if (*cptr == ',') {
|
||
cptr = parse_instruction (cptr + 1, &right);
|
||
if (! cptr)
|
||
return SCPE_ARG;
|
||
}
|
||
cptr = skip_spaces (cptr); /* absorb spaces */
|
||
if (*cptr != 0 && *cptr != ';' && *cptr != '\n' && *cptr != '\r') {
|
||
/*printf ("Extra symbols at eoln: %s\n", cptr);*/
|
||
return SCPE_2MARG;
|
||
}
|
||
*val = (t_value) left << 24 | right;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/*
|
||
* Печать машинной инструкции с мнемоникой.
|
||
*/
|
||
void besm6_fprint_cmd (FILE *of, uint32 cmd)
|
||
{
|
||
int reg, opcode, addr;
|
||
|
||
reg = (cmd >> 20) & 017;
|
||
if (cmd & BBIT(20)) {
|
||
opcode = (cmd >> 12) & 0370;
|
||
addr = cmd & BITS(15);
|
||
} else {
|
||
opcode = (cmd >> 12) & 077;
|
||
addr = cmd & 07777;
|
||
if (cmd & BBIT(19))
|
||
addr |= 070000;
|
||
}
|
||
fprintf (of, "%s", besm6_opname (opcode));
|
||
if (addr) {
|
||
fprintf (of, " ");
|
||
if (addr >= 077700)
|
||
fprintf (of, "-%o", (addr ^ 077777) + 1);
|
||
else
|
||
fprintf (of, "%o", addr);
|
||
}
|
||
if (reg) {
|
||
if (! addr)
|
||
fprintf (of, " ");
|
||
fprintf (of, "(%o)", reg);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Печать машинной инструкции в восьмеричном виде.
|
||
*/
|
||
void besm6_fprint_insn (FILE *of, uint32 insn)
|
||
{
|
||
if (insn & BBIT(20))
|
||
fprintf (of, "%02o %02o %05o ",
|
||
insn >> 20, (insn >> 15) & 037, insn & BITS(15));
|
||
else
|
||
fprintf (of, "%02o %03o %04o ",
|
||
insn >> 20, (insn >> 12) & 0177, insn & 07777);
|
||
}
|
||
|
||
/*
|
||
* Symbolic decode
|
||
*
|
||
* Inputs:
|
||
* *of = output stream
|
||
* addr = current PC
|
||
* *val = pointer to data
|
||
* *uptr = pointer to unit
|
||
* sw = switches
|
||
* Outputs:
|
||
* return = status code
|
||
*/
|
||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||
UNIT *uptr, int32 sw)
|
||
{
|
||
t_value cmd;
|
||
|
||
if (uptr && (uptr != &cpu_unit)) /* must be CPU */
|
||
return SCPE_ARG;
|
||
|
||
cmd = val[0];
|
||
|
||
|
||
if (sw & SWMASK ('M')) { /* symbolic decode? */
|
||
if (sw & SIM_SW_STOP && addr == PC && !(RUU & RUU_RIGHT_INSTR))
|
||
fprintf (of, "-> ");
|
||
besm6_fprint_cmd (of, (uint32)(cmd >> 24));
|
||
if (sw & SIM_SW_STOP) /* stop point */
|
||
fprintf (of, ", ");
|
||
else
|
||
fprintf (of, ",\n\t");
|
||
if (sw & SIM_SW_STOP && addr == PC && (RUU & RUU_RIGHT_INSTR))
|
||
fprintf (of, "-> ");
|
||
besm6_fprint_cmd (of, cmd & BITS(24));
|
||
|
||
} else if (sw & SWMASK ('I')) {
|
||
besm6_fprint_insn (of, (cmd >> 24) & BITS(24));
|
||
besm6_fprint_insn (of, cmd & BITS(24));
|
||
} else if (sw & SWMASK ('F')) {
|
||
fprintf (of, "%#.2g", besm6_to_ieee(cmd));
|
||
} else if (sw & SWMASK ('B')) {
|
||
fprintf (of, "%03o %03o %03o %03o %03o %03o",
|
||
(int) (cmd >> 40) & 0377,
|
||
(int) (cmd >> 32) & 0377,
|
||
(int) (cmd >> 24) & 0377,
|
||
(int) (cmd >> 16) & 0377,
|
||
(int) (cmd >> 8) & 0377,
|
||
(int) cmd & 0377);
|
||
} else if (sw & SWMASK ('X')) {
|
||
fprintf (of, "%013llx", cmd);
|
||
} else
|
||
fprintf (of, "%04o %04o %04o %04o",
|
||
(int) (cmd >> 36) & 07777,
|
||
(int) (cmd >> 24) & 07777,
|
||
(int) (cmd >> 12) & 07777,
|
||
(int) cmd & 07777);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/*
|
||
* Symbolic input
|
||
*
|
||
* Inputs:
|
||
* *cptr = pointer to input string
|
||
* addr = current PC
|
||
* *uptr = pointer to unit
|
||
* *val = pointer to output values
|
||
* sw = switches
|
||
* Outputs:
|
||
* status = error status
|
||
*/
|
||
t_stat parse_sym (CONST 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];
|
||
CONST char *p;
|
||
int i, c;
|
||
again:
|
||
if (! fgets (buf, sizeof (buf), input)) {
|
||
*type = 0;
|
||
return SCPE_OK;
|
||
}
|
||
p = skip_spaces (buf);
|
||
if (*p == '\n' || *p == ';')
|
||
goto again;
|
||
c = utf8_to_unicode (&p);
|
||
if (c == CYRILLIC_SMALL_LETTER_VE ||
|
||
c == CYRILLIC_CAPITAL_LETTER_VE ||
|
||
c == 'b' || c == 'B') {
|
||
/* Адрес размещения данных. */
|
||
*type = ':';
|
||
*val = strtol (p, 0, 8);
|
||
return SCPE_OK;
|
||
}
|
||
if (c == CYRILLIC_SMALL_LETTER_PE ||
|
||
c == CYRILLIC_CAPITAL_LETTER_PE ||
|
||
c == 'p' || c == 'P') {
|
||
/* Стартовый адрес. */
|
||
*type = '@';
|
||
*val = strtol (p, 0, 8);
|
||
return SCPE_OK;
|
||
}
|
||
if (c == CYRILLIC_SMALL_LETTER_CHE ||
|
||
c == CYRILLIC_CAPITAL_LETTER_CHE ||
|
||
c == 'f' || c == 'F') {
|
||
/* Вещественное число. */
|
||
*type = '=';
|
||
*val = ieee_to_besm6 (strtod (p, 0));
|
||
return SCPE_OK;
|
||
}
|
||
if (c == CYRILLIC_SMALL_LETTER_ES ||
|
||
c == CYRILLIC_CAPITAL_LETTER_ES ||
|
||
c == 'c' || c == 'C') {
|
||
/* Восьмеричное слово. */
|
||
*type = '=';
|
||
*val = 0;
|
||
for (i=0; i<16; ++i) {
|
||
p = skip_spaces (p);
|
||
if (*p < '0' || *p > '7') {
|
||
if (i == 0) {
|
||
/* слишком короткое слово */
|
||
goto bad;
|
||
}
|
||
break;
|
||
}
|
||
*val = *val << 3 | (*p++ - '0');
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
if (c == CYRILLIC_SMALL_LETTER_KA ||
|
||
c == CYRILLIC_CAPITAL_LETTER_KA ||
|
||
c == 'k' || c == 'K') {
|
||
/* Команда. */
|
||
*type = '*';
|
||
if (parse_instruction_word (p, val) != SCPE_OK)
|
||
goto bad;
|
||
return SCPE_OK;
|
||
}
|
||
/* Неверная строка входного файла */
|
||
bad: besm6_log ("Invalid input line: %s", buf);
|
||
return SCPE_FMT;
|
||
}
|
||
|
||
/*
|
||
* Load memory from file.
|
||
*/
|
||
t_stat besm6_load (FILE *input)
|
||
{
|
||
int addr, type;
|
||
t_value word;
|
||
t_stat err;
|
||
|
||
addr = 1;
|
||
PC = 1;
|
||
for (;;) {
|
||
err = besm6_read_line (input, &type, &word);
|
||
if (err)
|
||
return err;
|
||
switch (type) {
|
||
case 0: /* EOF */
|
||
return SCPE_OK;
|
||
case ':': /* address */
|
||
addr = (int)word;
|
||
break;
|
||
case '=': /* word */
|
||
if (addr < 010)
|
||
pult [0][addr] = SET_PARITY (word, PARITY_NUMBER);
|
||
else
|
||
memory [addr] = SET_PARITY (word, PARITY_NUMBER);
|
||
++addr;
|
||
break;
|
||
case '*': /* instruction */
|
||
if (addr < 010)
|
||
pult [0][addr] = SET_PARITY (word, PARITY_INSN);
|
||
else
|
||
memory [addr] = SET_PARITY (word, PARITY_INSN);
|
||
++addr;
|
||
break;
|
||
case '@': /* start address */
|
||
PC = (uint32)word;
|
||
break;
|
||
}
|
||
if (addr > MEMSIZE)
|
||
return SCPE_FMT;
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/*
|
||
* Dump memory to file.
|
||
*/
|
||
t_stat besm6_dump (FILE *of, const 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 [0][addr];
|
||
else
|
||
word = memory [addr];
|
||
if (word == 0)
|
||
continue;
|
||
if (addr != last_addr+1) {
|
||
fprintf (of, "\nв %05o\n", addr);
|
||
}
|
||
last_addr = addr;
|
||
if (IS_INSN (word)) {
|
||
fprintf (of, "к ");
|
||
besm6_fprint_cmd (of, (uint32)(word >> 24));
|
||
fprintf (of, ", ");
|
||
besm6_fprint_cmd (of, word & BITS(24));
|
||
fprintf (of, "\t\t; %05o - ", addr);
|
||
fprintf (of, "%04o %04o %04o %04o\n",
|
||
(int) (word >> 36) & 07777,
|
||
(int) (word >> 24) & 07777,
|
||
(int) (word >> 12) & 07777,
|
||
(int) word & 07777);
|
||
} else {
|
||
fprintf (of, "с %04o %04o %04o %04o",
|
||
(int) (word >> 36) & 07777,
|
||
(int) (word >> 24) & 07777,
|
||
(int) (word >> 12) & 07777,
|
||
(int) word & 07777);
|
||
fprintf (of, "\t\t; %05o\n", addr);
|
||
}
|
||
}
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/*
|
||
* Loader/dumper
|
||
*/
|
||
t_stat sim_load (FILE *fi, CONST char *cptr, CONST char *fnam, int dump_flag)
|
||
{
|
||
if (dump_flag)
|
||
return besm6_dump (fi, fnam);
|
||
|
||
return besm6_load (fi);
|
||
}
|