jtag memory interface working
This commit is contained in:
250
rtl/core/mcu.v
250
rtl/core/mcu.v
@@ -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
|
||||
|
||||
@@ -12,120 +12,64 @@ module top_jtag(
|
||||
wire clk_100;
|
||||
wire clk_15;
|
||||
assign clk_100 = aclk;
|
||||
clk_gen clocking(
|
||||
clk_gen clk(
|
||||
.clk_in(clk_100),
|
||||
.clk_out_15(clk_15)
|
||||
);
|
||||
|
||||
localparam integer JTAG_DATA_BITS = 8;
|
||||
wire [JTAG_DATA_BITS-1:0] jtag_data;
|
||||
wire i_rst;
|
||||
assign i_rst = !aresetn;
|
||||
|
||||
jtag_write_reg #(
|
||||
.DATA_BITS(JTAG_DATA_BITS),
|
||||
.CHAIN(1)
|
||||
) jtag_writer (
|
||||
.clk_i(clk_15),
|
||||
.rst_n_i(aresetn),
|
||||
.data_o(jtag_data)
|
||||
wire [31:0] wb_adr;
|
||||
wire [31:0] wb_dat;
|
||||
wire [31:0] wb_rdt;
|
||||
wire [3:0] wb_sel;
|
||||
wire wb_cyc;
|
||||
wire wb_we;
|
||||
wire wb_stb;
|
||||
wire wb_ack;
|
||||
wire cmd_reset;
|
||||
|
||||
jtag_wb_bridge #(
|
||||
.chain(1)
|
||||
) jtag_wb (
|
||||
.i_clk(clk_15),
|
||||
.i_rst(!aresetn),
|
||||
|
||||
.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 LED = jtag_data[7:0];
|
||||
assign led_green = jtag_data[0];
|
||||
assign led_red = jtag_data[7];
|
||||
assign r2r = jtag_data[5:0];
|
||||
wire [31:0] gpio;
|
||||
wire [31:0] gpio_in;
|
||||
assign gpio_in = 32'h0;
|
||||
|
||||
endmodule
|
||||
|
||||
module jtag_write_reg #(
|
||||
parameter integer DATA_BITS = 8,
|
||||
parameter integer CHAIN = 1
|
||||
)(
|
||||
input wire clk_i,
|
||||
input wire rst_n_i,
|
||||
output reg [DATA_BITS-1:0] data_o
|
||||
);
|
||||
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;
|
||||
reg [DATA_BITS-1:0] shift_q;
|
||||
reg [DATA_BITS-1:0] data_jtag_q;
|
||||
reg update_toggle_jtag_q;
|
||||
reg update_toggle_meta_q;
|
||||
reg update_toggle_sync_q;
|
||||
reg update_toggle_sync_d_q;
|
||||
reg [DATA_BITS-1:0] data_meta_q;
|
||||
reg [DATA_BITS-1:0] data_sync_q;
|
||||
|
||||
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)
|
||||
wb_gpio #(
|
||||
.address(32'h00000000)
|
||||
) u_wb_gpio (
|
||||
.i_wb_clk(clk_15),
|
||||
.i_wb_rst(i_rst | cmd_reset),
|
||||
.i_wb_adr(wb_adr),
|
||||
.i_wb_dat(wb_dat),
|
||||
.i_wb_sel(wb_sel),
|
||||
.i_wb_we(wb_we),
|
||||
.i_wb_stb(wb_stb & wb_cyc),
|
||||
.i_gpio(gpio_in),
|
||||
.o_wb_rdt(wb_rdt),
|
||||
.o_wb_ack(wb_ack),
|
||||
.o_gpio(gpio)
|
||||
);
|
||||
|
||||
always @(posedge jtag_drck or posedge jtag_reset or negedge rst_n_i) begin
|
||||
if (!rst_n_i || jtag_reset) begin
|
||||
shift_q <= {DATA_BITS{1'b0}};
|
||||
end else if (jtag_sel && jtag_capture) begin
|
||||
shift_q <= data_jtag_q;
|
||||
end else if (jtag_sel && jtag_shift) begin
|
||||
if (DATA_BITS == 1) begin
|
||||
shift_q <= jtag_tdi;
|
||||
end else begin
|
||||
shift_q <= {jtag_tdi, shift_q[DATA_BITS-1:1]};
|
||||
end
|
||||
end
|
||||
end
|
||||
assign LED = gpio[7:0];
|
||||
assign r2r = gpio[13:8];
|
||||
assign led_green = gpio[30];
|
||||
assign led_red = gpio[31];
|
||||
|
||||
always @(posedge jtag_update or posedge jtag_reset or negedge rst_n_i) begin
|
||||
if (!rst_n_i || jtag_reset) begin
|
||||
data_jtag_q <= {DATA_BITS{1'b0}};
|
||||
update_toggle_jtag_q <= 1'b0;
|
||||
end else if (jtag_sel) begin
|
||||
data_jtag_q <= shift_q;
|
||||
update_toggle_jtag_q <= ~update_toggle_jtag_q;
|
||||
end
|
||||
end
|
||||
|
||||
// CDC into clk_i domain: toggle synchronize + stable data sampling.
|
||||
always @(posedge clk_i or negedge rst_n_i) begin
|
||||
if (!rst_n_i) begin
|
||||
update_toggle_meta_q <= 1'b0;
|
||||
update_toggle_sync_q <= 1'b0;
|
||||
update_toggle_sync_d_q <= 1'b0;
|
||||
data_meta_q <= {DATA_BITS{1'b0}};
|
||||
data_sync_q <= {DATA_BITS{1'b0}};
|
||||
data_o <= {DATA_BITS{1'b0}};
|
||||
end else begin
|
||||
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;
|
||||
data_meta_q <= data_jtag_q;
|
||||
data_sync_q <= data_meta_q;
|
||||
|
||||
if (update_toggle_sync_q ^ update_toggle_sync_d_q) begin
|
||||
data_o <= data_sync_q;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Not used for this simple write-register, but kept for completeness.
|
||||
wire _unused_tck;
|
||||
wire _unused_runtest;
|
||||
assign _unused_tck = jtag_tck;
|
||||
assign _unused_runtest = jtag_runtest;
|
||||
endmodule
|
||||
|
||||
196
rtl/wb/jtag_wb_bridge.v
Normal file
196
rtl/wb/jtag_wb_bridge.v
Normal file
@@ -0,0 +1,196 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module jtag_wb_bridge #(
|
||||
parameter integer chain = 1,
|
||||
// 0: Use cmd_addr[1:0] to select byte lane on 32-bit WB data bus.
|
||||
// 1: Always use lane 0 (LSB), for byte-wide memories that return data in [7:0].
|
||||
parameter integer byte_aligned = 0
|
||||
)(
|
||||
input wire i_clk,
|
||||
input wire i_rst,
|
||||
|
||||
output wire [31:0] o_wb_adr,
|
||||
output wire [31:0] o_wb_dat,
|
||||
output wire [3:0] o_wb_sel,
|
||||
output wire o_wb_we,
|
||||
output wire o_wb_cyc,
|
||||
output wire o_wb_stb,
|
||||
input wire [31:0] i_wb_rdt,
|
||||
input wire i_wb_ack,
|
||||
|
||||
output wire o_cmd_reset
|
||||
);
|
||||
// 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;
|
||||
|
||||
reg [41:0] jtag_q;
|
||||
wire [41:0] jtag_data_in;
|
||||
wire jtag_async_reset;
|
||||
|
||||
jtag_if #(
|
||||
.chain(chain)
|
||||
) jtag (
|
||||
.i_tdo(jtag_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)
|
||||
);
|
||||
|
||||
assign jtag_async_reset = jtag_reset || i_rst;
|
||||
|
||||
// JTAG shift register behavior
|
||||
always @(posedge jtag_drck or posedge jtag_async_reset) begin
|
||||
if (jtag_async_reset) begin
|
||||
jtag_q <= 42'b0;
|
||||
end else if (jtag_sel && jtag_capture) begin
|
||||
jtag_q <= jtag_data_in;
|
||||
end else if (jtag_sel && jtag_shift) begin
|
||||
jtag_q <= {jtag_tdi, jtag_q[41:1]};
|
||||
end
|
||||
end
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// JTAG -> i_clk crossing using toggle request/ack handshake.
|
||||
// Command packet format: [41]=we, [40]=reset, [39:8]=addr, [7:0]=wdata
|
||||
// -----------------------------------------------------------------------------
|
||||
reg [41:0] j_cmd_hold;
|
||||
reg j_req_tgl;
|
||||
reg j_ack_sync_1;
|
||||
reg j_ack_sync_2;
|
||||
|
||||
reg s_ack_tgl;
|
||||
reg s_req_sync_1;
|
||||
reg s_req_sync_2;
|
||||
reg s_req_sync_3;
|
||||
reg [41:0] s_cmd_sync_1;
|
||||
reg [41:0] s_cmd_sync_2;
|
||||
|
||||
always @(posedge jtag_drck or posedge jtag_async_reset) begin
|
||||
if (jtag_async_reset) begin
|
||||
j_ack_sync_1 <= 1'b0;
|
||||
j_ack_sync_2 <= 1'b0;
|
||||
end else begin
|
||||
j_ack_sync_1 <= s_ack_tgl;
|
||||
j_ack_sync_2 <= j_ack_sync_1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge jtag_update or posedge jtag_async_reset) begin
|
||||
if (jtag_async_reset) begin
|
||||
j_cmd_hold <= 42'b0;
|
||||
j_req_tgl <= 1'b0;
|
||||
end else if (jtag_sel && (j_ack_sync_2 == j_req_tgl)) begin
|
||||
j_cmd_hold <= jtag_q;
|
||||
j_req_tgl <= ~j_req_tgl;
|
||||
end
|
||||
end
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Wishbone classic single-request master (1 outstanding transaction max).
|
||||
// -----------------------------------------------------------------------------
|
||||
reg wb_busy;
|
||||
reg [31:0] wb_adr_r;
|
||||
reg [31:0] wb_dat_r;
|
||||
reg [3:0] wb_sel_r;
|
||||
reg wb_we_r;
|
||||
reg cmd_reset_pulse_r;
|
||||
reg [31:0] resp_addr_r;
|
||||
reg [7:0] resp_data_r;
|
||||
|
||||
wire req_pulse;
|
||||
wire [7:0] cmd_wdata;
|
||||
wire [31:0] cmd_addr;
|
||||
wire cmd_reset;
|
||||
wire cmd_we;
|
||||
wire [1:0] req_lane;
|
||||
wire [1:0] resp_lane;
|
||||
|
||||
assign req_pulse = s_req_sync_2 ^ s_req_sync_3;
|
||||
assign cmd_wdata = s_cmd_sync_2[7:0];
|
||||
assign cmd_addr = s_cmd_sync_2[39:8];
|
||||
assign cmd_reset = s_cmd_sync_2[40];
|
||||
assign cmd_we = s_cmd_sync_2[41];
|
||||
assign req_lane = byte_aligned ? 2'b00 : cmd_addr[1:0];
|
||||
assign resp_lane = byte_aligned ? 2'b00 : wb_adr_r[1:0];
|
||||
|
||||
assign o_wb_adr = wb_adr_r;
|
||||
assign o_wb_dat = wb_dat_r;
|
||||
assign o_wb_sel = wb_sel_r;
|
||||
assign o_wb_we = wb_we_r;
|
||||
assign o_wb_cyc = wb_busy;
|
||||
assign o_wb_stb = wb_busy;
|
||||
assign o_cmd_reset = cmd_reset_pulse_r;
|
||||
|
||||
always @(posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
s_ack_tgl <= 1'b0;
|
||||
s_req_sync_1 <= 1'b0;
|
||||
s_req_sync_2 <= 1'b0;
|
||||
s_req_sync_3 <= 1'b0;
|
||||
s_cmd_sync_1 <= 42'b0;
|
||||
s_cmd_sync_2 <= 42'b0;
|
||||
wb_busy <= 1'b0;
|
||||
wb_adr_r <= 32'b0;
|
||||
wb_dat_r <= 32'b0;
|
||||
wb_sel_r <= 4'b0000;
|
||||
wb_we_r <= 1'b0;
|
||||
cmd_reset_pulse_r <= 1'b0;
|
||||
resp_addr_r <= 32'b0;
|
||||
resp_data_r <= 8'b0;
|
||||
end else begin
|
||||
s_req_sync_1 <= j_req_tgl;
|
||||
s_req_sync_2 <= s_req_sync_1;
|
||||
s_req_sync_3 <= s_req_sync_2;
|
||||
s_cmd_sync_1 <= j_cmd_hold;
|
||||
s_cmd_sync_2 <= s_cmd_sync_1;
|
||||
cmd_reset_pulse_r <= 1'b0;
|
||||
|
||||
if (req_pulse && !wb_busy) begin
|
||||
wb_busy <= 1'b1;
|
||||
wb_we_r <= cmd_we;
|
||||
wb_adr_r <= cmd_addr;
|
||||
|
||||
case (req_lane)
|
||||
2'b00: begin wb_sel_r <= 4'b0001; wb_dat_r <= {24'b0, cmd_wdata}; end
|
||||
2'b01: begin wb_sel_r <= 4'b0010; wb_dat_r <= {16'b0, cmd_wdata, 8'b0}; end
|
||||
2'b10: begin wb_sel_r <= 4'b0100; wb_dat_r <= {8'b0, cmd_wdata, 16'b0}; end
|
||||
default: begin wb_sel_r <= 4'b1000; wb_dat_r <= {cmd_wdata, 24'b0}; end
|
||||
endcase
|
||||
|
||||
cmd_reset_pulse_r <= cmd_reset;
|
||||
end
|
||||
|
||||
if (wb_busy && i_wb_ack) begin
|
||||
wb_busy <= 1'b0;
|
||||
wb_we_r <= 1'b0;
|
||||
resp_addr_r <= wb_adr_r;
|
||||
|
||||
case (resp_lane)
|
||||
2'b00: resp_data_r <= i_wb_rdt[7:0];
|
||||
2'b01: resp_data_r <= i_wb_rdt[15:8];
|
||||
2'b10: resp_data_r <= i_wb_rdt[23:16];
|
||||
default: resp_data_r <= i_wb_rdt[31:24];
|
||||
endcase
|
||||
|
||||
s_ack_tgl <= s_req_sync_2;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign jtag_data_in = {2'b00, resp_addr_r, resp_data_r};
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user