Skip to content

Commit 89b07cf

Browse files
committed
Slot2: rewrite Slide Controller
1 parent 3a1c9e2 commit 89b07cf

File tree

1 file changed

+150
-181
lines changed

1 file changed

+150
-181
lines changed
Lines changed: 150 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//Serial handling code heavily inspired by the Magic Reader code in GBE+
2+
//https://github.com/shonumi/gbe-plus/blob/7986317958a672d72ff54ea33f31bcca13cf8330/src/nds/slot2.cpp#L155
3+
14
/*
25
Copyright (C) 2023 DeSmuME team
36
@@ -21,34 +24,127 @@
2124
#include "../slot2.h"
2225
#include "../emufile.h"
2326

24-
#define SC_BITIN(X, Y) \
25-
do { \
26-
X = (X << 1) | (Y & 1); \
27-
bitsWritten++; \
28-
} while (0)
29-
30-
#define SC_BITOUT(X, Y) \
31-
do { \
32-
X = ((Y >> 7 - bitsRead) & 1); \
33-
bitsRead++; \
34-
} while(0)
35-
36-
u8 motionStatus;
37-
u8 xMotion;
38-
u8 yMotion;
27+
//Product ID, Revision ID, Motion status, X delta, Y delta, Surface quality
28+
//Average pixel, Maximum pixel, Reserved, Reserved, Configuration, Reserved
29+
//Data out lower, Data out upper, Shutter lower, Shutter upper, Frame period lower, Frame period upper
30+
static u8 scRegs[18] = { 0x03, 0x20, 0x00, 0x00, 0x00, 0x80, 0x20, 0x3F, 0x00,
31+
0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x20, 0xD1 };
3932

4033
class Slot2_SlideController : public ISlot2Interface
4134
{
4235
private:
43-
u8 prevClock;
44-
u8 bitsWritten;
45-
u8 bitsRead;
46-
u8 inByte;
47-
u16 regSel;
48-
49-
u8 configBits;
50-
u8 framePeriodLower;
51-
u8 framePeriodUpper;
36+
struct slideControllerSerial
37+
{
38+
u16 in_data;
39+
u16 out_data;
40+
u8 counter;
41+
u8 state;
42+
u8 sck;
43+
u8 reg_sel;
44+
u8 tmp;
45+
} slideCon = {};
46+
47+
void slideCon_reset()
48+
{
49+
slideCon.in_data = 0;
50+
slideCon.out_data = 0;
51+
slideCon.counter = 0;
52+
slideCon.state = 0;
53+
slideCon.sck = 0;
54+
slideCon.reg_sel = 0;
55+
slideCon.tmp = 0;
56+
57+
scRegs[0x02] = 0x00; //Motion status
58+
scRegs[0x03] = 0x00; //X delta
59+
scRegs[0x04] = 0x00; //Y delta
60+
scRegs[0x0A] = 0x00; //Config bits
61+
scRegs[0x10] = 0x20; //Frame period lower
62+
scRegs[0x11] = 0xD1; //Frame period upper
63+
}
64+
65+
void slideCon_process()
66+
{
67+
//Serial clock in bit 1
68+
u8 new_sck = (slideCon.in_data & 0x2) >> 1;
69+
//Serial data in bit 0
70+
u8 sd = slideCon.in_data & 0x1;
71+
72+
switch (slideCon.state)
73+
{
74+
case 0: //reg select
75+
//build reg select byte
76+
if ((slideCon.sck == 0) && (new_sck == 1) && (slideCon.counter < 8))
77+
{
78+
slideCon.reg_sel = (slideCon.reg_sel << 1) | sd;
79+
slideCon.counter++;
80+
}
81+
else if (slideCon.counter == 8)
82+
{
83+
//check if it's a read or a write by MSB
84+
if (slideCon.reg_sel & 0x80)
85+
{
86+
slideCon.state = 1;
87+
slideCon.reg_sel &= 0x7F;
88+
slideCon.tmp = 0;
89+
}
90+
else
91+
{
92+
slideCon.state = 2;
93+
}
94+
slideCon.counter = 0;
95+
}
96+
97+
98+
break;
99+
case 1: //write reg
100+
if ((slideCon.sck == 0) && (new_sck == 1) && (slideCon.counter < 8))
101+
{
102+
slideCon.tmp = (slideCon.tmp << 1) | sd;
103+
slideCon.counter++;
104+
}
105+
else if ((slideCon.sck == 0) && (new_sck == 0) && (slideCon.counter == 8))
106+
{
107+
//printf("WRITE REG: %02X = %02X\n", slideCon.reg_sel, slideCon.tmp);
108+
slideCon.state = 0;
109+
slideCon.counter = 0;
110+
111+
if (slideCon.reg_sel <= 0x11)
112+
scRegs[slideCon.reg_sel] = slideCon.tmp;
113+
}
114+
break;
115+
case 2: //read reg
116+
if ((slideCon.sck == 0) && (new_sck == 1) && (slideCon.counter < 8))
117+
{
118+
if (slideCon.reg_sel <= 0x11)
119+
slideCon.out_data = (scRegs[slideCon.reg_sel] >> (7 - slideCon.counter)) & 1;
120+
else
121+
slideCon.out_data = 0;
122+
slideCon.counter++;
123+
}
124+
else if ((slideCon.sck == 0) && (new_sck == 0) && (slideCon.counter == 8))
125+
{
126+
//printf("READ REG: %02X = %02X\n", slideCon.reg_sel, scRegs[slideCon.reg_sel]);
127+
slideCon.state = 0;
128+
slideCon.counter = 0;
129+
130+
//Reset motion flag if reg was motion status
131+
if (slideCon.reg_sel == 0x02)
132+
scRegs[0x02] &= 0x7F;
133+
//Reset motion deltas if they were read
134+
if ((slideCon.reg_sel == 0x03) || (slideCon.reg_sel == 0x04))
135+
scRegs[slideCon.reg_sel] = 0x00;
136+
}
137+
break;
138+
}
139+
140+
slideCon.sck = new_sck;
141+
142+
if (scRegs[0x0A] & 0x80) //Reset
143+
{
144+
slideCon_reset();
145+
}
146+
}
147+
52148
public:
53149

54150
virtual Slot2Info const* info()
@@ -59,152 +155,34 @@ class Slot2_SlideController : public ISlot2Interface
59155

60156
virtual void connect()
61157
{
62-
prevClock = 0;
63-
bitsWritten = 0;
64-
bitsRead = 0;
65-
inByte = 0;
66-
regSel = 0xFFFF;
67-
68-
motionStatus = 0;
69-
xMotion = 0;
70-
yMotion = 0;
71-
configBits = 0;
72-
framePeriodLower = 0x20;
73-
framePeriodUpper = 0xD1;
158+
slideCon_reset();
74159
}
75160

76161
virtual void writeWord(u8 PROCNUM, u32 addr, u16 val)
77162
{
78163
if (addr == 0x081E0000)
79164
{
80-
if ((prevClock == 0) && (val & 0x2) && (val & 0x8))
81-
{
82-
SC_BITIN(inByte, val);
83-
if (bitsWritten == 8)
84-
{
85-
bitsWritten = 0;
86-
if (regSel == 0xFFFF) //First byte written
87-
{
88-
regSel = inByte;
89-
}
90-
else //Second byte written
91-
{
92-
//printf("WRITE TO REG: %02X = %02X\n", regSel & 0x7F , inByte);
93-
switch (regSel & 0x7F)
94-
{
95-
case 0x0A: //Config bits
96-
configBits = inByte;
97-
break;
98-
case 0x10: //Frame period (lower)
99-
framePeriodLower = inByte;
100-
break;
101-
case 0x11: //Frame period(upper)
102-
framePeriodUpper = inByte;
103-
break;
104-
}
105-
regSel = 0xFFFF;
106-
}
107-
}
108-
}
109-
prevClock = (val & 0x2) >> 1;
110-
}
111-
112-
if (configBits & 0x80) //Reset
113-
{
114-
motionStatus = 0;
115-
xMotion = 0;
116-
yMotion = 0;
117-
configBits = 0;
118-
framePeriodLower = 0x20;
119-
framePeriodUpper = 0xD1;
120-
121-
prevClock = 0;
122-
bitsWritten = 0;
123-
bitsRead = 0;
124-
inByte = 0;
125-
regSel = 0xFFFF;
165+
slideCon.in_data = val;
166+
slideCon_process();
126167
}
127168
}
128169

129170
virtual u8 readByte(u8 PROCNUM, u32 addr)
130171
{
131172
if (addr == 0x080000B2)
132-
{
133173
return 0x96;
134-
}
135-
return 0xFF;
174+
else
175+
return 0xFF;
136176
}
137177

138178
virtual u16 readWord(u8 PROCNUM, u32 addr)
139179
{
140-
u16 outWord = 0;
180+
u16 outWord = 0xFFFF;
141181

142182
if (addr < 0x08000100)
143-
{
144183
outWord = 0xFEF0;
145-
}
146-
147-
if (addr == 0x081E0000)
148-
{
149-
switch (regSel)
150-
{
151-
case 0x00: //Product ID
152-
SC_BITOUT(outWord, 0x3);
153-
break;
154-
case 0x01: //Revision ID
155-
SC_BITOUT(outWord, 0x20); //Is this correct?
156-
break;
157-
case 0x02: //Motion status
158-
SC_BITOUT(outWord, motionStatus);
159-
if (bitsRead == 8) motionStatus = 0;
160-
break;
161-
case 0x03: //X motion delta
162-
SC_BITOUT(outWord, xMotion);
163-
if (bitsRead == 8) xMotion = 0;
164-
break;
165-
case 0x04: //Y motion delta
166-
SC_BITOUT(outWord, yMotion);
167-
if (bitsRead == 8) yMotion = 0;
168-
break;
169-
case 0x05: //Surface quality
170-
SC_BITOUT(outWord, 128);
171-
break;
172-
case 0x06: //Average pixel
173-
SC_BITOUT(outWord, 32);
174-
break;
175-
case 0x07: //Maximum pixel
176-
SC_BITOUT(outWord, 63);
177-
break;
178-
case 0x0A: //Configuration bits
179-
SC_BITOUT(outWord, configBits);
180-
break;
181-
case 0x0C: //Data out (lower)
182-
SC_BITOUT(outWord, 0);
183-
break;
184-
case 0x0D: //Data out (upper)
185-
SC_BITOUT(outWord, 0);
186-
break;
187-
case 0x0E: //Shutter value (lower)
188-
SC_BITOUT(outWord, 64);
189-
break;
190-
case 0x0F: //Shutter value (upper)
191-
SC_BITOUT(outWord, 0);
192-
break;
193-
case 0x10: //Frame period (lower)
194-
SC_BITOUT(outWord, framePeriodLower);
195-
break;
196-
case 0x11: //Frame period (upper)
197-
SC_BITOUT(outWord, framePeriodUpper);
198-
break;
199-
}
200-
201-
if (bitsRead == 8)
202-
{
203-
bitsRead = 0;
204-
//printf("READ FROM REG: %02X\n", regSel);
205-
regSel = 0xFFFF;
206-
}
207-
}
184+
else if (addr == 0x081E0000)
185+
outWord = slideCon.out_data;
208186

209187
return outWord;
210188
}
@@ -214,18 +192,15 @@ class Slot2_SlideController : public ISlot2Interface
214192
s32 version = 0;
215193
os.write_32LE(version);
216194

217-
os.write_u8(prevClock);
218-
os.write_u8(bitsWritten);
219-
os.write_u8(bitsRead);
220-
os.write_u8(inByte);
221-
os.write_16LE(regSel);
222-
223-
os.write_u8(configBits);
224-
os.write_u8(framePeriodLower);
225-
os.write_u8(framePeriodUpper);
226-
os.write_u8(motionStatus);
227-
os.write_u8(xMotion);
228-
os.write_u8(yMotion);
195+
for (int i = 0; i < 18; i++)
196+
os.write_u8(scRegs[i]);
197+
os.write_16LE(slideCon.in_data);
198+
os.write_16LE(slideCon.out_data);
199+
os.write_u8(slideCon.counter);
200+
os.write_u8(slideCon.state);
201+
os.write_u8(slideCon.sck);
202+
os.write_u8(slideCon.reg_sel);
203+
os.write_u8(slideCon.tmp);
229204
}
230205

231206
virtual void loadstate(EMUFILE& is)
@@ -234,18 +209,15 @@ class Slot2_SlideController : public ISlot2Interface
234209

235210
if (version == 0)
236211
{
237-
is.read_u8(prevClock);
238-
is.read_u8(bitsWritten);
239-
is.read_u8(bitsRead);
240-
is.read_u8(inByte);
241-
is.read_16LE(regSel);
242-
243-
is.read_u8(configBits);
244-
is.read_u8(framePeriodLower);
245-
is.read_u8(framePeriodUpper);
246-
is.read_u8(motionStatus);
247-
is.read_u8(xMotion);
248-
is.read_u8(yMotion);
212+
for (int i = 0; i < 18; i++)
213+
is.read_u8(scRegs[i]);
214+
is.read_16LE(slideCon.in_data);
215+
is.read_16LE(slideCon.out_data);
216+
is.read_u8(slideCon.counter);
217+
is.read_u8(slideCon.state);
218+
is.read_u8(slideCon.sck);
219+
is.read_u8(slideCon.reg_sel);
220+
is.read_u8(slideCon.tmp);
249221
}
250222
}
251223
};
@@ -254,11 +226,8 @@ ISlot2Interface* construct_Slot2_SlideController() { return new Slot2_SlideContr
254226

255227
void slideController_updateMotion(s8 x, s8 y)
256228
{
257-
xMotion = (u8)x;
258-
yMotion = (u8)y;
259-
if (xMotion || yMotion)
260-
motionStatus = 0x80;
229+
scRegs[0x03] = (u8)x;
230+
scRegs[0x04] = (u8)y;
231+
if (scRegs[0x03] || scRegs[0x04])
232+
scRegs[0x02] |= 0x80;
261233
}
262-
263-
#undef SC_BITIN
264-
#undef SC_BITOUT

0 commit comments

Comments
 (0)