Revision cd1a3f68
b/Makefile.target | ||
---|---|---|
476 | 476 |
endif |
477 | 477 |
ifeq ($(TARGET_BASE_ARCH), sh4) |
478 | 478 |
VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o |
479 |
VL_OBJS+= sh_timer.o ptimer.o |
|
479 | 480 |
endif |
480 | 481 |
ifeq ($(TARGET_BASE_ARCH), m68k) |
481 | 482 |
VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o |
b/hw/sh7750.c | ||
---|---|---|
64 | 64 |
uint8_t scbrr2; |
65 | 65 |
fifo serial2_receive_fifo; |
66 | 66 |
fifo serial2_transmit_fifo; |
67 |
/* Timers */ |
|
68 |
uint8_t tstr; |
|
69 |
/* Timer 0 */ |
|
70 |
QEMUTimer *timer0; |
|
71 |
uint16_t tcr0; |
|
72 |
uint32_t tcor0; |
|
73 |
uint32_t tcnt0; |
|
74 | 67 |
/* IO ports */ |
75 | 68 |
uint16_t gpioic; |
76 | 69 |
uint32_t pctra; |
... | ... | |
88 | 81 |
sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ |
89 | 82 |
/* Cache */ |
90 | 83 |
uint32_t ccr; |
91 |
} SH7750State; |
|
92 |
|
|
93 |
/********************************************************************** |
|
94 |
Timers |
|
95 |
**********************************************************************/ |
|
96 |
|
|
97 |
/* XXXXX At this time, timer0 works in underflow only mode, that is |
|
98 |
the value of tcnt0 is read at alarm computation time and cannot |
|
99 |
be read back by the guest OS */ |
|
100 |
|
|
101 |
static void start_timer0(SH7750State * s) |
|
102 |
{ |
|
103 |
uint64_t now, next, prescaler; |
|
104 |
|
|
105 |
if ((s->tcr0 & 6) == 6) { |
|
106 |
fprintf(stderr, "rtc clock for timer 0 not supported\n"); |
|
107 |
assert(0); |
|
108 |
} |
|
109 | 84 |
|
110 |
if ((s->tcr0 & 7) == 5) { |
|
111 |
fprintf(stderr, "timer 0 configuration not supported\n"); |
|
112 |
assert(0); |
|
113 |
} |
|
114 |
|
|
115 |
if ((s->tcr0 & 4) == 4) |
|
116 |
prescaler = 1024; |
|
117 |
else |
|
118 |
prescaler = 4 << (s->tcr0 & 3); |
|
119 |
|
|
120 |
now = qemu_get_clock(vm_clock); |
|
121 |
/* XXXXX */ |
|
122 |
next = |
|
123 |
now + muldiv64(prescaler * s->tcnt0, ticks_per_sec, |
|
124 |
s->periph_freq); |
|
125 |
if (next == now) |
|
126 |
next = now + 1; |
|
127 |
fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); |
|
128 |
fprintf(stderr, "timer will underflow in %f seconds\n", |
|
129 |
(float) (next - now) / (float) ticks_per_sec); |
|
130 |
|
|
131 |
qemu_mod_timer(s->timer0, next); |
|
132 |
} |
|
133 |
|
|
134 |
static void timer_start_changed(SH7750State * s) |
|
135 |
{ |
|
136 |
if (s->tstr & SH7750_TSTR_STR0) { |
|
137 |
start_timer0(s); |
|
138 |
} else { |
|
139 |
fprintf(stderr, "timer 0 is stopped\n"); |
|
140 |
qemu_del_timer(s->timer0); |
|
141 |
} |
|
142 |
} |
|
143 |
|
|
144 |
static void timer0_cb(void *opaque) |
|
145 |
{ |
|
146 |
SH7750State *s = opaque; |
|
147 |
|
|
148 |
s->tcnt0 = (uint32_t) 0; /* XXXXX */ |
|
149 |
if (--s->tcnt0 == (uint32_t) - 1) { |
|
150 |
fprintf(stderr, "timer 0 underflow\n"); |
|
151 |
s->tcnt0 = s->tcor0; |
|
152 |
s->tcr0 |= SH7750_TCR_UNF; |
|
153 |
if (s->tcr0 & SH7750_TCR_UNIE) { |
|
154 |
fprintf(stderr, |
|
155 |
"interrupt generation for timer 0 not supported\n"); |
|
156 |
assert(0); |
|
157 |
} |
|
158 |
} |
|
159 |
start_timer0(s); |
|
160 |
} |
|
161 |
|
|
162 |
static void init_timers(SH7750State * s) |
|
163 |
{ |
|
164 |
s->tcor0 = 0xffffffff; |
|
165 |
s->tcnt0 = 0xffffffff; |
|
166 |
s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s); |
|
167 |
} |
|
85 |
} SH7750State; |
|
168 | 86 |
|
169 | 87 |
/********************************************************************** |
170 | 88 |
First serial port |
... | ... | |
581 | 499 |
fprintf(stderr, |
582 | 500 |
"Read access to refresh count register, incrementing\n"); |
583 | 501 |
return s->rfcr++; |
584 |
case SH7750_TCR0_A7: |
|
585 |
return s->tcr0; |
|
586 | 502 |
case SH7750_SCLSR2_A7: |
587 | 503 |
/* Read and clear overflow bit */ |
588 | 504 |
r = s->sclsr2; |
... | ... | |
649 | 565 |
case SH7750_SCBRR2_A7: |
650 | 566 |
s->scbrr2 = mem_value; |
651 | 567 |
return; |
652 |
case SH7750_TSTR_A7: |
|
653 |
s->tstr = mem_value; |
|
654 |
timer_start_changed(s); |
|
655 |
return; |
|
656 | 568 |
case SH7750_SCSCR1_A7: |
657 | 569 |
s->scscr1 = mem_value; |
658 | 570 |
scscr1_changed(s); |
... | ... | |
721 | 633 |
case SH7750_SCSMR2_A7: |
722 | 634 |
s->scsmr2 = mem_value; |
723 | 635 |
return; |
724 |
case SH7750_TCR0_A7: |
|
725 |
s->tcr0 = mem_value; |
|
726 |
return; |
|
727 | 636 |
case SH7750_GPIOIC_A7: |
728 | 637 |
s->gpioic = mem_value; |
729 | 638 |
if (mem_value != 0) { |
... | ... | |
768 | 677 |
s->portpullupb = portpullup(mem_value); |
769 | 678 |
portb_changed(s, temp); |
770 | 679 |
return; |
771 |
case SH7750_TCNT0_A7: |
|
772 |
s->tcnt0 = mem_value & 0xf; |
|
773 |
return; |
|
774 | 680 |
case SH7750_MMUCR_A7: |
775 | 681 |
s->cpu->mmucr = mem_value; |
776 | 682 |
return; |
... | ... | |
828 | 734 |
sh7750_mem_read, |
829 | 735 |
sh7750_mem_write, s); |
830 | 736 |
cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); |
831 |
init_timers(s); |
|
832 | 737 |
init_serial_ports(s); |
738 |
|
|
739 |
tmu012_init(0x1fd80000, |
|
740 |
TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, |
|
741 |
s->periph_freq); |
|
742 |
tmu012_init(0x1e100000, 0, s->periph_freq); |
|
833 | 743 |
return s; |
834 | 744 |
} |
b/hw/sh7750_regnames.c | ||
---|---|---|
42 | 42 |
REGNAME(SH7750_RMONAR_A7) |
43 | 43 |
REGNAME(SH7750_RCR1_A7) |
44 | 44 |
REGNAME(SH7750_RCR2_A7) |
45 |
REGNAME(SH7750_TOCR_A7) |
|
46 |
REGNAME(SH7750_TSTR_A7) |
|
47 |
REGNAME(SH7750_TCOR0_A7) |
|
48 |
REGNAME(SH7750_TCOR1_A7) |
|
49 |
REGNAME(SH7750_TCOR2_A7) |
|
50 |
REGNAME(SH7750_TCNT0_A7) |
|
51 |
REGNAME(SH7750_TCNT1_A7) |
|
52 |
REGNAME(SH7750_TCNT2_A7) |
|
53 |
REGNAME(SH7750_TCR0_A7) |
|
54 |
REGNAME(SH7750_TCR1_A7) |
|
55 |
REGNAME(SH7750_TCR2_A7) |
|
56 |
REGNAME(SH7750_TCPR2_A7) |
|
57 | 45 |
REGNAME(SH7750_BCR1_A7) |
58 | 46 |
REGNAME(SH7750_BCR2_A7) |
59 | 47 |
REGNAME(SH7750_WCR1_A7) |
b/hw/sh7750_regs.h | ||
---|---|---|
524 | 524 |
year counters are stopped |
525 | 525 |
1 - sec, min, hr, day-of-week, month, |
526 | 526 |
year counters operate normally */ |
527 |
|
|
528 |
|
|
529 |
/* |
|
530 |
* Timer Unit (TMU) |
|
531 |
*/ |
|
532 |
/* Timer Output Control Register (byte) - TOCR */ |
|
533 |
#define SH7750_TOCR_REGOFS 0xD80000 /* offset */ |
|
534 |
#define SH7750_TOCR SH7750_P4_REG32(SH7750_TOCR_REGOFS) |
|
535 |
#define SH7750_TOCR_A7 SH7750_A7_REG32(SH7750_TOCR_REGOFS) |
|
536 |
#define SH7750_TOCR_TCOE 0x01 /* Timer Clock Pin Control: |
|
537 |
0 - TCLK is used as external clock |
|
538 |
input or input capture control |
|
539 |
1 - TCLK is used as on-chip RTC |
|
540 |
output clock pin */ |
|
541 |
|
|
542 |
/* Timer Start Register (byte) - TSTR */ |
|
543 |
#define SH7750_TSTR_REGOFS 0xD80004 /* offset */ |
|
544 |
#define SH7750_TSTR SH7750_P4_REG32(SH7750_TSTR_REGOFS) |
|
545 |
#define SH7750_TSTR_A7 SH7750_A7_REG32(SH7750_TSTR_REGOFS) |
|
546 |
#define SH7750_TSTR_STR2 0x04 /* TCNT2 performs count operations */ |
|
547 |
#define SH7750_TSTR_STR1 0x02 /* TCNT1 performs count operations */ |
|
548 |
#define SH7750_TSTR_STR0 0x01 /* TCNT0 performs count operations */ |
|
549 |
#define SH7750_TSTR_STR(n) (1 << (n)) |
|
550 |
|
|
551 |
/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */ |
|
552 |
#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12)) /* offset */ |
|
553 |
#define SH7750_TCOR(n) SH7750_P4_REG32(SH7750_TCOR_REGOFS(n)) |
|
554 |
#define SH7750_TCOR_A7(n) SH7750_A7_REG32(SH7750_TCOR_REGOFS(n)) |
|
555 |
#define SH7750_TCOR0 SH7750_TCOR(0) |
|
556 |
#define SH7750_TCOR1 SH7750_TCOR(1) |
|
557 |
#define SH7750_TCOR2 SH7750_TCOR(2) |
|
558 |
#define SH7750_TCOR0_A7 SH7750_TCOR_A7(0) |
|
559 |
#define SH7750_TCOR1_A7 SH7750_TCOR_A7(1) |
|
560 |
#define SH7750_TCOR2_A7 SH7750_TCOR_A7(2) |
|
561 |
|
|
562 |
/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */ |
|
563 |
#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12)) /* offset */ |
|
564 |
#define SH7750_TCNT(n) SH7750_P4_REG32(SH7750_TCNT_REGOFS(n)) |
|
565 |
#define SH7750_TCNT_A7(n) SH7750_A7_REG32(SH7750_TCNT_REGOFS(n)) |
|
566 |
#define SH7750_TCNT0 SH7750_TCNT(0) |
|
567 |
#define SH7750_TCNT1 SH7750_TCNT(1) |
|
568 |
#define SH7750_TCNT2 SH7750_TCNT(2) |
|
569 |
#define SH7750_TCNT0_A7 SH7750_TCNT_A7(0) |
|
570 |
#define SH7750_TCNT1_A7 SH7750_TCNT_A7(1) |
|
571 |
#define SH7750_TCNT2_A7 SH7750_TCNT_A7(2) |
|
572 |
|
|
573 |
/* Timer Control Register (half) - TCR0, TCR1, TCR2 */ |
|
574 |
#define SH7750_TCR_REGOFS(n) (0xD80010 + ((n)*12)) /* offset */ |
|
575 |
#define SH7750_TCR(n) SH7750_P4_REG32(SH7750_TCR_REGOFS(n)) |
|
576 |
#define SH7750_TCR_A7(n) SH7750_A7_REG32(SH7750_TCR_REGOFS(n)) |
|
577 |
#define SH7750_TCR0 SH7750_TCR(0) |
|
578 |
#define SH7750_TCR1 SH7750_TCR(1) |
|
579 |
#define SH7750_TCR2 SH7750_TCR(2) |
|
580 |
#define SH7750_TCR0_A7 SH7750_TCR_A7(0) |
|
581 |
#define SH7750_TCR1_A7 SH7750_TCR_A7(1) |
|
582 |
#define SH7750_TCR2_A7 SH7750_TCR_A7(2) |
|
583 |
|
|
584 |
#define SH7750_TCR2_ICPF 0x200 /* Input Capture Interrupt Flag |
|
585 |
(1 - input capture has occured) */ |
|
586 |
#define SH7750_TCR_UNF 0x100 /* Underflow flag */ |
|
587 |
#define SH7750_TCR2_ICPE 0x0C0 /* Input Capture Control: */ |
|
588 |
#define SH7750_TCR2_ICPE_DIS 0x000 /* Input Capture function is not used */ |
|
589 |
#define SH7750_TCR2_ICPE_NOINT 0x080 /* Input Capture function is used, but |
|
590 |
input capture interrupt is not |
|
591 |
enabled */ |
|
592 |
#define SH7750_TCR2_ICPE_INT 0x0C0 /* Input Capture function is used, |
|
593 |
input capture interrupt enabled */ |
|
594 |
#define SH7750_TCR_UNIE 0x020 /* Underflow Interrupt Control |
|
595 |
(1 - underflow interrupt enabled) */ |
|
596 |
#define SH7750_TCR_CKEG 0x018 /* Clock Edge selection: */ |
|
597 |
#define SH7750_TCR_CKEG_RAISE 0x000 /* Count/capture on rising edge */ |
|
598 |
#define SH7750_TCR_CKEG_FALL 0x008 /* Count/capture on falling edge */ |
|
599 |
#define SH7750_TCR_CKEG_BOTH 0x018 /* Count/capture on both rising and |
|
600 |
falling edges */ |
|
601 |
#define SH7750_TCR_TPSC 0x007 /* Timer prescaler */ |
|
602 |
#define SH7750_TCR_TPSC_DIV4 0x000 /* Counts on peripheral clock/4 */ |
|
603 |
#define SH7750_TCR_TPSC_DIV16 0x001 /* Counts on peripheral clock/16 */ |
|
604 |
#define SH7750_TCR_TPSC_DIV64 0x002 /* Counts on peripheral clock/64 */ |
|
605 |
#define SH7750_TCR_TPSC_DIV256 0x003 /* Counts on peripheral clock/256 */ |
|
606 |
#define SH7750_TCR_TPSC_DIV1024 0x004 /* Counts on peripheral clock/1024 */ |
|
607 |
#define SH7750_TCR_TPSC_RTC 0x006 /* Counts on on-chip RTC output clk */ |
|
608 |
#define SH7750_TCR_TPSC_EXT 0x007 /* Counts on external clock */ |
|
609 |
|
|
610 |
/* Input Capture Register (read-only) - TCPR2 */ |
|
611 |
#define SH7750_TCPR2_REGOFS 0xD8002C /* offset */ |
|
612 |
#define SH7750_TCPR2 SH7750_P4_REG32(SH7750_TCPR2_REGOFS) |
|
613 |
#define SH7750_TCPR2_A7 SH7750_A7_REG32(SH7750_TCPR2_REGOFS) |
|
614 |
|
|
615 | 527 |
/* |
616 | 528 |
* Bus State Controller - BSC |
617 | 529 |
*/ |
b/hw/sh_timer.c | ||
---|---|---|
1 |
/* |
|
2 |
* SuperH Timer modules. |
|
3 |
* |
|
4 |
* Copyright (c) 2007 Magnus Damm |
|
5 |
* Based on arm_timer.c by Paul Brook |
|
6 |
* Copyright (c) 2005-2006 CodeSourcery. |
|
7 |
* |
|
8 |
* This code is licenced under the GPL. |
|
9 |
*/ |
|
10 |
|
|
11 |
#include "vl.h" |
|
12 |
|
|
13 |
//#define DEBUG_TIMER |
|
14 |
|
|
15 |
#define TIMER_TCR_TPSC (7 << 0) |
|
16 |
#define TIMER_TCR_CKEG (3 << 3) |
|
17 |
#define TIMER_TCR_UNIE (1 << 5) |
|
18 |
#define TIMER_TCR_ICPE (3 << 6) |
|
19 |
#define TIMER_TCR_UNF (1 << 8) |
|
20 |
#define TIMER_TCR_ICPF (1 << 9) |
|
21 |
#define TIMER_TCR_RESERVED (0x3f << 10) |
|
22 |
|
|
23 |
#define TIMER_FEAT_CAPT (1 << 0) |
|
24 |
#define TIMER_FEAT_EXTCLK (1 << 1) |
|
25 |
|
|
26 |
typedef struct { |
|
27 |
ptimer_state *timer; |
|
28 |
uint32_t tcnt; |
|
29 |
uint32_t tcor; |
|
30 |
uint32_t tcr; |
|
31 |
uint32_t tcpr; |
|
32 |
int freq; |
|
33 |
int int_level; |
|
34 |
int feat; |
|
35 |
int enabled; |
|
36 |
qemu_irq irq; |
|
37 |
} sh_timer_state; |
|
38 |
|
|
39 |
/* Check all active timers, and schedule the next timer interrupt. */ |
|
40 |
|
|
41 |
static void sh_timer_update(sh_timer_state *s) |
|
42 |
{ |
|
43 |
#if 0 /* not yet */ |
|
44 |
/* Update interrupts. */ |
|
45 |
if (s->int_level && (s->tcr & TIMER_TCR_UNIE)) { |
|
46 |
qemu_irq_raise(s->irq); |
|
47 |
} else { |
|
48 |
qemu_irq_lower(s->irq); |
|
49 |
} |
|
50 |
#endif |
|
51 |
} |
|
52 |
|
|
53 |
uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) |
|
54 |
{ |
|
55 |
sh_timer_state *s = (sh_timer_state *)opaque; |
|
56 |
|
|
57 |
switch (offset >> 2) { |
|
58 |
case 0: |
|
59 |
return s->tcor; |
|
60 |
case 1: |
|
61 |
return ptimer_get_count(s->timer); |
|
62 |
case 2: |
|
63 |
return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); |
|
64 |
case 3: |
|
65 |
if (s->feat & TIMER_FEAT_CAPT) |
|
66 |
return s->tcpr; |
|
67 |
default: |
|
68 |
cpu_abort (cpu_single_env, "sh_timer_read: Bad offset %x\n", |
|
69 |
(int)offset); |
|
70 |
return 0; |
|
71 |
} |
|
72 |
} |
|
73 |
|
|
74 |
static void sh_timer_write(void *opaque, target_phys_addr_t offset, |
|
75 |
uint32_t value) |
|
76 |
{ |
|
77 |
sh_timer_state *s = (sh_timer_state *)opaque; |
|
78 |
int freq; |
|
79 |
|
|
80 |
switch (offset >> 2) { |
|
81 |
case 0: |
|
82 |
s->tcor = value; |
|
83 |
ptimer_set_limit(s->timer, s->tcor, 0); |
|
84 |
break; |
|
85 |
case 1: |
|
86 |
s->tcnt = value; |
|
87 |
ptimer_set_count(s->timer, s->tcnt); |
|
88 |
break; |
|
89 |
case 2: |
|
90 |
if (s->enabled) { |
|
91 |
/* Pause the timer if it is running. This may cause some |
|
92 |
inaccuracy dure to rounding, but avoids a whole lot of other |
|
93 |
messyness. */ |
|
94 |
ptimer_stop(s->timer); |
|
95 |
} |
|
96 |
freq = s->freq; |
|
97 |
/* ??? Need to recalculate expiry time after changing divisor. */ |
|
98 |
switch (value & TIMER_TCR_TPSC) { |
|
99 |
case 0: freq >>= 2; break; |
|
100 |
case 1: freq >>= 4; break; |
|
101 |
case 2: freq >>= 6; break; |
|
102 |
case 3: freq >>= 8; break; |
|
103 |
case 4: freq >>= 10; break; |
|
104 |
case 6: |
|
105 |
case 7: if (s->feat & TIMER_FEAT_EXTCLK) break; |
|
106 |
default: cpu_abort (cpu_single_env, |
|
107 |
"sh_timer_write: Reserved TPSC value\n"); break; |
|
108 |
} |
|
109 |
switch ((value & TIMER_TCR_CKEG) >> 3) { |
|
110 |
case 0: break; |
|
111 |
case 1: |
|
112 |
case 2: |
|
113 |
case 3: if (s->feat & TIMER_FEAT_EXTCLK) break; |
|
114 |
default: cpu_abort (cpu_single_env, |
|
115 |
"sh_timer_write: Reserved CKEG value\n"); break; |
|
116 |
} |
|
117 |
switch ((value & TIMER_TCR_ICPE) >> 6) { |
|
118 |
case 0: break; |
|
119 |
case 2: |
|
120 |
case 3: if (s->feat & TIMER_FEAT_CAPT) break; |
|
121 |
default: cpu_abort (cpu_single_env, |
|
122 |
"sh_timer_write: Reserved ICPE value\n"); break; |
|
123 |
} |
|
124 |
if ((value & TIMER_TCR_UNF) == 0) |
|
125 |
s->int_level = 0; |
|
126 |
|
|
127 |
value &= ~TIMER_TCR_UNF; |
|
128 |
|
|
129 |
if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) |
|
130 |
cpu_abort (cpu_single_env, |
|
131 |
"sh_timer_write: Reserved ICPF value\n"); |
|
132 |
|
|
133 |
value &= ~TIMER_TCR_ICPF; /* capture not supported */ |
|
134 |
|
|
135 |
if (value & TIMER_TCR_RESERVED) |
|
136 |
cpu_abort (cpu_single_env, |
|
137 |
"sh_timer_write: Reserved TCR bits set\n"); |
|
138 |
s->tcr = value; |
|
139 |
ptimer_set_limit(s->timer, s->tcor, 0); |
|
140 |
ptimer_set_freq(s->timer, freq); |
|
141 |
if (s->enabled) { |
|
142 |
/* Restart the timer if still enabled. */ |
|
143 |
ptimer_run(s->timer, 0); |
|
144 |
} |
|
145 |
break; |
|
146 |
case 3: |
|
147 |
if (s->feat & TIMER_FEAT_CAPT) { |
|
148 |
s->tcpr = value; |
|
149 |
break; |
|
150 |
} |
|
151 |
default: |
|
152 |
cpu_abort (cpu_single_env, "sh_timer_write: Bad offset %x\n", |
|
153 |
(int)offset); |
|
154 |
} |
|
155 |
sh_timer_update(s); |
|
156 |
} |
|
157 |
|
|
158 |
static void sh_timer_start_stop(void *opaque, int enable) |
|
159 |
{ |
|
160 |
sh_timer_state *s = (sh_timer_state *)opaque; |
|
161 |
|
|
162 |
#ifdef DEBUG_TIMER |
|
163 |
printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); |
|
164 |
#endif |
|
165 |
|
|
166 |
if (s->enabled && !enable) { |
|
167 |
ptimer_stop(s->timer); |
|
168 |
} |
|
169 |
if (!s->enabled && enable) { |
|
170 |
ptimer_run(s->timer, 0); |
|
171 |
} |
|
172 |
s->enabled = !!enable; |
|
173 |
|
|
174 |
#ifdef DEBUG_TIMER |
|
175 |
printf("sh_timer_start_stop done %d\n", s->enabled); |
|
176 |
#endif |
|
177 |
} |
|
178 |
|
|
179 |
static void sh_timer_tick(void *opaque) |
|
180 |
{ |
|
181 |
sh_timer_state *s = (sh_timer_state *)opaque; |
|
182 |
s->int_level = s->enabled; |
|
183 |
sh_timer_update(s); |
|
184 |
} |
|
185 |
|
|
186 |
static void *sh_timer_init(uint32_t freq, int feat) |
|
187 |
{ |
|
188 |
sh_timer_state *s; |
|
189 |
QEMUBH *bh; |
|
190 |
|
|
191 |
s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state)); |
|
192 |
s->freq = freq; |
|
193 |
s->feat = feat; |
|
194 |
s->tcor = 0xffffffff; |
|
195 |
s->tcnt = 0xffffffff; |
|
196 |
s->tcpr = 0xdeadbeef; |
|
197 |
s->tcor = 0; |
|
198 |
s->enabled = 0; |
|
199 |
|
|
200 |
bh = qemu_bh_new(sh_timer_tick, s); |
|
201 |
s->timer = ptimer_init(bh); |
|
202 |
/* ??? Save/restore. */ |
|
203 |
return s; |
|
204 |
} |
|
205 |
|
|
206 |
typedef struct { |
|
207 |
void *timer[3]; |
|
208 |
int level[3]; |
|
209 |
uint32_t tocr; |
|
210 |
uint32_t tstr; |
|
211 |
target_phys_addr_t base; |
|
212 |
int feat; |
|
213 |
} tmu012_state; |
|
214 |
|
|
215 |
static uint32_t tmu012_read(void *opaque, target_phys_addr_t offset) |
|
216 |
{ |
|
217 |
tmu012_state *s = (tmu012_state *)opaque; |
|
218 |
|
|
219 |
#ifdef DEBUG_TIMER |
|
220 |
printf("tmu012_read 0x%lx\n", (unsigned long) offset); |
|
221 |
#endif |
|
222 |
offset -= s->base; |
|
223 |
|
|
224 |
if (offset >= 0x20) { |
|
225 |
if (!(s->feat & TMU012_FEAT_3CHAN)) |
|
226 |
cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", |
|
227 |
(int)offset); |
|
228 |
return sh_timer_read(s->timer[2], offset - 0x20); |
|
229 |
} |
|
230 |
|
|
231 |
if (offset >= 0x14) |
|
232 |
return sh_timer_read(s->timer[1], offset - 0x14); |
|
233 |
|
|
234 |
if (offset >= 0x08) |
|
235 |
return sh_timer_read(s->timer[0], offset - 0x08); |
|
236 |
|
|
237 |
if (offset == 4) |
|
238 |
return s->tstr; |
|
239 |
|
|
240 |
if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) |
|
241 |
return s->tocr; |
|
242 |
|
|
243 |
cpu_abort (cpu_single_env, "tmu012_write: Bad offset %x\n", |
|
244 |
(int)offset); |
|
245 |
return 0; |
|
246 |
} |
|
247 |
|
|
248 |
static void tmu012_write(void *opaque, target_phys_addr_t offset, |
|
249 |
uint32_t value) |
|
250 |
{ |
|
251 |
tmu012_state *s = (tmu012_state *)opaque; |
|
252 |
|
|
253 |
#ifdef DEBUG_TIMER |
|
254 |
printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); |
|
255 |
#endif |
|
256 |
offset -= s->base; |
|
257 |
|
|
258 |
if (offset >= 0x20) { |
|
259 |
if (!(s->feat & TMU012_FEAT_3CHAN)) |
|
260 |
cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", |
|
261 |
(int)offset); |
|
262 |
sh_timer_write(s->timer[2], offset - 0x20, value); |
|
263 |
return; |
|
264 |
} |
|
265 |
|
|
266 |
if (offset >= 0x14) { |
|
267 |
sh_timer_write(s->timer[1], offset - 0x14, value); |
|
268 |
return; |
|
269 |
} |
|
270 |
|
|
271 |
if (offset >= 0x08) { |
|
272 |
sh_timer_write(s->timer[0], offset - 0x08, value); |
|
273 |
return; |
|
274 |
} |
|
275 |
|
|
276 |
if (offset == 4) { |
|
277 |
sh_timer_start_stop(s->timer[0], value & (1 << 0)); |
|
278 |
sh_timer_start_stop(s->timer[1], value & (1 << 1)); |
|
279 |
if (s->feat & TMU012_FEAT_3CHAN) |
|
280 |
sh_timer_start_stop(s->timer[2], value & (1 << 2)); |
|
281 |
else |
|
282 |
if (value & (1 << 2)) |
|
283 |
cpu_abort (cpu_single_env, "tmu012_write: Bad channel\n"); |
|
284 |
|
|
285 |
s->tstr = value; |
|
286 |
return; |
|
287 |
} |
|
288 |
|
|
289 |
if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) { |
|
290 |
s->tocr = value & (1 << 0); |
|
291 |
} |
|
292 |
} |
|
293 |
|
|
294 |
static CPUReadMemoryFunc *tmu012_readfn[] = { |
|
295 |
tmu012_read, |
|
296 |
tmu012_read, |
|
297 |
tmu012_read |
|
298 |
}; |
|
299 |
|
|
300 |
static CPUWriteMemoryFunc *tmu012_writefn[] = { |
|
301 |
tmu012_write, |
|
302 |
tmu012_write, |
|
303 |
tmu012_write |
|
304 |
}; |
|
305 |
|
|
306 |
void tmu012_init(uint32_t base, int feat, uint32_t freq) |
|
307 |
{ |
|
308 |
int iomemtype; |
|
309 |
tmu012_state *s; |
|
310 |
int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; |
|
311 |
|
|
312 |
s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state)); |
|
313 |
s->base = base; |
|
314 |
s->feat = feat; |
|
315 |
s->timer[0] = sh_timer_init(freq, timer_feat); |
|
316 |
s->timer[1] = sh_timer_init(freq, timer_feat); |
|
317 |
if (feat & TMU012_FEAT_3CHAN) |
|
318 |
s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT); |
|
319 |
iomemtype = cpu_register_io_memory(0, tmu012_readfn, |
|
320 |
tmu012_writefn, s); |
|
321 |
cpu_register_physical_memory(base, 0x00001000, iomemtype); |
|
322 |
/* ??? Save/restore. */ |
|
323 |
} |
b/vl.h | ||
---|---|---|
1517 | 1517 |
|
1518 | 1518 |
int sh7750_register_io_device(struct SH7750State *s, |
1519 | 1519 |
sh7750_io_device * device); |
1520 |
/* sh_timer.c */ |
|
1521 |
#define TMU012_FEAT_TOCR (1 << 0) |
|
1522 |
#define TMU012_FEAT_3CHAN (1 << 1) |
|
1523 |
#define TMU012_FEAT_EXTCLK (1 << 2) |
|
1524 |
void tmu012_init(uint32_t base, int feat, uint32_t freq); |
|
1525 |
|
|
1520 | 1526 |
/* tc58128.c */ |
1521 | 1527 |
int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); |
1522 | 1528 |
|
Also available in: Unified diff