[ucsim-z80] Fix #3828: uCsim SM83 flags simulation
[sdcc.git] / sdcc / sim / ucsim / src / sims / p1516.src / p1516.cc
blob14d6a41b120d07b51b75a3928e1df77dfb8c1330
1 /*
2 * Simulator of microcontrollers (p1516.cc)
4 * Copyright (C) 2020 Drotos Daniel
5 *
6 * To contact author send email to dr.dkdb@gmail.com
8 */
10 /* This file is part of microcontroller simulator: ucsim.
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.
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.
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@*/
28 #include <stdlib.h>
30 #include "dregcl.h"
32 #include "glob.h"
33 #include "portcl.h"
34 #include "uartcl.h"
35 #include "clockcl.h"
36 #include "timercl.h"
37 #include "fpgacl.h"
38 #include "brd_ctrlcl.h"
40 #include "p1516cl.h"
43 cl_pc_write::cl_pc_write(class cl_memory_cell *acell, class cl_uc *the_uc):
44 cl_memory_operator(acell)
46 uc= the_uc;
49 t_mem
50 cl_pc_write::write(t_mem val)
52 uc->set_PC(val);
53 return uc->PC;
57 cl_p1516::cl_p1516(class cl_sim *asim):
58 cl_uc(asim)
60 PCmask= 0xffffffff;
61 r2b_state= r2b_none;
64 int
65 cl_p1516::init(void)
67 int i;
68 cl_uc::init();
69 for (i=0; i<16; i++)
70 R[i]= 0;
71 reg_cell_var(&cF, &F, "F", "Flag register");
72 class cl_pc_write *pcw= new cl_pc_write(&cPC, this);
73 pcw->init();
74 cPC.append_operator(pcw);
75 return 0;
78 const char *
79 cl_p1516::id_string(void)
81 return "P1516";
84 void
85 cl_p1516::reset(void)
87 cl_uc::reset();
89 PC= R[15]= 0;
90 F= 0;//F&= ~(U|P);
93 void
94 cl_p1516::set_PC(t_addr addr)
96 PC= R[15]= addr;
99 void
100 cl_p1516::mk_hw_elements(void)
102 class cl_hw *h;
103 cl_uc::mk_hw_elements();
105 add_hw(h= new cl_dreg(this, 0, "dreg"));
106 h->init();
108 add_hw(pa= new cl_porto(this, 0xff00, "pa"));
109 pa->init();
110 add_hw(pb= new cl_porto(this, 0xff01, "pb"));
111 pb->init();
112 add_hw(pc= new cl_porto(this, 0xff02, "pc"));
113 pc->init();
114 add_hw(pd= new cl_porto(this, 0xff03, "pd"));
115 pd->init();
117 add_hw(pi= new cl_porti(this, 0xff20, "pi"));
118 pi->init();
119 add_hw(pj= new cl_porti(this, 0xff10, "pj"));
120 pj->init();
122 add_hw(h= new cl_timer(this, 0xff30, "timer"));
123 h->init();
125 add_hw(h= new cl_uart(this, 0, 0xff40));
126 h->init();
128 add_hw(h= new cl_clock(this, 0xff50, "clock"));
129 h->init();
131 class cl_port_ui *u= new cl_port_ui(this, 0, "dport");
132 u->init();
133 add_hw(u);
134 class cl_port_ui *uo= new cl_port_ui(this, 0, "oports");
135 uo->init();
136 add_hw(uo);
137 class cl_port_ui *ui= new cl_port_ui(this, 0, "iports");
138 ui->init();
139 add_hw(ui);
141 class cl_port_data d;
142 d.init();
143 d.cell_dir= NULL;
144 d.width= 32;
146 d.set_name("PA");
147 d.cell_p = pa->dr;
148 d.cell_in= pa->dr;
149 d.keyset = NULL;
150 d.basx = 15;
151 d.basy = 4;
152 u->add_port(&d, 0);
153 uo->add_port(&d, 0);
155 d.set_name("PB");
156 d.cell_p = pb->dr;
157 d.cell_in= pb->dr;
158 d.keyset = NULL;
159 d.basx = 15;
160 d.basy = 9;
161 u->add_port(&d, 1);
162 uo->add_port(&d, 1);
164 d.set_name("PC");
165 d.cell_p = pc->dr;
166 d.cell_in= pc->dr;
167 d.keyset = NULL;
168 d.basx = 15;
169 d.basy = 14;
170 u->add_port(&d, 2);
171 uo->add_port(&d, 2);
173 d.set_name("PD");
174 d.cell_p = pd->dr;
175 d.cell_in= pd->dr;
176 d.keyset = NULL;
177 d.basx = 15;
178 d.basy = 19;
179 u->add_port(&d, 3);
180 uo->add_port(&d, 3);
182 d.set_name("PI");
183 d.cell_p = pi->dr;
184 d.cell_in= pi->cfg_cell(port_pin);
185 d.keyset = chars(" qwertyui12345678");
186 d.basx = 15;
187 d.basy = 24;
188 u->add_port(&d, 4);
189 d.basy = 4;
190 ui->add_port(&d, 0);
192 d.set_name("PJ");
193 d.cell_p = pj->dr;
194 d.cell_in= pj->cfg_cell(port_pin);
195 d.keyset = chars(" asdfghjkzxcvbnm,");
196 d.basx = 15;
197 d.basy = 29;
198 u->add_port(&d, 5);
199 d.basy = 10;
200 ui->add_port(&d, 1);
202 add_hw(h= new cl_n4(this, 0, "n4ddr"));
203 h->init();
204 add_hw(h= new cl_bool(this, 0, "boolean"));
205 h->init();
206 add_hw(h= new cl_logsys(this, 0, "logsys"));
207 h->init();
209 add_hw(bc= new cl_brd_ctrl(this, 0, "brd_ctrl"));
210 h->init();
213 void
214 cl_p1516::make_memories(void)
216 class cl_address_space *as;
217 int i;
219 //double st= dnow();
220 rom= as= new cl_address_space("rom"/*MEM_ROM_ID*/, 0, 0x20000, 32);
221 as->init();
222 //printf("%f\n", dnow()-st);
223 address_spaces->add(as);
225 class cl_address_decoder *ad;
226 class cl_memory_chip *chip;
228 chip= new cl_chip32("rom_chip", 0x20000, 32, 0);
229 chip->init();
230 memchips->add(chip);
231 rom_chip= chip;
232 ad= new cl_address_decoder(as= rom, chip, 0, /*0xfeff*/0x1ffff, 0);
233 ad->init();
234 as->decoders->add(ad);
235 ad->activate(0);
236 /*ad= new cl_address_decoder(as= rom, chip, 0x10000, 0x1ffff, 0x10000);
237 ad->init();
238 as->decoders->add(ad);
239 ad->activate(0);*/
241 regs= new cl_address_space("regs", 0, 16, 32);
242 regs->init();
243 for (i= 0; i<16; i++)
245 RC[i]= regs->get_cell(i);
246 RC[i]->decode((t_mem*)&R[i]);
248 address_spaces->add(regs);
250 chars n, d;
251 for (i=0; i<16; i++)
253 n.format("R%d", i);
254 d.format("CPU register %d", i);
255 vars->add(n, regs, i, d);
260 struct dis_entry *
261 cl_p1516::dis_tbl(void)
263 return(disass_p1516);
266 char *
267 cl_p1516::disassc(t_addr addr, chars *comment)
269 chars work= chars(), temp= chars();
270 const char *b;
271 t_mem code, data= 0;
272 int i;
274 code= rom->get(addr);
276 i= 0;
277 while ((code & dis_tbl()[i].mask) != dis_tbl()[i].code &&
278 dis_tbl()[i].mnemonic)
279 i++;
280 if (dis_tbl()[i].mnemonic == NULL)
282 return strdup("-- UNKNOWN/INVALID");
284 b= dis_tbl()[i].mnemonic;
286 data= (code&0xf0000000)>>28;
287 if (((data & 1) == 0) || (dis_tbl()[i].branch == 'M'))
288 work.append(" ");
289 else
291 switch (data>>2)
293 case 0: work.append("S"); break;
294 case 1: work.append("C"); break;
295 case 2: work.append("Z"); break;
296 case 3: work.append("O"); break;
298 if (data&2)
299 work.append("1 ");
300 else
301 work+= "0 ";
304 while (*b)
306 if (*b == '%')
308 b++;
309 switch (*(b++))
311 case 'd': // Rd
312 data= (code & 0x00f00000)>>20;
313 work.appendf("r%d", data);
314 break;
315 case 'a': // Ra
316 data= (code & 0x000f0000)>>16;
317 work.appendf("r%d", data);
318 break;
319 case 'R': // Ra in LD, ST
320 data= (code & 0x000f0000)>>16;
321 work.appendf("r%d", data);
322 if (comment)
324 chars n= "";
325 addr_name(R[data], rom, &n);
326 comment->format("; [0x%08x%s]= 0x%08x",
327 R[data],
328 n.c_str(),
329 rom->get(R[data]));
331 break;
332 case 'b': // Rb
333 data= (code & 0x0000f000)>>12;
334 work.appendf("r%d", data);
335 break;
336 case '0': // LDL0
337 data= (code & 0x0000ffff);
338 work.appendf("0x0000%04x", data);
339 addr_name(data, rom, &work);
340 break;
341 case 'O': // LDL0 -> jump
342 data= (code & 0x0000ffff);
343 work.appendf("0x%04x", data);
344 addr_name(data, rom, &work);
345 break;
346 case 'l': // LDL
347 data= (code & 0x0000ffff);
348 work.appendf("0x....%04x", data);
349 break;
350 case 'h': // LDH
351 data= (code & 0x0000ffff);
352 work.appendf("0x%04x....", data);
353 break;
354 case 'A': // CALL
355 data= (code & 0x07ffffff);
356 work.appendf("0x%x", data);
357 addr_name(data, rom, &work);
358 break;
359 default:
360 temp= "?";
361 break;
363 if (comment && temp.nempty())
364 comment->append(temp);
366 else
367 work.append(*(b++));
370 return strdup(work.c_str());
373 void
374 cl_p1516::analyze_start(void)
376 class cl_var *v= new cl_var(".reset", rom, 0, chars("Auto-generated by analyze"), -1, -1);
377 v->init();
378 vars->add(v);
380 analyze(0);
383 void
384 cl_p1516::analyze(t_addr addr)
386 struct dis_entry *de;
387 int i;
389 while (!inst_at(addr))
391 t_mem code= rom->read(addr);
392 i= 0;
393 while ((code & dis_tbl()[i].mask) != dis_tbl()[i].code &&
394 dis_tbl()[i].mnemonic)
395 i++;
396 de= &dis_tbl()[i];
397 if (de->mnemonic == NULL)
398 return;
399 set_inst_at(addr);
400 if (de->branch!=' ')
401 switch (de->branch)
403 case 'x': case '_': // non-followable
404 return;
405 case 'M': // LDL0 r15,#imm
407 t_addr target= rom->read(addr) & 0xffff;
408 analyze_jump(addr, target, de->branch);
409 break;
412 addr= rom->validate_address(addr+1);
416 void
417 cl_p1516::print_regs(class cl_console_base *con)
419 int i;
420 con->dd_color("answer");
421 con->dd_printf(" F= 0x%08x ", F);
422 con->dd_printf("O=%c ", (F&O)?'1':'0');
423 con->dd_printf("C=%c ", (F&C)?'1':'0');
424 con->dd_printf("Z=%c ", (F&Z)?'1':'0');
425 con->dd_printf("S=%c ", (F&S)?'1':'0');
426 con->dd_printf("\n");
427 for (i= 0; i<16; i++)
429 if (i<10) con->dd_printf(" ");
430 con->dd_printf("R%d= 0x%08x ", i, R[i]);
431 if (i<10) con->dd_printf(" ");
432 con->dd_printf("[R%d]= 0x%08x", i, rom->get(R[i]));
433 if (i%2)
434 con->dd_printf("\n");
435 else
436 con->dd_printf(" ");
438 print_disass(PC, con);
442 bool
443 cl_p1516::cond(t_mem code)
445 t_mem cond= (code & 0xf0000000) >> 28;
446 if ((cond&1) == 1)
448 u8_t flag= 0, fv, v;
449 switch (cond>>2)
451 case 0: flag= F&S; break;
452 case 1: flag= F&C; break;
453 case 2: flag= F&Z; break;
454 case 3: flag= F&O; break;
456 fv= flag?1:0;
457 v= (cond&2)?1:0;
458 if (fv != v)
459 return false;
461 return true;
464 t_mem
465 cl_p1516::inst_ad(t_mem ra, t_mem rb, u32_t c)
467 u64_t big;
468 u32_t rd;
470 big= (u64_t)ra + (u64_t)rb + (u64_t)c;
471 F&= ~(C|S|Z|O);
472 if (big > 0xffffffff)
473 F|= C;
474 rd= big;
475 if (rd == 0)
476 F|= Z;
477 if (rd & 0x80000000)
478 F|= S;
479 big= (ra & 0x7fffffff) + (rb & 0x7fffffff) + c;
480 if ((big & 0x80000000) && !(F&C))
481 F|= O;
482 if (!(big & 0x80000000) && (F&C))
483 F|= O;
484 cF.W(F);
485 return rd;
489 cl_p1516::inst_alu(t_mem code)
491 u8_t d, a, b, Op;
492 u8_t c1, c2;
493 u64_t big;
495 d= (code & 0x00f00000) >> 20;
496 a= (code & 0x000f0000) >> 16;
497 b= (code & 0x0000f000) >> 12;
498 Op=(code & 0x00000f80) >> 7;
500 switch (Op)
502 case 0: // ADD
503 RC[d]->W(inst_ad(R[a], R[b], 0));
504 break;
505 case 1: // ADC
506 RC[d]->W(inst_ad(R[a], R[b], (F&C)?1:0));
507 break;
508 case 2: // SUB
509 RC[d]->W(inst_ad(R[a], ~(R[b]), 1));
510 break;
511 case 3: // SBB
512 RC[d]->W(inst_ad(R[a], ~(R[b]), (F&C)?1:0));
513 break;
515 case 4: // INC
516 RC[d]->W(inst_ad(R[a], 1, 0));
517 break;
518 case 5: // DEC
519 RC[d]->W(inst_ad(R[a], ~(1), 1));
520 break;
522 case 6: // AND
523 RC[d]->W(R[a] & R[b]);
524 SET_Z(R[d]);
525 break;
526 case 7: // OR
527 RC[d]->W(R[a] | R[b]);
528 SET_Z(R[d]);
529 break;
530 case 8: // XOR
531 RC[d]->W(R[a] ^ R[b]);
532 SET_Z(R[d]);
533 break;
535 case 9: // SHL
536 SET_C(R[a] & 0x80000000);
537 RC[d]->W(R[a] << 1);
538 SET_Z(R[d]);
539 break;
540 case 10: // SHR
541 SET_C(R[a] & 1);
542 RC[d]->W(R[a] >> 1);
543 SET_Z(R[d]);
544 break;
545 case 16: // SHA
546 SET_C(R[a] & 1);
547 RC[d]->W(((i32_t)(R[a])) >> 1);
548 SET_Z(R[d]);
549 break;
550 case 11: // ROL
551 c1= (F&C)?1:0;
552 c2= (R[a] & 0x80000000)?1:0;
553 RC[d]->W((R[a]<<1) + c1);
554 SET_C(c2);
555 SET_Z(R[d]);
556 break;
557 case 12: // ROR
558 c1= (F&C)?1:0;
559 c2= R[a] & 1;
560 R[d]= R[a] >> 1;
561 if (c1)
562 R[d]|= 0x80000000;
563 RC[d]->W(R[d]);
564 SET_C(c2);
565 SET_Z(R[d]);
566 break;
568 case 13: // MUL
569 RC[d]->W(R[a] * R[b]);
570 SET_Z(R[d]);
571 SET_S(R[d] & 0x80000000);
572 break;
573 case 19: // MUH
574 big= (u64_t)R[a] * (u64_t)R[b];
575 RC[d]->W(big >> 32);
576 SET_Z(R[d]);
577 SET_S(R[d] & 0x80000000);
578 break;
579 case 14: // DIV
580 break;
582 case 17: // SETC
583 SET_C(1);
584 break;
585 case 18: // CLRC
586 SET_C(0);
587 break;
589 case 15: // CMP
590 inst_ad(R[a], ~(R[b]), 1);
591 break;
594 return resGO;
598 cl_p1516::exec_inst(void)
600 t_mem code;
601 u8_t inst;
602 bool fe;
604 PC= R[15];
605 instPC= PC;
606 fe= fetch(&code);
607 tick(1);
608 R[15]= PC;
609 if (fe)
610 return(resBREAKPOINT);
612 if (!cond(code))
613 return resGO;
615 inst= (code & 0x0f000000) >> 24;
616 if (code & 0x08000000)
618 // CALL
619 t_addr data= (code & 0x07ffffff);
620 RC[14]->W(R[15]);
621 RC[15]->W(PC= data);
622 return resGO;
625 u8_t d, a;
626 d= (code & 0x00f00000) >> 20;
627 a= (code & 0x000f0000) >> 16;
628 switch (inst)
630 case 0: // nop
631 break;
632 case 1: // LD Rd,Ra
633 R[d]= rom->read(R[a]);
634 vc.rd++;
635 break;
636 case 2: // ST Rd,Ra
637 rom->write(R[a], R[d]);
638 vc.wr++;
639 break;
640 case 3: // MOV Rd,Ra
641 RC[d]->W(R[a]);
642 break;
643 case 4: // LDL0 Rd,data
644 RC[d]->W(code & 0x0000ffff);
645 break;
646 case 5: // LDL Rd,data
647 RC[d]->W((R[d] & 0xffff0000) | (code & 0x0000ffff));
648 break;
649 case 6: // LDH Rd,data
650 RC[d]->W((R[d] & 0x0000ffff) | (code << 16));
651 break;
652 case 7: // ALU
653 inst_alu(code);
654 break;
656 PC= R[15];
658 return resGO;
662 void
663 cl_p1516::btn_edge(int btn, bool press)
665 switch (r2b_state)
667 case r2b_none:
668 if ((btn==1) && press)
669 r2b_state= r2b_alarmed;
670 break;
671 case r2b_alarmed:
672 if ((btn==1) && !press)
673 r2b_state= r2b_none;
674 if ((btn==0) && press)
676 reset();
677 r2b_state= r2b_activated;
679 break;
680 case r2b_activated:
681 if ((btn==1) && !press)
682 r2b_state= r2b_none;
683 break;
688 /* End of p1516.src/p1516.cc */