GE-115 Emulator
An Emulator of the General Electrics GE-115 computer
connector34.c
Go to the documentation of this file.
1/*
2 * connector34.c — shared core for Standard-GE-100 controllers on connectors
3 * 3 and 4 (disk / tape). See connector34.h for the architecture overview.
4 *
5 * Functional / channel-API model. The core registers one ge_peri; its on_clock
6 * runs the reaction state machine, mirroring the integrated reader/printer
7 * pattern: it watches the PER micro-sequence (rSO states), resolves the target
8 * device from the latched connector + the unit-name byte, and during the
9 * channel-1 transfer phase presents input bytes on the selected connector's
10 * line bundle (ST3/ST4) so the CPU's own state_b9/state_b1 loop writes them to
11 * memory — exactly as the card reader does on connector 2.
12 *
13 * Non-interference: the core only acts while a connector-3/4 PER is in flight
14 * (per_pending) and that connector is actually selected (PC131/PC141). For any
15 * reader (connector 2) or channel-2 printer op those are false, so the core is
16 * inert and never touches ST3/ST4.
17 */
18
19#include "connector34.h"
20#include "ge.h"
21#include "reader.h"
22#include "signals.h"
23#include "log.h"
24
25#include <stdlib.h>
26#include <string.h>
27
28/* Largest single channel-API input transfer the core buffers. */
29#define C34_XFER_MAX 4096
30
31/* Per-byte presentation cadence (mirrors the card reader): present at IDLE,
32 * retire (clear the lines) at PRESENT, then back to IDLE for the next byte. */
38
40 struct ge_std_device *dev3; /* devices on connector 3 */
41 struct ge_std_device *dev4; /* devices on connector 4 */
42
43 /* current PER context */
45 uint16_t per_base;
46 uint8_t name_byte;
49 struct ge_std_device *cur; /* device claiming this PER, or NULL */
50 uint8_t order;
52
53 /* input transfer buffer (device -> CPU) */
54 uint8_t buf[C34_XFER_MAX];
55 uint16_t len;
56 uint16_t pos;
57 int filled;
58
59 /* functional access-latency model: a free-running on_clock counter (no real
60 * clock is available) and the tick at which the current op may transfer. */
61 unsigned long ticks;
62 unsigned long busy_until;
63
65
66 struct ge_peri peri;
67};
68
69/* Map a device reaction onto the channel-1 examine status byte (read back by an
70 * EPER via CE_chan1_status): 0x40 = RO6 set, no error; 0x42 also sets RO1 so the
71 * DU95 "no-error" decode reads error. */
72static void apply_reaction(struct ge *ge, std_reaction r)
73{
74 switch (r) {
77 ge->inject_chan1_status = 0x42; /* abnormal: EPER examine reads error */
78 break;
79 default:
80 ge->inject_chan1_status = 0x00; /* clean: CE_chan1_status uses 0x40 */
81 break;
82 }
83}
84
85static struct std_unitname decode_name(uint8_t nb)
86{
87 struct std_unitname un;
88 uint8_t top = (nb >> 6) & 3;
89 un.connector = (top == 0) ? 3 : (top == 1) ? 4 : (top == 2) ? 2 : 1;
90 un.unit = nb & 0x3f;
91 return un;
92}
93
95{
96 struct connector34_core *c = (struct connector34_core *)ge->std_core;
97 return decode_name(c ? c->name_byte : 0);
98}
99
100/* The connector the CPU has selected this cycle, or NULL. */
101static struct ge_connector *selected_connector(struct ge *ge)
102{
103 if (PC131(ge)) return &ge->ST3;
104 if (PC141(ge)) return &ge->ST4;
105 return NULL;
106}
107
109 struct std_unitname un)
110{
111 struct ge_std_device *d = (un.connector == 4) ? c->dev4
112 : (un.connector == 3) ? c->dev3 : NULL;
113 for (; d; d = d->next)
114 if (d->claims && d->claims(d->ctx, un))
115 return d;
116 return NULL;
117}
118
119/*
120 * Forwarded from reader.c connector_send_tu00() at CE11 (state b9 TO65), when
121 * the order byte (rRE) is clocked to the selected connector. Capture the order
122 * and deliver it to the device's command() hook. Timing/side-effects are left
123 * to on_clock (printer precedent).
124 */
125void connector34_deliver_order(struct ge *ge, struct ge_connector *conn)
126{
127 struct connector34_core *c = (struct connector34_core *)ge->std_core;
128 (void)conn;
129 if (!c || !c->per_pending)
130 return;
131 c->order = ge->rRE;
132 c->order_seen = 1;
133 if (c->cur && c->cur->command) {
134 std_reaction r = c->cur->command(ge, c->cur->ctx, c->un, c->order);
135 apply_reaction(ge, r);
136 }
137}
138
139void connector34_set_busy(struct ge *ge, unsigned ticks)
140{
141 struct connector34_core *c = (struct connector34_core *)ge->std_core;
142 if (c)
143 c->busy_until = c->ticks + ticks;
144}
145
147{
148 /* The CPU samples INTE = RINT & !MASC at alpha and vectors through the PSR
149 * area at 0x0300/0x0304. We only request it here; the machine performs the
150 * save/restore itself (see the LPSR interrupt sequence). */
151 ge->RINT = 1;
152 ge_log(LOG_PERI, "connector34: end-of-operation interrupt raised\n");
153}
154
155static int connector34_on_clock(struct ge *ge, void *opaque)
156{
157 struct connector34_core *c = (struct connector34_core *)opaque;
158 struct ge_connector *conn;
159
160 c->ticks++;
161
162 /* Per-cycle device housekeeping (seek / motion timers). */
163 for (struct ge_std_device *d = c->dev3; d; d = d->next)
164 if (d->tick) d->tick(ge, d->ctx);
165 for (struct ge_std_device *d = c->dev4; d; d = d->next)
166 if (d->tick) d->tick(ge, d->ctx);
167
168 /* Org phase of a PER begins: rV1 is the order-block base. Reset context and
169 * drop any stale unit-present assertion from a previous op. */
170 if (ge->rSO == 0xc8) {
171 c->per_pending = 1;
172 c->per_base = ge->rV1;
173 c->cur = NULL;
174 c->name_captured = 0;
175 c->order_seen = 0;
176 c->filled = 0;
177 c->len = c->pos = 0;
178 c->busy_until = 0;
179 c->state = C34_IDLE;
180 ge->ST3.mare = 0;
181 ge->ST4.mare = 0;
182 ge->inject_chan1_status = 0; /* clean unless a device reports error */
183 return 0;
184 }
185
186 if (!c->per_pending)
187 return 0;
188
189 /* The unit-name byte sits in rRE during state d8 (it is overwritten by the
190 * order byte later). Capture it and resolve the target device. d8 can be
191 * revisited by the unit-busy recycle, so re-capture is harmless. */
192 if (ge->rSO == 0xd9 && !c->name_captured) {
193 /* The unit-name byte lands in rRE during d9 (at the d8 cycle's TO00,
194 * when on_clock runs, rRE is still stale). Capture exactly once: later
195 * d-states overwrite rRE with the order byte, and the unit-busy CC->D8
196 * recycle revisits with other values. */
197 c->name_captured = 1;
198 c->name_byte = ge->rRE;
199 c->un = decode_name(c->name_byte);
200 c->cur = find_device(c, c->un);
201 /* Assert the addressed unit "present/ready" (MARE3/MARE4) so the
202 * channel-1 selection chain (PM13A/PM14A -> RM101 -> PUC1) completes
203 * and the PER proceeds to transfer, instead of taking the
204 * unit-not-available branch. */
205 if (c->cur) {
206 if (c->un.connector == 4)
207 ge->ST4.mare = 1;
208 else
209 ge->ST3.mare = 1;
210 }
211 return 0;
212 }
213
214 /* Transfer phase. Act only while this connector is selected and a device
215 * owns the addressed unit. */
216 conn = selected_connector(ge);
217 if (!c->cur || !conn)
218 return 0;
219
220 /* Retire a byte the CPU has consumed. This runs regardless of RASI so the
221 * FINAL byte (which carries fine=1 -> RIG1) is always cleared; otherwise a
222 * stuck te10 would keep the read loop re-reading stale data past the count
223 * (the card reader clears the same way at CR_PRESENTED). */
224 if (c->state == C34_PRESENT) {
226 c->state = (c->pos >= c->len) ? C34_DONE : C34_IDLE;
227 return 0;
228 }
229
230 /* Whole record presented: the last byte set RIG1 (RIVE), so the machine's
231 * own end-of-transfer microcode winds the PER back to alpha. Keep holding
232 * RC00 until it leaves the channel-1 transfer states so the sequencer can
233 * run that wind-down. */
234 if (c->state == C34_DONE) {
235 if (ge->rSO == 0xb8 || ge->rSO == 0xb1 || ge->rSO == 0xb9)
236 ge->RC00 = 1;
237 return 0;
238 }
239
240 /* Feed only once the CPU has entered the channel-1 transfer phase (RASI). */
241 if (!ge->RASI)
242 return 0;
243
244 /* Hold the CPU-active request (RC00) for the duration of the transfer. The
245 * channel-1 service loop only advances while RIA0 (= RC00 & !ALTO) is set;
246 * the integrated reader keeps RC00 asserted through its own RACI/RIUC path
247 * (CE03/CE08), but the connector path runs state_b9's !PC121 branch whose
248 * CE05 is a stub, so RC00 would drop and freeze the sequencer at b8. Assert
249 * it directly, mirroring how printer.c drives RC00 to complete a channel-2
250 * PER. Gated on connector selection, so reader/channel-2 ops are unaffected. */
251 ge->RC00 = 1;
252
253 /* Lazily pull the input record from the device on first entry. The transfer
254 * hook may declare access latency here (connector34_set_busy) before any
255 * byte is presented, so the whole transfer is delayed from the start. */
256 if (!c->filled) {
257 uint16_t n = C34_XFER_MAX;
258 std_reaction r;
259 c->len = 0;
260 if (c->cur->transfer) {
261 r = c->cur->transfer(ge, c->cur->ctx, c->un, 0 /*input*/,
262 c->buf, &n, C34_XFER_MAX);
263 c->len = (n > C34_XFER_MAX) ? C34_XFER_MAX : n;
264 apply_reaction(ge, r);
265 }
266 c->pos = 0;
267 c->filled = 1;
268 c->state = C34_IDLE;
269 }
270
271 /* Access latency: while the unit is still "busy" (seek/motion), present no
272 * data — the PER simply waits here (RC00 held) like any slow peripheral. */
273 if (c->ticks < c->busy_until)
274 return 0;
275
276 /* C34_IDLE: present the next byte (the last one carries end=1 -> RIG1). */
277 if (conn->te10) /* previous byte not yet consumed */
278 return 0;
279 if (c->pos >= c->len) { /* nothing left to present */
280 c->state = C34_DONE;
281 return 0;
282 }
283 {
284 uint8_t b = c->buf[c->pos++];
285 int end = (c->pos >= c->len);
286 connector_setup_to_send(ge, conn, b, end ? 1 : 0);
287 c->state = C34_PRESENT;
288 }
289 return 0;
290}
291
292static int connector34_deinit(struct ge *ge, void *opaque)
293{
294 if (ge->std_core == opaque)
295 ge->std_core = NULL;
296 free(opaque);
297 return 0;
298}
299
301{
302 struct connector34_core *c = (struct connector34_core *)ge->std_core;
303 if (c)
304 return 0; /* already initialised */
305 c = calloc(1, sizeof(*c));
306 if (!c)
307 return -1;
310 c->peri.ctx = c;
311 ge->std_core = c;
312 return ge_register_peri(ge, &c->peri);
313}
314
315int connector34_attach(struct ge *ge, struct ge_std_device *dev, uint8_t connector)
316{
317 struct connector34_core *c = (struct connector34_core *)ge->std_core;
318 if (!c || !dev || (connector != 3 && connector != 4))
319 return -1;
320 if (connector == 4) {
321 dev->next = c->dev4;
322 c->dev4 = dev;
323 } else {
324 dev->next = c->dev3;
325 c->dev3 = dev;
326 }
327 ge_log(LOG_PERI, "connector34: attached '%s' on connector %u\n",
328 dev->name ? dev->name : "?", connector);
329 return 0;
330}
static struct std_unitname decode_name(uint8_t nb)
Definition connector34.c:85
void connector34_deliver_order(struct ge *ge, struct ge_connector *conn)
int connector34_init(struct ge *ge)
int connector34_attach(struct ge *ge, struct ge_std_device *dev, uint8_t connector)
static void apply_reaction(struct ge *ge, std_reaction r)
Definition connector34.c:72
static int connector34_deinit(struct ge *ge, void *opaque)
#define C34_XFER_MAX
Definition connector34.c:29
struct std_unitname connector34_decode(struct ge *ge)
Definition connector34.c:94
c34_state
Definition connector34.c:33
@ C34_DONE
Definition connector34.c:36
@ C34_IDLE
Definition connector34.c:34
@ C34_PRESENT
Definition connector34.c:35
static struct ge_std_device * find_device(struct connector34_core *c, struct std_unitname un)
static int connector34_on_clock(struct ge *ge, void *opaque)
static struct ge_connector * selected_connector(struct ge *ge)
void connector34_raise_interrupt(struct ge *ge)
void connector34_set_busy(struct ge *ge, unsigned ticks)
std_reaction
Definition connector34.h:32
@ STD_NOT_ACCEPTED
Definition connector34.h:35
@ STD_NOT_POSSIBLE
Definition connector34.h:36
int ge_register_peri(struct ge *ge, struct ge_peri *p)
void ge_log(ge_log_type type, const char *format,...)
Log message.
Definition log.c:122
@ LOG_PERI
Peripherals IO.
Definition log.h:27
void connector_clear_sending(struct ge_connector *conn)
Definition reader.c:207
void connector_setup_to_send(struct ge *ge, struct ge_connector *conn, uint8_t data, uint8_t end)
Definition reader.c:183
Signals.
enum c34_state state
Definition connector34.c:64
unsigned long busy_until
Definition connector34.c:62
struct ge_std_device * dev3
Definition connector34.c:40
struct ge_std_device * dev4
Definition connector34.c:41
struct ge_std_device * cur
Definition connector34.c:49
struct std_unitname un
Definition connector34.c:48
struct ge_peri peri
Definition connector34.c:66
uint8_t buf[C34_XFER_MAX]
Definition connector34.c:54
unsigned long ticks
Definition connector34.c:61
uint16_t per_base
Definition connector34.c:45
uint8_t mare
Definition reader.h:69
uint8_t te10
Definition reader.h:70
Definition ge.h:732
void * ctx
Definition ge.h:738
int(* deinit)(struct ge *, void *)
Definition ge.h:737
int(* on_clock)(struct ge *, void *)
Definition ge.h:736
int(* claims)(void *ctx, struct std_unitname un)
Definition connector34.h:56
struct ge_std_device * next
Definition connector34.h:74
const char * name
Definition connector34.h:51
std_reaction(* command)(struct ge *, void *ctx, struct std_unitname un, uint8_t order)
Definition connector34.h:60
std_reaction(* transfer)(struct ge *, void *ctx, struct std_unitname un, int dir, uint8_t *buf, uint16_t *len, uint16_t cap)
Definition connector34.h:68
The entire state of the emulated system, including registers, memory, peripherals and timings.
Definition ge.h:96
uint8_t RINT
Definition ge.h:364
void * std_core
Shared core for Standard-GE-100 controllers on connectors 3/4 (disk/tape).
Definition ge.h:654
uint8_t rRE
Definition ge.h:244
struct ge_connector ST4
The I/O interface for the ST4 connector.
Definition ge.h:636
uint8_t inject_chan1_status
Channel-1 peripheral status override for error injection.
Definition ge.h:588
uint16_t rV1
Addresser for the first operand.
Definition ge.h:123
uint8_t rSO
Main sequencer.
Definition ge.h:220
struct ge_connector ST3
The I/O interface for the ST3 connector.
Definition ge.h:631
uint8_t RC00
Asynchronous CPU Cycle Request.
Definition ge.h:445
uint8_t RASI
Channel 1 in transfer.
Definition ge.h:404
uint8_t unit
Definition connector34.h:43
uint8_t connector
Definition connector34.h:42