jtag memory interface working

This commit is contained in:
2026-02-25 16:14:37 +01:00
parent 9930ce4461
commit 13f72e698f
10 changed files with 664 additions and 358 deletions

View File

@@ -153,6 +153,7 @@ module mcu #(
.sim(sim)
) mem (
.i_clk(i_clk),
.i_rst(i_rst),
.i_waddr(sram_waddr),
.i_wdata(sram_wdata),
.i_wen(sram_wen),
@@ -180,175 +181,6 @@ module mcu #(
endmodule
module jtag_mem_protocol #(
parameter aw = 8,
parameter chain = 1
)(
input wire i_clk,
input wire i_rst,
input wire [7:0] i_mem_rdata,
output reg o_mem_wen,
output reg [7:0] o_mem_wdata,
output reg [aw-1:0] o_mem_waddr,
output reg [aw-1:0] o_mem_raddr,
output reg o_core_reset
);
localparam FRAME_BITS = 42;
// Frame format (LSB-first on JTAG shift stream):
// [0] : core reset
// [1] : write (1=write, 0=read)
// [33:2] : address
// [41:34] : data
wire [31:0] cmd_addr_full;
wire cmd_reset;
wire cmd_write;
wire [7:0] cmd_data;
// JTAG interface wires
wire jtag_tck;
wire jtag_tdi;
wire jtag_drck;
wire jtag_capture;
wire jtag_shift;
wire jtag_update;
wire jtag_runtest;
wire jtag_reset;
wire jtag_sel;
// JTAG clock-domain regs
reg [FRAME_BITS-1:0] shift_q;
reg [FRAME_BITS-1:0] cmd_jtag_q;
reg update_toggle_jtag_q;
reg [FRAME_BITS-1:0] resp_meta_q;
reg [FRAME_BITS-1:0] resp_sync_q;
// Core clock-domain CDC regs
reg update_toggle_meta_q;
reg update_toggle_sync_q;
reg update_toggle_sync_d_q;
reg [FRAME_BITS-1:0] cmd_meta_q;
reg [FRAME_BITS-1:0] cmd_sync_q;
// Core clock-domain protocol state
reg [FRAME_BITS-1:0] resp_core_q;
reg read_pending_q;
reg [31:0] read_addr_full_q;
assign cmd_reset = cmd_sync_q[0];
assign cmd_write = cmd_sync_q[1];
assign cmd_addr_full = cmd_sync_q[33:2];
assign cmd_data = cmd_sync_q[41:34];
jtag_if #(
.chain(chain)
) jtag (
.i_tdo(shift_q[0]),
.o_tck(jtag_tck),
.o_tdi(jtag_tdi),
.o_drck(jtag_drck),
.o_capture(jtag_capture),
.o_shift(jtag_shift),
.o_update(jtag_update),
.o_runtest(jtag_runtest),
.o_reset(jtag_reset),
.o_sel(jtag_sel)
);
// JTAG domain: shift register and update event capture.
always @(posedge jtag_drck or posedge jtag_reset or posedge i_rst) begin
if (jtag_reset || i_rst) begin
shift_q <= {FRAME_BITS{1'b0}};
resp_meta_q <= {FRAME_BITS{1'b0}};
resp_sync_q <= {FRAME_BITS{1'b0}};
end else begin
resp_meta_q <= resp_core_q;
resp_sync_q <= resp_meta_q;
if (jtag_sel && jtag_capture) begin
shift_q <= resp_sync_q;
end else if (jtag_sel && jtag_shift) begin
shift_q <= {jtag_tdi, shift_q[FRAME_BITS-1:1]};
end
end
end
always @(posedge jtag_update or posedge jtag_reset or posedge i_rst) begin
if (jtag_reset || i_rst) begin
cmd_jtag_q <= {FRAME_BITS{1'b0}};
update_toggle_jtag_q <= 1'b0;
end else if (jtag_sel) begin
cmd_jtag_q <= shift_q;
update_toggle_jtag_q <= ~update_toggle_jtag_q;
end
end
// Core domain: receive command and execute against RAM port-B.
always @(posedge i_clk or posedge i_rst) begin
if (i_rst) begin
update_toggle_meta_q <= 1'b0;
update_toggle_sync_q <= 1'b0;
update_toggle_sync_d_q <= 1'b0;
cmd_meta_q <= {FRAME_BITS{1'b0}};
cmd_sync_q <= {FRAME_BITS{1'b0}};
o_mem_wen <= 1'b0;
o_mem_wdata <= 8'h00;
o_mem_waddr <= {aw{1'b0}};
o_mem_raddr <= {aw{1'b0}};
o_core_reset <= 1'b0;
resp_core_q <= {FRAME_BITS{1'b0}};
read_pending_q <= 1'b0;
read_addr_full_q <= 32'h0000_0000;
end else begin
// Defaults are one-cycle strobes for write/reset.
o_mem_wen <= 1'b0;
o_core_reset <= 1'b0;
update_toggle_meta_q <= update_toggle_jtag_q;
update_toggle_sync_q <= update_toggle_meta_q;
update_toggle_sync_d_q <= update_toggle_sync_q;
cmd_meta_q <= cmd_jtag_q;
cmd_sync_q <= cmd_meta_q;
// Complete pending read (port-B read is synchronous).
if (read_pending_q) begin
read_pending_q <= 1'b0;
resp_core_q[0] <= 1'b0;
resp_core_q[1] <= 1'b0;
resp_core_q[33:2] <= read_addr_full_q;
resp_core_q[41:34] <= i_mem_rdata;
end
// New JTAG command arrived.
if (update_toggle_sync_q ^ update_toggle_sync_d_q) begin
if (cmd_reset) begin
o_core_reset <= 1'b1;
end
if (cmd_write) begin
o_mem_waddr <= cmd_addr_full[aw-1:0];
o_mem_wdata <= cmd_data;
o_mem_wen <= 1'b1;
resp_core_q[0] <= cmd_reset;
resp_core_q[1] <= 1'b1;
resp_core_q[33:2] <= cmd_addr_full;
resp_core_q[41:34] <= cmd_data;
end else begin
o_mem_raddr <= cmd_addr_full[aw-1:0];
read_pending_q <= 1'b1;
read_addr_full_q <= cmd_addr_full;
end
end
end
end
// Keep lint quiet for currently-unused JTAG outputs.
wire _unused_tck;
wire _unused_runtest;
assign _unused_tck = jtag_tck;
assign _unused_runtest = jtag_runtest;
endmodule
module memory #(
parameter memfile = "",
parameter depth = 256,
@@ -356,6 +188,7 @@ module memory #(
localparam aw = `CLOG2(depth)
)(
input wire i_clk,
input wire i_rst,
input wire [aw-1:0] i_waddr,
input wire [7:0] i_wdata,
input wire i_wen,
@@ -364,38 +197,61 @@ module memory #(
output wire o_core_reset
);
// The actual memory
reg [7:0]mem [0:depth-1];
// Second interface
wire wen_b;
wire [7:0] wdata_b;
wire [aw-1:0] waddr_b;
reg [7:0] rdata_b;
wire [aw-1:0] raddr_b;
jtag_mem_protocol #(
.aw(aw),
.chain(1)
) jtag_mem (
reg [7:0] mem [0:depth-1];
wire [aw-1:0] mem_adr;
assign mem_adr = (i_wen==1'b1) ? i_waddr :
i_raddr;
// Second port wishbone
wire [31:0] wb_adr;
wire [31:0] wb_dat;
reg [31:0] wb_rdt;
wire [3:0] wb_sel;
wire wb_cyc;
wire wb_we;
wire wb_stb;
reg wb_ack;
reg wb_req_d;
wire cmd_reset;
// Driven by JTAG
jtag_wb_bridge #(
.chain(1),
.byte_aligned(1)
) jtag_wb (
.i_clk(i_clk),
.i_rst(1'b0),
.i_mem_rdata(rdata_b),
.o_mem_wen(wen_b),
.o_mem_wdata(wdata_b),
.o_mem_waddr(waddr_b),
.o_mem_raddr(raddr_b),
.o_core_reset(o_core_reset)
.i_rst(i_rst),
.o_wb_adr(wb_adr),
.o_wb_dat(wb_dat),
.o_wb_sel(wb_sel),
.o_wb_we(wb_we),
.o_wb_cyc(wb_cyc),
.o_wb_stb(wb_stb),
.i_wb_rdt(wb_rdt),
.i_wb_ack(wb_ack),
.o_cmd_reset(cmd_reset)
);
assign o_core_reset = cmd_reset;
// Read/Write
always @(posedge i_clk) begin
// main interface
if (i_wen)
mem[i_waddr] <= i_wdata;
o_rdata <= mem[i_raddr];
// second interface
if (wen_b)
mem[waddr_b] <= wdata_b;
rdata_b <= mem[raddr_b];
if (i_rst) begin
wb_req_d <= 1'b0;
wb_ack <= 1'b0;
wb_rdt <= 32'h00000000;
o_rdata <= 32'h00000000;
end else begin
if (i_wen)
mem[mem_adr] <= i_wdata;
o_rdata <= mem[mem_adr];
wb_req_d <= wb_stb && wb_cyc;
wb_ack <= wb_req_d;
if (wb_we && wb_stb && wb_cyc)
mem[wb_adr[aw-1:0]] <= wb_dat[7:0];
wb_rdt <= {24'h000000, mem[wb_adr[aw-1:0]]};
end
end
// Preload memory
@@ -411,4 +267,6 @@ module memory #(
end
end
endmodule