OSDN Git Service

bf4f4562117580bd57435348f632a411d9dab36f
[pf3gnuchains/pf3gnuchains3x.git] / sid / include / sidcpuutil.h
1 // sidcpuutil.h - Elements common to CPU models.  -*- C++ -*-
2
3 // Copyright (C) 1999-2004 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 #ifndef SIDCPUUTIL_H
8 #define SIDCPUUTIL_H
9
10 #include <sidattrutil.h>
11 #include <sidpinutil.h>
12 #include <sidbusutil.h>
13 #include <sidcomputil.h>
14 #include <sidmiscutil.h>
15 #include <sidwatchutil.h>
16 #include <sidschedutil.h>
17
18 using std::string;
19
20 namespace sidutil
21 {
22   // kinds of endianness
23   enum endian 
24   {
25     endian_unknown = 0,
26     endian_big = 1,
27     endian_little = 2
28   };
29   
30   inline
31     std::ostream& operator << (std::ostream& o, const endian& e)
32       {
33         switch (e) 
34           {
35           default: 
36           case endian_unknown: o << "unknown"; break;
37           case endian_big: o << "big"; break;
38           case endian_little: o << "little"; break;
39           }
40         return o;
41       }
42   
43   
44   inline
45     std::istream& operator >> (std::istream& i, endian& e)
46       {
47         std::string s;
48         i >> s;
49         if (s == "unknown" || s == "0") { e = endian_unknown; }
50         else if (s == "big" || s == "1") { e = endian_big; }
51         else if (s == "little" || s == "2") { e = endian_little; }
52         else { i.setstate(std::ios::badbit); e = endian_unknown; }
53         return i;
54       }
55
56   // ------------------------------------------------------------------------
57
58   class cpu_exception {};
59
60   class cpu_memory_fault: public cpu_exception
61   {
62   public:
63     sid::host_int_4 pc;
64     sid::host_int_4 address;
65     sid::bus::status status;
66     const char* operation;
67     
68     cpu_memory_fault (sid::host_int_4 p, sid::host_int_4 a, sid::bus::status s, const char* o):
69       pc(p), address(a), status(s), operation(o) 
70       {}
71   };
72   
73
74   // ------------------------------------------------------------------------
75
76
77   // Values travelling through the trap-type pin.
78   // Additional "arguments" are sent through the trap-code pin.
79   enum cpu_trap_type {
80     cpu_trap_software = 1,      // trap instruction hit
81     cpu_trap_breakpoint = 2,    // breakpoint instruction hit
82     cpu_trap_syscall = 3,       // system call instruction hit
83     cpu_trap_invalid_insn = 4,  // invalid instruction hit
84     cpu_trap_memory_fault = 5,  // memory fault encountered
85     cpu_trap_overflow = 6,      // arithmetic overflow
86     cpu_trap_stepped = 7,       // single-step completed
87   };
88
89
90   // Possible trap disposition codes
91   enum cpu_trap_disposition 
92   {
93     cpu_trap_unhandled = 0,     // dispatch to hardware fault handling
94     cpu_trap_handled = 1,       // supervisor handled faulting instruction
95     cpu_trap_reissue = 2,       // rerun faulting instruction
96     cpu_trap_skip = 3,          // skip faulting instruction
97   };
98
99
100   // ------------------------------------------------------------------------
101
102
103   class basic_cpu: public virtual sid::component,
104                    protected virtual fixed_pin_map_component,
105                    protected virtual fixed_accessor_map_component,
106                    protected virtual fixed_attribute_map_component,
107                    protected virtual fixed_relation_map_component,
108                    protected virtual fixed_bus_map_component
109   {
110     // custom memory allocators for poisioning freshly-allocated memory
111   public:
112     void* operator new (size_t sz)
113     {
114       void* p = ::operator new (sz);
115       // Initialize the object with garbage, to ease detection of missing initialization.
116       char* q = (char*) p;
117       char deadbeef[] = { 0xde, 0xad, 0xbe, 0xef };
118       for (unsigned i=0; i<sz; i++)
119         *q++ = deadbeef[i % 4];
120       return p;
121     }
122     void operator delete (void* p)
123     {
124       ::operator delete (p);
125     }
126
127     // recursion protection
128   protected:
129     recursion_limited step_limit;
130
131     // scheduler querying
132   protected:
133     friend class scheduler_time_query<basic_cpu>;
134     scheduler_time_query<basic_cpu> sched_query;
135
136     // triggerpoint support
137   protected:
138     friend class self_watcher<basic_cpu>;
139     self_watcher<basic_cpu> triggerpoint_manager;
140     // Virtual pin interfaces between self_watcher and fixed_pin_map_component
141     sid::component::status pin_factory (const std::string& name)
142       {
143         return this->triggerpoint_manager.create_virtual_pin (name);
144       }
145     void pin_junkyard (const std::string& name)
146       {
147         return this->triggerpoint_manager.destroy_virtual_pin (name);
148       }
149   // Helper functions for target view support
150   template <class PinType>
151   void add_watchable_pin (const std::string& name, PinType* pin)
152     {
153       this->add_pin (name, pin);
154       this->add_attribute (name, pin, "pin");
155       this->triggerpoint_manager.add_watchable_attribute (name);
156       this->categorize (name, "watchable");
157     }
158
159   template <class ValueType>
160   void add_watchable_register (const std::string& name, ValueType* value)
161     {
162       this->add_attribute (name, value, "register");
163       this->triggerpoint_manager.add_watchable_value (name, value);
164       this->categorize (name, "watchable");
165     }
166
167   template <class Class, typename Getter, typename Setter>
168   void add_watchable_register (const std::string& name,
169                                Class* receiver,
170                                Getter getter,
171                                Setter setter)
172     {
173       this->add_attribute_virtual (name, receiver, getter, setter, "register");
174       this->triggerpoint_manager.add_watchable_attribute (name);
175       this->categorize (name, "watchable");
176     }
177
178   template <class Class, typename Getter, typename Setter, typename Parameter>
179   void add_watchable_register (const std::string& name,
180                                Parameter param,
181                                Class* receiver,
182                                Getter getter,
183                                Setter setter)
184     {
185       this->add_attribute_virtual_parameterized (name, param, receiver, 
186                                                  getter, setter, "register");
187       this->triggerpoint_manager.add_watchable_attribute (name);
188       this->categorize (name, "watchable");
189     }
190
191   template <class ValueType>
192   void add_watchable_ro_register (const std::string& name, ValueType* value)
193     {
194       this->add_attribute_ro (name, value, "register");
195       this->triggerpoint_manager.add_watchable_attribute (name);
196       this->categorize (name, "watchable");
197     }
198
199     // step/yield control pins
200   protected:
201     callback_pin<basic_cpu> step_pin;
202     callback_pin<basic_cpu> yield_pin;
203     callback_pin<basic_cpu> print_insn_summary_pin;
204     bool yield_p;
205     sid::host_int_4 step_insn_count;
206     sid::host_int_8 total_insn_count;
207     mutable sid::host_int_8 total_latency;
208     sid::host_int_4 current_step_insn_count;
209     output_pin step_cycles_pin;
210     output_pin cg_caller_pin;
211     output_pin cg_callee_pin;
212    
213     // tracing
214   private:
215     string trace_filename;
216     callback_pin<basic_cpu> trace_pin;
217     class cpu_trace_stream: public std::ofstream
218     {
219     public:
220       cpu_trace_stream ()
221         :cout_p (true) {}
222       cpu_trace_stream (const std::string& filename)
223         :std::ofstream (filename.c_str ()), cout_p (false) {}
224       void divert_to_file () { cout_p = false; }
225       void divert_to_cout () { cout_p = true; }
226       void open (const std::string& filename)
227       {
228         std::ofstream::open (filename.c_str (), std::ios::app);
229         cout_p = false;
230       }
231       void end_line ()
232       {
233         if (LIKELY (cout_p))
234           std::cout << std::endl;
235         else
236           *this << std::endl;
237       }
238     private:
239       bool cout_p;
240
241       template <typename T> friend
242       basic_cpu::cpu_trace_stream& operator<< (basic_cpu::cpu_trace_stream& s, T t);
243     };
244
245     template <typename T> friend
246     cpu_trace_stream& operator<< (cpu_trace_stream& s, T t);
247
248     void trace_pin_handler (sid::host_int_4 value)
249       {
250         trace_stream << static_cast<char> (value);
251       }
252
253   public:
254     bool trace_extract_p;
255     bool trace_result_p;
256     bool trace_disass_p;
257     bool trace_semantics_p;
258     bool trace_counter_p;
259     bool final_insn_count_p;
260     bool enable_step_trap_p;
261     cpu_trace_stream trace_stream;
262
263     virtual void step_pin_handler (sid::host_int_4)
264       {
265         recursion_record limit (& this->step_limit);
266         if (UNLIKELY(! limit.ok())) return;
267
268         this->current_step_insn_count = 0;
269         this->yield_p = false;
270
271         // Check for triggerpoints due right now; may set yield_p!
272         this->triggerpoint_manager.check_and_dispatch ();
273
274         // Enter insn loop.  Poll continue_after_insn_p after each instruction
275         sid::host_int_8 prev_latency = this->total_latency;
276         sid::host_int_8 prev_insn_count = this->total_insn_count;
277         if (! this->yield_p)
278           this->step_insns ();
279         sid::host_int_8 num_insns = this->total_insn_count - prev_insn_count;
280         sid::host_int_8 latency = this->total_latency - prev_latency;
281
282         // Clamp
283         const sid::host_int_4 min_num_cycles = 1;
284         const sid::host_int_4 max_num_cycles = 0x7FFFFFFF;
285         sid::host_int_8 insn_cycles = num_insns + latency_to_cycles (latency);
286         sid::host_int_4 num_cycles =
287           insn_cycles <= min_num_cycles ? min_num_cycles :
288           insn_cycles >= max_num_cycles ? max_num_cycles :
289           insn_cycles;
290         this->stepped (num_cycles);
291       }
292     void yield ()
293       {
294         this->yield_p = true;
295         // A subsequent continue_after_insns_p should return false.
296       }
297     void yield_pin_handler (sid::host_int_4)
298       {
299         this->yield ();
300       }
301     virtual void print_insn_summary (sid::host_int_4)
302       {
303         std::cerr << "instruction count: " << this->total_insn_count << "  "
304                   << "simulated cycles: " << this->total_latency + this->total_insn_count << std::endl;
305       }
306     virtual void stepped (sid::host_int_4 n)
307       {
308         this->step_cycles_pin.drive (n);
309       }
310     void cg_profile (sid::host_int_4 caller, sid::host_int_4 callee)
311     {
312       // The drive sequence is important: see sw-profile-gprof
313       this->cg_caller_pin.drive (caller);
314       this->cg_callee_pin.drive (callee);
315
316       if (UNLIKELY(this->trace_result_p)) 
317         {
318           this->trace_stream << "cg-profile "
319                              << make_numeric_attribute (caller, 
320                                                         std::ios::hex|std::ios::showbase)
321                              << "->" 
322                              << make_numeric_attribute (callee,
323                                                         std::ios::hex|std::ios::showbase)
324                              << "  ";
325         }
326     }
327
328   public:
329     void set_total_latency (sid::host_int_8 latency) { this->total_latency = latency; }
330     void update_total_latency (sid::host_int_8 latency) { this->total_latency += latency; }
331     sid::host_int_8 get_total_latency () const  { return this->total_latency; }
332
333   protected:
334     virtual sid::host_int_8 latency_to_cycles (sid::host_int_8 num)
335     {
336       // Identity relationship: 1 latency unit = 1 cycle.
337       return num;
338     }
339
340     virtual void step_insns () = 0;
341     bool stop_after_insns_p (sid::host_int_4 num)
342       {
343         this->current_step_insn_count += num;
344         if (UNLIKELY(this->yield_p ||
345                     (this->current_step_insn_count >= this->step_insn_count)))
346           {
347             // Batch updates to total_insn_count to avoid long-long
348             // arithmetic overhead in the inner insn-stepping loops.
349             this->total_insn_count += this->current_step_insn_count;
350             this->current_step_insn_count = 0;
351             return true;
352           }
353         else
354           {
355             return false;
356           }
357       }
358
359     void
360     update_trace_destination ()
361     {
362       if (trace_filename == "-")
363         trace_stream.divert_to_cout ();
364       else
365         {
366           trace_stream.close ();
367           trace_stream.open (trace_filename);
368           trace_stream << "start of trace" << std::endl;
369           if (trace_stream.good ())
370             trace_stream.divert_to_file ();
371           else
372             trace_filename = "io-error!";
373         }
374     }
375
376     // Infer a change to trace_result_p after one of the other general 
377     // trace flags are changed.
378     void
379     update_trace_result_p ()
380     {
381       this->trace_result_p = (this->trace_semantics_p || this->trace_disass_p);
382     }
383
384
385     // Reset the processor model to power-up state.
386   private:
387     callback_pin<basic_cpu> reset_pin;
388     virtual void reset () = 0;
389     void reset_pin_handler(sid::host_int_4 v) { this->reset (); this->stepped(1); }
390
391     // Flush internal abstract icache (if any)
392   private:
393     callback_pin<basic_cpu> flush_icache_pin;
394     void flush_icache_pin_handler(sid::host_int_4 v) { this->flush_icache(); }
395   protected:
396     virtual void flush_icache () = 0;
397     virtual void flush_icache (sid::host_int_4 pc) { this->flush_icache (); }
398
399     // Set the initial PC after reset
400   private:
401     callback_pin<basic_cpu> pc_set_pin;
402     virtual void set_pc(sid::host_int_4) = 0;
403     void pc_set_pin_handler(sid::host_int_4 v) { this->set_pc (v); }
404
405     // Set the initial endianness after reset
406   private:
407     callback_pin<basic_cpu> endian_set_pin;
408     virtual void set_endian(sid::host_int_4) = 0;
409     void endian_set_pin_handler(sid::host_int_4 v) { this->set_endian (v); }
410     callback_pin<basic_cpu> eflags_set_pin;
411     virtual void set_eflags(sid::host_int_4) {}
412     void eflags_set_pin_handler(sid::host_int_4 v) { this->set_eflags (v); }
413
414     // Signal trap type code and argument
415   private:
416     output_pin trap_type_pin;
417     output_pin trap_code_pin;
418     input_pin trap_disposition_pin;
419   protected:
420     cpu_trap_disposition signal_trap (cpu_trap_type p, sid::host_int_4 param = 0)
421       {
422         // Prepare disposition pin in case we get no signal back
423         this->trap_disposition_pin.driven (sid::host_int_4(cpu_trap_unhandled));
424         this->trap_code_pin.drive (param);
425         this->trap_type_pin.drive (sid::host_int_4(p));
426         return static_cast<cpu_trap_disposition>(trap_disposition_pin.sense ());
427       }
428
429     
430     // state save/restore: Override these in derived classes, but
431     // include a call up to this base implementation.
432   protected:
433     virtual void stream_state(std::ostream& o) const 
434       {
435         o << "basic-cpu"
436           // attrs
437           << " " << this->step_insn_count
438           << " " << this->enable_step_trap_p
439           << " " << this->total_insn_count
440           << " " << this->total_latency
441           << " " << this->trace_extract_p
442           << " " << this->trace_result_p
443           << " " << this->trace_disass_p
444           << " " << this->trace_semantics_p
445           << " " << this->trace_counter_p
446           << " " << this->final_insn_count_p
447           // pins
448           << " " << this->step_cycles_pin
449           << " " << this->trap_type_pin
450           << " " << this->trap_code_pin;
451       }
452
453     virtual void destream_state(std::istream& i) 
454       {
455         std::string key;
456         i >> key;
457         if (key != "basic-cpu")
458           {
459             i.setstate (std::ios::badbit);
460             return;
461           }
462         i >> this->step_insn_count
463           >> this->enable_step_trap_p
464           >> this->total_insn_count
465           >> this->total_latency
466           >> this->trace_extract_p
467           >> this->trace_result_p
468           >> this->trace_disass_p
469           >> this->trace_semantics_p
470           >> this->trace_counter_p
471           >> this->final_insn_count_p
472           // pins
473           >> this->step_cycles_pin
474           >> this->trap_type_pin
475           >> this->trap_code_pin;
476       }
477
478     // helper functions
479   private:
480     friend std::ostream& operator << (std::ostream& o, const basic_cpu& c);
481     friend std::istream& operator >> (std::istream& i, basic_cpu& c);
482     std::string save_state() { return make_attribute(*this); }
483     sid::component::status restore_state(const std::string& s)
484       { return parse_attribute(s, *this); }
485
486
487     // ------------------------------------------------------------------------
488     // debugger access functions
489   private:
490     passthrough_bus debugger_bus;
491     virtual std::string dbg_get_reg (sid::host_int_4 n) = 0;
492     virtual sid::component::status dbg_set_reg (sid::host_int_4 n, const std::string& s) = 0;
493
494   protected:
495     template <typename PC>
496     void create_gdb_register_attrs (sid::host_int_4 count, 
497                                     const std::string& expedited_regno_list, 
498                                     PC* pc)
499       {
500         this->add_watchable_register ("gdb-register-pc", pc);
501         this->add_attribute_ro_value ("gdb-num-registers", count, "debugger");
502
503         // The "expedited" register list string is the semi-colon-delimited list of
504         // register numbers that should be sent to gdb immediately
505         // every time sid stops, rather than let gdb ask for it
506         // subsequently.  Usually, the PC, frame and stack pointer,
507         // and status register should be included in the list.  It
508         // makes gdb step operations much faster.
509         // The register numbering scheme is that decided by gdb. 
510
511         this->add_attribute_ro_value ("gdb-exp-registers", expedited_regno_list, "debugger");
512         for (sid::host_int_4 i=0; i<count; i++)
513           {
514             std::string name = std::string ("gdb-register-") + make_numeric_attribute (i);
515             attribute_coder_base* coder =
516               new attribute_coder_virtual_parameterized<basic_cpu,sid::host_int_4>
517               (this, & basic_cpu::dbg_get_reg, & basic_cpu::dbg_set_reg, i);
518             this->add_attribute_coder (name, coder, "debugger");
519           }
520       }
521
522
523     // ------------------------------------------------------------------------
524     // memory access functions
525
526   protected:
527     sid::bus* data_bus;
528     sid::bus* insn_bus;
529     sid::bus* disassembler_bus;
530
531   protected:
532     template <typename BigOrLittleInt>
533     BigOrLittleInt read_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt);
534     template <typename BigOrLittleInt>
535     BigOrLittleInt write_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value);
536     template <typename BigOrLittleInt>
537     BigOrLittleInt read_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt);
538     template <typename BigOrLittleInt>
539     BigOrLittleInt write_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value);
540
541     virtual bool handle_insn_memory_read_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
542     virtual bool handle_insn_memory_write_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
543     virtual bool handle_data_memory_read_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
544     virtual bool handle_data_memory_write_error (sid::bus::status s, sid::host_int_4 & address) { return false; }
545
546     virtual void record_insn_memory_read_latency (sid::bus::status s) { total_latency += s.latency; }
547     virtual void record_insn_memory_write_latency (sid::bus::status s) { total_latency += s.latency; }
548     virtual void record_data_memory_read_latency (sid::bus::status s) { total_latency += s.latency; }
549     virtual void record_data_memory_write_latency (sid::bus::status s) { total_latency += s.latency; }
550
551     // ------------------------------------------------------------------------
552     
553 public:
554     basic_cpu ():
555       total_latency (0),
556       step_limit ("instruction stepping", 1),
557       sched_query (this),
558       triggerpoint_manager (this),
559       step_pin (this, & basic_cpu::step_pin_handler),
560       yield_pin (this, & basic_cpu::yield_pin_handler),
561       reset_pin (this, & basic_cpu::reset_pin_handler),
562       print_insn_summary_pin (this, & basic_cpu::print_insn_summary),
563       flush_icache_pin (this, & basic_cpu::flush_icache_pin_handler),
564       pc_set_pin (this, & basic_cpu::pc_set_pin_handler),
565       endian_set_pin (this, & basic_cpu::endian_set_pin_handler),
566       eflags_set_pin (this, & basic_cpu::eflags_set_pin_handler),
567       debugger_bus (& this->data_bus),
568       trace_stream (),
569       trace_filename ("-"), // standard output
570       trace_pin (this, & basic_cpu::trace_pin_handler)
571       {
572         // buses
573         this->data_bus = 0;
574         add_accessor ("data-memory", & this->data_bus);
575         this->insn_bus = 0;
576         add_accessor ("insn-memory", & this->insn_bus);
577         this->disassembler_bus = 0;
578         add_accessor ("disassembler-memory", & this->disassembler_bus);
579         add_bus ("debugger-bus", & this->debugger_bus);
580
581         // pins
582         add_pin ("step!", & this->step_pin);
583         add_watchable_pin ("step-cycles", & this->step_cycles_pin);
584         add_pin ("flush-icache", & this->flush_icache_pin);
585         add_pin ("reset!", & this->reset_pin);
586         add_pin ("yield", & this->yield_pin);
587         add_pin ("start-pc-set!", & this->pc_set_pin);
588         add_pin ("cg-caller", & this->cg_caller_pin);
589         add_pin ("cg-callee", & this->cg_callee_pin);
590         add_pin ("print-insn-summary!", & this->print_insn_summary_pin);
591         add_pin ("endian-set!", & this->endian_set_pin);
592         add_pin ("eflags-set!", & this->eflags_set_pin);
593         add_watchable_pin ("trap", & this->trap_type_pin); // output side
594         add_watchable_pin ("trap-code", & this->trap_code_pin);
595         add_pin ("trap", & this->trap_disposition_pin); // input side
596         add_pin ("trace", & this->trace_pin);
597
598         // attributes
599         this->step_insn_count = 1;
600         add_attribute ("step-insn-count", & this->step_insn_count, "setting");
601         this->enable_step_trap_p = false;
602         add_attribute ("enable-step-trap?", & this->enable_step_trap_p, "setting");
603         this->total_insn_count = 0;
604         add_watchable_register ("insn-count", & this->total_insn_count);
605         add_attribute_virtual ("state-snapshot", this,
606                                & basic_cpu::save_state,
607                                & basic_cpu::restore_state);
608         add_attribute_notify ("trace-filename", & this->trace_filename, this,
609                               & basic_cpu::update_trace_destination,
610                               "setting");
611         this->trace_extract_p = false;
612         add_attribute ("trace-extract?", & trace_extract_p, "setting");
613         this->trace_semantics_p = false;
614         add_attribute_notify ("trace-semantics?", & this->trace_semantics_p, this,
615                                & basic_cpu::update_trace_result_p, 
616                                "setting");
617         this->trace_disass_p = false;
618         add_attribute_notify ("trace-disassemble?", & this->trace_disass_p, this,
619                                & basic_cpu::update_trace_result_p, 
620                                "setting");
621         // `trace-result?' should go away after all simulators are updated to
622         // use `trace-semantics?'.
623         this->trace_result_p = false;
624         add_attribute ("trace-result?", & this->trace_result_p, "setting");
625         this->trace_counter_p = false;
626         add_attribute ("trace-counter?", & this->trace_counter_p, "setting");
627         this->final_insn_count_p = false;
628         add_attribute ("final-insn-count?", & this->final_insn_count_p, "setting");
629       }
630
631     virtual ~basic_cpu() throw() {}
632   };
633
634
635   inline std::ostream& operator << (std::ostream& o, const basic_cpu& c) {
636     c.stream_state (o);
637     return o;
638   }
639   inline std::istream& operator >> (std::istream& i, basic_cpu& c) {
640     c.destream_state (i);
641     return i;
642   }
643
644     template <typename T>
645     basic_cpu::cpu_trace_stream& operator<< (basic_cpu::cpu_trace_stream& s, T t)
646     {
647       if (LIKELY (s.cout_p))
648         std::cout << t;
649       else
650         static_cast <std::ofstream&> (s) << t;
651       return s;
652     }
653   
654     template <typename BigOrLittleInt>
655     BigOrLittleInt basic_cpu::read_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt)
656       {
657         sid::bus::status s;
658         do
659           {
660             BigOrLittleInt value;
661             if (LIKELY(this->insn_bus))
662               {
663                 s = this->insn_bus->read (address, value);
664                 if (LIKELY(s == sid::bus::ok))
665                   {
666                     if (UNLIKELY ((trace_counter_p || final_insn_count_p) && s.latency))
667                       record_insn_memory_read_latency (s);
668                     return value;
669                   }
670               }
671             else
672               s = sid::bus::unmapped;
673           }
674         while (UNLIKELY (handle_insn_memory_read_error (s, address)));
675
676         throw cpu_memory_fault (pc, address, s, "insn read");
677       }
678
679     template <typename BigOrLittleInt>
680     BigOrLittleInt basic_cpu::write_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value)
681       {
682         sid::bus::status s;
683         do
684           {
685             if (LIKELY(this->insn_bus))
686               {
687                 s = this->insn_bus->write (address, value);
688                 if (LIKELY(s == sid::bus::ok))
689                   {
690                     if (UNLIKELY ((trace_counter_p || final_insn_count_p) && s.latency))
691                       record_insn_memory_write_latency (s);
692                     return value;
693                   }
694               }
695             else
696               s = sid::bus::unmapped;
697           }
698         while (UNLIKELY (handle_insn_memory_read_error (s, address)));
699
700         throw cpu_memory_fault (pc, address, s, "insn write");
701       }
702
703     template <typename BigOrLittleInt>
704     BigOrLittleInt basic_cpu::read_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt)
705       {
706         sid::bus::status s;
707         do
708           {
709             BigOrLittleInt value;
710             if (LIKELY(this->data_bus))
711               {
712                 s = this->data_bus->read (address, value);
713                 if (LIKELY(s == sid::bus::ok))
714                   {
715                     if (UNLIKELY ((trace_counter_p || final_insn_count_p) && s.latency))
716                       record_data_memory_read_latency (s);
717                     return value;
718                   }
719               }
720             else
721               s = sid::bus::unmapped;
722           }
723         while (UNLIKELY (handle_insn_memory_read_error (s, address)));
724
725         throw cpu_memory_fault (pc, address, s, "data read");
726       }
727
728     template <typename BigOrLittleInt>
729     BigOrLittleInt basic_cpu::write_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value)
730       {
731         sid::bus::status s;
732         do
733           {
734             if (LIKELY(this->data_bus))
735               {
736                 s = this->data_bus->write (address, value);
737                 if (LIKELY(s == sid::bus::ok))
738                   {
739                     if (UNLIKELY ((trace_counter_p || final_insn_count_p) && s.latency))
740                       record_data_memory_write_latency (s);
741                     return value;
742                   }
743               }
744             else
745               s = sid::bus::unmapped;
746           }
747         while (UNLIKELY (handle_insn_memory_read_error (s, address)));
748
749         throw cpu_memory_fault (pc, address, s, "data write");
750       }
751
752
753
754   // ------------------------------------------------------------------------
755   // Derived classes for memory access functions of various endianness
756
757   class basic_big_endian_cpu: public basic_cpu
758   {
759     void set_endian(sid::host_int_4) {}
760     void set_eflags(sid::host_int_4) {}
761
762   protected:
763
764     basic_big_endian_cpu ()
765       {
766         add_attribute_ro_value ("endian", endian_big, "register");
767       }
768     ~basic_big_endian_cpu () throw() {}
769
770     sid::host_int_1 read_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address)
771       {
772         return this->read_insn_memory (pc, address, sid::big_int_1());
773       }
774
775     sid::host_int_2 read_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address)
776       {
777         return this->read_insn_memory (pc, address, sid::big_int_2());
778       }
779
780     sid::host_int_4 read_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address)
781       {
782         return this->read_insn_memory (pc, address, sid::big_int_4());
783       }
784
785     sid::host_int_8 read_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address)
786       {
787         return this->read_insn_memory (pc, address, sid::big_int_8());
788       }
789
790     void write_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value)
791       {
792         this->write_insn_memory (pc, address, sid::big_int_1(value));
793       }
794
795     void write_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value)
796       {
797         this->write_insn_memory (pc, address, sid::big_int_2(value));
798       }
799
800     void write_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value)
801       {
802         this->write_insn_memory (pc, address, sid::big_int_4(value));
803       }
804
805     void write_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value)
806       {
807         this->write_insn_memory (pc, address, sid::big_int_8(value));
808       }
809
810     sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address)
811       {
812         return this->read_data_memory (pc, address, sid::big_int_1());
813       }
814
815     sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address)
816       {
817         return this->read_data_memory (pc, address, sid::big_int_2());
818       }
819
820     sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address)
821       {
822         return this->read_data_memory (pc, address, sid::big_int_4());
823       }
824
825     sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address)
826       {
827         return this->read_data_memory (pc, address, sid::big_int_8());
828       }
829
830     void write_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value)
831       {
832         this->write_data_memory (pc, address, sid::big_int_1(value));
833       }
834
835     void write_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value)
836       {
837         this->write_data_memory (pc, address, sid::big_int_2(value));
838       }
839
840     void write_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value)
841       {
842         this->write_data_memory (pc, address, sid::big_int_4(value));
843       }
844
845     void write_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value)
846       {
847         this->write_data_memory (pc, address, sid::big_int_8(value));
848       }
849   };
850
851
852   // ----------------------------------------------------------------------------
853
854   class basic_little_endian_cpu: public basic_cpu
855   {
856     void set_endian(sid::host_int_4) {}
857     void set_eflags(sid::host_int_4) {}
858
859   protected:
860     basic_little_endian_cpu ()
861       {
862         add_attribute_ro_value ("endian", endian_little, "register");
863       }
864     ~basic_little_endian_cpu () throw() {}
865
866     sid::host_int_1 read_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address)
867       {
868         return this->read_insn_memory (pc, address, sid::little_int_1());
869       }
870
871     sid::host_int_2 read_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address)
872       {
873         return this->read_insn_memory (pc, address, sid::little_int_2());
874       }
875
876     sid::host_int_4 read_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address)
877       {
878         return this->read_insn_memory (pc, address, sid::little_int_4());
879       }
880
881     sid::host_int_8 read_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address)
882       {
883         return this->read_insn_memory (pc, address, sid::little_int_8());
884       }
885
886     void write_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value)
887       {
888         this->write_insn_memory (pc, address, sid::little_int_1(value));
889       }
890
891     void write_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value)
892       {
893         this->write_insn_memory (pc, address, sid::little_int_2(value));
894       }
895
896     void write_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value)
897       {
898         this->write_insn_memory (pc, address, sid::little_int_4(value));
899       }
900
901     void write_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value)
902       {
903         this->write_insn_memory (pc, address, sid::little_int_8(value));
904       }
905
906     sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address)
907       {
908         return this->read_data_memory (pc, address, sid::little_int_1());
909       }
910
911     sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address)
912       {
913         return this->read_data_memory (pc, address, sid::little_int_2());
914       }
915
916     sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address)
917       {
918         return this->read_data_memory (pc, address, sid::little_int_4());
919       }
920
921     sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address)
922       {
923         return this->read_data_memory (pc, address, sid::little_int_8());
924       }
925
926     void write_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value)
927       {
928         this->write_data_memory (pc, address, sid::little_int_1(value));
929       }
930
931     void write_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value)
932       {
933         this->write_data_memory (pc, address, sid::little_int_2(value));
934       }
935
936     void write_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value)
937       {
938         this->write_data_memory (pc, address, sid::little_int_4(value));
939       }
940
941     void write_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value)
942       {
943         this->write_data_memory (pc, address, sid::little_int_8(value));
944       }
945   };
946
947
948   // ----------------------------------------------------------------------------
949
950
951   class basic_bi_endian_cpu: public basic_cpu
952   {
953     endian _current_endianness;
954   protected:
955     endian current_endianness() const { return this->_current_endianness; }
956
957   protected:
958     basic_bi_endian_cpu ()
959       {
960         this->_current_endianness = endian_big;
961         add_attribute ("endian", & this->_current_endianness, "register");
962       }
963     ~basic_bi_endian_cpu () throw() {}
964
965     void set_endian(sid::host_int_4 v)
966       {
967         switch (v)
968           {
969           case 1:
970             this->_current_endianness = endian_big;
971             break;
972           case 2:
973             this->_current_endianness = endian_little;
974             break;
975           default:
976             // XXX: warning message?
977             break;
978           }
979       }
980
981     void stream_state(std::ostream& o) const 
982       {
983         basic_cpu::stream_state(o);
984         o << " " << this->_current_endianness;
985       }
986
987     void destream_state(std::istream& i) 
988       {
989         basic_cpu::destream_state(i);
990         i >> this->_current_endianness;
991       }
992
993
994     sid::host_int_1 read_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address)
995       {
996         if (this->_current_endianness == endian_little)
997           return this->read_insn_memory (pc, address, sid::little_int_1());
998         else // endian_big or endian_unknown
999           return this->read_insn_memory (pc, address, sid::big_int_1());
1000       }
1001
1002     sid::host_int_2 read_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address)
1003       {
1004         if (this->_current_endianness == endian_little)
1005           return this->read_insn_memory (pc, address, sid::little_int_2());
1006         else // endian_big or endian_unknown
1007           return this->read_insn_memory (pc, address, sid::big_int_2());
1008       }
1009
1010     sid::host_int_4 read_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address)
1011       {
1012         if (this->_current_endianness == endian_little)
1013           return this->read_insn_memory (pc, address, sid::little_int_4());
1014         else // endian_big or endian_unknown
1015           return this->read_insn_memory (pc, address, sid::big_int_4());
1016       }
1017
1018     sid::host_int_8 read_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address)
1019       {
1020         if (this->_current_endianness == endian_little)
1021           return this->read_insn_memory (pc, address, sid::little_int_8());
1022         else // endian_big or endian_unknown
1023           return this->read_insn_memory (pc, address, sid::big_int_8());
1024       }
1025
1026     void write_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value)
1027       {
1028         if (this->_current_endianness == endian_little)
1029           this->write_insn_memory (pc, address, sid::little_int_1(value));
1030         else // endian_big or endian_unknown
1031           this->write_insn_memory (pc, address, sid::big_int_1(value));
1032       }
1033
1034     void write_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value)
1035       {
1036         if (this->_current_endianness == endian_little)
1037           this->write_insn_memory (pc, address, sid::little_int_2(value));
1038         else // endian_big or endian_unknown
1039           this->write_insn_memory (pc, address, sid::big_int_2(value));
1040       }
1041
1042     void write_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value)
1043       {
1044         if (this->_current_endianness == endian_little)
1045           this->write_insn_memory (pc, address, sid::little_int_4(value));
1046         else // endian_big or endian_unknown
1047           this->write_insn_memory (pc, address, sid::big_int_4(value));
1048       }
1049
1050     void write_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value)
1051       {
1052         if (this->_current_endianness == endian_little)
1053           this->write_insn_memory (pc, address, sid::little_int_8(value));
1054         else // endian_big or endian_unknown
1055           this->write_insn_memory (pc, address, sid::big_int_8(value));
1056       }
1057
1058     sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address)
1059       {
1060         if (this->_current_endianness == endian_little)
1061           return this->read_data_memory (pc, address, sid::little_int_1());
1062         else // endian_big or endian_unknown
1063           return this->read_data_memory (pc, address, sid::big_int_1());
1064       }
1065
1066     sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address)
1067       {
1068         if (this->_current_endianness == endian_little)
1069           return this->read_data_memory (pc, address, sid::little_int_2());
1070         else // endian_big or endian_unknown
1071           return this->read_data_memory (pc, address, sid::big_int_2());
1072       }
1073
1074     sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address)
1075       {
1076         if (this->_current_endianness == endian_little)
1077           return this->read_data_memory (pc, address, sid::little_int_4());
1078         else // endian_big or endian_unknown
1079           return this->read_data_memory (pc, address, sid::big_int_4());
1080       }
1081
1082     sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address)
1083       {
1084         if (this->_current_endianness == endian_little)
1085           return this->read_data_memory (pc, address, sid::little_int_8());
1086         else // endian_big or endian_unknown
1087           return this->read_data_memory (pc, address, sid::big_int_8());
1088       }
1089
1090     void write_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value)
1091       {
1092         if (this->_current_endianness == endian_little)
1093           this->write_data_memory (pc, address, sid::little_int_1(value));
1094         else // endian_big or endian_unknown
1095           this->write_data_memory (pc, address, sid::big_int_1(value));
1096       }
1097
1098     void write_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value)
1099       {
1100         if (this->_current_endianness == endian_little)
1101           this->write_data_memory (pc, address, sid::little_int_2(value));
1102         else // endian_big or endian_unknown
1103           this->write_data_memory (pc, address, sid::big_int_2(value));
1104       }
1105
1106     void write_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value)
1107       {
1108         if (this->_current_endianness == endian_little)
1109           this->write_data_memory (pc, address, sid::little_int_4(value));
1110         else // endian_big or endian_unknown
1111           this->write_data_memory (pc, address, sid::big_int_4(value));
1112       }
1113
1114     void write_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value)
1115       {
1116         if (this->_current_endianness == endian_little)
1117           this->write_data_memory (pc, address, sid::little_int_8(value));
1118         else // endian_big or endian_unknown
1119           this->write_data_memory (pc, address, sid::big_int_8(value));
1120       }
1121   };
1122
1123
1124 } // end namespace sidutil
1125
1126
1127 #endif // SIDCPUUTIL_H