OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / mmu / armRemap.cxx
1 // armRemap.cxx - An implementation of the "remap and pause"
2 // controller from the ARM PID7T development board.  -*- C++ -*-
3
4 // Copyright (C) 1999, 2000 Red Hat.
5 // This file is part of SID and is licensed under the GPL.
6 // See the file COPYING.SID for conditions for redistribution.
7
8 // A more thorough description of this component may be found at
9 // <http://www.arm.com/Documentation/UserMans/rps/#rp>.
10
11 #include "config.h"
12 #include "tconfig.h"
13  
14 #include <sidcomp.h>
15 #include <sidso.h>
16 #include <sidcomputil.h>
17 #include <sidattrutil.h>
18 #include <sidmiscutil.h>
19 #include <sidpinutil.h>
20 #include <sidbusutil.h>
21 #include <sidtypes.h>
22 #include <sidwatchutil.h>
23
24 using std::map;
25 using std::vector;
26 using std::string;
27 using std::ostream;
28 using std::istream;
29 using std::pair;
30 using std::ios;
31
32 using sid::component;
33 using sid::bus;
34 using sid::host_int_1;
35 using sid::host_int_4;
36 using sid::little_int_1;
37 using sid::little_int_2;
38 using sid::little_int_4;
39 using sid::little_int_8;
40 using sid::big_int_1;
41 using sid::big_int_2;
42 using sid::big_int_4;
43 using sid::big_int_8;
44 using sid::component_library;
45 using sid::COMPONENT_LIBRARY_MAGIC;
46
47 using sidutil::attribute_coder_base;
48 using sidutil::attribute_coder_virtual_parameterized;
49 using sidutil::fixed_attribute_map_component;
50 using sidutil::fixed_bus_map_component;
51 using sidutil::fixed_pin_map_component;
52 using sidutil::fixed_accessor_map_component;
53 using sidutil::make_attribute;
54 using sidutil::parse_attribute;
55 using sidutil::no_relation_component;
56 using sidutil::callback_pin;
57 using sidutil::output_pin;
58 using sidutil::word_bus;
59 using sidutil::self_watcher;
60 using sidutil::tokenize;
61
62 #include <map>
63 #include <vector>
64 #include <string>
65
66 #if SIDTARGET_ARM
67
68 class armRemapPause: public virtual component, 
69                      protected fixed_attribute_map_component,
70                      protected fixed_bus_map_component,
71                      protected fixed_pin_map_component,
72                      protected fixed_accessor_map_component,
73                      protected no_relation_component
74 {
75 public:
76   armRemapPause();
77
78 private:
79   class map_bus: public bus
80   {
81   public:
82     map_bus(armRemapPause* target) :target(target) {}
83
84 #define BUS_WRITE(type1, type2) \
85     virtual bus::status write(type1 address, type2 data) throw () = 0;
86 #define BUS_READ(type1, type2) \
87     virtual bus::status read(type1 address, type2& data) throw () = 0;
88     
89     BUS_WRITE(host_int_4, little_int_1);
90     BUS_WRITE(host_int_4, little_int_2);
91     BUS_WRITE(host_int_4, little_int_4);
92     BUS_WRITE(host_int_4, little_int_8);
93     BUS_WRITE(host_int_4, big_int_1);
94     BUS_WRITE(host_int_4, big_int_2);
95     BUS_WRITE(host_int_4, big_int_4);
96     BUS_WRITE(host_int_4, big_int_8);
97
98     BUS_READ(host_int_4, little_int_1);
99     BUS_READ(host_int_4, little_int_2);
100     BUS_READ(host_int_4, little_int_4);
101     BUS_READ(host_int_4, little_int_8);
102     BUS_READ(host_int_4, big_int_1);
103     BUS_READ(host_int_4, big_int_2);
104     BUS_READ(host_int_4, big_int_4);
105     BUS_READ(host_int_4, big_int_8);
106
107 #undef BUS_WRITE
108 #undef BUS_READ
109
110   protected:
111     armRemapPause* target;
112   };
113     
114   class reset_map_bus: public map_bus
115   {
116   public:
117     reset_map_bus(armRemapPause* target): map_bus(target) {}
118
119 #define BUS_WRITE(type1, type2) \
120     bus::status write(type1 address, type2 data) throw () { \
121         if (! target->downstream_bus) return bus::unmapped; \
122         type1 newAddress = translate(address); \
123         return target->downstream_bus->write(newAddress, data);\
124     }
125
126 #define BUS_READ(type1, type2) \
127     bus::status read(type1 address, type2& data) throw () { \
128         if (! target->downstream_bus) return bus::unmapped; \
129         type1 newAddress = translate(address); \
130         return target->downstream_bus->read(newAddress, data); \
131     }
132       
133     BUS_WRITE(host_int_4, little_int_1);
134     BUS_WRITE(host_int_4, little_int_2);
135     BUS_WRITE(host_int_4, little_int_4);
136     BUS_WRITE(host_int_4, little_int_8);
137     BUS_WRITE(host_int_4, big_int_1);
138     BUS_WRITE(host_int_4, big_int_2);
139     BUS_WRITE(host_int_4, big_int_4);
140     BUS_WRITE(host_int_4, big_int_8);
141
142     BUS_READ(host_int_4, little_int_1);
143     BUS_READ(host_int_4, little_int_2);
144     BUS_READ(host_int_4, little_int_4);
145     BUS_READ(host_int_4, little_int_8);
146     BUS_READ(host_int_4, big_int_1);
147     BUS_READ(host_int_4, big_int_2);
148     BUS_READ(host_int_4, big_int_4);
149     BUS_READ(host_int_4, big_int_8);
150
151 #undef BUS_WRITE
152 #undef BUS_READ
153     
154   private:
155     host_int_4 translate(host_int_4 address)
156       {
157         if (target->translations.empty())
158           return address;
159
160         armRemapPause::translation_t::iterator it =
161           target->translations.upper_bound(address);
162         
163         if (it == target->translations.begin())
164           return address;
165
166         it--;
167         assert(address >= it->first);
168         return (address - it->first) + it->second;
169       }
170   }; 
171   
172   class normal_map_bus: public map_bus
173   {
174   public:
175     normal_map_bus(armRemapPause* target): map_bus(target) {}
176
177 #define BUS_WRITE(type1,type2) \
178     bus::status write(type1 address, type2 data) throw ( ) { \
179         if (! target->downstream_bus) return bus::unmapped; \
180           return target->downstream_bus->write(address, data); }
181   
182 #define BUS_READ(type1,type2) \
183     bus::status read(type1 address, type2& data) throw ( ) { \
184         if (! target->downstream_bus) return bus::unmapped; \
185           return target->downstream_bus->read(address, data); }
186
187     BUS_WRITE(host_int_4, little_int_1);
188     BUS_WRITE(host_int_4, little_int_2);
189     BUS_WRITE(host_int_4, little_int_4);
190     BUS_WRITE(host_int_4, little_int_8);
191     BUS_WRITE(host_int_4, big_int_1);
192     BUS_WRITE(host_int_4, big_int_2);
193     BUS_WRITE(host_int_4, big_int_4);
194     BUS_WRITE(host_int_4, big_int_8);
195
196     BUS_READ(host_int_4, little_int_1);
197     BUS_READ(host_int_4, little_int_2);
198     BUS_READ(host_int_4, little_int_4);
199     BUS_READ(host_int_4, little_int_8);
200     BUS_READ(host_int_4, big_int_1);
201     BUS_READ(host_int_4, big_int_2);
202     BUS_READ(host_int_4, big_int_4);
203     BUS_READ(host_int_4, big_int_8);
204
205 #undef BUS_WRITE
206 #undef BUS_READ
207   };
208
209
210   class remap_bus: public bus
211   {
212   public:
213     remap_bus(armRemapPause *target)
214       :target(target), reset_map(target), normal_map(target),
215        bus(&reset_map) {}
216
217     // Based on the setting of the remapping_p variable, switch the
218     // bus object used to do downstream memory transactions.
219     void bus_update();
220
221     // Unconditional switch to the normal map.
222     void use_normal_map();
223
224 #define BUS_WRITE(type1, type2) \
225     bus::status write(type1 address, type2 data) throw () \
226       { return bus->write(address, data); }
227     
228 #define BUS_READ(type1, type2) \
229     bus::status read(type1 address, type2& data) throw () \
230       { return bus->read(address, data); }
231
232     BUS_WRITE(host_int_4, little_int_1);
233     BUS_WRITE(host_int_4, little_int_2);
234     BUS_WRITE(host_int_4, little_int_4);
235     BUS_WRITE(host_int_4, little_int_8);
236     BUS_WRITE(host_int_4, big_int_1);
237     BUS_WRITE(host_int_4, big_int_2);
238     BUS_WRITE(host_int_4, big_int_4);
239     BUS_WRITE(host_int_4, big_int_8);
240
241     BUS_READ(host_int_4, little_int_1);
242     BUS_READ(host_int_4, little_int_2);
243     BUS_READ(host_int_4, little_int_4);
244     BUS_READ(host_int_4, little_int_8);
245     BUS_READ(host_int_4, big_int_1);
246     BUS_READ(host_int_4, big_int_2);
247     BUS_READ(host_int_4, big_int_4);
248     BUS_READ(host_int_4, big_int_8);
249
250 #undef BUS_WRITE
251 #undef BUS_READ
252
253   protected:
254     armRemapPause* target;
255
256   private:
257     reset_map_bus reset_map;
258     normal_map_bus normal_map;
259     map_bus* bus;
260   };
261   
262
263   class bus_interface: public word_bus<little_int_4>
264   {
265   public:
266     bus_interface(armRemapPause* target): target(target) {}
267
268     bus::status word_write(host_int_4 addr,
269                            little_int_4 mask,
270                            little_int_4 data);
271
272     bus::status word_read(host_int_4 addr,
273                           little_int_4 mask,
274                           little_int_4& data);
275
276   private:
277     armRemapPause* target;
278   };
279
280   friend class bus_interface;
281   friend class remap_bus;
282   friend class reset_map_bus;
283   friend class normal_map_bus;
284
285   bus* downstream_bus;
286   remap_bus upstream_bus;
287
288   void reset(host_int_4 value);
289   host_int_4 resetStatus;
290
291   // The controller's programmable registers.
292   bus_interface registers;
293
294   // Are we currently applying the translation map?
295   bool remapping_p;
296
297   typedef map<host_int_4, host_int_4> translation_t;
298   typedef pair<host_int_4, host_int_4> addr_pair_t;
299   typedef map<host_int_4, addr_pair_t> entry_t;
300
301   // The translation map, containing entries of address ranges and
302   // their corresponding relocations.
303   translation_t translations;
304
305   // An orthogonal map to keep necessary state about known
306   // relocations.
307   entry_t entries;
308
309   host_int_1 num_relocations;
310   string get_num_relocations();
311   component::status set_num_relocations(const string& s);
312
313   string get_start(host_int_4 entryNum);
314   component::status set_start(host_int_4 entryNum, const string& s);
315   
316   string get_end(host_int_4 entryNum);
317   component::status set_end(host_int_4 entryNum, const string& s);
318
319   string get_reloc(host_int_4 entryNum);
320   component::status set_reloc(host_int_4 entryNum, const string& s);
321
322   callback_pin<armRemapPause> resetPin;
323   friend class callback_pin<armRemapPause>;
324
325   output_pin halt;
326
327   // State save/restore support.
328   string save_state();
329   sid::component::status restore_state(const string& state);
330   friend ostream& operator<< (ostream& op, const armRemapPause& obj);
331   friend istream& operator>> (istream& ip, armRemapPause& obj);
332
333   // Triggerpoint support.
334   friend class self_watcher<armRemapPause>;
335   self_watcher<armRemapPause> triggerpoint_manager;
336
337   sid::component::status
338   pin_factory(const string& name)
339     {
340       return this->triggerpoint_manager.create_virtual_pin(name);
341     }
342
343   void
344   pin_junkyard(const string& name)
345     {
346       return this->triggerpoint_manager.destroy_virtual_pin(name);
347     }
348 };
349
350
351 armRemapPause::armRemapPause()
352   :upstream_bus(this), downstream_bus(0),
353    resetStatus(0), registers(this), remapping_p(true), num_relocations(0),
354    resetPin(this, & armRemapPause::reset),
355    triggerpoint_manager(this)
356 {
357   add_accessor("all", &downstream_bus);
358   add_attribute_notify("remapping?", &remapping_p, &upstream_bus,
359                        &armRemapPause::remap_bus::bus_update, 
360                        "setting");
361   add_attribute_virtual("num-relocations", this,
362                         &armRemapPause::set_num_relocations,
363                         &armRemapPause::get_num_relocations);
364   add_attribute_virtual("state-snapshot", this,
365                         &armRemapPause::restore_state,
366                         &armRemapPause::save_state);
367   add_bus("access-port", &upstream_bus);
368   add_bus("registers", &registers);
369   add_pin("reset", &resetPin);
370   add_pin("halt!", &halt);
371
372   triggerpoint_manager.add_watchable_attribute("remapping?");
373   categorize("remapping?", "watchable");
374 }
375
376 string
377 armRemapPause::save_state()
378 {
379   return make_attribute(*this);
380 }
381
382 sid::component::status
383 armRemapPause::restore_state(const string& state)
384 {
385   return parse_attribute(state, *this);
386 }
387
388 ostream& operator<< (ostream& op, const armRemapPause& obj)
389 {
390   op << "remapping " << obj.remapping_p
391      << " num-relocs " << static_cast<unsigned int> (obj.num_relocations)
392      << " relocs ";
393
394   for (armRemapPause::entry_t::const_iterator it = obj.entries.begin();
395        it != obj.entries.end();
396        it++)
397     {
398       op << make_attribute(it->second.first) << ",";    // start address
399       op << make_attribute(it->second.second) << ",";   // end address
400       
401       host_int_4 start_addr = it->second.first;
402       armRemapPause::translation_t::const_iterator it = obj.translations.find(start_addr);
403       assert(it != obj.translations.end());
404       op << it->second << " ";                          // relocated address
405     }
406   return op;
407 }
408   
409 istream& operator>> (istream& ip, armRemapPause& obj)
410 {
411   string word;
412
413   // Temporary versions of all state variables.
414   // None of these are commited unless the entire state is known to be
415   // good.
416   bool temp_remapping_p;
417   unsigned temp_num_relocs = 0;
418
419   ip >> word;
420
421   if (word != "remapping")
422     {
423       ip.setstate(ios::badbit);
424       return ip;
425     }
426   ip >> temp_remapping_p;
427   if (!ip.good())
428     return ip;
429
430   ip >> word;
431   if (word != "num-relocs")
432     {
433       ip.setstate(ios::badbit);
434       return ip;
435     }
436   ip >> temp_num_relocs;
437   if (!ip.good())
438     return ip;
439
440   ip >> word;
441   if (word != "relocs")
442     {
443       ip.setstate(ios::badbit);
444       return ip;
445     }
446
447   armRemapPause::entry_t temp_entries;
448   armRemapPause::translation_t temp_translations;
449
450   unsigned i = 0;
451   while (ip >> word)
452     {
453       vector<string> v = tokenize(word, ",");
454       if (v.size() != 3) {
455         ip.setstate(ios::badbit);
456         return ip;
457       }
458       host_int_4 start_addr, end_addr, reloc_addr;
459       if ((parse_attribute(v[0], start_addr) != component::ok) ||
460           (parse_attribute(v[1], end_addr) != component::ok) ||
461           (parse_attribute(v[2], reloc_addr) != component::ok))
462         {
463           ip.setstate(ios::badbit);
464           return ip;
465         }
466
467       temp_entries[i].first = start_addr;
468       temp_entries[i].second = end_addr;
469       temp_translations[start_addr] = reloc_addr;
470
471       i++;
472     }
473
474   if (i != temp_num_relocs)
475     {
476       ip.setstate(ios::badbit);
477       return ip;
478     }
479
480   // If we got here, commit the new state--the data looks okay.
481   obj.remapping_p = temp_remapping_p;
482   obj.translations = temp_translations;
483   obj.entries = temp_entries;
484   obj.num_relocations = temp_num_relocs;
485
486   return ip;
487 }
488
489 string
490 armRemapPause::get_start(host_int_4 entryNum)
491 {
492   return make_attribute(entries[entryNum].first);
493 }
494
495
496 component::status
497 armRemapPause::set_start(host_int_4 entryNum, const string& s)
498 {
499   host_int_4 newBase;
500
501   component::status st = parse_attribute(s, newBase);
502   if (st != component::ok)
503     return st;
504
505   entries[entryNum].first = newBase;
506
507   // Translate from x => x in anticipation that the user never
508   // provides the relocation address via the N-reloc-to attribute.
509   // This allows us to safely make an necessary entry now, and we can
510   // update it once the relocation address is provided.
511   translations[newBase] = newBase;
512
513   return component::ok;
514 }
515
516
517 string
518 armRemapPause::get_end(host_int_4 entryNum)
519 {
520   return make_attribute(entries[entryNum].second);
521 }
522
523
524 component::status
525 armRemapPause::set_end(host_int_4 entryNum, const string& s)
526 {
527   host_int_4 address;
528
529   component::status st = parse_attribute(s, address);
530   if (st != component::ok)
531     return st;
532
533   entries[entryNum].second = address;
534
535   // Having an address for the end of a region allows us to make a new
536   // entry in the translation map that will return to mapping x => x.
537   // This mapping must take effect from end+1.
538   address++;
539   translations[address] = address;
540
541   return component::ok;
542 }
543
544
545 string
546 armRemapPause::get_reloc(host_int_4 entryNum)
547 {
548   return make_attribute(translations[entries[entryNum].first]);
549 }
550
551
552 component::status
553 armRemapPause::set_reloc(host_int_4 entryNum, const string& s)
554 {
555   host_int_4 newReloc;
556
557   component::status st = parse_attribute(s, newReloc);
558   if (st != component::ok)
559     return st;
560
561   translations[entries[entryNum].first] = newReloc;
562   return component::ok;
563 }
564
565
566 string
567 armRemapPause::get_num_relocations()
568 {
569   return make_attribute(num_relocations);
570 }
571
572
573 component::status
574 armRemapPause::set_num_relocations(const string& s)
575 {
576   if (num_relocations > 0)
577     return component::bad_value;
578
579   // NB: type should match that of armRemapPause::num_relocations
580   host_int_1 new_num; 
581
582   component::status st = parse_attribute(s, new_num);
583   if (st == component::ok)
584     {
585       for (unsigned i = num_relocations; i < new_num; i++)
586         {
587           // Create new attributes as necessary.
588           string prefix = make_attribute(i);
589           
590           attribute_coder_base* coder =
591             new attribute_coder_virtual_parameterized
592             <armRemapPause,host_int_4> (this,
593                                         &armRemapPause::get_start,
594                                         &armRemapPause::set_start,
595                                         i);
596           add_attribute_coder(string(prefix + "-start"),
597                               coder, "setting");
598           
599           coder =
600             new attribute_coder_virtual_parameterized
601             <armRemapPause,host_int_4> (this,
602                                         &armRemapPause::get_reloc,
603                                         &armRemapPause::set_reloc,
604                                         i);
605           add_attribute_coder(prefix + "-reloc-to", coder, "setting");
606           
607           coder =
608             new attribute_coder_virtual_parameterized
609             <armRemapPause,host_int_4> (this,
610                                         &armRemapPause::get_end,
611                                         &armRemapPause::set_end,
612                                         i);
613           add_attribute_coder(prefix + "-end", coder, "setting");
614         }
615       num_relocations = new_num;
616     }
617   return st;
618 }
619
620
621 void
622 armRemapPause::reset(host_int_4 value)
623 {
624   if (value > 0)
625     resetStatus |= 1;
626 }
627
628
629 void
630 armRemapPause::remap_bus::bus_update()
631 {
632   bus = (target->remapping_p) ? 
633     static_cast<map_bus*>(& reset_map) : 
634     & normal_map;
635
636   // Trigger checkpoint.
637   target->triggerpoint_manager.check_and_dispatch();
638 }
639
640
641 void
642 armRemapPause::remap_bus::use_normal_map()
643 {
644   target->remapping_p = false;
645   bus = &normal_map;
646
647   // Trigger checkpoint.
648   target->triggerpoint_manager.check_and_dispatch();
649 }
650
651 bus::status
652 armRemapPause::bus_interface::word_write(host_int_4 addr,
653                                          little_int_4 mask,
654                                          little_int_4 le_data) 
655 {
656   host_int_4 data = le_data;
657   switch (addr)
658     {
659     case 0:
660       // Pause.
661       target->halt.drive(1);
662       break;
663     case 4:
664       // Reserved.
665       break;
666     case 8:
667       // Switch from reset map to normal map.
668       target->upstream_bus.use_normal_map();
669       break;
670     case 12:
671       // Reset status set.
672       // Ignore for a minimal implementation.
673       break;
674     case 13:
675       // Reset status clear.
676       target->resetStatus &= ~data;
677       break;
678     }
679   return bus::ok;
680 }
681
682 bus::status
683 armRemapPause::bus_interface::word_read(host_int_4 addr,
684                                         little_int_4 mask,
685                                         little_int_4& data)
686 {
687   switch (addr) {
688   case 0:
689     // Reserved.
690     break;
691   case 4:
692     // Identification; just ensure bit 0 is cleared to say that we
693     // don't have any further identification to offer.
694     data = 0;
695     break;
696   case 8:
697     // Reserved.
698     break;
699   case 12:
700     // Reset status.
701     data = target->resetStatus;
702     break;
703   case 13:
704     // Reserved.
705     break;
706   }
707   return bus::ok;
708 }
709
710 #endif // SIDTARGET_ARM
711
712
713 extern const component_library mmu_component_library;
714
715 static vector<string>
716 compMmuListTypes()
717 {
718   vector<string> types;
719 #if SIDTARGET_ARM
720   types.push_back("hw-remap/pause-arm/ref");
721 #endif
722   return types;
723 }
724
725 static component*
726 compMmuCreate(const string& typeName)
727 {
728 #if SIDTARGET_ARM
729   if (typeName == "hw-remap/pause-arm/ref")
730     return new armRemapPause();
731 #endif
732   return 0;
733 }
734
735 static void
736 compMmuDelete(component* c)
737 {
738 #if SIDTARGET_ARM
739   delete dynamic_cast<armRemapPause*>(c);
740 #endif
741 }
742
743
744 const component_library mmu_component_library DLLEXPORT =
745 {
746   COMPONENT_LIBRARY_MAGIC,
747   &compMmuListTypes,
748   &compMmuCreate,
749   &compMmuDelete
750 };