Skip to content

Commit

Permalink
[chip_tb] Integrate usbdpi into chip tb
Browse files Browse the repository at this point in the history
Initial integration of usbdpi model into chip dvsim/tb;
usbdev_test is up and running
Simple chip_sw_usbdev_dpi_vseq created but incomplete.
Include workaround for mmio32 routines reading X from usbdev.
Added pull up resistors in diff receiver; driven by usbdev_aon_wake
module in pinmux.

Signed-off-by: Adrian Lees <[email protected]>
  • Loading branch information
alees24 committed Apr 20, 2023
1 parent a62db34 commit 8364a5d
Show file tree
Hide file tree
Showing 17 changed files with 314 additions and 39 deletions.
27 changes: 17 additions & 10 deletions hw/dv/dpi/usbdpi/usbdpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ static void setDeviceConfiguration(usbdpi_ctx_t *ctx, uint8_t config);
static void setTestStatus(usbdpi_ctx_t *ctx, uint32_t status, const char *msg);

// Change DP and DN outputs from host
static uint32_t set_driving(usbdpi_ctx_t *ctx, uint32_t d2p, uint32_t newval);
static uint32_t set_driving(usbdpi_ctx_t *ctx, uint32_t d2p, uint32_t newval,
bool p2d_oe);

// Try to send OUT transfer. Optionally expect Status packet (eg. ACK|NAK) in
// response
Expand Down Expand Up @@ -181,6 +182,7 @@ void usbdpi_device_to_host(void *ctx_void, const svBitVecVal *usb_d2p) {
"drives\n",
ctx->frame, ctx->tick_bits, st_states[ctx->state],
hs_states[ctx->hostSt]);
// TODO: stop the test
break;

// Device to host transmission; collect the bits
Expand All @@ -193,14 +195,13 @@ void usbdpi_device_to_host(void *ctx_void, const svBitVecVal *usb_d2p) {

case ST_IDLE:
// Nothing to do
ctx->state = ST_GET;
break;

default:
assert(!"Invalid/unknown state");
break;
}

