2 * Simulator of microcontrollers (pdk.cc)
4 * Copyright (C) 2016 Drotos Daniel
6 * To contact author send email to dr.dkdb@gmail.com
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
28 //#include "ddconfig.h"
31 //#include <stdarg.h> /* for va_list */
36 //#include "i_string.h"
54 //#include "regspdk.h"
56 /*******************************************************************/
58 cl_fpp::cl_fpp(int aid
, class cl_pdk
*the_puc
, class cl_sim
*asim
):
68 * Base type of PDK controllers
71 cl_fpp::cl_fpp(int aid
, class cl_pdk
*the_puc
, struct cpu_entry
*IType
, class cl_sim
*asim
) : cl_uc(asim
)
78 int cl_fpp::init(void) {
79 cl_uc::init(); /* Memories now exist */
83 // rom = address_space(MEM_ROM_ID);
84 // ram = mem(MEM_XRAM);
87 // zero out ram(this is assumed in regression tests)
88 // for (int i = 0x0; i < 0x8000; i++) {
89 // ram->set((t_addr)i, 0);
99 d
.format("Accumulator of FPP%d", id
);
100 puc
->mk_cvar(&cA
, n
, d
);
102 puc
->mk_cvar(&cA
, "A", "Accumulator");
103 n
.format("PC%d", id
);
104 d
.format("Program counter of FPP%d", id
);
105 puc
->mk_cvar(&cPC
, n
, d
);
119 void cl_fpp::reset(void) {
125 //for (t_addr i = 0; i < io_size; ++i) store_io(i, 0);
129 void cl_fpp::mk_hw_elements(void)
131 // TODO: Add hardware stuff here.
134 cl_uc::mk_hw_elements();
135 add_hw(h= new cl_dreg(this, 0, "dreg"));
140 void cl_fpp::make_memories(void)
142 class cl_address_space
*as
;
143 int rom_storage
= 0x2000, ram_storage
= 0x200;
148 case CPU_PDK13
: rom_width
= 13; break;
149 case CPU_PDK14
: rom_width
= 14; break;
150 case CPU_PDK15
: rom_width
= 15; break;
151 case CPU_PDK16
: rom_width
= 16; break;
152 default: rom_width
= 16;
163 rom
= as
= new cl_address_space("rom", 0, rom_storage
, rom_width
);
165 address_spaces
->add(as
);
166 ram
= as
= new cl_address_space("ram", 0, ram_storage
, 8);
168 address_spaces
->add(as
);
169 sfr
= as
= new cl_address_space("regs8", 0, io_size
, 8);
171 address_spaces
->add(as
);
173 class cl_address_decoder
*ad
;
174 class cl_memory_chip
*chip
;
176 chip
= new cl_chip16("rom_chip", rom_storage
, rom_width
);
180 ad
= new cl_address_decoder(as
= rom
, chip
, 0, rom_storage
-1, 0);
182 as
->decoders
->add(ad
);
185 chip
= new cl_chip16("ram_chip", ram_storage
, 8);
189 ad
= new cl_address_decoder(as
= ram
, chip
, 0, ram_storage
-1, 0);
191 as
->decoders
->add(ad
);
194 chip
= new cl_chip16("io_chip", io_size
, 8);
198 ad
= new cl_address_decoder(as
= sfr
, chip
, 0, io_size
-1, 0);
200 as
->decoders
->add(ad
);
203 // extra byte of the IO memory will point to the A register just for the debugger
204 sfr
->get_cell(io_size
)->decode(&(rA
));
207 cSP
= sfr
->get_cell(2);
208 cF
= sfr
->get_cell(0);
214 cl_fpp::build_cmdset(class cl_cmdset
*cmdset
)
217 cl_uc::build_cmdset(cmdset
);
222 * Help command interpreter
225 struct dis_entry *cl_fppa::dis_tbl(void) {
226 switch (type->type) {
228 return (disass_pdk_13);
230 return (disass_pdk_14);
232 return (disass_pdk_15);
234 return NULL;//__builtin_unreachable();
239 int cl_fpp::inst_length(t_addr
/*addr*/) {
243 int cl_fpp::inst_branch(t_addr addr
) {
246 get_disasm_info(addr
, NULL
, &b
, NULL
, NULL
);
251 bool cl_fpp::is_call(t_addr addr
) {
254 get_disasm_info(addr
, NULL
, NULL
, NULL
, &e
);
256 return e
? (e
->is_call
) : false;
259 int cl_fpp::longest_inst(void) { return 1; }
261 const char *cl_fpp::get_disasm_info(t_addr addr
, int *ret_len
, int *ret_branch
,
263 struct dis_entry
**dentry
) {
264 const char *b
= NULL
;
266 int start_addr
= addr
;
267 struct dis_entry
*instructions
= dis_tbl();
269 switch (type->type) {
271 instructions = disass_pdk_13;
274 instructions = disass_pdk_14;
277 instructions = disass_pdk_15;
280 return "";//__builtin_unreachable();
283 uint code
= rom
->get(addr
++);
285 while ((code
& instructions
[i
].mask
) != instructions
[i
].code
&&
286 instructions
[i
].mnemonic
)
288 dis_entry
*dis_e
= &instructions
[i
];
289 b
= instructions
[i
].mnemonic
;
292 *ret_branch
= dis_e
->branch
;
297 *immed_offset
= immed_n
;
299 *immed_offset
= (addr
- start_addr
);
302 if (ret_len
) *ret_len
= 1;
304 if (dentry
) *dentry
= dis_e
;
309 char *cl_fppa::disass(t_addr addr)
314 int immed_offset = 0;
315 struct dis_entry *dis_e;
320 b = get_disasm_info(addr, &len, NULL, &immed_offset, &dis_e);
324 return (strdup("UNKNOWN/INVALID"));
329 if ((*b == ' ') && first)
332 while (work.len() < 6) work.append(' ');
338 uint code = rom->get(addr) & ~(uint)dis_e->mask;
341 case 'k': // k immediate addressing
342 temp.format("#0x%x", code);
344 case 'm': // m memory addressing
350 temp.format("0x%x", code);
352 case 'i': // i IO addressing
353 // TODO: Maybe add pretty printing.
359 temp.format("[0x%x]", code);
361 case 'n': // n N-bit addressing
363 switch (type->type) {
365 n = (code & 0xE0) >> 5;
368 n = (code & 0x1C0) >> 6;
371 n = (code & 0x380) >> 7;
374 n= 0;//__builtin_unreachable();
376 temp.format("#0x%x", n);
388 return strdup(work.c_str());
393 cl_fpp::get_dis_entry(t_addr addr
)
396 code
= rom
->get(addr
);
399 while ((code
& dis_tbl()[i
].mask
) != dis_tbl()[i
].code
&&
400 dis_tbl()[i
].mnemonic
)
402 return &dis_tbl()[i
];
406 cl_fpp::disassc(t_addr addr
, chars
*comment
)
408 chars work
= chars(), temp
= chars(), fmt
= chars();
413 struct dis_entry
*de
;
415 code
= rom
->get(addr
);
416 de
= get_dis_entry(addr
);
417 if (!de
|| !de
->mnemonic
)
418 return strdup("-- UNKNOWN/INVALID");
426 if ((b
[i
] == ' ') && first
)
429 while (work
.len() < 9) work
.append(' ');
435 while (b
[i
] && (b
[i
]!='\''))
441 work
.appendf("0x%02x", code
& 0x1f);
443 work
.appendf("[0x%04x]", code
& 0xf);
445 work
.appendf("[0x%04x]", code
& 0x3f);
447 work
.appendf("[0x%04x]", code
& 0x7f);
449 work
.appendf("[0x%04x]", code
& 0xff);
451 work
.appendf("[0x%04x]", code
& 0x1f & ~1);
453 work
.appendf("[0x%04x]", code
& 0x7f & ~1);
455 work
.appendf("[0x%04x]", code
& 0xff & ~1);
457 work
.appendf("[0x%04x]", code
& 0x1ff & ~1);
459 work
.appendf("%d", (code
>>5)&7);
461 work
.appendf("%d", (code
>>6)&7);
463 work
.appendf("%d", (code
>>7)&7);
465 work
.appendf("%d", (code
>>9)&7);
467 work
.appendf("0x%04x", code
& 0xff);
469 work
.appendf("0x%04x", code
& 0x3ff);
471 work
.appendf("0x%04x", code
& 0x7ff);
473 work
.appendf("0x%04x", code
& 0xfff);
475 work
.appendf("0x%04x", code
& 0x1fff);
477 work
.appendf("%d", code
& 0xf);
479 work
.appendf("%d", code
& 0x1f);
480 if (comment
&& temp
.nempty())
481 comment
->append(temp
);
491 work
.appendf("[0x%04x]", code
& m_mask());
494 work
.appendf("[0x%04x]", code
& m_mask() & ~1);
497 work
.appendf("#0x%02x", code
& 0xff);
500 work
.appendf("0x%02x", code
& io_mask());
503 work
.appendf("%d", (code
>>5)&7);
506 if (comment
&& temp
.nempty())
507 comment
->append(temp
);
513 return strdup(work
.c_str());
517 cl_fpp::print_regs(class cl_console_base
*con
)
520 con
->dd_color("answer");
521 con
->dd_printf("A = %02x %3u\n", rA
, rA
);
522 con
->dd_printf(" OACZ\n");
523 con
->dd_printf("F = %02x ", rF
);
524 con
->dd_printf("%d%d%d%d\n", fO
, fA
, fC
, fZ
);
525 con
->dd_printf("SP= %02x\n", rSP
);
526 print_disass(PC
, con
);
533 int cl_fpp::exec_inst(void)
540 return (resBREAKPOINT
);
544 int status
= execute(code
);
545 if (status
== resINV_INST
)
547 return (resINV_INST
);
554 cl_fpp::push(u16_t word
)
557 ram
->write(rSP
, word
);
558 ram
->write(rSP
+1, word
>>8);
561 stack_check_overflow(b
);
565 cl_fpp::pushlh(u8_t low
, u8_t high
)
568 ram
->write(rSP
, low
);
569 ram
->write(rSP
+1, high
);
572 stack_check_overflow(b
);
576 cl_fpp::stack_check_overflow(void)
580 class cl_stack_op
*op
;
581 op
= new cl_stack_op(stack_push
, instPC
, rSP
-2, rSP
);
582 class cl_error_stack_overflow
*e
=
583 new cl_error_stack_overflow(op
);
590 cl_fpp::stack_check_overflow(t_addr sp_before
)
594 class cl_stack_op
*op
;
595 op
= new cl_stack_op(stack_push
, instPC
, sp_before
, rSP
);
596 class cl_error_stack_overflow
*e
=
597 new cl_error_stack_overflow(op
);
603 /****************************************************************************/
606 /* Set nr of active FPP */
609 cl_act_cell::write(t_mem val
)
611 val
= puc
->set_act(val
);
612 return cl_pdk_cell::write(val
);
618 cl_nuof_cell::write(t_mem val
)
620 val
= puc
->set_nuof(val
);
621 return cl_pdk_cell::write(val
);
625 cl_fppen_op::cl_fppen_op(class cl_pdk
*the_puc
, class cl_memory_cell
*acell
):
626 cl_memory_operator(acell
)
632 cl_fppen_op::write(t_mem val
)
634 return puc
->set_fppen(val
);
639 cl_xtal_writer::write(t_mem val
)
641 u32_t u
= puc
->osc
->frsys
;
647 cl_mulrh_op::cl_mulrh_op(class cl_pdk
*the_puc
, class cl_memory_cell
*acell
):
648 cl_memory_operator(acell
)
654 cl_mulrh_op::read(void)
664 cl_pdk::cl_pdk(struct cpu_entry
*IType
, class cl_sim
*asim
):
677 class cl_memory_operator
*op
;
680 cFPPEN
= sfr
->get_cell(1);
681 cFPPEN
->decode(&rFPPEN
);
682 op
= new cl_fppen_op(this, cFPPEN
);
684 cFPPEN
->append_operator(op
);
686 op
= new cl_mulrh_op(this, sfr
->get_cell(9));
687 sfr
->get_cell(9)->append_operator(op
);
689 mk_mvar(sfr
, 0, "FLAG", "ACC Status Flag Register");
690 mk_mvar(sfr
, 0, "F", "ACC Status Flag Register");
691 mk_mvar(sfr
, 1, "FPPEN", "FPP unit Enable Register");
692 mk_mvar(sfr
, 2, "SP", "Stack Pointer Register");
693 mk_mvar(sfr
, 3, "CLKMD", "Clock Mode Register");
694 mk_mvar(sfr
, 5, "INTRQ", "Interrupt Request Register");
695 mk_mvar(sfr
, 6, "T16M", "Timer16 Mode Register");
696 mk_mvar(sfr
, 8, "MULOP", "Multplier Operand Register");
697 mk_mvar(sfr
, 8, "MISC", "MISC Register");
698 mk_mvar(sfr
, 9, "MULRH", "Multplier Result High Byte Register");
699 mk_mvar(sfr
, 0xa, "EOSCR", "External Oscillator Setting Register");
700 mk_mvar(sfr
, 0xc, "INTEGS", "Interrupt Edge Select Register");
702 cact
= new cl_act_cell(this);
703 reg_cell_var(cact
, &act
, "fpp", "ID of actual FPPA");
705 cnuof_fpp
= new cl_nuof_cell(this);
706 reg_cell_var(cnuof_fpp
, &nuof_fpp
, "nuof_fpp", "Number of FPPs");
708 if (type
->type
== CPU_PDKX
)
723 cPC
.decode(&(fpps
[0]->PC
));
729 cl_pdk::id_string(void)
747 cl_pdk::make_memories(void)
749 class cl_address_space
*as
;
750 class cl_address_decoder
*ad
;
751 class cl_memory_chip
*chip
;
752 int rom_size
= 0x2000, ram_size
=0x200;
754 rom
= as
= new cl_address_space("rom", 0, rom_size
, 16);
756 address_spaces
->add(as
);
757 ram
= as
= new cl_address_space("ram", 0, ram_size
, 8);
759 address_spaces
->add(as
);
760 sfr
= as
= new cl_address_space("regs8", 0, io_size
, 8);
762 address_spaces
->add(as
);
764 chip
= new cl_chip16("rom_chip", rom_size
, 16);
768 ad
= new cl_address_decoder(as
= rom
, chip
, 0, rom_size
-1, 0);
770 as
->decoders
->add(ad
);
773 chip
= new cl_chip16("ram_chip", ram_size
, 8);
777 ad
= new cl_address_decoder(as
= ram
, chip
, 0, ram_size
-1, 0);
779 as
->decoders
->add(ad
);
782 chip
= new cl_chip16("io_chip", io_size
, 8);
786 ad
= new cl_address_decoder(as
= sfr
, chip
, 0, io_size
-1, 0);
788 as
->decoders
->add(ad
);
793 cl_pdk::mk_hw_elements(void)
796 cl_uc::mk_hw_elements();
798 add_hw(osc
= new cl_osc(this, "osc"));
801 add_hw(t16
= new cl_t16(this, "t16"));
804 add_hw(wdt
= new cl_wdt(this, "wdt"));
807 class cl_memory_cell
*c
;
808 class cl_hw
*simif
= get_hw("simif", 0);
811 c
= simif
->cfg_cell(simif_xtal
);
812 c
->prepend_operator(new cl_xtal_writer(this, c
));
817 cl_pdk::mk_fpp(int id
)
822 case CPU_PDK13
: fppa
= new cl_fpp13(id
, this, sim
); break;
823 case CPU_PDK14
: fppa
= new cl_fpp14(id
, this, sim
); break;
824 case CPU_PDK15
: fppa
= new cl_fpp15(id
, this, sim
); break;
825 case CPU_PDK16
: fppa
= new cl_fpp16(id
, this, sim
); break;
826 case CPU_PDKX
: fppa
= new cl_fpp15(id
, this, sim
); break;
827 default: fppa
= new cl_fpp14(id
, this, sim
); break;
838 for (i
=0; i
<nuof_fpp
; i
++)
844 isr_ticks
->set(0, 0);
845 idle_ticks
->set(0, 0);
846 halt_ticks
->set(0, 0);
847 vc
.inst
= vc
.fetch
= vc
.rd
= vc
.wr
= 0;
849 stack_ops
->free_all();
851 for (i
= 0; i
< hws
->count
; i
++)
853 class cl_hw
*hw
= (class cl_hw
*)(hws
->at(i
));
859 cl_pdk::set_fppen(u8_t val
)
865 for (i
=0, m
=1, n
=0; i
<8; i
++, m
<<=1)
877 cl_pdk::set_act(u8_t val
)
882 cPC
.decode(&(fpps
[act
]->PC
));
888 cl_pdk::set_nuof(u8_t val
)
921 cl_pdk::get_pc(int id
)
929 cl_pdk::set_pc(int id
, t_addr new_pc
)
933 fpps
[id
]->cPC
.W(new_pc
);
938 cl_pdk::exec_inst(void)
940 int it
, ret
= resHALT
;
943 while (!(rFPPEN
& (1<<act
)))
944 act
= (act
+1)%nuof_fpp
;
948 fpps
[act
]->pre_inst();
949 ret
= fpps
[act
]->exec_inst();
950 fpps
[act
]->post_inst();
951 it
= inst_ticks
= fpps
[act
]->inst_ticks
;
955 vc
.inst
= vc
.fetch
= vc
.rd
= vc
.wr
= 0;
956 for (i
= 0; i
<nuof_fpp
; i
++)
958 vc
.inst
+= fpps
[i
]->vc
.inst
;
959 vc
.fetch
+= fpps
[i
]->vc
.fetch
;
960 vc
.rd
+= fpps
[i
]->vc
.rd
;
961 vc
.wr
+= fpps
[i
]->vc
.wr
;
966 act
= (act
+1)%nuof_fpp
;
967 while (!(rFPPEN
& (1<<act
)));
968 cPC
.decode(&(fpps
[act
]->PC
));
977 cl_pdk::disassc(t_addr addr
, chars
*comment
)
979 return fpps
[0]->disassc(addr
, comment
);
984 cl_pdk::print_regs(class cl_console_base
*con
)
988 for (i
= 0; i
<nuof_fpp
; i
++)
990 //con->dd_color((i==act)?"result":"answer");
992 con
->dd_cprintf("ui_run", "FPP%d:EN ", i
);
994 con
->dd_cprintf("ui_stop", "FPP%d:DIS ", i
);
996 con
->dd_printf("\n");
997 for (i
= 0; i
<nuof_fpp
; i
++)
999 con
->dd_color((i
==act
)?"result":"answer");
1000 con
->dd_printf("A=%02x %3u ", fpps
[i
]->rA
, fpps
[i
]->rA
);
1002 con
->dd_printf("\n");
1003 for (i
= 0; i
<nuof_fpp
; i
++)
1005 con
->dd_color((i
==act
)?"result":"answer");
1006 con
->dd_printf(" OACZ ");
1008 con
->dd_printf("\n");
1009 for (i
= 0; i
<nuof_fpp
; i
++)
1011 con
->dd_color((i
==act
)?"result":"answer");
1012 con
->dd_printf("F=", fpps
[i
]->rF
);
1013 con
->dd_printf("%d%d%d%d ",
1014 ((fpps
[i
]->rF
&BIT_OV
)>>BITPOS_OV
),
1015 ((fpps
[i
]->rF
&BIT_AC
)>>BITPOS_AC
),
1016 ((fpps
[i
]->rF
&BIT_C
)>>BITPOS_C
),
1017 ((fpps
[i
]->rF
&BIT_Z
)>>BITPOS_Z
));
1019 con
->dd_printf("\n");
1020 for (i
= 0; i
<nuof_fpp
; i
++)
1022 con
->dd_color((i
==act
)?"result":"answer");
1023 con
->dd_printf("SP=%02x ", fpps
[i
]->rSP
);
1025 con
->dd_printf("\n");
1027 for (i
=0; i
<nuof_fpp
; i
++)
1029 con
->dd_color((i
==act
)?"result":"answer");
1030 con
->dd_printf("%cFPP%d%c: ", (rFPPEN
&(1<<act
))?'+':'-', i
, (act
==i
)?'*':' ');
1031 fpps
[0]->print_disass(fpps
[i
]->PC
, con
);
1036 /* End of pdk.src/pdk.cc */