@@ -51,69 +51,52 @@ REG16(CMCR, 0)
51
51
REG16 (CMCNT , 2 )
52
52
REG16 (CMCOR , 4 )
53
53
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
+ }
57
63
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 ))) {
60
66
return ;
61
67
}
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 ];
76
74
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 ;
80
77
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 ;
90
80
}
81
+
82
+ timer_mod (& cmt -> timer [ch ], fire_time );
91
83
}
92
84
93
85
static uint64_t cmt_read (void * opaque , hwaddr offset , unsigned size )
94
86
{
95
87
RCMTState * cmt = opaque ;
96
88
int ch = offset / 0x08 ;
97
- uint64_t ret ;
98
89
99
90
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 );
104
92
} else {
105
93
offset &= 0x07 ;
106
94
if (ch == 0 ) {
107
95
offset -= 0x02 ;
108
96
}
109
97
switch (offset ) {
110
98
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 ];
117
100
case A_CMCNT :
118
101
return read_cmcnt (cmt , ch );
119
102
case A_CMCOR :
@@ -123,12 +106,13 @@ static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
123
106
qemu_log_mask (LOG_UNIMP , "renesas_cmt: Register 0x%" HWADDR_PRIX " "
124
107
"not implemented\n" ,
125
108
offset );
126
- return UINT64_MAX ;
109
+ return UINT16_MAX ;
127
110
}
128
111
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 );
132
116
update_events (cmt , ch );
133
117
} else {
134
118
timer_del (& cmt -> timer [ch ]);
@@ -155,9 +139,13 @@ static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
155
139
FIELD_EX16 (val , CMCR , CKS ));
156
140
cmt -> cmcr [ch ] = FIELD_DP16 (cmt -> cmcr [ch ], CMCR , CMIE ,
157
141
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 );
158
145
break ;
159
146
case 2 :
160
147
cmt -> cmcnt [ch ] = val ;
148
+ cmt -> tick [ch ] = qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL );
161
149
break ;
162
150
case 4 :
163
151
cmt -> cmcor [ch ] = val ;
@@ -216,26 +204,29 @@ static void rcmt_reset(DeviceState *dev)
216
204
{
217
205
RCMTState * cmt = RCMT (dev );
218
206
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
+ }
222
213
}
223
214
224
215
static void rcmt_init (Object * obj )
225
216
{
226
217
SysBusDevice * d = SYS_BUS_DEVICE (obj );
227
218
RCMTState * cmt = RCMT (obj );
228
- int i ;
229
219
230
220
memory_region_init_io (& cmt -> memory , OBJECT (cmt ), & cmt_ops ,
231
221
cmt , "renesas-cmt" , 0x10 );
232
222
sysbus_init_mmio (d , & cmt -> memory );
233
223
234
- for (i = 0 ; i < ARRAY_SIZE ( cmt -> cmi ) ; i ++ ) {
224
+ for (int i = 0 ; i < CMT_CH ; i ++ ) {
235
225
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 );
236
229
}
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 );
239
230
}
240
231
241
232
static const VMStateDescription vmstate_rcmt = {
0 commit comments