Commit b7f4e50311a708f1d07c6add476b4f7812d25bd4
1 parent
2a3e33f7
TC:
- access to register not working - acess to rc return rb register - emulate TC usage for fast delay
Showing
1 changed file
with
62 additions
and
28 deletions
hw/at91_tc.c
| ... | ... | @@ -72,15 +72,23 @@ static void at91_tc_tick(void *opaque) |
| 72 | 72 | { |
| 73 | 73 | TCChannelState *s = opaque; |
| 74 | 74 | |
| 75 | - s->cv++; | |
| 76 | - /* TODO: Overflow check */ | |
| 77 | - if (s->cv == s->ra) { | |
| 78 | - s->sr |= SR_CPAS; | |
| 79 | - } | |
| 80 | - if (s->cv == s->rb) { | |
| 81 | - s->sr |= SR_CPBS; | |
| 82 | - } | |
| 83 | - if (s->cv == s->rc) { | |
| 75 | + if (s->mr & MR_WAVE) { | |
| 76 | + s->cv++; | |
| 77 | + /* TODO: Overflow check */ | |
| 78 | + if (s->cv == s->ra) { | |
| 79 | + s->sr |= SR_CPAS; | |
| 80 | + } | |
| 81 | + if (s->cv == s->rb) { | |
| 82 | + s->sr |= SR_CPBS; | |
| 83 | + } | |
| 84 | + if (s->cv == s->rc) { | |
| 85 | + s->sr |= SR_CPCS; | |
| 86 | + if (s->mr & MR_RCTRIG) { | |
| 87 | + s->cv = 0; | |
| 88 | + } | |
| 89 | + } | |
| 90 | + } else { | |
| 91 | + s->cv = s->rc; | |
| 84 | 92 | s->sr |= SR_CPCS; |
| 85 | 93 | if (s->mr & MR_RCTRIG) { |
| 86 | 94 | s->cv = 0; |
| ... | ... | @@ -106,7 +114,7 @@ static uint32_t at91_tc_channel_read(TCChannelState *s, |
| 106 | 114 | case TC_RB: |
| 107 | 115 | return s->rb; |
| 108 | 116 | case TC_RC: |
| 109 | - return s->rb; | |
| 117 | + return s->rc; | |
| 110 | 118 | case TC_SR: |
| 111 | 119 | sr = s->sr; |
| 112 | 120 | s->sr = 0; |
| ... | ... | @@ -119,6 +127,23 @@ static uint32_t at91_tc_channel_read(TCChannelState *s, |
| 119 | 127 | } |
| 120 | 128 | } |
| 121 | 129 | |
| 130 | +static int at91_tc_get_freq(uint32_t cmr) | |
| 131 | +{ | |
| 132 | + int freq; | |
| 133 | + | |
| 134 | + switch (cmr & 7) { | |
| 135 | + case 0: freq = at91_master_clock_frequency / 2; break; | |
| 136 | + case 1: freq = at91_master_clock_frequency / 8; break; | |
| 137 | + case 2: freq = at91_master_clock_frequency / 32; break; | |
| 138 | + case 3: freq = at91_master_clock_frequency / 128; break; | |
| 139 | + case 4: freq = at91_master_clock_frequency / 1024; break; | |
| 140 | + default: /* TODO: External clocks */ | |
| 141 | + freq = at91_master_clock_frequency / 16; | |
| 142 | + break; | |
| 143 | + } | |
| 144 | + return freq; | |
| 145 | +} | |
| 146 | + | |
| 122 | 147 | static void at91_tc_channel_write(TCChannelState *s, |
| 123 | 148 | target_phys_addr_t offset, uint32_t value) |
| 124 | 149 | { |
| ... | ... | @@ -127,30 +152,36 @@ static void at91_tc_channel_write(TCChannelState *s, |
| 127 | 152 | switch (offset) { |
| 128 | 153 | case TC_CCR: |
| 129 | 154 | if ((value & 3) == 1) { |
| 130 | - if (s->mr & MR_WAVE) { | |
| 131 | - s->cv = 0; | |
| 132 | - ptimer_run(s->timer, 0); | |
| 155 | + if (!(s->mr & MR_WAVE)) { | |
| 156 | + if (s->imr == 0 && s->rc != 0) { | |
| 157 | + freq = at91_tc_get_freq(s->mr); | |
| 158 | + freq /= s->rc; | |
| 159 | + if (freq > 1000) { | |
| 160 | + //just busy loop too wait something, with resolution more then 1ms | |
| 161 | + s->cv = s->rc; | |
| 162 | + s->sr |= SR_CPCS; | |
| 163 | + if (s->mr & MR_RCTRIG) { | |
| 164 | + s->cv = 0; | |
| 165 | + } | |
| 166 | + break; | |
| 167 | + } | |
| 168 | + } | |
| 169 | + //tick only once, this should speedup system | |
| 170 | + ptimer_set_limit(s->timer, s->rc, 1); | |
| 133 | 171 | } |
| 134 | - /* TODO: Counter mode */ | |
| 172 | + | |
| 173 | + s->cv = 0; | |
| 174 | + ptimer_run(s->timer, 0); | |
| 135 | 175 | } else if (value & 2) { |
| 136 | 176 | ptimer_stop(s->timer); |
| 177 | + ptimer_set_limit(s->timer, 1, 1); | |
| 137 | 178 | } |
| 138 | 179 | break; |
| 139 | 180 | case TC_CMR: |
| 140 | - if (value & MR_WAVE) { | |
| 141 | - switch (value & 7) { | |
| 142 | - case 0: freq = at91_master_clock_frequency / 2; break; | |
| 143 | - case 1: freq = at91_master_clock_frequency / 8; break; | |
| 144 | - case 2: freq = at91_master_clock_frequency / 32; break; | |
| 145 | - case 3: freq = at91_master_clock_frequency / 128; break; | |
| 146 | - case 4: freq = at91_master_clock_frequency / 1024; break; | |
| 147 | - default: /* TODO: External clocks */ | |
| 148 | - freq = at91_master_clock_frequency / 16; | |
| 149 | - break; | |
| 150 | - } | |
| 151 | - ptimer_set_freq(s->timer, freq); | |
| 152 | - } | |
| 153 | - /* TODO: Counter mode */ | |
| 181 | + freq = at91_tc_get_freq(value); | |
| 182 | + | |
| 183 | + ptimer_set_freq(s->timer, freq); | |
| 184 | + | |
| 154 | 185 | s->mr = value; |
| 155 | 186 | break; |
| 156 | 187 | case TC_RA: |
| ... | ... | @@ -175,6 +206,7 @@ static uint32_t at91_tc_mem_read(void *opaque, target_phys_addr_t offset) |
| 175 | 206 | { |
| 176 | 207 | TCState *s = opaque; |
| 177 | 208 | |
| 209 | + offset &= TC_SIZE - 1; | |
| 178 | 210 | switch (offset) { |
| 179 | 211 | case TC_BMR: |
| 180 | 212 | return 0; /* TODO */ |
| ... | ... | @@ -194,6 +226,8 @@ static void at91_tc_mem_write(void *opaque, target_phys_addr_t offset, |
| 194 | 226 | { |
| 195 | 227 | TCState *s = opaque; |
| 196 | 228 | |
| 229 | + offset &= TC_SIZE - 1; | |
| 230 | + | |
| 197 | 231 | switch (offset) { |
| 198 | 232 | case TC_BCR: |
| 199 | 233 | return; /* TODO */ | ... | ... |