Skip to content

Commit

Permalink
[dv/dpi] jtagdpi lookahead for 'R' on TCK posedge
Browse files Browse the repository at this point in the history
Clients performing a shift operation with data readback will be
sending a sequence of commands that toggle TCK, providing the data to
shift in, interleaved with read commands to sample the data shifted
out. In the current implementation where a single command is processed
on each jtagdpi tick, this leads to an uneven TCK duty cycle (i.e. 3
jtagdpi ticks per TCK cycle) whenever data read commands are present.

The JTAG spec dictates that TDO values change on the falling edge of
TCK and so should be sampled around the rising edge. The command
processing is changed to support a "lookahead" to attempt to pull a
read command back to the same jtagdpi tick where a TCK rising edge
command is handled. With this lookahead, a client that does (TCK
falling edge, TCK rising edge, read TDO) will complete its TCK cycle
in just 2 jtagdpi ticks.

In theory a client that generates a sequence like (TCK falling edge,
read TDO, TCK rising edge) could also lookahead from the read command
for a TCK rising edge. However, such a client is likely to read the
data before sending the rising edge command - so a successful
lookahead would incur an additional network round-trip to the
client. On the other hand, the client-side change to take advantage of
this optimization is trivial.

Signed-off-by: Kip Walker <[email protected]>
  • Loading branch information
kwalker27 authored and rswarbrick committed Dec 4, 2024
1 parent ccd8f9a commit 7e22215
Showing 1 changed file with 38 additions and 1 deletion.
39 changes: 38 additions & 1 deletion hw/dv/dpi/jtagdpi/jtagdpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,37 @@ struct jtagdpi_ctx {
uint8_t tdo;
uint8_t trst_n;
uint8_t srst_n;
// Lookahead buffer - non-zero if valid
char cmd;
};

static bool lookahead(struct jtagdpi_ctx *ctx) {
// Look at the next command if available. Return true if it's an
// 'R', otherwise buffer it to return via get_cmd().
char cmd;
if (!tcp_server_read(ctx->sock, &cmd)) {
return false;
}
if (cmd == 'R') {
return true;
} else {
ctx->cmd = cmd;
return false;
}
}

static bool get_cmd(struct jtagdpi_ctx *ctx, char *cmd) {
// Return a buffered command if available, or try to pull one from
// the socket.
if (ctx->cmd) {
*cmd = ctx->cmd;
ctx->cmd = 0;
return true;
} else {
return tcp_server_read(ctx->sock, cmd);
}
}

/**
* Reset the JTAG signals to a "dongle unplugged" state
*/
Expand Down Expand Up @@ -56,7 +85,7 @@ static void update_jtag_signals(struct jtagdpi_ctx *ctx) {

// read a command byte
char cmd;
if (!tcp_server_read(ctx->sock, &cmd)) {
if (!get_cmd(ctx, &cmd)) {
return;
}

Expand All @@ -66,10 +95,18 @@ static void update_jtag_signals(struct jtagdpi_ctx *ctx) {
// parse received command byte
if (cmd >= '0' && cmd <= '7') {
// JTAG write
uint8_t tck = ctx->tck;
char cmd_bit = cmd - '0';
ctx->tdi = (cmd_bit >> 0) & 0x1;
ctx->tms = (cmd_bit >> 1) & 0x1;
ctx->tck = (cmd_bit >> 2) & 0x1;
// On a rising edge of TCK, we can process a following 'R' command
// to sense the current TDO without waiting for the next DPI
// callback. Since TDO changes on the falling edge of TCK, it is
// already stable and valid.
if (!tck && ctx->tck && lookahead(ctx)) {
act_send_resp = true;
}
} else if (cmd >= 'r' && cmd <= 'u') {
// JTAG reset (active high from OpenOCD)
char cmd_bit = cmd - 'r';
Expand Down

0 comments on commit 7e22215

Please sign in to comment.