Resource information accessible to the user covers only resource references: the user cannot change the properties of the hardware resource itself; only resource references made by instructions and represented in reservation tables can be accessed and modified.
The accesses to resources attached to operands can be modified using the operand abstraction. However, to modify resources which do not appear explicitly in the assembly code, it is necessary to manipulate the contents of reservation tables.
In the following, we present the current state of the resource interface, which is undergoing deep restructuring aiming at a more systematic and orthogonal organization.
Resource descriptions in SALTO are maintained as a global resource database, searchable by resource names and ID numbers. Each resource has a unique ID number, a type, a name, and at most two aliases. The global resource database provides translations from resource names to IDs and database entries.
Resource type can be any of UNKNOWN_RTYPE, REGISTER_RTYPE, FUNCT_UNIT_RTYPE, or MEMORY_RTYPE.
Resource descriptions are implemented through the class rdb_res_entry providing the following methods:
To access the contents of the global resource database, it must first be extracted from SALTO's database server by the following statement:
Once the resource database is extracted, individual resource entries can be searched by name and by resource ID numbers:
Resource references contain information on resource accesses made during the execution of an instruction. A resource reference represents exactly one resource access: if the same resource is accessed several times during the execution of an instruction, each access will be represented by a separate resource reference object.
Resource references are implemented in class res_ref, further specialized into res_ref_id (basic resource references) and multi_ref (multi-register references). The methods available to the user are:
A reservation table entry indicates the nature and the schedule of a resource access: the information it contains specifies what operation is performed on the resource (read, write, use) and when (first and last cycle of the access). Resources which are accessed several times when executing an instruction give raise to as many reservation table entries as there are distinct accesses being made to the resource.
A reservation table entry provides the following functionalities:
Reservation tables are use to represent resource accesses within a common time frame, allowing to check for resource access conflicts over that time frame. A reservation table is attached to each assembly instruction, but the user can also set up reservation tables spanning several instructions. Reservation tables are used in instruction scheduling to ensure the feasibility of a given instruction schedule.
Reservation tables are implemented in the class reserv_table1 as lists of reservation table entries and can be manipulated using the following methods of that class:
To illustrate the operation of the current resource interface, let us have a closer look at two short examples: low-level dependence checking, and counting of accesses performed by an instruction.
The following is an excerpt from the implementation of class INST. The
method
INST::isRAW(INST *source) is used internally to check
if the current instruction may depend on instruction source.
For read access made by the current instruction (this), the
method searches for a write access to the same resource performed in the
instruction supplied as argument.
/*
* Does instruction -this- have a RAW hazard with -ii- ?
* We check if -this- reads a resource written by -ii-.
*/
bool
INST::isRAW(INST *ii, bool ignoreMem)
{
int i, j, rRid, rWid;
int nOfInput, nOfOutput;
res_ref *rread, *rwrite;
nOfInput = numberOfInput();
for(i=0; i < nOfInput; i++) {
rread = getInput(i); // current insn reads rread
// if 'rread' is a memory reference and we ignore the mem, let's
// just skip it
if (ignoreMem
&&
(rdb . get_res(rread -> get_res_id()) -> getType() == MEMORY_RTYPE))
continue;
rRid = rread -> get_res_id();
nOfOutput = ii -> numberOfOutput();
for(j=0; j < nOfOutput; j++) { // is it written in instruction 'ii'?
rwrite = ii -> getOutput(j);
rWid = rwrite -> get_res_id();
if (rWid == rRid)
return true; // if so, there's indeed a RAW hazard between 'ii' and 'this'
}
}
return false;
}
The code below is again taken from the implementation of class INST.
The method
INST::numberOfx(...) implements the counting of resource
accesses made by an instruction in the access mode specified as argument.
/*
* Return the number of resources read, written, and used by the
* instruction. The same resource will be counted as many times as it is
* accessed by the instruction.
*/
int
INST::numberOfx(enum access_mode acces)
{
reserv_table1 *reserv;
reserv_entry *entry;
int i, k;
if (!isAsm()) {
saltoWarn("*** INST::numberOfx(): insn %#lx is not an ASM operation!\n",
(unsigned long) this);
return -1;
}
k = 0;
reserv = ((xAsm *)this) -> get_reser();
for(i = 0; i < reserv -> get_size(); i++) {
entry = reserv -> get_entry(i);
if (entry -> get_access_mode() == acces) k++;
}
return k;
}