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