BESM6: Implemented WRU when no local console, added binary punchtape mode,

translated some comments.
This commit is contained in:
Leo Broukhis 2015-01-11 17:43:39 -08:00
parent c2cef3c051
commit 8f6e849ecf
7 changed files with 302 additions and 173 deletions

View file

@ -65,16 +65,27 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
extern const char *scp_errors[]; extern const char *scp_errors[];
/* нехранящие биты ГРП должны сбрасываться путем обнуления тех регистров, /* Wired (non-registered) bits of interrupt registers (GRP and PRP)
* сборкой которых они являются * cannot be cleared by writing to the GRP and must be cleared by clearing
* the registers generating the corresponding interrupts.
*/ */
#define GRP_WIRED_BITS 01400743700000000LL #define GRP_WIRED_BITS (GRP_DRUM1_FREE | GRP_DRUM2_FREE |\
GRP_CHAN3_DONE | GRP_CHAN4_DONE |\
GRP_CHAN5_DONE | GRP_CHAN6_DONE |\
GRP_CHAN3_FREE | GRP_CHAN4_FREE |\
GRP_CHAN5_FREE | GRP_CHAN6_FREE |\
GRP_CHAN7_FREE )
#define PRP_WIRED_BITS 0770000 /* So far irrelevant as none of the devices -
* punchcard I/O and punchtape output - had been implemented.
*/
#define PRP_WIRED_BITS (PRP_UVVK1_END | PRP_UVVK2_END |\
PRP_PCARD1_CHECK | PRP_PCARD2_CHECK |\
PRP_PCARD1_PUNCH | PRP_PCARD2_PUNCH |\
PRP_PTAPE1_PUNCH | PRP_PTAPE2_PUNCH )
int corr_stack; int corr_stack;
int redraw_panel; int redraw_panel;
uint32 delay;
jmp_buf cpu_halt; jmp_buf cpu_halt;
t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_examine (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
@ -131,7 +142,7 @@ REG cpu_reg[] = {
}; };
MTAB cpu_mod[] = { MTAB cpu_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle, NULL, "Display idle detection mode" }, { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle, NULL, "Enables idle detection mode" },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL, "Disables idle detection" }, { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL, NULL, "Disables idle detection" },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "REQ", &cpu_req, NULL, NULL, "Sends a request interrupt" }, { MTAB_XTD|MTAB_VDV, 0, NULL, "REQ", &cpu_req, NULL, NULL, "Sends a request interrupt" },
{ MTAB_XTD|MTAB_VDV, 0, "PANEL", "PANEL", &besm6_init_panel, NULL, NULL, "Displays graphical panel" }, { MTAB_XTD|MTAB_VDV, 0, "PANEL", "PANEL", &besm6_init_panel, NULL, NULL, "Displays graphical panel" },
@ -148,16 +159,16 @@ DEVICE cpu_dev = {
}; };
/* /*
* REG: псевдоустройство, содержащее латинские синонимы всех регистров. * REG: A pseudo-device containing Latin synonyms of all CPU registers.
*/ */
REG reg_reg[] = { REG reg_reg[] = {
{ "PC", &PC, 8, 15, 0, 1 }, /* счётчик адреса команды */ { "PC", &PC, 8, 15, 0, 1 }, /* program counter */
{ "RK", &RK, 8, 24, 0, 1 }, /* регистр выполняемой команды */ { "RK", &RK, 8, 24, 0, 1 }, /* instruction register */
{ "Aex", &Aex, 8, 15, 0, 1 }, /* исполнительный адрес */ { "Aex", &Aex, 8, 15, 0, 1 }, /* effective address */
{ "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* сумматор */ { "ACC", &ACC, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* accumulator */
{ "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* регистр младших разрядов */ { "RMR", &RMR, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* LSB register */
{ "RAU", &RAU, 2, 6, 0, 1 }, /* режимы АУ */ { "RAU", &RAU, 2, 6, 0, 1 }, /* ALU modes */
{ "M1", &M[1], 8, 15, 0, 1 }, /* регистры-модификаторы */ { "M1", &M[1], 8, 15, 0, 1 }, /* index (modifier) registers */
{ "M2", &M[2], 8, 15, 0, 1 }, { "M2", &M[2], 8, 15, 0, 1 },
{ "M3", &M[3], 8, 15, 0, 1 }, { "M3", &M[3], 8, 15, 0, 1 },
{ "M4", &M[4], 8, 15, 0, 1 }, { "M4", &M[4], 8, 15, 0, 1 },
@ -171,19 +182,19 @@ REG reg_reg[] = {
{ "M14", &M[014], 8, 15, 0, 1 }, { "M14", &M[014], 8, 15, 0, 1 },
{ "M15", &M[015], 8, 15, 0, 1 }, { "M15", &M[015], 8, 15, 0, 1 },
{ "M16", &M[016], 8, 15, 0, 1 }, { "M16", &M[016], 8, 15, 0, 1 },
{ "M17", &M[017], 8, 15, 0, 1 }, /* указатель магазина */ { "M17", &M[017], 8, 15, 0, 1 }, /* also the stack pointer */
{ "M20", &M[020], 8, 15, 0, 1 }, /* MOD - модификатор адреса */ { "M20", &M[020], 8, 15, 0, 1 }, /* MOD - address modifier register */
{ "M21", &M[021], 8, 15, 0, 1 }, /* PSW - режимы УУ */ { "M21", &M[021], 8, 15, 0, 1 }, /* PSW - CU modes */
{ "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - упрятывание режимов УУ */ { "M27", &M[027], 8, 15, 0, 1 }, /* SPSW - saved CU modes */
{ "M32", &M[032], 8, 15, 0, 1 }, /* ERET - адрес возврата из экстракода */ { "M32", &M[032], 8, 15, 0, 1 }, /* ERET - extracode return address */
{ "M33", &M[033], 8, 15, 0, 1 }, /* IRET - адрес возврата из прерывания */ { "M33", &M[033], 8, 15, 0, 1 }, /* IRET - interrupt return address */
{ "M34", &M[034], 8, 16, 0, 1 }, /* IBP - адрес прерывания по выполнению */ { "M34", &M[034], 8, 16, 0, 1 }, /* IBP - instruction bkpt address */
{ "M35", &M[035], 8, 16, 0, 1 }, /* DWP - адрес прерывания по чтению/записи */ { "M35", &M[035], 8, 16, 0, 1 }, /* DWP - watchpoint address */
{ "RUU", &RUU, 2, 9, 0, 1 }, /* ПКП, ПКЛ, РежЭ, РежПр, ПрИК, БРО, ПрК */ { "RUU", &RUU, 2, 9, 0, 1 }, /* execution modes */
{ "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* главный регистр прерываний */ { "GRP", &GRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* main interrupt reg */
{ "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* маска ГРП */ { "MGRP", &MGRP, 8, 48, 0, 1, NULL, NULL, REG_VMIO}, /* mask of the above */
{ "PRP", &PRP, 8, 24, 0, 1 }, /* периферийный регистр прерываний */ { "PRP", &PRP, 8, 24, 0, 1 }, /* peripheral interrupt reg */
{ "MPRP", &MPRP, 8, 24, 0, 1 }, /* маска ПРП */ { "MPRP", &MPRP, 8, 24, 0, 1 }, /* mask of the above*/
{ "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, { "BRZ0", &BRZ[0], 8, 50, 0, 1, NULL, NULL, REG_VMIO },
{ "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO }, { "BRZ1", &BRZ[1], 8, 50, 0, 1, NULL, NULL, REG_VMIO },
@ -245,7 +256,7 @@ char sim_name[] = "БЭСМ-6";
REG *sim_PC = &cpu_reg[0]; REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1; /* максимальное количество слов в машинной команде */ int32 sim_emax = 1; /* max number of addressable units per instruction */
DEVICE *sim_devices[] = { DEVICE *sim_devices[] = {
&cpu_dev, &cpu_dev,
@ -328,7 +339,7 @@ t_stat cpu_reset (DEVICE *dptr)
for (i=0; i<NREGS; ++i) for (i=0; i<NREGS; ++i)
M[i] = 0; M[i] = 0;
/* Устройства ввода с перфокарт не готовы */ /* Punchcard readers not yet implemented thus not ready */
READY2 |= 042000000; READY2 |= 042000000;
/* Регистр 17: БлП, БлЗ, ПОП, ПОК, БлПр */ /* Регистр 17: БлП, БлЗ, ПОП, ПОК, БлПр */
@ -435,8 +446,8 @@ static void cmd_002 ()
MGRP = ACC; MGRP = ACC;
break; break;
case 037: case 037:
/* Гашение главного регистра прерываний */ /* Clearing the main interrupt register: */
/* нехранящие биты невозможно погасить */ /* it is impossible to clear wired (stateless) bits this way */
GRP &= ACC | GRP_WIRED_BITS; GRP &= ACC | GRP_WIRED_BITS;
break; break;
case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71:
@ -471,8 +482,7 @@ static void cmd_002 ()
break; break;
default: default:
if ((Aex & 0340) == 0140) { if ((Aex & 0340) == 0140) {
/* TODO: управление блокировкой схемы /* TODO: watchdog reset mechanism */
* автоматического запуска */
longjmp (cpu_halt, STOP_UNIMPLEMENTED); longjmp (cpu_halt, STOP_UNIMPLEMENTED);
} }
/* Неиспользуемые адреса */ /* Неиспользуемые адреса */
@ -493,8 +503,13 @@ static void cmd_033 ()
#endif #endif
switch (Aex & 04177) { switch (Aex & 04177) {
case 0: case 0:
/* Точно неизвестно, что это такое, но драйвер МД /*
* иногда выдает команду "увв 0". */ * Using an I/O control instruction with Aex == 0
* after issuing a 033 instruction with a non-zero Aex
* to send data to a device was required
* for some devices (e.g. printers) according to the docs.
* What is the exact purpose is unclear (timing, power, ???)
*/
break; break;
case 1: case 2: case 1: case 2:
/* Управление обменом с магнитными барабанами */ /* Управление обменом с магнитными барабанами */
@ -562,7 +577,7 @@ static void cmd_033 ()
tty_send ((uint32) ACC & BITS(24)); tty_send ((uint32) ACC & BITS(24));
break; break;
case 0141: case 0141:
/* TODO: управление разметкой магнитной ленты */ /* TODO: formatting magnetic tape */
longjmp (cpu_halt, STOP_UNIMPLEMENTED); longjmp (cpu_halt, STOP_UNIMPLEMENTED);
break; break;
case 0142: case 0142:
@ -570,11 +585,12 @@ static void cmd_033 ()
longjmp (cpu_halt, STOP_UNIMPLEMENTED); longjmp (cpu_halt, STOP_UNIMPLEMENTED);
break; break;
case 0147: case 0147:
/* Запись в регистр управления электропитанием, */ /* Writing to the power supply control register
/* не оказывает видимого эффекта на выполнение */ * does not have any observable effect
*/
break; break;
case 0150: case 0151: case 0150: case 0151:
/* TODO: управление вводом с перфокарт */ /* TODO: reading from punchcards */
longjmp (cpu_halt, STOP_UNIMPLEMENTED); longjmp (cpu_halt, STOP_UNIMPLEMENTED);
break; break;
case 0153: case 0153:
@ -727,10 +743,9 @@ void check_initial_setup ()
*/ */
return; return;
} }
if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || if ((memory[TAKEN] & SETUP_REQS_ENABLED) == 0 || /* not ready for setup */
(memory[TAKEN] & ALL_REQS_ENABLED) != 0 || (memory[TAKEN] & ALL_REQS_ENABLED) != 0 || /* all done */
(MGRP & GRP_PANEL_REQ) == 0) { (MGRP & GRP_PANEL_REQ) == 0) { /* not at the moment */
/* Слишком рано, или уже не надо, или невовремя */
return; return;
} }
@ -774,7 +789,7 @@ void check_initial_setup ()
/* /*
* Execute one instruction, placed on address PC:RUU_RIGHT_INSTR. * Execute one instruction, placed on address PC:RUU_RIGHT_INSTR.
* Increment delay. When stopped, perform a longjmp to cpu_halt, * When stopped, perform a longjmp to cpu_halt,
* sending a stop code. * sending a stop code.
*/ */
void cpu_one_inst () void cpu_one_inst ()
@ -782,6 +797,14 @@ void cpu_one_inst ()
int reg, opcode, addr, nextpc, next_mod; int reg, opcode, addr, nextpc, next_mod;
t_value word; t_value word;
/*
* Instruction execution time in 100 ns ticks; not really used
* as the amortized 1 MIPS instruction rate is assumed.
* The assignments of MEAN_TIME(x,y) to the delay variable
* are kept as a reference.
*/
uint32 delay;
corr_stack = 0; corr_stack = 0;
word = mmu_fetch (PC); word = mmu_fetch (PC);
if (RUU & RUU_RIGHT_INSTR) if (RUU & RUU_RIGHT_INSTR)
@ -1668,7 +1691,11 @@ t_stat sim_instr (void)
} }
} }
if (PC > BITS(15)) { /* выход за пределы памяти */ if (PC > BITS(15) && IS_SUPERVISOR(RUU)) {
/*
* Runaway instruction execution in supervisor mode
* warrants attention.
*/
besm6_draw_panel(); besm6_draw_panel();
return STOP_RUNOUT; /* stop simulation */ return STOP_RUNOUT; /* stop simulation */
} }
@ -1680,7 +1707,8 @@ t_stat sim_instr (void)
} }
if (PRP & MPRP) { if (PRP & MPRP) {
/* регистр хранящий, сбрасывается программно */ /* There are interrupts pending in the peripheral
* interrupt register */
GRP |= GRP_SLAVE; GRP |= GRP_SLAVE;
} }
@ -1701,8 +1729,10 @@ t_stat sim_instr (void)
} }
/* /*
* В 9-й части частота таймера 250 Гц (4 мс), * A 250 Hz clock as per the original documentation,
* в жизни - 50 Гц (20 мс). * and matching the available software binaries.
* Some installations used 50 Hz with a modified OS
* for a better user time/system time ratio.
*/ */
t_stat fast_clk (UNIT * this) t_stat fast_clk (UNIT * this)
{ {
@ -1712,18 +1742,17 @@ t_stat fast_clk (UNIT * this)
++counter; ++counter;
++tty_counter; ++tty_counter;
/*besm6_debug ("*** таймер 20 мсек");*/
GRP |= GRP_TIMER; GRP |= GRP_TIMER;
/* Медленный таймер: должен быть 16 Гц. if ((counter & 15) == 0) {
* Но от него почему-то зависит вывод на терминалы, /*
* поэтому ускорим. */ * The OS used the (undocumented, later addition) slow clock interrupt to initiate servicing
if ((counter & 3) == 0) { * terminal I/O. Its frequency was reportedly 16 Hz; 64 ms is a good enough approximation.
/*besm6_debug ("*** таймер 80 мсек");*/ */
GRP |= GRP_SLOW_CLK; GRP |= GRP_SLOW_CLK;
} }
/* Перерисовка панели каждые 64 миллисекунды. */ /* Requesting panel redraw every 64 ms. */
if ((counter & 15) == 0) { if ((counter & 15) == 0) {
redraw_panel = 1; redraw_panel = 1;
} }
@ -1741,7 +1770,7 @@ t_stat fast_clk (UNIT * this)
} }
UNIT clocks[] = { UNIT clocks[] = {
{ UDATA(fast_clk, UNIT_IDLE, 0), CLK_DELAY }, /* 40 р, 50 Гц */ { UDATA(fast_clk, UNIT_IDLE, 0), CLK_DELAY }, /* Bit 40 of the GRP, 250 Hz */
}; };
t_stat clk_reset (DEVICE * dev) t_stat clk_reset (DEVICE * dev)

View file

@ -114,19 +114,15 @@ enum {
((x) >> 48) == CONVOL_NUMBER) ((x) >> 48) == CONVOL_NUMBER)
/* /*
* Вычисление правдоподобного времени выполнения команды, * An attempt to approximate instruction execution times.
* зная количество тактов в УУ и среднее в АУ. * The arguments number of clock ticks spent on an instruction
* Предполагаем, что в 50% случаев происходит совмещение * in the ALU and in the CU; the computed result assumes
* выполнения, поэтому суммируем большее и половину * a 50% overlap in execution.
* от меньшего значения.
*/ */
#define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y) #define MEAN_TIME(x,y) (x>y ? x+y/2 : x/2+y)
/* #define USEC 1 /* 1 microsecond */
* Считаем, что моделируеммая машина имеет опорную частоту 10 МГц. #define MSEC (1000*USEC) /* 1 millisecond */
*/
#define USEC 1 /* одна микросекунда - десять тактов */
#define MSEC (1000*USEC) /* одна миллисекунда */
#define CLK_TPS 250 /* Fast Clock Ticks Per Second (every 4ms) */ #define CLK_TPS 250 /* Fast Clock Ticks Per Second (every 4ms) */
#define CLK_DELAY 4000 /* Uncalibrated instructions per clock tick */ #define CLK_DELAY 4000 /* Uncalibrated instructions per clock tick */
@ -135,6 +131,7 @@ extern UNIT tty_unit[];
extern UNIT clocks[]; extern UNIT clocks[];
extern t_value memory [MEMSIZE]; extern t_value memory [MEMSIZE];
extern t_value pult [8]; extern t_value pult [8];
extern uint32 PC, RAU, RUU; extern uint32 PC, RAU, RUU;
extern uint32 M[NREGS]; extern uint32 M[NREGS];
extern t_value BRZ[8], RP[8], GRP, MGRP; extern t_value BRZ[8], RP[8], GRP, MGRP;
@ -379,14 +376,15 @@ t_value besm6_pack (t_value val, t_value mask);
t_value besm6_unpack (t_value val, t_value mask); t_value besm6_unpack (t_value val, t_value mask);
/* /*
* Разряды главного регистра прерываний (ГРП) * Bits of the main interrupt register ГРП (GRP)
* Внешние: * External:
*/ */
#define GRP_PRN1_SYNC 04000000000000000LL /* 48 */ #define GRP_PRN1_SYNC 04000000000000000LL /* 48 */
#define GRP_PRN2_SYNC 02000000000000000LL /* 47 */ #define GRP_PRN2_SYNC 02000000000000000LL /* 47 */
#define GRP_DRUM1_FREE 01000000000000000LL /* 46 */ #define GRP_DRUM1_FREE 01000000000000000LL /* 46 */
#define GRP_DRUM2_FREE 00400000000000000LL /* 45 */ #define GRP_DRUM2_FREE 00400000000000000LL /* 45 */
#define GRP_VNIIEM 00300000000000000LL /* 44-43, placeholder */ #define GRP_UVVK1_SYNC 00200000000000000LL /* 44 */
#define GRP_UVVK2_SYNC 00100000000000000LL /* 43 */
#define GRP_FS1_SYNC 00040000000000000LL /* 42 */ #define GRP_FS1_SYNC 00040000000000000LL /* 42 */
#define GRP_FS2_SYNC 00020000000000000LL /* 41 */ #define GRP_FS2_SYNC 00020000000000000LL /* 41 */
#define GRP_TIMER 00010000000000000LL /* 40 */ #define GRP_TIMER 00010000000000000LL /* 40 */
@ -405,10 +403,10 @@ t_value besm6_unpack (t_value val, t_value mask);
#define GRP_CHAN5_FREE 00000000400000000LL /* 27 */ #define GRP_CHAN5_FREE 00000000400000000LL /* 27 */
#define GRP_CHAN6_FREE 00000000200000000LL /* 26 */ #define GRP_CHAN6_FREE 00000000200000000LL /* 26 */
#define GRP_CHAN7_FREE 00000000100000000LL /* 25 */ #define GRP_CHAN7_FREE 00000000100000000LL /* 25 */
#define GRP_SERIAL 00000000001000000LL /* 19 */ #define GRP_SERIAL 00000000001000000LL /* 19, nonstandard */
#define GRP_WATCHDOG 00000000000002000LL /* 11 */ #define GRP_WATCHDOG 00000000000002000LL /* 11 */
#define GRP_SLOW_CLK 00000000000001000LL /* 10 */ #define GRP_SLOW_CLK 00000000000001000LL /* 10, nonstandard */
/* Внутренние: */ /* Internal: */
#define GRP_DIVZERO 00000000034000000LL /* 23-21 */ #define GRP_DIVZERO 00000000034000000LL /* 23-21 */
#define GRP_OVERFLOW 00000000014000000LL /* 22-21 */ #define GRP_OVERFLOW 00000000014000000LL /* 22-21 */
#define GRP_CHECK 00000000004000000LL /* 21 */ #define GRP_CHECK 00000000004000000LL /* 21 */
@ -426,6 +424,23 @@ t_value besm6_unpack (t_value val, t_value mask);
#define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK)) #define GRP_SET_BLOCK(x,m) (((x) & ~GRP_BLOCK_MASK) | ((m) & GRP_BLOCK_MASK))
#define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK)) #define GRP_SET_PAGE(x,m) (((x) & ~GRP_PAGE_MASK) | (((m)<<4) & GRP_PAGE_MASK))
/*
* Bits of the peripheral interrupt register ПРП (PRP)
*/
#define PRP_UVVK1_END 010000000 /* 22 */
#define PRP_UVVK2_END 004000000 /* 21 */
#define PRP_PCARD1_CHECK 002000000 /* 20 */
#define PRP_PCARD2_CHECK 001000000 /* 19 */
#define PRP_PCARD1_PUNCH 000400000 /* 18 */
#define PRP_PCARD2_PUNCH 000200000 /* 17 */
#define PRP_PTAPE1_PUNCH 000100000 /* 16 */
#define PRP_PTAPE2_PUNCH 000040000 /* 15 */
/* 14-13 unused */
#define PRP_CONS1_INPUT 000004000 /* 12 */
#define PRP_CONS2_INPUT 000002000 /* 11 */
#define PRP_CONS1_DONE 000001000 /* 10 */
#define PRP_CONS2_DONE 000000400 /* 9 */
/* Номер блока ОЗУ или номер страницы, вызвавших прерывание */ /* Номер блока ОЗУ или номер страницы, вызвавших прерывание */
extern uint32 iintr_data; extern uint32 iintr_data;

View file

@ -89,6 +89,7 @@ DEVICE fs_dev = {
enum { enum {
FS_IDLE, FS_IDLE,
FS_STARTING, FS_STARTING,
FS_BINARY,
FS_RUNNING, FS_RUNNING,
FS_IMAGE, FS_IMAGE,
FS_IMAGE_LAST = FS_IMAGE + CARD_LEN - 1, FS_IMAGE_LAST = FS_IMAGE + CARD_LEN - 1,
@ -100,6 +101,8 @@ enum {
FS_TAIL, FS_TAIL,
} fs_state[2]; } fs_state[2];
int fs_textmode[2];
/* /*
* Reset routine * Reset routine
*/ */
@ -116,10 +119,16 @@ t_stat fs_reset (DEVICE *dptr)
return SCPE_OK; return SCPE_OK;
} }
/*
* Attaches a raw binary file by default,
* with a -t switch attaches a prepared text file in UTF-8.
*/
t_stat fs_attach (UNIT *u, char *cptr) t_stat fs_attach (UNIT *u, char *cptr)
{ {
t_stat s; t_stat s;
int num = u - fs_unit; int num = u - fs_unit;
fs_textmode[num] = sim_switches & SWMASK('T');
sim_switches &= ~SWMASK('T');
s = attach_unit (u, cptr); s = attach_unit (u, cptr);
if (s != SCPE_OK) if (s != SCPE_OK)
return s; return s;
@ -186,6 +195,20 @@ void fs_control (int num, uint32 cmd)
} }
unsigned char unicode_to_gost (unsigned short val); unsigned char unicode_to_gost (unsigned short val);
/*
* The UPP code is the GOST 10859 code with odd parity.
* UPP stood for "unit for preparation of punchards".
*/
static unsigned char unicode_to_upp (unsigned short ch) {
unsigned char ret;
ch = ret = unicode_to_gost (ch);
ch = (ch & 0x55) + ((ch >> 1) & 0x55);
ch = (ch & 0x33) + ((ch >> 2) & 0x33);
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
return (ch & 1) ? ret : ret | 0x80;
}
static int utf8_getc (FILE *fin); static int utf8_getc (FILE *fin);
/* /*
@ -194,64 +217,66 @@ static int utf8_getc (FILE *fin);
*/ */
t_stat fs_event (UNIT *u) t_stat fs_event (UNIT *u)
{ {
static int cnt;
int num = u - fs_unit; int num = u - fs_unit;
again: again:
if (fs_state[num] == FS_STARTING) { if (fs_state[num] == FS_STARTING) {
/* По первому прерыванию после запуска двигателя ничего не читаем */ /* The first interrupt after starting the motor is dummy,
* no need to read anything from the attached file.
*/
FS[num] = 0; FS[num] = 0;
fs_state[num] = FS_RUNNING; cnt = 0;
} else if (fs_state[num] == FS_RUNNING) { fs_state[num] = fs_textmode[num] ? FS_RUNNING : FS_BINARY;
int ch; } else if (fs_state[num] == FS_BINARY) {
/* переводы строк игнорируются */ int ch = getc (u->fileref);
while ((ch = utf8_getc (u->fileref)) == '\n');
if (ch < 0) { if (ch < 0) {
/* хвост ленты без пробивок */
FS[num] = 0; FS[num] = 0;
fs_state[num] = FS_TAIL; fs_state[num] = FS_TAIL;
} else if (ch == '\f') { } else {
FS[num] = ch;
}
} else if (fs_state[num] == FS_RUNNING) {
int ch;
/* Line separators are ignored in running text mode */
do ch = utf8_getc (u->fileref); while (ch == '\n' || ch == '\r');
if (ch < 0) {
/* the tail end of the tape has no holes */
FS[num] = 0;
fs_state[num] = FS_TAIL;
} else if (ch == (']' & 037)) {
/* Switching from running text mode to "virtual punchcard" mode and back
* is done with an ASCII GS (group separator) symbol ctrl-].
*/
fs_state[num] = FS_IMAGE; fs_state[num] = FS_IMAGE;
goto again; goto again;
} else { } else {
ch = FS[num] = unicode_to_gost (ch); FS[num] = unicode_to_upp (ch);
ch = (ch & 0x55) + ((ch >> 1) & 0x55);
ch = (ch & 0x33) + ((ch >> 2) & 0x33);
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
if (ch & 1); else FS[num] |= 0x80;
} }
} else if (FS_IMAGE <= fs_state[num] && fs_state[num] <= FS_IMAGE_LAST) { } else if (FS_IMAGE <= fs_state[num] && fs_state[num] <= FS_IMAGE_LAST) {
int ch = utf8_getc (u->fileref); int ch = utf8_getc (u->fileref);
if (ch < 0) { if (ch < 0) {
/* обрыв ленты */ /* premature end of tape */
FS[num] = 0; FS[num] = 0;
fs_state[num] = FS_TAIL; fs_state[num] = FS_TAIL;
} else if (ch == '\r') {
/* always ignored */
goto again;
} else if (ch == '\n') { } else if (ch == '\n') {
/* идем дополнять образ карты нулевыми байтами */ /* Start returning zero bytes up to the end of the current "virtual punchard" */
fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE); fs_state[num] = FS_FILLUP + (fs_state[num] - FS_IMAGE);
goto again; goto again;
} else if (ch == '\f') { } else if (ch == (']' & 037)) {
if (fs_state[num] != FS_IMAGE) if (fs_state[num] != FS_IMAGE)
besm6_debug("<<< ENDA3 requested mid-card?"); besm6_debug("<<< ENDA3 requested mid-card?");
fs_state[num] = FS_ENDA3; fs_state[num] = FS_ENDA3;
goto again; goto again;
} else { } else {
ch = FS[num] = unicode_to_gost (ch); FS[num] = unicode_to_upp (ch);
ch = (ch & 0x55) + ((ch >> 1) & 0x55); if (++fs_state[num] == FS_TOOLONG) {
ch = (ch & 0x33) + ((ch >> 2) & 0x33); /* If a line is too long (> 120 chars), start the next "virtual punchcard" */
ch = (ch & 0x0F) + ((ch >> 4) & 0x0F); fs_state[num] = FS_IMAGE;
if (ch & 1); else FS[num] |= 0x80; }
++fs_state[num];
} }
} else if (fs_state[num] == FS_TOOLONG) {
/* дочитываем до конца строки */
int ch;
besm6_debug("<<< too long???");
while ((ch = utf8_getc (u->fileref)) != '\n' && ch >= 0);
if (ch < 0) {
/* хвост ленты без пробивок */
FS[num] = 0;
fs_state[num] = FS_TAIL;
} else
goto again;
} else if (FS_FILLUP <= fs_state[num] && fs_state[num] <= FS_FILLUP_LAST) { } else if (FS_FILLUP <= fs_state[num] && fs_state[num] <= FS_FILLUP_LAST) {
FS[num] = 0; FS[num] = 0;
if (++fs_state[num] == FS_ENDA3) { if (++fs_state[num] == FS_ENDA3) {
@ -278,15 +303,21 @@ int fs_read(int num) {
return FS[num]; return FS[num];
} }
/*
* Unlike the OS which uses GOST overline (approximated by ^) as a line separator
* in running text mode, the BESM-ALGOL programming system used a nonprintable
* character (0174) from the unused part of the codetable to allow compressing multiple
* source lines on a punchcard. To specify that character,
* we use ASCII RS (record separator) symbol ctrl-^.
*/
unsigned char unsigned char
unicode_to_gost (unsigned short val) unicode_to_gost (unsigned short val)
{ {
static const unsigned char tab0 [256] = { static const unsigned char tab0 [256] = {
/* 00 - 07 */ 017, 017, 017, 017, 017, 017, 017, 017, /* 00 - 07 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 08 - 0f */ 017, 017, 0214, 017, 017, 0174, 017, 017, /* 08 - 0f */ 017, 017, 0214, 017, 017, 017, 017, 017,
/* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017, /* 10 - 17 */ 017, 017, 017, 017, 017, 017, 017, 017,
/* 18 - 1f */ 017, 017, 017, 017, 017, 017, 017, 017, /* 18 - 1f */ 017, 017, 017, 017, 017, 017, 0174, 017,
/* !"#$%&' */ 0017, 0133, 0134, 0034, 0127, 0126, 0121, 0033, /* !"#$%&' */ 0017, 0133, 0134, 0034, 0127, 0126, 0121, 0033,
/* ()*+,-./ */ 0022, 0023, 0031, 0012, 0015, 0013, 0016, 0014, /* ()*+,-./ */ 0022, 0023, 0031, 0012, 0015, 0013, 0016, 0014,
/* 01234567 */ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, /* 01234567 */ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
@ -413,6 +444,11 @@ unicode_to_gost (unsigned short val)
case 0x83: return 0122; case 0x83: return 0122;
} }
break; break;
case 0x23:
switch ((unsigned char) val) {
case 0xe8: return 0020;
}
break;
case 0x25: case 0x25:
switch ((unsigned char) val) { switch ((unsigned char) val) {
case 0xc7: return 0127; case 0xc7: return 0127;

View file

@ -97,6 +97,8 @@ t_stat vt_clk(UNIT *);
extern char *get_sim_sw (char *cptr); extern char *get_sim_sw (char *cptr);
extern int32 tmr_poll; /* calibrated clock timer poll */ extern int32 tmr_poll; /* calibrated clock timer poll */
int attached_console;
UNIT tty_unit [] = { UNIT tty_unit [] = {
{ UDATA (vt_clk, UNIT_DIS|UNIT_IDLE, 0) }, /* fake unit, clock */ { UDATA (vt_clk, UNIT_DIS|UNIT_IDLE, 0) }, /* fake unit, clock */
{ UDATA (NULL, UNIT_SEQ, 0) }, { UDATA (NULL, UNIT_SEQ, 0) },
@ -228,6 +230,19 @@ t_stat vt_clk (UNIT * this)
t->rxb [t->rxbpi++] = '\3'; t->rxb [t->rxbpi++] = '\3';
} }
/*
* It the operator console is remote, we still need to probe the local keyboard
* for a WRU, say, 10 times a second.
*/
if (!attached_console) {
static int divider;
if (++divider == CLK_TPS/10) {
divider == 0;
if (SCPE_STOP == sim_poll_kbd())
stop_cpu = 1;
}
}
/* Polling sockets for transmission. */ /* Polling sockets for transmission. */
tmxr_poll_tx (&tty_desc); tmxr_poll_tx (&tty_desc);
/* If the TTY system is not idle, schedule the next interrupt /* If the TTY system is not idle, schedule the next interrupt
@ -343,6 +358,7 @@ t_stat tty_attach (UNIT *u, char *cptr)
if (num <= TTY_MAX) if (num <= TTY_MAX)
vt_mask |= 1 << (TTY_MAX - num); vt_mask |= 1 << (TTY_MAX - num);
besm6_debug ("*** console on T%03o", num); besm6_debug ("*** console on T%03o", num);
attached_console = 1;
return SCPE_OK; return SCPE_OK;
} }
return SCPE_ALATT; return SCPE_ALATT;

View file

@ -7,18 +7,18 @@ set cpu idle
;set disk debug ;set disk debug
; ;
; Приводим барабаны в исходное состояние. ; Initializing the magnetic drums.
; ;
attach -n drum0 drum1x.bin attach -n drum0 drum1x.bin
attach -n drum1 drum2x.bin attach -n drum1 drum2x.bin
; ;
; Создаем рабочий диск. ; Initializing a scratch disk.
; ;
attach -n disk6 2052.bin attach -n disk6 2052.bin
; ;
; Подключаем диски. ; Attaching system disks.
; ;
attach -e disk7 sbor2053.bin attach -e disk7 sbor2053.bin
attach -e disk5 krab2063.bin attach -e disk5 krab2063.bin
@ -27,27 +27,47 @@ attach -e disk1 svs2048.bin
attach -e disk2 alt2048.bin attach -e disk2 alt2048.bin
; ;
; Подключаем АЦПУ. ; Attaching an output file.
; ;
attach prn0 output.txt attach -n prn0 output.txt
; ;
; Активируем операторский терминал, ; Allowing telnet connections, port 4199.
; на который идут сообщения.
; ;
attach tty 4199
;
; Attaching a terminal serving as the operator console.
;
; This works on UNIX-like systems.
attach tty1 console attach tty1 console
; On Windows, a UTF-8 connnection works better over telnet.
; Use a different port for the operator console just in case.
;attach tty Line=1,4198
;set env PATH %PATH%;C:\Program Files (x86)\PuTTY
;! start putty telnet://localhost:4198
; ;
; Режимы по вкусу ; On Unix, telnet can also be used for the operator console.
; ! gnome-terminal -x sh -c "telnet localhost 4198" &
; ;
; Terminal modes (how to enter Cyrillics, should the backspace be erasing), etc.
; (authbs == authentic non-erasing)
;
; Using UTF-8 for input
; set tty1 unicode,authbs
;
; Entering Russian letters as lowercase Latin letters
; according to the standard Russian layout
;set tty1 jcuken,authbs ;set tty1 jcuken,authbs
;
; Entering Russian letters as corresponding lowercase Latin letters.
; Q = "ya", W = "ve", Y = "yeru", J = "short I", X = "soft sign",
; C = "ts", V = "zhe", grave = "yu", tilde = "ch", { = "sh", } = "shch",
; | = "reverse e"
set tty1 qwerty,authbs set tty1 qwerty,authbs
set -n tty1 log=tty1.txt set -n tty1 log=tty1.txt
;
; Разрешаем подключение пользователей по telnet, порт 4199.
;
attach tty 4199
set tty2 authbs set tty2 authbs
set tty3 authbs set tty3 authbs
set tty4 authbs set tty4 authbs
@ -73,18 +93,30 @@ set tty23 authbs
set tty24 authbs set tty24 authbs
; ;
; Включение БРС/БРЗ для совместимости. ; Enabling the true LRU behavior of caches
; Замедляет работу на 20%. ; slows down the simulation speed ~20%
; ;
;set mmu cache ;set mmu cache
echo ###
echo ### Zeroing out the first page of RAM (as would be entered from
echo ### switch registers after powering up the machine,
echo ### likely about once a year or less).
echo ###
d -ml 1 xta, vtm 1777(1)
d -ml 2 atx (1), utm -1(1)
d -ml 3 v1m 2(1), stop
run 1
echo ###
echo ### Done; data cache registers are displayed above. An error message
echo ### would be usually displayed there after a STOP instruction.
echo ### Naturally, at the moment they all contain zeros. Booting the OS now...
echo ###
; ;
; Запуск ОС ДИСПАК. ; Booting OS DISPAK.
; ;
load boot_dispak.b6 load boot_dispak.b6
; Происходит контроль числа по адресу 1031
d 1031 0
run 2000 run 2000
;quit ;quit

View file

@ -1,10 +1,10 @@
# Attaching the input device # Attaching the input device
at fs0 input.txt at -t fs0 input.txt
# Waiting for the end of initial setup # Waiting for the end of initial setup
expect -r "ДATA.*\n" expect -r "ДATA.*\n"
do dispak.ini do dispak.ini
# Now we're ready to send commands from the front panel # Now we're ready to send commands from the front panel
echo Requesting input from the punch tape reader (FS8) echo Requesting input from the punch tape reader (FS8), it takes a few seconds
d 6 1 d 6 1
d 5 10 d 5 10
set cpu req set cpu req
@ -14,6 +14,7 @@ go
# The process had been started, check state every 10 model seconds # The process had been started, check state every 10 model seconds
send after=1000000 "WCPP\r" send after=1000000 "WCPP\r"
expect -p -r "4199.*\n" send after=10000000 "WCPP\r"; go expect -p -r "4199.*\n" send after=10000000 "WCPP\r"; go
expect -c "KЗ" step 10000000
expect -c "HET\r\n" step 10000 expect -c "HET\r\n" step 10000
go go
echo Enabling the printer (ONL A0) echo Enabling the printer (ONL A0)
@ -24,7 +25,7 @@ expect -r "ECT.*\n"
go go
echo Checking for the printing to finish echo Checking for the printing to finish
send "HOMB\r" send "HOMB\r"
expect -p -r "4199.*\n" send "HOMB\r"; go expect -p -r "A0.*\n" send "HOMB\r"; go
expect -c "HET\r\n" expect -c "HET\r\n"
go go
echo Done echo Done

View file

@ -1,6 +1,6 @@
ШИФР 419999 ЗС5^ ШИФР 419999 ЗС5^
EEВ1А3 EEВ1А3
*NAME PRIME NUMBERS *NAME PRIME NUMBERS
* The ^L char before *NAME is important * The ^L char before *NAME is important
* NO LIST Disable source listing by removing spaces between * and NO * NO LIST Disable source listing by removing spaces between * and NO
*NO LOAD LIST Enable loader listing by adding 5 spaces between * and NO *NO LOAD LIST Enable loader listing by adding 5 spaces between * and NO
@ -50,4 +50,4 @@ c------ Printing every 1000th prime number
*EXECUTE *EXECUTE
* The ^L char after *END FILE is important * The ^L char after *END FILE is important
*END FILE *END FILE
ЕКОНЕЦ ЕКОНЕЦ