Skip to content

Commit ce7d330

Browse files
committed
target/arc: Don't use a timer for RTC and enable it by default
Using QTimer for RTC implementation is redundent and meaningless since it's just free-running clock. Also, enable RTC by default. If it's not available then Linux uses Timer 1 as fallback which is much less accurate. Signed-off-by: Yuriy Kolerov <ykolerov@synopsys.com>
1 parent d152379 commit ce7d330

File tree

4 files changed

+202
-119
lines changed

4 files changed

+202
-119
lines changed

target/arc/cpu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ static Property arc_cpu_properties[] = {
6565
DEFINE_PROP_UINT32("pc-size", ARCCPU, cfg.pc_size, 32),
6666
DEFINE_PROP_UINT32("num-regs", ARCCPU, cfg.rgf_num_regs, 32),
6767
DEFINE_PROP_UINT32("num-banks", ARCCPU, cfg.rgf_num_banks, 0),
68-
DEFINE_PROP_BOOL("rtc-opt", ARCCPU, cfg.rtc_option, false),
68+
DEFINE_PROP_BOOL("rtc-opt", ARCCPU, cfg.rtc_option, true),
6969
DEFINE_PROP_UINT32("freq_hz", ARCCPU, cfg.freq_hz, 4600000),
7070

7171
DEFINE_PROP_STRING("mmuv6-version", ARCCPU, cfg.mmuv6_version),

target/arc/cpu.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ typedef struct {
213213
uint64_t last_clk;
214214
} ARCTimer;
215215

216+
typedef struct {
217+
uint32_t low;
218+
uint32_t high;
219+
uint32_t ctrl;
220+
uint64_t stop_cycles;
221+
uint64_t stop_time_ns;
222+
uint64_t base_time_ns;
223+
} ARCRealTimeCounter;
224+
216225
/* ARC PIC interrupt bancked regs. */
217226
typedef struct {
218227
target_ulong priority;
@@ -259,6 +268,7 @@ struct CPUArchState {
259268
#define TMR_IP (1 << 3)
260269
#define TMR_PD (1 << 4)
261270
ARCTimer timer[2]; /* ARC CPU-Timer 0/1 */
271+
ARCRealTimeCounter rtc;
262272

263273
/* TODO: Verify correctness of this types for both ARCv2 and v3. */
264274
ARCIrq irq_bank[256]; /* IRQ register bank */
@@ -269,9 +279,6 @@ struct CPUArchState {
269279
uint32_t aux_irq_hint; /* AUX register, used to trigger soft irq */
270280
target_ulong aux_user_sp;
271281
uint32_t aux_irq_ctrl;
272-
uint32_t aux_rtc_ctrl;
273-
uint32_t aux_rtc_low;
274-
uint32_t aux_rtc_high;
275282

276283
/* TODO: This one in particular. */
277284
/* Fields required by exception handling. */
@@ -291,11 +298,8 @@ struct CPUArchState {
291298
/* Fields up to this point are cleared by a CPU reset */
292299
struct {} end_reset_fields;
293300

294-
uint64_t last_clk_rtc;
295-
296301
void *irq[256];
297302
QEMUTimer *cpu_timer[2]; /* Internal timer. */
298-
QEMUTimer *cpu_rtc; /* Internal RTC. */
299303

300304
const struct arc_boot_info *boot_info;
301305

target/arc/timer.c

Lines changed: 135 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,27 @@ static uint64_t get_ns(CPUARCState *env)
4646
#endif
4747
}
4848

49+
uint64_t arc_get_cycles(CPUARCState *env)
50+
{
51+
uint64_t diff = get_ns(env) - env->rtc.base_time_ns;
52+
53+
/*
54+
* In user mode host's cycles are stored in base_time_ns and get_ns()
55+
* returns host cycles. Thus, return just a difference in this case
56+
* without converting from nanoseconds to cycles.
57+
*/
58+
#ifndef CONFIG_USER_ONLY
59+
return NS_TO_CYCLE(diff);
60+
#else
61+
return diff;
62+
#endif
63+
}
64+
65+
uint64_t arc_get_global_cycles(void)
66+
{
67+
return arc_get_cycles(&ARC_CPU(first_cpu)->env);
68+
}
69+
4970
static uint32_t get_t_count(CPUARCState *env, uint32_t t)
5071
{
5172
#ifndef CONFIG_USER_ONLY
@@ -141,78 +162,6 @@ static void arc_timer1_cb(void *opaque)
141162
}
142163
#endif
143164

144-
/* RTC counter update. */
145-
static void cpu_rtc_count_update(CPUARCState *env)
146-
{
147-
uint64_t now;
148-
uint64_t llreg;
149-
150-
assert((env_archcpu(env)->timer_build & TB_RTC) && env->cpu_rtc);
151-
now = get_ns(env);
152-
153-
if (!(env->aux_rtc_ctrl & 0x01)) {
154-
return;
155-
}
156-
157-
llreg = ((now - env->last_clk_rtc) / TIMER_PERIOD(FREQ_HZ));
158-
llreg += env->aux_rtc_low + ((uint64_t)env->aux_rtc_high << 32);
159-
env->aux_rtc_high = llreg >> 32;
160-
env->aux_rtc_low = (uint32_t) llreg;
161-
162-
env->last_clk_rtc = now;
163-
qemu_log_mask(LOG_UNIMP, "[RTC] RTC count-regs update\n");
164-
}
165-
166-
#ifndef CONFIG_USER_ONLY
167-
/* Update the next timeout time as difference between Count and Limit */
168-
static void cpu_rtc_update(CPUARCState *env)
169-
{
170-
uint64_t wait = 0;
171-
uint64_t now, period;
172-
uint64_t next;
173-
174-
assert(env->cpu_rtc);
175-
now = get_ns(env);
176-
177-
if (!(env->aux_rtc_ctrl & 0x01)) {
178-
return;
179-
}
180-
181-
period = TIMER_PERIOD(FREQ_HZ);
182-
wait = UINT64_MAX - ((((uint64_t) env->aux_rtc_high) << 32)
183-
+ env->aux_rtc_low);
184-
wait -= (now - env->last_clk_rtc) / period;
185-
186-
/* Limit timeout rate. */
187-
if ((wait * period) < TIMEOUT_LIMIT) {
188-
period = TIMEOUT_LIMIT / wait;
189-
}
190-
191-
next = now + (uint64_t) wait * period;
192-
timer_mod(env->cpu_rtc, next);
193-
qemu_log_mask(LOG_UNIMP, "[RTC] RTC update\n");
194-
}
195-
#endif
196-
197-
#ifndef CONFIG_USER_ONLY
198-
/* RTC call back routine. */
199-
static void arc_rtc_cb(void *opaque)
200-
{
201-
CPUARCState *env = (CPUARCState *) opaque;
202-
203-
if (!(env_archcpu(env)->timer_build & TB_RTC)) {
204-
return;
205-
}
206-
207-
qemu_log_mask(LOG_UNIMP, "[RTC] RTC expired\n");
208-
209-
env->aux_rtc_high = 0;
210-
env->aux_rtc_low = 0;
211-
env->last_clk_rtc = get_ns(env);
212-
cpu_rtc_update(env);
213-
}
214-
#endif
215-
216165
/* Helper used when resetting the system. */
217166
static void cpu_arc_count_reset(CPUARCState *env, uint32_t timer)
218167
{
@@ -284,35 +233,88 @@ static void cpu_arc_control_set(CPUARCState *env,
284233
}
285234
}
286235

287-
/* Get The RTC count value. */
288-
static uint32_t arc_rtc_count_get(CPUARCState *env, bool lower)
236+
#if defined(TARGET_ARC64)
237+
static uint64_t arc_rtc_count_get_low(CPUARCState *env)
289238
{
290-
cpu_rtc_count_update(env);
291-
return lower ? env->aux_rtc_low : env->aux_rtc_high;
239+
uint8_t enabled = FIELD_EX32(env->rtc.ctrl, ARC_RTC_CTRL, ENABLE);
240+
241+
if (enabled) {
242+
return arc_get_cycles(env);
243+
} else {
244+
return env->rtc.stop_cycles;
245+
}
292246
}
247+
#else
248+
static uint32_t arc_rtc_count_get_low(CPUARCState *env)
249+
{
250+
uint8_t enabled = FIELD_EX32(env->rtc.ctrl, ARC_RTC_CTRL, ENABLE);
251+
uint64_t cycles;
252+
253+
if (enabled) {
254+
cycles = arc_get_cycles(env);
255+
} else {
256+
cycles = env->rtc.stop_cycles;
257+
}
258+
259+
/*
260+
* If RTC is enabled then update (high,low) pair with the latest cycles
261+
* count. Otherwise, don't update it and use the old value.
262+
*/
263+
env->rtc.low = cycles & 0xFFFFFFFF;
264+
env->rtc.high = (cycles >> 32) & 0xFFFFFFFF;
265+
266+
return env->rtc.low;
267+
}
268+
269+
static uint32_t arc_rtc_count_get_high(CPUARCState *env)
270+
{
271+
return env->rtc.high;
272+
}
273+
#endif
293274

294275
/* Set the RTC control bits. */
295276
static void arc_rtc_ctrl_set(CPUARCState *env, uint32_t val)
296277
{
297278
#ifndef CONFIG_USER_ONLY
279+
uint8_t enable = FIELD_EX32(val, ARC_RTC_CTRL, ENABLE);
280+
uint8_t enabled = FIELD_EX32(env->rtc.ctrl, ARC_RTC_CTRL, ENABLE);
281+
uint8_t clear = FIELD_EX32(val, ARC_RTC_CTRL, CLEAR);
282+
298283
assert(GET_STATUS_BIT(env->stat, Uf) == 0);
299284

300-
if (val & 0x02) {
301-
env->aux_rtc_low = 0;
302-
env->aux_rtc_high = 0;
303-
env->last_clk_rtc = get_ns(env);
285+
/* Case: RTC is enabled and it's going to be disabled.
286+
* Remember stop time and save the latest cycles count for further using.
287+
*/
288+
if (enabled && !enable) {
289+
env->rtc.stop_time_ns = get_ns(env);
290+
env->rtc.stop_cycles = arc_get_cycles(env);
304291
}
305-
if (!(val & 0x01)) {
306-
timer_del(env->cpu_rtc);
292+
293+
if (clear) {
294+
env->rtc.base_time_ns = get_ns(env);
295+
296+
/*
297+
* If RTC is stopped then remember stop time - it will allow to reset
298+
* the counter after reactivating the RTC.
299+
*/
300+
if (!enabled) {
301+
env->rtc.stop_time_ns = env->rtc.base_time_ns;
302+
env->rtc.stop_cycles = 0;
303+
}
307304
}
308305

309-
/* Restart RTC, update last clock. */
310-
if ((env->aux_rtc_ctrl & 0x01) == 0 && (val & 0x01)) {
311-
env->last_clk_rtc = get_ns(env);
306+
/*
307+
* Case: RTC is disabled and it's going to be enabled.
308+
* Increase base time to fill the gap between stop and now.
309+
*/
310+
if (!enabled && enable) {
311+
env->rtc.base_time_ns += get_ns(env) - env->rtc.stop_time_ns;
312312
}
313313

314-
env->aux_rtc_ctrl = 0xc0000000 | (val & 0x01);
315-
cpu_rtc_update(env);
314+
/* Always set atomicity bits since. */
315+
env->rtc.ctrl = FIELD_DP32(env->rtc.ctrl, ARC_RTC_CTRL, ENABLE, enable);
316+
env->rtc.ctrl = FIELD_DP32(env->rtc.ctrl, ARC_RTC_CTRL, A0, 1);
317+
env->rtc.ctrl = FIELD_DP32(env->rtc.ctrl, ARC_RTC_CTRL, A1, 1);
316318
#endif
317319
}
318320

@@ -324,47 +326,65 @@ cpu_arc_clock_init(ARCCPU *cpu)
324326
CPUARCState *env = &cpu->env;
325327

326328
#ifndef CONFIG_USER_ONLY
327-
if (env_archcpu(env)->timer_build & TB_T0) {
328-
env->cpu_timer[0] =
329-
timer_new_ns(QEMU_CLOCK_VIRTUAL, &arc_timer0_cb, env);
329+
if (FIELD_EX32(cpu->timer_build, ARC_TIMER_BUILD, T0)) {
330+
env->cpu_timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, &arc_timer0_cb, env);
330331
}
331332

332-
if (env_archcpu(env)->timer_build & TB_T1) {
333-
env->cpu_timer[1] =
334-
timer_new_ns(QEMU_CLOCK_VIRTUAL, &arc_timer1_cb, env);
335-
}
336-
337-
if (env_archcpu(env)->timer_build & TB_RTC) {
338-
env->cpu_rtc =
339-
timer_new_ns(QEMU_CLOCK_VIRTUAL, &arc_rtc_cb, env);
333+
if (FIELD_EX32(cpu->timer_build, ARC_TIMER_BUILD, T1)) {
334+
env->cpu_timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, &arc_timer1_cb, env);
340335
}
341336
#endif
342337

343338
env->timer[0].last_clk = get_ns(env);
344339
env->timer[1].last_clk = get_ns(env);
345340
}
346341

347-
void
348-
arc_initializeTIMER(ARCCPU *cpu)
342+
/*
343+
* TODO: Implement setting default interrupt priorities for Timer 0 and Timer 1.
344+
*/
345+
346+
void arc_initializeTIMER(ARCCPU *cpu)
349347
{
350-
CPUARCState *env = &cpu->env;
348+
uint32_t build = 0;
349+
uint8_t version;
350+
351+
switch (cpu->family) {
352+
case ARC_OPCODE_ARC64:
353+
version = 0x7;
354+
break;
355+
case ARC_OPCODE_ARC32:
356+
version = 0x6;
357+
break;
358+
default:
359+
version = 0x4;
360+
}
361+
362+
build = FIELD_DP32(build, ARC_TIMER_BUILD, VERSION, version);
363+
364+
if (cpu->cfg.has_timer_0) {
365+
build = FIELD_DP32(build, ARC_TIMER_BUILD, T0, 1);
366+
}
367+
368+
if (cpu->cfg.has_timer_1) {
369+
build = FIELD_DP32(build, ARC_TIMER_BUILD, T1, 1);
370+
}
371+
372+
if (cpu->cfg.rtc_option) {
373+
build = FIELD_DP32(build, ARC_TIMER_BUILD, RTC, 1);
374+
}
351375

352-
/* FIXME! add default timer priorities. */
353-
env_archcpu(env)->timer_build = 0x04 | (cpu->cfg.has_timer_0 ? TB_T0 : 0) |
354-
(cpu->cfg.has_timer_1 ? TB_T1 : 0) |
355-
(cpu->cfg.rtc_option ? TB_RTC : 0);
376+
cpu->timer_build = build;
356377
}
357378

358-
void
359-
arc_resetTIMER(ARCCPU *cpu)
379+
void arc_resetTIMER(ARCCPU *cpu)
360380
{
361381
CPUARCState *env = &cpu->env;
362382

363-
if (env_archcpu(env)->timer_build & TB_T0) {
383+
if (FIELD_EX32(cpu->timer_build, ARC_TIMER_BUILD, T0)) {
364384
cpu_arc_count_reset(env, 0);
365385
}
366386

367-
if (env_archcpu(env)->timer_build & TB_T1) {
387+
if (FIELD_EX32(cpu->timer_build, ARC_TIMER_BUILD, T1)) {
368388
cpu_arc_count_reset(env, 1);
369389
}
370390
}
@@ -405,15 +425,18 @@ aux_timer_get(const struct arc_aux_reg_detail *aux_reg_detail, void *data)
405425
break;
406426

407427
case AUX_ID_aux_rtc_low:
408-
return arc_rtc_count_get(env, true);
428+
return arc_rtc_count_get_low(env);
409429
break;
410430

431+
#if !defined(TARGET_ARC64)
432+
/* AUX_RTC_HIGH register is not presented on ARC HS6x processors. */
411433
case AUX_ID_aux_rtc_high:
412-
return arc_rtc_count_get(env, false);
434+
return arc_rtc_count_get_high(env);
413435
break;
436+
#endif
414437

415438
case AUX_ID_aux_rtc_ctrl:
416-
return env->aux_rtc_ctrl;
439+
return env->rtc.ctrl;
417440
break;
418441

419442
default:

0 commit comments

Comments
 (0)