Last active
September 7, 2022 13:15
-
-
Save logicplace/4a4143942894ef1bbba7f4fda3c5906d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <pm.h> | |
#include <stdint.h> | |
// These are extra return values | |
int8_t reg_L, reg_B; | |
union { | |
struct { | |
uint8_t u150a; // $150a | |
uint8_t length; // $150b | |
uint8_t start_p; // $150c | |
uint8_t *start; // $150d | |
uint16_t suffix; // $150f | |
uint8_t u1511; // $1511 | |
} send; | |
struct { // sizeof 28 | |
uint8_t u150a; // $150a | |
uint8_t u150b; // $150b | |
uint8_t u150c; // $150c | |
uint8_t u150d[2]; // $150b | |
uint8_t u150f; // $150f bitmask of some sort | |
uint8_t u1510; // $1510 | |
uint8_t u1511; // $1511 | |
uint8_t *u1512; // $1512 | |
union { | |
uint8_t *u1514; // $1514 | |
} ptr; | |
union { | |
uint8_t u1514; // $1514 | |
uint8_t u1515; // $1515 | |
} end; | |
uint8_t data[4]; // $1516 | |
uint8_t u151a; // $151a | |
uint8_t u151b; // $151b | |
uint8_t u151c; // $151c | |
uint8_t *u151d; // $151d | |
uint8_t u151f[7]; // $151f | |
} recv; | |
} working; | |
// more referenced, $1527~$152f, but seem to be separate structures | |
uint8_t* /*_at(0x152c) */ buffer; | |
extern uint8_t flags; | |
void send(uint8_t byte); | |
void wait_for(int cycles); | |
// @0031dd - Tetris (EU) | |
void ir_out( | |
uint8_t H, | |
uint8_t* /*_far*/ start, | |
uint8_t length, | |
uint8_t A | |
) { | |
// Put in global struct | |
working.send.u150a = A; | |
working.send.length = length; | |
working.send.start_p = (uint16_t)start >> 16; | |
working.send.start = (uint16_t)start & 0xffff; | |
working.send.u1511 = H; | |
int i, res = 0; | |
if (length) { | |
uint8_t *s = start; | |
res = i = length; | |
for (; i; --i) { | |
res += *s; | |
++s; | |
} | |
} | |
res += A; | |
working.send.suffix = res; | |
if (H != 1) { | |
IRQ_ACT4 = IRQ4_IR_RECV; | |
i = 0x300; | |
do { | |
_nop(); | |
if (!--i) break; | |
} while (!(IRQ_ACT4 & IRQ4_IR_RECV)); | |
wait_for(812); // 2 + (6 + 2 + 2) * 0x51 | |
} | |
if (length == 0) { | |
start = &res; | |
} | |
for (i = 18;;) { | |
ir_pulse(); | |
if (--i) break; | |
wait_for(68); | |
} | |
wait_for(70); | |
wait_for(120); // @0034df | |
wait_for(61); | |
send(0); | |
wait_for(51); | |
// XI set from start param for these.. | |
send(A); | |
wait_for(51); | |
send(length); | |
wait_for(40); // + 11 for preparing argument | |
send(A ^ length); | |
wait_for(20); | |
int max_bytes = 3; | |
// waits omitted after this point (sorry) | |
for (i = length; i;) { | |
while (i) { | |
send(*start); | |
if (!--max_bytes) break; | |
++start; | |
--i; | |
} | |
if (max_bytes) { | |
// Bytes have been completely sent | |
switch (max_bytes) { | |
case 1: | |
// remaining length was 2 | |
start -= 2; // back to initial byte | |
send(*start ^ *(start + 1)); | |
break; | |
case 2: | |
// remaining length was 1 | |
--start; // back to initial byte | |
send(*start); | |
break; | |
case 3: | |
// remaining length was 0 | |
break; | |
} | |
break; | |
} else { | |
// remaining length was 3 or higher | |
// More bytes to send, send parity check | |
start -= 2; // back to initial byte | |
send(*start ^ *(start + 1) ^ *(start + 2)); | |
max_bytes = 4; // +1 for the parity byte | |
} | |
} | |
send(res >> 8); | |
send(res & 0xff); | |
send((res >> 8) ^ (res & 0xff)); | |
} | |
// @003404 - Tetris (EU) | |
void send(uint8_t byte) { | |
int i, num_set = 0; | |
wait_for(6); | |
ir_pulse(); | |
wait_for(67); | |
for (i = 8;;) { | |
if (byte & (1 << (i-1))) { | |
ir_pulse(); | |
++num_set; | |
} else { | |
wait_for(120); // length of an ir_pulse (@0034df) | |
} | |
if (!--i) break; | |
wait_for(61); | |
} | |
// $00345f | |
if (num_set & 1) { | |
num_set = 0; | |
wait_for(61); | |
ir_pulse(); | |
} else { | |
num_set = 0; | |
wait_for(61); | |
wait_for(120); // length of an ir_pulse (@0034df) | |
} | |
return; | |
} | |
// @0034b1 - Tetris (EU) | |
// pulse for 16 cycles (120 total cycles taken (incl call/ret)) | |
void ir_pulse(void) { | |
_push("IY", "B"); | |
_ld("IY", 0x2061); // IO_DATA | |
_ld("B", 4); // pulse for 16 cycles (each DJR is 4 cycles) | |
_int(0x4c); // ir_pulse in BIOS | |
_pop("B", "IY"); | |
wait_for(63); | |
return; | |
} | |
#define fun_003c7c(H) \ | |
(working.recv.u150a = max( \ | |
working.recv.u150a - (14 * (18 - H)), 0), \ | |
1) | |
uint8_t fun_00351a(uint8_t A, uint8_t *IX, uint16_t IY) { | |
int i, j, L, res, *cur, *out; | |
// BR = 0x20 and zeroes EP, XP, and YP | |
if (A >= 0x80) { | |
return 5; | |
} | |
// $00352a | |
*cur = working.recv.data; | |
for (i = sizeof(working.recv); i; --i) { | |
*cur = 0; | |
++cur; | |
} | |
// $00353e | |
working.recv.u1510 = A; | |
working.recv.u1512 = IX; | |
working.recv.u151d = IX; | |
IRQ_ACT4 = IRQ4_IR_RECV; // clear IR IRQ | |
// $003551 | |
i = 18; | |
L = 0; | |
IY = IY >= 24 ? IY - 23 : 1; | |
do { | |
_nop(); | |
if(!--IY) break; | |
} while(!(IRQ_ACT4 & IRQ4_IR_RECV)); | |
working.recv.u150a = IY; | |
wait_for(5); | |
for (j = 13;;) { | |
wait_for(6); | |
if(!--j) break; | |
} | |
wait_for(3); | |
for (reg_B = 9;;) { | |
res = read_bit(L); | |
if (!--i) break; | |
if (res != 1) { | |
return fun_003c7c(i); | |
} | |
wait_for(109); | |
} | |
// $0035c3 | |
if (res != 0) { | |
return fun_003c7c(i); | |
} | |
wait_for(109); | |
// $0035ff | |
for (cur = working.recv.data;;) { | |
res = read_bit(L); | |
if (res == -1) { | |
// $003c96 | |
return 2; | |
} else if(reg_B == 1) { | |
// $0036bd | |
if (res != (L & 1)) { | |
L = 0; | |
i ^= *cur; | |
if (cur == 0x1519) { | |
res = working.recv.u151a; | |
wait_for(15); | |
break; | |
} | |
++cur; | |
wait_for(79); | |
} else { | |
// $003700 | |
if (working.recv.u151a != 0) { | |
// $003c99 | |
return 3; | |
} | |
working.recv.u151a = 1; | |
working.recv.ptr.u1514 = cur; | |
L = 0; | |
if (cur == 0x1519) { | |
res = 1; | |
break; | |
} | |
++cur; | |
wait_for(59); | |
} | |
} else if(reg_B == 10) { | |
// $003684 | |
if (res != 1) { | |
// $003ca5 | |
return -2; | |
} | |
wait_for(97); | |
} else if (res == 0) { | |
// $003650 | |
*cur = (*cur << 1); | |
wait_for(90); // +4 for OR and INC | |
} else { | |
// $00361b | |
*cur = (*cur << 1) | 1; | |
++L; | |
wait_for(86); | |
} | |
} | |
// $00374c | |
cur = working.recv.data; | |
if (res == 0) { | |
working.recv.u150a = *cur++; | |
working.recv.u150b = *cur++; | |
res = working.recv.u150c = *cur; | |
wait_for(8); | |
} else { | |
*working.recv.ptr.u1514 = i; | |
working.recv.u150a = *cur++; | |
working.recv.u150b = *cur++; | |
res = working.recv.u150c = *cur; | |
} | |
// $00377c | |
if (res >= 3) { | |
if (res - 1 >= working.recv.u1510) { | |
// $003c9f | |
return 5; | |
} | |
working.recv.u150f = 0x03; | |
wait_for(3); | |
// $003790 | |
for (;;) { | |
for (;;) { | |
res = read_bit(L); | |
if (res == -1) { | |
// $003c96 | |
return 2; | |
} else if(reg_B == 1) { | |
// $0038ea | |
if (res != (L & 1)) { | |
L = 0; | |
i ^= *cur; | |
if (cur == 0x1519) { | |
// $00396d | |
res = working.recv.u151a; | |
wait_for(15); | |
break; | |
} | |
++cur; | |
wait_for(79); | |
} else { | |
// $00392d | |
if (working.recv.u151a != 0) { | |
// $003c99 | |
return 3; | |
} | |
working.recv.u151a = 1; | |
working.recv.ptr.u1514 = cur; | |
L = 0; | |
if (cur == 0x1519) { | |
res = 1; | |
break; | |
} | |
++cur; | |
wait_for(59); | |
} | |
} else if(reg_B == 10) { | |
// $003812 | |
if (res != 1) { | |
// $003ca5 | |
return -2; | |
} | |
if (1 & working.recv.u150f) { | |
// $003855 | |
i = 0; L = 0; | |
working.recv.u151a = 0; | |
working.recv.data[3] = 0; | |
working.recv.data[2] = 0; | |
working.recv.data[1] = 0; | |
working.recv.data[0] = 0; | |
working.recv.u150f &= 0xfe; | |
wait_for(52); | |
} else if (2 & working.recv.u150f) { | |
// $00388d | |
working.recv.u151b = (uint8_t)(working.recv.u150c / 3); | |
working.recv.u151c = working.recv.u150c % 3; | |
working.recv.u150f &= 0xfd; | |
wait_for(31); | |
} else if (4 & working.recv.u150f) { | |
// $0038bf | |
working.recv.u151d += 3; | |
working.recv.u150f &= 0xfb; | |
wait_for(35); | |
} | |
wait_for(70); | |
} else if (res == 0) { | |
// $0037de | |
*cur = (*cur << 1); | |
wait_for(90); // +4 for OR and INC | |
} else { | |
// $0037a9 | |
*cur = (*cur << 1) | 1; | |
++L; | |
wait_for(86); | |
} | |
} | |
// $003979 | |
if (res == 0) { | |
out = working.recv.u151d; | |
cur = working.recv.data; | |
*out++ = *cur++; | |
*out++ = *cur++; | |
*out = *cur; | |
wait_for(8); | |
} else { | |
*working.recv.ptr.u1514 = i; | |
out = working.recv.u151d; | |
cur = working.recv.data; | |
*out++ = *cur++; | |
*out++ = *cur++; | |
*out = *cur; | |
} | |
if ((res = working.recv.u151b - 1)) { | |
working.recv.u151b = res; | |
L = -1; | |
_nop(); | |
} else { | |
// $0039cb | |
wait_for(6); | |
break; | |
} | |
} | |
} else { | |
// $0039bc | |
working.recv.u151c = res; | |
working.recv.u150f = 0xff; | |
wait_for(4); | |
} | |
// $0039d1 | |
res = read_bit(L); | |
if (res == -1) { | |
// $003c96 | |
return 2; | |
} | |
switch (working.recv.u151c) { | |
case 0: | |
// $0039e9 | |
res = 0x1d; | |
wait_for(4); | |
break; | |
case 1: | |
// $0039ed | |
res = 0x31; | |
break; | |
default: | |
// $0039e5 | |
res = 0x3b; | |
break; | |
} | |
L = res; | |
working.recv.u151c = res + 1; | |
cur = working.recv.u151f; | |
*cur = 1; | |
i = 7; | |
wait_for(83); | |
// $003a2b | |
for (;;) { | |
res = read_bit(L); | |
if (res == -1) { | |
// $003c96 | |
return 2; | |
} | |
// $003a33 | |
if (res != 1) { | |
*cur = *cur << 1; | |
wait_for(1); | |
} else { | |
// $003a3e | |
*cur = (*cur << 1) | 1; | |
} | |
// $003a44 | |
if(!--i) { | |
++cur; | |
i = 8; | |
} else { | |
wait_for(6); | |
} | |
if (!--L) break; | |
wait_for(85); | |
} | |
// $003a81 | |
for (; i; --i) { | |
// $003a86 | |
*cur = *cur << 1; | |
} | |
// $003a8d | |
if (working.recv.u1510 < working.recv.u150c) { | |
// $003c9f | |
return 5; | |
} | |
if (working.recv.u150f != 0xff) { | |
working.recv.u151d += 3; | |
} | |
L = working.recv.u151c; | |
working.recv.end.u1514 = (uint8_t)(L / 10); | |
working.recv.data[0] = 0; | |
working.recv.end.u1515 = 0; | |
working.recv.data[1] = 10; | |
out = cur = working.recv.u151f; | |
i = 8; | |
_ld("A", 0); // waste cycles | |
res = *cur; | |
// $003ad6 | |
for (;;) { | |
switch (--working.recv.data[1]) { | |
case 9: | |
// $003af9 | |
res <<= 1; | |
break; | |
case 0: | |
// $003aff | |
uint8_t tmp = working.recv.end.u1515, tL, tC; | |
*out = tmp; | |
tL = 0; | |
for (j = 8;;) { | |
tC = tmp & 0x80; // carry flag | |
tmp <<= 1; | |
if (tC) ++tL; | |
if (!--j) break; | |
} | |
tL &= 1; | |
res <<= 1; | |
_rl(tmp); // 0xce91 | |
tmp &= 1; | |
if (tL == tmp) { | |
// $003b26 | |
working.recv.data[0] <<= 1; | |
} else { | |
// $003b32 | |
working.recv.data[0] = (working.recv.data[0] << 1) | 1; | |
} | |
// $003b3e | |
working.recv.data[1] = 10; | |
++out; | |
break; | |
default: | |
res <<= 1; | |
_rl(working.recv.end.u1515); // 0xce91 | |
} | |
// $003b4b | |
if (!--L) break; | |
if (!--i) { | |
i = 8; | |
++cur; | |
res = *cur; // from $003ad5 | |
} | |
} | |
// $003b56 | |
switch(working.recv.end.u1514) { | |
case 3: | |
// 3c06 | |
break; | |
case 5: | |
// 3bb7 | |
break; | |
default: | |
working.recv.data[0] <<= 2; | |
if (fun_003ca8(0x1518, 0x151f, 3) == 1) { | |
// $003c99 | |
return 3; | |
} | |
break; | |
} | |
// $003c33 | |
} | |
// @003cd5 - Tetris (EU) | |
int8_t read_bit(int8_t L) { | |
int i; | |
wait_for(1); | |
IRQ_ACT4 = IRQ4_IR_RECV; // clear IR IRQ | |
if (--reg_B) { | |
// $003cff | |
wait_for(51); | |
return IRQ_ACT4 & IRQ4_IR_RECV ? 1 : 0; | |
} else { | |
reg_B = 10; | |
for (i = 10;;) { | |
if (!--i) return -1; | |
if (IRQ_ACT4 & IRQ4_IR_RECV) break; | |
} | |
if (L == -1) { | |
working.recv.u150f = 0x05; | |
} else { | |
wait_for(9); | |
} | |
wait_for(6); | |
return 1; | |
} | |
} | |
// @003df6 - Tetris (EU) | |
void /*_interrupt(...)*/ ir_recv() { | |
flags &= 0xcf; // reset interrupt priority | |
IRQ_ACT4 = IRQ4_IR_RECV; // clear IR IRQ | |
switch (fun_003ffa()) { | |
case 0: | |
*(uint8_t*)0x1528 = reg_B + 0x80; | |
IRQ_ENA4 &= ~IRQ4_IR_RECV; // disable IR IRQ | |
break; | |
case 3: | |
*(uint8_t*)0x1528 = 2; | |
IRQ_ENA4 &= ~IRQ4_IR_RECV; // disable IR IRQ | |
break; | |
default: | |
break; | |
} | |
IRQ_ACT4 = IRQ4_IR_RECV; // clear IR IRQ | |
} | |
// @003ffa - Tetris (EU) | |
uint8_t fun_003ffa() { | |
int ret, res; | |
// These are pushed to the stack in pairs via HL | |
uint8_t IRQ_ENA1_bak = IRQ_ENA1; | |
uint8_t IRQ_ENA2_bak = IRQ_ENA2; | |
uint8_t IRQ_ENA4_bak = IRQ_ENA4; | |
uint8_t PRC_MODE_bak = PRC_MODE; | |
IRQ_ENA1 = 0; | |
IRQ_ENA2 &= IRQ2_CART_EJECT | IRQ2_CART; | |
IRQ_ENA3 &= ~(IRQ4_IR_RECV | IRQ4_SHOCK); | |
if (is_prc_busy()) { | |
// $004087 | |
ret = 1; | |
} else { | |
PRC_MODE = 0; | |
*buffer = 0; | |
res = fun_00351a(0x0050, *(uint16_t*)0x00152a, *(uint8_t*)0x152f); | |
*buffer = res; | |
switch (res) { | |
case -1: | |
// $00408b | |
ret = 2; | |
break; | |
case 1: | |
// $004093 | |
ret = 4; | |
break; | |
case 0: | |
// $004046 | |
*(uint8_t*)0x152d = reg_L; | |
if (reg_B == -1 || *(uint8_t*)0x1527 == reg_B) { | |
// $004056 | |
ir_out(1, buffer, 1, 0); | |
ret = 0; | |
} else { | |
// $00408f | |
ret = 3; | |
} | |
break; | |
default: | |
ret = 1; | |
break; | |
} | |
} | |
// $004067 | |
IRQ_ACT1 = 0xff; | |
IRQ_ACT2 = 0xff; | |
IRQ_ACT3 = 0xff; | |
IRQ_ACT4 = 0xff; | |
IRQ_ENA4 = IRQ_ENA4_bak; | |
PRC_MODE = PRC_MODE_bak; | |
IRQ_ENA1 = IRQ_ENA1_bak; | |
IRQ_ENA2 = IRQ_ENA2_bak; | |
reg_B = *(uint8_t*)0x152d; | |
return ret; | |
} | |
// @0040be - Tetris (EU) | |
uint8_t is_prc_busy() { | |
// TODO | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment