Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPI device bootstrap support #20669

Open
wants to merge 11 commits into
base: integrated_dev
Choose a base branch
from
Open
27 changes: 23 additions & 4 deletions hw/dv/dpi/common/tcp_server/tcp_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct tcp_server_ctx {
int sfd; // socket fd
int cfd; // client fd
pthread_t sock_thread;
pthread_mutex_t sock_mutex;
};

static bool tcp_buffer_is_full(struct tcp_buf *buf) {
Expand Down Expand Up @@ -319,6 +320,7 @@ static void *server_create(void *ctx_void) {

// Initialise timeout
timeout.tv_sec = 0;
timeout.tv_usec = 0;

// Initialise fd_set

Expand Down Expand Up @@ -357,6 +359,7 @@ static void *server_create(void *ctx_void) {
// New client data
if (FD_ISSET(ctx->cfd, &read_fds)) {
unsigned count = 0;
pthread_mutex_lock(&ctx->sock_mutex);
while (!tcp_buffer_is_full(ctx->buf_in)) {
if (get_byte(ctx, &xfer_data)) {
tcp_buffer_put_byte(ctx->buf_in, xfer_data);
Expand All @@ -370,12 +373,15 @@ static void *server_create(void *ctx_void) {
break;
}
}
pthread_mutex_unlock(&ctx->sock_mutex);
}

if (ctx->cfd != 0) {
pthread_mutex_lock(&ctx->sock_mutex);
while (tcp_buffer_get_byte(ctx->buf_out, &xfer_data)) {
put_byte(ctx, xfer_data);
}
pthread_mutex_unlock(&ctx->sock_mutex);
}
}

Expand Down Expand Up @@ -411,8 +417,9 @@ struct tcp_server_ctx *tcp_server_create(const char *display_name,
ctx->display_name = strdup(display_name);
assert(ctx->display_name);

if (pthread_create(&ctx->sock_thread, NULL, server_create, (void *)ctx) !=
0) {
if (pthread_mutex_init(&ctx->sock_mutex, NULL) != 0 ||
pthread_create(&ctx->sock_thread, NULL, server_create, (void *)ctx) !=
0) {
fprintf(stderr, "%s: Unable to create TCP socket thread\n",
ctx->display_name);
ctx_free(ctx);
Expand All @@ -423,11 +430,23 @@ struct tcp_server_ctx *tcp_server_create(const char *display_name,
}

bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat) {
return tcp_buffer_get_byte(ctx->buf_in, dat);
bool result;
pthread_mutex_lock(&ctx->sock_mutex);
result = tcp_buffer_get_byte(ctx->buf_in, dat);
pthread_mutex_unlock(&ctx->sock_mutex);
return result;
}

void tcp_server_write(struct tcp_server_ctx *ctx, char dat) {
tcp_buffer_put_byte(ctx->buf_out, dat);
bool done = false;
while (!done) {
pthread_mutex_lock(&ctx->sock_mutex);
if (!tcp_buffer_is_full(ctx->buf_out)) {
tcp_buffer_put_byte(ctx->buf_out, dat);
done = true;
}
pthread_mutex_unlock(&ctx->sock_mutex);
}
}

void tcp_server_close(struct tcp_server_ctx *ctx) {
Expand Down
14 changes: 12 additions & 2 deletions hw/dv/dpi/dmidpi/dmidpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct dmidpi_ctx {
struct tcp_server_ctx *sock;
struct jtag_ctx jtag;
struct dmi_sig_values sig;
int id_code;
};

/**
Expand All @@ -101,7 +102,7 @@ static void set_dr_data(struct dmidpi_ctx *ctx) {
ctx->jtag.dr_length = 1;
break;
case IdCode:
ctx->jtag.dr_shift_reg = IDCODEVAL;
ctx->jtag.dr_shift_reg = ctx->id_code;
ctx->jtag.dr_length = 32;
break;
case DTMCSR:
Expand Down Expand Up @@ -374,14 +375,23 @@ static void update_dmi_state(struct dmidpi_ctx *ctx) {
}
}

void *dmidpi_create(const char *display_name, int listen_port) {
void *dmidpi_create(const char *display_name, unsigned int id_code,
int listen_port) {
// Create context
struct dmidpi_ctx *ctx =
(struct dmidpi_ctx *)calloc(1, sizeof(struct dmidpi_ctx));
assert(ctx);

// Initialize ID code value
if (id_code != 0) {
ctx->id_code = id_code;
} else {
ctx->id_code = IDCODEVAL;
}

// Set up socket details
ctx->sock = tcp_server_create(display_name, listen_port);
assert(ctx->sock);

printf(
"\n"
Expand Down
4 changes: 3 additions & 1 deletion hw/dv/dpi/dmidpi/dmidpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ extern "C" {
* Call from a initial block.
*
* @param display_name Name of the interface (for display purposes only)
* @param id_code ID of DMI device
* @param listen_port Port to listen on
* @return an initialized struct dmidpi_ctx context object
*/
void *dmidpi_create(const char *display_name, int listen_port);
void *dmidpi_create(const char *display_name, unsigned int id_code,
int listen_port);

/**
* Destructor: Close all connections and free all resources
Expand Down
6 changes: 4 additions & 2 deletions hw/dv/dpi/dmidpi/dmidpi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

module dmidpi #(
parameter string Name = "dmi0", // name of the interface (display only)
parameter int unsigned IdCode = 'h0000_0000, // ID of the DMI device (Use default)
parameter int ListenPort = 44853 // TCP port to listen on
)(
input bit clk_i,
Expand All @@ -22,7 +23,8 @@ module dmidpi #(
);

import "DPI-C"
function chandle dmidpi_create(input string name, input int listen_port);
function chandle dmidpi_create(input string name, input int unsigned id_code,
input int listen_port);

import "DPI-C"
function void dmidpi_tick(input chandle ctx, output bit dmi_req_valid,
Expand All @@ -38,7 +40,7 @@ module dmidpi #(
chandle ctx;

initial begin
ctx = dmidpi_create(Name, ListenPort);
ctx = dmidpi_create(Name, IdCode, ListenPort);
end

final begin
Expand Down
137 changes: 95 additions & 42 deletions hw/dv/dpi/gpiodpi/gpiodpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <sys/types.h>
#include <unistd.h>

#include "tcp_server.h"

// The number of ticks of host_to_device_tick between making syscalls.
#define TICKS_PER_SYSCALL 2048

Expand All @@ -37,6 +39,9 @@ struct gpiodpi_ctx {
// The number of pins we're driving.
int n_bits;

// Signal used for chip reset.
svBit rst_n;

// The last known value of the pins, in little-endian order.
uint32_t driven_pin_values;
// Whether or not the pin is being driven weakly or strongly.
Expand All @@ -45,6 +50,9 @@ struct gpiodpi_ctx {
// avoid excessive `read` syscalls to the pipe fd.
uint32_t counter;

// Server context
struct tcp_server_ctx *sock;

// File descriptors and paths for the device-to-host and host-to-device
// FIFOs.
int dev_to_host_fifo;
Expand Down Expand Up @@ -105,45 +113,59 @@ static void print_usage(char *rfifo, char *wfifo, int n_bits) {
wfifo);
}

void *gpiodpi_create(const char *name, int n_bits) {
void *gpiodpi_create(const char *name, int listen_port, int n_bits) {
struct gpiodpi_ctx *ctx =
(struct gpiodpi_ctx *)malloc(sizeof(struct gpiodpi_ctx));
(struct gpiodpi_ctx *)calloc(1, sizeof(struct gpiodpi_ctx));
assert(ctx);

// n_bits > 32 requires more sophisticated handling of svBitVecVal which we
// currently don't do.
assert(n_bits <= 32 && "n_bits must be <= 32");
ctx->n_bits = n_bits;
ctx->rst_n = 1;

ctx->driven_pin_values = 0;
ctx->weak_pins = 0;
ctx->counter = 0;

char cwd_buf[PATH_MAX];
char *cwd = getcwd(cwd_buf, sizeof(cwd_buf));
assert(cwd != NULL);
if (listen_port >= 0 && listen_port <= 0xffff) {
// Create socket
ctx->sock = tcp_server_create(name, listen_port);
assert(ctx->sock);

int path_len;
path_len = snprintf(ctx->dev_to_host_path, PATH_MAX, "%s/%s-read", cwd, name);
assert(path_len > 0 && path_len <= PATH_MAX);
path_len =
snprintf(ctx->host_to_dev_path, PATH_MAX, "%s/%s-write", cwd, name);
assert(path_len > 0 && path_len <= PATH_MAX);

ctx->dev_to_host_fifo = open_fifo(ctx->dev_to_host_path, O_RDWR);
if (ctx->dev_to_host_fifo < 0) {
return NULL;
}
printf(
"\n"
"GPIO: FIFO pipes created at %s:%d (read) and %s:%d (write) for %d-bit "
"wide GPIO. Connect them with any telnet terminal program.\n",
"localhost", listen_port, "localhost", listen_port, n_bits);
} else {
char cwd_buf[PATH_MAX];
char *cwd = getcwd(cwd_buf, sizeof(cwd_buf));
assert(cwd != NULL);

int path_len;
path_len =
snprintf(ctx->dev_to_host_path, PATH_MAX, "%s/%s-read", cwd, name);
assert(path_len > 0 && path_len <= PATH_MAX);
path_len =
snprintf(ctx->host_to_dev_path, PATH_MAX, "%s/%s-write", cwd, name);
assert(path_len > 0 && path_len <= PATH_MAX);

ctx->dev_to_host_fifo = open_fifo(ctx->dev_to_host_path, O_RDWR);
if (ctx->dev_to_host_fifo < 0) {
return NULL;
}

ctx->host_to_dev_fifo = open_fifo(ctx->host_to_dev_path, O_RDWR);
if (ctx->host_to_dev_fifo < 0) {
return NULL;
}
ctx->host_to_dev_fifo = open_fifo(ctx->host_to_dev_path, O_RDWR);
if (ctx->host_to_dev_fifo < 0) {
return NULL;
}

int flags = fcntl(ctx->host_to_dev_fifo, F_GETFL, 0);
fcntl(ctx->host_to_dev_fifo, F_SETFL, flags | O_NONBLOCK);
int flags = fcntl(ctx->host_to_dev_fifo, F_GETFL, 0);
fcntl(ctx->host_to_dev_fifo, F_SETFL, flags | O_NONBLOCK);

print_usage(ctx->dev_to_host_path, ctx->host_to_dev_path, ctx->n_bits);
print_usage(ctx->dev_to_host_path, ctx->host_to_dev_path, ctx->n_bits);
}

return (void *)ctx;
}
Expand All @@ -169,7 +191,15 @@ void gpiodpi_device_to_host(void *ctx_void, svBitVecVal *gpio_data,
}
*pin_char = '\n';

ssize_t written = write(ctx->dev_to_host_fifo, gpio_str, ctx->n_bits + 1);
ssize_t written = 0;
if (ctx->sock) {
for (int i = 0; i < ctx->n_bits + 1; i++) {
tcp_server_write(ctx->sock, gpio_str[i]);
written++;
}
} else {
written = write(ctx->dev_to_host_fifo, gpio_str, ctx->n_bits + 1);
}
assert(written == ctx->n_bits + 1);
}

Expand Down Expand Up @@ -211,14 +241,28 @@ static void set_bit_val(uint32_t *word, uint32_t idx, bool val) {

uint32_t gpiodpi_host_to_device_tick(void *ctx_void, svBitVecVal *gpio_oe,
svBitVecVal *gpio_pull_en,
svBitVecVal *gpio_pull_sel) {
svBitVecVal *gpio_pull_sel,
svBit *gpio_rst_n) {
struct gpiodpi_ctx *ctx = (struct gpiodpi_ctx *)ctx_void;
assert(ctx);

if (ctx->counter % TICKS_PER_SYSCALL == 0) {
char gpio_str[256];
ssize_t read_len =
read(ctx->host_to_dev_fifo, gpio_str, sizeof(gpio_str) - 1);
ssize_t read_len = 0;
if (ctx->sock) {
bool rv;
do {
rv = tcp_server_read(ctx->sock, &gpio_str[read_len]);
if (rv) {
read_len++;
}
} while (read_len > 0 && read_len < 256 &&
(gpio_str[read_len - 1] != '\0' &&
gpio_str[read_len - 1] != '\r' &&
gpio_str[read_len - 1] != '\n'));
} else {
read_len = read(ctx->host_to_dev_fifo, gpio_str, sizeof(gpio_str) - 1);
}
if (read_len > 0) {
gpio_str[read_len] = '\0';

Expand All @@ -245,6 +289,8 @@ uint32_t gpiodpi_host_to_device_tick(void *ctx_void, svBitVecVal *gpio_oe,
}
CLR_BIT(ctx->driven_pin_values, idx);
set_bit_val(&ctx->weak_pins, idx, weak);
} else if (idx == 255) {
ctx->rst_n = 0;
} else {
fprintf(stderr,
"GPIO: Host tried to pull invalid pin low: pin %2d\n",
Expand All @@ -265,6 +311,8 @@ uint32_t gpiodpi_host_to_device_tick(void *ctx_void, svBitVecVal *gpio_oe,
}
SET_BIT(ctx->driven_pin_values, idx);
set_bit_val(&ctx->weak_pins, idx, weak);
} else if (idx == 255) {
ctx->rst_n = 1;
} else {
fprintf(stderr,
"GPIO: Host tried to pull invalid pin high: pin %2d\n",
Expand All @@ -281,6 +329,7 @@ uint32_t gpiodpi_host_to_device_tick(void *ctx_void, svBitVecVal *gpio_oe,
}

parse_loop_end:
*gpio_rst_n = ctx->rst_n;
ctx->counter += 1;
// The verilated module simulates logic, but the weak/strong inputs result
// from the properties of the IO pads and the selection of external pull
Expand All @@ -303,22 +352,26 @@ void gpiodpi_close(void *ctx_void) {
return;
}

if (close(ctx->dev_to_host_fifo) != 0) {
printf("GPIO: Failed to close FIFO file at %s: %s\n", ctx->dev_to_host_path,
strerror(errno));
}
if (close(ctx->host_to_dev_fifo) != 0) {
printf("GPIO: Failed to close FIFO file at %s: %s\n", ctx->host_to_dev_path,
strerror(errno));
}
if (ctx->sock) {
tcp_server_close(ctx->sock);
} else {
if (close(ctx->dev_to_host_fifo) != 0) {
printf("GPIO: Failed to close FIFO file at %s: %s\n",
ctx->dev_to_host_path, strerror(errno));
}
if (close(ctx->host_to_dev_fifo) != 0) {
printf("GPIO: Failed to close FIFO file at %s: %s\n",
ctx->host_to_dev_path, strerror(errno));
}

if (unlink(ctx->dev_to_host_path) != 0) {
printf("GPIO: Failed to unlink FIFO file at %s: %s\n",
ctx->dev_to_host_path, strerror(errno));
}
if (unlink(ctx->host_to_dev_path) != 0) {
printf("GPIO: Failed to unlink FIFO file at %s: %s\n",
ctx->host_to_dev_path, strerror(errno));
if (unlink(ctx->dev_to_host_path) != 0) {
printf("GPIO: Failed to unlink FIFO file at %s: %s\n",
ctx->dev_to_host_path, strerror(errno));
}
if (unlink(ctx->host_to_dev_path) != 0) {
printf("GPIO: Failed to unlink FIFO file at %s: %s\n",
ctx->host_to_dev_path, strerror(errno));
}
}

free(ctx);
Expand Down
Loading
Loading