Skip to content

Commit

Permalink
Update PIO program to pass read/write commands through FIFO
Browse files Browse the repository at this point in the history
alongside bit counts. Also, don't return RX data on write commands.
These two changes allow the probe code to return early after
pushing write commands into the FIFO, which improves throughput.
  • Loading branch information
Wren6991 committed May 9, 2023
1 parent 46eb924 commit 491b96c
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 49 deletions.
48 changes: 34 additions & 14 deletions src/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,37 @@ void probe_assert_reset(bool state)
#endif
}

typedef enum probe_pio_command {
CMD_WRITE = 0,
CMD_SKIP,
CMD_READ
} probe_pio_command_t;

static inline uint32_t fmt_probe_command(uint bit_count, bool out_en, probe_pio_command_t cmd) {
uint cmd_addr =
cmd == CMD_WRITE ? probe.offset + probe_offset_write_cmd :
cmd == CMD_SKIP ? probe.offset + probe_offset_get_next_cmd :
probe.offset + probe_offset_read_cmd;
return ((bit_count - 1) & 0xff) | ((uint)out_en << 8) | (cmd_addr << 9);
}

void probe_write_bits(uint bit_count, uint32_t data_byte) {
DEBUG_PINS_SET(probe_timing, DBG_PIN_WRITE);
pio_sm_put_blocking(pio0, PROBE_SM, bit_count - 1);
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(bit_count, true, CMD_WRITE));
pio_sm_put_blocking(pio0, PROBE_SM, data_byte);
DEBUG_PINS_SET(probe_timing, DBG_PIN_WRITE_WAIT);
picoprobe_dump("Write %d bits 0x%x\n", bit_count, data_byte);
// Wait for pio to push garbage to rx fifo so we know it has finished sending
pio_sm_get_blocking(pio0, PROBE_SM);
DEBUG_PINS_CLR(probe_timing, DBG_PIN_WRITE_WAIT);
// Return immediately so we can cue up the next command whilst this one runs
DEBUG_PINS_CLR(probe_timing, DBG_PIN_WRITE);
}

void probe_hiz_clocks(uint bit_count) {
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(bit_count, false, CMD_WRITE));
pio_sm_put_blocking(pio0, PROBE_SM, 0);
}

uint32_t probe_read_bits(uint bit_count) {
DEBUG_PINS_SET(probe_timing, DBG_PIN_READ);
pio_sm_put_blocking(pio0, PROBE_SM, bit_count - 1);
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(bit_count, false, CMD_READ));
uint32_t data = pio_sm_get_blocking(pio0, PROBE_SM);
uint32_t data_shifted = data;
if (bit_count < 32) {
Expand All @@ -101,14 +117,20 @@ uint32_t probe_read_bits(uint bit_count) {
return data_shifted;
}

static void probe_wait_idle() {
pio0->fdebug = 1u << (PIO_FDEBUG_TXSTALL_LSB + PROBE_SM);
while (!(pio0->fdebug & (1u << (PIO_FDEBUG_TXSTALL_LSB + PROBE_SM))))
;
}

void probe_read_mode(void) {
pio_sm_exec(pio0, PROBE_SM, pio_encode_jmp(probe.offset + probe_offset_in_posedge));
while(pio_sm_get_pc(pio0, PROBE_SM) != probe.offset + probe_offset_in_idle);
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(0, false, CMD_SKIP));
probe_wait_idle();
}

void probe_write_mode(void) {
pio_sm_exec(pio0, PROBE_SM, pio_encode_jmp(probe.offset + probe_offset_out_negedge));
while(pio_sm_get_pc(pio0, PROBE_SM) != probe.offset + probe_offset_out_idle);
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(0, true, CMD_SKIP));
probe_wait_idle();
}

void probe_init() {
Expand All @@ -123,13 +145,11 @@ void probe_init() {
// Set up divisor
probe_set_swclk_freq(1000);

// Enable SM
// Jump SM to command dispatch routine, and enable it
pio_sm_exec(pio0, PROBE_SM, offset + probe_offset_get_next_cmd);
pio_sm_set_enabled(pio0, PROBE_SM, 1);
probe.initted = 1;
}

// Jump to write program
probe_write_mode();
}

void probe_deinit(void)
Expand Down
3 changes: 3 additions & 0 deletions src/probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@
#endif

void probe_set_swclk_freq(uint freq_khz);

// Bit counts in the range 1..256
void probe_write_bits(uint bit_count, uint32_t data_byte);
uint32_t probe_read_bits(uint bit_count);
void probe_hiz_clocks(uint bit_count);

void probe_read_mode(void);
void probe_write_mode(void);
Expand Down
60 changes: 37 additions & 23 deletions src/probe.pio
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
* Copyright (c) 2021-2023 Raspberry Pi (Trading) Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -23,32 +23,46 @@
*
*/

