@@ -51,69 +51,52 @@ REG16(CMCR, 0)
5151REG16 (CMCNT , 2 )
5252REG16 (CMCOR , 4 )
5353
54- static void update_events (RCMTState * cmt , int ch )
55- {
56- int64_t next_time ;
54+ static uint16_t read_cmcnt (RCMTState * cmt , int ch ) {
55+ if (!(cmt -> cmstr & (1 << ch ))) {
56+ return cmt -> cmcnt [ch ];
57+ }
58+ int64_t elapsed_ns = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL ) - cmt -> tick [ch ];
59+ uint64_t ticks = (elapsed_ns * cmt -> cmt_freq [ch ]) / (NANOSECONDS_PER_SECOND );
60+ uint32_t limit = cmt -> cmcor [ch ] + 1 ;
61+ return (cmt -> cmcnt [ch ] + ticks ) % limit ;
62+ }
5763
58- if (( cmt -> cmstr & ( 1 << ch )) == 0 ) {
59- /* count disable, so not happened next event. */
64+ static void update_events ( RCMTState * cmt , int ch ) {
65+ if (!( cmt -> cmstr & ( 1 << ch ))) {
6066 return ;
6167 }
62- next_time = cmt -> cmcor [ch ] - cmt -> cmcnt [ch ];
63- next_time *= NANOSECONDS_PER_SECOND ;
64- next_time /= cmt -> input_freq ;
65- /*
66- * CKS -> div rate
67- * 0 -> 8 (1 << 3)
68- * 1 -> 32 (1 << 5)
69- * 2 -> 128 (1 << 7)
70- * 3 -> 512 (1 << 9)
71- */
72- next_time *= 1 << (3 + FIELD_EX16 (cmt -> cmcr [ch ], CMCR , CKS ) * 2 );
73- next_time += qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
74- timer_mod (& cmt -> timer [ch ], next_time );
75- }
68+ uint16_t current = read_cmcnt (cmt , ch );
69+ uint32_t remain = (cmt -> cmcor [ch ] + 1 ) - current ;
70+ if (remain == 0 ) {
71+ remain = cmt -> cmcor [ch ] + 1 ;
72+ }
73+ int64_t next_time = (int64_t )remain * NANOSECONDS_PER_SECOND / cmt -> cmt_freq [ch ];
7674
77- static int64_t read_cmcnt (RCMTState * cmt , int ch )
78- {
79- int64_t delta , now = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
75+ int64_t now = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
76+ int64_t fire_time = now + next_time ;
8077
81- if (cmt -> cmstr & (1 << ch )) {
82- delta = (now - cmt -> tick [ch ]);
83- delta /= NANOSECONDS_PER_SECOND ;
84- delta /= cmt -> input_freq ;
85- delta /= 1 << (3 + FIELD_EX16 (cmt -> cmcr [ch ], CMCR , CKS ) * 2 );
86- cmt -> tick [ch ] = now ;
87- return cmt -> cmcnt [ch ] + delta ;
88- } else {
89- return cmt -> cmcnt [ch ];
78+ if (fire_time <= now ) {
79+ fire_time = now + 1 ;
9080 }
81+
82+ timer_mod (& cmt -> timer [ch ], fire_time );
9183}
9284
9385static uint64_t cmt_read (void * opaque , hwaddr offset , unsigned size )
9486{
9587 RCMTState * cmt = opaque ;
9688 int ch = offset / 0x08 ;
97- uint64_t ret ;
9889
9990 if (offset == A_CMSTR ) {
100- ret = 0 ;
101- ret = FIELD_DP16 (ret , CMSTR , STR ,
102- FIELD_EX16 (cmt -> cmstr , CMSTR , STR ));
103- return ret ;
91+ return FIELD_EX16 (cmt -> cmstr , CMSTR , STR );
10492 } else {
10593 offset &= 0x07 ;
10694 if (ch == 0 ) {
10795 offset -= 0x02 ;
10896 }
10997 switch (offset ) {
11098 case A_CMCR :
111- ret = 0 ;
112- ret = FIELD_DP16 (ret , CMCR , CKS ,
113- FIELD_EX16 (cmt -> cmstr , CMCR , CKS ));
114- ret = FIELD_DP16 (ret , CMCR , CMIE ,
115- FIELD_EX16 (cmt -> cmstr , CMCR , CMIE ));
116- return ret ;
99+ return cmt -> cmcr [ch ];
117100 case A_CMCNT :
118101 return read_cmcnt (cmt , ch );
119102 case A_CMCOR :
@@ -123,12 +106,13 @@ static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
123106 qemu_log_mask (LOG_UNIMP , "renesas_cmt: Register 0x%" HWADDR_PRIX " "
124107 "not implemented\n" ,
125108 offset );
126- return UINT64_MAX ;
109+ return UINT16_MAX ;
127110}
128111
129- static void start_stop (RCMTState * cmt , int ch , int st )
130- {
131- if (st ) {
112+ static void start_stop (RCMTState * cmt , int ch , int enable ) {
113+ if (enable ) {
114+ cmt -> cmcnt [ch ] = 0 ;
115+ cmt -> tick [ch ] = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
132116 update_events (cmt , ch );
133117 } else {
134118 timer_del (& cmt -> timer [ch ]);
@@ -155,9 +139,13 @@ static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
155139 FIELD_EX16 (val , CMCR , CKS ));
156140 cmt -> cmcr [ch ] = FIELD_DP16 (cmt -> cmcr [ch ], CMCR , CMIE ,
157141 FIELD_EX16 (val , CMCR , CMIE ));
142+ cmt -> cmt_freq [ch ] =
143+ cmt -> input_freq / (8u << (2 * FIELD_EX16 (cmt -> cmcr [ch ], CMCR , CKS )));
144+ update_events (cmt , ch );
158145 break ;
159146 case 2 :
160147 cmt -> cmcnt [ch ] = val ;
148+ cmt -> tick [ch ] = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
161149 break ;
162150 case 4 :
163151 cmt -> cmcor [ch ] = val ;
@@ -216,26 +204,29 @@ static void rcmt_reset(DeviceState *dev)
216204{
217205 RCMTState * cmt = RCMT (dev );
218206 cmt -> cmstr = 0 ;
219- cmt -> cmcr [0 ] = cmt -> cmcr [1 ] = 0 ;
220- cmt -> cmcnt [0 ] = cmt -> cmcnt [1 ] = 0 ;
221- cmt -> cmcor [0 ] = cmt -> cmcor [1 ] = 0xffff ;
207+ for (int i = 0 ; i < CMT_CH ; i ++ ) {
208+ cmt -> cmcr [i ] = 0 ;
209+ cmt -> cmcnt [i ] = 0 ;
210+ cmt -> cmcor [i ] = 0xFFFF ;
211+ cmt -> tick [i ] = 0 ;
212+ }
222213}
223214
224215static void rcmt_init (Object * obj )
225216{
226217 SysBusDevice * d = SYS_BUS_DEVICE (obj );
227218 RCMTState * cmt = RCMT (obj );
228- int i ;
229219
230220 memory_region_init_io (& cmt -> memory , OBJECT (cmt ), & cmt_ops ,
231221 cmt , "renesas-cmt" , 0x10 );
232222 sysbus_init_mmio (d , & cmt -> memory );
233223
234- for (i = 0 ; i < ARRAY_SIZE ( cmt -> cmi ) ; i ++ ) {
224+ for (int i = 0 ; i < CMT_CH ; i ++ ) {
235225 sysbus_init_irq (d , & cmt -> cmi [i ]);
226+ cmt -> cmt_freq [i ] = cmt -> input_freq >> 3 ;
227+ timer_init_ns (& cmt -> timer [i ], QEMU_CLOCK_VIRTUAL ,
228+ (i == 0 ? timer_event0 : timer_event1 ), cmt );
236229 }
237- timer_init_ns (& cmt -> timer [0 ], QEMU_CLOCK_VIRTUAL , timer_event0 , cmt );
238- timer_init_ns (& cmt -> timer [1 ], QEMU_CLOCK_VIRTUAL , timer_event1 , cmt );
239230}
240231
241232static const VMStateDescription vmstate_rcmt = {
0 commit comments