1 |
dpavlin |
14 |
/* |
2 |
dpavlin |
22 |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
3 |
dpavlin |
14 |
* |
4 |
|
|
* Redistribution and use in source and binary forms, with or without |
5 |
|
|
* modification, are permitted provided that the following conditions are met: |
6 |
|
|
* |
7 |
|
|
* 1. Redistributions of source code must retain the above copyright |
8 |
|
|
* notice, this list of conditions and the following disclaimer. |
9 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
|
|
* notice, this list of conditions and the following disclaimer in the |
11 |
|
|
* documentation and/or other materials provided with the distribution. |
12 |
|
|
* 3. The name of the author may not be used to endorse or promote products |
13 |
|
|
* derived from this software without specific prior written permission. |
14 |
|
|
* |
15 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
|
|
* SUCH DAMAGE. |
26 |
|
|
* |
27 |
|
|
* |
28 |
dpavlin |
24 |
* $Id: cpu_avr_instr.c,v 1.15 2006/03/05 16:20:24 debug Exp $ |
29 |
dpavlin |
14 |
* |
30 |
|
|
* Atmel AVR (8-bit) instructions. |
31 |
|
|
* |
32 |
dpavlin |
20 |
* Individual functions should keep track of cpu->n_translated_instrs. |
33 |
dpavlin |
14 |
* (n_translated_instrs is automatically increased by 1 for each function |
34 |
|
|
* call. If no instruction was executed, then it should be decreased. If, say, |
35 |
|
|
* 4 instructions were combined into one function and executed, then it should |
36 |
|
|
* be increased by 3.) |
37 |
|
|
*/ |
38 |
|
|
|
39 |
|
|
|
40 |
|
|
/*****************************************************************************/ |
41 |
|
|
|
42 |
|
|
|
43 |
dpavlin |
24 |
void push_value(struct cpu *cpu, uint32_t value, int len) |
44 |
|
|
{ |
45 |
|
|
unsigned char data[4]; |
46 |
|
|
data[0] = value; data[1] = value >> 8; |
47 |
|
|
data[2] = value >> 16; data[3] = value >> 24; |
48 |
|
|
cpu->memory_rw(cpu, cpu->mem, cpu->cd.avr.sp + AVR_SRAM_BASE, |
49 |
|
|
data, len, MEM_WRITE, CACHE_DATA); |
50 |
|
|
cpu->cd.avr.sp -= len; |
51 |
|
|
cpu->cd.avr.sp &= cpu->cd.avr.sram_mask; |
52 |
|
|
} |
53 |
|
|
|
54 |
|
|
|
55 |
|
|
void pop_value(struct cpu *cpu, uint32_t *value, int len) |
56 |
|
|
{ |
57 |
|
|
unsigned char data[4]; |
58 |
|
|
cpu->cd.avr.sp += len; |
59 |
|
|
cpu->cd.avr.sp &= cpu->cd.avr.sram_mask; |
60 |
|
|
cpu->memory_rw(cpu, cpu->mem, cpu->cd.avr.sp + AVR_SRAM_BASE, |
61 |
|
|
data, len, MEM_READ, CACHE_DATA); |
62 |
|
|
*value = data[0]; |
63 |
|
|
if (len > 1) |
64 |
|
|
(*value) += (data[1] << 8); |
65 |
|
|
if (len > 2) |
66 |
|
|
(*value) += (data[2] << 16); |
67 |
|
|
if (len > 3) |
68 |
|
|
(*value) += (data[3] << 24); |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
|
72 |
|
|
/*****************************************************************************/ |
73 |
|
|
|
74 |
|
|
|
75 |
dpavlin |
14 |
/* |
76 |
|
|
* nop: Do nothing. |
77 |
|
|
*/ |
78 |
|
|
X(nop) |
79 |
|
|
{ |
80 |
|
|
} |
81 |
|
|
|
82 |
|
|
|
83 |
|
|
/* |
84 |
dpavlin |
24 |
* breq: Conditional relative jump. |
85 |
|
|
* |
86 |
|
|
* arg[1]: relative offset |
87 |
|
|
*/ |
88 |
|
|
X(breq) |
89 |
|
|
{ |
90 |
|
|
uint32_t low_pc; |
91 |
|
|
|
92 |
|
|
if (!(cpu->cd.avr.sreg & AVR_SREG_Z)) |
93 |
|
|
return; |
94 |
|
|
|
95 |
|
|
cpu->cd.avr.extra_cycles ++; |
96 |
|
|
|
97 |
|
|
/* Calculate new PC from the next instruction + arg[1] */ |
98 |
|
|
low_pc = ((size_t)ic - (size_t)cpu->cd.avr.cur_ic_page) / |
99 |
|
|
sizeof(struct avr_instr_call); |
100 |
|
|
cpu->pc &= ~((AVR_IC_ENTRIES_PER_PAGE-1) |
101 |
|
|
<< AVR_INSTR_ALIGNMENT_SHIFT); |
102 |
|
|
cpu->pc += (low_pc << AVR_INSTR_ALIGNMENT_SHIFT); |
103 |
|
|
cpu->pc += (int32_t)ic->arg[1]; |
104 |
|
|
|
105 |
|
|
/* Find the new physical page and update the translation pointers: */ |
106 |
|
|
avr_pc_to_pointers(cpu); |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
|
110 |
|
|
/* |
111 |
|
|
* breq_samepage: Continional relative jump (to within the same page). |
112 |
|
|
* |
113 |
|
|
* arg[1] = pointer to new avr_instr_call |
114 |
|
|
*/ |
115 |
|
|
X(breq_samepage) |
116 |
|
|
{ |
117 |
|
|
if (!(cpu->cd.avr.sreg & AVR_SREG_Z)) |
118 |
|
|
return; |
119 |
|
|
|
120 |
|
|
cpu->cd.avr.extra_cycles ++; |
121 |
|
|
cpu->cd.avr.next_ic = (struct avr_instr_call *) ic->arg[1]; |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
|
125 |
|
|
/* |
126 |
|
|
* brne: Conditional relative jump. |
127 |
|
|
* |
128 |
|
|
* arg[1]: relative offset |
129 |
|
|
*/ |
130 |
|
|
X(brne) |
131 |
|
|
{ |
132 |
|
|
uint32_t low_pc; |
133 |
|
|
|
134 |
|
|
if (cpu->cd.avr.sreg & AVR_SREG_Z) |
135 |
|
|
return; |
136 |
|
|
|
137 |
|
|
cpu->cd.avr.extra_cycles ++; |
138 |
|
|
|
139 |
|
|
/* Calculate new PC from the next instruction + arg[1] */ |
140 |
|
|
low_pc = ((size_t)ic - (size_t)cpu->cd.avr.cur_ic_page) / |
141 |
|
|
sizeof(struct avr_instr_call); |
142 |
|
|
cpu->pc &= ~((AVR_IC_ENTRIES_PER_PAGE-1) |
143 |
|
|
<< AVR_INSTR_ALIGNMENT_SHIFT); |
144 |
|
|
cpu->pc += (low_pc << AVR_INSTR_ALIGNMENT_SHIFT); |
145 |
|
|
cpu->pc += (int32_t)ic->arg[1]; |
146 |
|
|
|
147 |
|
|
/* Find the new physical page and update the translation pointers: */ |
148 |
|
|
avr_pc_to_pointers(cpu); |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
|
152 |
|
|
/* |
153 |
|
|
* brne_samepage: Continional relative jump (to within the same page). |
154 |
|
|
* |
155 |
|
|
* arg[1] = pointer to new avr_instr_call |
156 |
|
|
*/ |
157 |
|
|
X(brne_samepage) |
158 |
|
|
{ |
159 |
|
|
if (cpu->cd.avr.sreg & AVR_SREG_Z) |
160 |
|
|
return; |
161 |
|
|
|
162 |
|
|
cpu->cd.avr.extra_cycles ++; |
163 |
|
|
cpu->cd.avr.next_ic = (struct avr_instr_call *) ic->arg[1]; |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
|
167 |
|
|
/* |
168 |
dpavlin |
14 |
* clX: Clear an sreg bit. |
169 |
|
|
*/ |
170 |
|
|
X(clc) { cpu->cd.avr.sreg &= ~AVR_SREG_C; } |
171 |
|
|
X(clz) { cpu->cd.avr.sreg &= ~AVR_SREG_Z; } |
172 |
|
|
X(cln) { cpu->cd.avr.sreg &= ~AVR_SREG_N; } |
173 |
|
|
X(clv) { cpu->cd.avr.sreg &= ~AVR_SREG_V; } |
174 |
|
|
X(cls) { cpu->cd.avr.sreg &= ~AVR_SREG_S; } |
175 |
|
|
X(clh) { cpu->cd.avr.sreg &= ~AVR_SREG_H; } |
176 |
|
|
X(clt) { cpu->cd.avr.sreg &= ~AVR_SREG_T; } |
177 |
|
|
X(cli) { cpu->cd.avr.sreg &= ~AVR_SREG_I; } |
178 |
|
|
|
179 |
|
|
|
180 |
|
|
/* |
181 |
|
|
* ldi: Load immediate. |
182 |
|
|
* |
183 |
dpavlin |
24 |
* arg[1]: ptr to register |
184 |
|
|
* arg[2]: byte value |
185 |
dpavlin |
14 |
*/ |
186 |
|
|
X(ldi) |
187 |
|
|
{ |
188 |
dpavlin |
24 |
*(uint8_t *)(ic->arg[1]) = ic->arg[2]; |
189 |
dpavlin |
14 |
} |
190 |
|
|
|
191 |
|
|
|
192 |
|
|
/* |
193 |
dpavlin |
24 |
* ld_y: Load byte pointed to by register Y into a register. |
194 |
dpavlin |
14 |
* |
195 |
|
|
* arg[1]: ptr to rd |
196 |
|
|
*/ |
197 |
dpavlin |
24 |
X(ld_y) |
198 |
|
|
{ |
199 |
|
|
cpu->memory_rw(cpu, cpu->mem, AVR_SRAM_BASE + cpu->cd.avr.r[28] |
200 |
|
|
+ 256*cpu->cd.avr.r[29], (uint8_t *)(ic->arg[1]), 1, MEM_READ, |
201 |
|
|
CACHE_DATA); |
202 |
|
|
cpu->cd.avr.extra_cycles ++; |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
|
206 |
|
|
/* |
207 |
|
|
* out: Write a byte from a register to I/O space. |
208 |
|
|
* (out is the generic function, out_* are special cases.) |
209 |
|
|
* |
210 |
|
|
* arg[1]: ptr to rr |
211 |
|
|
* arg[2]: I/O port nr |
212 |
|
|
*/ |
213 |
|
|
X(out) |
214 |
|
|
{ |
215 |
|
|
cpu->memory_rw(cpu, cpu->mem, AVR_SRAM_BASE + ic->arg[2], |
216 |
|
|
(uint8_t *)(ic->arg[1]), 1, MEM_WRITE, CACHE_DATA); |
217 |
|
|
} |
218 |
|
|
X(out_ddra) { cpu->cd.avr.ddra = *(uint8_t *)(ic->arg[1]); } |
219 |
|
|
X(out_ddrb) { cpu->cd.avr.ddrb = *(uint8_t *)(ic->arg[1]); } |
220 |
|
|
X(out_ddrc) { cpu->cd.avr.ddrc = *(uint8_t *)(ic->arg[1]); } |
221 |
|
|
X(out_ddrd) { cpu->cd.avr.ddrd = *(uint8_t *)(ic->arg[1]); } |
222 |
|
|
X(out_porta) { cpu->cd.avr.portd_write = *(uint8_t *)(ic->arg[1]); } |
223 |
|
|
X(out_portb) { cpu->cd.avr.portd_write = *(uint8_t *)(ic->arg[1]); } |
224 |
|
|
X(out_portc) { cpu->cd.avr.portd_write = *(uint8_t *)(ic->arg[1]); } |
225 |
|
|
X(out_portd) { cpu->cd.avr.portd_write = *(uint8_t *)(ic->arg[1]); } |
226 |
|
|
|
227 |
|
|
|
228 |
|
|
/* |
229 |
|
|
* adiw: rd+1:rd += constant |
230 |
|
|
* |
231 |
|
|
* arg[1]: ptr to rd |
232 |
|
|
* arg[2]: k |
233 |
|
|
*/ |
234 |
|
|
X(adiw) |
235 |
|
|
{ |
236 |
|
|
uint32_t value = *(uint8_t *)(ic->arg[1]) + |
237 |
|
|
(*(uint8_t *)(ic->arg[1] + 1) << 8); |
238 |
|
|
value += ic->arg[2]; |
239 |
|
|
|
240 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
241 |
|
|
| AVR_SREG_Z | AVR_SREG_C); |
242 |
|
|
|
243 |
|
|
/* TODO: is this V bit calculated correctly? */ |
244 |
|
|
if (value > 0xffff) |
245 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_C | AVR_SREG_V; |
246 |
|
|
if (value & 0x8000) |
247 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_N; |
248 |
|
|
if (value == 0) |
249 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
250 |
|
|
|
251 |
|
|
if ((cpu->cd.avr.sreg & AVR_SREG_N? 1 : 0) ^ |
252 |
|
|
(cpu->cd.avr.sreg & AVR_SREG_V? 1 : 0)) |
253 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S; |
254 |
|
|
|
255 |
|
|
*(uint8_t *)(ic->arg[1]) = value; |
256 |
|
|
*(uint8_t *)(ic->arg[1] + 1) = value >> 8; |
257 |
|
|
|
258 |
|
|
cpu->cd.avr.extra_cycles ++; |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
|
262 |
|
|
/* |
263 |
|
|
* and: rd = rd & rr |
264 |
|
|
* |
265 |
|
|
* arg[1]: ptr to rr |
266 |
|
|
* arg[2]: ptr to rd |
267 |
|
|
*/ |
268 |
|
|
X(and) |
269 |
|
|
{ |
270 |
|
|
*(uint8_t *)(ic->arg[2]) &= *(uint8_t *)(ic->arg[1]); |
271 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
272 |
|
|
| AVR_SREG_Z); |
273 |
|
|
if (*(uint8_t *)(ic->arg[2]) == 0) |
274 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
275 |
|
|
if (*(uint8_t *)(ic->arg[2]) & 0x80) |
276 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S | AVR_SREG_N; |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
|
280 |
|
|
/* |
281 |
|
|
* eor: rd = rd ^ rr |
282 |
|
|
* |
283 |
|
|
* arg[1]: ptr to rr |
284 |
|
|
* arg[2]: ptr to rd |
285 |
|
|
*/ |
286 |
|
|
X(eor) |
287 |
|
|
{ |
288 |
|
|
*(uint8_t *)(ic->arg[2]) ^= *(uint8_t *)(ic->arg[1]); |
289 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
290 |
|
|
| AVR_SREG_Z); |
291 |
|
|
if (*(uint8_t *)(ic->arg[2]) == 0) |
292 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
293 |
|
|
if (*(uint8_t *)(ic->arg[2]) & 0x80) |
294 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S | AVR_SREG_N; |
295 |
|
|
} |
296 |
|
|
|
297 |
|
|
|
298 |
|
|
/* |
299 |
|
|
* andi: rd = rd & imm |
300 |
|
|
* |
301 |
|
|
* arg[1]: ptr to rd |
302 |
|
|
* arg[2]: imm |
303 |
|
|
*/ |
304 |
|
|
X(andi) |
305 |
|
|
{ |
306 |
|
|
uint8_t x = *(uint8_t *)(ic->arg[1]) & ic->arg[2]; |
307 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
308 |
|
|
| AVR_SREG_Z); |
309 |
|
|
if (x == 0) |
310 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
311 |
|
|
if (x & 0x80) |
312 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S | AVR_SREG_N; |
313 |
|
|
*(uint8_t *)(ic->arg[1]) = x; |
314 |
|
|
} |
315 |
|
|
|
316 |
|
|
|
317 |
|
|
/* |
318 |
|
|
* cpi: Compare rd with immediate |
319 |
|
|
* |
320 |
|
|
* arg[1]: ptr to rd |
321 |
|
|
* arg[2]: imm |
322 |
|
|
*/ |
323 |
|
|
X(cpi) |
324 |
|
|
{ |
325 |
|
|
uint8_t x = *(uint8_t *)(ic->arg[1]), k = ic->arg[2], z = x - k; |
326 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
327 |
|
|
| AVR_SREG_Z | AVR_SREG_H | AVR_SREG_C); |
328 |
|
|
if (z == 0) |
329 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
330 |
|
|
if (z & 0x80) |
331 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_N; |
332 |
|
|
/* TODO: h and v bits! */ |
333 |
|
|
if (abs((int)k) > abs((int)x)) |
334 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_C; |
335 |
|
|
if ((cpu->cd.avr.sreg & AVR_SREG_N? 1 : 0) ^ |
336 |
|
|
(cpu->cd.avr.sreg & AVR_SREG_V? 1 : 0)) |
337 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S; |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
|
341 |
|
|
/* |
342 |
|
|
* mov: Copy register. |
343 |
|
|
* |
344 |
|
|
* arg[1]: ptr to rr |
345 |
|
|
* arg[2]: ptr to rd |
346 |
|
|
*/ |
347 |
dpavlin |
14 |
X(mov) |
348 |
|
|
{ |
349 |
dpavlin |
24 |
*(uint8_t *)(ic->arg[2]) = *(uint8_t *)(ic->arg[1]); |
350 |
dpavlin |
14 |
} |
351 |
|
|
|
352 |
|
|
|
353 |
|
|
/* |
354 |
dpavlin |
24 |
* sts: Store a register into memory. |
355 |
|
|
* |
356 |
|
|
* arg[1]: pointer to the register |
357 |
|
|
* arg[2]: absolute address (16 bits) |
358 |
|
|
*/ |
359 |
|
|
X(sts) |
360 |
|
|
{ |
361 |
|
|
uint8_t r = *(uint8_t *)(ic->arg[1]); |
362 |
|
|
if (!cpu->memory_rw(cpu, cpu->mem, ic->arg[2] + AVR_SRAM_BASE, |
363 |
|
|
&r, sizeof(uint8_t), MEM_WRITE, CACHE_DATA)) { |
364 |
|
|
fatal("sts: write failed: TODO\n"); |
365 |
|
|
exit(1); |
366 |
|
|
} |
367 |
|
|
cpu->cd.avr.extra_cycles ++; |
368 |
|
|
} |
369 |
|
|
|
370 |
|
|
|
371 |
|
|
/* |
372 |
|
|
* st_y: Store a register into memory at address Y. |
373 |
|
|
* st_y_plus: Store a register into memory at address Y, and update Y. |
374 |
|
|
* st_minus_y: Same as above, but with pre-decrement instead of post-increment. |
375 |
|
|
* |
376 |
|
|
* arg[1]: pointer to the register |
377 |
|
|
*/ |
378 |
|
|
X(st_y) |
379 |
|
|
{ |
380 |
|
|
uint16_t y = (cpu->cd.avr.r[29] << 8) + cpu->cd.avr.r[28]; |
381 |
|
|
cpu->memory_rw(cpu, cpu->mem, AVR_SRAM_BASE + y, |
382 |
|
|
(uint8_t *)ic->arg[1], sizeof(uint8_t), MEM_WRITE, CACHE_DATA); |
383 |
|
|
cpu->cd.avr.extra_cycles ++; |
384 |
|
|
} |
385 |
|
|
X(st_y_plus) |
386 |
|
|
{ |
387 |
|
|
uint16_t y = (cpu->cd.avr.r[29] << 8) + cpu->cd.avr.r[28]; |
388 |
|
|
cpu->memory_rw(cpu, cpu->mem, AVR_SRAM_BASE + y, |
389 |
|
|
(uint8_t *)ic->arg[1], sizeof(uint8_t), MEM_WRITE, CACHE_DATA); |
390 |
|
|
cpu->cd.avr.extra_cycles ++; |
391 |
|
|
y ++; |
392 |
|
|
cpu->cd.avr.r[29] = y >> 8; |
393 |
|
|
cpu->cd.avr.r[28] = y; |
394 |
|
|
} |
395 |
|
|
X(st_minus_y) |
396 |
|
|
{ |
397 |
|
|
uint16_t y = (cpu->cd.avr.r[29] << 8) + cpu->cd.avr.r[28]; |
398 |
|
|
y --; |
399 |
|
|
cpu->cd.avr.r[29] = y >> 8; |
400 |
|
|
cpu->cd.avr.r[28] = y; |
401 |
|
|
cpu->memory_rw(cpu, cpu->mem, AVR_SRAM_BASE + y, |
402 |
|
|
(uint8_t *)ic->arg[1], sizeof(uint8_t), MEM_WRITE, CACHE_DATA); |
403 |
|
|
cpu->cd.avr.extra_cycles ++; |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
|
407 |
|
|
/* |
408 |
|
|
* cbi,sbi: Clear/Set bit in I/O register. |
409 |
|
|
* |
410 |
|
|
* arg[1]: I/O register number (0..31) |
411 |
|
|
* arg[2]: byte mask to and/or into the old value (1, 2, ..., 0x40, or 0x80) |
412 |
|
|
*/ |
413 |
|
|
X(cbi) |
414 |
|
|
{ |
415 |
|
|
uint8_t r; |
416 |
|
|
cpu->memory_rw(cpu, cpu->mem, ic->arg[1] + AVR_SRAM_BASE, |
417 |
|
|
&r, sizeof(uint8_t), MEM_READ, CACHE_DATA); |
418 |
|
|
r &= ic->arg[2]; |
419 |
|
|
cpu->memory_rw(cpu, cpu->mem, ic->arg[1] + AVR_SRAM_BASE, |
420 |
|
|
&r, sizeof(uint8_t), MEM_WRITE, CACHE_DATA); |
421 |
|
|
cpu->cd.avr.extra_cycles ++; |
422 |
|
|
} |
423 |
|
|
X(sbi) |
424 |
|
|
{ |
425 |
|
|
uint8_t r; |
426 |
|
|
cpu->memory_rw(cpu, cpu->mem, ic->arg[1] + AVR_SRAM_BASE, |
427 |
|
|
&r, sizeof(uint8_t), MEM_READ, CACHE_DATA); |
428 |
|
|
r |= ic->arg[2]; |
429 |
|
|
cpu->memory_rw(cpu, cpu->mem, ic->arg[1] + AVR_SRAM_BASE, |
430 |
|
|
&r, sizeof(uint8_t), MEM_WRITE, CACHE_DATA); |
431 |
|
|
cpu->cd.avr.extra_cycles ++; |
432 |
|
|
} |
433 |
|
|
|
434 |
|
|
|
435 |
|
|
/* |
436 |
|
|
* lpm: Load program memory at addess Z into r0. |
437 |
|
|
*/ |
438 |
|
|
X(lpm) |
439 |
|
|
{ |
440 |
|
|
uint16_t z = (cpu->cd.avr.r[31] << 8) + cpu->cd.avr.r[30]; |
441 |
|
|
cpu->memory_rw(cpu, cpu->mem, z, &cpu->cd.avr.r[0], |
442 |
|
|
sizeof(uint8_t), MEM_READ, CACHE_DATA); |
443 |
|
|
cpu->cd.avr.extra_cycles += 2; |
444 |
|
|
} |
445 |
|
|
|
446 |
|
|
|
447 |
|
|
/* |
448 |
|
|
* ret: Return from subroutine call. |
449 |
|
|
*/ |
450 |
|
|
X(ret) |
451 |
|
|
{ |
452 |
|
|
uint32_t new_pc; |
453 |
|
|
|
454 |
|
|
cpu->cd.avr.extra_cycles += 3 + cpu->cd.avr.is_22bit; |
455 |
|
|
|
456 |
|
|
/* Pop the address of the following instruction: */ |
457 |
|
|
pop_value(cpu, &new_pc, 2 + cpu->cd.avr.is_22bit); |
458 |
|
|
cpu->pc = new_pc << 1; |
459 |
|
|
|
460 |
|
|
/* Find the new physical page and update the translation pointers: */ |
461 |
|
|
avr_pc_to_pointers(cpu); |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
|
465 |
|
|
/* |
466 |
|
|
* rcall: Relative call. |
467 |
|
|
* |
468 |
|
|
* arg[1]: relative offset |
469 |
|
|
*/ |
470 |
|
|
X(rcall) |
471 |
|
|
{ |
472 |
|
|
uint32_t low_pc; |
473 |
|
|
|
474 |
|
|
cpu->cd.avr.extra_cycles += 2 + cpu->cd.avr.is_22bit; |
475 |
|
|
|
476 |
|
|
/* Push the address of the following instruction: */ |
477 |
|
|
low_pc = ((size_t)ic - (size_t)cpu->cd.avr.cur_ic_page) / |
478 |
|
|
sizeof(struct avr_instr_call); |
479 |
|
|
cpu->pc &= ~((AVR_IC_ENTRIES_PER_PAGE-1) |
480 |
|
|
<< AVR_INSTR_ALIGNMENT_SHIFT); |
481 |
|
|
cpu->pc += (low_pc << AVR_INSTR_ALIGNMENT_SHIFT); |
482 |
|
|
push_value(cpu, (cpu->pc >> 1) + 1, 2 + cpu->cd.avr.is_22bit); |
483 |
|
|
|
484 |
|
|
/* Calculate new PC from the next instruction + arg[1] */ |
485 |
|
|
cpu->pc += (int32_t)ic->arg[1]; |
486 |
|
|
|
487 |
|
|
/* Find the new physical page and update the translation pointers: */ |
488 |
|
|
avr_pc_to_pointers(cpu); |
489 |
|
|
} |
490 |
|
|
|
491 |
|
|
|
492 |
|
|
/* |
493 |
dpavlin |
14 |
* rjmp: Relative jump. |
494 |
|
|
* |
495 |
dpavlin |
24 |
* arg[1]: relative offset |
496 |
dpavlin |
14 |
*/ |
497 |
|
|
X(rjmp) |
498 |
|
|
{ |
499 |
|
|
uint32_t low_pc; |
500 |
|
|
|
501 |
|
|
cpu->cd.avr.extra_cycles ++; |
502 |
|
|
|
503 |
dpavlin |
24 |
/* Calculate new PC from the next instruction + arg[1] */ |
504 |
dpavlin |
14 |
low_pc = ((size_t)ic - (size_t)cpu->cd.avr.cur_ic_page) / |
505 |
|
|
sizeof(struct avr_instr_call); |
506 |
|
|
cpu->pc &= ~((AVR_IC_ENTRIES_PER_PAGE-1) |
507 |
|
|
<< AVR_INSTR_ALIGNMENT_SHIFT); |
508 |
|
|
cpu->pc += (low_pc << AVR_INSTR_ALIGNMENT_SHIFT); |
509 |
dpavlin |
24 |
cpu->pc += (int32_t)ic->arg[1]; |
510 |
dpavlin |
14 |
|
511 |
|
|
/* Find the new physical page and update the translation pointers: */ |
512 |
|
|
avr_pc_to_pointers(cpu); |
513 |
|
|
} |
514 |
|
|
|
515 |
|
|
|
516 |
|
|
/* |
517 |
|
|
* rjmp_samepage: Relative jump (to within the same translated page). |
518 |
|
|
* |
519 |
dpavlin |
24 |
* arg[1] = pointer to new avr_instr_call |
520 |
dpavlin |
14 |
*/ |
521 |
|
|
X(rjmp_samepage) |
522 |
|
|
{ |
523 |
|
|
cpu->cd.avr.extra_cycles ++; |
524 |
dpavlin |
24 |
cpu->cd.avr.next_ic = (struct avr_instr_call *) ic->arg[1]; |
525 |
dpavlin |
14 |
} |
526 |
|
|
|
527 |
|
|
|
528 |
|
|
/* |
529 |
|
|
* seX: Set an sreg bit. |
530 |
|
|
*/ |
531 |
|
|
X(sec) { cpu->cd.avr.sreg |= AVR_SREG_C; } |
532 |
|
|
X(sez) { cpu->cd.avr.sreg |= AVR_SREG_Z; } |
533 |
|
|
X(sen) { cpu->cd.avr.sreg |= AVR_SREG_N; } |
534 |
|
|
X(sev) { cpu->cd.avr.sreg |= AVR_SREG_V; } |
535 |
|
|
X(ses) { cpu->cd.avr.sreg |= AVR_SREG_S; } |
536 |
|
|
X(seh) { cpu->cd.avr.sreg |= AVR_SREG_H; } |
537 |
|
|
X(set) { cpu->cd.avr.sreg |= AVR_SREG_T; } |
538 |
|
|
X(sei) { cpu->cd.avr.sreg |= AVR_SREG_I; } |
539 |
|
|
|
540 |
|
|
|
541 |
|
|
/* |
542 |
dpavlin |
24 |
* push, pop: Push/pop a register onto/from the stack. |
543 |
dpavlin |
14 |
* |
544 |
dpavlin |
24 |
* arg[1]: ptr to rd |
545 |
dpavlin |
14 |
*/ |
546 |
dpavlin |
24 |
X(push) { push_value(cpu, *(uint8_t *)(ic->arg[1]), 1); |
547 |
|
|
cpu->cd.avr.extra_cycles ++; } |
548 |
|
|
X(pop) { uint32_t t; pop_value(cpu, &t, 1); *(uint8_t *)(ic->arg[1]) = t; |
549 |
|
|
cpu->cd.avr.extra_cycles ++; } |
550 |
|
|
|
551 |
|
|
|
552 |
|
|
/* |
553 |
|
|
* inc, dec: Increment/decrement a register. |
554 |
|
|
* |
555 |
|
|
* arg[1]: ptr to rd |
556 |
|
|
*/ |
557 |
|
|
X(inc) |
558 |
|
|
{ |
559 |
|
|
uint8_t x = *(uint8_t *)(ic->arg[1]) + 1; |
560 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
561 |
|
|
| AVR_SREG_Z); |
562 |
|
|
if (x == 0) |
563 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
564 |
|
|
if (x == 0x80) |
565 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_V; |
566 |
|
|
if (x & 0x80) |
567 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_N; |
568 |
|
|
if ((cpu->cd.avr.sreg & AVR_SREG_N? 1 : 0) ^ |
569 |
|
|
(cpu->cd.avr.sreg & AVR_SREG_V? 1 : 0)) |
570 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S; |
571 |
|
|
*(uint8_t *)(ic->arg[1]) = x; |
572 |
|
|
} |
573 |
|
|
X(dec) |
574 |
|
|
{ |
575 |
|
|
uint8_t x = *(uint8_t *)(ic->arg[1]) - 1; |
576 |
|
|
cpu->cd.avr.sreg &= ~(AVR_SREG_S | AVR_SREG_V | AVR_SREG_N |
577 |
|
|
| AVR_SREG_Z); |
578 |
|
|
if (x == 0) |
579 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_Z; |
580 |
|
|
if (x == 0x7f) |
581 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_V; |
582 |
|
|
if (x & 0x80) |
583 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_N; |
584 |
|
|
if ((cpu->cd.avr.sreg & AVR_SREG_N? 1 : 0) ^ |
585 |
|
|
(cpu->cd.avr.sreg & AVR_SREG_V? 1 : 0)) |
586 |
|
|
cpu->cd.avr.sreg |= AVR_SREG_S; |
587 |
|
|
*(uint8_t *)(ic->arg[1]) = x; |
588 |
|
|
} |
589 |
|
|
|
590 |
|
|
|
591 |
|
|
/* |
592 |
|
|
* swap: Swap nibbles in a register. |
593 |
|
|
* |
594 |
|
|
* arg[1]: ptr to rd |
595 |
|
|
*/ |
596 |
dpavlin |
14 |
X(swap) |
597 |
|
|
{ |
598 |
dpavlin |
24 |
uint8_t x = *(uint8_t *)(ic->arg[1]); |
599 |
|
|
*(uint8_t *)(ic->arg[1]) = (x >> 4) | (x << 4); |
600 |
dpavlin |
14 |
} |
601 |
|
|
|
602 |
|
|
|
603 |
|
|
/*****************************************************************************/ |
604 |
|
|
|
605 |
|
|
|
606 |
|
|
X(end_of_page) |
607 |
|
|
{ |
608 |
|
|
/* Update the PC: (offset 0, but on the next page) */ |
609 |
|
|
cpu->pc &= ~((AVR_IC_ENTRIES_PER_PAGE-1) << 1); |
610 |
|
|
cpu->pc += (AVR_IC_ENTRIES_PER_PAGE << 1); |
611 |
|
|
|
612 |
|
|
/* Find the new physical page and update the translation pointers: */ |
613 |
|
|
avr_pc_to_pointers(cpu); |
614 |
|
|
|
615 |
|
|
/* end_of_page doesn't count as an executed instruction: */ |
616 |
|
|
cpu->n_translated_instrs --; |
617 |
|
|
} |
618 |
|
|
|
619 |
|
|
|
620 |
|
|
/*****************************************************************************/ |
621 |
|
|
|
622 |
|
|
|
623 |
|
|
/* |
624 |
|
|
* avr_combine_instructions(): |
625 |
|
|
* |
626 |
|
|
* Combine two or more instructions, if possible, into a single function call. |
627 |
|
|
*/ |
628 |
|
|
void avr_combine_instructions(struct cpu *cpu, struct avr_instr_call *ic, |
629 |
|
|
uint32_t addr) |
630 |
|
|
{ |
631 |
|
|
int n_back; |
632 |
|
|
n_back = (addr >> 1) & (AVR_IC_ENTRIES_PER_PAGE-1); |
633 |
|
|
|
634 |
|
|
if (n_back >= 1) { |
635 |
|
|
/* TODO */ |
636 |
|
|
} |
637 |
|
|
|
638 |
|
|
/* TODO: Combine forward as well */ |
639 |
|
|
} |
640 |
|
|
|
641 |
|
|
|
642 |
|
|
/*****************************************************************************/ |
643 |
|
|
|
644 |
|
|
|
645 |
dpavlin |
24 |
static uint16_t read_word(struct cpu *cpu, unsigned char *ib, int addr) |
646 |
|
|
{ |
647 |
|
|
uint16_t iword; |
648 |
|
|
unsigned char *page = cpu->cd.avr.host_load[addr >> 12]; |
649 |
|
|
|
650 |
|
|
if (page != NULL) { |
651 |
|
|
/* fatal("TRANSLATION HIT!\n"); */ |
652 |
|
|
memcpy(ib, page + (addr & 0xfff), sizeof(uint16_t)); |
653 |
|
|
} else { |
654 |
|
|
/* fatal("TRANSLATION MISS!\n"); */ |
655 |
|
|
if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, |
656 |
|
|
sizeof(uint16_t), MEM_READ, CACHE_INSTRUCTION)) { |
657 |
|
|
fatal("to_be_translated(): " |
658 |
|
|
"read failed: TODO\n"); |
659 |
|
|
exit(1); |
660 |
|
|
} |
661 |
|
|
} |
662 |
|
|
|
663 |
|
|
iword = *((uint16_t *)&ib[0]); |
664 |
|
|
|
665 |
|
|
#ifdef HOST_BIG_ENDIAN |
666 |
|
|
iword = ((iword & 0xff) << 8) | |
667 |
|
|
((iword & 0xff00) >> 8); |
668 |
|
|
#endif |
669 |
|
|
return iword; |
670 |
|
|
} |
671 |
|
|
|
672 |
|
|
|
673 |
dpavlin |
14 |
/* |
674 |
|
|
* avr_instr_to_be_translated(): |
675 |
|
|
* |
676 |
|
|
* Translate an instruction word into an avr_instr_call. ic is filled in with |
677 |
|
|
* valid data for the translated instruction, or a "nothing" instruction if |
678 |
|
|
* there was a translation failure. The newly translated instruction is then |
679 |
|
|
* executed. |
680 |
|
|
*/ |
681 |
|
|
X(to_be_translated) |
682 |
|
|
{ |
683 |
dpavlin |
24 |
int addr, low_pc, rd, rr, tmp, main_opcode, a; |
684 |
dpavlin |
14 |
uint16_t iword; |
685 |
|
|
unsigned char ib[2]; |
686 |
|
|
void (*samepage_function)(struct cpu *, struct avr_instr_call *); |
687 |
|
|
|
688 |
|
|
/* Figure out the (virtual) address of the instruction: */ |
689 |
|
|
low_pc = ((size_t)ic - (size_t)cpu->cd.avr.cur_ic_page) |
690 |
|
|
/ sizeof(struct avr_instr_call); |
691 |
|
|
addr = cpu->pc & ~((AVR_IC_ENTRIES_PER_PAGE-1) << |
692 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT); |
693 |
|
|
addr += (low_pc << AVR_INSTR_ALIGNMENT_SHIFT); |
694 |
|
|
cpu->pc = addr; |
695 |
|
|
addr &= ~((1 << AVR_INSTR_ALIGNMENT_SHIFT) - 1); |
696 |
|
|
|
697 |
|
|
addr &= cpu->cd.avr.pc_mask; |
698 |
|
|
|
699 |
|
|
/* Read the instruction word from memory: */ |
700 |
dpavlin |
24 |
iword = read_word(cpu, ib, addr); |
701 |
dpavlin |
14 |
|
702 |
|
|
|
703 |
|
|
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
704 |
|
|
#include "cpu_dyntrans.c" |
705 |
|
|
#undef DYNTRANS_TO_BE_TRANSLATED_HEAD |
706 |
|
|
|
707 |
|
|
|
708 |
dpavlin |
24 |
/* Default instruction length: */ |
709 |
|
|
ic->arg[0] = 1; |
710 |
|
|
|
711 |
|
|
|
712 |
dpavlin |
14 |
/* |
713 |
|
|
* Translate the instruction: |
714 |
|
|
*/ |
715 |
|
|
main_opcode = iword >> 12; |
716 |
|
|
|
717 |
|
|
switch (main_opcode) { |
718 |
|
|
|
719 |
|
|
case 0x0: |
720 |
|
|
if (iword == 0x0000) { |
721 |
|
|
ic->f = instr(nop); |
722 |
|
|
break; |
723 |
|
|
} |
724 |
|
|
goto bad; |
725 |
|
|
|
726 |
|
|
case 0x2: |
727 |
dpavlin |
24 |
if ((iword & 0xfc00) == 0x2000) { |
728 |
|
|
rd = (iword & 0x1f0) >> 4; |
729 |
|
|
rr = ((iword & 0x200) >> 5) | (iword & 0xf); |
730 |
|
|
ic->f = instr(and); |
731 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rr]); |
732 |
|
|
ic->arg[2] = (size_t)(&cpu->cd.avr.r[rd]); |
733 |
|
|
break; |
734 |
|
|
} |
735 |
|
|
if ((iword & 0xfc00) == 0x2400) { |
736 |
|
|
rd = (iword & 0x1f0) >> 4; |
737 |
|
|
rr = ((iword & 0x200) >> 5) | (iword & 0xf); |
738 |
|
|
ic->f = instr(eor); |
739 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rr]); |
740 |
|
|
ic->arg[2] = (size_t)(&cpu->cd.avr.r[rd]); |
741 |
|
|
break; |
742 |
|
|
} |
743 |
dpavlin |
14 |
if ((iword & 0xfc00) == 0x2c00) { |
744 |
|
|
rd = (iword & 0x1f0) >> 4; |
745 |
|
|
rr = ((iword & 0x200) >> 5) | (iword & 0xf); |
746 |
|
|
ic->f = instr(mov); |
747 |
dpavlin |
24 |
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rr]); |
748 |
|
|
ic->arg[2] = (size_t)(&cpu->cd.avr.r[rd]); |
749 |
|
|
break; |
750 |
|
|
} |
751 |
|
|
goto bad; |
752 |
|
|
|
753 |
|
|
case 0x3: |
754 |
|
|
rd = ((iword >> 4) & 15) + 16; |
755 |
|
|
ic->f = instr(cpi); |
756 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
757 |
|
|
ic->arg[2] = ((iword >> 4) & 0xf0) + (iword & 0xf); |
758 |
|
|
break; |
759 |
|
|
|
760 |
|
|
case 0x7: |
761 |
|
|
rd = ((iword >> 4) & 15) + 16; |
762 |
|
|
ic->f = instr(andi); |
763 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
764 |
|
|
ic->arg[2] = ((iword >> 4) & 0xf0) + (iword & 0xf); |
765 |
|
|
break; |
766 |
|
|
|
767 |
|
|
case 0x8: |
768 |
|
|
if ((iword & 0xfe0f) == 0x8008) { |
769 |
|
|
rd = (iword >> 4) & 31; |
770 |
|
|
ic->f = instr(ld_y); |
771 |
dpavlin |
14 |
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
772 |
|
|
break; |
773 |
|
|
} |
774 |
dpavlin |
24 |
if ((iword & 0xfe0f) == 0x8208) { |
775 |
|
|
rd = (iword >> 4) & 31; |
776 |
|
|
ic->f = instr(st_y); |
777 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
778 |
|
|
break; |
779 |
|
|
} |
780 |
dpavlin |
14 |
goto bad; |
781 |
|
|
|
782 |
|
|
case 0x9: |
783 |
dpavlin |
24 |
if ((iword & 0xfe0f) == 0x900f) { |
784 |
|
|
rd = (iword >> 4) & 31; |
785 |
|
|
ic->f = instr(pop); |
786 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
787 |
|
|
break; |
788 |
|
|
} |
789 |
|
|
if ((iword & 0xfe0f) == 0x9200) { |
790 |
|
|
uint8_t tmpbytes[2]; |
791 |
|
|
ic->arg[0] = 2; /* Note: 2 words! */ |
792 |
|
|
ic->f = instr(sts); |
793 |
|
|
rd = (iword >> 4) & 31; |
794 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
795 |
|
|
ic->arg[2] = read_word(cpu, tmpbytes, addr + 2); |
796 |
|
|
break; |
797 |
|
|
} |
798 |
|
|
if ((iword & 0xfe0f) == 0x9209) { |
799 |
|
|
rd = (iword >> 4) & 31; |
800 |
|
|
ic->f = instr(st_y_plus); |
801 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
802 |
|
|
break; |
803 |
|
|
} |
804 |
|
|
if ((iword & 0xfe0f) == 0x920a) { |
805 |
|
|
rd = (iword >> 4) & 31; |
806 |
|
|
ic->f = instr(st_minus_y); |
807 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
808 |
|
|
break; |
809 |
|
|
} |
810 |
|
|
if ((iword & 0xfe0f) == 0x920f) { |
811 |
|
|
rd = (iword >> 4) & 31; |
812 |
|
|
ic->f = instr(push); |
813 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
814 |
|
|
break; |
815 |
|
|
} |
816 |
dpavlin |
14 |
if ((iword & 0xfe0f) == 0x9402) { |
817 |
|
|
rd = (iword >> 4) & 31; |
818 |
|
|
ic->f = instr(swap); |
819 |
dpavlin |
24 |
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
820 |
dpavlin |
14 |
break; |
821 |
|
|
} |
822 |
dpavlin |
24 |
if ((iword & 0xfe0f) == 0x9403) { |
823 |
|
|
rd = (iword >> 4) & 31; |
824 |
|
|
ic->f = instr(inc); |
825 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
826 |
|
|
break; |
827 |
|
|
} |
828 |
dpavlin |
14 |
if ((iword & 0xff8f) == 0x9408) { |
829 |
|
|
switch ((iword >> 4) & 7) { |
830 |
|
|
case 0: ic->f = instr(sec); break; |
831 |
|
|
case 1: ic->f = instr(sez); break; |
832 |
|
|
case 2: ic->f = instr(sen); break; |
833 |
|
|
case 3: ic->f = instr(sev); break; |
834 |
|
|
case 4: ic->f = instr(ses); break; |
835 |
|
|
case 5: ic->f = instr(seh); break; |
836 |
|
|
case 6: ic->f = instr(set); break; |
837 |
|
|
case 7: ic->f = instr(sei); break; |
838 |
|
|
} |
839 |
|
|
break; |
840 |
|
|
} |
841 |
dpavlin |
24 |
if ((iword & 0xfe0f) == 0x940a) { |
842 |
|
|
rd = (iword >> 4) & 31; |
843 |
|
|
ic->f = instr(dec); |
844 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
845 |
|
|
break; |
846 |
|
|
} |
847 |
dpavlin |
14 |
if ((iword & 0xff8f) == 0x9488) { |
848 |
|
|
switch ((iword >> 4) & 7) { |
849 |
|
|
case 0: ic->f = instr(clc); break; |
850 |
|
|
case 1: ic->f = instr(clz); break; |
851 |
|
|
case 2: ic->f = instr(cln); break; |
852 |
|
|
case 3: ic->f = instr(clv); break; |
853 |
|
|
case 4: ic->f = instr(cls); break; |
854 |
|
|
case 5: ic->f = instr(clh); break; |
855 |
|
|
case 6: ic->f = instr(clt); break; |
856 |
|
|
case 7: ic->f = instr(cli); break; |
857 |
|
|
} |
858 |
|
|
break; |
859 |
|
|
} |
860 |
dpavlin |
24 |
if ((iword & 0xffff) == 0x9508) { |
861 |
|
|
ic->f = instr(ret); |
862 |
|
|
break; |
863 |
|
|
} |
864 |
|
|
if ((iword & 0xffff) == 0x95c8) { |
865 |
|
|
ic->f = instr(lpm); |
866 |
|
|
break; |
867 |
|
|
} |
868 |
|
|
if ((iword & 0xff00) == 0x9600) { |
869 |
|
|
ic->f = instr(adiw); |
870 |
|
|
rd = ((iword >> 3) & 6) + 24; |
871 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
872 |
|
|
ic->arg[2] = (iword & 15) + ((iword & 0xc0) >> 2); |
873 |
|
|
break; |
874 |
|
|
} |
875 |
|
|
if ((iword & 0xfd00) == 0x9800) { |
876 |
|
|
if (iword & 0x200) |
877 |
|
|
ic->f = instr(sbi); |
878 |
|
|
else |
879 |
|
|
ic->f = instr(cbi); |
880 |
|
|
ic->arg[1] = (iword >> 3) & 31; |
881 |
|
|
ic->arg[2] = 1 << (iword & 7); |
882 |
|
|
if (!(iword & 0x200)) |
883 |
|
|
ic->arg[2] = ~ic->arg[2]; |
884 |
|
|
break; |
885 |
|
|
} |
886 |
dpavlin |
14 |
goto bad; |
887 |
|
|
|
888 |
dpavlin |
24 |
case 0xb: |
889 |
|
|
if ((iword & 0xf800) == 0xb800) { |
890 |
|
|
a = ((iword & 0x600) >> 5) | (iword & 0xf); |
891 |
|
|
rr = (iword >> 4) & 31; |
892 |
|
|
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rr]); |
893 |
|
|
ic->arg[2] = a; |
894 |
|
|
switch (a) { |
895 |
|
|
case 0x1a: ic->f = instr(out_ddra); break; |
896 |
|
|
case 0x17: ic->f = instr(out_ddrb); break; |
897 |
|
|
case 0x14: ic->f = instr(out_ddrc); break; |
898 |
|
|
case 0x11: ic->f = instr(out_ddrd); break; |
899 |
|
|
case 0x1b: ic->f = instr(out_porta); break; |
900 |
|
|
case 0x18: ic->f = instr(out_portb); break; |
901 |
|
|
case 0x15: ic->f = instr(out_portc); break; |
902 |
|
|
case 0x12: ic->f = instr(out_portd); break; |
903 |
|
|
default:ic->f = instr(out); |
904 |
|
|
} |
905 |
|
|
break; |
906 |
|
|
} |
907 |
|
|
goto bad; |
908 |
|
|
|
909 |
|
|
case 0xc: /* rjmp */ |
910 |
|
|
case 0xd: /* rcall */ |
911 |
|
|
samepage_function = NULL; |
912 |
|
|
switch (main_opcode) { |
913 |
|
|
case 0xc: |
914 |
|
|
ic->f = instr(rjmp); |
915 |
|
|
samepage_function = instr(rjmp_samepage); |
916 |
|
|
break; |
917 |
|
|
case 0xd: |
918 |
|
|
ic->f = instr(rcall); |
919 |
|
|
break; |
920 |
|
|
} |
921 |
|
|
ic->arg[1] = (((int16_t)((iword & 0x0fff) << 4)) >> 3) + 2; |
922 |
dpavlin |
14 |
/* Special case: branch within the same page: */ |
923 |
dpavlin |
24 |
if (samepage_function != NULL) { |
924 |
dpavlin |
14 |
uint32_t mask_within_page = |
925 |
|
|
((AVR_IC_ENTRIES_PER_PAGE-1) << |
926 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT) | |
927 |
|
|
((1 << AVR_INSTR_ALIGNMENT_SHIFT) - 1); |
928 |
|
|
uint32_t old_pc = addr; |
929 |
dpavlin |
24 |
uint32_t new_pc = old_pc + (int32_t)ic->arg[1]; |
930 |
dpavlin |
14 |
if ((old_pc & ~mask_within_page) == |
931 |
|
|
(new_pc & ~mask_within_page)) { |
932 |
|
|
ic->f = samepage_function; |
933 |
dpavlin |
24 |
ic->arg[1] = (size_t) ( |
934 |
dpavlin |
14 |
cpu->cd.avr.cur_ic_page + |
935 |
|
|
((new_pc & mask_within_page) >> |
936 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT)); |
937 |
|
|
} |
938 |
|
|
} |
939 |
|
|
break; |
940 |
|
|
|
941 |
|
|
case 0xe: |
942 |
|
|
rd = ((iword >> 4) & 0xf) + 16; |
943 |
|
|
ic->f = instr(ldi); |
944 |
dpavlin |
24 |
ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]); |
945 |
|
|
ic->arg[2] = ((iword >> 4) & 0xf0) | (iword & 0xf); |
946 |
dpavlin |
14 |
break; |
947 |
|
|
|
948 |
dpavlin |
24 |
case 0xf: |
949 |
|
|
if ((iword & 0xfc07) == 0xf001) { |
950 |
|
|
ic->f = instr(breq); |
951 |
|
|
samepage_function = instr(breq_samepage); |
952 |
|
|
tmp = (iword >> 3) & 0x7f; |
953 |
|
|
if (tmp >= 64) |
954 |
|
|
tmp -= 128; |
955 |
|
|
ic->arg[1] = (tmp + 1) * 2; |
956 |
|
|
/* Special case: branch within the same page: */ |
957 |
|
|
if (samepage_function != NULL) { |
958 |
|
|
uint32_t mask_within_page = |
959 |
|
|
((AVR_IC_ENTRIES_PER_PAGE-1) << |
960 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT) | |
961 |
|
|
((1 << AVR_INSTR_ALIGNMENT_SHIFT) - 1); |
962 |
|
|
uint32_t old_pc = addr; |
963 |
|
|
uint32_t new_pc = old_pc + (int32_t)ic->arg[1]; |
964 |
|
|
if ((old_pc & ~mask_within_page) == |
965 |
|
|
(new_pc & ~mask_within_page)) { |
966 |
|
|
ic->f = samepage_function; |
967 |
|
|
ic->arg[1] = (size_t) ( |
968 |
|
|
cpu->cd.avr.cur_ic_page + |
969 |
|
|
((new_pc & mask_within_page) >> |
970 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT)); |
971 |
|
|
} |
972 |
|
|
} |
973 |
|
|
break; |
974 |
|
|
} |
975 |
|
|
/* TODO: refactor */ |
976 |
|
|
if ((iword & 0xfc07) == 0xf401) { |
977 |
|
|
ic->f = instr(brne); |
978 |
|
|
samepage_function = instr(brne_samepage); |
979 |
|
|
tmp = (iword >> 3) & 0x7f; |
980 |
|
|
if (tmp >= 64) |
981 |
|
|
tmp -= 128; |
982 |
|
|
ic->arg[1] = (tmp + 1) * 2; |
983 |
|
|
/* Special case: branch within the same page: */ |
984 |
|
|
if (samepage_function != NULL) { |
985 |
|
|
uint32_t mask_within_page = |
986 |
|
|
((AVR_IC_ENTRIES_PER_PAGE-1) << |
987 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT) | |
988 |
|
|
((1 << AVR_INSTR_ALIGNMENT_SHIFT) - 1); |
989 |
|
|
uint32_t old_pc = addr; |
990 |
|
|
uint32_t new_pc = old_pc + (int32_t)ic->arg[1]; |
991 |
|
|
if ((old_pc & ~mask_within_page) == |
992 |
|
|
(new_pc & ~mask_within_page)) { |
993 |
|
|
ic->f = samepage_function; |
994 |
|
|
ic->arg[1] = (size_t) ( |
995 |
|
|
cpu->cd.avr.cur_ic_page + |
996 |
|
|
((new_pc & mask_within_page) >> |
997 |
|
|
AVR_INSTR_ALIGNMENT_SHIFT)); |
998 |
|
|
} |
999 |
|
|
} |
1000 |
|
|
break; |
1001 |
|
|
} |
1002 |
|
|
goto bad; |
1003 |
|
|
|
1004 |
dpavlin |
14 |
default:goto bad; |
1005 |
|
|
} |
1006 |
|
|
|
1007 |
|
|
|
1008 |
|
|
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
1009 |
|
|
#include "cpu_dyntrans.c" |
1010 |
|
|
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |
1011 |
|
|
} |
1012 |
|
|
|