rtl: jtag: optimization
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/1/head
parent
442e9e8f5c
commit
045f482fe1
|
@ -24,70 +24,67 @@
|
|||
`define DTM_OP_WRITE 2'b10
|
||||
|
||||
|
||||
module jtag_dm(
|
||||
module jtag_dm #(
|
||||
parameter DMI_ADDR_BITS = 6,
|
||||
parameter DMI_DATA_BITS = 32,
|
||||
parameter DMI_OP_BITS = 2)(
|
||||
|
||||
clk,
|
||||
rst_n,
|
||||
dtm_req_valid,
|
||||
dtm_req_data,
|
||||
dtm_req_valid_i,
|
||||
dtm_req_data_i,
|
||||
|
||||
dm_is_busy,
|
||||
dm_resp_data,
|
||||
dm_is_busy_o,
|
||||
dm_resp_data_o,
|
||||
dm_resp_ready_i,
|
||||
|
||||
dm_reg_we,
|
||||
dm_reg_addr,
|
||||
dm_reg_wdata,
|
||||
dm_reg_rdata,
|
||||
dm_mem_we,
|
||||
dm_mem_addr,
|
||||
dm_mem_wdata,
|
||||
dm_mem_rdata,
|
||||
dm_op_req,
|
||||
dm_reg_we_o,
|
||||
dm_reg_addr_o,
|
||||
dm_reg_wdata_o,
|
||||
dm_reg_rdata_i,
|
||||
dm_mem_we_o,
|
||||
dm_mem_addr_o,
|
||||
dm_mem_wdata_o,
|
||||
dm_mem_rdata_i,
|
||||
dm_op_req_o,
|
||||
|
||||
dm_halt_req,
|
||||
dm_reset_req
|
||||
dm_halt_req_o,
|
||||
dm_reset_req_o
|
||||
|
||||
);
|
||||
|
||||
parameter DMI_ADDR_BITS = 6;
|
||||
parameter DMI_DATA_BITS = 32;
|
||||
parameter DMI_OP_BITS = 2;
|
||||
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
||||
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
||||
parameter SHIFT_REG_BITS = DTM_REQ_BITS;
|
||||
|
||||
// input and output
|
||||
// 输入输出信号
|
||||
input wire clk;
|
||||
input wire rst_n;
|
||||
input wire dtm_req_valid;
|
||||
input wire[DTM_REQ_BITS - 1:0] dtm_req_data;
|
||||
output reg dm_is_busy;
|
||||
output reg[DM_RESP_BITS - 1:0] dm_resp_data;
|
||||
output reg dm_reg_we;
|
||||
output reg[4:0] dm_reg_addr;
|
||||
output reg[31:0] dm_reg_wdata;
|
||||
input wire[31:0] dm_reg_rdata;
|
||||
output reg dm_mem_we;
|
||||
output reg[31:0] dm_mem_addr;
|
||||
output reg[31:0] dm_mem_wdata;
|
||||
input wire[31:0] dm_mem_rdata;
|
||||
output reg dm_op_req;
|
||||
output reg dm_halt_req;
|
||||
output reg dm_reset_req;
|
||||
input wire dtm_req_valid_i;
|
||||
input wire[DTM_REQ_BITS-1:0] dtm_req_data_i;
|
||||
output wire dm_is_busy_o;
|
||||
output wire[DM_RESP_BITS-1:0] dm_resp_data_o;
|
||||
output wire dm_reg_we_o;
|
||||
output wire[4:0] dm_reg_addr_o;
|
||||
output wire[31:0] dm_reg_wdata_o;
|
||||
input wire[31:0] dm_reg_rdata_i;
|
||||
output wire dm_mem_we_o;
|
||||
output wire[31:0] dm_mem_addr_o;
|
||||
output wire[31:0] dm_mem_wdata_o;
|
||||
input wire[31:0] dm_mem_rdata_i;
|
||||
output wire dm_op_req_o;
|
||||
output wire dm_halt_req_o;
|
||||
output wire dm_reset_req_o;
|
||||
input wire dm_resp_ready_i;
|
||||
|
||||
localparam STATE_IDLE = 2'b0;
|
||||
localparam STATE_EX = 2'b1;
|
||||
localparam STATE_IDLE = 3'b001;
|
||||
localparam STATE_EXE = 3'b010;
|
||||
localparam STATE_RESP = 3'b100;
|
||||
|
||||
reg[1:0] state;
|
||||
reg[DMI_OP_BITS - 1:0] op;
|
||||
reg[DMI_DATA_BITS - 1:0] data;
|
||||
reg[DMI_ADDR_BITS - 1:0] address;
|
||||
reg[DTM_REQ_BITS - 1:0] req_data;
|
||||
reg is_halted;
|
||||
reg is_reseted;
|
||||
reg is_read_reg;
|
||||
reg[2:0] state;
|
||||
reg[2:0] state_next;
|
||||
|
||||
// DM regs
|
||||
// DM模块寄存器
|
||||
reg[31:0] dcsr;
|
||||
reg[31:0] dmstatus;
|
||||
reg[31:0] dmcontrol;
|
||||
|
@ -99,6 +96,7 @@ module jtag_dm(
|
|||
reg[31:0] sbdata0;
|
||||
reg[31:0] command;
|
||||
|
||||
// DM模块寄存器地址
|
||||
localparam DCSR = 16'h7b0;
|
||||
localparam DMSTATUS = 6'h11;
|
||||
localparam DMCONTROL = 6'h10;
|
||||
|
@ -113,254 +111,434 @@ module jtag_dm(
|
|||
|
||||
localparam OP_SUCC = 2'b00;
|
||||
|
||||
|
||||
// 当前状态切换
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state <= STATE_IDLE;
|
||||
dm_mem_we <= 1'b0;
|
||||
dm_reg_we <= 1'b0;
|
||||
dm_resp_data <= {(DM_RESP_BITS){1'b0}};
|
||||
dm_is_busy <= 1'b0;
|
||||
dm_halt_req <= 1'b0;
|
||||
dm_reset_req <= 1'b0;
|
||||
dm_mem_addr <= 32'h0;
|
||||
dm_reg_addr <= 5'h0;
|
||||
is_halted <= 1'b0;
|
||||
is_reseted <= 1'b0;
|
||||
dm_op_req <= 1'b0;
|
||||
op <= 2'h0;
|
||||
data <= 32'h0;
|
||||
sbaddress0 <= 32'h0;
|
||||
dcsr <= 32'h0;
|
||||
hartinfo <= 32'h0;
|
||||
sbcs <= 32'h0;
|
||||
dmcontrol <= 32'h0;
|
||||
abstractcs <= 32'h0;
|
||||
data0 <= 32'h0;
|
||||
sbdata0 <= 32'h0;
|
||||
command <= 32'h0;
|
||||
dm_reg_wdata <= 32'h0;
|
||||
dm_mem_wdata <= 32'h0;
|
||||
address <= 6'h0;
|
||||
dmstatus <= 32'h0;
|
||||
is_read_reg <= 1'b0;
|
||||
end else begin
|
||||
if (state == STATE_IDLE) begin
|
||||
dm_mem_we <= 1'b0;
|
||||
dm_reg_we <= 1'b0;
|
||||
dm_reset_req <= 1'b0;
|
||||
if (dtm_req_valid == `DTM_REQ_VALID) begin
|
||||
state <= STATE_EX;
|
||||
op <= dtm_req_data[DMI_OP_BITS - 1:0];
|
||||
data <= dtm_req_data[DMI_DATA_BITS + DMI_OP_BITS - 1:DMI_OP_BITS];
|
||||
address <= dtm_req_data[DTM_REQ_BITS - 1:DMI_DATA_BITS + DMI_OP_BITS];
|
||||
req_data <= dtm_req_data;
|
||||
dm_is_busy <= 1'b1;
|
||||
if ((dtm_req_data[DMI_OP_BITS - 1:0] == `DTM_OP_READ &&
|
||||
dtm_req_data[DTM_REQ_BITS - 1:DMI_DATA_BITS + DMI_OP_BITS] == DMSTATUS) ||
|
||||
(dtm_req_data[DMI_OP_BITS - 1:0] == `DTM_OP_NOP)) begin
|
||||
state <= state_next;
|
||||
end
|
||||
end
|
||||
|
||||
// 下一个状态切换
|
||||
always @ (*) begin
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (dtm_req_valid_i == `DTM_REQ_VALID) begin
|
||||
state_next = STATE_EXE;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_EXE: begin
|
||||
if (access_core) begin
|
||||
state_next = STATE_RESP;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_RESP: begin
|
||||
if (dm_resp_ready_i == 1'b1) begin
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
state_next = STATE_RESP;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
reg[31:0] mem_rdata;
|
||||
reg[31:0] reg_rdata;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mem_rdata <= 32'h0;
|
||||
reg_rdata <= 32'h0;
|
||||
end else begin
|
||||
if (state == STATE_RESP && dm_resp_ready_i == 1'b1) begin
|
||||
mem_rdata <= dm_mem_rdata_i;
|
||||
reg_rdata <= dm_reg_rdata_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg[DTM_REQ_BITS-1:0] dtm_req_data;
|
||||
|
||||
// 锁存jtag_dirver模块传过来的数据
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dtm_req_data <= {DTM_REQ_BITS{1'b0}};
|
||||
end else begin
|
||||
if ((state == STATE_IDLE) && (dtm_req_valid_i == `DTM_REQ_VALID)) begin
|
||||
dtm_req_data <= dtm_req_data_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire[DMI_OP_BITS-1:0] op = dtm_req_data[DMI_OP_BITS-1:0];
|
||||
wire[DMI_DATA_BITS-1:0] data = dtm_req_data[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
|
||||
wire[DMI_ADDR_BITS-1:0] address = dtm_req_data[DTM_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
|
||||
|
||||
wire op_write = (op == `DTM_OP_WRITE);
|
||||
wire op_read = (op == `DTM_OP_READ);
|
||||
wire op_nop = (op == `DTM_OP_NOP);
|
||||
wire access_dmstatus = (address == DMSTATUS);
|
||||
wire access_dmcontrol = (address == DMCONTROL);
|
||||
wire access_hartinfo = (address == HARTINFO);
|
||||
wire access_abstractcs = (address == ABSTRACTCS);
|
||||
wire access_data0 = (address == DATA0);
|
||||
wire access_sbcs = (address == SBCS);
|
||||
wire access_sbaddress0 = (address == SBADDRESS0);
|
||||
wire access_sbdata0 = (address == SBDATA0);
|
||||
wire access_command = (address == COMMAND);
|
||||
|
||||
wire access_core = (~op_nop) & (~access_dmcontrol) & (~access_dmstatus) & (~access_hartinfo);
|
||||
|
||||
reg dm_op_req;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dm_op_req <= 1'b0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (access_core) begin
|
||||
dm_op_req <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
end
|
||||
STATE_IDLE: begin
|
||||
dm_op_req <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign dm_op_req_o = dm_op_req;
|
||||
|
||||
reg[31:0] rdata;
|
||||
// 返回数据给jtag driver模块
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rdata <= 32'h0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
case (op)
|
||||
`DTM_OP_READ: begin
|
||||
case (address)
|
||||
DMSTATUS: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {address, dmstatus, OP_SUCC};
|
||||
rdata <= dmstatus;
|
||||
end
|
||||
|
||||
DMCONTROL: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {address, dmcontrol, OP_SUCC};
|
||||
rdata <= dmcontrol;
|
||||
end
|
||||
|
||||
HARTINFO: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {address, hartinfo, OP_SUCC};
|
||||
rdata <= 32'h0;
|
||||
end
|
||||
|
||||
SBCS: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {address, sbcs, OP_SUCC};
|
||||
rdata <= sbcs;
|
||||
end
|
||||
|
||||
ABSTRACTCS: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {address, abstractcs, OP_SUCC};
|
||||
rdata <= abstractcs;
|
||||
end
|
||||
|
||||
DATA0: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
if (is_read_reg == 1'b1) begin
|
||||
dm_resp_data <= {address, dm_reg_rdata, OP_SUCC};
|
||||
rdata <= reg_rdata;
|
||||
end else begin
|
||||
dm_resp_data <= {address, data0, OP_SUCC};
|
||||
rdata <= data0;
|
||||
end
|
||||
is_read_reg <= 1'b0;
|
||||
end
|
||||
|
||||
SBDATA0: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {address, dm_mem_rdata, OP_SUCC};
|
||||
if (sbcs[16] == 1'b1) begin
|
||||
sbaddress0 <= sbaddress0 + 4;
|
||||
rdata <= mem_rdata;
|
||||
end
|
||||
if (sbcs[15] == 1'b1) begin
|
||||
dm_mem_addr <= sbaddress0 + 4;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
rdata <= 32'h0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
default: begin
|
||||
rdata <= 32'h0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
`DTM_OP_WRITE: begin
|
||||
case (address)
|
||||
DMCONTROL: begin
|
||||
// reset DM module
|
||||
if (data[0] == 1'b0) begin
|
||||
dcsr <= 32'hc0;
|
||||
dmstatus <= 32'h430c82; // not halted, all running
|
||||
hartinfo <= 32'h0;
|
||||
sbcs <= 32'h20040404;
|
||||
abstractcs <= 32'h1000003;
|
||||
assign dm_resp_data_o = {address, rdata, OP_SUCC};
|
||||
|
||||
wire dm_reset = (state == STATE_EXE) & op_write & (access_dmcontrol) & (data[0] == 1'b0);
|
||||
|
||||
// dmcontrol
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dmcontrol <= 32'h0;
|
||||
end else if (dm_reset) begin
|
||||
dmcontrol <= data;
|
||||
dm_halt_req <= 1'b0;
|
||||
dm_reset_req <= 1'b0;
|
||||
is_halted <= 1'b0;
|
||||
is_reseted <= 1'b0;
|
||||
// DM is active
|
||||
end else begin
|
||||
// we have only one hart
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_dmcontrol) begin
|
||||
dmcontrol <= (data & ~(32'h3fffc0)) | 32'h10000;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// dmstatus
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
dmstatus <= 32'h430c82; // not halted, all running
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_dmcontrol) begin
|
||||
// halt
|
||||
if (data[31] == 1'b1) begin
|
||||
dm_halt_req <= 1'b1;
|
||||
is_halted <= 1'b1;
|
||||
// clear ALLRUNNING ANYRUNNING and set ALLHALTED
|
||||
dmstatus <= {dmstatus[31:12], 4'h3, dmstatus[7:0]};
|
||||
// resume
|
||||
end else if (is_halted == 1'b1 && data[30] == 1'b1) begin
|
||||
dm_halt_req <= 1'b0;
|
||||
is_halted <= 1'b0;
|
||||
end else if (dm_halt_req == 1'b1 && data[30] == 1'b1) begin
|
||||
// set ALLRUNNING ANYRUNNING and clear ALLHALTED
|
||||
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
|
||||
end
|
||||
end else if (core_reset) begin
|
||||
// set ALLRUNNING ANYRUNNING and clear ALLHALTED
|
||||
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
|
||||
end
|
||||
end
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
COMMAND: begin
|
||||
// access reg
|
||||
if (data[31:24] == 8'h0) begin
|
||||
wire access_reg = (data[31:24] == 8'h0);
|
||||
|
||||
// command
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
abstractcs <= 32'h1000003;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_command & access_reg) begin
|
||||
if (data[22:20] > 3'h2) begin
|
||||
abstractcs <= abstractcs | (1'b1 << 9);
|
||||
abstractcs <= abstractcs | 32'h200;
|
||||
end else begin
|
||||
abstractcs <= abstractcs & (~(3'h7 << 8));
|
||||
// read or write
|
||||
if (data[18] == 1'b0) begin
|
||||
// read
|
||||
if (data[16] == 1'b0) begin
|
||||
if (data[15:0] == DCSR) begin
|
||||
data0 <= dcsr;
|
||||
end else if (data[15:0] < 16'h1020) begin
|
||||
dm_reg_addr <= data[15:0] - 16'h1000;
|
||||
is_read_reg <= 1'b1;
|
||||
end
|
||||
// write
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// data0
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
data0 <= 32'h0;
|
||||
end else begin
|
||||
// when write dpc, we reset cpu here
|
||||
if (data[15:0] == DPC) begin
|
||||
dm_reset_req <= 1'b1;
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_data0) begin
|
||||
data0 <= data;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// sbcs
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
sbcs <= 32'h20040404;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_sbcs) begin
|
||||
sbcs <= data;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// sbaddress0
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
sbaddress0 <= 32'h0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_sbaddress0) begin
|
||||
sbaddress0 <= data;
|
||||
end
|
||||
if ((op_write | op_read) & access_sbdata0 & (sbcs[16] == 1'b1)) begin
|
||||
sbaddress0 <= sbaddress0 + 4;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// sbdata0
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
sbdata0 <= 32'h0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_sbdata0) begin
|
||||
sbdata0 <= data;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
reg dm_halt_req;
|
||||
|
||||
// dm_halt_req
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
dm_halt_req <= 1'b0;
|
||||
is_halted <= 1'b0;
|
||||
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
|
||||
end else if (data[15:0] < 16'h1020) begin
|
||||
dm_reg_we <= 1'b1;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_dmcontrol) begin
|
||||
// halt
|
||||
if (data[31] == 1'b1) begin
|
||||
dm_halt_req <= 1'b1;
|
||||
// resume
|
||||
end else if ((dm_halt_req == 1'b1) && (data[30] == 1'b1)) begin
|
||||
dm_halt_req <= 1'b0;
|
||||
end
|
||||
end else if (core_reset) begin
|
||||
dm_halt_req <= 1'b0;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign dm_halt_req_o = dm_halt_req;
|
||||
|
||||
wire core_reset = (state == STATE_EXE) & op_write & access_command & access_reg & (data[22:20] <= 3'h2) &
|
||||
(data[18] == 1'b0) & (data[16] == 1'b1) & (data[15:0] == DPC);
|
||||
|
||||
assign dm_reset_req_o = core_reset;
|
||||
|
||||
reg[31:0] dm_mem_addr;
|
||||
reg[31:0] dm_mem_wdata;
|
||||
reg dm_mem_we;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
dm_mem_addr <= 32'h0;
|
||||
dm_mem_wdata <= 32'h0;
|
||||
dm_mem_we <= 1'b0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write) begin
|
||||
case (address)
|
||||
SBDATA0: begin
|
||||
dm_mem_addr <= sbaddress0;
|
||||
dm_mem_wdata <= data;
|
||||
dm_mem_we <= 1'b1;
|
||||
end
|
||||
SBADDRESS0: begin
|
||||
if (sbcs[20] == 1'b1) begin
|
||||
dm_mem_addr <= data;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end else if (op_read) begin
|
||||
if (access_sbdata0 & (sbcs[15] == 1'b1)) begin
|
||||
dm_mem_addr <= sbaddress0 + 4;
|
||||
end
|
||||
end
|
||||
end
|
||||
STATE_IDLE: begin
|
||||
dm_mem_we <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign dm_mem_addr_o = dm_mem_addr;
|
||||
assign dm_mem_wdata_o = dm_mem_wdata;
|
||||
assign dm_mem_we_o = dm_mem_we;
|
||||
|
||||
reg dm_reg_we;
|
||||
reg[4:0] dm_reg_addr;
|
||||
reg[31:0] dm_reg_wdata;
|
||||
reg is_read_reg;
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n | dm_reset) begin
|
||||
dm_reg_we <= 1'b0;
|
||||
dm_reg_addr <= 5'h0;
|
||||
dm_reg_wdata <= 32'h0;
|
||||
is_read_reg <= 1'b0;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_EXE: begin
|
||||
if (op_write & access_command) begin
|
||||
// 访问寄存器
|
||||
if (access_reg & (data[22:20] <= 3'h2)) begin
|
||||
// 读或写, 目前只支持通用寄存器读写
|
||||
if ((data[18] == 1'b0) & (data[15:0] < 16'h1020) & (data[15:0] != DPC)) begin
|
||||
dm_reg_addr <= data[15:0] - 16'h1000;
|
||||
// 读
|
||||
if (data[16] == 1'b0) begin
|
||||
is_read_reg <= 1'b1;
|
||||
// 写
|
||||
end else begin
|
||||
dm_reg_we <= 1'b1;
|
||||
dm_reg_wdata <= data0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else if (op_read & access_data0) begin
|
||||
is_read_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
end
|
||||
|
||||
DATA0: begin
|
||||
data0 <= data;
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
end
|
||||
|
||||
SBCS: begin
|
||||
sbcs <= data;
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
end
|
||||
|
||||
SBADDRESS0: begin
|
||||
sbaddress0 <= data;
|
||||
if (sbcs[20] == 1'b1) begin
|
||||
dm_mem_addr <= data;
|
||||
end
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
end
|
||||
|
||||
SBDATA0: begin
|
||||
sbdata0 <= data;
|
||||
dm_mem_addr <= sbaddress0;
|
||||
dm_mem_wdata <= data;
|
||||
dm_mem_we <= 1'b1;
|
||||
if (sbcs[16] == 1'b1) begin
|
||||
sbaddress0 <= sbaddress0 + 4;
|
||||
end
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
end
|
||||
|
||||
default: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
`DTM_OP_NOP: begin
|
||||
dm_is_busy <= 1'b0;
|
||||
state <= STATE_IDLE;
|
||||
dm_resp_data <= {{address}, {(DMI_DATA_BITS){1'b0}}, OP_SUCC};
|
||||
STATE_IDLE: begin
|
||||
dm_reg_we <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign dm_reg_we_o = dm_reg_we;
|
||||
assign dm_reg_addr_o = dm_reg_addr;
|
||||
assign dm_reg_wdata_o = dm_reg_wdata;
|
||||
|
||||
assign dm_is_busy_o = (state != STATE_IDLE);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
`define DTM_REQ_INVALID 1'b0
|
||||
|
||||
|
||||
module jtag_driver(
|
||||
module jtag_driver #(
|
||||
parameter DMI_ADDR_BITS = 6,
|
||||
parameter DMI_DATA_BITS = 32,
|
||||
parameter DMI_OP_BITS = 2)(
|
||||
|
||||
rst_n,
|
||||
|
||||
|
@ -43,9 +46,6 @@ module jtag_driver(
|
|||
parameter DTM_VERSION = 4'h1;
|
||||
parameter IR_BITS = 5;
|
||||
|
||||
parameter DMI_ADDR_BITS = 6;
|
||||
parameter DMI_DATA_BITS = 32;
|
||||
parameter DMI_OP_BITS = 2;
|
||||
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
||||
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
||||
parameter SHIFT_REG_BITS = DTM_REQ_BITS;
|
||||
|
@ -171,7 +171,7 @@ module jtag_driver(
|
|||
always @(posedge jtag_TCK or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dtm_req_valid <= `DTM_REQ_INVALID;
|
||||
dtm_req_data <= 40'h0;
|
||||
dtm_req_data <= {DTM_REQ_BITS{1'b0}};
|
||||
end else begin
|
||||
if (jtag_state == UPDATE_DR) begin
|
||||
if (ir_reg == REG_DMI) begin
|
||||
|
@ -227,5 +227,4 @@ module jtag_driver(
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
`include "../core/defines.v"
|
||||
|
||||
// JTAG顶层模块
|
||||
// 涉及跨时钟域传输,这里采用打两拍的方式进行同步
|
||||
module jtag_top(
|
||||
module jtag_top #(
|
||||
parameter DMI_ADDR_BITS = 6,
|
||||
parameter DMI_DATA_BITS = 32,
|
||||
parameter DMI_OP_BITS = 2)(
|
||||
|
||||
input wire clk,
|
||||
|
||||
input wire jtag_rst_n,
|
||||
|
||||
input wire jtag_pin_TCK,
|
||||
|
@ -29,24 +30,21 @@ module jtag_top(
|
|||
input wire jtag_pin_TDI,
|
||||
output wire jtag_pin_TDO,
|
||||
|
||||
output reg reg_we_o,
|
||||
output wire reg_we_o,
|
||||
output wire[4:0] reg_addr_o,
|
||||
output wire[31:0] reg_wdata_o,
|
||||
input wire[31:0] reg_rdata_i,
|
||||
output reg mem_we_o,
|
||||
output wire mem_we_o,
|
||||
output wire[31:0] mem_addr_o,
|
||||
output wire[31:0] mem_wdata_o,
|
||||
input wire[31:0] mem_rdata_i,
|
||||
output wire op_req_o,
|
||||
|
||||
output reg halt_req_o,
|
||||
output reg reset_req_o
|
||||
output wire halt_req_o,
|
||||
output wire reset_req_o
|
||||
|
||||
);
|
||||
|
||||
parameter DMI_ADDR_BITS = 6;
|
||||
parameter DMI_DATA_BITS = 32;
|
||||
parameter DMI_OP_BITS = 2;
|
||||
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
||||
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
|
||||
|
||||
|
@ -63,59 +61,69 @@ module jtag_top(
|
|||
wire dm_mem_we_o;
|
||||
wire[31:0] dm_mem_addr_o;
|
||||
wire[31:0] dm_mem_wdata_o;
|
||||
wire dm_op_req_o;
|
||||
wire dm_op_req_sync;
|
||||
wire dm_halt_req_o;
|
||||
wire dm_reset_req_o;
|
||||
wire dm_resp_ready;
|
||||
wire halt_req_sync;
|
||||
wire reset_req_sync;
|
||||
|
||||
reg tmp_reg_we_o;
|
||||
reg[4:0] tmp_reg_addr_o;
|
||||
reg[31:0] tmp_reg_wdata_o;
|
||||
reg tmp_mem_we_o;
|
||||
reg[31:0] tmp_mem_addr_o;
|
||||
reg[31:0] tmp_mem_wdata_o;
|
||||
reg tmp_op_req_o;
|
||||
reg tmp_halt_req_o;
|
||||
reg tmp_reset_req_o;
|
||||
assign reg_addr_o = dm_op_req_sync? dm_reg_addr_o: 5'h0;
|
||||
assign reg_wdata_o = dm_op_req_sync? dm_reg_wdata_o: 32'h0;
|
||||
assign reg_we_o = dm_op_req_sync? dm_reg_we_o: 1'b0;
|
||||
assign mem_addr_o = dm_op_req_sync? dm_mem_addr_o: 32'h0;
|
||||
assign mem_wdata_o = dm_op_req_sync? dm_mem_wdata_o: 32'h0;
|
||||
assign mem_we_o = dm_op_req_sync? dm_mem_we_o: 1'b0;
|
||||
assign halt_req_o = halt_req_sync;
|
||||
assign reset_req_o = reset_req_sync;
|
||||
|
||||
assign op_req_o = dm_op_req_sync;
|
||||
|
||||
assign reg_addr_o = dm_reg_addr_o;
|
||||
assign reg_wdata_o = dm_reg_wdata_o;
|
||||
assign mem_addr_o = dm_mem_addr_o;
|
||||
assign mem_wdata_o = dm_mem_wdata_o;
|
||||
assign op_req_o = dm_op_req_o;
|
||||
gen_ticks_sync #(
|
||||
.DW(1),
|
||||
.DP(2)
|
||||
) u_halt_sync_o(
|
||||
.rst(jtag_rst_n),
|
||||
.clk(clk),
|
||||
.din(dm_halt_req_o),
|
||||
.dout(halt_req_sync)
|
||||
);
|
||||
|
||||
gen_ticks_sync #(
|
||||
.DW(1),
|
||||
.DP(2)
|
||||
) u_reset_sync_o(
|
||||
.rst(jtag_rst_n),
|
||||
.clk(clk),
|
||||
.din(dm_reset_req_o),
|
||||
.dout(reset_req_sync)
|
||||
);
|
||||
|
||||
// 打第一拍
|
||||
always @ (posedge clk) begin
|
||||
if (!jtag_rst_n) begin
|
||||
tmp_reg_we_o <= `WriteDisable;
|
||||
tmp_mem_we_o <= `WriteDisable;
|
||||
tmp_halt_req_o <= 1'b0;
|
||||
tmp_reset_req_o <= 1'b0;
|
||||
end else begin
|
||||
tmp_reg_we_o <= dm_reg_we_o;
|
||||
tmp_mem_we_o <= dm_mem_we_o;
|
||||
tmp_halt_req_o <= dm_halt_req_o;
|
||||
tmp_reset_req_o <= dm_reset_req_o;
|
||||
end
|
||||
end
|
||||
gen_ticks_sync #(
|
||||
.DW(1),
|
||||
.DP(2)
|
||||
) u_jtag_sync_o(
|
||||
.rst(jtag_rst_n),
|
||||
.clk(clk),
|
||||
.din(dm_op_req_o),
|
||||
.dout(dm_op_req_sync)
|
||||
);
|
||||
|
||||
// 打第二拍
|
||||
always @ (posedge clk) begin
|
||||
if (!jtag_rst_n) begin
|
||||
reg_we_o <= `WriteDisable;
|
||||
mem_we_o <= `WriteDisable;
|
||||
halt_req_o <= 1'b0;
|
||||
reset_req_o <= 1'b0;
|
||||
end else begin
|
||||
reg_we_o <= tmp_reg_we_o;
|
||||
mem_we_o <= tmp_mem_we_o;
|
||||
halt_req_o <= tmp_halt_req_o;
|
||||
reset_req_o <= tmp_reset_req_o;
|
||||
end
|
||||
end
|
||||
gen_ticks_sync #(
|
||||
.DW(1),
|
||||
.DP(2)
|
||||
) u_jtag_sync_i(
|
||||
.rst(jtag_rst_n),
|
||||
.clk(jtag_pin_TCK),
|
||||
.din(dm_op_req_sync),
|
||||
.dout(dm_resp_ready)
|
||||
);
|
||||
|
||||
jtag_driver u_jtag_driver(
|
||||
jtag_driver #(
|
||||
.DMI_ADDR_BITS(DMI_ADDR_BITS),
|
||||
.DMI_DATA_BITS(DMI_DATA_BITS),
|
||||
.DMI_OP_BITS(DMI_OP_BITS)
|
||||
) u_jtag_driver(
|
||||
.rst_n(jtag_rst_n),
|
||||
.jtag_TCK(jtag_pin_TCK),
|
||||
.jtag_TDI(jtag_pin_TDI),
|
||||
|
@ -127,24 +135,29 @@ module jtag_top(
|
|||
.dtm_req_data(dtm_req_data)
|
||||
);
|
||||
|
||||
jtag_dm u_jtag_dm(
|
||||
jtag_dm #(
|
||||
.DMI_ADDR_BITS(DMI_ADDR_BITS),
|
||||
.DMI_DATA_BITS(DMI_DATA_BITS),
|
||||
.DMI_OP_BITS(DMI_OP_BITS)
|
||||
) u_jtag_dm(
|
||||
.clk(jtag_pin_TCK),
|
||||
.rst_n(jtag_rst_n),
|
||||
.dtm_req_valid(dtm_req_valid),
|
||||
.dtm_req_data(dtm_req_data),
|
||||
.dm_is_busy(dm_is_busy),
|
||||
.dm_resp_data(dm_resp_data),
|
||||
.dm_reg_we(dm_reg_we_o),
|
||||
.dm_reg_addr(dm_reg_addr_o),
|
||||
.dm_reg_wdata(dm_reg_wdata_o),
|
||||
.dm_reg_rdata(reg_rdata_i),
|
||||
.dm_mem_we(dm_mem_we_o),
|
||||
.dm_mem_addr(dm_mem_addr_o),
|
||||
.dm_mem_wdata(dm_mem_wdata_o),
|
||||
.dm_mem_rdata(mem_rdata_i),
|
||||
.dm_op_req(dm_op_req_o),
|
||||
.dm_halt_req(dm_halt_req_o),
|
||||
.dm_reset_req(dm_reset_req_o)
|
||||
.dm_resp_ready_i(dm_resp_ready),
|
||||
.dtm_req_valid_i(dtm_req_valid),
|
||||
.dtm_req_data_i(dtm_req_data),
|
||||
.dm_is_busy_o(dm_is_busy),
|
||||
.dm_resp_data_o(dm_resp_data),
|
||||
.dm_reg_we_o(dm_reg_we_o),
|
||||
.dm_reg_addr_o(dm_reg_addr_o),
|
||||
.dm_reg_wdata_o(dm_reg_wdata_o),
|
||||
.dm_reg_rdata_i(reg_rdata_i),
|
||||
.dm_mem_we_o(dm_mem_we_o),
|
||||
.dm_mem_addr_o(dm_mem_addr_o),
|
||||
.dm_mem_wdata_o(dm_mem_wdata_o),
|
||||
.dm_mem_rdata_i(mem_rdata_i),
|
||||
.dm_op_req_o(dm_op_req_o),
|
||||
.dm_halt_req_o(dm_halt_req_o),
|
||||
.dm_reset_req_o(dm_reset_req_o)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -116,8 +116,6 @@ module tinyriscv_soc_top(
|
|||
// jtag
|
||||
wire jtag_halt_req_o;
|
||||
wire jtag_reset_req_o;
|
||||
reg jtag_rst;
|
||||
reg[2:0] jtag_rst_cnt;
|
||||
wire[`RegAddrBus] jtag_reg_addr_o;
|
||||
wire[`RegBus] jtag_reg_data_o;
|
||||
wire jtag_reg_we_o;
|
||||
|
@ -337,25 +335,14 @@ module tinyriscv_soc_top(
|
|||
.mem_rdata_i(m3_data_o)
|
||||
);
|
||||
|
||||
// jtag模块复位逻辑
|
||||
always @ (posedge clk) begin
|
||||
if (rst == `RstEnable) begin
|
||||
jtag_rst <= 1'b1;
|
||||
jtag_rst_cnt <= 3'h0;
|
||||
end else begin
|
||||
if (jtag_rst_cnt < 3'h5) begin
|
||||
jtag_rst <= ~jtag_rst;
|
||||
jtag_rst_cnt <= jtag_rst_cnt + 1'b1;
|
||||
end else begin
|
||||
jtag_rst <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// jtag模块例化
|
||||
jtag_top u_jtag_top(
|
||||
jtag_top #(
|
||||
.DMI_ADDR_BITS(6),
|
||||
.DMI_DATA_BITS(32),
|
||||
.DMI_OP_BITS(2)
|
||||
) u_jtag_top(
|
||||
.clk(clk),
|
||||
.jtag_rst_n(jtag_rst),
|
||||
.jtag_rst_n(rst),
|
||||
.jtag_pin_TCK(jtag_TCK),
|
||||
.jtag_pin_TMS(jtag_TMS),
|
||||
.jtag_pin_TDI(jtag_TDI),
|
||||
|
|
Loading…
Reference in New Issue