ctx->state = ST_GET;
} else {
if (ctx->state == ST_GET) {
ctx->state = ST_IDLE;
Expand Down Expand Up @@ -1046,8 +1047,9 @@ void testUnimplEp(usbdpi_ctx_t *ctx, uint8_t pid, uint8_t device,
}
}

// Change DP and DN outputs from host
uint32_t set_driving(usbdpi_ctx_t *ctx, uint32_t d2p, uint32_t newval) {
// Change host outputs
uint32_t set_driving(usbdpi_ctx_t *ctx, uint32_t d2p, uint32_t newval,
bool p2d_oe) {
// Always maintain the current state of VBUS
uint32_t driving = ctx->driving & P2D_SENSE;
if (d2p & D2P_DNPU) {
Expand All @@ -1064,6 +1066,10 @@ uint32_t set_driving(usbdpi_ctx_t *ctx, uint32_t d2p, uint32_t newval) {
driving |= P2D_DN;
}
}
// Enable host output drivers?
if (p2d_oe) {
driving |= P2D_OE;
}
return driving;
}

Expand Down Expand Up @@ -1286,7 +1292,7 @@ uint8_t usbdpi_host_to_device(void *ctx_void, const svBitVecVal *usb_d2p) {

case ST_SYNC:
dat = ((USB_SYNC & ctx->bit)) ? P2D_DP : P2D_DN;
ctx->driving = set_driving(ctx, d2p, dat);
ctx->driving = set_driving(ctx, d2p, dat, true);
force_stat = 1;
ctx->bit <<= 1;
if (ctx->bit == 0x100) {
Expand All @@ -1307,7 +1313,7 @@ uint8_t usbdpi_host_to_device(void *ctx_void, const svBitVecVal *usb_d2p) {
ctx->linebits = (ctx->linebits << 1);
} else if (ctx->byte >= sending->num_bytes) {
ctx->state = ST_EOP;
ctx->driving = set_driving(ctx, d2p, 0); // SE0
ctx->driving = set_driving(ctx, d2p, 0, true); // SE0
ctx->bit = 1;
force_stat = 1;
} else {
Expand All @@ -1329,19 +1335,20 @@ uint8_t usbdpi_host_to_device(void *ctx_void, const svBitVecVal *usb_d2p) {
} break;

case ST_EOP0:
ctx->driving = set_driving(ctx, d2p, 0); // SE0
ctx->driving = set_driving(ctx, d2p, 0, true); // SE0
ctx->state = ST_EOP;
break;

case ST_EOP: // SE0 SE0 J
if (ctx->bit == 4) {
ctx->driving = set_driving(ctx, d2p, P2D_DP); // J
ctx->driving = set_driving(ctx, d2p, P2D_DP, true); // J
}
if (ctx->bit == 8) {
usbdpi_transfer_t *sending = ctx->sending;
assert(sending);
// Stop driving: host pulldown to SE0 unless there is a pullup on DP
ctx->driving = set_driving(ctx, d2p, (d2p & D2P_PU) ? P2D_DP : 0);
ctx->driving =
set_driving(ctx, d2p, (d2p & D2P_PU) ? P2D_DP : 0, false);
if (ctx->byte == sending->data_start) {
ctx->bit = 1;
ctx->state = ST_SYNC;
Expand Down
1 change: 1 addition & 0 deletions hw/dv/dpi/usbdpi/usbdpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ typedef uint32_t svBitVecVal;
#define P2D_DN 2
#define P2D_DP 4
#define P2D_D 8
#define P2D_OE 0x10

/* Remember these go LSB first */

Expand Down
50 changes: 31 additions & 19 deletions hw/dv/dpi/usbdpi/usbdpi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@

module usbdpi #(
parameter string NAME = "usb0",
parameter LOG_LEVEL = 1
parameter int LOG_LEVEL = 1
)(
input logic clk_i,
input logic rst_ni,
input logic clk_48MHz_i,
output logic dp_en_p2d,
output logic dp_p2d,
input logic dp_d2p,
input logic dp_en_d2p,
output logic dn_en_p2d,
output logic dn_p2d,
input logic dn_d2p,
input logic dn_en_d2p,
Expand Down Expand Up @@ -52,7 +54,6 @@ module usbdpi #(

initial begin
ctx = usbdpi_create(NAME, LOG_LEVEL);
sense_p2d = 1'b0;
end

final begin
Expand Down Expand Up @@ -146,7 +147,7 @@ module usbdpi #(
// Test steps
typedef enum bit [6:0] {

STEP_BUS_RESET = 0,
STEP_BUS_RESET = 7'h0,
STEP_SET_DEVICE_ADDRESS,
STEP_GET_DEVICE_DESCRIPTOR,
STEP_GET_CONFIG_DESCRIPTOR,
Expand All @@ -169,13 +170,13 @@ module usbdpi #(
STEP_ENDPT_UNIMPL_IN,
STEP_DEVICE_UK_SETUP,
STEP_IDLE_START,
STEP_IDLE_END = STEP_IDLE_START + 4,
STEP_IDLE_END = STEP_IDLE_START + 7'h4,

// usbdev_stream_test
STEP_STREAM_SERVICE = 'h20,
STEP_STREAM_SERVICE = 7'h20,

// Disconnect the device and stop
STEP_BUS_DISCONNECT = 'h7f
STEP_BUS_DISCONNECT = 7'h7f
} usbdpi_test_step_t;

// Make usb_monitor diagnostic information viewable in waveforms
Expand Down Expand Up @@ -212,22 +213,33 @@ module usbdpi #(

assign d2p = {dp_d2p, dp_en_d2p, dn_d2p, dn_en_d2p, d_d2p, d_en_d2p, se0_d2p, tx_use_d_se0_d2p,
pullupdp_d2p, pullupdn_d2p, rx_enable};
always_ff @(posedge clk_48MHz_i) begin
if (!sense_p2d || pullup_detect) begin
automatic byte p2d = usbdpi_host_to_device(ctx, d2p);
d_last <= d_p2d;
dp_int <= p2d[2];
dn_int <= p2d[1];
sense_p2d <= p2d[0];
unused_dummy <= |p2d[7:4];
d2p_r <= d2p;
if (d2p_r != d2p) begin
usbdpi_device_to_host(ctx, d2p);
end
end else begin // if (pullup_detect)
always_ff @(posedge clk_48MHz_i or negedge rst_ni) begin
if (!rst_ni) begin
sense_p2d <= 1'b0;
dp_en_p2d <= 1'b0;
dn_en_p2d <= 1'b0;
d_last <= 0;
dp_int <= 0;
dn_int <= 0;
end else begin
if (!sense_p2d || pullup_detect) begin
automatic byte p2d = usbdpi_host_to_device(ctx, d2p);
d_last <= d_p2d;
dp_en_p2d <= p2d[4];
dn_en_p2d <= p2d[4];
dp_int <= p2d[2];
dn_int <= p2d[1];
sense_p2d <= p2d[0];
unused_dummy <= |p2d[7:5];
d2p_r <= d2p;
if (d2p_r != d2p) begin
usbdpi_device_to_host(ctx, d2p);
end
end else begin
d_last <= 0;
dp_int <= 0;
dn_int <= 0;
end
end
end

Expand Down
16 changes: 16 additions & 0 deletions hw/dv/sv/usb20_agent/usb20_usbdpi.core
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CAPI=2:
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
name: "lowrisc:dv:usb20_usbdpi:0.1"
description: "USB20-USBDPI"

filesets:
files_rtl:
files:
- usb20_usbdpi.sv: { file_type: systemVerilogSource }

targets:
default:
filesets:
- files_rtl
162 changes: 162 additions & 0 deletions hw/dv/sv/usb20_agent/usb20_usbdpi.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

module usb20_usbdpi (
input clk_i,
input rst_ni,

// VBUS/SENSE is driven high to activate/power the device.
output usb_sense_o,

// Bidirectional, differential bus.
inout usb_p,
inout usb_n
);

// Functioning sketch of integration of USBDPI model into dv top-level tb
// as a connectivity and function test for ASIC

// This module integrates the existing `usbdpi` module into the DV chip test
// bench, reconstructing the two unidirectional buses and driver enables that
// the DPI model requires for its operation, using just the bare bidirectional
// USB signals.
//
// Nomenclature notes:
// dp (or p) and dn (or n) are the two signals of the differential USB
// d2p means device to DPI
// p2d means DPI to device

// VBUS/SENSE output from DPI
wire usb_sense_p2d;
// DPI driver enables
wire usb_dp_en_p2d;
wire usb_dn_en_p2d;
// DPI driver outputs
wire usb_dp_p2d;
wire usb_dn_p2d;

assign usb_sense_o = usb_sense_p2d;

// Weak pull downs so that we can detect the presence of the device, and we
// also prevent Z triggering 'X assertions' in usbdev
assign (weak0, weak1) usb_p = 1'b0;
assign (weak0, weak1) usb_n = 1'b0;
// Tri-stated output drivers
assign (strong0, strong1) usb_p = usb_dp_en_p2d ? usb_dp_p2d : 1'bZ;
assign (strong0, strong1) usb_n = usb_dn_en_p2d ? usb_dn_p2d : 1'bZ;

///////////////////////////////////////////////////////////////////////////
// Simple detection of pull up assertion indicating device presence;
// we simply respond to the first line to be pulled high by the device after
// VSENSE assertion, without regard for proper USB 2.0 timing
///////////////////////////////////////////////////////////////////////////
logic usb_pullupdp_d2p;
logic usb_pullupdn_d2p;

// Has either pull up been asserted by the device?
wire usb_pullup_detect = usb_pullupdp_d2p | usb_pullupdn_d2p;

always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
usb_pullupdp_d2p <= 1'b0;
usb_pullupdn_d2p <= 1'b0;
end else if (usb_sense_p2d && !usb_pullup_detect) begin
// Is the FS device pulling DP high?
if (usb_p === 1'b1) begin
usb_pullupdp_d2p <= 1'b1;
end
// Is the FS device pulling DN high, implying that it has been configured
// to perform pin-flipping?
if (usb_n === 1'b1) begin
usb_pullupdn_d2p <= 1'b1;
end
end
end

///////////////////////////////////////////////////////////////////////////
// Basic activity detection; DPI model indicates whether it is driving,
// but for the device we must detect a departure from the bus Idle state
///////////////////////////////////////////////////////////////////////////
logic usb_dp_en_d2p_last;
logic usb_dn_en_d2p_last;
logic usb_dp_en_d2p;
logic usb_dn_en_d2p;

always_comb begin
usb_dp_en_d2p = usb_dp_en_d2p_last;
usb_dn_en_d2p = usb_dn_en_d2p_last;
// Detect transmission start of DPI or device
if (usb_dp_en_p2d || (!usb_dp_en_d2p && usb_p != 1'b1)) begin
usb_dp_en_d2p = !usb_dp_en_p2d;
end
if (usb_dn_en_p2d || (!usb_dn_en_d2p && usb_n != 1'b0)) begin
usb_dn_en_d2p = !usb_dn_en_p2d;
end
end

// Count of SE0 cycles (1/4 bit intervals). This is just an approximate
// detection of EOP for the purpose of ascertaining when the device is
// relinquishing the bus; it will also count during bus resets.
logic [2:0] se0_cnt;
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
se0_cnt <= 'b0;
end else if (usb_p === 1'b0 && usb_n === 1'b0) begin
se0_cnt <= se0_cnt + 1'b1;
end else begin
se0_cnt <= 'b0;
end
end

// Assume that the device is driving if the DPI model is not
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
usb_dp_en_d2p_last <= 1'b0;
usb_dn_en_d2p_last <= 1'b0;
end else if (usb_sense_p2d & usb_pullup_detect) begin
// Detect the end of EOP when the device has been transmitting
if (&{usb_dp_en_d2p_last, se0_cnt}) begin
usb_dp_en_d2p_last <= 1'b0;
end else begin
usb_dp_en_d2p_last <= usb_dp_en_d2p;
end
// Detect the end of EOP when the device has been transmitting
if ({usb_dn_en_d2p_last, se0_cnt}) begin
usb_dn_en_d2p_last <= 1'b0;
end else begin
usb_dn_en_d2p_last <= usb_dn_en_d2p;
end
end
end

// USB DPI
usbdpi u_usbdpi (
.clk_i (clk_i),
.rst_ni (rst_ni),
.clk_48MHz_i (clk_i),

.sense_p2d (usb_sense_p2d),
.pullupdp_d2p (usb_pullupdp_d2p),
.pullupdn_d2p (usb_pullupdn_d2p),

.dp_en_p2d (usb_dp_en_p2d),
.dp_p2d (usb_dp_p2d),
.dp_d2p (usb_p),
.dp_en_d2p (usb_dp_en_d2p),

.dn_en_p2d (usb_dn_en_p2d),
.dn_p2d (usb_dn_p2d),
.dn_d2p (usb_n),
.dn_en_d2p (usb_dn_en_d2p),

// ASIC communicates via true differential signaling
.d_p2d (),
.d_d2p (1'b0), // not used
.d_en_d2p (1'b0),
.se0_d2p (1'b0), // not used
.rx_enable_d2p (1'b0),
.tx_use_d_se0_d2p(1'b0)
);

endmodule
Loading

0 comments on commit 8364a5d

Please sign in to comment.