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
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
4033class Slot2_SlideController : public ISlot2Interface
4134{
4235private:
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+
52148public:
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
255227void 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