// compMapper.cxx - a bus mapper component. -*- C++ -*-
-// Copyright (C) 1999-2001 Red Hat.
+// Copyright (C) 1999-2002 Red Hat.
// This file is part of SID and is licensed under the GPL.
// See the file COPYING.SID for conditions for redistribution.
using sidutil::make_numeric_attribute;
using sidutil::parse_attribute;
using sidutil::tokenize;
+using sidutil::callback_pin;
using sidutil::attribute_coder_virtual_parameterized;
host_int_2 width_shift; // log2(width)
string spec; // user-given specification string
+
+ vector<host_int_4> banks; // sorted list of bank #s in which this record is active
};
bool
overlaps_p (const mapping_record& a, const mapping_record& b)
{
+ // Reject disjoint banks
+ vector<host_int_4> intersection (a.banks.size());
+ vector<host_int_4>::iterator r =
+ set_intersection (a.banks.begin(), a.banks.end(),
+ b.banks.begin(), b.banks.end(),
+ intersection.begin());
+ if (r == intersection.begin()) // empty intersection?
+ return false;
+
// I always rederive this little formula from first principles.
host_int_4 max_first = max(a.low, b.low);
host_int_4 min_last = min(a.high, b.high);
}
-class mr_cmp: public std::binary_function<mapping_record, mapping_record, bool>
+bool
+selected_p (const mapping_record& a, host_int_4 bank)
+{
+#if 0
+ // This doesn't have to be fast, but since banks<> is kept sorted, might as well
+ // use binary search.
+
+ vector<host_int_4>::const_iterator where =
+ lower_bound (a.banks.begin (), a.banks.end (), bank);
+
+ return (where != a.banks.end ());
+#endif
+
+ for (int i=0; i<a.banks.size(); i++)
+ {
+ if (a.banks[i] == bank) return true;
+ }
+ return false;
+}
+
+
+
+class mr_value_cmp: public std::binary_function<mapping_record, mapping_record, bool>
{
public:
bool operator () (const mapping_record& a, const mapping_record& b) const
{
return (a.low < b.low);
}
+};
+
+class mr_ptr_cmp: public std::binary_function<mapping_record*, mapping_record*, bool>
+{
+public:
+ bool operator () (const mapping_record* a, const mapping_record* b) const
+ {
+ return (a->low < b->low);
+ }
- bool operator () (const mapping_record& a, host_int_4 addr) const
+ bool operator () (const mapping_record* a, host_int_4 addr) const
{
- return (a.high < addr);
+ return (a->high < addr);
}
- bool operator () (host_int_4 addr, const mapping_record& b) const
+ bool operator () (host_int_4 addr, const mapping_record* b) const
{
- return (addr < b.low);
+ return (addr < b->low);
}
};
public:
generic_mapper_bus (generic_mapper* target, bool transparent_p): target (target)
{
- this->tlb1 = 0;
- this->tlb2 = 0;
+ this->tlb1 = this->tlb2 = 0;
this->low_multiplier = (transparent_p ? 0 : 1);
}
mutable struct mapping_record* tlb1;
mutable struct mapping_record* tlb2;
unsigned low_multiplier;
+
+public:
+ void clear_tlb () { tlb1 = tlb2 = 0; }
};
generic_mapper_bus::~generic_mapper_bus () throw () {
protected:
friend class generic_mapper_bus;
- vector<mapping_record> accessors;
+ vector<mapping_record> accessors; // All records
generic_mapper_bus my_bus;
+ // banking
+ vector<mapping_record*> selected_accessors; // All records in current bank
+ host_int_4 bank;
+ callback_pin<generic_mapper> bank_pin;
+ void bank_pin_handler (host_int_4);
+ void bank_changed ();
+
// stats
host_int_4 access_count;
host_int_4 cache_hit_count;
generic_mapper::generic_mapper (bool transparent_p)
:my_bus (this, transparent_p),
+ bank (0),
+ bank_pin (this, & generic_mapper::bank_pin_handler),
latency (0)
{
add_bus ("access-port", &this->my_bus);
add_attribute_virtual ("state-snapshot", this,
& generic_mapper::save_state,
& generic_mapper::restore_state);
-
- add_attribute ("latency", &latency, "setting");
+
+ add_attribute ("latency", & this->latency, "setting");
+ add_attribute_notify ("bank", & this->bank,
+ this, & generic_mapper::bank_changed,
+ "register");
+ add_pin ("bank", & this->bank_pin);
this->access_count = 0;
add_attribute ("access-count", & this->access_count, "register");
}
+
+void
+generic_mapper::bank_pin_handler (host_int_4 new_bank)
+{
+ this->bank = new_bank;
+ this->bank_changed ();
+}
+
+
+// Regenerate the selected-accessors sorted vector after the bank number
+// or overall accessor list have changed.
+void
+generic_mapper::bank_changed ()
+{
+ this->selected_accessors.clear ();
+
+ for (vector<mapping_record>::iterator it = this->accessors.begin();
+ it != this->accessors.end();
+ it++)
+ {
+ if (selected_p (*it, this->bank))
+ {
+ // cout << "mapper bank " << this->bank << " sel: " << it->spec << endl;
+ this->selected_accessors.push_back (it);
+ }
+ }
+
+ sort (this->selected_accessors.begin(),
+ this->selected_accessors.end(),
+ mr_ptr_cmp ());
+
+ this->my_bus.clear_tlb ();
+}
+
+
vector<string>
generic_mapper::accessor_names () throw()
{
}
this->accessors.push_back (*r);
- sort(this->accessors.begin(),this->accessors.end(),mr_cmp());
+ // sort for aesthetic reasons
+ sort (this->accessors.begin(), this->accessors.end(), mr_value_cmp ());
+ this->bank_changed (); // recalculate selected_accessors
add_attribute_virtual_parameterized (name + "-hits",
name,
{
remove_attribute (name + "-hits");
this->accessors.erase (it);
- sort(this->accessors.begin(),this->accessors.end(),mr_cmp());
+ // sort for aesthetic reasons
+ sort (this->accessors.begin(), this->accessors.end(), mr_value_cmp ());
+ this->bank_changed (); // recalculate selected_accessors
return component::ok;
}
}
// Return 0 on parse or validity-checking error.
//
// Accept the following forms:
-// [LOW-HIGH] (4 tokens)
-// [LOW-HIGH,STRIDE,WIDTH] (6 tokens)
-// [BYTES_PER_WORD,LOW-HIGH] (5 tokens)
-// [BYTES_PER_WORD,LOW-HIGH,STRIDE,WIDTH] (7 tokens)
+//
+// GARBAGE1[SPEC]GARBAGE2
+//
+// where SPEC ::=
+// LOW-HIGH (2 tokens)
+// LOW-HIGH,STRIDE,WIDTH (3 tokens)
+// BYTES_PER_WORD*LOW-HIGH (4 tokens)
+// BYTES_PER_WORD*LOW-HIGH,STRIDE,WIDTH (5 tokens)
+//
+// and GARBAGE2 ::=
+// {BANKS}GARBAGE3
+// or GARBAGE3
+//
+// where BANKS ::= specifies mapping banks
+// BANK1,BANK2,BANK3,... (0- tokens)
//
// Each number may be specified in any format that parse_attribute()
// understands.
// Fill in this struct in stack; may return copy if all goes well
mapping_record record;
- vector<string> fields = tokenize (str, "[-,]");
+ vector<string> fields_outer = tokenize (str, "[]");
+ if (fields_outer.size() != 3)
+ {
+ cerr << "mapper error: parse error (missing [SPEC]) in " << str << endl;
+ return 0;
+ }
+
+ string garbage1 = fields_outer[0];
+ string spec = fields_outer[1];
+ string garbage2 = fields_outer[2];
- // Must have between 4 and 7 tokens (including empties
- // before/after "[" and "]")
- if (fields.size() < 4 || fields.size() > 7)
+ // Process bank numbers spec
+ vector<string> bankspec = tokenize (garbage2, "{}");
+
+ // cout << "suffix=" << garbage2 << endl;
+ // for (int j=0; j<bankspec.size(); j++)
+ // cout << "bank[" << j << "] = `" << bankspec[j] << "'" << endl;
+
+ if (bankspec.size() == 3)
{
- cerr << "mapper error: parse error (bad number of fields) in " << str << endl;
+ // Process each number
+ vector<string> banks = tokenize (bankspec[1], ",");
+ for (unsigned i=0; i<banks.size(); i++)
+ {
+ string bankstr = banks[i];
+ // accept & bypass empty strings
+ if (bankstr.length () == 0)
+ continue;
+
+ host_int_4 bank;
+ component::status stat = parse_attribute(bankstr, bank);
+ if (stat != component::ok)
+ {
+ cerr << "mapper error: parse error (bank#) in " << str << endl;
+ return 0;
+ }
+
+ record.banks.push_back (bank);
+ // cout << "added bank=" << bank << endl;
+ }
+ }
+ else if (bankspec.size() == 0) // no "{" nor "}" appears
+ {
+ // No bank number specification: default 0
+ record.banks.push_back (0);
+ // cout << "set bank=" << 0 << endl;
+ }
+ else
+ {
+ cerr << "mapper error: parse error (bad {bank} block) in " << str << endl;
+ return 0;
+ }
+
+ // XXX: equivocate */-/, separators
+ vector<string> fields = tokenize (spec, "*-,");
+
+ // Must have between 2 and 5 tokens (including empties
+ // before/after "[" and "]"
+ if (fields.size() < 2 || fields.size() > 5)
+ {
+ cerr << "mapper error: parse error (bad number of [SPEC] fields) in "
+ << str << endl;
return 0;
}
// strip the word width off the front of the descriptor array
record.bytes_per_word = 1;
- if (fields.size() == 5 || fields.size() == 7)
+ if (fields.size() == 3 || fields.size() == 5)
{
- component::status stat = parse_attribute(fields [fields.size () - 2], record.bytes_per_word);
+ component::status stat = parse_attribute(fields [0], record.bytes_per_word);
if (stat != component::ok)
{
cerr << "mapper error: parse error (bytes_per_word) in " << str << endl;
return 0;
}
- fields.pop_back ();
+ fields.erase (fields.begin ());
}
+
+ assert (fields.size() == 2 || fields.size() == 4);
- record.use_strideoffset_p = (fields.size() == 6);
+ record.use_strideoffset_p = (fields.size() == 4);
record.spec = str;
record.hit_count = 0;
// parse two or four fields
- component::status s1 = parse_attribute(fields[1], record.low);
- component::status s2 = parse_attribute(fields[2], record.high);
+ component::status s1 = parse_attribute(fields[0], record.low);
+ component::status s2 = parse_attribute(fields[1], record.high);
if (s1 != component::ok || s2 != component::ok)
{
cerr << "mapper error: parse error (low-high) in " << str << endl;
}
if (record.use_strideoffset_p)
{
- component::status s3 = parse_attribute(fields[3], record.stride);
- component::status s4 = parse_attribute(fields[4], record.width);
+ component::status s3 = parse_attribute(fields[2], record.stride);
+ component::status s4 = parse_attribute(fields[3], record.width);
if (s3 != component::ok || s4 != component::ok)
{
cerr << "mapper error: parse error (stride,width) in " << str << endl;
}
// binary search in one statement!
- vector<mapping_record>::iterator where =
- lower_bound (this->target->accessors.begin (),
- this->target->accessors.end (),
- address,
- mr_cmp ());
-
- // XXX: other optimizations
+ vector<mapping_record*>::iterator where =
+ lower_bound (this->target->selected_accessors.begin (),
+ this->target->selected_accessors.end (),
+ address,
+ mr_ptr_cmp ());
- while (where != this->target->accessors.end ())
+ while (where != this->target->selected_accessors.end ())
{
- mapping_record* found = & * where;
+ mapping_record* found = *where;
// cout << " [found: " << found.first << "-" << found.last << "]" << endl;
// Incoming address is smaller than the first map entry?
This component distributes bus accesses to one of a number of configured
bus accessors, depending on the address of the incoming memory access.
- A mapper defines an address space. The address space is decomposed into
- non-overlapping regions by configuring a dynamic collection of accessors.
- Each accessor is connected to a single slave bus. To configure the address
- mapping, you must name each accessor according to one of these forms:
+ A mapper defines a group of address spaces. Each group is known as a bank.
+ Each address space is decomposed into non-overlapping regions by
+ configuring a dynamic collection of accessors. Each accessor is connected
+ to a single slave bus. To configure the address mapping, you must name
+ each accessor according to one of these forms:
* [<low>-<high>]
- * [<low>-<high>,<wordsize>]
+ * [<wordsize>*<low>-<high>]
* [<low>-<high>,<stride>,<width>]
- * [<low>-<high>,<stride>,<width>,<wordsize>]
+ * [<wordsize>*<low>-<high>,<stride>,<width>]
where:
* <low> is the starting address for the mapped region.
* <high> is the ending address for the mapped region.
multiplier you can use to permit specifying <low>, <high>, <stride>
and <width> in terms of multi-byte words.
- In addition, any text may appear outside the "[" and "]" brackets, as long
- as that text does not include any of the separator characters "[" "]" "-"
- ",".
+ To the right of the "]" closing bracket, an optional specification block
+ may list the numbers of mapping banks for this record. This block is
+ formatted as a comma-separated list of numbers, given between "{" and "}"
+ brackets. The default is to reside in bank 0 only.
+
+ In addition, any text may appear to the left of the "[" and "]" brackets,
+ as long as that text does not include any of the characters "[" "]".
+ Likewise, text may appear to the right, but it must exclude the "[", "]",
+ "{", and "}" bracket characters.
Each number may be specified in decimal, hexadecimal, octal, and binary
forms, with the appropriate prefix (none, "0x", "0", "0b", respectively).
| | entry, or inconsistent ranges |
| | or stride/width values. |
|----------------+--------------------------------|
+ | banking | When the bank attribute is set |
+ | | with a numeric value, or the |
+ | | bank pin is driven with a |
+ | | number, the mapping group or |
+ | | bank number is instantly |
+ | | changed. Subsequent mapping |
+ | | activities will see only those |
+ | | mapping entries that include |
+ | | the new bank number. |
+ |----------------+--------------------------------|
| mapping | When an incoming access on the |
| | access-port bus is received, |
| | its base address is compared |
| | to all the registered outgoing |
- | | accessors. If one is found |
- | | that contains the address, the |
- | | current address is transformed |
+ | | accessors in the current bank. |
+ | | If one is found that contains |
+ | | the address, the current |
+ | | address is transformed |
| | according to the following |
| | rules: |
| | * The accessor's <low> |
This component distributes bus accesses to one of a number of
configured bus accessors, depending on the address of the
incoming memory access.</p>
+
<p>
- A mapper defines an address space. The address space is
- decomposed into non-overlapping regions by configuring a dynamic
- collection of accessors. Each accessor is connected to a single
- slave bus. To configure the address mapping, you must name each
- accessor according to one of these forms:
+ A mapper defines a group of address spaces. Each group is
+ known as a <b>bank</b>. Each address space is decomposed
+ into non-overlapping regions by configuring a dynamic
+ collection of accessors. Each accessor is connected to a
+ single slave bus. To configure the address mapping, you
+ must name each accessor according to one of these forms:
<ul>
<li><tt>[<low>-<high>]</tt></li>
- <li><tt>[<low>-<high>,<wordsize>]</tt></li>
+ <li><tt>[<wordsize>*<low>-<high>]</tt></li>
<li><tt>[<low>-<high>,<stride>,<width>]</tt></li>
- <li><tt>[<low>-<high>,<stride>,<width>,<wordsize>]</tt></li>
+ <li><tt>[<wordsize>*<low>-<high>,<stride>,<width>]</tt></li>
</ul>
where:
</p>
<p>
- In addition, any text may appear outside the "[" and "]" brackets,
- as long as that text does not include any of the separator
- characters "[" "]" "-" ",".</p>
+ To the right of the "]" closing bracket, an optional specification block
+ may list the numbers of mapping banks for this record. This block is
+ formatted as a comma-separated list of numbers, given between "{" and "}"
+ brackets. The default is to reside in bank 0 only.</p>
+
+ <p>
+ In addition, any text may appear to the left of the "[" and
+ "]" brackets, as long as that text does not include any of
+ the characters "[" "]". Likewise, text may appear to the
+ right, but it must exclude the "[", "]", "{", and "}"
+ bracket characters.</p>
<p>
Each number may be specified in decimal, hexadecimal, octal, and
an existing entry, or inconsistent ranges or stride/width
values.</p></p>
</behavior>
+ <behavior name="banking">
+ <p>
+ <p>
+ When the <attribute>bank</attribute> attribute is set with a
+ numeric value, or the <pin>bank</pin> pin is driven with a
+ number, the mapping group or bank number is instantly
+ changed. Subsequent mapping activities will see only those
+ mapping entries that include the new bank number.
+ </p>
+ </p>
+ </behavior>
<behavior name="mapping">
<p>
<p>
When an incoming access on the <bus>access-port</bus> bus is
received, its base address is compared to all the registered
- outgoing accessors. If one is found that contains the
- address, the current address is transformed according to the
- following rules:
+ outgoing accessors in the current bank. If one is found
+ that contains the address, the current address is
+ transformed according to the following rules:
<ul>
<li>