GE-115 Emulator
An Emulator of the General Electrics GE-115 computer
pulse.c
Go to the documentation of this file.
1#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include "ge.h"
5#include "signals.h"
6#include "log.h"
7
15static inline uint8_t odd_parity(uint8_t data)
16{
17 /* __builtin_popcount gives the number of set bits; if it's already
18 * odd we need parity=0; if even we need parity=1. */
19 return (__builtin_popcount(data) & 1) ? 0 : 1;
20}
21
42#define GE_MAX_CORE 0x8000u /* 32K: the largest build ch.001 defines */
43
44static inline int mem_addr_installed(struct ge *ge, uint16_t addr)
45{
46 if (ge->mem_size)
47 return addr < ge->mem_size;
48 return addr < GE_MAX_CORE && ge_mem_in_bounds(ge, addr);
49}
50
78static inline void mem_fault(struct ge *ge, uint8_t *lamp)
79{
80 *lamp = 1;
82 ge->ALTO = 1;
83}
84
85static void on_TO00(struct ge *ge) {
86 /* cpu fo. 115 */
87 ge->RIA0 = ge->RC00 && !ge->ALTO;
88 ge->RESI = ge->RC01;
89 ge->RIA2 = ge->RC02;
90 ge->RIA3 = ge->RC03;
91
92 ge->RETO = RES01(ge);
93 ge->RET2 = RES2(ge); /* T010 latch, cp06 ch.132-6 (see ge.h RET2) */
94
95 /* TODO: a "counter" with RAMO, RAMI should condition RIA0 */
96
97 ge_log(LOG_CYCLE, " async: RC00: %d RC01: %d RC02: %d RC03: %d ALTO: %d\n",
98 ge->RC00, ge->RC01, ge->RC02, ge->RC03, ge->ALTO);
99
100 ge_log(LOG_CYCLE, " sync: RIA0: %d RESI: %d RIA2: %d RIA3: %d\n",
101 ge->RIA0, ge->RESI, ge->RIA2, ge->RIA3);
102
103 ge_log(LOG_CYCLE, " -> RIUC: %d RES0: %d RES2: %d RES3: %d\n",
104 RIUC(ge), RES0(ge), RES2(ge), RES3(ge));
105
106 /* set NI to output the counting network.
107 * ("this occoursr alwas during the 1st phase", cpu fo.125) */
108
109 ge->kNI.ni1 = NS_CN1;
110 ge->kNI.ni2 = NS_CN2;
111 ge->kNI.ni3 = NS_CN3;
112 ge->kNI.ni4 = NS_CN4;
113
114 /* CO41 used to set from_zero is issued in TO10, so this looks
115 * like a reasonable place to reset this. CO40 (decreasing) must be reset
116 * here too, otherwise a stale "decreasing" from one decrement turns every
117 * later +1 advance into a -1 (now that the counting network honours it). */
118 memset(&ge->counting_network.cmds, 0, sizeof(ge->counting_network.cmds));
119 memset(&ge->counting_network.ci_cmds, 0, sizeof(ge->counting_network.ci_cmds));
120
121 /* CI45/46/47 are state-local UA mode pulses. */
122 memset(&ge->ua_controls, 0, sizeof(ge->ua_controls));
123}
124
125static void on_TO10(struct ge *ge) {
126 ge->ffFA = ge->ffFI; /* cpu fo. 129 */
127 ge->rSA = NA_knot(ge); /* cpu fo. 128 */
128
129 /* save SA to emulate the future state network */
130 ge->future_state = ge->rSA;
131
132 /* TODO: a "counter" with RAMO, RAMI should count (cpu fo. 115) */
133}
134
135static void on_TO11(struct ge *ge) {}
136static void on_TO15(struct ge *ge) {}
137
138static void on_TO19(struct ge *ge) {
139 /* intermediate fo. 9 B1*/
140 ge->RECE = 0;
141}
142
143static void on_TO20(struct ge *ge) {
144 ge->rBO = NO_knot(ge); /* cpu fo. 142, 126 */
145 ge->rVO = NO_knot(ge); /* cpu fo. 124, 125 */
146
147 ge->kNO.forcings = 0;
148 ge->kNO.force_mode = KNOT_FORCING_NONE;
149
150 ge->ACIC = 0; /* cpu fo. 99 */
151 ge->rRO = 0; /* cpu fo. 142 */
152}
153
154static void on_TO25(struct ge *ge) {}
155static void on_TO30(struct ge *ge) {}
156
157static void on_TO40(struct ge *ge) {
158 /* stub */
160 ge->kNI.ni1 = NS_CN1;
161 ge->kNI.ni2 = NS_CN2;
162 ge->kNI.ni3 = NS_CN3;
163 ge->kNI.ni4 = NS_CN4;
164 }
165}
166
167static void on_TO50(struct ge *ge) {
168 if (ge->PEC1_pending) {
169 ge->PEC1 = 1;
170 ge->PEC1_pending = 0;
171 }
172
173 /* not sure about the timing of memory ops
174 * read was previously done in TO65 with write, but
175 * it didn't work to implement the state CC for PERI.
176 * reading here seems to work in all known cases */
177 if (ge->memory_command == MC_READ) {
178 if (!mem_addr_installed(ge, ge->rVO)) {
179 /* Address outside installed memory: raise INV ADD fault */
181 ge_log(LOG_STATES, "memory read: INV ADD rVO=%x (bound %uK)\n",
183 } else {
184 ge->inv_add = 0; /* the address is there: condition gone */
185 ge->rRO = ge->mem[ge->rVO];
186 ge_log(LOG_STATES, "memory read: RO = mem[VO] = mem[%x] = %x\n",
187 ge->rVO, ge->rRO);
188
189 /* Parity check. A location this machine has written carries a
190 * check bit gemu generated, and comparing it is the whole point.
191 *
192 * A location it has NOT written is a question about the iron, not
193 * about the model: core retains, so on a real machine every cell
194 * holds something with the check bit whatever wrote it last left
195 * behind, and reads clean. gemu's array starts virgin -- data 0
196 * with check bit 0, which is an even count and therefore a parity
197 * ERROR -- so checking it would report a fault the machine does
198 * not have. Hence the exemption, and hence `mem_check_blank` for
199 * the machine that really is in that state: powered up with core
200 * never written, MEM CHECK stands on for as long as it runs
201 * through it, which is what Electric Dreams shows with nothing
202 * loaded. See ge.h. */
203 if (ge->mem_written[ge->rVO] || ge->mem_check_blank) {
204 if (odd_parity(ge->mem[ge->rVO]) != ge->mem_parity[ge->rVO]) {
207 "memory read: MEM CHECK parity error at %x\n",
208 ge->rVO);
209 } else {
210 ge->mem_check = 0; /* checked, and good */
211 }
212 }
213 }
214
215 ge->memory_command = MC_NONE;
216 }
217}
218
219static void on_TO50_1(struct ge *ge) {
221 /* timing chart js1-js2-jie-ecc, fo. 32,
222 * also, display, fo. 17 */
223 ge->rBO = NO_knot(ge);
224 }
225
227
228 ge->kNO.forcings = 0;
229 ge->kNO.force_mode = KNOT_FORCING_NONE;
230}
231
232static void on_TO60(struct ge *ge) {}
233static void on_TO64(struct ge *ge) {}
234
235static void on_TO65(struct ge *ge) {
236 /* not sure about the timing of memory ops
237 * in cpu fo. 145, "write" seems to be at around TO65,
238 * and the "test k" fails if it's in TO50. */
239
240 if (ge->memory_command == MC_WRITE) {
241 if (!mem_addr_installed(ge, ge->rVO)) {
242 /* Address outside installed memory: raise INV ADD fault, skip store */
244 ge_log(LOG_STATES, "memory write: INV ADD rVO=%x (bound %uK)\n",
246 } else {
247 ge->inv_add = 0; /* the address is there: condition gone */
248
249 uint8_t parity = odd_parity(ge->rRO);
250
251 /* Console check-bit forcing: during a storage forcing from the
252 * console (rotary pos 8, RS_V1_SCR) with INCE inserted, AM08 is
253 * stored as the parity bit and the normal parity generation for
254 * AM07-00 is inhibited. This lets the operator key in a wrong
255 * check bit to exercise MEM CHECK detection. (CPU[4] ยง4.2, fo.36-37) */
257 parity = (ge->console_switches.AM >> 8) & 1;
258
259 ge->mem[ge->rVO] = ge->rRO;
260 ge->mem_parity[ge->rVO] = parity;
261 ge->mem_written[ge->rVO] = 1;
262 ge_log(LOG_STATES, "memory write: mem[VO] = RO = mem[%x] = %x (parity %d)\n",
263 ge->rVO, ge->rRO, parity);
264 }
265
266 ge->memory_command = MC_NONE;
267 }
268
269 /* "enables the second phase commands for count selection" (cpu fo.142):
270 * the CO-phase counting flags are replaced by the CI-phase staging, so
271 * the TI05 loads (CI05 NI->L1, ...) see the CI40/41/42/44 selection. */
273 memset(&ge->counting_network.ci_cmds, 0, sizeof(ge->counting_network.ci_cmds));
274}
275
276static void on_TO70(struct ge *ge) {
277 if (ge->PEC1)
278 ge->RASI = 0;
279}
280
281static void on_TO80(struct ge *ge) {}
282
283static void on_TO89(struct ge *ge) {
284 ge->PEC1 = 0;
285 ge->PEC1_pending = 0;
286}
287
288static void on_TO90(struct ge *ge) {
289 /* TODO: check if ! is correct: PODIB should be PODI negated */
290 if (!ge->PODI)
291 ge->ACIC = 1; /* cpu fo. 99 */
292}
293
294static void on_TI05(struct ge *ge) {
295 /* TODO: check if ! is correct: PODIB should be PODI negated */
296 if (ge->PODI)
297 ge->ACIC = 1; /* cpu fo. 99 */
298}
299
300static void on_TI06(struct ge *ge) {}
301static void on_TI10(struct ge *ge) {}
302
303static on_pulse_cb pulse_cb[END_OF_STATUS] = {
304 on_TO00,
305 on_TO10,
306 on_TO11,
307 on_TO15,
308 on_TO19,
309 on_TO20,
310 on_TO25,
311 on_TO30,
312 on_TO40,
313 on_TO50,
314 on_TO50_1,
315 on_TO60,
316 on_TO64,
317 on_TO65,
318 on_TO70,
319 on_TO80,
320 on_TO89,
321 on_TO90,
322 on_TI05,
323 on_TI06,
324 on_TI10,
325};
326
327
328void pulse(struct ge *ge)
329{
330 if (pulse_cb[ge->current_clock]) {
332 }
333}
@ RS_V1_SCR
Definition console.h:16
@ NS_CN1
Definition ge.h:106
@ NS_CN2
Definition ge.h:107
@ NS_CN4
Definition ge.h:109
@ NS_CN3
Definition ge.h:108
void(* on_pulse_cb)(struct ge *)
Definition ge.h:872
static uint16_t NO_knot(struct ge *ge)
Knot driven by P0, V1, V2, V4, L1, R1, V3 and L3.
Definition signals.h:212
static uint8_t NA_knot(struct ge *ge)
Knot driven by SO or SI.
Definition signals.h:298
static uint16_t ge_memory_capacity_k(struct ge *ge)
Definition signals.h:629
static uint8_t ge_mem_in_bounds(struct ge *ge, uint16_t addr)
Installed memory, in K.
Definition signals.h:616
void ge_log(ge_log_type type, const char *format,...)
Log message.
Definition log.c:122
@ LOG_STATES
State trace.
Definition log.h:21
@ LOG_CYCLE
Cycle attribution debug.
Definition log.h:25
static void on_TO70(struct ge *ge)
Definition pulse.c:276
static void mem_fault(struct ge *ge, uint8_t *lamp)
The fault lamps, and the error stop.
Definition pulse.c:78
static void on_TO90(struct ge *ge)
Definition pulse.c:288
static void on_TO89(struct ge *ge)
Definition pulse.c:283
static void on_TO50(struct ge *ge)
Definition pulse.c:167
static void on_TO20(struct ge *ge)
Definition pulse.c:143
static void on_TI10(struct ge *ge)
Definition pulse.c:301
static uint8_t odd_parity(uint8_t data)
Compute the odd-parity bit for an 8-bit data value.
Definition pulse.c:15
static void on_TO10(struct ge *ge)
Definition pulse.c:125
static void on_TO50_1(struct ge *ge)
Definition pulse.c:219
static void on_TI06(struct ge *ge)
Definition pulse.c:300
static void on_TO19(struct ge *ge)
Definition pulse.c:138
static void on_TO11(struct ge *ge)
Definition pulse.c:135
#define GE_MAX_CORE
Does the machine have core at this address?
Definition pulse.c:42
static void on_TI05(struct ge *ge)
Definition pulse.c:294
static on_pulse_cb pulse_cb[END_OF_STATUS]
Definition pulse.c:303
static void on_TO65(struct ge *ge)
Definition pulse.c:235
static void on_TO40(struct ge *ge)
Definition pulse.c:157
static void on_TO80(struct ge *ge)
Definition pulse.c:281
static void on_TO60(struct ge *ge)
Definition pulse.c:232
static int mem_addr_installed(struct ge *ge, uint16_t addr)
Definition pulse.c:44
static void on_TO25(struct ge *ge)
Definition pulse.c:154
static void on_TO30(struct ge *ge)
Definition pulse.c:155
static void on_TO64(struct ge *ge)
Definition pulse.c:233
void pulse(struct ge *ge)
Definition pulse.c:328
static void on_TO00(struct ge *ge)
Definition pulse.c:85
static void on_TO15(struct ge *ge)
Definition pulse.c:136
Signals.
uint16_t INCE
Do not error-correct external units input.
Definition console.h:136
uint16_t AM
Forcing bits.
Definition console.h:155
uint16_t INAR
Do not stop on memory error.
Definition console.h:121
struct ge_counting_network::cmds cmds
struct cmds ci_cmds
Definition ge.h:57
enum knot_ni_source ni4
Definition ge.h:120
enum knot_ni_source ni2
Definition ge.h:118
enum knot_ni_source ni1
Definition ge.h:117
enum knot_ni_source ni3
Definition ge.h:119
uint8_t forcings
Definition ge.h:77
enum ge_knot_no::@1 force_mode
The entire state of the emulated system, including registers, memory, peripherals and timings.
Definition ge.h:172
uint8_t RET2
Channel-2 cycle-assignment memory.
Definition ge.h:369
uint8_t ALTO
Stops internal cycles.
Definition ge.h:392
uint8_t ffFA
Special conditions register 2.
Definition ge.h:352
uint8_t future_state
Future state.
Definition ge.h:675
uint8_t inv_add
Invalid-address fault flag: set when rVO >= installed memory size.
Definition ge.h:729
uint8_t PODI
Slow delay line.
Definition ge.h:400
uint8_t mem_written[MEM_SIZE]
1 once a location has been written; prevents false MEM CHECK on cleared memory
Definition ge.h:701
enum ge_console_rotary register_selector
The current state of the console register rotary switch.
Definition ge.h:680
uint8_t RIA0
Synchronous CPU Cycle Request.
Definition ge.h:629
uint32_t mem_size
Installed memory size; 0 is treated as MEM_SIZE (full address space)
Definition ge.h:723
uint8_t RIA2
Synchronous Channel 2 Cycle Request.
Definition ge.h:643
uint8_t PEC1
Definition ge.h:549
uint8_t mem_check
Parity fault flag: set when a READ finds a parity mismatch on a previously-written location.
Definition ge.h:726
uint8_t mem_check_blank
Read never-written core as a parity error (default 0).
Definition ge.h:720
uint16_t rRO
Multipurpose 8+1 bit register.
Definition ge.h:248
struct ge_counting_network counting_network
Definition ge.h:738
struct ge_console_switches console_switches
The current state of the console switches.
Definition ge.h:685
uint8_t RIA3
Synchronous Channel 3 Cycle Request.
Definition ge.h:650
uint8_t ffFI
Special conditions register 1.
Definition ge.h:342
uint8_t RC00
Asynchronous CPU Cycle Request.
Definition ge.h:574
uint16_t rBO
Default operator.
Definition ge.h:277
uint8_t RC01
Asynchronous Channel 1 Cycle Request.
Definition ge.h:587
enum ge::@3 memory_command
uint8_t RECE
Selection Check Byte.
Definition ge.h:653
struct ge_ua_controls ua_controls
Definition ge.h:739
struct ge_knot_ni kNI
Knot driven by counting network, or by the UA to store the result of the operation.
Definition ge.h:241
uint8_t mem[MEM_SIZE]
The memory of the emulated system.
Definition ge.h:695
uint8_t RASI
Channel 1 in transfer.
Definition ge.h:533
uint8_t rSA
Future state configuration.
Definition ge.h:331
uint8_t PEC1_pending
Definition ge.h:550
uint8_t RC02
Asynchronous Channel 2 Cycle Request.
Definition ge.h:602
uint8_t RESI
Synchronous Channel 1 Cycle Request.
Definition ge.h:636
uint16_t rVO
Default memory addresser.
Definition ge.h:268
uint8_t RC03
Asynchronous Channel 3 Cycle Request.
Definition ge.h:617
uint8_t ACIC
Recycle delay line.
Definition ge.h:421
enum clock current_clock
Definition ge.h:174
uint8_t mem_parity[MEM_SIZE]
Stored odd-parity bit (1 bit per location) written alongside mem[].
Definition ge.h:698
uint8_t RETO
Definition ge.h:358
uint8_t TO50_did_CI32_or_CI33
Workaround for pulse TO50.
Definition ge.h:816
struct ge_knot_no kNO
Definition ge.h:235