diff --git a/ge.c b/ge.c index 460b04a..af28b99 100644 --- a/ge.c +++ b/ge.c @@ -17,6 +17,9 @@ void ge_init(struct ge *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) @@ -236,12 +239,8 @@ int ge_deinit(struct ge *ge) void connectors_first_clock(struct ge *ge) { - ge_log(LOG_READER, " RA101 = %d\n", RA101(ge)); - ge_log(LOG_READER, " RF101 = %d\n", RF101(ge)); - ge_log(LOG_READER, " RB111 = %d\n", RB111(ge)); - ge_log(LOG_READER, " Signaling incoming data\n"); - if (RA101(ge)) { + ge_log(LOG_READER, "RA101: signaling incoming data\n"); ge->RC01 = 1; } } diff --git a/ge.h b/ge.h index 3924873..868b8a6 100644 --- a/ge.h +++ b/ge.h @@ -497,6 +497,7 @@ struct ge { uint8_t RAVI:1; uint8_t RT121:1; + uint8_t RT131:1; /** * Future state @@ -529,10 +530,20 @@ struct ge { struct ge_counting_network counting_network; /** - * The I/O interface for the integrated reader + * The I/O interface for the integrated reader (RI) */ struct ge_integrated_reader integrated_reader; + /** + * The I/O interface for the ST3 connector + */ + struct ge_connector ST3; + + /** + * The I/O interface for the ST4 connector + */ + struct ge_connector ST4; + struct ge_peri *peri; /** diff --git a/msl-commands.c b/msl-commands.c index 4a82d36..1410818 100644 --- a/msl-commands.c +++ b/msl-commands.c @@ -198,7 +198,7 @@ static void CE01(struct ge* ge) { static void CE02(struct ge* ge) { /* admits AEBE: */ /* UNIV 1.2µs --> RATE1 nand PC131 --> AEBE */ - /* AEBE is a control signal sent to ST3 */ + /* AEBE is a control signal sent to ST3 and ST4 */ /* Unconditionally set by command CE02 (cpu fo. 235) */ ge->PIC1 = 1; @@ -304,7 +304,14 @@ static void CE09(struct ge *ge) { /* emits TU101: */ /* UNIV 1.2µs --> RT111 */ - reader_send_tu10(ge); + uint8_t RT111 = 1; + + /* intermediate fo 14 D3 */ + uint8_t TU03A = !(RT111 && PC121(ge)); + uint8_t TU03 = !TU03A; + + if (TU03) + reader_send_tu10(ge); } static void CE10(struct ge *ge) { @@ -319,7 +326,20 @@ static void CE10(struct ge *ge) { } static void CE11(struct ge* ge) { - ge_log(LOG_PERI, "TODO: emit TU301.. should not be used by RI but only ST3 and ST4\n"); + ge->RT131 = 1; + + /* UNIV seems a delay line to synchronise the hardware, let's + * ignore the exact timings. */ + + /* ad hoc logic, this should be conditioned by TU30C and TU30D + * (intermediate fo 14, B4 B5) to send the command only to the + * specified units, but the signals don't fully work here */ + + if (PC131(ge)) + connector_send_tu00(ge, &ge->ST3); + + if (PC141(ge)) + connector_send_tu00(ge, &ge->ST4); } static void CE18(struct ge *ge) { diff --git a/reader.c b/reader.c index 4184b6c..9481dc8 100644 --- a/reader.c +++ b/reader.c @@ -89,3 +89,78 @@ uint8_t reader_get_FINI1(struct ge *ge) ge_log(LOG_READER, "**** reading FINI1 %d\n", ge->integrated_reader.fini); return ge->integrated_reader.fini; } + +uint8_t connector_get_MARE(struct ge_connector *conn) +{ + ge_log(LOG_READER, "%s -- connector_get_MARE\n", conn->name); + return conn->mare; +} + +uint8_t connector_get_TE10(struct ge_connector *conn) +{ + ge_log(LOG_READER, "%s -- connector_get_TE10\n", conn->name); + return conn->te10; +} + +uint8_t connector_get_TE20(struct ge_connector *conn) +{ + ge_log(LOG_READER, "%s -- connector_get_TE20\n", conn->name); + return conn->te20; +} + +uint8_t connector_get_TE30(struct ge_connector *conn) +{ + ge_log(LOG_READER, "%s -- connector_get_TE30\n", conn->name); + return conn->te30; +} + +uint8_t connector_get_FINE(struct ge_connector *conn) +{ + ge_log(LOG_READER, "%s -- connector_get_FINE\n", conn->name); + return conn->fine; +} + +void connector_setup_to_send(struct ge *ge, struct ge_connector *conn, uint8_t data, uint8_t end) +{ + /* equivalent of lu08, but not sure if it's TE10 or TE20, seems or-red together + * (intermediate fo. 11, D1, D2) */ + + conn->te10 = 1; + conn->te20 = 1; + conn->data = data; + conn->fine = end; + + /* signal end character */ + /* todo: should use RF101 here? is "if (end)" correct? */ + if (end) + ge->RIG1 = 1; + + /* todo: should be conditioned by PIM11, but it's false at this point + * without this, we don't get to state ea after waiting state b8 when + * reading */ + if (end) + ge->PEC1 = 1; + + if (RB111(ge)) { + ge_log(LOG_READER, "XXX\n"); + } +} + +void connector_clear_sending(struct ge_connector *conn) +{ + conn->te10 = 0; + conn->te20 = 0; + conn->data = 0; +} + +void connector_send_tu00(struct ge *ge, struct ge_connector *conn) +{ + uint8_t command = ge->rRE; + + switch (command) { +#define X(cmd, namex, desc) case cmd: ge_log(LOG_READER, " connector %s got: %02x - %s\n", conn->name, cmd, desc ); break; + ENUMERATE_READER_COMMANDS +#undef X + } + +} diff --git a/reader.h b/reader.h index bbf7834..dabc9e7 100644 --- a/reader.h +++ b/reader.h @@ -22,5 +22,27 @@ uint8_t reader_get_LU08(struct ge *); uint8_t reader_get_LUPO1(struct ge *); uint8_t reader_get_FINI1(struct ge *); +struct ge_connector { + const char *name; + + uint8_t data; + + uint8_t mare:1; + uint8_t te10:1; + uint8_t te20:1; + uint8_t te30:1; + uint8_t fine:1; +}; + +void connector_setup_to_send(struct ge *, struct ge_connector *, uint8_t, uint8_t); +void connector_send_tu00(struct ge *, struct ge_connector *); +void connector_clear_sending(struct ge_connector *); + +uint8_t connector_get_MARE(struct ge_connector *); +uint8_t connector_get_TE10(struct ge_connector *); +uint8_t connector_get_TE20(struct ge_connector *); +uint8_t connector_get_TE30(struct ge_connector *); +uint8_t connector_get_FINE(struct ge_connector *); + #endif diff --git a/signals.h b/signals.h index 33c1656..65d4b60 100644 --- a/signals.h +++ b/signals.h @@ -21,18 +21,18 @@ * @{ */ -SIG(RESIA) { return !ge->RESI; } -SIG(RIA01) { return ge->RIA0; } -SIG(RIA2A) { return !ge->RIA2; } -SIG(RIA3A) { return !ge->RIA3; } +SIG(RESI) { return ge->RESI; } +SIG(RESI1) { return RESI(ge); } +SIG(RESIA) { return !RESI1(ge); } +SIG(RIA01) { return ge->RIA0; } +SIG(RIA2A) { return !ge->RIA2; } +SIG(RIA3A) { return !ge->RIA3; } SIG(RIUCA) { return !(RIA01(ge) && RESIA(ge) && RIA2A(ge) && RIA3A(ge)); } /* adding RIUCA here breaks machine startup */ SIG(RES01) { return !(RESIA(ge) /* && RIUCA(ge) */); } -SIG(RESI) { return ge->RESI; } - /** Cycle assigned to channel 1 */ SIG(RES0) { return RES01(ge); } @@ -62,6 +62,8 @@ SIG(RIUC) { return ge->RIA0 & !ge->RESI & !ge->RIA3 & !ge->RIA2; } +SIG(RES31) { return RES3(ge); }; + /** @} */ /** @@ -270,21 +272,6 @@ static inline uint16_t NI_knot(struct ge *ge) { (ni1 << 0)); } -/** - * NI Knot - * - * Can't find proper documentation in PDS, but it's documented in the intermediate - * block diagram, fo. 14. - * - * Should be a multiplexer of the I/O units outputs. - */ -static inline uint16_t NE_knot(struct ge *ge) { - /* TODO: proper implementation, just return the RI data */ - uint16_t ret = ge->integrated_reader.data; - ge_log(LOG_PERI, "READING FROM NE KNOT --> %03x\n", ret); - return ret; -} - /** @} */ /** @@ -450,14 +437,18 @@ SIG(FUSE1) { return 0; } SIG(FINA1) { return 0; } /* ST3 */ -SIG(MARE3) { return 0; } -SIG(TE303) { return 0; } -SIG(FINE3) { return 0; } +SIG(MARE3) { return connector_get_MARE(&ge->ST3); } +SIG(TE103) { return connector_get_TE10(&ge->ST3); } +SIG(TE203) { return connector_get_TE20(&ge->ST3); } +SIG(TE303) { return connector_get_TE30(&ge->ST3); } +SIG(FINE3) { return connector_get_FINE(&ge->ST3); } /* ST4 */ -SIG(MARE4) { return 0; } -SIG(TE304) { return 0; } -SIG(FINE4) { return 0; } +SIG(MARE4) { return connector_get_MARE(&ge->ST4); } +SIG(TE104) { return connector_get_TE10(&ge->ST4); } +SIG(TE204) { return connector_get_TE20(&ge->ST4); } +SIG(TE304) { return connector_get_TE30(&ge->ST4); } +SIG(FINE4) { return connector_get_FINE(&ge->ST4); } /** @} */ @@ -468,6 +459,7 @@ SIG(PB13A) { return !(TE303(ge) && PC131(ge)); } SIG(PB14A) { return !(TE304(ge) && PC141(ge)); } SIG(RT121) { /* UNIV 1.2µs */ return ge->RT121; } +SIG(RT131) { /* UNIV 1.2µs */ return ge->RT131; } SIG(RB101) { return !(AITEA(ge) && PB11A(ge) && PB13A(ge) && PB14A(ge)); } SIG(RB121) { /* UNIV 1.2µs */ return RB101(ge); } @@ -581,6 +573,10 @@ SIG(PUB01) { return !(PUB01_d1(ge) && PUB01_d2(ge) && PUB01_d3(ge) && PUB01_d /** Integrated printer on channel 2 */ SIG(PC211) { return !PC21A(ge); } +SIG(PC321) { return !PC32A(ge); } +SIG(PC331) { return !PC33A(ge); } +SIG(PC341) { return !PC34A(ge); } + /** @} */ /* !(!rejected && in transfer) => rejected || !in_transfer */ @@ -629,8 +625,12 @@ SIG(TU00A) { return !(RT121(ge) && RUF1A(ge) && PC121(ge));} */ SIG(FU091) { return 0; } /* todo: printer */ -SIG(PTA31) { return 0; } /* todo: ST3 */ -SIG(PTA41) { return 0; } /* todo: ST4 */ + +SIG(PTA3A) { return !(TE103(ge) && TE203(ge)); } +SIG(PTA31) { return !PTA3A(ge); } + +SIG(PTA4A) { return !(TE104(ge) && TE204(ge)); } +SIG(PTA41) { return !PTA4A(ge); } SIG(PA11A) { return !(FU091(ge) && PC111(ge)); } SIG(PA12A) { return !(LU081(ge) && PC121(ge)); } @@ -640,4 +640,106 @@ SIG(RA101) { return !(PA11A(ge) && PA12A(ge) && PA13A(ge) && PA13A(ge) && PA14A( /* } */ +SIG(RET21) { return 0; }; +SIG(PC221) { return 0; }; + +/** + * @defgroup ne-logic NE Knot Logic + * + * From the Intermediate Block Diagram, fo. 14 + * + * @{ + */ + +SIG(PIB1A) { return !(RET21(ge) && PC211(ge)); } +SIG(PIB11) { return !PIB1A(ge); } + +SIG(PB12A) { return !(RESI1(ge) && PC121(ge)); } +SIG(PB22A) { return !(RET21(ge) && PC221(ge)); } +SIG(PB32A) { return !(RES31(ge) && PC321(ge)); } +SIG(PIB21) { return !(PB12A(ge) && PB22A(ge) && PB32A(ge)); } + +SIG(RB13A) { return !(RESI1(ge) && PC131(ge)); } +SIG(RB33A) { return !(RES31(ge) && PC331(ge)); } +SIG(PIB31) { return !(RB13A(ge) && RB33A(ge)); } + +SIG(RB14A) { return !(RESI1(ge) && PC141(ge)); } +SIG(RB34A) { return !(RES31(ge) && PC341(ge)); } +SIG(PIB41) { return !(RB14A(ge) && RB34A(ge)); } + +/** + * NE Knot + * + * Can't find proper documentation in PDS, but it's documented in the intermediate + * block diagram, fo. 14. + * + * Should be a multiplexer of the I/O units outputs. + */ +static inline uint16_t NE_knot(struct ge *ge) { + uint16_t ret = 0; + const char *where = ""; + + uint8_t count = PIB11(ge) + PIB21(ge) + PIB31(ge) + PIB41(ge); + + if (count > 1) { + ge_log(LOG_PERI, "multiple input signals for NE knot (?!)\n"); + } + + if (PIB11(ge)) { + where = "PI"; + ge_log(LOG_PERI, "TODO -- printer\n"); + } + + if (PIB21(ge)) { + where = "RI"; + ret = ge->integrated_reader.data; + } + + if (PIB31(ge)) { + where = "ST3"; + ret = ge->ST3.data; + } + + if (PIB41(ge)) { + where = "ST4"; + ret = ge->ST3.data; + } + + ge_log(LOG_PERI, "READING FROM NE KNOT %s --> %03x\n", where, ret); + return ret; +} + +/* } */ + +/** + * @defgroup connector-3 Connector 3 Logic + * + * From the Intermediate Block Diagram, fo. 14 + * + * @{ + */ + +#define NAOR(a, b, c, d) !(a || b || c || d) + +SIG(RT111) { return 0; } + +SIG(RT311) { return 0; } +SIG(RT321) { return 0; } +SIG(RT331) { return 0; } + +SIG(RATE1) { return 0; } +SIG(PUOO3) { return 0; } +SIG(RUF31) { return 0; } +SIG(RAVI1) { return 0; } + +SIG(TU10C) { return NAOR(RT111(ge), PC131(ge), RT311(ge), PC331(ge)); } +SIG(TU20C) { return NAOR(RT121(ge), PC131(ge), RT321(ge), PC331(ge)); } +SIG(TU30C) { return NAOR(RT131(ge), PC131(ge), RT331(ge), PC331(ge)); } +SIG(AEBEC) { return !(RATE1(ge) && PC131(ge)); } +SIG(AECO3) { return !PUOO3(ge); } +SIG(FINUC) { return NAOR(RUF11(ge), PC131(ge), RUF31(ge), PC331(ge)); } +SIG(PV13A) { return !(RAVI1(ge) && PC131(ge)); } +SIG(VICU3) { return !(FINUC(ge) && PV13A(ge)); } +/* } */ + #endif diff --git a/tests/initial-load.c b/tests/initial-load.c index 7df2b70..54b2901 100644 --- a/tests/initial-load.c +++ b/tests/initial-load.c @@ -2,11 +2,11 @@ #include "../ge.h" #include "../bit.h" -#define ASSERT_CYCLE(x, name) \ - do { \ +#define ASSERT_CYCLE(x, name) \ + do { \ printf("\n" name "\n\n"); \ - ASSERT_EQ(g.rSO, x); \ - ge_run_cycle(&g); \ + ASSERT_EQ(g.rSO, x); \ + ge_run_cycle(&g); \ } while (0) UTEST(load, load_1_button) { @@ -69,6 +69,7 @@ UTEST(load, load_1_button) { ASSERT_EQ((g.rV1 & 0xff00) >> 8, 0); /* memory address hi */ ASSERT_CYCLE(0xab, "TPER-CPER 5"); + ASSERT_TRUE(g.RC00); /* cpu should run */ ASSERT_EQ(g.rV1, 0); /* memory address low */ ASSERT_TRUE(g.RASI); /* channel 1 in transfer */ ASSERT_TRUE(g.RIA0); /* synchronous cycle request */ @@ -134,3 +135,79 @@ UTEST(load, load_1_button) { ASSERT_CYCLE(0xeb, "TPER END 2"); ASSERT_CYCLE(0xe3, "Alpha 1"); } + +UTEST(load, load_2_button) { + struct ge g; + struct ge_console c; + + ge_init(&g); + ge_clear(&g); + ge_load_2(&g); + ge_load(&g); + ge_start(&g); + + ASSERT_CYCLE(0x00, "Display"); + ASSERT_CYCLE(0x80, "Initialisation"); + ASSERT_TRUE(BIT(g.ffFI, 6)); /* always true */ + ASSERT_EQ(g.ffFI, 0x40); + + ASSERT_CYCLE(0xc8, "PER-PERI 1"); + ASSERT_FALSE(BIT(g.rL2, 6)); /* false == input transfer */ + ASSERT_FALSE(BIT(g.rL2, 5)); /* false == increasing addresses */ + ASSERT_FALSE(BIT(g.rL2, 4)); /* false == input with packing */ + ASSERT_FALSE(BIT(g.rL2, 3)); /* false == channel 1 or 3 */ + ASSERT_FALSE(BIT(g.rL2, 2)); /* false == wait for peripheral availability */ + ASSERT_FALSE(BIT(g.rL2, 1)); /* always false */ + ASSERT_FALSE(BIT(g.rL2, 0)); /* false == channel 1 or 2 */ + ASSERT_EQ(g.rL2, 0x00); + + ASSERT_FALSE(BIT(g.ffFI, 4)); /* always false */ + ASSERT_FALSE(BIT(g.ffFI, 5)); /* connector and channel not busy */ + + ASSERT_CYCLE(0xd8, "PER-PERI 2"); + ASSERT_EQ(g.rRE, 0x00); /* peripheral name: */ + /* 0x80 == connector 2 */ + /* 0x00 == connector 3 */ + + ASSERT_CYCLE(0xd9, "PER-PERI 3"); + ASSERT_CYCLE(0xda, "PER-PERI 4"); + ASSERT_CYCLE(0xdb, "PER-PERI 5"); + ASSERT_TRUE(BIT(g.ffFI, 4)); /* always true */ + ASSERT_EQ(g.ffFI, 0x50); + + ASSERT_CYCLE(0xdc, "PER-PERI 6"); + ASSERT_EQ(g.rV1, g.rV3); + ASSERT_EQ(g.rRO, 0x01); + + ASSERT_CYCLE(0xcc, "PER-PERI 7"); + ASSERT_EQ(g.rRE, 0x40); /* 0x40: read forward command */ + ASSERT_EQ(g.rRA, 0x40); + + ASSERT_CYCLE(0xca, "TPER-CPER 1"); + ASSERT_FALSE(g.RIG1); /* reset end from controller 1 */ + + ASSERT_CYCLE(0xa8, "TPER-CPER 2"); + ASSERT_EQ((g.rL1 & 0xff00) >> 8, 0); /* length of read hi (zero on initial load) */ + + ASSERT_CYCLE(0xa9, "TPER-CPER 3"); + ASSERT_EQ(g.rL1, 0x80); /* length of read low (0x80 on initial load) */ + + ASSERT_CYCLE(0xaa, "TPER-CPER 4"); + ASSERT_EQ((g.rV1 & 0xff00) >> 8, 0); /* memory address hi */ + + ASSERT_CYCLE(0xab, "TPER-CPER 5"); + ASSERT_EQ(g.rV1, 0); /* memory address low */ + ASSERT_TRUE(g.RASI); /* channel 1 in transfer */ + ASSERT_TRUE(g.RIA0); /* synchronous cycle request */ + ASSERT_FALSE(g.RESI); /* not synchronous channel 1 request */ + ASSERT_FALSE(g.RIA2); /* not synchronous channel 2 request */ + ASSERT_FALSE(g.RIA3); /* not synchronous channel 3 request */ + + /* here the machine is waiting for the acknowledgment from the + * device, after having issued the AEBE signal, however */ + + ASSERT_FALSE(g.RC00); + ASSERT_FALSE(g.RC01); + ASSERT_FALSE(g.RC02); + ASSERT_FALSE(g.RC03); +}