vibed jtagram with script as drop in replacement of serving_ram

This commit is contained in:
2026-02-22 21:27:40 +01:00
parent 20cfece6e3
commit 9322766cef
5 changed files with 471 additions and 0 deletions

54
rtl/serv/serving_ram_dp.v Normal file
View File

@@ -0,0 +1,54 @@
`default_nettype none
`include "../util/clog2.vh"
module serving_ram_dp
#(// Memory parameters
parameter depth = 256,
parameter aw = `CLOG2(depth),
parameter memfile = "",
parameter sim = 1'b0)
(
// CPU port (compatible with serving_ram)
input wire i_clk,
input wire [aw-1:0] i_waddr,
input wire [7:0] i_wdata,
input wire i_wen,
input wire [aw-1:0] i_raddr,
output reg [7:0] o_rdata,
// Debug/programming port
input wire i_dbg_clk,
input wire [aw-1:0] i_dbg_addr,
input wire [7:0] i_dbg_wdata,
input wire i_dbg_wen,
output wire [7:0] o_dbg_rdata
);
reg [7:0] mem [0:depth-1] /* verilator public */;
always @(posedge i_clk) begin
if (i_wen)
mem[i_waddr] <= i_wdata;
o_rdata <= mem[i_raddr];
end
always @(posedge i_dbg_clk) begin
if (i_dbg_wen)
mem[i_dbg_addr] <= i_dbg_wdata;
end
// Asynchronous debug read simplifies JTAG readback logic.
assign o_dbg_rdata = mem[i_dbg_addr];
integer i;
initial begin
if (sim == 1'b1) begin
for (i = 0; i < depth; i = i + 1)
mem[i] = 8'h00;
end
if (|memfile) begin
$display("Preloading %m from %s", memfile);
$readmemh(memfile, mem);
end
end
endmodule

View File

@@ -0,0 +1,65 @@
`default_nettype none
`include "../util/clog2.vh"
// Drop-in serving RAM variant with USER JTAG programming access.
module serving_ram_jtag
#(
parameter depth = 256,
parameter aw = `CLOG2(depth),
parameter memfile = "",
parameter sim = 1'b0,
parameter USER_CHAIN = 1
)
(
input wire i_clk,
input wire [aw-1:0] i_waddr,
input wire [7:0] i_wdata,
input wire i_wen,
input wire [aw-1:0] i_raddr,
output wire [7:0] o_rdata
);
wire dbg_clk;
wire [aw-1:0] dbg_addr;
wire [7:0] dbg_wdata;
wire dbg_wen;
wire [7:0] dbg_rdata;
serving_ram_dp
#(
.depth(depth),
.aw(aw),
.memfile(memfile),
.sim(sim)
)
i_serving_ram_dp
(
.i_clk(i_clk),
.i_waddr(i_waddr),
.i_wdata(i_wdata),
.i_wen(i_wen),
.i_raddr(i_raddr),
.o_rdata(o_rdata),
.i_dbg_clk(dbg_clk),
.i_dbg_addr(dbg_addr),
.i_dbg_wdata(dbg_wdata),
.i_dbg_wen(dbg_wen),
.o_dbg_rdata(dbg_rdata)
);
serving_ram_jtag_bridge
#(
.depth(depth),
.aw(aw),
.USER_CHAIN(USER_CHAIN)
)
i_serving_ram_jtag_bridge
(
.o_ram_clk(dbg_clk),
.o_ram_addr(dbg_addr),
.o_ram_wdata(dbg_wdata),
.o_ram_wen(dbg_wen),
.i_ram_rdata(dbg_rdata)
);
endmodule

View File

@@ -0,0 +1,107 @@
`default_nettype none
`include "../util/clog2.vh"
// Simple USER JTAG data-register protocol (LSB-first):
// bit[0] : write_enable (1=write, 0=read/select)
// bit[32:1] : 32-bit address
// bit[40:33] : write data
//
// On UPDATE:
// - write command: writes byte to RAM
// - read command : updates current read address for next CAPTURE/SHIFT readback
// - RAM uses the lower aw address bits from the 32-bit protocol address
//
// On CAPTURE, readback register loads:
// bit[0] : valid (always 1)
// bit[8:1] : read data at current read address
// remaining bits : zero
module serving_ram_jtag_bridge
#(
parameter depth = 256,
parameter aw = `CLOG2(depth),
parameter USER_CHAIN = 1
)
(
output wire o_ram_clk,
output wire [aw-1:0] o_ram_addr,
output wire [7:0] o_ram_wdata,
output wire o_ram_wen,
input wire [7:0] i_ram_rdata
);
localparam integer JTAG_AW = 32;
localparam integer FRAME_W = 1 + JTAG_AW + 8;
localparam integer PAD_W = FRAME_W - 9;
wire tap_drck;
wire tap_shift;
wire tap_update;
wire tap_reset;
wire tap_sel;
wire tap_tdi;
wire tap_tdo;
reg [FRAME_W-1:0] shift_in;
reg [FRAME_W-1:0] shift_out;
reg [aw-1:0] read_addr;
reg shift_active_d;
wire cmd_write;
wire [JTAG_AW-1:0] cmd_addr;
wire [aw-1:0] cmd_addr_ram;
wire [7:0] cmd_wdata;
assign cmd_write = shift_in[0];
assign cmd_addr = shift_in[JTAG_AW:1];
assign cmd_wdata = shift_in[JTAG_AW+8:JTAG_AW+1];
assign cmd_addr_ram = cmd_addr[aw-1:0];
// Update command shift register and shift response out on DRCK.
// Readback data is loaded on the first shift pulse of a DR scan.
always @(posedge tap_drck or posedge tap_reset) begin
if (tap_reset) begin
shift_in <= {FRAME_W{1'b0}};
shift_out <= {FRAME_W{1'b0}};
shift_active_d <= 1'b0;
end else if (tap_sel && tap_shift) begin
if (!shift_active_d)
shift_out <= {{PAD_W{1'b0}}, i_ram_rdata, 1'b1};
else
shift_out <= {1'b0, shift_out[FRAME_W-1:1]};
shift_in <= {tap_tdi, shift_in[FRAME_W-1:1]};
shift_active_d <= 1'b1;
end else begin
shift_active_d <= 1'b0;
end
end
// Read command selects the address for the next capture.
always @(posedge tap_update or posedge tap_reset) begin
if (tap_reset)
read_addr <= {aw{1'b0}};
else if (tap_sel && !cmd_write)
read_addr <= cmd_addr_ram;
end
assign o_ram_clk = tap_update;
assign o_ram_wen = tap_update & tap_sel & cmd_write;
assign o_ram_wdata = cmd_wdata;
assign o_ram_addr = tap_update ? cmd_addr_ram : read_addr;
assign tap_tdo = shift_out[0];
jtag_tap_spartan6
#(.USER_CHAIN(USER_CHAIN))
i_jtag_tap
(
.o_drck(tap_drck),
.o_capture(),
.o_shift(tap_shift),
.o_update(tap_update),
.o_reset(tap_reset),
.o_sel(tap_sel),
.o_tdi(tap_tdi),
.i_tdo(tap_tdo)
);
endmodule