2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 void W3100A::initialize()
15 idm_or = idm_ar0 = idm_ar1 = 0;
16 memset(regs, 0, sizeof(regs));
17 memset(cx_rw_pr, 0, sizeof(cx_rw_pr));
18 memset(cx_rr_pr, 0, sizeof(cx_rr_pr));
19 memset(cx_ta_pr, 0, sizeof(cx_ta_pr));
20 memset(cx_tw_pr, 0, sizeof(cx_tw_pr));
21 memset(cx_tr_pr, 0, sizeof(cx_tr_pr));
24 #define GET_ADDR() { \
26 raddr = idm_ar0 | (idm_ar1 << 8); \
28 raddr = (idm_ar0 << 8) | idm_ar1; \
32 #define INC_ADDR() { \
35 idm_ar0 = (idm_or & 2) ? (raddr & 0xff) : (raddr >> 8); \
36 idm_ar1 = (idm_or & 2) ? (raddr >> 8) : (raddr & 0xff); \
40 void W3100A::write_io8(uint32_t addr, uint32_t data)
57 process_cmd(raddr, data);
63 uint32_t W3100A::read_io8(uint32_t addr)
72 process_status(raddr);
79 void W3100A::process_cmd(uint16_t raddr, uint8_t data)
81 uint16_t bufsz[4] = { 1024, 2048, 4096, 8192 };
86 // sys init (ch.0 only)
88 regs[4] = 1; // always success
96 uint8_t mode = regs[0xa1 + 24 * ch] & 7;
98 emu->disconnect_socket(ch);
100 bool result = false, connect = false;
101 regs[0xa0 + 24 * ch] = 0; // SOCK_CLOSE
103 result = connect = emu->initialize_socket_tcp(ch);
105 } else if(mode == 2) {
106 result = connect = emu->initialize_socket_udp(ch);
108 regs[0xa0 + 24 * ch] = 0xf; // SOCK_UDP
112 regs[4 + ch] &= ~(2 | 4 | 8);
113 regs[4 + ch] |= (result ? 2 : 0) | (connect ? 0 : 8);
114 // patch to force buffer is empty
115 cx_ta_pr[ch] = cx_tr_pr[ch] = cx_tw_pr[ch];
116 cx_rw_pr[ch] = cx_rr_pr[ch] = 0;
121 regs[0xa0 + 24 * ch] = 3; // SOCK_SYNSENT
122 uint32_t ipaddr = regs[0xa8 + 24 * ch];
123 ipaddr |= regs[0xa9 + 24 * ch] << 8;
124 ipaddr |= regs[0xaa + 24 * ch] << 16;
125 ipaddr |= regs[0xab + 24 * ch] << 24;
126 int port = (regs[0xac + 24 * ch] << 8) | regs[0xad + 24 * ch];
127 if(!emu->connect_socket(ch, ipaddr, port)) {
128 regs[4 + ch] &= ~4; // established = false
129 regs[4 + ch] |= 8; // closed = true
130 regs[0xa0 + 24 * ch] = 0; // SOCK_CLOSED
135 regs[0xa0 + 24 * ch] = 2; // SOCK_LISTEN
136 if(!emu->listen_socket(ch)) {
137 regs[4 + ch] &= ~4; // established = false
138 regs[4 + ch] |= 8; // closed = true
139 regs[0xa0 + 24 * ch] = 0; // SOCK_CLOSED
144 emu->disconnect_socket(ch);
148 send_dst_ptr[ch] = cx_tw_pr[ch];
149 uint32_t rd_ptr = is_tcp[ch] ? cx_ta_pr[ch] : cx_tr_pr[ch];
150 if(rd_ptr != send_dst_ptr[ch]) {
151 regs[ch + 4] &= ~0x20;
153 emu->send_socket_data_tcp(ch);
155 uint32_t ipaddr = regs[0xa8 + 24 * ch];
156 ipaddr |= regs[0xa9 + 24 * ch] << 8;
157 ipaddr |= regs[0xaa + 24 * ch] << 16;
158 ipaddr |= regs[0xab + 24 * ch] << 24;
159 int port = (regs[0xac + 24 * ch] << 8) | regs[0xad + 24 * ch];
160 emu->send_socket_data_udp(ch, ipaddr, port);
163 regs[ch + 4] |= 0x20; // send ok
168 recv_dst_ptr[ch] = cx_rr_pr[ch];
169 regs[ch + 4] &= ~0x40; // recv ok
172 case 0x10: case 0x11: case 0x12: case 0x13: ch = 0; goto lbl_cx_rw_pr;
173 case 0x1c: case 0x1d: case 0x1e: case 0x1f: ch = 1; goto lbl_cx_rw_pr;
174 case 0x28: case 0x29: case 0x2a: case 0x2b: ch = 2; goto lbl_cx_rw_pr;
175 case 0x34: case 0x35: case 0x36: case 0x37: ch = 3;
177 cx_rw_pr[ch] = regs[0x10 + 12 * ch] << 24;
178 cx_rw_pr[ch] |= regs[0x11 + 12 * ch] << 16;
179 cx_rw_pr[ch] |= regs[0x12 + 12 * ch] << 8;
180 cx_rw_pr[ch] |= regs[0x13 + 12 * ch] << 0;
182 case 0x14: case 0x15: case 0x16: case 0x17: ch = 0; goto lbl_cx_rr_pr;
183 case 0x20: case 0x21: case 0x22: case 0x23: ch = 1; goto lbl_cx_rr_pr;
184 case 0x2c: case 0x2d: case 0x2e: case 0x2f: ch = 2; goto lbl_cx_rr_pr;
185 case 0x38: case 0x39: case 0x3a: case 0x3b: ch = 3;
187 cx_rr_pr[ch] = regs[0x14 + 12 * ch] << 24;
188 cx_rr_pr[ch] |= regs[0x15 + 12 * ch] << 16;
189 cx_rr_pr[ch] |= regs[0x16 + 12 * ch] << 8;
190 cx_rr_pr[ch] |= regs[0x17 + 12 * ch] << 0;
192 case 0x18: case 0x19: case 0x1a: case 0x1b: ch = 0; goto lbl_cx_ta_pr;
193 case 0x24: case 0x25: case 0x26: case 0x27: ch = 1; goto lbl_cx_ta_pr;
194 case 0x30: case 0x31: case 0x32: case 0x33: ch = 2; goto lbl_cx_ta_pr;
195 case 0x3c: case 0x3d: case 0x3e: case 0x3f: ch = 3;
197 cx_ta_pr[ch] = regs[0x18 + 12 * ch] << 24;
198 cx_ta_pr[ch] |= regs[0x19 + 12 * ch] << 16;
199 cx_ta_pr[ch] |= regs[0x1a + 12 * ch] << 8;
200 cx_ta_pr[ch] |= regs[0x1b + 12 * ch] << 0;
202 case 0x40: case 0x41: case 0x42: case 0x43: ch = 0; goto lbl_cx_tw_pr;
203 case 0x4c: case 0x4d: case 0x4e: case 0x4f: ch = 1; goto lbl_cx_tw_pr;
204 case 0x58: case 0x59: case 0x5a: case 0x5b: ch = 2; goto lbl_cx_tw_pr;
205 case 0x64: case 0x65: case 0x66: case 0x67: ch = 3;
207 cx_tw_pr[ch] = regs[0x40 + 12 * ch] << 24;
208 cx_tw_pr[ch] |= regs[0x41 + 12 * ch] << 16;
209 cx_tw_pr[ch] |= regs[0x42 + 12 * ch] << 8;
210 cx_tw_pr[ch] |= regs[0x43 + 12 * ch] << 0;
212 case 0x44: case 0x45: case 0x46: case 0x47: ch = 0; goto lbl_cx_tr_pr;
213 case 0x50: case 0x51: case 0x52: case 0x53: ch = 1; goto lbl_cx_tr_pr;
214 case 0x5c: case 0x5d: case 0x5e: case 0x5f: ch = 2; goto lbl_cx_tr_pr;
215 case 0x68: case 0x69: case 0x6a: case 0x6b: ch = 3;
217 cx_tr_pr[ch] = regs[0x44 + 12 * ch] << 24;
218 cx_tr_pr[ch] |= regs[0x45 + 12 * ch] << 16;
219 cx_tr_pr[ch] |= regs[0x46 + 12 * ch] << 8;
220 cx_tr_pr[ch] |= regs[0x47 + 12 * ch] << 0;
223 rx_bufsz[0] = bufsz[(data >> 0) & 3];
224 rx_bufsz[1] = bufsz[(data >> 2) & 3];
225 rx_bufsz[2] = bufsz[(data >> 4) & 3];
226 rx_bufsz[3] = bufsz[(data >> 6) & 3];
229 tx_bufsz[0] = bufsz[(data >> 0) & 3];
230 tx_bufsz[1] = bufsz[(data >> 2) & 3];
231 tx_bufsz[2] = bufsz[(data >> 4) & 3];
232 tx_bufsz[3] = bufsz[(data >> 6) & 3];
237 void W3100A::process_status(uint16_t raddr)
242 case 0x1e0: ch = 0; goto lbl_cx_srw_pr;
243 case 0x1e3: ch = 1; goto lbl_cx_srw_pr;
244 case 0x1e6: ch = 2; goto lbl_cx_srw_pr;
247 regs[0x10 + 12 * ch] = cx_rw_pr[ch] >> 24;
248 regs[0x11 + 12 * ch] = cx_rw_pr[ch] >> 16;
249 regs[0x12 + 12 * ch] = cx_rw_pr[ch] >> 8;
250 regs[0x13 + 12 * ch] = cx_rw_pr[ch] >> 0;
252 case 0x1e1: ch = 0; goto lbl_cx_srr_pr;
253 case 0x1e4: ch = 1; goto lbl_cx_srr_pr;
254 case 0x1e7: ch = 2; goto lbl_cx_srr_pr;
257 regs[0x14 + 12 * ch] = cx_rr_pr[ch] >> 24;
258 regs[0x15 + 12 * ch] = cx_rr_pr[ch] >> 16;
259 regs[0x16 + 12 * ch] = cx_rr_pr[ch] >> 8;
260 regs[0x17 + 12 * ch] = cx_rr_pr[ch] >> 0;
262 case 0x1e2: ch = 0; goto lbl_cx_sta_pr;
263 case 0x1e5: ch = 1; goto lbl_cx_sta_pr;
264 case 0x1e8: ch = 2; goto lbl_cx_sta_pr;
267 regs[0x18 + 12 * ch] = cx_ta_pr[ch] >> 24;
268 regs[0x19 + 12 * ch] = cx_ta_pr[ch] >> 16;
269 regs[0x1a + 12 * ch] = cx_ta_pr[ch] >> 8;
270 regs[0x1b + 12 * ch] = cx_ta_pr[ch] >> 0;
272 case 0x1f0: ch = 0; goto lbl_cx_stw_pr;
273 case 0x1f3: ch = 1; goto lbl_cx_stw_pr;
274 case 0x1f6: ch = 2; goto lbl_cx_stw_pr;
277 regs[0x40 + 12 * ch] = cx_tw_pr[ch] >> 24;
278 regs[0x41 + 12 * ch] = cx_tw_pr[ch] >> 16;
279 regs[0x42 + 12 * ch] = cx_tw_pr[ch] >> 8;
280 regs[0x43 + 12 * ch] = cx_tw_pr[ch] >> 0;
282 case 0x1f1: ch = 0; goto lbl_cx_str_pr;
283 case 0x1f4: ch = 1; goto lbl_cx_str_pr;
284 case 0x1f7: ch = 2; goto lbl_cx_str_pr;
287 regs[0x44 + 12 * ch] = cx_tr_pr[ch] >> 24;
288 regs[0x45 + 12 * ch] = cx_tr_pr[ch] >> 16;
289 regs[0x46 + 12 * ch] = cx_tr_pr[ch] >> 8;
290 regs[0x47 + 12 * ch] = cx_tr_pr[ch] >> 0;
295 void W3100A::notify_connected(int ch)
297 regs[4 + ch] |= 4; // established = true
298 regs[4 + ch] &= ~8; // closed = false
299 regs[0xa0 + 24 * ch] = 6; // SOCK_ESTABLISHED
302 void W3100A::notify_disconnected(int ch)
304 regs[4 + ch] &= ~4; // established = false
305 regs[4 + ch] |= 8; // closed = true
306 if(regs[ch] & 0x40) { // recv_ok = true
307 regs[4 + ch] |= 0x40;
309 regs[0xa0 + 24 * ch] = 0; // SOCK_CLOSED
312 uint8_t* W3100A::get_send_buffer(int ch, int* size)
314 uint32_t cx_ta_tr = is_tcp[ch] ? cx_ta_pr[ch] : cx_tr_pr[ch];
315 uint32_t rd_ptr = cx_ta_tr & (tx_bufsz[ch] - 1);
316 uint32_t wr_ptr = send_dst_ptr[ch] & (tx_bufsz[ch] - 1);
318 if(!(regs[ch] & 0x20)) {
320 } else if(rd_ptr == wr_ptr && cx_ta_tr != send_dst_ptr[ch]) {
322 } else if(rd_ptr <= wr_ptr) {
323 *size = wr_ptr - rd_ptr;
325 *size = tx_bufsz[ch] - rd_ptr;
327 uint32_t ofs = 0x4000;
328 for(int i = 0; i < ch; i++) {
331 return ®s[ofs + rd_ptr];
334 void W3100A::inc_send_buffer_ptr(int ch, int size)
337 cx_ta_pr[ch] += size;
338 if(cx_ta_pr[ch] == send_dst_ptr[ch]) {
339 regs[ch + 4] |= 0x20; // send ok
342 cx_tr_pr[ch] += size;
343 if(cx_tr_pr[ch] == send_dst_ptr[ch]) {
344 regs[ch + 4] |= 0x20; // send ok
349 uint8_t* W3100A::get_recv_buffer0(int ch, int* size0, int* size1)
351 uint32_t wr_ptr = cx_rw_pr[ch] & (rx_bufsz[ch] - 1);
352 uint32_t rr_ptr = recv_dst_ptr[ch] & (rx_bufsz[ch] - 1);
354 if(!(regs[ch] & 0x40)) {
356 } else if(rr_ptr == wr_ptr && cx_rw_pr[ch] != recv_dst_ptr[ch]) {
358 } else if(rr_ptr <= wr_ptr) {
359 *size0 = rx_bufsz[ch] - wr_ptr;
362 *size0 = rr_ptr - wr_ptr;
365 uint32_t ofs = 0x6000;
366 for(int i = 0; i < ch; i++) {
369 return ®s[ofs + wr_ptr];
372 uint8_t* W3100A::get_recv_buffer1(int ch)
374 uint32_t ofs = 0x6000;
375 for(int i = 0; i < ch; i++) {
381 void W3100A::inc_recv_buffer_ptr(int ch, int size)
383 // uint32_t wr_ptr = cx_rw_pr[ch];
384 // wr_ptr = (wr_ptr + size) & (rx_bufsz[ch] - 1);
385 // cx_rw_pr[ch] = (cx_rw_pr[ch] & ~(rx_bufsz[ch] - 1)) | wr_ptr;
386 cx_rw_pr[ch] += size;
387 // regs[ch + 4] |= 0x40; // recv ok
390 #define STATE_VERSION 1
392 bool W3100A::process_state(FILEIO* state_fio, bool loading)
394 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
397 if(!state_fio->StateCheckInt32(this_device_id)) {
400 state_fio->StateValue(idm_or);
401 state_fio->StateValue(idm_ar0);
402 state_fio->StateValue(idm_ar1);
403 state_fio->StateArray(regs, sizeof(regs), 1);
404 state_fio->StateArray(is_tcp, sizeof(is_tcp), 1);
405 state_fio->StateArray(rx_bufsz, sizeof(rx_bufsz), 1);
406 state_fio->StateArray(tx_bufsz, sizeof(tx_bufsz), 1);
407 state_fio->StateArray(cx_rw_pr, sizeof(cx_rw_pr), 1);
408 state_fio->StateArray(cx_rr_pr, sizeof(cx_rr_pr), 1);
409 state_fio->StateArray(cx_ta_pr, sizeof(cx_ta_pr), 1);
410 state_fio->StateArray(cx_tw_pr, sizeof(cx_tw_pr), 1);
411 state_fio->StateArray(cx_tr_pr, sizeof(cx_tr_pr), 1);
412 state_fio->StateArray(send_dst_ptr, sizeof(send_dst_ptr), 1);
413 state_fio->StateArray(recv_dst_ptr, sizeof(recv_dst_ptr), 1);