/[gxemul]/upstream/0.4.2/src/cpus/cpu_avr_instr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.4.2/src/cpus/cpu_avr_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations)
Mon Oct 8 16:20:48 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 25594 byte(s)
0.4.2
1 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
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 * $Id: cpu_avr_instr.c,v 1.15 2006/03/05 16:20:24 debug Exp $
29 *
30 * Atmel AVR (8-bit) instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (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 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 /*
76 * nop: Do nothing.
77 */
78 X(nop)
79 {
80 }
81
82
83 /*
84 * 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 * 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 * arg[1]: ptr to register
184 * arg[2]: byte value
185 */
186 X(ldi)
187 {
188 *(uint8_t *)(ic->arg[1]) = ic->arg[2];
189 }
190
191
192 /*
193 * ld_y: Load byte pointed to by register Y into a register.
194 *
195 * arg[1]: ptr to rd
196 */
197 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 X(mov)
348 {
349 *(uint8_t *)(ic->arg[2]) = *(uint8_t *)(ic->arg[1]);
350 }
351
352
353 /*
354 * 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 * rjmp: Relative jump.
494 *
495 * arg[1]: relative offset
496 */
497 X(rjmp)
498 {
499 uint32_t low_pc;
500
501 cpu->cd.avr.extra_cycles ++;
502
503 /* Calculate new PC from the next instruction + arg[1] */
504 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 cpu->pc += (int32_t)ic->arg[1];
510
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 * arg[1] = pointer to new avr_instr_call
520 */
521 X(rjmp_samepage)
522 {
523 cpu->cd.avr.extra_cycles ++;
524 cpu->cd.avr.next_ic = (struct avr_instr_call *) ic->arg[1];
525 }
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 * push, pop: Push/pop a register onto/from the stack.
543 *
544 * arg[1]: ptr to rd
545 */
546 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 X(swap)
597 {
598 uint8_t x = *(uint8_t *)(ic->arg[1]);
599 *(uint8_t *)(ic->arg[1]) = (x >> 4) | (x << 4);
600 }
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 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 /*
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 int addr, low_pc, rd, rr, tmp, main_opcode, a;
684 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 iword = read_word(cpu, ib, addr);
701
702
703 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
704 #include "cpu_dyntrans.c"
705 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
706
707
708 /* Default instruction length: */
709 ic->arg[0] = 1;
710
711
712 /*
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 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 if ((iword & 0xfc00) == 0x2c00) {
744 rd = (iword & 0x1f0) >> 4;
745 rr = ((iword & 0x200) >> 5) | (iword & 0xf);
746 ic->f = instr(mov);
747 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 ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]);
772 break;
773 }
774 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 goto bad;
781
782 case 0x9:
783 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 if ((iword & 0xfe0f) == 0x9402) {
817 rd = (iword >> 4) & 31;
818 ic->f = instr(swap);
819 ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]);
820 break;
821 }
822 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 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 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 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 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 goto bad;
887
888 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 /* Special case: branch within the same page: */
923 if (samepage_function != NULL) {
924 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 uint32_t new_pc = old_pc + (int32_t)ic->arg[1];
930 if ((old_pc & ~mask_within_page) ==
931 (new_pc & ~mask_within_page)) {
932 ic->f = samepage_function;
933 ic->arg[1] = (size_t) (
934 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 ic->arg[1] = (size_t)(&cpu->cd.avr.r[rd]);
945 ic->arg[2] = ((iword >> 4) & 0xf0) | (iword & 0xf);
946 break;
947
948 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 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

  ViewVC Help
Powered by ViewVC 1.1.26