// Every TX FIFO entry is either a command, or up to 32 bits of data.
// Command format:
//
// | 13:9 | 8 | 7:0 |
// | Cmd | Dir | Count |
//
// Count is the number of bits to be transferred by this command, minus 1.
// Dir is the output enable for the SWDIO pin.
// Cmd is the address of the write_cmd, read_cmd or get_next_cmd label.
//
// write_cmd expects a FIFO data entry, but read_cmd does not.
//
// read_cmd pushes data to the FIFO, but write_cmd does not. (The lack of RX
// garbage on writes allows the interface code to return early after pushing a
// write command, as there is no need in general to poll for a command's
// completion as long as all commands are executed in order.)

.program probe
.side_set 1 opt

public out_negedge:
set pindirs, 1 side 0x0 ; Init OE clock 0
public out_idle:
pull ; Pull number of bits to shift -1 from tx fifo and put into output shift register
mov x, osr ; mov bits to shift -1 from output shift register into x
pull ; Pull data to shift out
out_negedge_bitloop:
out pins, 1 side 0x0 ; clock data out on falling edge
jmp x-- out_negedge_bitloop side 0x1 ; data is present for posedge
set pins, 1 side 0x0 ; Drive data high (idle bus state)
push ; Push to rx fifo just so processor knows when done
jmp out_negedge ; Wait for next transaction
public write_cmd:
pull
write_bitloop:
out pins, 1 side 0x0 ; Data is output by host on negedge
jmp x-- write_bitloop side 0x1 ; ...and captured by target on posedge
; Fall through to next command
.wrap_target
public get_next_cmd:
pull side 0x0 ; SWCLK is initially low
out x, 8 ; Get bit count
out pindirs, 1 ; Set SWDIO direction
out pc, 5 ; Go to command routine

public read_cmd:
read_bitloop:
in pins, 1 side 0x1 ; Data is captured by host on posedge
jmp x-- read_bitloop side 0x0
push
.wrap ; Wrap to next command

public in_posedge:
set pindirs, 0 side 0x0 ; INIT IE clock 0
public in_idle:
pull ; Pull number of bits to shift -1 from tx fifo and put into output shift register
mov x, osr ; mov bits to shift -1 from output shift register into x into x
in_posedge_bitloop:
in pins, 1 side 0x1 ; Generate posedge and read data
jmp x-- in_posedge_bitloop side 0x0 ;
push ; Push to rx fifo when done
jmp in_posedge ; Jump back to start

; Implement probe_gpio_init() and probe_sm_init() methods here - set pins, offsets, sidesets etc
% c-sdk {
Expand Down
18 changes: 6 additions & 12 deletions src/sw_dp_pio.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
probe_write_bits(8, prq);

/* Turnaround (ignore read bits) */
probe_read_mode();

ack = probe_read_bits(DAP_Data.swd_conf.turnaround + 3);
ack >>= DAP_Data.swd_conf.turnaround;

Expand All @@ -154,12 +152,10 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
picoprobe_debug("Read %02x ack %02x 0x%08x parity %01x\n",
prq, ack, val, bit);
/* Turnaround for line idle */
probe_read_bits(DAP_Data.swd_conf.turnaround);
probe_write_mode();
probe_hiz_clocks(DAP_Data.swd_conf.turnaround);
} else {
/* Turnaround for write */
probe_read_bits(DAP_Data.swd_conf.turnaround);
probe_write_mode();
probe_hiz_clocks(DAP_Data.swd_conf.turnaround);

/* Write WDATA[0:31] */
val = *data;
Expand All @@ -178,9 +174,9 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
/* Idle cycles - drive 0 for N clocks */
if (DAP_Data.transfer.idle_cycles) {
for (n = DAP_Data.transfer.idle_cycles; n; ) {
if (n > 32) {
probe_write_bits(32, 0);
n -= 32;
if (n > 256) {
probe_write_bits(256, 0);
n -= 256;
} else {
probe_write_bits(n, 0);
n -= n;
Expand All @@ -195,8 +191,7 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
/* Dummy Read RDATA[0:31] + Parity */
probe_read_bits(33);
}
probe_read_bits(DAP_Data.swd_conf.turnaround);
probe_write_mode();
probe_hiz_clocks(DAP_Data.swd_conf.turnaround);
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) {
/* Dummy Write WDATA[0:31] + Parity */
probe_write_bits(32, 0);
Expand All @@ -209,7 +204,6 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
n = DAP_Data.swd_conf.turnaround + 32U + 1U;
/* Back off data phase */
probe_read_bits(n);
probe_write_mode();
return ((uint8_t)ack);
}

Expand Down

0 comments on commit 491b96c

Please sign in to comment.