1 // armRemap.cxx - An implementation of the "remap and pause"
2 // controller from the ARM PID7T development board. -*- C++ -*-
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.
8 // A more thorough description of this component may be found at
9 // <http://www.arm.com/Documentation/UserMans/rps/#rp>.
16 #include <sidcomputil.h>
17 #include <sidattrutil.h>
18 #include <sidmiscutil.h>
19 #include <sidpinutil.h>
20 #include <sidbusutil.h>
22 #include <sidwatchutil.h>
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;
44 using sid::component_library;
45 using sid::COMPONENT_LIBRARY_MAGIC;
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;
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
79 class map_bus: public bus
82 map_bus(armRemapPause* target) :target(target) {}
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;
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);
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);
111 armRemapPause* target;
114 class reset_map_bus: public map_bus
117 reset_map_bus(armRemapPause* target): map_bus(target) {}
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);\
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); \
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);
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);
155 host_int_4 translate(host_int_4 address)
157 if (target->translations.empty())
160 armRemapPause::translation_t::iterator it =
161 target->translations.upper_bound(address);
163 if (it == target->translations.begin())
167 assert(address >= it->first);
168 return (address - it->first) + it->second;
172 class normal_map_bus: public map_bus
175 normal_map_bus(armRemapPause* target): map_bus(target) {}
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); }
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); }
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);
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);
210 class remap_bus: public bus
213 remap_bus(armRemapPause *target)
214 :target(target), reset_map(target), normal_map(target),
217 // Based on the setting of the remapping_p variable, switch the
218 // bus object used to do downstream memory transactions.
221 // Unconditional switch to the normal map.
222 void use_normal_map();
224 #define BUS_WRITE(type1, type2) \
225 bus::status write(type1 address, type2 data) throw () \
226 { return bus->write(address, data); }
228 #define BUS_READ(type1, type2) \
229 bus::status read(type1 address, type2& data) throw () \
230 { return bus->read(address, data); }
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);
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);
254 armRemapPause* target;
257 reset_map_bus reset_map;
258 normal_map_bus normal_map;
263 class bus_interface: public word_bus<little_int_4>
266 bus_interface(armRemapPause* target): target(target) {}
268 bus::status word_write(host_int_4 addr,
272 bus::status word_read(host_int_4 addr,
277 armRemapPause* target;
280 friend class bus_interface;
281 friend class remap_bus;
282 friend class reset_map_bus;
283 friend class normal_map_bus;
286 remap_bus upstream_bus;
288 void reset(host_int_4 value);
289 host_int_4 resetStatus;
291 // The controller's programmable registers.
292 bus_interface registers;
294 // Are we currently applying the translation map?
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;
301 // The translation map, containing entries of address ranges and
302 // their corresponding relocations.
303 translation_t translations;
305 // An orthogonal map to keep necessary state about known
309 host_int_1 num_relocations;
310 string get_num_relocations();
311 component::status set_num_relocations(const string& s);
313 string get_start(host_int_4 entryNum);
314 component::status set_start(host_int_4 entryNum, const string& s);
316 string get_end(host_int_4 entryNum);
317 component::status set_end(host_int_4 entryNum, const string& s);
319 string get_reloc(host_int_4 entryNum);
320 component::status set_reloc(host_int_4 entryNum, const string& s);
322 callback_pin<armRemapPause> resetPin;
323 friend class callback_pin<armRemapPause>;
327 // State save/restore support.
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);
333 // Triggerpoint support.
334 friend class self_watcher<armRemapPause>;
335 self_watcher<armRemapPause> triggerpoint_manager;
337 sid::component::status
338 pin_factory(const string& name)
340 return this->triggerpoint_manager.create_virtual_pin(name);
344 pin_junkyard(const string& name)
346 return this->triggerpoint_manager.destroy_virtual_pin(name);
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)
357 add_accessor("all", &downstream_bus);
358 add_attribute_notify("remapping?", &remapping_p, &upstream_bus,
359 &armRemapPause::remap_bus::bus_update,
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", ®isters);
369 add_pin("reset", &resetPin);
370 add_pin("halt!", &halt);
372 triggerpoint_manager.add_watchable_attribute("remapping?");
373 categorize("remapping?", "watchable");
377 armRemapPause::save_state()
379 return make_attribute(*this);
382 sid::component::status
383 armRemapPause::restore_state(const string& state)
385 return parse_attribute(state, *this);
388 ostream& operator<< (ostream& op, const armRemapPause& obj)
390 op << "remapping " << obj.remapping_p
391 << " num-relocs " << static_cast<unsigned int> (obj.num_relocations)
394 for (armRemapPause::entry_t::const_iterator it = obj.entries.begin();
395 it != obj.entries.end();
398 op << make_attribute(it->second.first) << ","; // start address
399 op << make_attribute(it->second.second) << ","; // end address
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
409 istream& operator>> (istream& ip, armRemapPause& obj)
413 // Temporary versions of all state variables.
414 // None of these are commited unless the entire state is known to be
416 bool temp_remapping_p;
417 unsigned temp_num_relocs = 0;
421 if (word != "remapping")
423 ip.setstate(ios::badbit);
426 ip >> temp_remapping_p;
431 if (word != "num-relocs")
433 ip.setstate(ios::badbit);
436 ip >> temp_num_relocs;
441 if (word != "relocs")
443 ip.setstate(ios::badbit);
447 armRemapPause::entry_t temp_entries;
448 armRemapPause::translation_t temp_translations;
453 vector<string> v = tokenize(word, ",");
455 ip.setstate(ios::badbit);
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))
463 ip.setstate(ios::badbit);
467 temp_entries[i].first = start_addr;
468 temp_entries[i].second = end_addr;
469 temp_translations[start_addr] = reloc_addr;
474 if (i != temp_num_relocs)
476 ip.setstate(ios::badbit);
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;
490 armRemapPause::get_start(host_int_4 entryNum)
492 return make_attribute(entries[entryNum].first);
497 armRemapPause::set_start(host_int_4 entryNum, const string& s)
501 component::status st = parse_attribute(s, newBase);
502 if (st != component::ok)
505 entries[entryNum].first = newBase;
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;
513 return component::ok;
518 armRemapPause::get_end(host_int_4 entryNum)
520 return make_attribute(entries[entryNum].second);
525 armRemapPause::set_end(host_int_4 entryNum, const string& s)
529 component::status st = parse_attribute(s, address);
530 if (st != component::ok)
533 entries[entryNum].second = address;
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.
539 translations[address] = address;
541 return component::ok;
546 armRemapPause::get_reloc(host_int_4 entryNum)
548 return make_attribute(translations[entries[entryNum].first]);
553 armRemapPause::set_reloc(host_int_4 entryNum, const string& s)
557 component::status st = parse_attribute(s, newReloc);
558 if (st != component::ok)
561 translations[entries[entryNum].first] = newReloc;
562 return component::ok;
567 armRemapPause::get_num_relocations()
569 return make_attribute(num_relocations);
574 armRemapPause::set_num_relocations(const string& s)
576 if (num_relocations > 0)
577 return component::bad_value;
579 // NB: type should match that of armRemapPause::num_relocations
582 component::status st = parse_attribute(s, new_num);
583 if (st == component::ok)
585 for (unsigned i = num_relocations; i < new_num; i++)
587 // Create new attributes as necessary.
588 string prefix = make_attribute(i);
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,
596 add_attribute_coder(string(prefix + "-start"),
600 new attribute_coder_virtual_parameterized
601 <armRemapPause,host_int_4> (this,
602 &armRemapPause::get_reloc,
603 &armRemapPause::set_reloc,
605 add_attribute_coder(prefix + "-reloc-to", coder, "setting");
608 new attribute_coder_virtual_parameterized
609 <armRemapPause,host_int_4> (this,
610 &armRemapPause::get_end,
611 &armRemapPause::set_end,
613 add_attribute_coder(prefix + "-end", coder, "setting");
615 num_relocations = new_num;
622 armRemapPause::reset(host_int_4 value)
630 armRemapPause::remap_bus::bus_update()
632 bus = (target->remapping_p) ?
633 static_cast<map_bus*>(& reset_map) :
636 // Trigger checkpoint.
637 target->triggerpoint_manager.check_and_dispatch();
642 armRemapPause::remap_bus::use_normal_map()
644 target->remapping_p = false;
647 // Trigger checkpoint.
648 target->triggerpoint_manager.check_and_dispatch();
652 armRemapPause::bus_interface::word_write(host_int_4 addr,
654 little_int_4 le_data)
656 host_int_4 data = le_data;
661 target->halt.drive(1);
667 // Switch from reset map to normal map.
668 target->upstream_bus.use_normal_map();
672 // Ignore for a minimal implementation.
675 // Reset status clear.
676 target->resetStatus &= ~data;
683 armRemapPause::bus_interface::word_read(host_int_4 addr,
692 // Identification; just ensure bit 0 is cleared to say that we
693 // don't have any further identification to offer.
701 data = target->resetStatus;
710 #endif // SIDTARGET_ARM
713 extern const component_library mmu_component_library;
715 static vector<string>
718 vector<string> types;
720 types.push_back("hw-remap/pause-arm/ref");
726 compMmuCreate(const string& typeName)
729 if (typeName == "hw-remap/pause-arm/ref")
730 return new armRemapPause();
736 compMmuDelete(component* c)
739 delete dynamic_cast<armRemapPause*>(c);
744 const component_library mmu_component_library DLLEXPORT =
746 COMPONENT_LIBRARY_MAGIC,