[ucsim] Update email and file info, fix stm8 flash controller
[sdcc.git] / sdcc / sim / ucsim / src / sims / m68hc12.src / m68hc12.cc
blob76cabcab9b13601b7d0699bc5fc548f29e84ea3b
1 /*
2 * Simulator of microcontrollers (m68hc12.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>
29 #include <ctype.h>
30 #include <string.h>
32 #include "globals.h"
33 #include "utils.h"
35 #include "dregcl.h"
37 #include "wraps.h"
38 #include "hcwrapcl.h"
39 #include "glob12.h"
40 #include "m68hc12cl.h"
42 class cl_m68hc12 *uc;
46 * CCR
49 t_mem
50 cl_ccr::write(t_mem val)
52 u8_t act= d();
53 act&= flagX;
54 if (act == 0)
55 val&= ~flagX;
56 return cl_cell8::write(val);
61 * M68HC12 processor
64 int
65 cl_m68hc12::proba(int i, t_mem code)
67 return i;
72 cl_m68hc12::cl_m68hc12(class cl_sim *asim):
73 cl_m68hcbase(asim)
75 IRQ_AT = 0xfff2;
76 XIRQ_AT = 0xfff4;
77 SWI_AT = 0xfff6;
78 TRAP_AT = 0xfff8;
79 COP_AT = 0xfffa;
80 CMR_AT = 0xfffc;
81 RESET_AT = 0xfffe;
82 class cl_ccr c;
83 memcpy((void*)&cCC, (void*)&c, sizeof(class cl_cell8));
84 hc12wrap= new cl_12wrap();
85 hc12wrap->init();
86 extra_ticks= 0;
87 cCC.decode(&CC);
90 int
91 cl_m68hc12::init(void)
93 int i;
95 cl_m68hcbase::init();
96 #define RCV(R) reg_cell_var(&c ## R , &r ## R , "" #R "" , "CPU register " #R "")
97 RCV(TMP2);
98 RCV(TMP3);
100 //set_xtal(8000000);
102 for (i= 0; i<=255; i++)
103 itab[i]= instruction_wrapper_invalid;
105 tex_cells[0]= &cA;
106 tex_cells[1]= &cB;
107 tex_cells[2]= &cCC;
108 tex_cells[3]= &cTMP3;
109 tex_cells[4]= &cD;
110 tex_cells[5]= &cX;
111 tex_cells[6]= &cY;
112 tex_cells[7]= &cSP;
114 tex_names[0]= "A";
115 tex_names[1]= "B";
116 tex_names[2]= "CCR";
117 tex_names[3]= "TMP3";
118 tex_names[4]= "D";
119 tex_names[5]= "X";
120 tex_names[6]= "Y";
121 tex_names[7]= "SP";
123 loop_cells[0]= &cA;
124 loop_cells[1]= &cB;
125 loop_cells[2]= NULL;
126 loop_cells[3]= NULL;
127 loop_cells[4]= &cD;
128 loop_cells[5]= &cX;
129 loop_cells[6]= &cY;
130 loop_cells[7]= &cSP;
132 loop_names[0]= "A";
133 loop_names[1]= "B";
134 loop_names[2]= "-";
135 loop_names[3]= "-";
136 loop_names[4]= "D";
137 loop_names[5]= "X";
138 loop_names[6]= "Y";
139 loop_names[7]= "SP";
141 return 0;
145 const char *
146 cl_m68hc12::id_string(void)
148 return "M68HC12";
151 void
152 cl_m68hc12::reset(void)
154 cl_m68hcbase::reset();
155 rCC= flagStop|flagX|flagI;
156 //post_inc_dec= 0;
157 rev_st= 0;
160 void
161 cl_m68hc12::make_memories(void)
163 class cl_address_space *as;
164 class cl_address_decoder *ad;
165 class cl_memory_chip *chip;
167 rom= as= new cl_address_space("rom", 0, 0x10000, 8);
168 as->init();
169 address_spaces->add(as);
171 chip= new cl_chip8("rom_chip", 0x400000, 8);
172 chip->init();
173 memchips->add(chip);
174 ad= new cl_address_decoder(as= rom,
175 chip, 0, 0xffff, 0);
176 ad->init();
177 as->decoders->add(ad);
178 ad->activate(0);
181 void
182 cl_m68hc12::make_cpu_hw(void)
184 add_hw(cpu12= new cl_hc12_cpu(this));
185 cpu12->init();
186 cpu= cpu12;
189 void
190 CL12::pre_inst(void)
192 cl_m68hcbase::pre_inst();
193 block_irq= false;
194 cI= &cIX;
195 xb_tick_shift= 0;
196 extra_ticks= 0;
199 void
200 CL12::pre_emu(void)
202 cl_m68hcbase::pre_emu();
203 block_irq= false;
204 cI= &cIX;
205 xb_tick_shift= 0;
206 extra_ticks= 0;
210 CL12::exec_inst(void)
212 int res= resINV;
213 t_mem code;
214 hcwrapper_fn fn= NULL;
216 instPC= PC;
217 if (fetch(&code))
218 return resBREAKPOINT;
219 if (code == 0x18)
221 code= fetch();
222 fn= hc12wrap->page0x18[code];
223 inst_ticks= ticks12p18[code];
225 else if (code == 0x04)
227 code= fetch();
228 res= loop(code);
229 fn= NULL;
231 else
233 fn= hc12wrap->page0[code];
234 inst_ticks= ticks12p0[code];
236 if (fn)
237 res= fn(this, code);
238 if (res != resNOT_DONE)
239 return res;
241 inst_unknown(rom->read(instPC));
242 return(res);
245 void
246 CL12::post_inst(void)
248 if (inst_ticks & 0xf00)
249 inst_ticks= (inst_ticks>>(4*xb_tick_shift)) & 0xf;
250 tick(inst_ticks);
251 if (extra_ticks)
252 tick(extra_ticks);
253 cl_m68hcbase::post_inst();
256 void
257 CL12::post_emu(void)
259 if (inst_ticks & 0xf00)
260 inst_ticks= (inst_ticks>>(4*xb_tick_shift)) & 0xf;
261 tick(inst_ticks);
262 if (extra_ticks)
263 tick(extra_ticks);
264 cl_m68hcbase::post_emu();
267 i16_t
268 CL12::s8_16(u8_t op)
270 if (op&0x80)
271 return 0xff00 | op;
272 return op;
276 CL12::xb_type(u8_t p)
278 if ((p & 0x20) == 0)
279 // 1. rr0n nnnn n5,r rr={X,Y,SP,PC}
280 return 1;
281 if ((p&0xe7) == 0xe7)
282 // 6. 111r r111 [D,r] rr={X,Y,SP,PC}
283 return 6;
284 if ((p&0xe7) == 0xe3)
285 // 5. 111r r011 [n16,r] rr={X,Y,SP,PC}
286 return 5;
287 if ((p&0xc0) != 0xc0)
288 // 3. rr1p nnnn n4,+-r+- rr={X,Y,SP}
289 return 3;
290 if ((p&0xe4) == 0xe0)
291 // 2. 111r r0zs n9/16,r rr={X,Y,SP,PC}
292 return 2;
293 // if ((p&0xe4) == 0xe4)
294 // 4. 111r r1aa {A,B,D},r rr={X,Y,SP,PC}
295 return 4;
298 bool
299 CL12::xb_indirect(u8_t p)
301 if ((p & 0x20) == 0) return false;
302 if ((p&0xe7) == 0xe7) return true;
303 if ((p&0xe7) == 0xe3) return true;
304 return false;
307 bool
308 CL12::xb_PC(u8_t p)
310 int t= xb_type(p);
311 switch (t)
313 case 1: return (p&0xc0)==0xc0;
314 case 6: return (p&0x18)==0x18;
315 case 5: return (p&0x18)==0x18;
316 case 3: return false;
317 case 2: return (p&0x18)==0x18;
318 case 4: return (p&0x18)==0x18;
320 return false;
323 t_addr
324 CL12::naddr(t_addr *addr /* of xb */, u8_t *pg, u32_t use_PC)
326 u8_t p, h, l;
327 i8_t n;
328 i16_t ioffset= 0;
329 u16_t uoffset= 0;
330 u16_t ival= 0, a= 0;
331 //i8_t post_inc_dec= 0;
332 class cl_cell16 *post_idx_reg= NULL;
334 if (addr)
336 p= rom->read(*addr);
337 (*addr)++;
339 else
340 p= fetch();
341 use_PC&= 0xffff;
343 switch (xb_type(p))
345 case 1: // 1. rr0n nnnn n5,r rr={X,Y,SP,PC}
346 switch (p & 0xc0)
348 case 0x00: ival= rX; break;
349 case 0x40: ival= rY; break;
350 case 0x80: ival= rSP; break;
351 case 0xc0:
352 if (use_PC)
353 ival= use_PC;
354 else if (addr)
355 ival= (*addr)&0xffff;
356 else
357 ival= PC&0xffff;
358 break;
360 ioffset= p&0x1f;
361 if (p&0x10) ioffset|= 0xffe0;
362 xb_tick_shift= 0;
363 return (u16_t)(ival+ioffset);
364 break;
366 case 6: // 6. 111r r111 [D,r] rr={X,Y,SP,PC}
367 switch (p & 0x18)
369 case 0x00: ival= rX; break;
370 case 0x10: ival= rY; break;
371 case 0x08: ival= rSP; break;
372 case 0x18:
373 if (use_PC)
374 ival= use_PC;
375 else if (addr)
376 ival= (*addr)&0xffff;
377 else
378 ival= PC&0xffff;
379 break;
381 ioffset= rD;
382 a= (u16_t)(ival+ioffset);
383 if (pg)
384 *pg= rom->read(a+2);
385 xb_tick_shift= 2;
386 return (u16_t)read_addr(rom, a);
387 break;
389 case 5: // 5. 111r r011 [n16,r] rr={X,Y,SP,PC}
390 switch (p & 0x18)
392 case 0x00: ival= rX; break;
393 case 0x10: ival= rY; break;
394 case 0x08: ival= rSP; break;
395 case 0x18:
396 if (use_PC)
397 ival= use_PC;
398 else if (addr)
399 ival= (*addr)&0xffff;
400 else
401 ival= PC&0xffff;
402 break;
404 if (addr)
406 h= rom->read(*addr);
407 (*addr)++;
408 l= rom->read(*addr);
409 (*addr)++;
411 else
413 h= fetch();
414 l= fetch();
416 ioffset= h*256+l;
417 a= (u16_t)(ival+ioffset);
418 if (pg)
419 *pg= rom->read(a+2);
420 xb_tick_shift= 2;
421 return (u16_t)read_addr(rom, a);
422 break;
424 case 3: // 3. rr1p nnnn n4,+-r+- rr={X,Y,SP}
425 switch (p & 0xc0)
427 case 0x00: ival= rX; post_idx_reg= &cX; break;
428 case 0x40: ival= rY; post_idx_reg= &cY; break;
429 case 0x80: ival= rSP; post_idx_reg= &cSP; break;
431 n= p&0xf;
432 if (n&0x08) n|= 0xf0; else n++;
433 if (p&0x10)
435 // post +-
436 ival= (post_idx_reg->R() + (int)n);
437 if (!addr)
439 //post_inc_dec= n;
440 post_idx_reg->W(ival);
443 else
445 // pre +-
446 if (!addr)
447 post_idx_reg->W(ival);
448 ival= (post_idx_reg->R() + (int)n);
450 xb_tick_shift= 0;
451 return (u16_t)ival;
452 break;
454 case 2: // 2. 111r r0zs n9/16,r rr={X,Y,SP,PC}
455 switch (p & 0x18)
457 case 0x00: ival= rX; break;
458 case 0x10: ival= rY; break;
459 case 0x08: ival= rSP; break;
460 case 0x18:
461 if (use_PC)
462 ival= use_PC;
463 else if (addr)
464 ival= (*addr)&0xffff;
465 else
466 ival= PC&0xffff;
467 break;
469 if ((p&0x02) == 0x00)
471 // 9 bit
472 if (addr)
474 ioffset= rom->read(*addr);
475 (*addr)++;
477 else
478 ioffset= fetch();
479 if (p&0x01) ioffset|= 0xff00;
480 xb_tick_shift= 0;
482 else
484 // 16 bit
485 if (addr)
487 h= rom->read(*addr);
488 (*addr)++;
489 l= rom->read(*addr);
490 (*addr)++;
492 else
494 h= fetch();
495 l= fetch();
497 ioffset= h*256+l;
498 xb_tick_shift= 1;
500 return (u16_t)(ival+ioffset);
501 break;
503 default: // 4. 111r r1aa {A,B,D},r rr={X,Y,SP,PC}
504 switch (p & 0x18)
506 case 0x00: ival= rX; break;
507 case 0x08: ival= rY; break;
508 case 0x10: ival= rSP; break;
509 case 0x18:
510 if (use_PC)
511 ival= use_PC;
512 else if (addr)
513 ival= (*addr)&0xffff;
514 else
515 ival= PC&0xffff;
516 break;
518 switch (p&0x03)
520 case 0x00: uoffset= rA; break;
521 case 0x01: uoffset= rB; break;
522 case 0x02: uoffset= rD; break;
524 xb_tick_shift= 0;
525 return (u16_t)(ival+uoffset);
526 break;
529 return (u16_t)a;
532 u8_t
533 CL12::xbop8()
535 u16_t a= naddr(NULL, NULL);
536 return rom->read(a);
539 u16_t
540 CL12::xbop16()
542 u16_t a= naddr(NULL, NULL);
543 u8_t h, l;
544 h= rom->read(a);
545 l= rom->read(a+1);
546 return h*256+l;
549 class cl_memory_cell &
550 CL12::xb(void)
552 t_addr a= naddr(NULL, NULL);
553 class cl_cell8 *c= (class cl_cell8 *)rom->get_cell(a);
554 return *c;
557 void
558 CL12::push_regs(bool inst_part)
560 rom->write(--rSP, PC&0xff);
561 rom->write(--rSP, PC>>8);
562 rom->write(--rSP, rIY&0xff);
563 rom->write(--rSP, rIY>>8);
564 rom->write(--rSP, rIX&0xff);
565 rom->write(--rSP, rIX>>8);
566 rom->write(--rSP, rA);
567 rom->write(--rSP, rB);
568 rom->write(--rSP, rCC);
571 void
572 CL12::pull_regs(bool inst_part)
574 u8_t l, h;
575 rCC= rom->read(rSP++);
576 rB= rom->read(rSP++);
577 rA= rom->read(rSP++);
578 h= rom->read(rSP++);
579 l= rom->read(rSP++);
580 rIX= h*256+l;
581 h= rom->read(rSP++);
582 l= rom->read(rSP++);
583 rIY= h*256+l;
584 h= rom->read(rSP++);
585 l= rom->read(rSP++);
586 PC= h*256+l;
590 CL12::trap(t_mem code)
592 push_regs(true);
593 PC= read_addr(rom, TRAP_AT);
594 return resGO;
598 void
599 cl_m68hc12::print_regs(class cl_console_base *con)
601 con->dd_color("answer");
602 con->dd_printf("A= $%02x %3d %+4d %c ", rA, rA, (i8_t)rA, isprint(rA)?rA:'.');
603 con->dd_printf("B= $%02x %3d %+4d %c ", rB, rB, (i8_t)rB, isprint(rB)?rB:'.');
604 con->dd_printf(" D= $%04x %5d %+5d ", rD, rD, (i16_t)rD);
605 con->dd_printf("\n");
606 con->dd_printf("CC= "); con->print_bin(rF, 8);
607 con->dd_printf(" TMP2= $%04x %5d %+5d",
608 rTMP2, rTMP2, rTMP2);
609 con->dd_printf("\n");
610 con->dd_printf(" SXHINZVC");
611 con->dd_printf(" TMP3= $%04x %5d %+5d",
612 rTMP3, rTMP3, rTMP3);
613 con->dd_printf("\n");
615 con->dd_printf("IX= ");
616 class cl_dump_ads ads(IX, IX+7);
617 rom->dump(0, /*IX, IX+7*/&ads, 8, con);
618 con->dd_color("answer");
620 con->dd_printf("IY= ");
621 ads._ss(IY, IY+7);
622 rom->dump(0, /*IY, IY+7*/&ads, 8, con);
623 con->dd_color("answer");
625 con->dd_printf("SP= ");
626 ads._ss(SP, SP+7);
627 rom->dump(0, /*SP, SP+7*/&ads, 8, con);
628 con->dd_color("answer");
630 print_disass(PC, con);
635 * CPU peripheral for HC12 cpu
638 cl_hc12_cpu::cl_hc12_cpu(class cl_uc *auc):
639 cl_hw(auc, HW_CPU, 0, "cpu")
641 muc= (class cl_m68hc12 *)auc;
645 cl_hc12_cpu::init(void)
647 class cl_cvar *v;
648 cl_hw::init();
650 ppage= register_cell(muc->rom, 0x0035);
651 dpage= register_cell(muc->rom, 0x0034);
652 epage= register_cell(muc->rom, 0x0036);
653 windef= register_cell(muc->rom, 0x0037);
655 uc->vars->add(v= new cl_var("PPAGE", muc->rom, 0x0035,
656 "Program page register"));
657 v->init();
658 uc->vars->add(v= new cl_var("DPAGE", muc->rom, 0x0034,
659 "Data page register"));
660 v->init();
661 uc->vars->add(v= new cl_var("EPAGE", muc->rom, 0x0036,
662 "Extra page register"));
663 v->init();
664 uc->vars->add(v= new cl_var("WINDEF", muc->rom, 0x0037,
665 "Window definition register"));
666 v->init();
667 return 0;
670 void
671 cl_hc12_cpu::reset(void)
673 ppage->write(0);
674 dpage->write(0);
675 epage->write(0);
676 windef->write(0);
679 void
680 cl_hc12_cpu::print_info(class cl_console_base *con)
682 con->dd_color("answer");
683 con->dd_printf("PPAGE= $%02x\n", ppage->read());
684 con->dd_printf("DPAGE= $%02x\n", dpage->read());
685 con->dd_printf("EPAGE= $%02x\n", epage->read());
686 u8_t w= windef->read();
687 con->dd_printf("PWEN= %d\n", (w&0x40)?1:0);
688 con->dd_printf("DWEN= %d\n", (w&0x80)?1:0);
689 con->dd_printf("EWEN= %d\n", (w&0x20)?1:0);
692 t_mem
693 cl_hc12_cpu::ppage_write(u8_t val)
695 return ppage->write(val);
699 /* End of m68hc12.src/m68hc12.cc */