1 // arm7f.cxx - Implementations of hand-written functions for the ARM7
2 // simulator. -*- C++ -*-
4 // Copyright (C) 1999, 2000 Red Hat.
5 // Portions Copyright (C) 2004 Sirius Satellite Radio Inc.
6 // This file is part of SID and is licensed under the GPL.
7 // See the file COPYING.SID for conditions for redistribution.
13 using namespace sidutil;
15 using namespace arm7f;
18 arm7f_cpu::arm7f_cpu ():
19 arm_engine (32768), // XXX: tune size
20 thumb_engine (32768), // XXX: tune size
23 // ??? One might want to quibble over the case of these pins (nFIQ?).
24 add_watchable_pin ("nm", & nm_pin);
25 add_watchable_pin ("tbit", & tbit_pin);
26 // add_watchable_pin ("isync", & isync_pin);
27 add_watchable_pin ("nfiq", & nfiq_pin);
28 add_watchable_pin ("nirq", & nirq_pin);
29 // add_watchable_pin ("nreset", & nreset_pin);
31 // Default is the scache engine.
32 this->set_scache_engine ();
33 // Don't set the registers etc to power-up values here.
34 // Defer it to the reset signal.
36 // Create attributes to access our innards.
39 // ??? However, the system distinguishes between the pc as being the
40 // current (or next) instruction to execute and the value of r15 read
41 // by an instruction (they're different, but related). The "pc" attribute
42 // returns the former, and "r15" the latter.
43 for (unsigned i = 0; i < 16; ++i)
45 string name = string ("r") + make_numeric_attribute (i);
46 SI* value = & this->hardware.h_gr[i];
47 this->add_watchable_register (name, value);
49 if (i >= 8 && i <= 14)
51 value = & this->hardware.h_gr_fiq[i-8];
52 this->add_watchable_register (name + "_fiq", value);
54 if (i >= 13 && i <= 14)
56 this->add_watchable_register (name + "_svc", & this->hardware.h_gr_svc[i-13]);
57 this->add_watchable_register (name + "_abt", & this->hardware.h_gr_abt[i-13]);
58 this->add_watchable_register (name + "_irq", & this->hardware.h_gr_irq[i-13]);
59 this->add_watchable_register (name + "_und", & this->hardware.h_gr_und[i-13]);
62 // add pc itself after r15
66 USI* value = & this->hardware.h_pc;
67 this->add_watchable_register (name, value);
70 // ... and for registers exposed via virtual attributes
71 add_attribute_virtual ("cpsr", this,
72 & arm7f_cpu::get_h_cpsr_for_attr,
73 & arm7f_cpu::set_h_cpsr_for_attr, "register");
74 this->triggerpoint_manager.add_watchable_attribute ("cpsr");
75 this->categorize ("cpsr", "watchable");
77 add_attribute_virtual ("cpsr-flags", this,
78 & arm7f_cpu::get_h_cpsr2_for_attr,
79 & arm7f_cpu::set_h_cpsr2_for_attr, "register");
81 add_watchable_register ("spsr_fiq", & this->hardware.h_spsr_fiq);
82 add_watchable_register ("spsr_svc", & this->hardware.h_spsr_svc);
83 add_watchable_register ("spsr_abt", & this->hardware.h_spsr_abt);
84 add_watchable_register ("spsr_irq", & this->hardware.h_spsr_irq);
85 add_watchable_register ("spsr_und", & this->hardware.h_spsr_und);
87 // Add register access for debugger
88 this->create_gdb_register_attrs (26, "7;11;13;14;15;25", & this->hardware.h_pc);
90 // These need to be 'pulled' high if they are not connected.
96 arm7f_cpu::get_h_cpsr2_for_attr ()
98 string n = this->hardware.h_nbit ? "N" : "";
99 string z = this->hardware.h_zbit ? "Z" : "";
100 string c = this->hardware.h_cbit ? "C" : "";
101 string v = this->hardware.h_vbit ? "V" : "";
102 string i = this->hardware.h_ibit ? "I" : "";
103 string f = this->hardware.h_fbit ? "F" : "";
104 string t = this->hardware.h_tbit ? "T" : "";
105 string m = string(":") +
106 (this->hardware.h_mbits == ARM_MODE_USER ? "USER" :
107 this->hardware.h_mbits == ARM_MODE_FIQ ? "FIQ" :
108 this->hardware.h_mbits == ARM_MODE_IRQ ? "IRQ" :
109 this->hardware.h_mbits == ARM_MODE_SUPERVISOR ? "SUPERVISOR" :
110 this->hardware.h_mbits == ARM_MODE_ABORT ? "ABORT" :
111 this->hardware.h_mbits == ARM_MODE_UNDEFINED ? "UNDEFINED" :
112 this->hardware.h_mbits == ARM_MODE_SYSTEM ? "SYSTEM" : "???");
114 return n + z + c + v + i + f + t + m;
122 // initialize registers to powerup values
124 // Initialize cpsr in a couple of steps.
125 // First "zero out" everything, then set anything that needs it.
126 // Remember that the mode bits can only have valid values.
127 // h_mbits must always have a valid value, so set it directly first, before
128 // calling h_cpsr_set.
129 this->hardware.h_mbits = ARM_MODE_SUPERVISOR;
130 this->h_cpsr_set (ARM_MODE_SUPERVISOR << 0);
131 // Mask out I and F interrupts.
132 this->h_ibit_set (1);
133 this->h_fbit_set (1);
135 // Make sure we are in arm mode
136 this->h_tbit_set (0);
138 // Point the PC at the reset handler.
141 // initialize various implementation state
143 this->pending_eit = EIT_NONE;
145 // Don't need to power-on-reset anything else, but do so anyway to aid
148 // Note that due to the way we handle the pc, setting h_gr[15] does not
149 // set the pc. Quibble if ya want.
150 for (int i = 0; i <= 15; ++i)
151 this->h_gr_set (i, 0);
152 for (int i = 0; i <= 7; ++i)
153 this->h_gr_usr_set (i, 0);
154 for (int i = 0; i <= 7; ++i)
155 this->h_gr_fiq_set (i, 0);
156 for (int i = 0; i <= 1; ++i)
157 this->h_gr_svc_set (i, 0);
158 for (int i = 0; i <= 1; ++i)
159 this->h_gr_abt_set (i, 0);
160 for (int i = 0; i <= 1; ++i)
161 this->h_gr_irq_set (i, 0);
162 for (int i = 0; i <= 1; ++i)
163 this->h_gr_und_set (i, 0);
164 this->h_spsr_fiq_set (0);
165 this->h_spsr_svc_set (0);
166 this->h_spsr_abt_set (0);
167 this->h_spsr_irq_set (0);
168 this->h_spsr_und_set (0);
170 // enable update_stepper from now on
171 this->initialized_p = true;
173 this->triggerpoint_manager.check_and_dispatch ();
175 // These need to be 'pulled' high if they are not connected.
183 arm7f_cpu::step_insns ()
185 if (! this->initialized_p)
187 cerr << "hw-cpu-arm7f: illegal step before initialization." << endl;
192 // Check for currently asserted interrupt pins. Interrupts are only checked for at each
193 // step size block of instructions.
194 if(!this->h_fbit_get() && !nfiq_pin.sense())
197 if(!this->h_ibit_get() && !nirq_pin.sense())
200 // If an eit is queued, process it now.
201 if (this->pending_eit != EIT_NONE)
202 this->process_eit (this->pending_eit);
204 if (this->engine_type == ENGINE_PBB)
206 if (this->h_tbit_get ())
207 this->step_thumb_pbb ();
209 this->step_arm_pbb ();
213 if (this->h_tbit_get ())
227 // Return h-mbits, as an ARM_MODE enum.
232 return (arm::ARM_MODE) this->h_mbits_get ();
236 arm7f_cpu::queue_eit (arm7f::eit new_eit)
238 if (this->pending_eit == new_eit)
241 // don't override higher priority eit
242 if (this->pending_eit != EIT_NONE)
244 // ARM DDI 0029E, page 3-14
245 int current_priority = this->eit_priority (this->pending_eit);
246 int new_priority = this->eit_priority (new_eit);
247 // higher priorities have lower numbers
248 if (new_priority >= current_priority)
252 this->pending_eit = new_eit;
254 // TODO: simultaneous data abort and fiq interrupt (page 3-14).
258 arm7f_cpu::eit_priority (arm7f::eit e)
264 case EIT_DATA_ABORT :
270 case EIT_PREFETCH_ABORT :
272 case EIT_UNDEFINED_INSN :
280 // FIXME: revisit making pc an arg
283 arm7f_cpu::process_eit (arm7f::eit new_eit)
285 // Clean the sucker out
286 this->flush_icache ();
288 PCADDR pc = this->h_pc_get ();
290 // At this point in the processing, pc is the address of the next
291 // insn to be executed.
295 case EIT_DATA_ABORT :
297 this->h_spsr_abt_set(this->h_cpsr_get());
298 this->h_tbit_set (0);
300 this->h_gr_abt_set (1, pc + 8);
301 this->h_mbits_set(ARM_MODE_ABORT);
302 this->h_pc_set (0x10);
303 this->pending_eit = EIT_NONE;
307 assert (! this->h_fbit_get ());
308 assert (this->mode () != ARM_MODE_FIQ);
309 // save cpsr before setting h-fbit
310 this->h_spsr_fiq_set (this->h_cpsr_get ());
311 this->h_fbit_set (1);
312 this->h_tbit_set (0);
314 this->h_gr_fiq_set (6, pc + 4);
315 this->h_mbits_set (ARM_MODE_FIQ);
316 this->h_pc_set (0x1c);
317 this->pending_eit = EIT_NONE;
321 assert (! this->h_ibit_get ());
322 assert (this->mode () != ARM_MODE_IRQ);
323 // save cpsr before setting h-ibit
324 this->h_spsr_irq_set (this->h_cpsr_get ());
325 this->h_ibit_set (1);
326 this->h_tbit_set (0);
328 this->h_gr_irq_set (1, pc + 4);
329 this->h_mbits_set (ARM_MODE_IRQ);
330 this->h_pc_set (0x18);
331 this->pending_eit = EIT_NONE;
334 case EIT_PREFETCH_ABORT :
336 this->h_spsr_abt_set(this->h_cpsr_get());
337 this->h_tbit_set (0);
339 this->h_gr_abt_set (1, pc + 4);
340 this->h_mbits_set(ARM_MODE_ABORT);
341 this->h_pc_set (0x0c);
342 this->pending_eit = EIT_NONE;
345 case EIT_UNDEFINED_INSN :
346 this->h_spsr_und_set (this->h_cpsr_get ());
348 if (this->h_tbit_get ())
349 this->h_gr_und_set (1, pc + 2);
351 this->h_gr_und_set (1, pc + 4);
352 this->h_tbit_set (0);
353 this->h_mbits_set (ARM_MODE_UNDEFINED);
354 this->h_pc_set (0x4);
355 this->pending_eit = EIT_NONE;
359 this->h_spsr_svc_set (this->h_cpsr_get ());
361 if (this->h_tbit_get ())
362 this->h_gr_svc_set (1, pc + 2);
364 this->h_gr_svc_set (1, pc + 4);
365 this->h_tbit_set (0);
366 this->h_mbits_set (ARM_MODE_SUPERVISOR);
367 this->h_pc_set (0x8);
368 this->pending_eit = EIT_NONE;
372 cgen_rtx_error ("Unknown EIT mode");
379 // Override for handling sets of the engine-type attribute.
382 arm7f_cpu::set_engine_type (const string& s)
384 component::status status;
386 status = cgen_bi_endian_cpu::set_engine_type (s);
387 if (status != component::ok)
389 if (this->engine_type == ENGINE_SCACHE)
390 this->set_scache_engine ();
391 else if (this->engine_type == ENGINE_PBB)
392 this->set_pbb_engine ();
394 return component::bad_value;
395 return component::ok;
399 arm7f_cpu::set_pbb_engine ()
401 this->engine_type = ENGINE_PBB;
402 this->update_engine ();
406 arm7f_cpu::set_scache_engine ()
408 this->engine_type = ENGINE_SCACHE;
409 this->update_engine ();
413 arm7f_cpu::update_engine ()
415 if (this->engine_type == ENGINE_PBB)
417 this->arm_engine.set_pbb_engine ();
418 this->thumb_engine.set_pbb_engine ();
422 this->arm_engine.set_scache_engine ();
423 this->thumb_engine.set_scache_engine ();
430 arm7f_cpu::step_arm ()
432 assert (! this->h_tbit_get ());
436 // Fetch/decode the instruction ------------------------------
437 PCADDR pc = this->h_pc_get ();
439 arm_scache* sem = this->arm_engine.find (pc, found);
444 USI insn = this->GETIMEMSI (pc, pc);
445 sem->decode (this, pc, insn, insn);
447 catch (cpu_memory_fault& t)
449 this->memory_trap (t);
454 // Execute the instruction -----------------------------------
455 if (this->trace_result_p)
456 this->begin_trace (pc, sem->idesc->insn_name);
459 if (this->eval_cond (sem->cond, pc))
461 // Set R15 in case the insn uses it.
462 this->h_gr_set (H_GR_PC, pc + sem->idesc->attrs.get_r15_offset_attr ());
463 sem->idesc->execute (this, sem);
467 this->h_pc_set (pc + 4);
470 catch (cpu_memory_fault& t)
472 this->memory_trap (t);
475 catch (cpu_exception& t)
479 if (this->trace_result_p)
483 // Do post-instruction processing ----------------------------
484 if (this->enable_step_trap_p)
485 this->signal_trap (sidutil::cpu_trap_stepped);
486 this->triggerpoint_manager.check_and_dispatch ();
488 // test for exit condition
489 if (stop_after_insns_p (1))
496 arm7f_cpu::step_thumb ()
498 assert (this->h_tbit_get ());
502 // Fetch/decode the instruction ------------------------------
503 PCADDR pc = this->h_pc_get ();
505 thumb_scache* sem = this->thumb_engine.find (pc, found);
510 UHI insn = this->GETIMEMHI (pc, pc);
511 sem->decode (this, pc, insn, insn);
513 catch (cpu_memory_fault& t)
515 this->memory_trap (t);
520 // Execute the instruction -----------------------------------
521 if (this->trace_result_p)
522 this->begin_trace (pc, sem->idesc->insn_name);
525 // Set R15 in case the insn uses it.
526 this->h_gr_set (H_GR_PC, pc + 4);
527 sem->idesc->execute (this, sem);
529 catch (cpu_memory_fault& t)
531 this->memory_trap (t);
534 catch (cpu_exception& t)
538 if (this->trace_result_p)
542 // Do post-instruction processing ----------------------------
543 if (this->enable_step_trap_p)
544 this->signal_trap (sidutil::cpu_trap_stepped);
545 this->triggerpoint_manager.check_and_dispatch ();
547 // test for exit condition
548 if (stop_after_insns_p (1))
555 // PBB steppers and support
558 arm7f_cpu::step_arm_pbb ()
560 assert (! this->h_tbit_get ());
562 // With single-stepping or active triggerpoints, use scache only
563 if (this->triggerpoint_manager.checking_any_p ()
564 || this->enable_step_trap_p)
565 return this->step_arm ();
569 // This function takes care of step_insn_count.
570 // There are no triggerpoints or single-stepping to worry about.
571 this->arm_pbb_run ();
573 catch (cpu_memory_fault& t)
575 this->memory_trap (t);
577 catch (cpu_exception& t)
584 arm7f_cpu::step_thumb_pbb ()
586 assert (this->h_tbit_get ());
588 // With single-stepping or active triggerpoints, use scache only
589 if (this->triggerpoint_manager.checking_any_p ()
590 || this->enable_step_trap_p)
591 return this->step_thumb ();
595 // This function takes care of step_insn_count.
596 // There are no triggerpoints or single-stepping to worry about.
597 this->thumb_pbb_run ();
599 catch (cpu_memory_fault& t)
601 this->memory_trap (t);
603 catch (cpu_exception& t)
610 // Compiler for the ARM PBB engine.
613 arm7f_cpu::arm_pbb_begin (PCADDR pc)
617 arm_engine_t* engine = & this->arm_engine;
618 bool trace_p = this->trace_result_p;
620 unsigned block_size = engine->max_real_insns (this);
622 // Multiply by enough so we have enough space for the virtual insns.
623 unsigned alloc_blocks;
626 // *4 = before,cond,insn,after insns. +1 = chain insn.
627 alloc_blocks = block_size * 4 + 1;
631 // *2 = cond,insn insns. +1 = chain insn.
632 alloc_blocks = block_size * 2 + 1;
635 vpc = engine->pbb_find_or_alloc (pc, alloc_blocks, found);
639 // Ok, here's where the real fun begins. Compile a pseudo-basic-block.
641 arm_scache* sc = vpc;
645 sc_end = vpc + (alloc_blocks
646 // back up to ensure there's room for all of the last insn
648 // and room for the final chain insn
651 sc_end = vpc + (alloc_blocks
652 // back up to ensure there's room for all of the last insn
654 // and room for the final chain insn
663 insn = this->GETIMEMSI (pc, pc);
665 catch (cpu_memory_fault& t)
667 this->memory_trap (t);
671 // FIXME: magic number
672 UINT cond = insn >> 28;
676 engine->compile_before_insn (this, sc, pc,
677 // FIXME: magic number
678 sc + (cond == 14 ? 1 : 2));
682 // First insert a conditional execution handler if needed.
683 // FIXME: magic number
686 engine->compile_cond_insn (this, sc, pc, cond);
691 sc->decode (this, pc, insn, insn);
692 sc->execute.cgoto = sc->idesc->cgoto;
694 // Compute whether we need to end the block at this insn now, while we
695 // have sc pointing to the insn's cache entry.
696 // ??? One call that tests both?
697 bool cti_p = (sc->idesc->attrs.get_uncond_cti_attr ()
698 || sc->idesc->attrs.get_cond_cti_attr ());
704 engine->compile_after_insn (this, sc, pc, sc - 1);
713 engine->compile_cti_chain_insn (this, sc, pc, count);
719 // Compile a chain insn to link to next block.
720 engine->compile_chain_insn (this, sc, pc, count);
725 // Compiler for the Thumb PBB engine.
728 arm7f_cpu::thumb_pbb_begin (PCADDR pc)
732 thumb_engine_t* engine = & this->thumb_engine;
733 bool trace_p = this->trace_result_p;
735 unsigned block_size = engine->max_real_insns (this);
737 // Multiply by enough so we have enough space for the virtual insns.
738 unsigned alloc_blocks;
741 // *3 = before,insn,after insns. +1 = chain insn.
742 alloc_blocks = block_size * 3 + 1;
747 alloc_blocks = block_size + 1;
750 vpc = engine->pbb_find_or_alloc (pc, alloc_blocks, found);
754 // Ok, here's where the real fun begins. Compile a pseudo-basic-block.
756 thumb_scache* sc = vpc;
758 thumb_scache* sc_end;
760 sc_end = vpc + (alloc_blocks
761 // back up to ensure there's room for all of the last insn
763 // and room for the final chain insn
766 sc_end = vpc + (alloc_blocks
767 // back up to ensure there's room for the chain insn
776 insn = this->GETIMEMHI (pc, pc);
778 catch (cpu_memory_fault& t)
780 this->memory_trap (t);
786 engine->compile_before_insn (this, sc, pc, sc + 1);
791 sc->decode (this, pc, insn, insn);
792 sc->execute.cgoto = sc->idesc->cgoto;
794 // Compute whether we need to end the block at this insn now, while we
795 // have sc pointing to the insn's cache entry.
796 // ??? One call that tests both?
797 bool cti_p = (sc->idesc->attrs.get_uncond_cti_attr ()
798 || sc->idesc->attrs.get_cond_cti_attr ());
804 engine->compile_after_insn (this, sc, pc, sc - 1);
813 engine->compile_cti_chain_insn (this, sc, pc, count);
819 // Compile a chain insn to link to next block.
820 engine->compile_chain_insn (this, sc, pc, count);
825 // Memory trap(/fault) handling.
828 arm7f_cpu::memory_trap (const cpu_memory_fault& t)
830 this->h_gr_set (H_GR_PC, t.pc);
831 this->h_pc_set (t.pc);
833 cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_memory_fault, t.address);
837 case cpu_trap_unhandled:
838 if (string (t.operation) == "insn read")
839 this->queue_eit (EIT_PREFETCH_ABORT);
841 this->queue_eit (EIT_DATA_ABORT);
846 PCADDR pc = t.pc + (this->h_tbit_get() ? 2 : 4); // skip this insn
847 this->h_gr_set (H_GR_PC, pc);
852 case cpu_trap_handled:
853 case cpu_trap_reissue:
863 // Invalid instruction handling.
865 // Give a component listening on our trap-type pin an opportunity to
866 // deal with it. If that fails, treat the fault like hardware would.
867 // PC is the address of the invalid insn.
870 arm7f_cpu::invalid_insn (PCADDR pc)
872 this->h_gr_set (H_GR_PC, pc);
875 cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_invalid_insn, pc);
879 case cpu_trap_unhandled:
880 this->h_gr_set (H_GR_PC, pc);
882 this->queue_eit (EIT_UNDEFINED_INSN);
887 PCADDR npc = pc + (this->h_tbit_get() ? 2 : 4); // skip this insn
888 this->h_gr_set (H_GR_PC, npc);
889 this->h_pc_set (npc);
893 case cpu_trap_handled:
894 case cpu_trap_reissue:
902 throw cpu_exception ();
907 // Special "nreset" pin handling.
909 arm7f_cpu::do_nreset_pin (host_int_4 value)
911 // FIXME: Should be able to catch transitions but can't do
912 // that with callback_pin.
913 //if (nreset_pin.sense () == value)
918 // Reset pin has gone high, start executing insns.
920 // Initialize cpsr in a couple of steps.
921 // First "zero out" everything, then set anything that needs it.
922 // Remember that the mode bits can only have valid values.
923 // h_mbits must always have a valid value, so set it directly first,
924 // before calling h_cpsr_set.
925 this->hardware.h_mbits = ARM_MODE_SUPERVISOR;
926 this->h_cpsr_set (ARM_MODE_SUPERVISOR << 0);
927 this->h_ibit_set (1);
928 this->h_fbit_set (1);
932 this->pending_eit = EIT_NONE;
936 // Reset pin has gone low, put cpu in reset state.
937 this->step_pin.set_callback (& arm7f_cpu::step_reset);
939 // lock out other interrupts (EIT_RESET has highest priority)
940 this->pending_eit = EIT_RESET;
946 // Stepper while reset pin is held low.
947 // XXX: not implemented
949 arm7f_cpu::step_reset (host_int_4)
951 assert (! this->nreset_pin.sense ());
953 // See ARM DDI 0029E, page 3-15.
954 // ??? It doesn't say what happens if a reset happens while in thumb mode
955 // [do half-word insns get fetched?], but presumably it doesn't matter. :-)
956 PCADDR pc = this->h_pc_get () & 0xfffffffc;
957 //SI insn = this->GETIMEMSI(pc, pc); // FIXME: what if there's a SIGSEGV?
958 this->h_pc_set (pc + 4);
960 this->triggerpoint_manager.check_and_dispatch ();
965 // EIT (exception, interrupt, and trap) pins.
968 // Miscellaneous pins.
971 arm7f_cpu::flush_icache ()
973 this->thumb_engine.flush ();
974 this->arm_engine.flush ();
977 // Additional support for setting particular hardware regs.
978 // Update tbit_pin based on given new value for the T bit.
979 // Yield from instruction engine loop to make isa switch effective.
981 arm7f_cpu::arm_tbit_set (BI newval)
983 // Tell existing engine to yield control if we're switching engines.
984 // ??? Should only do this if running, though it's harmless if not.
985 BI oldval = this->h_tbit_get ();
986 if (oldval == newval)
989 this->hardware.h_tbit = newval;
991 if (this->warnings_enabled)
994 this->trace_stream << " <switching to thumb mode> ";
996 this->trace_stream << " <switching to arm mode> ";
999 // Update the tbit pin.
1000 this->tbit_pin.drive (newval);
1003 // This should arrange an immediate exit from the scache/pbb engine loops.
1007 // Update the h-gr regs based on the new value for M4-M0.
1008 // Also update nm_pin.
1010 arm7f_cpu::arm_mbits_set (UINT newval)
1012 UINT oldval = this->h_mbits_get ();
1014 // exit quickly for frequent case
1015 // N.B. code below assumes this is done
1016 if (newval == oldval)
1019 // swap out the current set of r8-r12
1022 case ARM_MODE_USER :
1023 case ARM_MODE_SYSTEM :
1024 case ARM_MODE_SUPERVISOR :
1025 case ARM_MODE_ABORT :
1027 case ARM_MODE_UNDEFINED :
1032 cerr << "hw-cpu-arm7t: ignoring invalid h-mbits:" << newval << endl;
1036 // swap out the current set of r8-r12
1039 case ARM_MODE_USER :
1040 case ARM_MODE_SYSTEM :
1041 case ARM_MODE_SUPERVISOR :
1042 case ARM_MODE_ABORT :
1044 case ARM_MODE_UNDEFINED :
1045 // nothing to do unless new mode is fiq
1046 if (newval != ARM_MODE_FIQ)
1048 for (int i = 8; i <= 12; ++i)
1049 this->h_gr_usr_set (i - 8, this->h_gr_get (i));
1052 for (int i = 8; i <= 12; ++i)
1053 this->h_gr_fiq_set (i - 8, this->h_gr_get (i));
1059 // swap in the new set of r8-r12
1062 case ARM_MODE_USER :
1063 case ARM_MODE_SYSTEM :
1064 case ARM_MODE_SUPERVISOR :
1065 case ARM_MODE_ABORT :
1067 case ARM_MODE_UNDEFINED :
1068 // nothing to do unless old mode was fiq
1069 if (oldval != ARM_MODE_FIQ)
1071 for (int i = 8; i <= 12; ++i)
1072 this->h_gr_set (i, this->h_gr_usr_get (i - 8));
1075 for (int i = 8; i <= 12; ++i)
1076 this->h_gr_set (i, this->h_gr_fiq_get (i - 8));
1080 // swap out the current set of r13,r14
1083 case ARM_MODE_USER :
1084 case ARM_MODE_SYSTEM :
1085 // nothing to do if new mode is the other of the two
1086 if (newval == ARM_MODE_USER || newval == ARM_MODE_SYSTEM)
1088 for (int i = 13; i <= 14; ++i)
1089 this->h_gr_usr_set (i - 8, this->h_gr_get (i));
1091 case ARM_MODE_SUPERVISOR :
1092 for (int i = 13; i <= 14; ++i)
1093 this->h_gr_svc_set (i - 13, this->h_gr_get (i));
1095 case ARM_MODE_ABORT :
1096 for (int i = 13; i <= 14; ++i)
1097 this->h_gr_abt_set (i - 13, this->h_gr_get (i));
1100 for (int i = 13; i <= 14; ++i)
1101 this->h_gr_irq_set (i - 13, this->h_gr_get (i));
1103 case ARM_MODE_UNDEFINED :
1104 for (int i = 13; i <= 14; ++i)
1105 this->h_gr_und_set (i - 13, this->h_gr_get (i));
1108 for (int i = 13; i <= 14; ++i)
1109 this->h_gr_fiq_set (i - 8, this->h_gr_get (i));
1115 // swap in the new set of r13,r14
1118 case ARM_MODE_USER :
1119 case ARM_MODE_SYSTEM :
1120 // nothing to do if old mode was the other of the two
1121 if (oldval == ARM_MODE_USER || oldval == ARM_MODE_SYSTEM)
1123 for (int i = 13; i <= 14; ++i)
1124 this->h_gr_set (i, this->h_gr_usr_get (i - 8));
1126 case ARM_MODE_SUPERVISOR :
1127 for (int i = 13; i <= 14; ++i)
1128 this->h_gr_set (i, this->h_gr_svc_get (i - 13));
1130 case ARM_MODE_ABORT :
1131 for (int i = 13; i <= 14; ++i)
1132 this->h_gr_set (i, this->h_gr_abt_get (i - 13));
1135 for (int i = 13; i <= 14; ++i)
1136 this->h_gr_set (i, this->h_gr_irq_get (i - 13));
1138 case ARM_MODE_UNDEFINED :
1139 for (int i = 13; i <= 14; ++i)
1140 this->h_gr_set (i, this->h_gr_und_get (i - 13));
1143 for (int i = 13; i <= 14; ++i)
1144 this->h_gr_set (i, this->h_gr_fiq_get (i - 8));
1148 // Finally update register
1149 this->hardware.h_mbits = newval;
1150 // Update the nm pin.
1151 this->nm_pin.drive ((~newval) & 0x1f);
1154 // Software generated interrupt support.
1157 arm7f_cpu::arm_swi (PCADDR pc, UINT arg)
1159 // Update recorded pc in case software trap handling component wants to
1160 // use it. This is also needed if the insn is handled as hardware would.
1161 this->h_gr_set (H_GR_PC, pc);
1162 this->h_pc_set (pc);
1164 cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_software, arg);
1168 case cpu_trap_unhandled:
1169 this->queue_eit (EIT_SWI_INSN);
1174 PCADDR npc = pc + (this->h_tbit_get() ? 2 : 4); // skip this insn
1175 this->h_gr_set (H_GR_PC, npc);
1176 this->h_pc_set (npc);
1180 case cpu_trap_handled:
1181 case cpu_trap_reissue:
1189 throw cpu_exception ();
1194 arm7f_cpu::thumb_swi (PCADDR pc, UINT arg)
1196 return this->arm_swi (pc, arg);
1199 // State dump/restore support.
1202 arm7f_cpu::stream_state (ostream& o) const
1204 // call base class first
1205 cgen_bi_endian_cpu::stream_state (o);
1207 // component and cpu variant indicators
1212 o << " " << initialized_p
1213 << " " << static_cast<int>(pending_eit);
1219 << " " << nirq_pin << endl;
1221 // XXX: Cheat by dumping the entire hardware struct in binary form. That
1222 // means that this state image will not be restorable on a different
1223 // endianness host platform.
1224 string hw = string(reinterpret_cast<const char*>(& this->hardware), sizeof(this->hardware));
1225 o << " " << string2stream(hw);
1229 arm7f_cpu::destream_state (istream& i)
1231 // call base class first
1232 cgen_bi_endian_cpu::destream_state (i);
1236 if (key != "arm-cpu")
1238 i.setstate (ios::badbit);
1244 if (cpu_variant != "arm7tdmi")
1246 i.setstate (ios::badbit);
1251 int pending_eit_asint;
1253 >> pending_eit_asint;
1254 pending_eit = static_cast<arm7f::eit>(pending_eit_asint);
1263 i >> stream2string(hw);
1264 if (hw.size() != sizeof(this->hardware))
1265 i.setstate (ios::badbit);
1268 const char* hwbin = hw.data();
1269 ::memcpy (reinterpret_cast<char*>(& this->hardware), hwbin, sizeof(this->hardware));
1272 // reinitialize derived state
1278 // Debugger interface functions: return bitwise register images in
1279 // "target byte order".
1282 arm7f_cpu::dbg_get_reg (host_int_4 reg)
1286 if (reg < 16) // general purpose registers
1291 value = h_pc_get ();
1293 value = h_gr_get (reg);
1295 // change to "target endian"
1296 if (current_endianness() == endian_big)
1298 big_int_4 v = value;
1299 for (unsigned i=0; i<4; i++)
1300 attr += v.read_byte (i);
1304 little_int_4 v = value;
1305 for (unsigned i=0; i<4; i++)
1306 attr += v.read_byte (i);
1308 assert (attr.length () == 4);
1310 else if ((reg >= 16) && (reg <= 23)) // floating point registers
1312 for (unsigned i = 0; i < 12; i++)
1314 assert (attr.length () == 12);
1316 else if (reg == 24) // floating point status ?
1318 for (unsigned i = 0; i < 4; i++)
1320 assert (attr.length () == 4);
1322 else if (reg == 25) // cpsr
1324 host_int_4 value = h_cpsr_get ();
1326 // change to "target endian"
1327 if (current_endianness() == endian_big)
1329 big_int_4 v = value;
1330 for (unsigned i=0; i<4; i++)
1331 attr += v.read_byte (i);
1335 little_int_4 v = value;
1336 for (unsigned i=0; i<4; i++)
1337 attr += v.read_byte (i);
1339 assert (attr.length () == 4);
1347 arm7f_cpu::dbg_set_reg (host_int_4 reg, const string& attr)
1349 if (reg < 16) // general purpose registers
1351 if (attr.length () != 4)
1352 return component::bad_value;
1355 // change from "target endian"
1356 if (current_endianness() == endian_big)
1359 for (unsigned i=0; i<4; i++)
1360 v.write_byte (i, attr[i]);
1366 for (unsigned i=0; i<4; i++)
1367 v.write_byte (i, attr[i]);
1374 h_gr_set (reg, value);
1376 return component::ok;
1378 else if ((reg >= 16) && (reg <= 23)) // floating point registers
1380 if (attr.length () != 12)
1381 return component::bad_value;
1383 return component::ok;
1385 else if (reg == 24) // floating point status ?
1387 if (attr.length () != 4)
1388 return component::bad_value;
1390 return component::ok;
1392 else if (reg == 25) // cpsr
1394 if (attr.length () != 4)
1395 return component::bad_value;
1398 // change from "target endian"
1399 if (current_endianness() == endian_big)
1402 for (unsigned i=0; i<4; i++)
1403 v.write_byte (i, attr[i]);
1409 for (unsigned i=0; i<4; i++)
1410 v.write_byte (i, attr[i]);
1416 return component::ok;
1419 return component::not_found;
1424 // ----------------------------------------------------------------------------
1425 // More semantic helper routines -- too large to inline throughout
1427 // Support for operand2 in the data processing insns.
1430 // Shift RM according to TYPE,SHIFT.
1431 // XXX: Semantic subroutines in cgen would be useful here. If the
1432 // subroutines are inlined the only benefit would be readability of the
1433 // generated code. Still, that's not irrelevant.
1435 // FIXME: making this inline is a quick hack to work around a compilation
1436 // problem (symbol undefined).
1439 arm7f_cpu::compute_operand2_immshift (SI rm, int type, int shift)
1443 case SHIFT_TYPE_LSL : return rm << shift;
1444 case SHIFT_TYPE_LSR : return (USI) rm >> shift;
1445 case SHIFT_TYPE_ASR : return rm >> shift;
1446 case SHIFT_TYPE_ROR :
1447 if (shift == 0) // it is RRX
1448 return ((USI)rm >> 1) | ((USI)this->hardware.h_cbit << 31);
1450 return RORSI (rm, shift);
1457 arm7f_cpu::compute_operand2_regshift (SI rm, int type, SI shift)
1463 case SHIFT_TYPE_LSL :
1467 case SHIFT_TYPE_LSR :
1470 return (USI) rm >> shift;
1471 case SHIFT_TYPE_ASR :
1475 case SHIFT_TYPE_ROR :
1477 shift = ((shift - 1) & 31) + 1;
1478 if (shift == 0 || shift == 32)
1480 return RORSI (rm, shift);
1487 arm7f_cpu::compute_carry_out_immshift (SI rm, int type, int shift, BI cbit)
1491 case SHIFT_TYPE_LSL :
1494 return (rm >> (32 - shift)) & 1;
1495 case SHIFT_TYPE_LSR :
1498 return (rm >> (shift - 1)) & 1;
1499 case SHIFT_TYPE_ASR :
1502 return (rm >> (shift - 1)) & 1;
1503 case SHIFT_TYPE_ROR :
1505 shift = ((shift - 1) & 31) + 1;
1508 return (rm >> (shift - 1)) & 1;
1514 BI arm7f_cpu::compute_carry_out_regshift (SI rm, int type, SI shift, BI cbit)
1520 case SHIFT_TYPE_LSL :
1527 return (rm >> (32 - shift)) & 1;
1528 case SHIFT_TYPE_LSR :
1535 return (rm >> (shift - 1)) & 1;
1536 case SHIFT_TYPE_ASR :
1541 return (rm >> (shift - 1)) & 1;
1542 case SHIFT_TYPE_ROR :
1547 return (rm >> (shift - 1)) & 1;