GE-115 Emulator
An Emulator of the General Electrics GE-115 computer
ge.c
Go to the documentation of this file.
1#include <stdint.h>
2#include <stddef.h>
3#include <string.h>
4#include <unistd.h>
5#include "ge.h"
6#include "signals.h"
7#include "msl.h"
8#include "console_socket.h"
9#include "peripherical.h"
10#include "log.h"
11
12#define MAX_PROGRAM_STORAGE_WORDS 129
13
14void ge_init(struct ge *ge)
15{
16 memset(ge, 0, sizeof(*ge));
17 ge->halted = 1;
18 ge->powered = 1;
20
21 ge->ST3.name = "ST3";
22 ge->ST4.name = "ST4";
23
24 ge->channel2.name = "CAN2";
25}
26
27void ge_clear(struct ge *ge)
28{
29 ge->AINI = 0;
30 ge->ALAM = 0;
31 ge->PODI = 0;
32 ge->ADIR = 0;
33 ge->ACIC = 1;
34
35 /* After the powering on of the machine the timing starts pressing the
36 * "CLEAR" switch (cpu fo. 99). */
37 ge->halted = 0;
38
39 /* (One of) the possible set conditions (is): or with
40 * "CLEAR" and.. (cpu fo. 98) */
41 ge->ALTO = 1;
42
43 /* By pressing "CLEAR" tje FF RC01, RC02, RC03 are reset and the FF
44 * RC00 is set. (cpu fo. 115) */
45 ge->RC00 = 1;
46 ge->RC01 = 0;
47 ge->RC02 = 0;
48 ge->RC03 = 0;
49
50 /* REGEN: general clear of the integrated-reader command/mode latches (the
51 * controller's reset line). Pulse `regen` and drop the CPU->reader command
52 * lines + the CPU-selected read mode so a CLEAR returns the reader to its
53 * power-up state. (Inert: the data path and the harness-selected transcode
54 * mode are unaffected; active_valid==0 keeps the harness mode in force.) */
67 ge->PEC1_pending = 0;
68
70}
71
72/* Seed the eight change / segment-base registers to their identity defaults
73 * N<<12: change register N is the 16-bit big-endian word at mem[240+2N], and
74 * an instruction address with modifier N (address bits 12-14) resolves to
75 * displacement + base[N]. With these defaults a bare 12-bit displacement
76 * carrying modifier N addresses segment N (0x1000*N ..), so a program's paged
77 * addresses (e.g. JU 0x172a) resolve to their full load addresses; programs
78 * may reload a base via LR/LA for paged access.
79 *
80 * Called by ge_clear (reset) and re-applied after a direct binary image load,
81 * because a contiguous image spanning the 0x00F0-0x00FF window would otherwise
82 * overwrite the bases (with its own bytes, or zeros in reconstructed gaps). */
84{
85 for (int n = 0; n < 8; n++) {
86 uint16_t v = (uint16_t)(n << 12);
87 ge->mem[240 + 2 * n] = (uint8_t)(v >> 8);
88 ge->mem[240 + 2 * n + 1] = (uint8_t)(v & 0xff);
89 ge->cr_cache[n] = v; /* seed the addressing cache to match */
90 }
91}
92
93int ge_load_program(struct ge *ge, uint8_t *program, uint8_t size)
94{
95 if (program == NULL && size != 0)
96 return -1;
97
100
101 /* simulate the loading for now */
102 memcpy(ge->mem, program, size);
103 return 0;
104}
105
106/* odd-parity bit for a byte: 1 if the byte has an even number of set bits
107 * (so data+parity is odd). Mirrors odd_parity() in pulse.c. */
108static inline uint8_t ge_odd_parity(uint8_t data)
109{
110 return __builtin_parity(data) ? 0 : 1;
111}
112
113/* Store a byte to memory the way every real write does: data + generated odd
114 * parity + mark written. The microcoded path (pulse.c on_TO65) does this for
115 * itself (and honours the INCE check-bit forcing); this helper is for the
116 * hybrid ALU/SS execution helpers (alu_*.c) and the change-register store,
117 * which write ge->mem[] directly and would otherwise leave stale parity and
118 * trip a false MEM CHECK on read-back. */
119void ge_mem_store8(struct ge *ge, uint16_t addr, uint8_t val)
120{
121 ge->mem[addr] = val;
122 ge->mem_parity[addr] = ge_odd_parity(val);
123 ge->mem_written[addr] = 1;
124}
125
126/* Load a flat image into memory at `origin` (the unified-format payload).
127 * Unlike ge_load_program this is origin-aware and not size-capped; it also
128 * primes the parity store and marks the cells written, so reads of the loaded
129 * code parity-check cleanly. Returns 0 on success, -1 if it would exceed the
130 * installed memory. */
131int ge_load_image(struct ge *ge, const uint8_t *image, size_t size,
132 uint16_t origin)
133{
134 uint32_t max = ge->mem_size ? ge->mem_size : MEM_SIZE;
135
136 if (image == NULL && size != 0)
137 return -1;
138 if ((uint32_t)origin + (uint32_t)size > max)
139 return -1;
140
141 for (size_t i = 0; i < size; i++) {
142 uint16_t a = (uint16_t)(origin + i);
143 ge->mem[a] = image[i];
144 ge->mem_parity[a] = ge_odd_parity(image[i]);
145 ge->mem_written[a] = 1;
146 }
147 return 0;
148}
149
150/* Enter execution at `entry` without the peripheral LOAD bootstrap: seed the
151 * program counter and drop the sequencer straight into the alpha (fetch) phase.
152 * Use after ge_clear + ge_load_image for the direct binary-load path; the
153 * --deck card-reader path uses the natural state 00 -> 80 -> alpha bootstrap
154 * instead (which leaves entry at 0). */
155void ge_enter(struct ge *ge, uint16_t entry)
156{
157 ge->rPO = entry;
158 ge->rSO = 0xe2; /* alpha phase: fetch the instruction at PO */
159 ge->rSA = 0xe2;
160}
161
162void ge_load(struct ge *ge)
163{
164 /* When pressing LOAD button, AINI is set. If AINI is set, the state 80
165 * (initialitiation) goes to state c8, starting the loading of the program
166 * (of max 129 words) from one of the peripherc unit. */
167
168 /* set AINI FF to 1 (pag. 96) */
169 ge->AINI = 1;
170}
171
172void ge_load_1(struct ge * ge)
173{
174 /* It is possible to choose one between the two units thus prepared
175 * positioning the operating console switch LOAD1/LOAD2 (The possible
176 * choices are: Conn.2/Conn.3; Conn.4/Conn.3; Conn.2/Conn.4).
177 *
178 * (cpu fo. 43) */
179
180 /* from the previous manual excerpt, ,i would have expected ALOI = 0t to
181 * be LOAD1 and ALOI = 1 to be LOAD2, but running the initial load tests,
182 * ALOI = 1 will result in the machine using the 0x80 unit name, which is
183 * connector 2, while ALOI = 0 results in a 0x00 unit name, which is
184 * connector 3. */
185
186 ge->ALOI = 1;
187}
188
189void ge_load_2(struct ge * ge)
190{
191 ge->ALOI = 0;
192}
193
194void ge_start(struct ge *ge)
195{
196 /* according to the cpu documents, we should set the flipflop ARES here to
197 * implement the initial loading of 80 into SO, however with the current
198 * implementation it's not needed */
199
200 ge->ALTO = 0; /* cpu fo. 97 */
201}
202
203static void ge_print_well_known_states(uint8_t state) {
204 const char *name;
205 switch (state) {
206 case 0x00:
207 name = "- Display sequence";
208 break;
209 case 0x08:
210 name = "- Forcing sequence";
211 break;
212 case 0x64:
213 case 0x65:
214 name = "- Beta Phase";
215 break;
216 case 0x80:
217 name = "- Initialitiation";
218 break;
219 case 0xE2:
220 case 0xE3:
221 name = "- Alpha Phase";
222 break;
223 case 0xF0:
224 name = "- Interruption";
225 break;
226 default:
227 name = "";
228 }
229
230 ge_log(LOG_STATES, "Running state %02x %s\n", state, name);
231}
232
233const char *ge_clock_name(enum clock c)
234{
235 switch (c) {
236 #define X(name) \
237 case name : \
238 return #name ;
240 #undef X
241 }
242
243 return "";
244}
245
247{
249 return;
251 "SO: %02x SA: %02x PO: %04x RO: %04x BO: %04x FO: %04x - "
252 "V1: %04x V2: %04x V3: %04x V4: %04x - "
253 "L1: %04x L2: %04x L3 : %04x\n",
254 ge->rSO, ge->rSA, ge->rPO, ge->rRO, ge->rBO, ge->rFO,
255 ge->rV1, ge->rV2, ge->rV3, ge->rV4,
256 ge->rL1, ge->rL2, ge->rL3);
257}
258
260{
262 "%s: "
263 "SO: %02x SA: %02x PO: %04x RO: %04x BO: %04x FO: %04x - "
264 "NO: %02x NI: %02x - "
265 "FA: %02x FI: %02x - "
266 "V1: %04x V2: %04x V3: %04x V4: %04x - "
267 "L1: %04x L2: %04x L3 : %04x\n",
269 ge->rSO, ge->rSA, ge->rPO, ge->rRO, ge->rBO, ge->rFO,
270 NO_knot(ge), NI_knot(ge),
271 ge->ffFA, ge->ffFI,
272 ge->rV1, ge->rV2, ge->rV3, ge->rV4,
273 ge->rL1, ge->rL2, ge->rL3);
274}
275
277{
278 ge->current_clock++;
279 if (ge->current_clock == END_OF_STATUS)
280 ge->current_clock = TO00;
281}
282
283uint8_t ge_clock_is_first(struct ge* ge)
284{
285 return ge->current_clock == TO00;
286}
287
288uint8_t ge_clock_is_last(struct ge* ge)
289{
290 return ge->current_clock == (END_OF_STATUS - 1);
291}
292
293int ge_run_pulse(struct ge *ge)
294{
295 int r;
296 struct msl_timing_state *state;
297
298 if (ge_clock_is_first(ge)) {
299 r = ge_peri_on_clock(ge);
300 if (r != 0)
301 return r;
302
303 /* poll the connectors and try to set up the cpu state.
304 * should this be here? */
306 }
307
308 /* Execute common pulse machine logic */
309 pulse(ge);
310
311 /* Execute peripherals pulse callbacks */
313 if (r != 0)
314 return r;
315
316 /* Execute the commands from the timing charts */
317 state = msl_get_state(ge->rSA);
318
319 /* The state to execute gets loaded in SA at TO10 */
320 if (ge->current_clock == TO10)
322
323 if (!state) {
324 ge_log(LOG_ERR, "no timing charts found for state %02X\n", ge->rSA);
325 return 1;
326 }
327
328 /* Latch the instruction-start PC for the disassembly display. In the alpha
329 * fetch (e2/e3) PO addresses the opcode and is NOT advanced within the state
330 * (operand fetch / PO recomputation happens in the later e0/e4/e6 states), so
331 * this is the address of the instruction now executing. It stays put while
332 * operands are read and PO is recomputed (e.g. across a jump), so a UI
333 * highlight tracking it does not drift onto operand (DB) bytes or the next
334 * line — it only moves when the next instruction is actually fetched. */
335 if (ge->rSA == 0xe2 || ge->rSA == 0xe3)
336 ge->instr_pc = ge->rPO;
337
338 msl_run_state(ge, state);
339
340 if (ge_clock_is_last(ge)) {
343 }
344
346 return 0;
347}
348
349int ge_run_cycle(struct ge *ge)
350{
351 do {
352 int r = ge_run_pulse(ge);
353 if (r)
354 return r;
355 } while (!ge_clock_is_first(ge));
356
357 return 0;
358}
359
360int ge_deinit(struct ge *ge)
361{
363 return 0;
364}
365
367{
368 if (RA101(ge)) {
369 ge_log(LOG_READER, "RA101: signaling incoming data\n");
370 ge->RC01 = 1;
371 }
372}
373
374void fsn_last_clock(struct ge *ge)
375{
376 /* At the end of a CPU cycle the future-status network is stored in SO
377 * (cpu fo. 127), advancing the program sequencer one state.
378 *
379 * In maintenance forcing (rotary off NORM) the program sequencer is frozen:
380 * the manual (CPU[4] §4 "Maintenance Panel", dwg 30004122 fo. 35-37) says a
381 * forcing cycle writes the *register under exam* (displayed through BO), it
382 * does not step the program. So a forcing cycle must NOT advance SO — that
383 * is what lets the operator key an instruction across phases (force SO=E2,
384 * step to E0, force FO, step to the 0x64 beta, force L1, step to execute).
385 * The one exception is rotary position 13 (RS_SO), which forces SO/SI
386 * itself — that is how the operator sets the sequencer state.
387 *
388 * RICI ("disable next status") suppresses the advance in normal operation,
389 * letting a status be re-executed. */
390 uint8_t sel_norm = ge->register_selector == RS_NORM;
391 uint8_t sel_so = ge->register_selector == RS_SO;
392 uint8_t advance_so = sel_norm ? !ge->console_switches.RICI : sel_so;
393 if (ge->RIA0 && advance_so) {
394 ge_log(LOG_FUTURE, "last clock cpu, %02x in SO\n", ge->future_state);
395 ge->rSO = ge->future_state;
396 } else {
397 ge_log(LOG_FUTURE, "last clock cpu, SO held at %02x (RIA0 %d advance %d)\n",
398 ge->rSO, ge->RIA0, advance_so);
399 }
400
401 /* after the end of a cpu work cycle, (ALTO / ALS71=1) is set if
402 * the PAPA switch is inserted, or if the rotary switch is neither
403 * in the normal position, nor in position 8 for recording in
404 * memory ALSOA=0) (cpu fo. 98)
405 */
406 uint8_t is_papa = ge->console_switches.PAPA;
407 uint8_t is_norm = ge->register_selector == RS_NORM;
408 uint8_t is_scr = ge->register_selector == RS_V1_SCR;
409
410 /* Step-by-step (PAPA, the ASIN request) can be inhibited by the program:
411 * INS sets ADIR=1, ENS / CLEAR clear it (CPU[4] §3.3). The maintenance STOC
412 * switch overrides the inhibit. This is the HW gate ALTO <- ... ASIN(ATOC +
413 * !ADIR), with ATOC = STOC (msl-states.c fo., cpu fo. 98). */
414 uint8_t step_enabled = ge->console_switches.STOC || !ge->ADIR;
415 uint8_t papa_stop = is_papa && step_enabled;
416 ge_log(LOG_FUTURE, " papa: %d, step_en: %d, norm: %d, scr: %d ==> %d\n",
417 is_papa, step_enabled, is_norm, is_scr,
418 ge->RIA0 && (papa_stop || !(is_norm || is_scr)));
419
420 if (ge->RIA0 && (papa_stop || !(is_norm || is_scr)))
421 ge->ALTO = 1;
422
423 /* PATE stops the timing after every cycle of the delay line — a finer step
424 * than PAPA and, unlike PAPA, it is not gated by the CPU/channel cycle
425 * (RIA0/RIA2), so it does interfere with peripheral transfers. One START
426 * then runs exactly one delay-line cycle. (CPU[4] §4, fo.35) */
428 ge->ALTO = 1;
429
430 /* after the execution of a channel 2 cycle, load the first
431 * 4 bits of the future status network in SI. (cpu fo. 127) */
432 if (ge->RIA2) {
433 ge_log(LOG_FUTURE, "last clock ch2, %02x in SI\n", ge->future_state);
434 ge->rSI = ge->future_state;
435 }
436
437}
@ RS_V1_SCR
Definition console.h:16
@ RS_SO
Definition console.h:21
@ RS_NORM
Definition console.h:18
int ge_deinit(struct ge *ge)
Deinitialize the emulator.
Definition ge.c:360
void ge_seed_segment_bases(struct ge *ge)
Seed the eight change/segment-base registers (mem[240+2N]) to identity bases N<<12.
Definition ge.c:83
void ge_load_1(struct ge *ge)
Emulate the press of the "load 1" button in the console.
Definition ge.c:172
void ge_print_registers_nonverbose(struct ge *ge)
Definition ge.c:246
#define MAX_PROGRAM_STORAGE_WORDS
Definition ge.c:12
static void ge_print_well_known_states(uint8_t state)
Definition ge.c:203
void ge_clear(struct ge *ge)
Emulate the press of the "clear" button in the console.
Definition ge.c:27
int ge_run_cycle(struct ge *ge)
Run all GE "mastri" clock periods until next clock cycle.
Definition ge.c:349
void ge_clock_increment(struct ge *ge)
Definition ge.c:276
const char * ge_clock_name(enum clock c)
The clock period name name.
Definition ge.c:233
uint8_t ge_clock_is_first(struct ge *ge)
Definition ge.c:283
void ge_mem_store8(struct ge *ge, uint16_t addr, uint8_t val)
Store a byte with generated odd parity + mark-written (for the hybrid ALU/SS write paths that write g...
Definition ge.c:119
void ge_load_2(struct ge *ge)
Emulate the press of the "load 2" button in the console.
Definition ge.c:189
void ge_enter(struct ge *ge, uint16_t entry)
Enter execution at entry: seed PO and drop into the alpha (fetch) phase, bypassing the peripheral LOA...
Definition ge.c:155
uint8_t ge_clock_is_last(struct ge *ge)
Definition ge.c:288
static uint8_t ge_odd_parity(uint8_t data)
Definition ge.c:108
void ge_init(struct ge *ge)
Initialize the emulator.
Definition ge.c:14
int ge_run_pulse(struct ge *ge)
Run a single pulse (i.e. a single GE "mastri" clock periods)
Definition ge.c:293
void fsn_last_clock(struct ge *ge)
Commit the future state.
Definition ge.c:374
void ge_print_registers_verbose(struct ge *ge)
Definition ge.c:259
void ge_load(struct ge *ge)
Emulate the press of the "load" button in the console.
Definition ge.c:162
int ge_load_image(struct ge *ge, const uint8_t *image, size_t size, uint16_t origin)
Load a flat image at origin (unified-format payload); origin-aware, not size-capped,...
Definition ge.c:131
int ge_load_program(struct ge *ge, uint8_t *program, uint8_t size)
Copy a program at the start of memory.
Definition ge.c:93
void connectors_first_clock(struct ge *ge)
Definition ge.c:366
void ge_start(struct ge *ge)
Emulate the press of the "start" button in the console.
Definition ge.c:194
#define MEM_SIZE
Definition ge.h:12
#define ENUMERATE_CLOCKS
Definition ge.h:14
void pulse(struct ge *ge)
Definition pulse.c:248
clock
Definition ge.h:38
static uint16_t NI_knot(struct ge *ge)
NI Knot.
Definition signals.h:301
static uint16_t NO_knot(struct ge *ge)
Knot driven by P0, V1, V2, V4, L1, R1, V3 and L3.
Definition signals.h:170
void ge_log(ge_log_type type, const char *format,...)
Log message.
Definition log.c:122
uint8_t ge_log_enabled(ge_log_type type)
Check if a log type is enabled.
Definition log.c:137
@ LOG_REGS_V
Register trace per pulse.
Definition log.h:23
@ LOG_ERR
Emulator unrecoverable condition.
Definition log.h:18
@ LOG_FUTURE
Future state network debug.
Definition log.h:24
@ LOG_REGS
Register trace per cycle.
Definition log.h:20
@ LOG_STATES
State trace.
Definition log.h:21
@ LOG_READER
Integrated Reader.
Definition log.h:28
void msl_run_state(struct ge *ge, struct msl_timing_state *state)
Runs a machine state.
Definition msl.c:18
struct msl_timing_state * msl_get_state(uint8_t SO)
Gets timing state␐␐␐␐␐␐␐␐␐.
Definition msl.c:9
int ge_peri_on_pulses(struct ge *ge)
Definition peripherical.c:7
int ge_peri_deinit(struct ge *ge)
int ge_peri_on_clock(struct ge *ge)
Signals.
const char * name
Definition channel.h:39
const char * name
Definition reader.h:65
uint16_t PATE
Stop after a cycle.
Definition console.h:89
uint16_t RICI
Disables next status.
Definition console.h:97
uint16_t PAPA
Step By Step execution.
Definition console.h:81
uint8_t mode_debi
Definition reader.h:42
uint8_t mode_mi01
Definition reader.h:43
uint8_t mode_n001
Definition reader.h:40
uint8_t active_valid
Definition reader.h:51
uint8_t mode_n002
Definition reader.h:41
uint8_t mode_mi02
Definition reader.h:44
The entire state of the emulated system, including registers, memory, peripherals and timings.
Definition ge.h:96
uint8_t ALAM
Operator Call.
Definition ge.h:332
uint16_t instr_pc
Instruction-start PC (display aid, not a real register).
Definition ge.h:121
uint8_t ALOI
Load connector selection.
Definition ge.h:285
uint8_t AINI
Program Loading.
Definition ge.h:278
struct ge_integrated_reader integrated_reader
The I/O interface for the integrated reader (RI)
Definition ge.h:595
struct ge_connector ST4
The I/O interface for the ST4 connector.
Definition ge.h:636
uint8_t ALTO
Stops internal cycles.
Definition ge.h:293
uint8_t ffFA
Special conditions register 2.
Definition ge.h:263
uint16_t rPO
Program addresser.
Definition ge.h:113
uint8_t future_state
Future state.
Definition ge.h:546
uint8_t PODI
Slow delay line.
Definition ge.h:301
uint8_t mem_written[MEM_SIZE]
1 once a location has been written; prevents false MEM CHECK on cleared memory
Definition ge.h:572
enum ge_console_rotary register_selector
The current state of the console register rotary switch.
Definition ge.h:551
uint8_t RIA0
Synchronous CPU Cycle Request.
Definition ge.h:500
uint32_t mem_size
Installed memory size; 0 is treated as MEM_SIZE (full address space)
Definition ge.h:575
uint8_t RIA2
Synchronous Channel 2 Cycle Request.
Definition ge.h:514
uint16_t rV1
Addresser for the first operand.
Definition ge.h:123
uint8_t rSO
Main sequencer.
Definition ge.h:220
uint8_t halted
Definition ge.h:99
uint16_t rRO
Multipurpose 8+1 bit register.
Definition ge.h:171
struct ge_console_switches console_switches
The current state of the console switches.
Definition ge.h:556
struct ge_connector ST3
The I/O interface for the ST3 connector.
Definition ge.h:631
uint8_t rL2
Auxiliary register.
Definition ge.h:155
uint8_t powered
Definition ge.h:100
uint8_t ffFI
Special conditions register 1.
Definition ge.h:253
uint8_t RC00
Asynchronous CPU Cycle Request.
Definition ge.h:445
uint16_t rBO
Default operator.
Definition ge.h:188
uint8_t RC01
Asynchronous Channel 1 Cycle Request.
Definition ge.h:458
uint8_t mem[MEM_SIZE]
The memory of the emulated system.
Definition ge.h:566
struct ge_channel channel2
Integrated channel 2 (CAN2) line bundle — shared by the integrated reader (input),...
Definition ge.h:645
uint16_t rV4
Addresser for external instructions using channel 2.
Definition ge.h:126
uint16_t rL1
Length of the operand.
Definition ge.h:154
uint8_t rSA
Future state configuration.
Definition ge.h:242
uint8_t PEC1_pending
Definition ge.h:421
uint16_t rV2
Addresser for the second operand.
Definition ge.h:124
uint8_t RC02
Asynchronous Channel 2 Cycle Request.
Definition ge.h:473
uint8_t ADIR
Disable Step By Step.
Definition ge.h:362
uint8_t rSI
Peripheral unit sequencer.
Definition ge.h:234
uint8_t RC03
Asynchronous Channel 3 Cycle Request.
Definition ge.h:488
uint8_t ACIC
Recycle delay line.
Definition ge.h:322
enum clock current_clock
Definition ge.h:98
uint16_t rL3
Length of operands involving channel 3.
Definition ge.h:156
uint8_t mem_parity[MEM_SIZE]
Stored odd-parity bit (1 bit per location) written alongside mem[].
Definition ge.h:569
uint16_t rV3
Addresser for external instructions using channel 3.
Definition ge.h:125
uint8_t rFO
Current function code.
Definition ge.h:195
uint16_t cr_cache[8]
Change/segment-register CACHE used for modified-address resolution.
Definition ge.h:140
Timing chart.
Definition msl-timings.h:52