CPU is now either waiting for dongle to take some data from dmseg (if we requested for CPU do give us internal state, for example),
or it will wait for some data from dongle (if it needs following instruction because it did previous, or if the operand address of the currently executed opcode
falls somewhere (anywhere) in dmseg (0xff..ff20000 - 0xff..ff2fffff)).
to give it an operand, because it saw in the instruction opcode that operand address is somewhere in dmseg. That provoked the CPU to stall (it tried operand fetch to dmseg and stopped),
operand from the address in dmseg, CPU will stall waiting for the dongle to do the action of passing the operand and signal this by putting PrAcc to 0.
If this operand is somewhere in RAM, CPU will not stall (it stalls only on dmseg), but it will just take it and proceed to next instruction. But since PC for next instruction
Some instructions are jumps (if these are jumps in dmseg addr, CPU will jump and then stall. If this is jump to some address in RAM, CPU will jump and just proceed -
if ((retval = mips32_pracc_exec_write(&ctx, address)) != ERROR_OK)
return retval;
}
else
{
/* Check to see if its reading at the debug vector. The first pass through
* the module is always read at the vector, so the first one we allow. When
* the second read from the vector occurs we are done and just exit. */
if ((address == MIPS32_PRACC_TEXT) && (pass++))
{
break;
}
if ((retval = mips32_pracc_exec_read(&ctx, address)) != ERROR_OK)
return retval;
}
if (cycle == 0)
break;
}
@endcode
and using presented R (mips32_pracc_exec_read()) and W (mips32_pracc_exec_write()) functions it reads in the code (RO) and reads and writes operands (RW).
@section fdimpl OpenOCD FASTDATA Implementation
OpenOCD FASTDATA write function, mips32_pracc_fastdata_xfer() is called from bulk_write_memory callback, which writes a count items of 4 bytes
to the memory of a target at the an address given. Because it operates only on whole words, this should be faster than target_write_memory().
In order to implement FASTDATA write, mips32_pracc_fastdata_xfer() uses the following handler :
@code
uint32_t handler_code[] = {
/* caution when editing, table is modified below */
This handler is put into the RAM and executed from there, and not instruction by instruction, like in previous simple write
(mips_m4k_write_memory()) and read (mips_m4k_read_memory()) functions.
N.B. When it is executing this code in RAM, CPU will not stall on instructions, but execute all until it comes to the :
@code
MIPS32_LW(9,0,8) /* start addr in t1 */
@endcode
and there it will stall - because it will see that one of the operands have to be fetched from dmseg (EJTAG memory, in this case FASTDATA memory segment).
This handler is loaded in the RAM, at the reserved location "work_area". This work_area is configured in OpenOCD configuration script and should be selected
in that way that it is not clobbered (overwritten) by data we want to write-in using FASTDATA.
What is executed instruction by instruction which is passed by dongle (via EJATG memory) is small jump code, which jumps at the handler in RAM.
CPU stalls on dmseg when receiving these jmp_code instructions, but once it jumps in RAM, CPU do not stall anymore and executes bunch of handler instructions.
and then passes to CPU start and end address of the loop region for handler in RAM.
In the loop in handler, CPU sees that it has to take and operand from FSTDATA area (to write it to the dst in RAM after), and so it stalls, putting PrAcc to "1".
OpenOCD fills the data via this loop :
@code
for (i = 0; i < count; i++)
{
/* Send the data out using fastdata (clears the access pending bit) */
Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds to execute the handler. However, since the handler is in an assembly loop,
After the last data has been given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, this instruction do not point into dmseg, so
On its side, OpenOCD checks in CPU has jumped back to MIPS32_PRACC_TEXT, which is the confirmation that it correctly executed all the rest of the handler in RAM,
and that is not stuck somewhere in the RAM, or stalling on some access in dmesg - that would be an error:
FASTDATA register is 1-bit width register. It takes in SPrAcc bit which should be shifted first,
followed by 32 bit of data.
Scan width of FASTDTA is 33 bits in total : 33 bits are shifted in and 33 bits are shifted out.
First bit that is shifted out is SPrAcc that comes out of Fastdata register and should give us status on FATSDATA write we want to do.
@section fdcheck OpenOCD misses FASTDATA check
Download flow (probe -> target block transfer) :
1) Probe transfer target execution to a loop in target memory doing a fixed number of "loads" to fastdata area of dmseg (and stores to the target download destination.)
2) Probe loops attempting to satisfy the loads "expected" from the target.
On FASTDATA access "successful" move on to next "load".
On FASTDATA access "failure" repeat until "successful" or timeout.
(A "failure" is an attempt to satisfy an access when none are pending.)
Note: A failure may have a recoverable (and even expected) cause like slow target execution of the load loop. Other failures may be due to unexpected more troublesome causes like an exception while in debug mode or a target hang on a bad target memory access.
You shift "download" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete.
If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.)
- Upload (CPU -> dongle) :
You shift "dummy" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete. The "upload" is the DATA shifted out of the target.
If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.)
Basically, if checking first (before scan) if CPU is pending on FASTDATA access (PrAcc is "1"), like this
@code
wait(ready);
do_scan();
@endcode
which is inefficient, we should do it like this :
@code
BEGIN :
do_scan();
if (!was_ready)
goto BEGIN;
@endcode
by checking SPrAcc that we shifted out.
If some FASTDATA write fails, OpenOCD will continue with it's loop (on the host side), but CPU will rest pending (on the target side)
In this case, we can lower the JTAG frequency and try again, because most probable reason of this failure is that we tried FASTDATA upload before CPU arrived to rise PrAcc (i.e. before it was pending on access).
-# CPU jumps to Debug Exception Vector Location 0xFF200200 in dmseg and it stalls, pending and waiting for EJTAG to give it first debug instruction and signal it by putting PrAcc to "0"
-# When PrAcc goes to "0" CPU execute one opcode sent by EJTAG via DATA reg. Then it pends on next access, waiting for PrAcc to be put to "0" again
-# Following this game, OpenOCD first loads handler code in RAM, and then sends the jmp_code - instruction by instruction via DATA reg, which redirects CPU to handler previously set up in RAM
-# Once in RAM CPU does not pend on any instruction, but it executes all handler instructions until first "fetch" to Fastdata area - then it stops and pends.
-# So - when it comes to any instruction (opcode) in this handler in RAM which reads (or writes) to Fastdata area (0xF..F20.0000 to 0xF..F20.000F), CPU stops (i.e. stalls access).
I.e. it stops on this lw opcode and waits to FASTDATA TAP command from the probe.
-# CPU continues only if OpenOCD shifted in SPrAcc "0" (and if the PrAcc was "1"). It shifts-out "1" to tell us that it was OK (processor was stalled, so it can complete the access),
and that it continued execution of the handler in RAM.
-# If PrAcc was not "1" CPU will not continue (go to next instruction), but will shift-out "0" and keep stalling on the same instruction of my handler in RAM.
-# When it jumps back to 0xFF200200 in dmseg processor stops and pends, waiting for OpenOCD to send it instruction via DATA reg and signal it by putting PrAcc to "0".