This class is a SystemC module (i.e. it has
sc_module
as a base class).
The Debug Unit functions work by queuing instances of
TapAction
sub-classes on a queue (FIFO)
connected to the JTAG interface (class
JtagSC
). This allows the debug unit to read
and write the various JTAG registers. In each case the debug unit
waits (using the SystemC wait
function) for
notification that the action is complete before proceeding. The full
interface is described in Embecosm Application Note 5
Using JTAG with SystemC: Implementation of a Cycle
Accurate Interface [9].
The Debug Unit caches the current value of the debug chain. This means it can avoid selecting the chain for a debug action, where it is unchanged from the previous action.
The public interface to DebugUnitSC
is as
follows:
DebugUnitSC
. Constructor, which takes as
argument a pointer to the TAP action queue of the target
processor's JTAG interface.
The constructor instantiates the SPR and memory caches and marks the current stall state of the target as unknown and the current debug chain as undefined.
~DebugUnitSC
. The destructor, which deletes
the SPR and memory caches.
resetDebugUnit
. This function is called to
reset the JTAG interface (rather than the CPU). It achieves
this by queuing a TapActionReset
instance on the JTAG queue.
reset
. This function resets the CPU. This is
achieved by selecting the REGISTER
debug
chain and writing bit 1 of the RISCOP
CPU
control register.
stall
and unstall
. These
stall and unstall the processor by selecting the
REGISTER
debug chain and respectively setting
and clearing bit 0 of the RISCOP
CPU control
register. As a matter of good practice the current value of the
register is read, the relevant bit changed and the value written
back. This ensures any other bits are unchanged.
In practice the only other bit that has any effect in the current implementation is bit-1 (the reset bit), which should always be clear in this circumstance. However using this approach ensures robustness of the code in the event of new control bits being added in future debug units. If performance was particularly critical, this function could be optimized by not reading the current value of the register.
isStalled
. Return true
if
the processor is currently stalled and false
otherwise.
The Debug Unit maintains a private enumeration variable
(stallState
) tracking the stall state of the
processor. It is set to STALLED
whenever the
processor is explicitly stalled (by using the
stall
function) or is discovered to be
stalled. It is set to UNKNOWN
whenever the
processor is explicitly unstalled, or found to be unstalled.
Note | |
---|---|
A processor which is running (i.e. UNSTALLED) can at any time
stall, for example due to hitting a breakpoint. Hence the only
two useful values are |
If the StallState
shows the processor is
currently stalled, the function immediately returns
TRUE. Otherwise it selects the REGISTER
debug
chain and reads bit 0 of the RISCOP
CPU
control register. It then sets StallState
to
STALLED
if the bit is set and
UNKNOWN
if it is clear and returns
true
if the state is stalled and
false
otherwise.
readSpr
and
writeSpr
. These functions respectively read
and write a SPR by selecting the RISC_DEBUG
debug chain and shifting a data register with the SPR, W and
Data fields set appropriately.
This access can be optimized by use of the SPR cache. This is described in Section 5.2.
Almost all SPRs are readable. However the Next Program Counter (NPC) SPR has some unexpected behavior due to the operation of the processor pipeline, which must be managed. This is described in Section 4.6.1.
andSpr
and orSpr
. Most
SPR accesses involve reading a SPR using AND and OR
operations to clear or set a bit and then writing the value
back. These functions are provided as a convenience for such
operations. They just call the main readSpr
and writeSpr
functions.
readMem32
and
writeMem32
. These functions respectively
read and write a 32-bit value from memory attached to the
Wishbone bus of the OpenRISC 1000. The WISHBONE
debug chain is selected, and the value read or written by
shifting a data register with the Address, W and Data fields set
appropriately.
In the case of readMem32
the memory access
is usually not fast enough to populate the data out field in
time. The solution is either to use the JTAG
PAUSE-DR
state after bit 32 has been shifted,
or to perform the read twice. The Embecosm Cycle Accurate
SystemC JTAG interface currently has no support for
mid-transfer use of PAUSE-DR
, so in this
implementation reads are performed twice.
Note | |
---|---|
The GDB client will work with target endianness for any data it accesses, so there is no need to make any transformation of data being transferred. |
Caution | |
---|---|
Using GDB to read or write memory mapped device registers can be unreliable, particularly if reading has side effects (due to reads being performed twice). It is best avoided. |
readMem8
and
writeMem8
. These functions respectively
read and write a single byte from memory attached to the
Wishbone bus of the OpenRISC 1000.
Since the Debug Unit only provides for 32-bit read and write,
the operation is achieved by using 32-bit access (using
readMem32
and
writeMem32
) and selecting the relevant
byte. In the case of writing this requires reading the original
32-bit value, patching the relevant byte and writing back the
32-bit value.
Since the byte access will use host-endian arithmetic, the value
read must be converted from model endianness and any value
written must be converted back to model endianness. The
Utils
class provides suitable static
functions to do this in Utils::mtohl
and
Utils::htoml
.
Note | |
---|---|
Endianness is a compile time constant of the GDB
server. Either
This is conveniently set in the |
Caution | |
---|---|
With the need for multiple accesses to 32-bit values for both read and write, using these functions to access memory mapped device registers is best avoided, particularly where registers (or any neighboring registers) have side-effects. |