OSDN Git Service

Use datarootdir for locales.
[pf3gnuchains/pf3gnuchains4x.git] / sid / component / cgen-cpu / arm7t / arm7f.cxx
1 // arm7f.cxx - Implementations of hand-written functions for the ARM7
2 // simulator.  -*- C++ -*-
3
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.
8
9 #include "arm7f.h"
10
11 using namespace std;
12 using namespace sid;
13 using namespace sidutil;
14 using namespace arm;
15 using namespace arm7f;
16
17
18 arm7f_cpu::arm7f_cpu ():
19   arm_engine (32768),   // XXX: tune size
20   thumb_engine (32768), // XXX: tune size
21   initialized_p (false)
22 {
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);
30
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.
35
36   // Create attributes to access our innards.
37
38   // R15 is the pc.
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)
44     {
45       string name = string ("r") + make_numeric_attribute (i);
46       SI* value = & this->hardware.h_gr[i];
47       this->add_watchable_register (name, value);
48
49       if (i >= 8 && i <= 14)
50         {
51           value = & this->hardware.h_gr_fiq[i-8];
52           this->add_watchable_register (name + "_fiq", value);
53         }
54       if (i >= 13 && i <= 14)
55         {
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]);
60         }
61     }
62   // add pc itself after r15
63   if (true)
64     {
65       string name = "pc";
66       USI* value = & this->hardware.h_pc;
67       this->add_watchable_register (name, value);
68     }
69
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");
76
77   add_attribute_virtual ("cpsr-flags", this,
78                          & arm7f_cpu::get_h_cpsr2_for_attr,
79                          & arm7f_cpu::set_h_cpsr2_for_attr, "register");
80
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);
86
87   // Add register access for debugger
88   this->create_gdb_register_attrs (26, "7;11;13;14;15;25", & this->hardware.h_pc);
89
90   // These need to be 'pulled' high if they are not connected.
91   nirq_pin.driven(1);
92   nfiq_pin.driven(1);
93 }
94
95 string
96 arm7f_cpu::get_h_cpsr2_for_attr ()
97 {
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" : "???");
113
114   return n + z + c + v + i + f + t + m;
115 }
116
117
118
119 void
120 arm7f_cpu::reset ()
121 {
122   // initialize registers to powerup values
123
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);
134
135   // Make sure we are in arm mode
136   this->h_tbit_set (0); 
137
138   // Point the PC at the reset handler.
139   this->h_pc_set (0);
140
141   // initialize various implementation state
142
143   this->pending_eit = EIT_NONE;
144
145   // Don't need to power-on-reset anything else, but do so anyway to aid
146   // debugging.
147
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);
169
170   // enable update_stepper from now on
171   this->initialized_p = true;
172
173   this->triggerpoint_manager.check_and_dispatch ();
174
175   // These need to be 'pulled' high if they are not connected.
176   nirq_pin.driven(1);
177   nfiq_pin.driven(1);
178 }
179
180
181 // 
182 void
183 arm7f_cpu::step_insns ()
184 {
185   if (! this->initialized_p)
186     {
187       cerr << "hw-cpu-arm7f: illegal step before initialization." << endl;
188       this->reset();
189       return;
190     }
191
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())
195     queue_eit (EIT_FIQ);
196  
197   if(!this->h_ibit_get() && !nirq_pin.sense())
198     queue_eit (EIT_IRQ);
199
200   // If an eit is queued, process it now.
201   if (this->pending_eit != EIT_NONE)
202     this->process_eit (this->pending_eit);
203
204   if (this->engine_type == ENGINE_PBB)
205     {
206       if (this->h_tbit_get ())
207         this->step_thumb_pbb ();
208       else
209         this->step_arm_pbb ();      
210     }
211   else
212     {
213       if (this->h_tbit_get ())
214         this->step_thumb ();
215       else
216         this->step_arm ();          
217     }
218 }
219
220
221
222
223
224 \f
225 // EIT support.
226
227 // Return h-mbits, as an ARM_MODE enum.
228
229 arm::ARM_MODE
230 arm7f_cpu::mode ()
231 {
232   return (arm::ARM_MODE) this->h_mbits_get ();
233 }
234
235 void
236 arm7f_cpu::queue_eit (arm7f::eit new_eit)
237 {
238   if (this->pending_eit == new_eit)
239     return;
240
241   // don't override higher priority eit
242   if (this->pending_eit != EIT_NONE)
243     {
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)
249         return;
250     }
251
252   this->pending_eit = new_eit;
253
254   // TODO: simultaneous data abort and fiq interrupt (page 3-14).
255 }
256
257 int
258 arm7f_cpu::eit_priority (arm7f::eit e)
259 {
260   switch (e)
261     {
262     case EIT_RESET :
263       return 1;
264     case EIT_DATA_ABORT :
265       return 2;
266     case EIT_FIQ :
267       return 3;
268     case EIT_IRQ :
269       return 4;
270     case EIT_PREFETCH_ABORT :
271       return 5;
272     case EIT_UNDEFINED_INSN :
273     case EIT_SWI_INSN :
274       return 6;
275     default :
276       assert (0);
277     }
278 }
279
280 // FIXME: revisit making pc an arg
281
282 void
283 arm7f_cpu::process_eit (arm7f::eit new_eit)
284 {
285   // Clean the sucker out
286   this->flush_icache ();
287
288   PCADDR pc = this->h_pc_get ();
289
290   // At this point in the processing, pc is the address of the next
291   // insn to be executed.
292
293   switch (new_eit)
294     {
295     case EIT_DATA_ABORT :
296       // save cpsr
297       this->h_spsr_abt_set(this->h_cpsr_get());
298       this->h_tbit_set (0);
299       // set R14
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;
304       break;
305
306     case EIT_FIQ :
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);
313       // set R14_fiq
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;
318       break;
319
320     case EIT_IRQ :
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);
327       // set R14_irq
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;
332       break;
333
334     case EIT_PREFETCH_ABORT :
335       // save cpsr
336       this->h_spsr_abt_set(this->h_cpsr_get());
337       this->h_tbit_set (0);
338       // set R14
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;
343       break;
344
345     case EIT_UNDEFINED_INSN :
346       this->h_spsr_und_set (this->h_cpsr_get ());
347       // set R14_und
348       if (this->h_tbit_get ())
349         this->h_gr_und_set (1, pc + 2);
350       else
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;
356       break;
357
358     case EIT_SWI_INSN :
359       this->h_spsr_svc_set (this->h_cpsr_get ());
360       // set R14_swi
361       if (this->h_tbit_get ())
362         this->h_gr_svc_set (1, pc + 2);
363       else
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;
369       break;
370
371     default :
372       cgen_rtx_error ("Unknown EIT mode");
373       break;
374     }
375 }
376 \f
377 // Engine support.
378
379 // Override for handling sets of the engine-type attribute.
380
381 component::status
382 arm7f_cpu::set_engine_type (const string& s)
383 {
384   component::status status;
385  
386   status = cgen_bi_endian_cpu::set_engine_type (s);
387   if (status != component::ok)
388     return status;
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 ();
393   else
394     return component::bad_value;
395   return component::ok;
396 }
397
398 void
399 arm7f_cpu::set_pbb_engine ()
400 {
401   this->engine_type = ENGINE_PBB;
402   this->update_engine ();
403 }
404
405 void
406 arm7f_cpu::set_scache_engine ()
407 {
408   this->engine_type = ENGINE_SCACHE;
409   this->update_engine ();
410 }
411
412 void
413 arm7f_cpu::update_engine ()
414 {
415   if (this->engine_type == ENGINE_PBB)
416     {
417       this->arm_engine.set_pbb_engine ();
418       this->thumb_engine.set_pbb_engine ();
419     }
420   else
421     {
422       this->arm_engine.set_scache_engine ();
423       this->thumb_engine.set_scache_engine ();
424     }
425 }
426
427 // Scache steppers
428
429 void
430 arm7f_cpu::step_arm ()
431 {
432   assert (! this->h_tbit_get ());
433
434   while (true)
435     {
436       // Fetch/decode the instruction  ------------------------------
437       PCADDR pc = this->h_pc_get ();
438       bool found;
439       arm_scache* sem = this->arm_engine.find (pc, found);
440       if (! found)
441         {
442           try
443             {
444               USI insn = this->GETIMEMSI (pc, pc);
445               sem->decode (this, pc, insn, insn);
446             }
447           catch (cpu_memory_fault& t)
448             {
449               this->memory_trap (t);
450               break;
451             }
452         }
453
454       // Execute the instruction  -----------------------------------
455       if (this->trace_result_p)
456         this->begin_trace (pc, sem->idesc->insn_name);
457       try 
458         {
459           if (this->eval_cond (sem->cond, pc))
460             {
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);
464             }
465           else
466             {
467               this->h_pc_set (pc + 4);
468             }
469         }
470       catch (cpu_memory_fault& t)
471         {
472           this->memory_trap (t);
473           this->yield ();
474         }
475       catch (cpu_exception& t)
476         {
477           this->yield ();
478         }
479       if (this->trace_result_p)
480         this->end_trace ();
481       
482
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 ();
487       
488       // test for exit condition
489       if (stop_after_insns_p (1))
490         break;
491     }
492 }
493
494
495 void
496 arm7f_cpu::step_thumb ()
497 {
498   assert (this->h_tbit_get ());
499
500   while (true)
501     {
502       // Fetch/decode the instruction  ------------------------------
503       PCADDR pc = this->h_pc_get ();
504       bool found;
505       thumb_scache* sem = this->thumb_engine.find (pc, found);
506       if (! found)
507         {
508           try
509             {
510               UHI insn = this->GETIMEMHI (pc, pc);
511               sem->decode (this, pc, insn, insn);
512             }
513           catch (cpu_memory_fault& t)
514             {
515               this->memory_trap (t);
516               break;
517             }
518         }
519
520       // Execute the instruction  -----------------------------------
521       if (this->trace_result_p)
522         this->begin_trace (pc, sem->idesc->insn_name);
523       try 
524         {
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);
528         }
529       catch (cpu_memory_fault& t)
530         {
531           this->memory_trap (t);
532           this->yield ();
533         }
534       catch (cpu_exception& t)
535         {
536           this->yield ();
537         }
538       if (this->trace_result_p)
539         this->end_trace ();
540       
541
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 ();
546       
547       // test for exit condition
548       if (stop_after_insns_p (1))
549         break;
550     }
551 }
552
553
554
555 // PBB steppers and support
556
557 void
558 arm7f_cpu::step_arm_pbb ()
559 {
560   assert (! this->h_tbit_get ());
561
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 ();
566
567   try
568     {
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 ();
572     }
573   catch (cpu_memory_fault& t)
574     {
575       this->memory_trap (t);
576     }
577   catch (cpu_exception& t)
578     {
579     }
580 }
581
582
583 void
584 arm7f_cpu::step_thumb_pbb ()
585 {
586   assert (this->h_tbit_get ());
587  
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 ();
592
593   try
594     {
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 ();
598     }
599   catch (cpu_memory_fault& t)
600     {
601       this->memory_trap (t);
602     }
603   catch (cpu_exception& t)
604     {
605     }
606 }
607
608
609
610 // Compiler for the ARM PBB engine.
611
612 arm_scache*
613 arm7f_cpu::arm_pbb_begin (PCADDR pc)
614 {
615   bool found;
616   arm_scache* vpc;
617   arm_engine_t* engine = & this->arm_engine;
618   bool trace_p = this->trace_result_p;
619
620   unsigned block_size = engine->max_real_insns (this);
621
622   // Multiply by enough so we have enough space for the virtual insns.
623   unsigned alloc_blocks;
624   if (trace_p)
625     {
626       // *4 = before,cond,insn,after insns.  +1 = chain insn.
627       alloc_blocks = block_size * 4 + 1;
628     }
629   else
630     {
631       // *2 = cond,insn insns.  +1 = chain insn.
632       alloc_blocks = block_size * 2 + 1;
633     }
634
635   vpc = engine->pbb_find_or_alloc (pc, alloc_blocks, found);
636   if (found)
637     return vpc;
638
639   // Ok, here's where the real fun begins.  Compile a pseudo-basic-block.
640
641   arm_scache* sc = vpc;
642
643   arm_scache* sc_end;
644   if (trace_p)
645     sc_end = vpc + (alloc_blocks
646                     // back up to ensure there's room for all of the last insn
647                     - 3
648                     // and room for the final chain insn
649                     - 1);
650   else
651     sc_end = vpc + (alloc_blocks
652                     // back up to ensure there's room for all of the last insn
653                     - 1
654                     // and room for the final chain insn
655                     - 1);
656
657   unsigned count = 0;
658   do
659     {
660       USI insn;
661       try
662         {
663           insn = this->GETIMEMSI (pc, pc);
664         }
665       catch (cpu_memory_fault& t)
666         {
667           this->memory_trap (t);
668           break;
669         }
670
671       // FIXME: magic number
672       UINT cond = insn >> 28;
673
674       if (trace_p)
675         {
676           engine->compile_before_insn (this, sc, pc,
677                                        // FIXME: magic number
678                                        sc + (cond == 14 ? 1 : 2));
679           ++sc;
680         }
681
682       // First insert a conditional execution handler if needed.
683       // FIXME: magic number
684       if (cond != 14)
685         {
686           engine->compile_cond_insn (this, sc, pc, cond);
687           ++sc;
688         }
689
690       // Compile the insn.
691       sc->decode (this, pc, insn, insn);
692       sc->execute.cgoto = sc->idesc->cgoto;
693
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 ());
699
700       ++sc;
701
702       if (trace_p)
703         {
704           engine->compile_after_insn (this, sc, pc, sc - 1);
705           ++sc;
706         }
707
708       pc += 4;
709       ++count;
710
711       if (cti_p)
712         {
713           engine->compile_cti_chain_insn (this, sc, pc, count);
714           return vpc;
715         }
716     }
717   while (sc < sc_end);
718
719   // Compile a chain insn to link to next block.
720   engine->compile_chain_insn (this, sc, pc, count);
721
722   return vpc;
723 }
724
725 // Compiler for the Thumb PBB engine.
726
727 thumb_scache*
728 arm7f_cpu::thumb_pbb_begin (PCADDR pc)
729 {
730   bool found;
731   thumb_scache* vpc;
732   thumb_engine_t* engine = & this->thumb_engine;
733   bool trace_p = this->trace_result_p;
734
735   unsigned block_size = engine->max_real_insns (this);
736
737   // Multiply by enough so we have enough space for the virtual insns.
738   unsigned alloc_blocks;
739   if (trace_p)
740     {
741       // *3 = before,insn,after insns.  +1 = chain insn.
742       alloc_blocks = block_size * 3 + 1;
743     }
744   else
745     {
746       // +1 = chain insn.
747       alloc_blocks = block_size + 1;
748     }
749
750   vpc = engine->pbb_find_or_alloc (pc, alloc_blocks, found);
751   if (found)
752     return vpc;
753
754   // Ok, here's where the real fun begins.  Compile a pseudo-basic-block.
755
756   thumb_scache* sc = vpc;
757
758   thumb_scache* sc_end;
759   if (trace_p)
760     sc_end = vpc + (alloc_blocks
761                     // back up to ensure there's room for all of the last insn
762                     - 2
763                     // and room for the final chain insn
764                     - 1);
765   else
766     sc_end = vpc + (alloc_blocks
767                     // back up to ensure there's room for the chain insn
768                     - 1);
769
770   unsigned count = 0;
771   do
772     {
773       UHI insn;
774       try
775         {
776           insn = this->GETIMEMHI (pc, pc);
777         }
778       catch (cpu_memory_fault& t)
779         {
780           this->memory_trap (t);
781           break;
782         }
783
784       if (trace_p)
785         {
786           engine->compile_before_insn  (this, sc, pc, sc + 1);
787           ++sc;
788         }
789
790       // Compile the insn.
791       sc->decode (this, pc, insn, insn);
792       sc->execute.cgoto = sc->idesc->cgoto;
793
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 ());
799
800       ++sc;
801
802       if (trace_p)
803         {
804           engine->compile_after_insn (this, sc, pc, sc - 1);
805           ++sc;
806         }
807
808       pc += 2;
809       ++count;
810
811       if (cti_p)
812         {
813           engine->compile_cti_chain_insn (this, sc, pc, count);
814           return vpc;
815         }
816     }
817   while (sc < sc_end);
818
819   // Compile a chain insn to link to next block.
820   engine->compile_chain_insn (this, sc, pc, count);
821
822   return vpc;
823 }
824 \f
825 // Memory trap(/fault) handling.
826
827 void
828 arm7f_cpu::memory_trap (const cpu_memory_fault& t)
829 {
830   this->h_gr_set (H_GR_PC, t.pc);
831   this->h_pc_set (t.pc);
832
833   cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_memory_fault, t.address);
834
835   switch (whatnext)
836     {
837     case cpu_trap_unhandled:
838       if (string (t.operation) == "insn read")
839         this->queue_eit (EIT_PREFETCH_ABORT);
840       else
841         this->queue_eit (EIT_DATA_ABORT);
842       break;
843
844     case cpu_trap_skip:
845       {
846         PCADDR pc = t.pc + (this->h_tbit_get() ? 2 : 4); // skip this insn
847         this->h_gr_set (H_GR_PC, pc);
848         this->h_pc_set (pc);
849       }
850       break;
851
852     case cpu_trap_handled:
853     case cpu_trap_reissue:
854       break;
855
856     default:
857       abort ();
858     }
859
860   this->yield();
861 }
862 \f
863 // Invalid instruction handling.
864
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.
868
869 void
870 arm7f_cpu::invalid_insn (PCADDR pc)
871 {
872   this->h_gr_set (H_GR_PC, pc);
873   this->h_pc_set (pc);
874
875   cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_invalid_insn, pc);
876
877   switch (whatnext)
878     {
879     case cpu_trap_unhandled:
880       this->h_gr_set (H_GR_PC, pc);
881       this->h_pc_set (pc);
882       this->queue_eit (EIT_UNDEFINED_INSN);
883       break;
884
885     case cpu_trap_skip:
886       {
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);
890       }
891       break;
892
893     case cpu_trap_handled:
894     case cpu_trap_reissue:
895       break;
896
897     default:
898       abort ();
899     }
900
901   this->yield();
902   throw cpu_exception ();
903 }
904 \f
905 #if 0
906
907 // Special "nreset" pin handling.
908 void
909 arm7f_cpu::do_nreset_pin (host_int_4 value)
910 {
911   // FIXME: Should be able to catch transitions but can't do
912   // that with callback_pin.
913   //if (nreset_pin.sense () == value)
914   //  return;
915
916   if (value)
917     {
918       // Reset pin has gone high, start executing insns.
919
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);
929
930       this->h_pc_set (0);
931
932       this->pending_eit = EIT_NONE;
933     }
934   else
935     {
936       // Reset pin has gone low, put cpu in reset state.
937       this->step_pin.set_callback (& arm7f_cpu::step_reset);
938
939       // lock out other interrupts (EIT_RESET has highest priority)
940       this->pending_eit = EIT_RESET;
941     }
942 }
943 #endif
944
945 #if 0
946 // Stepper while reset pin is held low.
947 // XXX: not implemented
948 void
949 arm7f_cpu::step_reset (host_int_4)
950 {
951   assert (! this->nreset_pin.sense ());
952
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);
959
960   this->triggerpoint_manager.check_and_dispatch ();
961 }
962 #endif
963
964 \f
965 // EIT (exception, interrupt, and trap) pins.
966
967 \f
968 // Miscellaneous pins.
969
970 void
971 arm7f_cpu::flush_icache ()
972 {
973   this->thumb_engine.flush ();
974   this->arm_engine.flush ();
975 }
976 \f
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.
980 void
981 arm7f_cpu::arm_tbit_set (BI newval)
982 {
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)
987     return;
988
989   this->hardware.h_tbit = newval;
990
991   if (this->warnings_enabled)
992     {
993       if (newval)
994         this->trace_stream << " <switching to thumb mode> ";
995       else
996         this->trace_stream << " <switching to arm mode> ";
997     }
998
999   // Update the tbit pin.
1000   this->tbit_pin.drive (newval);
1001
1002   this->yield ();
1003   // This should arrange an immediate exit from the scache/pbb engine loops.
1004 }
1005
1006
1007 // Update the h-gr regs based on the new value for M4-M0.
1008 // Also update nm_pin.
1009 void
1010 arm7f_cpu::arm_mbits_set (UINT newval)
1011 {
1012   UINT oldval = this->h_mbits_get ();
1013
1014   // exit quickly for frequent case
1015   // N.B. code below assumes this is done
1016   if (newval == oldval)
1017     return;
1018
1019   // swap out the current set of r8-r12
1020   switch (oldval)
1021     {
1022     case ARM_MODE_USER :
1023     case ARM_MODE_SYSTEM :
1024     case ARM_MODE_SUPERVISOR :
1025     case ARM_MODE_ABORT :
1026     case ARM_MODE_IRQ :
1027     case ARM_MODE_UNDEFINED :
1028     case ARM_MODE_FIQ :
1029       break;
1030
1031     default:
1032       cerr << "hw-cpu-arm7t: ignoring invalid h-mbits:" << newval << endl;
1033       return;
1034     }
1035
1036   // swap out the current set of r8-r12
1037   switch (oldval)
1038     {
1039     case ARM_MODE_USER :
1040     case ARM_MODE_SYSTEM :
1041     case ARM_MODE_SUPERVISOR :
1042     case ARM_MODE_ABORT :
1043     case ARM_MODE_IRQ :
1044     case ARM_MODE_UNDEFINED :
1045       // nothing to do unless new mode is fiq
1046       if (newval != ARM_MODE_FIQ)
1047         break;
1048       for (int i = 8; i <= 12; ++i)
1049         this->h_gr_usr_set (i - 8, this->h_gr_get (i));
1050       break;
1051     case ARM_MODE_FIQ :
1052       for (int i = 8; i <= 12; ++i)
1053         this->h_gr_fiq_set (i - 8, this->h_gr_get (i));
1054       break;
1055     default :
1056       assert (0);
1057     }
1058
1059   // swap in the new set of r8-r12
1060   switch (newval)
1061     {
1062     case ARM_MODE_USER :
1063     case ARM_MODE_SYSTEM :
1064     case ARM_MODE_SUPERVISOR :
1065     case ARM_MODE_ABORT :
1066     case ARM_MODE_IRQ :
1067     case ARM_MODE_UNDEFINED :
1068       // nothing to do unless old mode was fiq
1069       if (oldval != ARM_MODE_FIQ)
1070         break;
1071       for (int i = 8; i <= 12; ++i)
1072         this->h_gr_set (i, this->h_gr_usr_get (i - 8));
1073       break;
1074     case ARM_MODE_FIQ :
1075       for (int i = 8; i <= 12; ++i)
1076         this->h_gr_set (i, this->h_gr_fiq_get (i - 8));
1077       break;
1078     }
1079
1080   // swap out the current set of r13,r14
1081   switch (oldval)
1082     {
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)
1087         break;
1088       for (int i = 13; i <= 14; ++i)
1089         this->h_gr_usr_set (i - 8, this->h_gr_get (i));
1090       break;
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));
1094       break;
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));
1098       break;
1099     case ARM_MODE_IRQ :
1100       for (int i = 13; i <= 14; ++i)
1101         this->h_gr_irq_set (i - 13, this->h_gr_get (i));
1102       break;
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));
1106       break;
1107     case ARM_MODE_FIQ :
1108       for (int i = 13; i <= 14; ++i)
1109         this->h_gr_fiq_set (i - 8, this->h_gr_get (i));
1110       break;
1111     default :
1112       assert (0);
1113     }
1114
1115   // swap in the new set of r13,r14
1116   switch (newval)
1117     {
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)
1122         break;
1123       for (int i = 13; i <= 14; ++i)
1124         this->h_gr_set (i, this->h_gr_usr_get (i - 8));
1125       break;
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));
1129       break;
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));
1133       break;
1134     case ARM_MODE_IRQ :
1135       for (int i = 13; i <= 14; ++i)
1136         this->h_gr_set (i, this->h_gr_irq_get (i - 13));
1137       break;
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));
1141       break;
1142     case ARM_MODE_FIQ :
1143       for (int i = 13; i <= 14; ++i)
1144         this->h_gr_set (i, this->h_gr_fiq_get (i - 8));
1145       break;
1146     }
1147
1148   // Finally update register
1149   this->hardware.h_mbits = newval;
1150   // Update the nm pin.
1151   this->nm_pin.drive ((~newval) & 0x1f);
1152 }
1153 \f
1154 // Software generated interrupt support.
1155
1156 SI
1157 arm7f_cpu::arm_swi (PCADDR pc, UINT arg)
1158 {
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);
1163
1164   cpu_trap_disposition whatnext = this->signal_trap (cpu_trap_software, arg);
1165
1166   switch (whatnext)
1167     {
1168     case cpu_trap_unhandled:
1169       this->queue_eit (EIT_SWI_INSN);
1170       break;
1171
1172     case cpu_trap_skip:
1173       {
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);
1177       }
1178       break;
1179
1180     case cpu_trap_handled:
1181     case cpu_trap_reissue:
1182       break;
1183
1184     default:
1185       abort ();
1186     }
1187
1188   this->yield();
1189   throw cpu_exception ();
1190 }
1191
1192
1193 SI
1194 arm7f_cpu::thumb_swi (PCADDR pc, UINT arg)
1195 {
1196   return this->arm_swi (pc, arg);
1197 }
1198 \f
1199 // State dump/restore support.
1200
1201 void 
1202 arm7f_cpu::stream_state (ostream& o) const
1203 {
1204   // call base class first
1205   cgen_bi_endian_cpu::stream_state (o);
1206
1207   // component and cpu variant indicators
1208   o << " arm-cpu"
1209     << " arm7tdmi";
1210
1211   // misc. state
1212   o << " " << initialized_p
1213     << " " << static_cast<int>(pending_eit);
1214
1215   // pins
1216   o << " " << nm_pin
1217     << " " << tbit_pin
1218     << " " << nfiq_pin
1219     << " " << nirq_pin << endl;
1220
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);
1226 }
1227
1228 void 
1229 arm7f_cpu::destream_state (istream& i)
1230 {
1231   // call base class first
1232   cgen_bi_endian_cpu::destream_state (i);
1233
1234   string key;
1235   i >> key;
1236   if (key != "arm-cpu")
1237     {
1238       i.setstate (ios::badbit);
1239       return;
1240     }
1241
1242   string cpu_variant;
1243   i >> cpu_variant;
1244   if (cpu_variant != "arm7tdmi")
1245     {
1246       i.setstate (ios::badbit);
1247       return;
1248     }
1249
1250   // misc. state
1251   int pending_eit_asint;
1252   i >> initialized_p
1253     >> pending_eit_asint;
1254   pending_eit = static_cast<arm7f::eit>(pending_eit_asint);
1255
1256   // pins
1257   i >> nm_pin
1258     >> tbit_pin
1259     >> nfiq_pin
1260     >> nirq_pin;
1261
1262   string hw;
1263   i >> stream2string(hw);
1264   if (hw.size() != sizeof(this->hardware))
1265     i.setstate (ios::badbit);
1266   else
1267     {
1268       const char* hwbin = hw.data();
1269       ::memcpy (reinterpret_cast<char*>(& this->hardware), hwbin, sizeof(this->hardware));
1270     }
1271
1272   // reinitialize derived state
1273   flush_icache ();
1274 }
1275
1276
1277
1278 // Debugger interface functions: return bitwise register images in
1279 // "target byte order".
1280
1281 string
1282 arm7f_cpu::dbg_get_reg (host_int_4 reg)
1283 {
1284   string attr;
1285
1286   if (reg < 16) // general purpose registers
1287     {
1288       host_int_4 value;
1289
1290       if (reg == H_GR_PC)
1291         value = h_pc_get ();
1292       else
1293         value = h_gr_get (reg);
1294
1295       // change to "target endian"
1296       if (current_endianness() == endian_big)
1297         {
1298           big_int_4 v = value;
1299           for (unsigned i=0; i<4; i++)
1300             attr += v.read_byte (i);
1301         }
1302       else
1303         {
1304           little_int_4 v = value;
1305           for (unsigned i=0; i<4; i++)
1306             attr += v.read_byte (i);
1307         }
1308       assert (attr.length () == 4);
1309     }
1310   else if ((reg >= 16) && (reg <= 23)) // floating point registers
1311     {
1312       for (unsigned i = 0; i < 12; i++)
1313         attr += '\0';
1314       assert (attr.length () == 12);
1315     }
1316   else if (reg == 24) // floating point status ?
1317     {
1318       for (unsigned i = 0; i < 4; i++)
1319         attr += '\0';
1320       assert (attr.length () == 4);
1321     }
1322   else if (reg == 25) // cpsr
1323     {
1324       host_int_4 value = h_cpsr_get ();
1325
1326       // change to "target endian"
1327       if (current_endianness() == endian_big)
1328         {
1329           big_int_4 v = value;
1330           for (unsigned i=0; i<4; i++)
1331             attr += v.read_byte (i);
1332         }
1333       else
1334         {
1335           little_int_4 v = value;
1336           for (unsigned i=0; i<4; i++)
1337             attr += v.read_byte (i);
1338         }
1339       assert (attr.length () == 4);
1340     }
1341
1342   return attr;
1343 }
1344
1345
1346 component::status 
1347 arm7f_cpu::dbg_set_reg (host_int_4 reg, const string& attr)
1348 {
1349   if (reg < 16) // general purpose registers
1350     {
1351       if (attr.length () != 4)
1352         return component::bad_value;
1353
1354       host_int_4 value;
1355       // change from "target endian"
1356       if (current_endianness() == endian_big)
1357         {
1358           big_int_4 v;
1359           for (unsigned i=0; i<4; i++)
1360             v.write_byte (i, attr[i]);
1361           value = v;
1362         }
1363       else
1364         {
1365           little_int_4 v;
1366           for (unsigned i=0; i<4; i++)
1367             v.write_byte (i, attr[i]);
1368           value = v;
1369         }
1370
1371       if (reg == H_GR_PC)
1372         h_pc_set (value);
1373       else
1374         h_gr_set (reg, value);
1375
1376       return component::ok;
1377     }
1378   else if ((reg >= 16) && (reg <= 23)) // floating point registers
1379     {
1380       if (attr.length () != 12)
1381         return component::bad_value;
1382
1383       return component::ok;
1384     }
1385   else if (reg == 24) // floating point status ?
1386     {
1387       if (attr.length () != 4)
1388         return component::bad_value;
1389
1390       return component::ok;
1391     }
1392   else if (reg == 25) // cpsr
1393     {
1394       if (attr.length () != 4)
1395         return component::bad_value;
1396
1397       host_int_4 value;
1398       // change from "target endian"
1399       if (current_endianness() == endian_big)
1400         {
1401           big_int_4 v;
1402           for (unsigned i=0; i<4; i++)
1403             v.write_byte (i, attr[i]);
1404           value = v;
1405         }
1406       else
1407         {
1408           little_int_4 v;
1409           for (unsigned i=0; i<4; i++)
1410             v.write_byte (i, attr[i]);
1411           value = v;
1412         }
1413
1414       h_cpsr_set (value);
1415
1416       return component::ok;
1417     }
1418
1419   return component::not_found;
1420 }
1421
1422
1423
1424 // ----------------------------------------------------------------------------
1425 // More semantic helper routines -- too large to inline throughout
1426
1427   // Support for operand2 in the data processing insns.
1428   // ??? Move to RTL.
1429
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.
1434
1435   // FIXME: making this inline is a quick hack to work around a compilation
1436   // problem (symbol undefined).
1437
1438 SI 
1439 arm7f_cpu::compute_operand2_immshift (SI rm, int type, int shift)
1440 {
1441   switch (type)
1442     {
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);
1449       else
1450         return RORSI (rm, shift);
1451     }
1452   abort();
1453 }
1454
1455
1456 SI
1457 arm7f_cpu::compute_operand2_regshift (SI rm, int type, SI shift)
1458 {
1459   shift &= 255;
1460       
1461   switch (type)
1462     {
1463     case SHIFT_TYPE_LSL :
1464       if (shift >= 32)
1465         return 0;
1466       return rm << shift;
1467     case SHIFT_TYPE_LSR :
1468       if (shift >= 32)
1469         return 0;
1470       return (USI) rm >> shift;
1471     case SHIFT_TYPE_ASR :
1472       if (shift >= 32)
1473         return rm >> 31;
1474       return rm >> shift;
1475     case SHIFT_TYPE_ROR :
1476       if (shift > 32)
1477         shift = ((shift - 1) & 31) + 1;
1478       if (shift == 0 || shift == 32)
1479         return rm;
1480       return RORSI (rm, shift);
1481     }
1482   abort ();
1483 }
1484
1485
1486 BI
1487 arm7f_cpu::compute_carry_out_immshift (SI rm, int type, int shift, BI cbit)
1488 {
1489   switch (type)
1490     {
1491     case SHIFT_TYPE_LSL :
1492       if (shift == 0)
1493         return cbit;
1494       return (rm >> (32 - shift)) & 1;
1495     case SHIFT_TYPE_LSR :
1496       if (shift == 0)
1497         return rm < 0;
1498       return (rm >> (shift - 1)) & 1;
1499     case SHIFT_TYPE_ASR :
1500       if (shift == 0)
1501         return rm < 0;
1502       return (rm >> (shift - 1)) & 1;
1503     case SHIFT_TYPE_ROR :
1504       if (shift > 32)
1505         shift = ((shift - 1) & 31) + 1;
1506       if (shift == 0)
1507         return rm & 1;
1508       return (rm >> (shift - 1)) & 1;
1509     }
1510   abort ();
1511 }
1512
1513
1514 BI arm7f_cpu::compute_carry_out_regshift (SI rm, int type, SI shift, BI cbit)
1515 {
1516   shift &= 255;
1517       
1518   switch (type)
1519     {
1520     case SHIFT_TYPE_LSL :
1521       if (shift == 0)
1522         return cbit;
1523       if (shift == 32)
1524         return rm & 1;
1525       if (shift > 32)
1526         return 0;
1527       return (rm >> (32 - shift)) & 1;
1528     case SHIFT_TYPE_LSR :
1529       if (shift == 0)
1530         return cbit;
1531       if (shift == 32)
1532         return rm < 0;
1533       if (shift > 32)
1534         return 0;
1535       return (rm >> (shift - 1)) & 1;
1536     case SHIFT_TYPE_ASR :
1537       if (shift == 0)
1538         return cbit;
1539       if (shift >= 32)
1540         return rm < 0;
1541       return (rm >> (shift - 1)) & 1;
1542     case SHIFT_TYPE_ROR :
1543       if (shift == 0)
1544         return cbit;
1545       if (shift == 32)
1546         return rm < 0;
1547       return (rm >> (shift - 1)) & 1;
1548     }
1549   abort ();
1550 }