-
Notifications
You must be signed in to change notification settings - Fork 2
/
ge.c
280 lines (233 loc) · 7.42 KB
/
ge.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include "ge.h"
#include "signals.h"
#include "msl.h"
#include "console_socket.h"
#include "peripherical.h"
#include "log.h"
#define MAX_PROGRAM_STORAGE_WORDS 129
void ge_init(struct ge *ge)
{
memset(ge, 0, sizeof(*ge));
ge->halted = 1;
ge->powered = 1;
ge->register_selector = RS_NORM;
ge->ST3.name = "ST3";
ge->ST4.name = "ST4";
}
void ge_clear(struct ge *ge)
{
ge->AINI = 0;
ge->ALAM = 0;
ge->PODI = 0;
ge->ADIR = 0;
ge->ACIC = 1;
/* After the powering on of the machine the timing starts pressing the
* "CLEAR" switch (cpu fo. 99). */
ge->halted = 0;
/* (One of) the possible set conditions (is): or with
* "CLEAR" and.. (cpu fo. 98) */
ge->ALTO = 1;
/* By pressing "CLEAR" tje FF RC01, RC02, RC03 are reset and the FF
* RC00 is set. (cpu fo. 115) */
ge->RC00 = 1;
ge->RC01 = 0;
ge->RC02 = 0;
ge->RC03 = 0;
}
int ge_load_program(struct ge *ge, uint8_t *program, uint8_t size)
{
if (program == NULL && size != 0)
return -1;
if (size > MAX_PROGRAM_STORAGE_WORDS)
size = MAX_PROGRAM_STORAGE_WORDS;
/* simulate the loading for now */
memcpy(ge->mem, program, size);
return 0;
}
void ge_load(struct ge *ge)
{
/* When pressing LOAD button, AINI is set. If AINI is set, the state 80
* (initialitiation) goes to state c8, starting the loading of the program
* (of max 129 words) from one of the peripherc unit. */
/* set AINI FF to 1 (pag. 96) */
ge->AINI = 1;
}
void ge_load_1(struct ge * ge)
{
/* It is possible to choose one between the two units thus prepared
* positioning the operating console switch LOAD1/LOAD2 (The possible
* choices are: Conn.2/Conn.3; Conn.4/Conn.3; Conn.2/Conn.4).
*
* (cpu fo. 43) */
/* from the previous manual excerpt, ,i would have expected ALOI = 0t to
* be LOAD1 and ALOI = 1 to be LOAD2, but running the initial load tests,
* ALOI = 1 will result in the machine using the 0x80 unit name, which is
* connector 2, while ALOI = 0 results in a 0x00 unit name, which is
* connector 3. */
ge->ALOI = 1;
}
void ge_load_2(struct ge * ge)
{
ge->ALOI = 0;
}
void ge_start(struct ge *ge)
{
/* according to the cpu documents, we should set the flipflop ARES here to
* implement the initial loading of 80 into SO, however with the current
* implementation it's not needed */
ge->ALTO = 0; /* cpu fo. 97 */
}
static void ge_print_well_known_states(uint8_t state) {
const char *name;
switch (state) {
case 0x00: name = "- Display sequence"; break;
case 0x08: name = "- Forcing sequence"; break;
case 0x64:
case 0x65: name = "- Beta Phase"; break;
case 0x80: name = "- Initialitiation"; break;
case 0xE2:
case 0xE3: name = "- Alpha Phase"; break;
case 0xF0: name = "- Interruption"; break;
default: name = "";
}
ge_log(LOG_STATES, "Running state %02x %s\n", state, name);
}
const char *ge_clock_name(enum clock c)
{
switch (c) {
#define X(name) case name : return #name ;
ENUMERATE_CLOCKS
#undef X
}
return "";
}
void ge_print_registers_nonverbose(struct ge *ge)
{
if (ge_log_enabled(LOG_REGS_V)) return;
ge_log(LOG_REGS,
"SO: %02x SA: %02x PO: %04x RO: %04x BO: %04x FO: %04x - "
"V1: %04x V2: %04x V3: %04x V4: %04x - "
"L1: %04x L2: %04x L3 : %04x\n",
ge->rSO, ge->rSA, ge->rPO, ge->rRO, ge->rBO, ge->rFO,
ge->rV1, ge->rV2, ge->rV3, ge->rV4,
ge->rL1, ge->rL2, ge->rL3);
}
void ge_print_registers_verbose(struct ge *ge)
{
ge_log(LOG_REGS_V,
"%s: "
"SO: %02x SA: %02x PO: %04x RO: %04x BO: %04x FO: %04x - "
"NO: %02x NI: %02x - "
"FA: %02x FI: %02x - "
"V1: %04x V2: %04x V3: %04x V4: %04x - "
"L1: %04x L2: %04x L3 : %04x\n",
ge_clock_name(ge->current_clock),
ge->rSO, ge->rSA, ge->rPO, ge->rRO, ge->rBO, ge->rFO,
NO_knot(ge), NI_knot(ge),
ge->ffFA, ge->ffFI,
ge->rV1, ge->rV2, ge->rV3, ge->rV4,
ge->rL1, ge->rL2, ge->rL3);
}
void ge_clock_increment(struct ge* ge)
{
ge->current_clock++;
if (ge->current_clock == END_OF_STATUS)
ge->current_clock = TO00;
}
uint8_t ge_clock_is_first(struct ge* ge)
{
return ge->current_clock == TO00;
}
uint8_t ge_clock_is_last(struct ge* ge)
{
return ge->current_clock == (END_OF_STATUS - 1);
}
int ge_run_pulse(struct ge *ge)
{
int r;
struct msl_timing_state *state;
if (ge_clock_is_first(ge)) {
r = ge_peri_on_clock(ge);
if (r != 0)
return r;
/* poll the connectors and try to set up the cpu state.
* should this be here? */
connectors_first_clock(ge);
}
/* Execute common pulse machine logic */
pulse(ge);
/* Execute peripherals pulse callbacks */
r = ge_peri_on_pulses(ge);
if (r != 0)
return r;
/* Execute the commands from the timing charts */
state = msl_get_state(ge->rSA);
/* The state to execute gets loaded in SA at TO10 */
if (ge->current_clock == TO10)
ge_print_well_known_states(ge->rSA);
if (!state) {
ge_log(LOG_ERR, "no timing charts found for state %02X\n", ge->rSA);
return 1;
}
msl_run_state(ge, state);
if (ge_clock_is_last(ge)) {
fsn_last_clock(ge);
ge_print_registers_nonverbose(ge);
}
ge_clock_increment(ge);
return 0;
}
int ge_run_cycle(struct ge *ge)
{
do {
int r = ge_run_pulse(ge);
if (r)
return r;
} while (!ge_clock_is_first(ge));
return 0;
}
int ge_deinit(struct ge *ge)
{
ge_peri_deinit(ge);
return 0;
}
void connectors_first_clock(struct ge *ge)
{
if (RA101(ge)) {
ge_log(LOG_READER, "RA101: signaling incoming data\n");
ge->RC01 = 1;
}
}
void fsn_last_clock(struct ge *ge)
{
/* at the end of a cycle attributed to the CPU, provided RICI
* is not active and the rotary switch is in normal position,
* the future status network is stored in SO. (cpu fo. 127) */
if (ge->RIA0 && !ge->console_switches.RICI) {
ge_log(LOG_FUTURE, "last clock cpu, %02x in SO\n", ge->future_state);
ge->rSO = ge->future_state;
} else {
ge_log(LOG_FUTURE, "last clock cpu, not setting future state %02x in SO becuse RIA0 %d and !RICI %d\n", ge->future_state, ge->RIA0, !ge->console_switches.RICI);
}
/* after the end of a cpu work cycle, (ALTO / ALS71=1) is set if
* the PAPA switch is inserted, or if the rotary switch is neither
* in the normal position, nor in position 8 for recording in
* memory ALSOA=0) (cpu fo. 98)
*/
uint8_t is_papa = ge->console_switches.PAPA;
uint8_t is_norm = ge->register_selector == RS_NORM;
uint8_t is_scr = ge->register_selector == RS_V1_SCR;
ge_log(LOG_FUTURE, " papa: %d, norm: %d, scr: %d ==> %d\n", is_papa, is_norm, is_scr, ge->RIA0 && (is_papa || !(is_norm || is_scr)));
if (ge->RIA0 && (is_papa || !(is_norm || is_scr)))
ge->ALTO = 1;
/* after the execution of a channel 2 cycle, load the first
* 4 bits of the future status network in SI. (cpu fo. 127) */
if (ge->RIA2) {
ge_log(LOG_FUTURE, "last clock ch2, %02x in SI\n", ge->future_state);
ge->rSI = ge->future_state;
}
}