[ucsim-z80] Fix #3828: uCsim SM83 flags simulation
[sdcc.git] / sdcc / sim / ucsim / src / sims / pdk.src / t16.cc
blob6c4f8f90eebb9f2ba59a3500dd6aa1a9612126fe
1 /*
2 * Simulator of microcontrollers (t16.cc)
4 * Copyright (C) 2024 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 "pdkcl.h"
29 #include "osccl.h"
31 #include "t16cl.h"
34 cl_t16::cl_t16(class cl_uc *auc, const char *aname):
35 cl_hw(auc, HW_TIMER, 0, aname)
37 puc= (class cl_pdk *)auc;
38 src= NULL;
41 int
42 cl_t16::init(void)
44 mod= register_cell(puc->sfr, 6);
45 edg= register_cell(puc->sfr, 0xc);
46 irq= register_cell(puc->sfr, 5);
47 cl_hw::init();
48 uc->mk_mvar(cfg, t16_cnt, "T16", cfg_help(t16_cnt));
49 reset();
50 return 0;
53 const char *
54 cl_t16::cfg_help(t_addr addr)
56 switch ((enum t16_cfg)addr)
58 case t16_on: return "Turn ticking of T16 on/off (bool, RW)";
59 case t16_cnt: return "T16 counter value (RW)";
60 case t16_nuof: return "";
62 return "Not used";
65 void
66 cl_t16::reset(void)
68 cnt= 0;
69 last= 0;
70 mod->set(0);
71 recalc();
74 void
75 cl_t16::recalc(void)
77 u8_t v= mod->get();
78 switch ((v>>5)&7)
80 case 0: clk_source="None"; src= NULL; break;
81 case 1: clk_source="SysClk"; src= &(puc->osc->sys); break;
82 case 2: clk_source="None"; src= NULL; break;
83 case 3: /* TODO PA4 */ clk_source="PA4"; src= NULL; break;
84 case 4: clk_source="ihrc"; src= &(puc->osc->ihrc); break;
85 case 5: clk_source="eosc"; src= &(puc->osc->eosc); break;
86 case 6: clk_source="ilrc"; src= &(puc->osc->ilrc); break;
87 case 7: /* TODO PA0 */ clk_source="PA0"; src= NULL; break;
89 set_div();
90 mask= 1<<((v&7)+8);
91 pre= 0;
92 if (src)
93 last= *src;
96 void
97 cl_t16::set_div(void)
99 u8_t v= mod->get();
100 switch ((v>>3)&3)
102 case 0: div= 1; break;
103 case 1: div= 4; break;
104 case 2: div= 16; break;
105 case 3: div= 64; break;
109 void
110 cl_t16::write(class cl_memory_cell *cell, t_mem *val)
112 if (conf(cell, val))
113 return;
114 if (cell == mod)
116 if ((*val & 0xff) != cell->get())
118 cell->set(*val);
119 recalc();
122 /*else if (cell == egs)
125 /*else if (cell == irq)
128 cell->set(*val);
131 t_mem
132 cl_t16::conf_op(cl_memory_cell *cell, t_addr addr, t_mem *val)
134 switch (addr)
136 case t16_on: // turn this HW on/off
137 if (val)
138 on= *val;
139 else
140 cell->set(on?1:0);
141 break;
142 case t16_cnt:
143 if (val)
144 cnt= *val & 0xffff;
145 else
146 cell->set(cnt);
147 break;
149 return cell->get();
153 cl_t16::tick(int cycles)
155 if (src)
157 t_mem act= *src;
158 if (act != last)
160 int d= act - last, i;
161 if (d<0) d= -d;
162 if (d)
164 pre+= d;
165 if ((i= pre/div))
167 u16_t prev= cnt;
168 cnt+= i;
169 pre%= div;
170 if ((prev & mask) != (cnt & mask))
172 // 0= rising, 1= falling
173 u8_t edge= edg->get() & 0x10;
174 if (( edge && !(cnt & mask)) ||
175 (!edge && (cnt & mask)))
177 irq->write(irq->get() | 4);
182 last= act;
185 return 0;
188 void
189 cl_t16::print_info(class cl_console_base *con)
191 con->dd_printf("T16 Src=%s/%d pre=%u mask=%04x edge=%s irq=%d\n",
192 clk_source.c_str(), div, pre, mask,
193 (edg->get()&0x10)?"fall":"rise",
194 (irq->get()&4)?1:0);
195 con->dd_printf("cnt= %5u 0x%04x\n", cnt, cnt);
199 /* End of pdk.src/t16.cc */