1 /*
2 * Simulator of microcontrollers (s51.src/mdu.cc)
3 *
4 * Copyright (C) 2016,16 Drotos Daniel, Talker Bt.
5 *
6 * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
7 *
8 */
9
10 /* This file is part of microcontroller simulator: ucsim.
11
12 UCSIM is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 UCSIM is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with UCSIM; see the file COPYING. If not, write to the Free
24 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 02111-1307, USA. */
26 /*@1@*/
27
28 #include "uc51cl.h"
29
30 #include "mducl.h"
31
cl_mdu(class cl_uc * auc,int aid)32 cl_mdu::cl_mdu(class cl_uc *auc, int aid):
33 cl_hw(auc, HW_CALC, aid, "mdu")
34 {
35 }
36
37 void
op_32udiv16(void)38 cl_mdu::op_32udiv16(void)
39 {
40 u32_t dend= v[3]*256*256*256 + v[2]*256*256 + v[1]*256 + v[0];
41 u16_t dor= v[5]*256 + v[4];
42 u32_t quo= 0;
43 u16_t rem= 0;
44 if (dor == 0)
45 set_ovr(true);
46 else
47 {
48 quo= dend / dor;
49 rem= dend % dor;
50 set_ovr(false);
51 //printf("\nSIM %u/%u=%u,%u %x,%x\n", dend, dor, quo, rem, quo, rem);
52 }
53 regs[0]->set(quo & 0xff);
54 regs[1]->set((quo>>8) & 0xff);
55 regs[2]->set((quo>>16) & 0xff);
56 regs[3]->set((quo>>24) & 0xff);
57 regs[4]->set(rem & 0xff);
58 regs[5]->set((rem>>8) & 0xff);
59 /*{
60 int j;
61 for (j=0;j<6;j++)
62 {
63 printf(" REG[%d]=%02x/%02x %p\n",j,regs[j]->get(),sfr->get(0xe9+j), regs[j]);
64 }
65 }*/
66 }
67
68 void
op_16udiv16(void)69 cl_mdu::op_16udiv16(void)
70 {
71 // 16/16
72 u16_t dend= v[1]*256 + v[0];
73 u16_t dor= v[5]*256 + v[4];
74 u16_t quo= 0;
75 u16_t rem= 0;
76 if (dor == 0)
77 set_ovr(true);
78 else
79 {
80 quo= dend / dor;
81 rem= dend % dor;
82 set_ovr(false);
83 }
84 regs[0]->set(quo & 0xff);
85 regs[1]->set((quo>>8) & 0xff);
86 regs[4]->set(rem & 0xff);
87 regs[5]->set((rem>>8) & 0xff);
88 }
89
90 void
op_16umul16(void)91 cl_mdu::op_16umul16(void)
92 {
93 u16_t mand= v[1]*256 + v[0];
94 u16_t mor= v[5]*256 + v[4];
95 u32_t pr= mand * mor;
96 regs[0]->set(pr & 0xff);
97 regs[1]->set((pr>>8) & 0xff);
98 regs[2]->set((pr>>16) & 0xff);
99 regs[3]->set((pr>>24) & 0xff);
100 if (pr > 0xffff)
101 set_ovr(true);
102 else
103 set_ovr(false);
104 regs[4]->set(v[4]); // behavior of xc88x
105 regs[5]->set(v[5]);
106 }
107
108 void
op_norm(void)109 cl_mdu::op_norm(void)
110 {
111 u32_t d;
112
113 d= v[3]*256*256*256 + v[2]*256*256 + v[1]*256 + v[0];
114 if (d == 0)
115 set_steps(0);
116 else if (d & 0x80000000)
117 set_ovr(true);
118 else
119 {
120 int i;
121 for (i= 0; (d&0x80000000)==0; i++)
122 d<<= 1;
123 set_steps(i);
124 //printf("NORM d=%x i=%d\n", d, i);
125 }
126 regs[0]->set(d & 0xff);
127 regs[1]->set((d>>8) & 0xff);
128 regs[2]->set((d>>16) & 0xff);
129 regs[3]->set((d>>24) & 0xff);
130 }
131
132 /* Logical shift */
133
134 void
op_lshift(void)135 cl_mdu::op_lshift(void)
136 {
137 u32_t d;
138
139 d= v[3]*256*256*256 + v[2]*256*256 + v[1]*256 + v[0];
140 if (dir_right())
141 d<<= get_steps();
142 else
143 d>>= get_steps();
144 regs[0]->set(d & 0xff);
145 regs[1]->set((d>>8) & 0xff);
146 regs[2]->set((d>>16) & 0xff);
147 regs[3]->set((d>>24) & 0xff);
148 }
149
150
151 /* 517
152 */
153
cl_mdu517(class cl_uc * auc,int aid)154 cl_mdu517::cl_mdu517(class cl_uc *auc, int aid):
155 cl_mdu(auc, aid)
156 {
157 }
158
159 int
init(void)160 cl_mdu517::init(void)
161 {
162 int i;
163 class cl_51core *u= (cl_51core*)uc;
164
165 cl_hw::init();
166
167 con= register_cell(u->sfr, 0xef);
168 for (i= 0; i<6; i++)
169 {
170 regs[i]= register_cell(u->sfr, 0xe9+i);
171 v[i]= regs[i]->get();
172 }
173 nuof_writes= 0;
174 writes= 0xffffffffffffULL;
175 //calcing= 0;
176 return 0;
177 }
178
179 t_mem
read(class cl_memory_cell * cell)180 cl_mdu517::read(class cl_memory_cell *cell)
181 {
182 cl_address_space *sfr= ((cl_51core*)uc)->sfr;
183 t_addr a;
184 t_mem v= cell->get();
185
186 if (conf(cell, NULL))
187 return v;
188 if (cell == con)
189 cell->set(v&= ~0x80);
190 else if (sfr->is_owned(cell, &a))
191 {
192 a-= 0xe9;
193 if ((a < 0) ||
194 (a > 5))
195 return v;
196 }
197 return v;
198 }
199
200 void
write(class cl_memory_cell * cell,t_mem * val)201 cl_mdu517::write(class cl_memory_cell *cell, t_mem *val)
202 {
203 cl_address_space *sfr= ((cl_51core*)uc)->sfr;
204 t_addr a;
205 u8_t ar= con->get() & ~0x80;
206
207 if (conf(cell, val))
208 return;
209
210 if (sfr->is_owned(cell, &a))
211 {
212 // if (a==0xee) printf(" WRITE EE %02x\n", *val);
213 a-= 0xe9;
214 if ((a < 0) ||
215 (a > 6))
216 {
217 return;
218 }
219 /*if (calcing)
220 {
221 regs[6]->set(ar | 0x80);
222 return;
223 }*/
224 if (a == 0)
225 {
226 writes= 0xffffffffffffULL;
227 nuof_writes= 0;
228 set_err(false);
229 }
230 if (nuof_writes > 5)
231 {
232 set_err(true);
233 return;
234 }
235 writes&= ~(0xffL << (nuof_writes*8));
236 writes|= ((u64_t)a << (nuof_writes*8));
237 if (a == 6)
238 {
239 writes= 0xff0603020100ULL; // force norm/shift
240 con->set(ar= *val & 0x7f);
241 set_err(false);
242 }
243 else
244 {
245 v[a]= *val;
246 nuof_writes++;
247 }
248
249 switch (writes)
250 {
251 // 665544332211
252 case 0x050403020100ULL:
253 {
254 // 32/16
255 op_32udiv16();
256 //calcing= 6;
257 writes= 0xffffffffffffULL;
258 nuof_writes= 0;
259 break;
260 }
261 // 665544332211
262 case 0xffff05040100ULL:
263 {
264 op_16udiv16();
265 //calcing= 6;
266 writes= 0xffffffffffffULL;
267 nuof_writes= 0;
268 break;
269 }
270 // 665544332211
271 case 0xffff05010400ULL:
272 {
273 // 16*16
274 op_16umul16();
275 writes= 0xffffffffffffULL;
276 nuof_writes= 0;
277 break;
278 }
279 // 665544332211
280 case 0xff0603020100ULL:
281 {
282 // norm, shift
283 if ((ar & 0x1f) == 0)
284 op_norm();
285 else
286 op_lshift();
287 writes= 0xffffffffffffULL;
288 nuof_writes= 0;
289 break;
290 }
291 default:
292 if (nuof_writes > 5)
293 {
294 set_err(true);
295 writes= 0xffffffffffffULL;
296 nuof_writes= 0;
297 }
298 break;
299 }
300 if (a < 6)
301 *val= regs[a]->get();
302 else if (cell == con)
303 *val= con->get();
304 }
305 }
306
307 bool
dir_right(void)308 cl_mdu517::dir_right(void)
309 {
310 return (con->get() & 0x20) != 0;
311 }
312
313 void
set_steps(int steps)314 cl_mdu517::set_steps(int steps)
315 {
316 t_mem val= con->get();
317 val&= ~0x1f;
318 steps&= 0x1f;
319 con->set(val | steps);
320 }
321
322 int
get_steps(void)323 cl_mdu517::get_steps(void)
324 {
325 return con->get() & 0x1f;
326 }
327
328 void
set_ovr(bool val)329 cl_mdu517::set_ovr(bool val)
330 {
331 if (val)
332 con->set_bit1(0x40);
333 else
334 con->set_bit0(0x40);
335 }
336
337 void
set_err(bool val)338 cl_mdu517::set_err(bool val)
339 {
340 if (val)
341 con->set_bit1(0x80);
342 else
343 con->set_bit0(0x80);
344 }
345
346 t_mem
conf_op(cl_memory_cell * cell,t_addr addr,t_mem * val)347 cl_mdu517::conf_op(cl_memory_cell *cell, t_addr addr, t_mem *val)
348 {
349 return cell->get();
350 }
351
352 /* XC88X
353 */
354
cl_mdu88x(class cl_uc * auc,int aid)355 cl_mdu88x::cl_mdu88x(class cl_uc *auc, int aid):
356 cl_mdu(auc, aid)
357 {
358 }
359
360 int
init(void)361 cl_mdu88x::init(void)
362 {
363 int i;
364 class cl_51core *u= (cl_51core*)uc;
365
366 cl_hw::init();
367
368 stat= register_cell(u->sfr, 0xb0);
369 con= register_cell(u->sfr, 0xb1);
370 for (i= 0; i<6; i++)
371 {
372 regs[i]= register_cell(u->sfr, 0xb2+i);
373 v[i]= regs[i]->get();
374 }
375 //calcing= 0;
376 return 0;
377 }
378
379 t_mem
read(class cl_memory_cell * cell)380 cl_mdu88x::read(class cl_memory_cell *cell)
381 {
382 cl_address_space *sfr= ((cl_51core*)uc)->sfr;
383 t_addr a;
384 t_mem val= cell->get();
385
386 if (conf(cell, NULL))
387 return val;
388 if (cell == stat)
389 {}
390 else if (cell == con)
391 {}
392 else if (sfr->is_owned(cell, &a))
393 {
394 a-= 0xb2;
395 if ((a < 0) ||
396 (a > 5))
397 {
398 if (con->get() & 0x20)
399 val= regs[a]->get();
400 else
401 val= v[a];
402 }
403 }
404 return val;
405 }
406
407 void
write(class cl_memory_cell * cell,t_mem * val)408 cl_mdu88x::write(class cl_memory_cell *cell, t_mem *val)
409 {
410 cl_address_space *sfr= ((cl_51core*)uc)->sfr;
411 t_addr a;
412
413 if (conf(cell, val))
414 return;
415
416 if (cell == stat)
417 {}
418 else if (cell == con)
419 {
420 if (((con->get() & 0x10) == 0) &&
421 (*val & 0x10))
422 {
423 // START
424 if (busy())
425 // skip when already BUSY
426 return;
427 con->set(*val&= ~0x10);
428 set_bsy(true);
429 switch (*val & 0x0f)
430 {
431 case 0:
432 op_16umul16();
433 ticks= 16 / uc->clock_per_cycle();
434 break;
435 case 1:
436 op_16udiv16();
437 ticks= 16 / uc->clock_per_cycle();
438 break;
439 case 2:
440 op_32udiv16();
441 ticks= 32 / uc->clock_per_cycle();
442 break;
443 case 3:
444 ticks= (get_steps()+1) / uc->clock_per_cycle();
445 op_lshift();
446 break;
447 case 4:
448 op_16smul16();
449 ticks= 16 / uc->clock_per_cycle();
450 break;
451 case 5:
452 op_16sdiv16();
453 ticks= 16 / uc->clock_per_cycle();
454 break;
455 case 6:
456 op_32sdiv16();
457 ticks= 32 / uc->clock_per_cycle();
458 break;
459 case 7:
460 ticks= (get_steps()+1) / uc->clock_per_cycle();
461 op_ashift();
462 break;
463 case 8:
464 op_norm();
465 ticks= (get_steps()+1) / uc->clock_per_cycle();
466 break;
467 default:
468 {
469 // ERROR, unknown opcode
470 set_bsy(false);
471 set_err(true);
472 }
473 }
474 }
475 }
476 else if (sfr->is_owned(cell, &a))
477 {
478 a-= 0xb2;
479 if ((a < 0) ||
480 (a > 5))
481 return;
482 /*if (calcing)
483 {
484 regs[6]->set(ar | 0x80);
485 return;
486 }*/
487 v[a]= *val;
488 if (cell == stat)
489 *val= stat->get();
490 else if (cell == con)
491 *val= con->get();
492 else if (a < 6)
493 *val= regs[a]->get();
494 }
495 }
496
497 int
tick(int cycles)498 cl_mdu88x::tick(int cycles)
499 {
500 if (busy())
501 {
502 ticks-= cycles;
503 if (ticks < 0)
504 ticks= 0;
505 set_bsy(false);
506 }
507 return 0;
508 }
509
510
511 void
op_32sdiv16(void)512 cl_mdu88x::op_32sdiv16(void)
513 {
514 i32_t dend= v[3]*256*256*256 + v[2]*256*256 + v[1]*256 + v[0];
515 i16_t dor= v[5]*256 + v[4];
516 i32_t quo= 0;
517 i16_t rem= 0;
518 if (dor == 0)
519 set_ovr(true);
520 else
521 {
522 quo= dend / dor;
523 rem= dend % dor;
524 set_ovr(false);
525 //printf("\nSIM %d/%d=%d,%d %x,%x\n", dend, dor, quo, rem, quo, rem);
526 }
527 regs[0]->set(quo & 0xff);
528 regs[1]->set((quo>>8) & 0xff);
529 regs[2]->set((quo>>16) & 0xff);
530 regs[3]->set((quo>>24) & 0xff);
531 regs[4]->set(rem & 0xff);
532 regs[5]->set((rem>>8) & 0xff);
533 /*{
534 int j;
535 for (j=0;j<6;j++)
536 {
537 printf(" REG[%d]=%02x/%02x %p\n",j,regs[j]->get(),sfr->get(0xe9+j), regs[j]);
538 }
539 }*/
540 }
541
542 void
op_16sdiv16(void)543 cl_mdu88x::op_16sdiv16(void)
544 {
545 // 16/16
546 i16_t dend= v[1]*256 + v[0];
547 i16_t dor= v[5]*256 + v[4];
548 i16_t quo= 0;
549 i16_t rem= 0;
550 if (dor == 0)
551 set_ovr(true);
552 else
553 {
554 quo= dend / dor;
555 rem= dend % dor;
556 set_ovr(false);
557 }
558 regs[0]->set(quo & 0xff);
559 regs[1]->set((quo>>8) & 0xff);
560 regs[4]->set(rem & 0xff);
561 regs[5]->set((rem>>8) & 0xff);
562 }
563
564 void
op_16smul16(void)565 cl_mdu88x::op_16smul16(void)
566 {
567 i16_t mand= v[1]*256 + v[0];
568 i16_t mor= v[5]*256 + v[4];
569 i32_t pr= mand * mor;
570 regs[0]->set(pr & 0xff);
571 regs[1]->set((pr>>8) & 0xff);
572 regs[2]->set((pr>>16) & 0xff);
573 regs[3]->set((pr>>24) & 0xff);
574 if (pr > 0xffff)
575 set_ovr(true);
576 else
577 set_ovr(false);
578 regs[4]->set(v[4]); // behavior of xc88x
579 regs[5]->set(v[5]);
580 }
581
582 /* Arithmetic shift */
583
584 void
op_ashift(void)585 cl_mdu88x::op_ashift(void)
586 {
587 i32_t d;
588
589 d= v[3]*256*256*256 + v[2]*256*256 + v[1]*256 + v[0];
590 if (dir_right())
591 d<<= get_steps();
592 else
593 d>>= get_steps();
594 regs[0]->set(d & 0xff);
595 regs[1]->set((d>>8) & 0xff);
596 regs[2]->set((d>>16) & 0xff);
597 regs[3]->set((d>>24) & 0xff);
598 }
599
600
601 bool
dir_right(void)602 cl_mdu88x::dir_right(void)
603 {
604 return (v[4] & 0x20) != 0;
605 }
606
607 void
set_steps(int steps)608 cl_mdu88x::set_steps(int steps)
609 {
610 regs[4]->set(steps & 0x1f);
611 }
612
613 int
get_steps(void)614 cl_mdu88x::get_steps(void)
615 {
616 return v[4] & 0x1f;
617 }
618
619 void
set_ovr(bool val)620 cl_mdu88x::set_ovr(bool val)
621 {
622 }
623
624 void
set_err(bool val)625 cl_mdu88x::set_err(bool val)
626 {
627 if (val)
628 stat->set_bit1(0x02);
629 else
630 stat->set_bit0(0x02);
631 }
632
633 void
set_bsy(bool val)634 cl_mdu88x::set_bsy(bool val)
635 {
636 if (val)
637 stat->set_bit1(0x04);
638 else
639 stat->set_bit0(0x04);
640 }
641
642 bool
busy(void)643 cl_mdu88x::busy(void)
644 {
645 return (stat->get() & 0x04) != 0;
646 }
647
648
649 t_mem
conf_op(cl_memory_cell * cell,t_addr addr,t_mem * val)650 cl_mdu88x::conf_op(cl_memory_cell *cell, t_addr addr, t_mem *val)
651 {
652 return cell->get();
653 }
654
655
656 /* End of s51.src/mdu.cc */
657