OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / include / sidcpuutil.h
1 // sidcpuutil.h - Elements common to CPU models.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 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
17 namespace sidutil
18 {
19   // kinds of endianness
20   enum endian 
21   {
22     endian_unknown = 0,
23     endian_big = 1,
24     endian_little = 2
25   };
26   
27   inline
28     std::ostream& operator << (std::ostream& o, const endian& e)
29       {
30         switch (e) 
31           {
32           default: 
33           case endian_unknown: o << "unknown"; break;
34           case endian_big: o << "big"; break;
35           case endian_little: o << "little"; break;
36           }
37         return o;
38       }
39   
40   
41   inline
42     std::istream& operator >> (std::istream& i, endian& e)
43       {
44         std::string s;
45         i >> s;
46         if (s == "unknown" || s == "0") { e = endian_unknown; }
47         else if (s == "big" || s == "1") { e = endian_big; }
48         else if (s == "little" || s == "2") { e = endian_little; }
49         else { i.setstate(std::ios::badbit); e = endian_unknown; }
50         return i;
51       }
52
53   // ------------------------------------------------------------------------
54
55   class cpu_exception {};
56
57   class cpu_memory_fault: public cpu_exception
58   {
59   public:
60     sid::host_int_4 pc;
61     sid::host_int_4 address;
62     sid::bus::status status;
63     const char* operation;
64     
65     cpu_memory_fault (sid::host_int_4 p, sid::host_int_4 a, sid::bus::status s, const char* o):
66       pc(p), address(a), status(s), operation(o) 
67       {}
68   };
69   
70
71   // ------------------------------------------------------------------------
72
73
74   // Values travelling through the trap-type pin.
75   // Additional "arguments" are sent through the trap-code pin.
76   enum cpu_trap_type {
77     cpu_trap_software = 1,      // trap instruction hit
78     cpu_trap_breakpoint = 2,    // breakpoint instruction hit
79     cpu_trap_syscall = 3,       // system call instruction hit
80     cpu_trap_invalid_insn = 4,  // invalid instruction hit
81     cpu_trap_memory_fault = 5,  // memory fault encountered
82     cpu_trap_overflow = 6,      // arithmetic overflow
83     cpu_trap_stepped = 7,       // single-step completed
84   };
85
86
87   // Possible trap disposition codes
88   enum cpu_trap_disposition 
89   {
90     cpu_trap_unhandled = 0,     // dispatch to hardware fault handling
91     cpu_trap_handled = 1,       // supervisor handled faulting instruction
92     cpu_trap_reissue = 2,       // rerun faulting instruction
93     cpu_trap_skip = 3,          // skip faulting instruction
94   };
95
96
97   // ------------------------------------------------------------------------
98
99
100   class basic_cpu: public virtual sid::component,
101                    protected fixed_pin_map_component,
102                    protected fixed_accessor_map_component,
103                    protected fixed_attribute_map_component,
104                    protected no_relation_component,
105                    protected fixed_bus_map_component
106   {
107
108     // recursion protection
109   protected:
110     recursion_limited step_limit;
111
112     // triggerpoint support
113   protected:
114     friend class self_watcher<basic_cpu>;
115     self_watcher<basic_cpu> triggerpoint_manager;
116     // Virtual pin interfaces between self_watcher and fixed_pin_map_component
117     sid::component::status pin_factory (const std::string& name)
118       {
119         return this->triggerpoint_manager.create_virtual_pin (name);
120       }
121     void pin_junkyard (const std::string& name)
122       {
123         return this->triggerpoint_manager.destroy_virtual_pin (name);
124       }
125   // Helper functions for target view support
126   template <class PinType>
127   void add_watchable_pin (const std::string& name, PinType* pin)
128     {
129       this->add_pin (name, pin);
130       this->add_attribute (name, pin, "pin");
131       this->triggerpoint_manager.add_watchable_attribute (name);
132       this->categorize (name, "watchable");
133     }
134
135   template <class ValueType>
136   void add_watchable_register (const std::string& name, ValueType* value)
137     {
138       this->add_attribute (name, value, "register");
139       this->triggerpoint_manager.add_watchable_attribute (name);
140       this->categorize (name, "watchable");
141     }
142
143   template <class Class, typename Getter, typename Setter>
144   void add_watchable_register (const std::string& name,
145                                Class* receiver,
146                                Getter getter,
147                                Setter setter)
148     {
149       this->add_attribute_virtual (name, receiver, getter, setter, "register");
150       this->triggerpoint_manager.add_watchable_attribute (name);
151       this->categorize (name, "watchable");
152     }
153
154   template <class Class, typename Getter, typename Setter, typename Parameter>
155   void add_watchable_register (const std::string& name,
156                                Parameter param,
157                                Class* receiver,
158                                Getter getter,
159                                Setter setter)
160     {
161       this->add_attribute_virtual_parameterized (name, param, receiver, 
162                                                  getter, setter, "register");
163       this->triggerpoint_manager.add_watchable_attribute (name);
164       this->categorize (name, "watchable");
165     }
166
167   template <class ValueType>
168   void add_watchable_ro_register (const std::string& name, ValueType* value)
169     {
170       this->add_attribute_ro (name, value, "register");
171       this->triggerpoint_manager.add_watchable_attribute (name);
172       this->categorize (name, "watchable");
173     }
174
175     // step/yield control pins
176   private:
177     callback_pin<basic_cpu> step_pin;
178     callback_pin<basic_cpu> yield_pin;
179     bool yield_p;
180     sid::host_int_4 step_insn_count;
181     sid::host_int_8 total_insn_count;
182     sid::host_int_4 current_step_insn_count;
183     output_pin step_cycles_pin;
184   public:
185     bool trace_extract_p;
186     bool trace_result_p;
187     bool enable_step_trap_p;
188
189     void step_pin_handler (sid::host_int_4)
190       {
191         recursion_record limit (& this->step_limit);
192         if (! limit.ok()) return;
193
194         this->current_step_insn_count = 0;
195         this->yield_p = false;
196
197         // Enter insn loop.  Poll continue_after_insn_p after each instruction
198         sid::host_int_8 prev_insn_count = this->total_insn_count;
199         this->step_insns ();
200         sid::host_int_8 num_insns = this->total_insn_count - prev_insn_count;
201
202         // Clamp
203         const sid::host_int_4 min_num_cycles = 1;
204         const sid::host_int_4 max_num_cycles = 0x7FFFFFFF;
205         sid::host_int_4 num_cycles = 
206           num_insns <= min_num_cycles ? min_num_cycles :
207           num_insns >= max_num_cycles ? max_num_cycles :
208           num_insns;
209         this->stepped (num_cycles);
210       }
211     void yield ()
212       {
213         this->yield_p = true;
214         // A subsequent continue_after_insns_p should return false.
215       }
216     void yield_pin_handler (sid::host_int_4)
217       {
218         this->yield ();
219       }
220
221   protected:
222     virtual void step_insns () = 0;
223     void stepped (sid::host_int_4 n)
224       {
225         this->step_cycles_pin.drive (n);
226       }
227     bool stop_after_insns_p (sid::host_int_4 num)
228       {
229         this->current_step_insn_count += num;
230         if (this->yield_p ||
231             (this->current_step_insn_count >= this->step_insn_count))
232           {
233             // Batch updates to total_insn_count to avoid long-long
234             // arithmetic overhead in the inner insn-stepping loops.
235             this->total_insn_count += this->current_step_insn_count;
236             this->current_step_insn_count = 0;
237             return true;
238           }
239         else
240           {
241             return false;
242           }
243       }
244
245
246     // Reset the processor model to power-up state.
247   private:
248     callback_pin<basic_cpu> reset_pin;
249     virtual void reset () = 0;
250     void reset_pin_handler(sid::host_int_4 v) { this->reset (); this->stepped(1); }
251
252     // Flush internal abstract icache (if any)
253   private:
254     callback_pin<basic_cpu> flush_icache_pin;
255     virtual void flush_icache () = 0;
256     void flush_icache_pin_handler(sid::host_int_4 v) { this->flush_icache(); }
257
258     // Set the initial PC after reset
259   private:
260     callback_pin<basic_cpu> pc_set_pin;
261     virtual void set_pc(sid::host_int_4) = 0;
262     void pc_set_pin_handler(sid::host_int_4 v) { this->set_pc (v); }
263
264     // Set the initial endianness after reset
265   private:
266     callback_pin<basic_cpu> endian_set_pin;
267     virtual void set_endian(sid::host_int_4) = 0;
268     void endian_set_pin_handler(sid::host_int_4 v) { this->set_endian (v); }
269
270     // Signal trap type code and argument
271   private:
272     output_pin trap_type_pin;
273     output_pin trap_code_pin;
274     input_pin trap_disposition_pin;
275   protected:
276     cpu_trap_disposition signal_trap (cpu_trap_type p, sid::host_int_4 param = 0)
277       {
278         // Prepare disposition pin in case we get no signal back
279         this->trap_disposition_pin.driven (sid::host_int_4(cpu_trap_unhandled));
280         this->trap_code_pin.drive (param);
281         this->trap_type_pin.drive (sid::host_int_4(p));
282         return static_cast<cpu_trap_disposition>(trap_disposition_pin.sense ());
283       }
284
285     
286     // state save/restore: Override these in derived classes, but
287     // include a call up to this base implementation.
288   protected:
289     virtual void stream_state(std::ostream& o) const 
290       {
291         o << "basic-cpu"
292           // attrs
293           << " " << this->step_insn_count
294           << " " << this->enable_step_trap_p
295           << " " << this->total_insn_count
296           << " " << this->trace_extract_p
297           << " " << this->trace_result_p
298           // pins
299           << " " << this->step_cycles_pin
300           << " " << this->trap_type_pin
301           << " " << this->trap_code_pin;
302       }
303
304     virtual void destream_state(std::istream& i) 
305       {
306         std::string key;
307         i >> key;
308         if (key != "basic-cpu")
309           {
310             i.setstate (std::ios::badbit);
311             return;
312           }
313         i >> this->step_insn_count
314           >> this->enable_step_trap_p
315           >> this->total_insn_count
316           >> this->trace_extract_p
317           >> this->trace_result_p
318           // pins
319           >> this->step_cycles_pin
320           >> this->trap_type_pin
321           >> this->trap_code_pin;
322       }
323
324     // helper functions
325   private:
326     friend std::ostream& operator << (std::ostream& o, const basic_cpu& c);
327     friend std::istream& operator >> (std::istream& i, basic_cpu& c);
328     std::string save_state() { return make_attribute(*this); }
329     sid::component::status restore_state(const std::string& s)
330       { return parse_attribute(s, *this); }
331
332
333     // ------------------------------------------------------------------------
334     // debugger access functions
335   private:
336     passthrough_bus debugger_bus;
337     virtual std::string dbg_get_reg (sid::host_int_4 n) = 0;
338     virtual sid::component::status dbg_set_reg (sid::host_int_4 n, const std::string& s) = 0;
339
340   protected:
341     template <typename PC>
342     void create_gdb_register_attrs (sid::host_int_4 count, 
343                                     const std::string& expedited_regno_list, 
344                                     PC* pc)
345       {
346         this->triggerpoint_manager.add_watchable_value ("gdb-register-pc", pc);
347         this->add_attribute_ro_value ("gdb-num-registers", count, "debugger");
348         this->add_attribute_ro_value ("gdb-exp-registers", expedited_regno_list, "debugger");
349         for (sid::host_int_4 i=0; i<count; i++)
350           {
351             std::string name = std::string ("gdb-register-") + make_numeric_attribute (i);
352             attribute_coder_base* coder =
353               new attribute_coder_virtual_parameterized<basic_cpu,sid::host_int_4>
354               (this, & basic_cpu::dbg_get_reg, & basic_cpu::dbg_set_reg, i);
355             this->add_attribute_coder (name, coder, "debugger");
356           }
357       }
358
359
360     // ------------------------------------------------------------------------
361     // memory access functions
362
363   protected:
364     sid::bus* data_bus;
365     sid::bus* insn_bus;
366
367   protected:
368     template <typename BigOrLittleInt>
369     BigOrLittleInt read_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt) const;
370     template <typename BigOrLittleInt>
371     BigOrLittleInt write_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value) const;
372     template <typename BigOrLittleInt>
373     BigOrLittleInt read_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt) const;
374     template <typename BigOrLittleInt>
375     BigOrLittleInt write_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value) const;
376
377     // ------------------------------------------------------------------------
378     
379 public:
380     basic_cpu ():
381       step_limit ("instruction stepping", 1),
382       triggerpoint_manager (this),
383       step_pin (this, & basic_cpu::step_pin_handler),
384       yield_pin (this, & basic_cpu::yield_pin_handler),
385       reset_pin (this, & basic_cpu::reset_pin_handler),
386       flush_icache_pin (this, & basic_cpu::flush_icache_pin_handler),
387       pc_set_pin (this, & basic_cpu::pc_set_pin_handler),
388       endian_set_pin (this, & basic_cpu::endian_set_pin_handler),
389       debugger_bus (& this->data_bus)
390       {
391         // buses
392         this->data_bus = 0;
393         add_accessor ("data-memory", & this->data_bus);
394         this->insn_bus = 0;
395         add_accessor ("insn-memory", & this->insn_bus);
396         add_bus ("debugger-bus", & this->debugger_bus);
397
398         // pins
399         add_pin ("step!", & this->step_pin);
400         add_watchable_pin ("step-cycles", & this->step_cycles_pin);
401         add_pin ("flush-icache", & this->flush_icache_pin);
402         add_pin ("reset!", & this->reset_pin);
403         add_pin ("yield", & this->yield_pin);
404         add_pin ("start-pc-set!", & this->pc_set_pin);
405         add_pin ("endian-set!", & this->endian_set_pin);
406         add_watchable_pin ("trap", & this->trap_type_pin); // output side
407         add_watchable_pin ("trap-code", & this->trap_code_pin);
408         add_pin ("trap", & this->trap_disposition_pin); // input side
409
410         // attributes
411         this->step_insn_count = 1;
412         add_attribute ("step-insn-count", & this->step_insn_count, "setting");
413         this->enable_step_trap_p = false;
414         add_attribute ("enable-step-trap?", & this->enable_step_trap_p, "setting");
415         this->total_insn_count = 0;
416         add_watchable_register ("insn-count", & this->total_insn_count);
417         add_attribute_virtual ("state-snapshot", this,
418                                & basic_cpu::save_state,
419                                & basic_cpu::restore_state);
420         add_attribute ("trace-extract?", & trace_extract_p, "setting");
421         add_attribute ("trace-result?", & trace_result_p, "setting");
422       }
423
424     ~basic_cpu() {}
425   };
426
427
428   inline std::ostream& operator << (std::ostream& o, const basic_cpu& c) {
429     c.stream_state (o);
430     return o;
431   }
432   inline std::istream& operator >> (std::istream& i, basic_cpu& c) {
433     c.destream_state (i);
434     return i;
435   }
436
437     template <typename BigOrLittleInt>
438     BigOrLittleInt basic_cpu::read_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt) const
439       {
440         BigOrLittleInt value;
441         sid::bus::status s = 
442           this->insn_bus ? this->insn_bus->read (address, value) : sid::bus::unmapped;
443         if (s == sid::bus::ok)
444           return value;
445
446         throw cpu_memory_fault (pc, address, s, "insn read");
447       }
448
449     template <typename BigOrLittleInt>
450     BigOrLittleInt basic_cpu::write_insn_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value) const
451       {
452         sid::bus::status s = 
453           this->insn_bus ? this->insn_bus->write (address, value) : sid::bus::unmapped;
454         if (s == sid::bus::ok)
455           return value;
456
457         throw cpu_memory_fault (pc, address, s, "insn write");
458       }
459
460     template <typename BigOrLittleInt>
461     BigOrLittleInt basic_cpu::read_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt) const
462       {
463         BigOrLittleInt value;
464         sid::bus::status s = 
465           this->data_bus ? this->data_bus->read (address, value) : sid::bus::unmapped;
466         if (s == sid::bus::ok)
467           return value;
468
469         throw cpu_memory_fault (pc, address, s, "data read");
470       }
471
472     template <typename BigOrLittleInt>
473     BigOrLittleInt basic_cpu::write_data_memory (sid::host_int_4 pc, sid::host_int_4 address, BigOrLittleInt value) const
474       {
475         sid::bus::status s = 
476           this->data_bus ? this->data_bus->write (address, value) : sid::bus::unmapped;
477         if (s == sid::bus::ok)
478           return value;
479
480         throw cpu_memory_fault (pc, address, s, "data write");
481       }
482
483
484
485   // ------------------------------------------------------------------------
486   // Derived classes for memory access functions of various endianness
487
488   class basic_big_endian_cpu: public basic_cpu
489   {
490     void set_endian(sid::host_int_4) {}
491
492   protected:
493
494     basic_big_endian_cpu ()
495       {
496         add_attribute_ro_value ("endian", endian_big, "register");
497       }
498     ~basic_big_endian_cpu () {}
499
500     sid::host_int_1 read_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) const
501       {
502         return this->read_insn_memory (pc, address, sid::big_int_1());
503       }
504
505     sid::host_int_2 read_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) const
506       {
507         return this->read_insn_memory (pc, address, sid::big_int_2());
508       }
509
510     sid::host_int_4 read_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) const
511       {
512         return this->read_insn_memory (pc, address, sid::big_int_4());
513       }
514
515     sid::host_int_8 read_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) const
516       {
517         return this->read_insn_memory (pc, address, sid::big_int_8());
518       }
519
520     void write_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value) const
521       {
522         this->write_insn_memory (pc, address, sid::big_int_1(value));
523       }
524
525     void write_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value) const
526       {
527         this->write_insn_memory (pc, address, sid::big_int_2(value));
528       }
529
530     void write_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value) const
531       {
532         this->write_insn_memory (pc, address, sid::big_int_4(value));
533       }
534
535     void write_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value) const
536       {
537         this->write_insn_memory (pc, address, sid::big_int_8(value));
538       }
539
540     sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) const
541       {
542         return this->read_data_memory (pc, address, sid::big_int_1());
543       }
544
545     sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) const
546       {
547         return this->read_data_memory (pc, address, sid::big_int_2());
548       }
549
550     sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) const
551       {
552         return this->read_data_memory (pc, address, sid::big_int_4());
553       }
554
555     sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) const
556       {
557         return this->read_data_memory (pc, address, sid::big_int_8());
558       }
559
560     void write_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value) const
561       {
562         this->write_data_memory (pc, address, sid::big_int_1(value));
563       }
564
565     void write_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value) const
566       {
567         this->write_data_memory (pc, address, sid::big_int_2(value));
568       }
569
570     void write_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value) const
571       {
572         this->write_data_memory (pc, address, sid::big_int_4(value));
573       }
574
575     void write_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value) const
576       {
577         this->write_data_memory (pc, address, sid::big_int_8(value));
578       }
579   };
580
581
582   // ----------------------------------------------------------------------------
583
584   class basic_little_endian_cpu: public basic_cpu
585   {
586     void set_endian(sid::host_int_4) {}
587
588   protected:
589     basic_little_endian_cpu ()
590       {
591         add_attribute_ro_value ("endian", endian_little, "register");
592       }
593     ~basic_little_endian_cpu () {}
594
595     sid::host_int_1 read_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) const
596       {
597         return this->read_insn_memory (pc, address, sid::little_int_1());
598       }
599
600     sid::host_int_2 read_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) const
601       {
602         return this->read_insn_memory (pc, address, sid::little_int_2());
603       }
604
605     sid::host_int_4 read_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) const
606       {
607         return this->read_insn_memory (pc, address, sid::little_int_4());
608       }
609
610     sid::host_int_8 read_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) const
611       {
612         return this->read_insn_memory (pc, address, sid::little_int_8());
613       }
614
615     void write_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value) const
616       {
617         this->write_insn_memory (pc, address, sid::little_int_1(value));
618       }
619
620     void write_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value) const
621       {
622         this->write_insn_memory (pc, address, sid::little_int_2(value));
623       }
624
625     void write_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value) const
626       {
627         this->write_insn_memory (pc, address, sid::little_int_4(value));
628       }
629
630     void write_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value) const
631       {
632         this->write_insn_memory (pc, address, sid::little_int_8(value));
633       }
634
635     sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) const
636       {
637         return this->read_data_memory (pc, address, sid::little_int_1());
638       }
639
640     sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) const
641       {
642         return this->read_data_memory (pc, address, sid::little_int_2());
643       }
644
645     sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) const
646       {
647         return this->read_data_memory (pc, address, sid::little_int_4());
648       }
649
650     sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) const
651       {
652         return this->read_data_memory (pc, address, sid::little_int_8());
653       }
654
655     void write_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value) const
656       {
657         this->write_data_memory (pc, address, sid::little_int_1(value));
658       }
659
660     void write_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value) const
661       {
662         this->write_data_memory (pc, address, sid::little_int_2(value));
663       }
664
665     void write_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value) const
666       {
667         this->write_data_memory (pc, address, sid::little_int_4(value));
668       }
669
670     void write_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value) const
671       {
672         this->write_data_memory (pc, address, sid::little_int_8(value));
673       }
674   };
675
676
677   // ----------------------------------------------------------------------------
678
679
680   class basic_bi_endian_cpu: public basic_cpu
681   {
682     endian _current_endianness;
683   protected:
684     endian current_endianness() const { return this->_current_endianness; }
685
686   protected:
687     basic_bi_endian_cpu ()
688       {
689         this->_current_endianness = endian_big;
690         add_attribute ("endian", & this->_current_endianness, "register");
691       }
692     ~basic_bi_endian_cpu () {}
693
694     void set_endian(sid::host_int_4 v)
695       {
696         switch (v)
697           {
698           case 1:
699             this->_current_endianness = endian_big;
700             break;
701           case 2:
702             this->_current_endianness = endian_little;
703             break;
704           default:
705             // XXX: warning message?
706             break;
707           }
708       }
709
710     void stream_state(std::ostream& o) const 
711       {
712         basic_cpu::stream_state(o);
713         o << " " << this->_current_endianness;
714       }
715
716     void destream_state(std::istream& i) 
717       {
718         basic_cpu::destream_state(i);
719         i >> this->_current_endianness;
720       }
721
722
723     sid::host_int_1 read_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) const
724       {
725         if (this->_current_endianness == endian_little)
726           return this->read_insn_memory (pc, address, sid::little_int_1());
727         else // endian_big or endian_unknown
728           return this->read_insn_memory (pc, address, sid::big_int_1());
729       }
730
731     sid::host_int_2 read_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) const
732       {
733         if (this->_current_endianness == endian_little)
734           return this->read_insn_memory (pc, address, sid::little_int_2());
735         else // endian_big or endian_unknown
736           return this->read_insn_memory (pc, address, sid::big_int_2());
737       }
738
739     sid::host_int_4 read_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) const
740       {
741         if (this->_current_endianness == endian_little)
742           return this->read_insn_memory (pc, address, sid::little_int_4());
743         else // endian_big or endian_unknown
744           return this->read_insn_memory (pc, address, sid::big_int_4());
745       }
746
747     sid::host_int_8 read_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) const
748       {
749         if (this->_current_endianness == endian_little)
750           return this->read_insn_memory (pc, address, sid::little_int_8());
751         else // endian_big or endian_unknown
752           return this->read_insn_memory (pc, address, sid::big_int_8());
753       }
754
755     void write_insn_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value) const
756       {
757         if (this->_current_endianness == endian_little)
758           this->write_insn_memory (pc, address, sid::little_int_1(value));
759         else // endian_big or endian_unknown
760           this->write_insn_memory (pc, address, sid::big_int_1(value));
761       }
762
763     void write_insn_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value) const
764       {
765         if (this->_current_endianness == endian_little)
766           this->write_insn_memory (pc, address, sid::little_int_2(value));
767         else // endian_big or endian_unknown
768           this->write_insn_memory (pc, address, sid::big_int_2(value));
769       }
770
771     void write_insn_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value) const
772       {
773         if (this->_current_endianness == endian_little)
774           this->write_insn_memory (pc, address, sid::little_int_4(value));
775         else // endian_big or endian_unknown
776           this->write_insn_memory (pc, address, sid::big_int_4(value));
777       }
778
779     void write_insn_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value) const
780       {
781         if (this->_current_endianness == endian_little)
782           this->write_insn_memory (pc, address, sid::little_int_8(value));
783         else // endian_big or endian_unknown
784           this->write_insn_memory (pc, address, sid::big_int_8(value));
785       }
786
787     sid::host_int_1 read_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address) const
788       {
789         if (this->_current_endianness == endian_little)
790           return this->read_data_memory (pc, address, sid::little_int_1());
791         else // endian_big or endian_unknown
792           return this->read_data_memory (pc, address, sid::big_int_1());
793       }
794
795     sid::host_int_2 read_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address) const
796       {
797         if (this->_current_endianness == endian_little)
798           return this->read_data_memory (pc, address, sid::little_int_2());
799         else // endian_big or endian_unknown
800           return this->read_data_memory (pc, address, sid::big_int_2());
801       }
802
803     sid::host_int_4 read_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address) const
804       {
805         if (this->_current_endianness == endian_little)
806           return this->read_data_memory (pc, address, sid::little_int_4());
807         else // endian_big or endian_unknown
808           return this->read_data_memory (pc, address, sid::big_int_4());
809       }
810
811     sid::host_int_8 read_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address) const
812       {
813         if (this->_current_endianness == endian_little)
814           return this->read_data_memory (pc, address, sid::little_int_8());
815         else // endian_big or endian_unknown
816           return this->read_data_memory (pc, address, sid::big_int_8());
817       }
818
819     void write_data_memory_1 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_1 value) const
820       {
821         if (this->_current_endianness == endian_little)
822           this->write_data_memory (pc, address, sid::little_int_1(value));
823         else // endian_big or endian_unknown
824           this->write_data_memory (pc, address, sid::big_int_1(value));
825       }
826
827     void write_data_memory_2 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_2 value) const
828       {
829         if (this->_current_endianness == endian_little)
830           this->write_data_memory (pc, address, sid::little_int_2(value));
831         else // endian_big or endian_unknown
832           this->write_data_memory (pc, address, sid::big_int_2(value));
833       }
834
835     void write_data_memory_4 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_4 value) const
836       {
837         if (this->_current_endianness == endian_little)
838           this->write_data_memory (pc, address, sid::little_int_4(value));
839         else // endian_big or endian_unknown
840           this->write_data_memory (pc, address, sid::big_int_4(value));
841       }
842
843     void write_data_memory_8 (sid::host_int_4 pc, sid::host_int_4 address, sid::host_int_8 value) const
844       {
845         if (this->_current_endianness == endian_little)
846           this->write_data_memory (pc, address, sid::little_int_8(value));
847         else // endian_big or endian_unknown
848           this->write_data_memory (pc, address, sid::big_int_8(value));
849       }
850   };
851
852
853 } // end namespace sidutil
854
855
856 #endif // SIDCPUUTIL_H