temp commit

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-04-25 17:14:09 +08:00
parent 462cc4c786
commit ec65381ba9
30 changed files with 2614 additions and 2045 deletions

View File

@ -1,11 +1,11 @@
+incdir+../rtl/core
+incdir+../rtl/debug
../rtl/core/clint.sv
../rtl/core/csr_reg.sv
../rtl/core/csr.sv
../rtl/core/defines.sv
../rtl/core/divider.sv
../rtl/core/exception.sv
../rtl/core/exu.sv
../rtl/core/exu_alu_datapath.sv
../rtl/core/exu_commit.sv
@ -22,9 +22,15 @@
../rtl/core/tinyriscv_core.sv
../rtl/core/tracer.sv
../rtl/debug/jtag_def.sv
../rtl/debug/jtag_tap.sv
../rtl/debug/jtag_dtm.sv
../rtl/debug/jtag_dmi.sv
../rtl/debug/jtag_dm.sv
../rtl/debug/jtag_driver.sv
../rtl/debug/jtag_mem.sv
../rtl/debug/jtag_sba.sv
../rtl/debug/jtag_top.sv
../rtl/debug/debug_rom.sv
../rtl/perips/gpio.sv
../rtl/perips/ram.sv
@ -32,18 +38,13 @@
../rtl/perips/timer.sv
../rtl/perips/uart.sv
../rtl/sys_bus/rib.sv
../rtl/sys_bus/obi_interconnect.sv
../rtl/sys_bus/obi_interconnect_master_sel.sv
../rtl/sys_bus/obi_interconnect_slave_sel.sv
../rtl/top/tinyriscv_soc_top.sv
../rtl/utils/full_handshake_rx.sv
../rtl/utils/full_handshake_tx.sv
../rtl/utils/gen_buf.sv
../rtl/utils/gen_dff.sv
../rtl/utils/gen_ram.sv
../rtl/utils/vld_rdy.sv
../rtl/utils/cdc_2phase.sv

View File

@ -1,223 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
// core local interruptor module
// 核心中断管理、仲裁模块
module clint(
input wire clk,
input wire rst_n,
// from core
input wire[`INT_WIDTH-1:0] int_flag_i, // 中断输入信号
// from exu
input wire inst_ecall_i, // ecall指令
input wire inst_ebreak_i, // ebreak指令
input wire inst_mret_i, // mret指令
input wire[31:0] inst_addr_i, // 指令地址
input wire jump_flag_i,
input wire mem_access_misaligned_i,
// from csr_reg
input wire[31:0] csr_mtvec_i, // mtvec寄存器
input wire[31:0] csr_mepc_i, // mepc寄存器
input wire[31:0] csr_mstatus_i, // mstatus寄存器
// to csr_reg
output reg csr_we_o, // 写CSR寄存器标志
output reg[31:0] csr_waddr_o, // 写CSR寄存器地址
output reg[31:0] csr_wdata_o, // 写CSR寄存器数据
// to pipe_ctrl
output wire stall_flag_o, // 流水线暂停标志
output wire[31:0] int_addr_o, // 中断入口地址
output wire int_assert_o // 中断标志
);
// 中断状态定义
localparam S_INT_IDLE = 4'b0001;
localparam S_INT_SYNC_ASSERT = 4'b0010;
localparam S_INT_ASYNC_ASSERT = 4'b0100;
localparam S_INT_MRET = 4'b1000;
// 写CSR寄存器状态定义
localparam S_CSR_IDLE = 5'b00001;
localparam S_CSR_MSTATUS = 5'b00010;
localparam S_CSR_MEPC = 5'b00100;
localparam S_CSR_MSTATUS_MRET = 5'b01000;
localparam S_CSR_MCAUSE = 5'b10000;
reg[3:0] int_state;
reg[4:0] csr_state;
reg[31:0] inst_addr;
reg[31:0] cause;
wire global_int_en = csr_mstatus_i[3];
assign stall_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? 1'b1: 1'b0;
// 将跳转标志放在流水线上传递
wire pc_state_jump_flag;
gen_rst_0_dff #(1) pc_state_dff(clk, rst_n, jump_flag_i, pc_state_jump_flag);
wire if_state_jump_flag;
gen_rst_0_dff #(1) if_state_dff(clk, rst_n, pc_state_jump_flag, if_state_jump_flag);
wire id_state_jump_flag;
gen_rst_0_dff #(1) id_state_dff(clk, rst_n, if_state_jump_flag, id_state_jump_flag);
wire ex_state_jump_flag;
gen_rst_0_dff #(1) ex_state_dff(clk, rst_n, id_state_jump_flag, ex_state_jump_flag);
wire[3:0] state_jump_flag = {pc_state_jump_flag, if_state_jump_flag, id_state_jump_flag, ex_state_jump_flag};
// 如果流水线没有冲刷完成则不响应中断
wire inst_addr_valid = (~(|state_jump_flag)) | ex_state_jump_flag;
// 中断仲裁逻辑
always @ (*) begin
// 同步中断
if (inst_ecall_i | inst_ebreak_i | mem_access_misaligned_i) begin
int_state = S_INT_SYNC_ASSERT;
// 异步中断
end else if ((int_flag_i != `INT_NONE) & global_int_en & inst_addr_valid) begin
int_state = S_INT_ASYNC_ASSERT;
// 中断返回
end else if (inst_mret_i) begin
int_state = S_INT_MRET;
// 无中断响应
end else begin
int_state = S_INT_IDLE;
end
end
// 写CSR寄存器状态切换
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
csr_state <= S_CSR_IDLE;
cause <= 32'h0;
inst_addr <= 32'h0;
end else begin
case (csr_state)
S_CSR_IDLE: begin
case (int_state)
// 同步中断
S_INT_SYNC_ASSERT: begin
csr_state <= S_CSR_MEPC;
// 在中断处理函数里会将中断返回地址加4
inst_addr <= inst_addr_i;
cause <= inst_ebreak_i? 32'd3:
inst_ecall_i? 32'd11:
mem_access_misaligned_i? 32'd4:
32'd10;
end
// 异步中断
S_INT_ASYNC_ASSERT: begin
csr_state <= S_CSR_MEPC;
inst_addr <= inst_addr_i;
// 定时器中断
cause <= 32'h80000004;
end
// 中断返回
S_INT_MRET: begin
csr_state <= S_CSR_MSTATUS_MRET;
end
endcase
end
S_CSR_MEPC: begin
csr_state <= S_CSR_MSTATUS;
end
S_CSR_MSTATUS: begin
csr_state <= S_CSR_MCAUSE;
end
S_CSR_MCAUSE: begin
csr_state <= S_CSR_IDLE;
end
S_CSR_MSTATUS_MRET: begin
csr_state <= S_CSR_IDLE;
end
default: begin
csr_state <= S_CSR_IDLE;
end
endcase
end
end
// 发出中断信号前先写几个CSR寄存器
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
csr_we_o <= 1'b0;
csr_waddr_o <= 32'h0;
csr_wdata_o <= 32'h0;
end else begin
case (csr_state)
// 将mepc寄存器的值设为当前指令地址
S_CSR_MEPC: begin
csr_we_o <= 1'b1;
csr_waddr_o <= {20'h0, `CSR_MEPC};
csr_wdata_o <= inst_addr;
end
// 写中断产生的原因
S_CSR_MCAUSE: begin
csr_we_o <= 1'b1;
csr_waddr_o <= {20'h0, `CSR_MCAUSE};
csr_wdata_o <= cause;
end
// 关闭全局中断
S_CSR_MSTATUS: begin
csr_we_o <= 1'b1;
csr_waddr_o <= {20'h0, `CSR_MSTATUS};
csr_wdata_o <= {csr_mstatus_i[31:4], 1'b0, csr_mstatus_i[2:0]};
end
// 中断返回
S_CSR_MSTATUS_MRET: begin
csr_we_o <= 1'b1;
csr_waddr_o <= {20'h0, `CSR_MSTATUS};
csr_wdata_o <= {csr_mstatus_i[31:4], csr_mstatus_i[7], csr_mstatus_i[2:0]};
end
default: begin
csr_we_o <= 1'b0;
csr_waddr_o <= 32'h0;
csr_wdata_o <= 32'h0;
end
endcase
end
end
reg in_int_context;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
in_int_context <= 1'b0;
end else begin
if (csr_state == S_CSR_MSTATUS_MRET) begin
in_int_context <= 1'b0;
end else if (csr_state != S_CSR_IDLE) begin
in_int_context <= 1'b1;
end
end
end
assign int_assert_o = (csr_state == S_CSR_MCAUSE) | (csr_state == S_CSR_MSTATUS_MRET);
assign int_addr_o = (csr_state == S_CSR_MCAUSE)? csr_mtvec_i:
(csr_state == S_CSR_MSTATUS_MRET)? csr_mepc_i:
32'h0;
endmodule

View File

@ -36,7 +36,9 @@ module csr_reg(
output wire[31:0] mtvec_o, // mtvec寄存器值
output wire[31:0] mepc_o, // mepc寄存器值
output wire[31:0] mstatus_o // mstatus寄存器值
output wire[31:0] mstatus_o, // mstatus寄存器值
output wire[31:0] mie_o, // mie寄存器值
output wire[31:0] dpc_o // dpc寄存器值
);
@ -67,6 +69,9 @@ module csr_reg(
reg[31:0] mhartid_d;
wire[31:0] mhartid_q;
reg mhartid_we;
reg[31:0] dpc_d;
wire[31:0] dpc_q;
reg dpc_we;
reg[63:0] cycle;
@ -83,6 +88,8 @@ module csr_reg(
assign mtvec_o = mtvec_q;
assign mepc_o = mepc_q;
assign mstatus_o = mstatus_q;
assign mie_o = mie_q;
assign dpc_o = dpc_q;
reg[31:0] exu_rdata;
@ -122,6 +129,9 @@ module csr_reg(
`CSR_MHARTID: begin
exu_rdata = mhartid_q;
end
`CSR_DPC: begin
exu_rdata = dpc_q;
end
default: begin
exu_rdata = 32'h0;
end
@ -154,6 +164,8 @@ module csr_reg(
dscratch1_we = 1'b0;
mhartid_d = mhartid_q;
mhartid_we = 1'b0;
dpc_d = dpc_q;
dpc_we = 1'b0;
if (we) begin
case (waddr[11:0])
@ -193,6 +205,10 @@ module csr_reg(
mhartid_d = wdata;
mhartid_we = 1'b1;
end
`CSR_DPC: begin
dpc_d = wdata;
dpc_we = 1'b1;
end
default:;
endcase
end
@ -297,4 +313,15 @@ module csr_reg(
.rdata_o(mhartid_q)
);
// dpc
csr #(
.RESET_VAL(32'h0)
) dpc_csr (
.clk(clk),
.rst_n(rst_n),
.wdata_i(dpc_d),
.we_i(dpc_we),
.rdata_o(dpc_q)
);
endmodule

View File

@ -54,6 +54,7 @@
`define INST_MRET 32'h30200073
`define INST_ECALL 32'h00000073
`define INST_EBREAK 32'h00100073
`define INST_DRET 32'h7b200073
// 指令译码信息
`define DECINFO_GRP_BUS 2:0
@ -118,12 +119,13 @@
`define DECINFO_MEM_SH (`DECINFO_GRP_WIDTH+6)
`define DECINFO_MEM_SW (`DECINFO_GRP_WIDTH+7)
`define DECINFO_SYS_BUS_WIDTH (`DECINFO_GRP_WIDTH+5)
`define DECINFO_SYS_BUS_WIDTH (`DECINFO_GRP_WIDTH+6)
`define DECINFO_SYS_ECALL (`DECINFO_GRP_WIDTH+0)
`define DECINFO_SYS_EBREAK (`DECINFO_GRP_WIDTH+1)
`define DECINFO_SYS_NOP (`DECINFO_GRP_WIDTH+2)
`define DECINFO_SYS_MRET (`DECINFO_GRP_WIDTH+3)
`define DECINFO_SYS_FENCE (`DECINFO_GRP_WIDTH+4)
`define DECINFO_SYS_DRET (`DECINFO_GRP_WIDTH+5)
// 最长的那组
`define DECINFO_WIDTH `DECINFO_CSR_BUS_WIDTH
@ -137,6 +139,8 @@
`define CSR_MIE 12'h304
`define CSR_MSTATUS 12'h300
`define CSR_MSCRATCH 12'h340
`define CSR_MHARTID 12'hF14
`define CSR_DCSR 12'h7b0
`define CSR_DPC 12'h7b1
`define CSR_DSCRATCH0 12'h7b2
`define CSR_DSCRATCH1 12'h7b3
`define CSR_MHARTID 12'hF14

262
rtl/core/exception.sv Normal file
View File

@ -0,0 +1,262 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "defines.sv"
`define CAUSE_IRQ_EXTERNAL_M {1'b1, 31'd11}
`define CAUSE_IRQ_SOFTWARE_M {1'b1, 31'd3}
`define CAUSE_IRQ_TIMER_M {1'b1, 31'd7}
`define CAUSE_EXCEP_ECALL_M {1'b0, 31'd11}
`define CAUSE_EXCEP_EBREAK_M {1'b0, 31'd3}
`define MIE_MTIE_BIT 7
`define MIE_MEIE_BIT 11
`define MIE_MSIE_BIT 3
module exception (
input wire clk,
input wire rst_n,
input wire inst_valid_i,
input wire inst_ecall_i, // ecall指令
input wire inst_ebreak_i, // ebreak指令
input wire inst_mret_i, // mret指令
input wire inst_dret_i, // dret指令
input wire[31:0] inst_addr_i, // 指令地址
input wire[31:0] mtvec_i, // mtvec寄存器
input wire[31:0] mepc_i, // mepc寄存器
input wire[31:0] mstatus_i, // mstatus寄存器
input wire[31:0] mie_i, // mie寄存器
input wire[31:0] dpc_i, // dpc寄存器
input wire irq_software_i,
input wire irq_timer_i,
input wire irq_external_i,
input wire[14:0] irq_fast_i,
input wire[31:0] debug_halt_addr_i,
input wire debug_req_i,
output wire csr_we_o, // 写CSR寄存器标志
output wire[31:0] csr_waddr_o, // 写CSR寄存器地址
output wire[31:0] csr_wdata_o, // 写CSR寄存器数据
output wire stall_flag_o, // 流水线暂停标志
output wire[31:0] int_addr_o, // 中断入口地址
output wire int_assert_o // 中断标志
);
localparam ILLEGAL_INSTR_OFFSET = 0;
localparam INSTR_ADDR_MISA_OFFSET = 4;
localparam ECALL_OFFSET = 8;
localparam EBREAK_OFFSET = 12;
localparam LOAD_MISA_OFFSET = 16;
localparam STORE_MISA_OFFSET = 20;
localparam RESERVED1_EXCEPTION_OFFSET = 24;
localparam RESERVED2_EXCEPTION_OFFSET = 28;
localparam EXTERNAL_INT_OFFSET = 32;
localparam SOFTWARE_INT_OFFSET = 36;
localparam TIMER_INT_OFFSET = 40;
localparam FAST_INT_OFFSET = 44;
localparam S_IDLE = 3'b001;
localparam S_W_MEPC = 3'b010;
localparam S_ASSERT = 3'b100;
reg debug_mode_d, debug_mode_q;
reg[2:0] state_d, state_q;
reg[31:0] assert_addr_d, assert_addr_q;
reg[31:0] return_addr_d, return_addr_q;
reg csr_we;
reg[31:0] csr_waddr;
reg[31:0] csr_wdata;
wire global_int_en;
assign global_int_en = mstatus_i[3];
reg[3:0] fast_irq_id;
wire fast_irq_req;
always @ (*) begin
if (irq_fast_i[ 0]) fast_irq_id = 4'd0;
else if (irq_fast_i[ 1]) fast_irq_id = 4'd1;
else if (irq_fast_i[ 2]) fast_irq_id = 4'd2;
else if (irq_fast_i[ 3]) fast_irq_id = 4'd3;
else if (irq_fast_i[ 4]) fast_irq_id = 4'd4;
else if (irq_fast_i[ 5]) fast_irq_id = 4'd5;
else if (irq_fast_i[ 6]) fast_irq_id = 4'd6;
else if (irq_fast_i[ 7]) fast_irq_id = 4'd7;
else if (irq_fast_i[ 8]) fast_irq_id = 4'd8;
else if (irq_fast_i[ 9]) fast_irq_id = 4'd9;
else if (irq_fast_i[10]) fast_irq_id = 4'd10;
else if (irq_fast_i[11]) fast_irq_id = 4'd11;
else if (irq_fast_i[12]) fast_irq_id = 4'd12;
else if (irq_fast_i[13]) fast_irq_id = 4'd13;
else fast_irq_id = 4'd14;
end
assign fast_irq_req = |irq_fast_i;
reg interrupt_req_tmp;
reg[31:0] interrupt_cause;
reg[31:0] interrupt_offset;
wire interrupt_req = inst_valid_i & interrupt_req_tmp;
always @ (*) begin
if (fast_irq_req) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = {1'b1, {26{1'b0}}, 1'b1, fast_irq_id};
interrupt_offset = {fast_irq_id, 2'b0} + FAST_INT_OFFSET;
end else if (irq_external_i & mie_i[`MIE_MEIE_BIT]) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = `CAUSE_IRQ_EXTERNAL_M;
interrupt_offset = EXTERNAL_INT_OFFSET;
end else if (irq_software_i & mie_i[`MIE_MSIE_BIT]) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = `CAUSE_IRQ_SOFTWARE_M;
interrupt_offset = SOFTWARE_INT_OFFSET;
end else if (irq_timer_i & mie_i[`MIE_MTIE_BIT]) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = `CAUSE_IRQ_TIMER_M;
interrupt_offset = TIMER_INT_OFFSET;
end else begin
interrupt_req_tmp = 1'b0;
interrupt_cause = 32'h0;
interrupt_offset = 32'h0;
end
end
reg exception_req;
reg[31:0] exception_cause;
reg[31:0] exception_offset;
always @ (*) begin
if (inst_ecall_i) begin
exception_req = 1'b1;
exception_cause = `CAUSE_EXCEP_ECALL_M;
exception_offset = ECALL_OFFSET;
end else if (inst_ebreak_i) begin
exception_req = 1'b1;
exception_cause = `CAUSE_EXCEP_EBREAK_M;
exception_offset = EBREAK_OFFSET;
end else begin
exception_req = 1'b0;
exception_cause = 32'h0;
exception_offset = 32'h0;
end
end
wire int_or_exception_req;
wire[31:0] int_or_exception_cause;
wire[31:0] int_or_exception_offset;
assign int_or_exception_req = (interrupt_req & global_int_en) | exception_req;
assign int_or_exception_cause = exception_req ? exception_cause : interrupt_cause;
assign int_or_exception_offset = exception_req ? exception_offset : interrupt_offset;
wire debug_mode_req = (~debug_mode_q) & debug_req_i & inst_valid_i;
assign stall_flag_o = ((state_q != S_IDLE) & (state_q != S_ASSERT)) |
(interrupt_req & global_int_en) | exception_req |
debug_mode_req |
inst_mret_i |
inst_dret_i;
always @ (*) begin
state_d = state_q;
assert_addr_d = assert_addr_q;
debug_mode_d = debug_mode_q;
return_addr_d = return_addr_q;
csr_we = 1'b0;
csr_waddr = 32'h0;
csr_wdata = 32'h0;
case (state_q)
S_IDLE: begin
if (int_or_exception_req) begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MCAUSE};
csr_wdata = int_or_exception_cause;
assert_addr_d = mtvec_i + int_or_exception_offset;
return_addr_d = inst_addr_i;
state_d = S_W_MEPC;
end else if (debug_mode_req) begin
debug_mode_d = 1'b1;
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_DPC};
csr_wdata = inst_addr_i;
assert_addr_d = debug_halt_addr_i;
state_d = S_ASSERT;
end else if (inst_mret_i) begin
assert_addr_d = mepc_i;
state_d = S_ASSERT;
end else if (inst_dret_i) begin
assert_addr_d = dpc_i;
state_d = S_ASSERT;
debug_mode_d = 1'b0;
end
end
S_W_MEPC: begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MEPC};
csr_wdata = return_addr_q;
state_d = S_ASSERT;
end
S_ASSERT: begin
csr_we = 1'b0;
state_d = S_IDLE;
end
default:;
endcase
end
assign csr_we_o = csr_we;
assign csr_waddr_o = csr_waddr;
assign csr_wdata_o = csr_wdata;
assign int_assert_o = (state_q == S_ASSERT);
assign int_addr_o = assert_addr_q;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
assert_addr_q <= 32'h0;
debug_mode_q <= 1'b0;
return_addr_q <= 32'h0;
end else begin
state_q <= state_d;
assert_addr_q <= assert_addr_d;
debug_mode_q <= debug_mode_d;
return_addr_q <= return_addr_d;
end
end
endmodule

View File

@ -30,6 +30,7 @@ module exu(
output wire inst_ecall_o, // ecall指令
output wire inst_ebreak_o, // ebreak指令
output wire inst_mret_o, // mret指令
output wire inst_dret_o, // dret指令
// mem
input wire[31:0] mem_rdata_i, // 内存输入数据
@ -143,6 +144,7 @@ module exu(
wire sys_op_ecall_o;
wire sys_op_ebreak_o;
wire sys_op_fence_o;
wire sys_op_dret_o;
exu_dispatch u_exu_dispatch(
// input
@ -219,12 +221,14 @@ module exu(
.sys_op_mret_o(sys_op_mret_o),
.sys_op_ecall_o(sys_op_ecall_o),
.sys_op_ebreak_o(sys_op_ebreak_o),
.sys_op_fence_o(sys_op_fence_o)
.sys_op_fence_o(sys_op_fence_o),
.sys_op_dret_o(sys_op_dret_o)
);
assign inst_ecall_o = sys_op_ecall_o;
assign inst_ebreak_o = sys_op_ebreak_o;
assign inst_mret_o = sys_op_mret_o;
assign inst_dret_o = sys_op_dret_o;
wire[31:0] alu_res_o;
wire[31:0] bjp_res_o;

View File

@ -99,7 +99,8 @@ module exu_dispatch(
output wire sys_op_mret_o,
output wire sys_op_ecall_o,
output wire sys_op_ebreak_o,
output wire sys_op_fence_o
output wire sys_op_fence_o,
output wire sys_op_dret_o
);
@ -206,5 +207,6 @@ module exu_dispatch(
assign sys_op_ecall_o = sys_info[`DECINFO_SYS_ECALL];
assign sys_op_ebreak_o = sys_info[`DECINFO_SYS_EBREAK];
assign sys_op_fence_o = sys_info[`DECINFO_SYS_FENCE];
assign sys_op_dret_o = sys_info[`DECINFO_SYS_DRET];
endmodule

View File

@ -156,6 +156,7 @@ module idu(
wire inst_remu = opcode_0110011 & funct3_111 & funct7_0000001;
wire inst_nop = (inst_i == `INST_NOP);
wire inst_mret = (inst_i == `INST_MRET);
wire inst_dret = (inst_i == `INST_DRET);
// 将指令分类
wire inst_type_load = opcode_0000011;
@ -228,6 +229,7 @@ module idu(
assign dec_sys_info_bus[`DECINFO_SYS_EBREAK] = inst_ebreak;
assign dec_sys_info_bus[`DECINFO_SYS_NOP] = inst_nop;
assign dec_sys_info_bus[`DECINFO_SYS_MRET] = inst_mret;
assign dec_sys_info_bus[`DECINFO_SYS_DRET] = inst_dret;
assign dec_sys_info_bus[`DECINFO_SYS_FENCE] = inst_fence | inst_fence_i;
// 指令中的立即数
@ -259,7 +261,7 @@ module idu(
wire op_bjp = inst_jal | inst_jalr | inst_type_branch;
wire op_muldiv = inst_type_muldiv;
wire op_csr = inst_csrrw | inst_csrrwi | inst_csrrs | inst_csrrsi | inst_csrrc | inst_csrrci;
wire op_sys = inst_ebreak | inst_ecall | inst_nop | inst_mret | inst_fence | inst_fence_i;
wire op_sys = inst_ebreak | inst_ecall | inst_nop | inst_mret | inst_fence | inst_fence_i | inst_dret;
wire op_mem = inst_type_load | inst_type_store;
assign dec_info_bus_o = ({`DECINFO_WIDTH{op_alu}} & {{`DECINFO_WIDTH-`DECINFO_ALU_BUS_WIDTH{1'b0}}, dec_alu_info_bus}) |

View File

@ -49,7 +49,6 @@ module tinyriscv_core #(
input wire irq_timer_i,
input wire irq_external_i,
input wire[14:0] irq_fast_i,
input wire irq_nm_i,
// debug req signal
input wire debug_req_i
@ -114,6 +113,7 @@ module tinyriscv_core #(
wire ex_inst_ecall_o;
wire ex_inst_ebreak_o;
wire ex_inst_mret_o;
wire ex_inst_dret_o;
wire ex_inst_valid_o;
// gpr_reg模块输出信号
@ -126,6 +126,8 @@ module tinyriscv_core #(
wire[31:0] csr_mtvec_o;
wire[31:0] csr_mepc_o;
wire[31:0] csr_mstatus_o;
wire[31:0] csr_mie_o;
wire[31:0] csr_dpc_o;
// pipe_ctrl模块输出信号
wire[31:0] ctrl_flush_addr_o;
@ -197,7 +199,9 @@ module tinyriscv_core #(
.clint_wdata_i(clint_csr_wdata_o),
.mtvec_o(csr_mtvec_o),
.mepc_o(csr_mepc_o),
.mstatus_o(csr_mstatus_o)
.mstatus_o(csr_mstatus_o),
.mie_o(csr_mie_o),
.dpc_o(csr_dpc_o)
);
ifu_idu u_ifu_idu(
@ -283,6 +287,7 @@ module tinyriscv_core #(
.inst_ecall_o(ex_inst_ecall_o),
.inst_ebreak_o(ex_inst_ebreak_o),
.inst_mret_o(ex_inst_mret_o),
.inst_dret_o(ex_inst_dret_o),
.int_stall_i(clint_stall_flag_o),
.csr_raddr_o(ex_csr_raddr_o),
.csr_rdata_i(csr_ex_data_o),
@ -300,19 +305,26 @@ module tinyriscv_core #(
.rd_we_i(ie_rd_we_o)
);
clint u_clint(
exception u_exception(
.clk(clk),
.rst_n(rst_n),
.int_flag_i(`INT_NONE),
.inst_valid_i(ex_inst_valid_o),
.inst_ecall_i(ex_inst_ecall_o),
.inst_ebreak_i(ex_inst_ebreak_o),
.inst_mret_i(ex_inst_mret_o),
.inst_dret_i(ex_inst_dret_o),
.inst_addr_i(ie_dec_pc_o),
.jump_flag_i(ex_jump_flag_o),
.mem_access_misaligned_i(ex_mem_access_misaligned_o),
.csr_mtvec_i(csr_mtvec_o),
.csr_mepc_i(csr_mepc_o),
.csr_mstatus_i(csr_mstatus_o),
.mtvec_i(csr_mtvec_o),
.mepc_i(csr_mepc_o),
.mstatus_i(csr_mstatus_o),
.mie_i(csr_mie_o),
.dpc_i(csr_dpc_o),
.irq_software_i(irq_software_i),
.irq_timer_i(irq_timer_i),
.irq_external_i(irq_external_i),
.irq_fast_i(irq_fast_i),
.debug_halt_addr_i(DEBUG_HALT_ADDR),
.debug_req_i(debug_req_i),
.csr_we_o(clint_csr_we_o),
.csr_waddr_o(clint_csr_waddr_o),
.csr_wdata_o(clint_csr_wdata_o),

71
rtl/debug/debug_rom.sv Normal file
View File

@ -0,0 +1,71 @@
/* Copyright 2018 ETH Zurich and University of Bologna.
* Copyright and related rights are licensed under the Solderpad Hardware
* License, Version 0.51 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
* or agreed to in writing, software, hardware and materials distributed under
* this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* File: $filename.v
*
* Description: Auto-generated bootrom
*/
// Auto-generated code
module debug_rom (
input wire clk_i,
input wire req_i,
input wire [63:0] addr_i,
output wire [63:0] rdata_o
);
localparam RomSize = 19;
wire [RomSize-1:0][63:0] mem;
assign mem = {
64'h00000000_7b200073,
64'h7b202473_7b302573,
64'h10852423_f1402473,
64'ha85ff06f_7b202473,
64'h7b302573_10052223,
64'h00100073_7b202473,
64'h7b302573_10052623,
64'h00c51513_00c55513,
64'h00000517_fd5ff06f,
64'hfa041ce3_00247413,
64'h40044403_00a40433,
64'hf1402473_02041c63,
64'h00147413_40044403,
64'h00a40433_10852023,
64'hf1402473_00c51513,
64'h00c55513_00000517,
64'h7b351073_7b241073,
64'h0ff0000f_04c0006f,
64'h07c0006f_00c0006f
};
reg [4:0] addr_q;
always @ (posedge clk_i) begin
if (req_i) begin
addr_q <= addr_i[7:3];
end
end
reg[63:0] rdata;
// this prevents spurious Xes from propagating into
// the speculative fetch stage of the core
always @ (*) begin
rdata = 64'h0;
if (addr_q < 5'd19) begin
rdata = mem[addr_q];
end
end
assign rdata_o = rdata;
endmodule

130
rtl/debug/jtag_def.sv Normal file
View File

@ -0,0 +1,130 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`define DbgVersion013 4'h2
`define ProgBufSize 5'h8
`define DataCount 4'h2
`define HaltAddress 64'h800
`define ResumeAddress `HaltAddress + 4
`define ExceptionAddress `HaltAddress + 8
`define DataAddr 12'h380
// dmi op
`define DMI_OP_NOP 2'b00
`define DMI_OP_READ 2'b01
`define DMI_OP_WRITE 2'b10
// DM regs addr
`define Data0 6'h04
`define Data1 6'h05
`define Data2 6'h06
`define Data3 6'h07
`define DMControl 6'h10
`define DMStatus 6'h11
`define Hartinfo 6'h12
`define AbstractCS 6'h16
`define Command 6'h17
`define ProgBuf0 6'h20
`define ProgBuf1 6'h21
`define ProgBuf2 6'h22
`define ProgBuf3 6'h23
`define ProgBuf4 6'h24
`define ProgBuf5 6'h25
`define ProgBuf6 6'h26
`define ProgBuf7 6'h27
`define ProgBuf8 6'h28
`define ProgBuf9 6'h29
`define ProgBuf10 6'h2A
`define ProgBuf11 6'h2B
`define ProgBuf12 6'h2C
`define ProgBuf13 6'h2D
`define ProgBuf14 6'h2E
`define ProgBuf15 6'h2F
`define SBAddress3 6'h37
`define SBCS 6'h38
`define SBAddress0 6'h39
`define SBAddress1 6'h3A
`define SBAddress2 6'h3B
`define SBData0 6'h3C
`define SBData1 6'h3D
`define SBData2 6'h3E
`define SBData3 6'h3F
// dmstatus bit index
`define Impebreak 22
`define Allhavereset 19
`define Anyhavereset 18
`define Allresumeack 17
`define Anyresumeack 16
`define Allnonexistent 15
`define Anynonexistent 14
`define Allunavail 13
`define Anyunavail 12
`define Allrunning 11
`define Anyrunning 10
`define Allhalted 9
`define Anyhalted 8
`define Authenticated 7
`define Authbusy 6
`define Hasresethaltreq 5
`define Confstrptrvalid 4
`define Version 3:0
// dmcontrol bit index
`define Haltreq 31
`define Resumereq 30
`define Hartreset 29
`define Ackhavereset 28
`define Hasel 26
`define Hartsello 25:16
`define Hartselhi 15:6
`define Setresethaltreq 3
`define Clrresethaltreq 2
`define Ndmreset 1
`define Dmactive 0
// abstractcs bit index
`define Progbufsize 28:24
`define Busy 12
`define Cmderr 10:8
`define Datacount 3:0
// abstract command access register bit index
`define Cmdtype 31:24
`define Aarsize 22:20
`define Aarpostincrement 19
`define Postexec 18
`define Transfer 17
`define Write 16
`define Regno 15:0
// sbcs bit index
`define Sbversion 31:29
`define Sbbusyerror 22
`define Sbbusy 21
`define Sbreadonaddr 20
`define Sbaccess 19:17
`define Sbautoincrement 16
`define Sbreadondata 15
`define Sberror 14:12
`define Sbasize 11:5
`define Sbaccess128 4
`define Sbaccess64 3
`define Sbaccess32 2
`define Sbaccess16 1
`define Sbaccess8 0

View File

@ -1,381 +1,370 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`define DTM_OP_NOP 2'b00
`define DTM_OP_READ 2'b01
`define DTM_OP_WRITE 2'b10
module jtag_dm #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2)(
clk,
rst_n,
// rx
dm_ack_o,
dtm_req_valid_i,
dtm_req_data_i,
// tx
dtm_ack_i,
dm_resp_data_o,
dm_resp_valid_o,
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_mem_sel_o,
req_valid_o,
req_ready_i,
rsp_valid_i,
rsp_ready_o,
dm_halt_req_o,
dm_reset_req_o
);
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 wire clk;
input wire rst_n;
output wire dm_ack_o;
input wire dtm_req_valid_i;
input wire[DTM_REQ_BITS-1:0] dtm_req_data_i;
input wire dtm_ack_i;
output wire[DM_RESP_BITS-1:0] dm_resp_data_o;
output wire dm_resp_valid_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[3:0] dm_mem_sel_o;
output wire req_valid_o;
input wire req_ready_i;
input wire rsp_valid_i;
output wire rsp_ready_o;
output wire dm_halt_req_o;
output wire dm_reset_req_o;
// DM模块寄存器
reg[31:0] dcsr;
reg[31:0] dmstatus;
reg[31:0] dmcontrol;
reg[31:0] hartinfo;
reg[31:0] abstractcs;
reg[31:0] data0;
reg[31:0] sbcs;
reg[31:0] sbaddress0;
reg[31:0] sbdata0;
reg[31:0] command;
// DM模块寄存器地址
localparam DCSR = 16'h7b0;
localparam DMSTATUS = 6'h11;
localparam DMCONTROL = 6'h10;
localparam HARTINFO = 6'h12;
localparam ABSTRACTCS = 6'h16;
localparam DATA0 = 6'h04;
localparam SBCS = 6'h38;
localparam SBADDRESS0 = 6'h39;
localparam SBDATA0 = 6'h3C;
localparam COMMAND = 6'h17;
localparam DPC = 16'h7b1;
localparam OP_SUCC = 2'b00;
localparam STATE_IDLE = 3'b001;
localparam STATE_EXE = 3'b010;
localparam STATE_END = 3'b100;
reg[2:0] state;
reg[31:0] read_data;
reg dm_reg_we;
reg[4:0] dm_reg_addr;
reg[31:0] dm_reg_wdata;
reg dm_mem_we;
reg[31:0] dm_mem_addr;
reg[31:0] dm_mem_wdata;
reg[31:0] dm_mem_rdata;
reg dm_halt_req;
reg dm_reset_req;
reg need_resp;
reg is_read_reg;
wire rx_valid;
wire[DTM_REQ_BITS-1:0] rx_data; // driver请求数据
reg[DTM_REQ_BITS-1:0] rx_data_r;
wire[3:0] dm_mem_sel = (sbcs[19:17] == 3'd0)? 4'b0001:
(sbcs[19:17] == 3'd1)? 4'b0011:
4'b1111;
wire[2:0] address_inc_step = (sbcs[19:17] == 3'd0)? 3'd1:
(sbcs[19:17] == 3'd1)? 3'd2:
3'd4;
wire[31:0] sbaddress0_next = sbaddress0 + {29'h0, address_inc_step};
wire[DM_RESP_BITS-1:0] dm_resp_data;
wire[DMI_OP_BITS-1:0] op = rx_data_r[DMI_OP_BITS-1:0];
wire[DMI_DATA_BITS-1:0] data = rx_data_r[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
wire[DMI_ADDR_BITS-1:0] address = rx_data_r[DTM_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
wire req_sys_bus = ~(address == DMSTATUS);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
dm_mem_we <= 1'b0;
dm_reg_we <= 1'b0;
dm_halt_req <= 1'b0;
dm_reset_req <= 1'b0;
dm_mem_addr <= 32'h0;
dm_reg_addr <= 5'h0;
sbaddress0 <= 32'h0;
dcsr <= 32'h0;
hartinfo <= 32'h0;
sbcs <= 32'h20040404;
dmcontrol <= 32'h0;
abstractcs <= 32'h1000003;
data0 <= 32'h0;
sbdata0 <= 32'h0;
command <= 32'h0;
dm_reg_wdata <= 32'h0;
dm_mem_wdata <= 32'h0;
dm_mem_rdata <= 32'h0;
dmstatus <= 32'h430c82;
is_read_reg <= 1'b0;
read_data <= 32'h0;
need_resp <= 1'b0;
state <= STATE_IDLE;
end else begin
case (state)
STATE_IDLE: begin
// 接收到driver的请求
if (rx_valid) begin
rx_data_r <= rx_data;
state <= STATE_EXE;
end
end
STATE_EXE: begin
state <= STATE_END;
need_resp <= 1'b1;
case (op)
`DTM_OP_READ: begin
case (address)
DMSTATUS: begin
read_data <= dmstatus;
end
DMCONTROL: begin
read_data <= dmcontrol;
end
HARTINFO: begin
read_data <= hartinfo;
end
SBCS: begin
read_data <= sbcs;
end
ABSTRACTCS: begin
read_data <= abstractcs;
end
DATA0: begin
if (is_read_reg == 1'b1) begin
read_data <= dm_reg_rdata_i;
end else begin
read_data <= data0;
end
is_read_reg <= 1'b0;
end
SBDATA0: begin
read_data <= dm_mem_rdata;
if (sbcs[16] == 1'b1) begin
sbaddress0 <= sbaddress0_next;
end
if (sbcs[15] == 1'b1) begin
dm_mem_addr <= sbaddress0_next;
end
end
default: begin
read_data <= {(DMI_DATA_BITS){1'b0}};
end
endcase
end
`DTM_OP_WRITE: begin
read_data <= {(DMI_DATA_BITS){1'b0}};
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;
dmcontrol <= data;
dm_halt_req <= 1'b0;
dm_reset_req <= 1'b0;
// DM is active
end else begin
// we have only one hart
dmcontrol <= (data & ~(32'h3fffc0)) | 32'h10000;
// halt
if (data[31] == 1'b1) begin
dm_halt_req <= 1'b1;
// clear ALLRUNNING ANYRUNNING and set ALLHALTED
dmstatus <= {dmstatus[31:12], 4'h3, dmstatus[7:0]};
// reset
end else if (data[1] == 1'b1) begin
dm_reset_req <= 1'b1;
dm_halt_req <= 1'b0;
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
// resume
end else if (dm_halt_req == 1'b1 && data[30] == 1'b1) begin
dm_halt_req <= 1'b0;
// set ALLRUNNING ANYRUNNING and clear ALLHALTED
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]};
end
end
end
COMMAND: begin
// access reg
if (data[31:24] == 8'h0) begin
if (data[22:20] > 3'h2) begin
abstractcs <= abstractcs | (1'b1 << 9);
end else begin
abstractcs <= abstractcs & (~(3'h7 << 8));
// read or write
if (data[18] == 1'b0) begin
dm_reg_addr <= data[15:0] - 16'h1000;
// read
if (data[16] == 1'b0) begin
if (data[15:0] == DCSR) begin
data0 <= dcsr;
end else if (data[15:0] < 16'h1020) begin
is_read_reg <= 1'b1;
end
// write
end else begin
if (data[15:0] < 16'h1020) begin
dm_reg_we <= 1'b1;
dm_reg_wdata <= data0;
end
end
end
end
end
end
DATA0: begin
data0 <= data;
end
SBCS: begin
sbcs <= data;
end
SBADDRESS0: begin
sbaddress0 <= data;
if (sbcs[20] == 1'b1) begin
dm_mem_addr <= data;
end
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_next;
end
end
endcase
end
`DTM_OP_NOP: begin
read_data <= {(DMI_DATA_BITS){1'b0}};
end
endcase
end
STATE_END: begin
state <= STATE_IDLE;
dm_mem_rdata <= dm_mem_rdata_i;
need_resp <= 1'b0;
dm_mem_we <= 1'b0;
dm_reg_we <= 1'b0;
dm_reset_req <= 1'b0;
end
endcase
end
end
wire jtag_req_hsked = (req_valid_o & req_ready_i);
wire jtag_rsp_hsked = (rsp_valid_i & rsp_ready_o);
assign rsp_ready_o = (~rst_n)? 1'b0: 1'b1;
assign dm_mem_sel_o = dm_mem_sel;
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_mem_we_o = dm_mem_we;
assign dm_mem_addr_o = dm_mem_addr;
assign dm_mem_wdata_o = dm_mem_wdata;
assign req_valid_o = (state != STATE_IDLE) & req_sys_bus;
assign dm_halt_req_o = dm_halt_req;
assign dm_reset_req_o = dm_reset_req;
assign dm_resp_data = {address, read_data, OP_SUCC};
full_handshake_tx #(
.DW(DM_RESP_BITS)
) tx(
.clk(clk),
.rst_n(rst_n),
.ack_i(dtm_ack_i),
.req_i(need_resp),
.req_data_i(dm_resp_data),
.idle_o(),
.req_o(dm_resp_valid_o),
.req_data_o(dm_resp_data_o)
);
full_handshake_rx #(
.DW(DTM_REQ_BITS)
) rx(
.clk(clk),
.rst_n(rst_n),
.req_i(dtm_req_valid_i),
.req_data_i(dtm_req_data_i),
.ack_o(dm_ack_o),
.recv_data_o(rx_data),
.recv_rdy_o(rx_valid)
);
endmodule
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "jtag_def.sv"
module jtag_dm #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2,
localparam DMI_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
localparam DMI_RESP_BITS = DMI_REQ_BITS
)(
input wire clk,
input wire rst_n,
// from DMI
input wire [DMI_REQ_BITS-1:0] dmi_data_i,
input wire dmi_valid_i,
output wire dm_ready_o,
// to DMI
output wire [DMI_RESP_BITS-1:0] dm_data_o,
output wire dm_valid_o,
input wire dmi_ready_i,
output wire debug_req_o,
output wire ndmreset_o,
// jtag access mem devices(DM as master)
output wire master_req_o,
input wire master_gnt_i,
input wire master_rvalid_i,
output wire master_we_o,
output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
output wire [31:0] master_wdata_o,
input wire [31:0] master_rdata_i,
input wire master_err_i,
// core fetch instr or mem(DM as slave)
input wire slave_req_i,
input wire slave_we_i,
input wire [31:0] slave_addr_i,
input wire [3:0] slave_be_i,
input wire [31:0] slave_wdata_i,
output wire [31:0] slave_rdata_o
);
localparam HARTINFO = {8'h0, 4'h2, 3'b0, 1'b1, `DataCount, `DataAddr};
wire halted;
wire resumeack;
wire sbbusy;
wire[DMI_OP_BITS-1:0] dm_op;
wire[DMI_ADDR_BITS-1:0] dm_op_addr;
wire[DMI_DATA_BITS-1:0] dm_op_data;
reg havereset_d, havereset_q;
reg clear_resumeack;
reg sbaddress_write_valid;
reg sbdata_write_valid;
reg[31:0] dm_resp_data_d, dm_resp_data_q;
wire[31:0] sba_sbaddress;
wire[31:0] dm_sbaddress;
wire resumereq;
wire cmdbusy;
// DM regs
reg[31:0] dmstatus;
reg[31:0] dmcontrol_d, dmcontrol_q;
reg[31:0] abstractcs;
reg[31:0] sbcs_d, sbcs_q;
reg[31:0] sbdata0_d, sbdata0_q;
reg[31:0] sbaddress0_d, sbaddress0_q;
reg[31:0] command_d, command_q;
reg[31:0] data0_d, data0_q;
reg[2:0] cmderr_d, cmderr_q;
assign dm_sbaddress = sbaddress0_q;
assign dm_op = dmi_data_i[DMI_OP_BITS-1:0];
assign dm_op_addr = dmi_data_i[DMI_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
assign dm_op_data = dmi_data_i[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
localparam S_REQ = 2'b01;
localparam S_RESP = 2'b10;
reg[2:0] req_state_d, req_state_q;
reg dm_valid_d, dm_valid_q;
// response FSM
always @ (*) begin
req_state_d = req_state_q;
dm_valid_d = dm_valid_q;
case (req_state_q)
S_REQ: begin
if (dmi_valid_i & dm_ready_o) begin
req_state_d = S_RESP;
dm_valid_d = 1'b1;
end
end
S_RESP: begin
if (dmi_ready_i) begin
dm_valid_d = 1'b0;
req_state_d = S_REQ;
end
end
default:;
endcase
end
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
req_state_q <= S_REQ;
dm_valid_q <= 1'b0;
end else begin
req_state_q <= req_state_d;
dm_valid_q <= dm_valid_d;
end
end
// we always ready to receive dmi request
assign dm_ready_o = 1'b1;
assign dm_valid_o = dm_valid_q;
assign dm_data_o = {{DMI_ADDR_BITS{1'b0}}, dm_resp_data_q, 2'b00}; // response successfully
// DMI read or write operation
always @ (*) begin
// dmstatus
dmstatus = 32'h0;
dmstatus[`Version] = `DbgVersion013;
dmstatus[`Authenticated] = 1'b1;
dmstatus[`Allresumeack] = resumeack;
dmstatus[`Anyresumeack] = resumeack;
dmstatus[`Allhavereset] = havereset_q;
dmstatus[`Anyhavereset] = havereset_q;
dmstatus[`Allhalted] = halted;
dmstatus[`Anyhalted] = halted;
dmstatus[`Allrunning] = ~halted;
dmstatus[`Anyrunning] = ~halted;
// abstractcs
cmderr_d = cmderr_q;
abstractcs = 32'h0;
abstractcs[`Datacount] = `DataCount;
abstractcs[`Progbufsize] = `ProgBufSize;
abstractcs[`Busy] = cmdbusy;
abstractcs[`Cmderr] = cmderr_q;
havereset_d = havereset_q;
sbaddress0_d = sba_sbaddress;
dmcontrol_d = dmcontrol_q;
clear_resumeack = 1'b0;
sbaddress_write_valid = 1'b0;
sbdata_write_valid = 1'b0;
data0_d = data0_q;
sbcs_d = sbcs_q;
sbdata0_d = sbdata0_q;
dm_resp_data_d = dm_resp_data_q;
if (dmi_valid_i & dm_ready_o) begin
// read
if (dm_op == `DMI_OP_READ) begin
case (dm_op_addr)
`DMStatus: dm_resp_data_d = dmstatus;
`DMControl: dm_resp_data_d = dmcontrol_q;
`Hartinfo: dm_resp_data_d = HARTINFO;
`SBCS: dm_resp_data_d = sbcs_q;
`AbstractCS:dm_resp_data_d = abstractcs;
default:;
endcase
// write
end else if (dm_op == `DMI_OP_WRITE) begin
case (dm_op_addr)
`DMControl: begin
dmcontrol_d = dm_op_data;
if (dmcontrol_d[`Ackhavereset]) begin
havereset_d = 1'b0;
end
end
`Data0: begin
data0_d = dm_op_data;
end
`SBCS: begin
if (sbbusy) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbcs_d = dm_op_data;
// write 1 to clear
sbcs_d[`Sbbusyerror] = sbcs_q[`Sbbusyerror] & (~sbcs_d[`Sbbusyerror]);
sbcs_d[`Sberror] = sbcs_q[`Sberror] & (~sbcs_d[`Sberror]);
end
end
`SBAddress0: begin
if (sbbusy | sbcs_d[`Sbbusyerror]) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbaddress0_d = dm_op_data;
sbaddress_write_valid = (sbcs_q[`Sberror] == 3'b0);
end
end
`SBData0: begin
if (sbbusy | sbcs_d[`Sbbusyerror]) begin
sbcs_d[`Sbbusyerror] = 1'b1;
end else begin
sbdata0_d = dm_op_data;
sbdata_write_valid = (sbcs_q[`Sberror] == 3'b0);
end
end
`AbstractCS: begin
end
default:;
endcase
// nop
end else begin
end
end
// dmcontrol
dmcontrol_d[`Hasel] = 1'b0;
dmcontrol_d[`Hartreset] = 1'b0;
dmcontrol_d[`Setresethaltreq] = 1'b0;
dmcontrol_d[`Clrresethaltreq] = 1'b0;
dmcontrol_d[`Ackhavereset] = 1'b0;
dmcontrol_d[`Hartsello] = 10'h1;
dmcontrol_d[`Hartselhi] = 10'h0;
// 收到resume请求后清resume应答
if (!dmcontrol_q[`Resumereq] && dmcontrol_d[`Resumereq]) begin
clear_resumeack = 1'b1;
end
// 发出resume后并且收到应答
if (dmcontrol_q[`Resumereq] && resumeack) begin
// 清resume请求位
dmcontrol_d[`Resumereq] = 1'b0;
end
// sbcs
sbcs_d[`Sbversion] = 3'd1;
sbcs_d[`Sbbusy] = sbbusy;
sbcs_d[`Sbasize] = 7'd32;
sbcs_d[`Sbaccess128] = 1'b0;
sbcs_d[`Sbaccess64] = 1'b0;
sbcs_d[`Sbaccess32] = 1'b1;
sbcs_d[`Sbaccess16] = 1'b0;
sbcs_d[`Sbaccess8] = 1'b0;
sbcs_d[`Sbaccess] = 3'd2;
// set the havereset flag when we did a ndmreset
if (ndmreset_o) begin
havereset_d = 1'b1;
end
end
assign debug_req_o = dmcontrol_q[`Haltreq];
assign ndmreset_o = dmcontrol_q[`Ndmreset];
assign resumereq = dmcontrol_q[`Resumereq];
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
dmcontrol_q <= 32'h0;
havereset_q <= 1'b1;
data0_q <= 32'h0;
sbcs_q <= 32'h0;
sbaddress0_q <= 32'h0;
sbdata0_q <= 32'h0;
dm_resp_data_q <= 32'h0;
cmderr_q <= 3'h0;
end else begin
if (!dmcontrol_q[`Dmactive]) begin
dmcontrol_q[`Haltreq] <= 1'b0;
dmcontrol_q[`Resumereq] <= 1'b0;
dmcontrol_q[`Hartreset] <= 1'b0;
dmcontrol_q[`Ackhavereset] <= 1'b0;
dmcontrol_q[`Hasel] <= 1'b0;
dmcontrol_q[`Hartsello] <= 10'b0;
dmcontrol_q[`Hartselhi] <= 10'b0;
dmcontrol_q[`Setresethaltreq] <= 1'b0;
dmcontrol_q[`Clrresethaltreq] <= 1'b0;
dmcontrol_q[`Ndmreset] <= 1'b0;
dmcontrol_q[`Dmactive] <= dmcontrol_d[`Dmactive];
data0_q <= 32'h0;
sbcs_q <= 32'h0;
sbaddress0_q <= 32'h0;
sbdata0_q <= 32'h0;
dm_resp_data_q <= 32'h0;
cmderr_q <= 3'h0;
end else begin
dmcontrol_q <= dmcontrol_d;
data0_q <= data0_d;
sbcs_q <= sbcs_d;
sbaddress0_q <= sbaddress0_d;
sbdata0_q <= sbdata0_d;
dm_resp_data_q <= dm_resp_data_d;
cmderr_q <= cmderr_d;
end
havereset_q <= havereset_d;
end
end
jtag_mem #(
) u_jtag_mem (
.clk(clk),
.rst_n(rst_n),
.halted_o(halted),
.resumeack_o(resumeack),
.clear_resumeack_i(clear_resumeack),
.resumereq_i(resumereq),
.haltreq_i(debug_req_o),
.cmdbusy_o(cmdbusy),
.req_i(slave_req_i),
.we_i(slave_we_i),
.addr_i(slave_addr_i),
.be_i(slave_be_i),
.wdata_i(slave_wdata_i),
.rdata_o(slave_rdata_o)
);
jtag_sba #(
) u_jtag_sba (
.clk(clk),
.rst_n(rst_n),
.sbbusy_o(sbbusy),
.master_req_o(master_req_o),
.master_gnt_i(master_gnt_i),
.master_rvalid_i(master_rvalid_i),
.master_we_o(master_we_o),
.master_be_o(master_be_o),
.master_addr_o(master_addr_o),
.master_wdata_o(master_wdata_o),
.master_rdata_i(master_rdata_i),
.master_err_i(master_err_i)
);
endmodule

76
rtl/debug/jtag_dmi.sv Normal file
View File

@ -0,0 +1,76 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_dmi #(
parameter DATA_WIDTH = 40
)(
// JTAG side(master side)
input wire jtag_tck_i,
input wire jtag_trst_ni,
input wire [DATA_WIDTH-1:0] jtag_data_i,
input wire jtag_valid_i,
output wire jtag_ready_o,
output wire [DATA_WIDTH-1:0] jtag_data_o,
output wire jtag_valid_o,
input wire jtag_ready_i,
// Core side(slave side)
input wire clk_i,
input wire rst_ni,
input wire [DATA_WIDTH-1:0] core_data_i,
input wire core_valid_i,
output wire core_ready_o,
output wire [DATA_WIDTH-1:0] core_data_o,
output wire core_valid_o,
input wire core_ready_i
);
cdc_2phase #(.DATA_WIDTH(DATA_WIDTH)) u_cdc_req (
.src_rst_ni ( jtag_trst_ni ),
.src_clk_i ( jtag_tck_i ),
.src_data_i ( jtag_data_i ),
.src_valid_i ( jtag_valid_i ),
.src_ready_o ( jtag_ready_o ),
.dst_rst_ni ( rst_ni ),
.dst_clk_i ( clk_i ),
.dst_data_o ( core_data_o ),
.dst_valid_o ( core_valid_o ),
.dst_ready_i ( core_ready_i )
);
cdc_2phase #(.DATA_WIDTH(DATA_WIDTH)) u_cdc_resp (
.src_rst_ni ( rst_ni ),
.src_clk_i ( clk_i ),
.src_data_i ( core_data_i ),
.src_valid_i ( core_valid_i ),
.src_ready_o ( core_ready_o ),
.dst_rst_ni ( jtag_trst_ni ),
.dst_clk_i ( jtag_tck_i ),
.dst_data_o ( jtag_data_o ),
.dst_valid_o ( jtag_valid_o ),
.dst_ready_i ( jtag_ready_i )
);
endmodule

View File

@ -1,290 +1,290 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_driver #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2)(
rst_n,
jtag_TCK,
jtag_TDI,
jtag_TMS,
jtag_TDO,
// rx
dm_resp_i,
dm_resp_data_i,
dtm_ack_o,
// tx
dm_ack_i,
dtm_req_valid_o,
dtm_req_data_o
);
parameter IDCODE_VERSION = 4'h1;
parameter IDCODE_PART_NUMBER = 16'he200;
parameter IDCODE_MANUFLD = 11'h537;
parameter DTM_VERSION = 4'h1;
parameter IR_BITS = 5;
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 rst_n;
input wire jtag_TCK;
input wire jtag_TDI;
input wire jtag_TMS;
output reg jtag_TDO;
input wire dm_resp_i;
input wire[DM_RESP_BITS - 1:0] dm_resp_data_i;
output wire dtm_ack_o;
input wire dm_ack_i;
output wire dtm_req_valid_o;
output wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
// JTAG StateMachine
parameter TEST_LOGIC_RESET = 4'h0;
parameter RUN_TEST_IDLE = 4'h1;
parameter SELECT_DR = 4'h2;
parameter CAPTURE_DR = 4'h3;
parameter SHIFT_DR = 4'h4;
parameter EXIT1_DR = 4'h5;
parameter PAUSE_DR = 4'h6;
parameter EXIT2_DR = 4'h7;
parameter UPDATE_DR = 4'h8;
parameter SELECT_IR = 4'h9;
parameter CAPTURE_IR = 4'hA;
parameter SHIFT_IR = 4'hB;
parameter EXIT1_IR = 4'hC;
parameter PAUSE_IR = 4'hD;
parameter EXIT2_IR = 4'hE;
parameter UPDATE_IR = 4'hF;
// DTM regs
parameter REG_BYPASS = 5'b11111;
parameter REG_IDCODE = 5'b00001;
parameter REG_DMI = 5'b10001;
parameter REG_DTMCS = 5'b10000;
reg[IR_BITS - 1:0] ir_reg;
reg[SHIFT_REG_BITS - 1:0] shift_reg;
reg[3:0] jtag_state;
wire is_busy;
reg sticky_busy;
reg dtm_req_valid;
reg[DTM_REQ_BITS - 1:0] dtm_req_data;
reg[DM_RESP_BITS - 1:0] dm_resp_data;
reg dm_is_busy;
wire[5:0] addr_bits = DMI_ADDR_BITS[5:0];
wire [SHIFT_REG_BITS - 1:0] busy_response;
wire [SHIFT_REG_BITS - 1:0] none_busy_response;
wire[31:0] idcode;
wire[31:0] dtmcs;
wire[1:0] dmi_stat;
wire dtm_reset;
wire tx_idle;
wire rx_valid;
wire[DM_RESP_BITS - 1:0] rx_data;
wire tx_valid;
wire[DTM_REQ_BITS - 1:0] tx_data;
assign dtm_reset = shift_reg[16];
assign idcode = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
assign dtmcs = {14'b0,
1'b0, // dmihardreset
1'b0, // dmireset
1'b0,
3'h5, // idle
dmi_stat, // dmistat
addr_bits, // abits
DTM_VERSION}; // version
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
assign none_busy_response = dm_resp_data;
assign is_busy = sticky_busy | dm_is_busy;
assign dmi_stat = is_busy ? 2'b01 : 2'b00;
// state switch
always @(posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
jtag_state <= TEST_LOGIC_RESET;
end else begin
case (jtag_state)
TEST_LOGIC_RESET : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
RUN_TEST_IDLE : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_DR : jtag_state <= jtag_TMS ? SELECT_IR : CAPTURE_DR;
CAPTURE_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
SHIFT_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
EXIT1_DR : jtag_state <= jtag_TMS ? UPDATE_DR : PAUSE_DR;
PAUSE_DR : jtag_state <= jtag_TMS ? EXIT2_DR : PAUSE_DR;
EXIT2_DR : jtag_state <= jtag_TMS ? UPDATE_DR : SHIFT_DR;
UPDATE_DR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_IR : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR;
CAPTURE_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
SHIFT_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
EXIT1_IR : jtag_state <= jtag_TMS ? UPDATE_IR : PAUSE_IR;
PAUSE_IR : jtag_state <= jtag_TMS ? EXIT2_IR : PAUSE_IR;
EXIT2_IR : jtag_state <= jtag_TMS ? UPDATE_IR : SHIFT_IR;
UPDATE_IR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
endcase
end
end
// IR or DR shift
always @(posedge jtag_TCK) begin
case (jtag_state)
// IR
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, 1'b1}; //JTAG spec says it must be b01
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS - IR_BITS){1'b0}}, jtag_TDI, shift_reg[IR_BITS - 1:1]}; // right shift 1 bit
// DR
CAPTURE_DR: case (ir_reg)
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, idcode};
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, dtmcs};
REG_DMI : shift_reg <= is_busy ? busy_response : none_busy_response;
default:
shift_reg <= {(SHIFT_REG_BITS){1'b0}};
endcase
SHIFT_DR : case (ir_reg)
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, jtag_TDI}; // in = out
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
REG_DMI : shift_reg <= {jtag_TDI, shift_reg[SHIFT_REG_BITS - 1:1]}; // right shift 1 bit
default:
shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}} , jtag_TDI};
endcase
endcase
end
// start access DM module
always @(posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dtm_req_valid <= 1'b0;
dtm_req_data <= {DTM_REQ_BITS{1'b0}};
end else begin
if (jtag_state == UPDATE_DR) begin
if (ir_reg == REG_DMI) begin
// if DM can be access
if (!is_busy & tx_idle) begin
dtm_req_valid <= 1'b1;
dtm_req_data <= shift_reg;
end
end
end else begin
dtm_req_valid <= 1'b0;
end
end
end
assign tx_valid = dtm_req_valid;
assign tx_data = dtm_req_data;
// DTM reset
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
sticky_busy <= 1'b0;
end else begin
if (jtag_state == UPDATE_DR) begin
if (ir_reg == REG_DTMCS & dtm_reset) begin
sticky_busy <= 1'b0;
end
end else if (jtag_state == CAPTURE_DR) begin
if (ir_reg == REG_DMI) begin
sticky_busy <= is_busy;
end
end
end
end
// receive DM response data
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dm_resp_data <= {DM_RESP_BITS{1'b0}};
end else begin
if (rx_valid) begin
dm_resp_data <= rx_data;
end
end
end
// tx busy
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dm_is_busy <= 1'b0;
end else begin
if (dtm_req_valid) begin
dm_is_busy <= 1'b1;
end else if (rx_valid) begin
dm_is_busy <= 1'b0;
end
end
end
// TAP reset
always @(negedge jtag_TCK) begin
if (jtag_state == TEST_LOGIC_RESET) begin
ir_reg <= REG_IDCODE;
end else if (jtag_state == UPDATE_IR) begin
ir_reg <= shift_reg[IR_BITS - 1:0];
end
end
// TDO output
always @(negedge jtag_TCK) begin
if (jtag_state == SHIFT_IR) begin
jtag_TDO <= shift_reg[0];
end else if (jtag_state == SHIFT_DR) begin
jtag_TDO <= shift_reg[0];
end else begin
jtag_TDO <= 1'b0;
end
end
full_handshake_tx #(
.DW(DTM_REQ_BITS)
) tx(
.clk(jtag_TCK),
.rst_n(rst_n),
.ack_i(dm_ack_i),
.req_i(tx_valid),
.req_data_i(tx_data),
.idle_o(tx_idle),
.req_o(dtm_req_valid_o),
.req_data_o(dtm_req_data_o)
);
full_handshake_rx #(
.DW(DM_RESP_BITS)
) rx(
.clk(jtag_TCK),
.rst_n(rst_n),
.req_i(dm_resp_i),
.req_data_i(dm_resp_data_i),
.ack_o(dtm_ack_o),
.recv_data_o(rx_data),
.recv_rdy_o(rx_valid)
);
endmodule
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_driver #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2)(
rst_n,
jtag_TCK,
jtag_TDI,
jtag_TMS,
jtag_TDO,
// rx
dm_resp_i,
dm_resp_data_i,
dtm_ack_o,
// tx
dm_ack_i,
dtm_req_valid_o,
dtm_req_data_o
);
parameter IDCODE_VERSION = 4'h1;
parameter IDCODE_PART_NUMBER = 16'he200;
parameter IDCODE_MANUFLD = 11'h537;
parameter DTM_VERSION = 4'h1;
parameter IR_BITS = 5;
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 rst_n;
input wire jtag_TCK;
input wire jtag_TDI;
input wire jtag_TMS;
output reg jtag_TDO;
input wire dm_resp_i;
input wire[DM_RESP_BITS - 1:0] dm_resp_data_i;
output wire dtm_ack_o;
input wire dm_ack_i;
output wire dtm_req_valid_o;
output wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
// JTAG StateMachine
parameter TEST_LOGIC_RESET = 4'h0;
parameter RUN_TEST_IDLE = 4'h1;
parameter SELECT_DR = 4'h2;
parameter CAPTURE_DR = 4'h3;
parameter SHIFT_DR = 4'h4;
parameter EXIT1_DR = 4'h5;
parameter PAUSE_DR = 4'h6;
parameter EXIT2_DR = 4'h7;
parameter UPDATE_DR = 4'h8;
parameter SELECT_IR = 4'h9;
parameter CAPTURE_IR = 4'hA;
parameter SHIFT_IR = 4'hB;
parameter EXIT1_IR = 4'hC;
parameter PAUSE_IR = 4'hD;
parameter EXIT2_IR = 4'hE;
parameter UPDATE_IR = 4'hF;
// DTM regs
parameter REG_BYPASS = 5'b11111;
parameter REG_IDCODE = 5'b00001;
parameter REG_DMI = 5'b10001;
parameter REG_DTMCS = 5'b10000;
reg[IR_BITS - 1:0] ir_reg;
reg[SHIFT_REG_BITS - 1:0] shift_reg;
reg[3:0] jtag_state;
wire is_busy;
reg sticky_busy;
reg dtm_req_valid;
reg[DTM_REQ_BITS - 1:0] dtm_req_data;
reg[DM_RESP_BITS - 1:0] dm_resp_data;
reg dm_is_busy;
wire[5:0] addr_bits = DMI_ADDR_BITS[5:0];
wire [SHIFT_REG_BITS - 1:0] busy_response;
wire [SHIFT_REG_BITS - 1:0] none_busy_response;
wire[31:0] idcode;
wire[31:0] dtmcs;
wire[1:0] dmi_stat;
wire dtm_reset;
wire tx_idle;
wire rx_valid;
wire[DM_RESP_BITS - 1:0] rx_data;
wire tx_valid;
wire[DTM_REQ_BITS - 1:0] tx_data;
assign dtm_reset = shift_reg[16];
assign idcode = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
assign dtmcs = {14'b0,
1'b0, // dmihardreset
1'b0, // dmireset
1'b0,
3'h5, // idle
dmi_stat, // dmistat
addr_bits, // abits
DTM_VERSION}; // version
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
assign none_busy_response = dm_resp_data;
assign is_busy = sticky_busy | dm_is_busy;
assign dmi_stat = is_busy ? 2'b01 : 2'b00;
// state switch
always @(posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
jtag_state <= TEST_LOGIC_RESET;
end else begin
case (jtag_state)
TEST_LOGIC_RESET : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
RUN_TEST_IDLE : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_DR : jtag_state <= jtag_TMS ? SELECT_IR : CAPTURE_DR;
CAPTURE_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
SHIFT_DR : jtag_state <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
EXIT1_DR : jtag_state <= jtag_TMS ? UPDATE_DR : PAUSE_DR;
PAUSE_DR : jtag_state <= jtag_TMS ? EXIT2_DR : PAUSE_DR;
EXIT2_DR : jtag_state <= jtag_TMS ? UPDATE_DR : SHIFT_DR;
UPDATE_DR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_IR : jtag_state <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR;
CAPTURE_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
SHIFT_IR : jtag_state <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
EXIT1_IR : jtag_state <= jtag_TMS ? UPDATE_IR : PAUSE_IR;
PAUSE_IR : jtag_state <= jtag_TMS ? EXIT2_IR : PAUSE_IR;
EXIT2_IR : jtag_state <= jtag_TMS ? UPDATE_IR : SHIFT_IR;
UPDATE_IR : jtag_state <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
endcase
end
end
// IR or DR shift
always @(posedge jtag_TCK) begin
case (jtag_state)
// IR
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, 1'b1}; //JTAG spec says it must be b01
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS - IR_BITS){1'b0}}, jtag_TDI, shift_reg[IR_BITS - 1:1]}; // right shift 1 bit
// DR
CAPTURE_DR: case (ir_reg)
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, idcode};
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, dtmcs};
REG_DMI : shift_reg <= is_busy ? busy_response : none_busy_response;
default:
shift_reg <= {(SHIFT_REG_BITS){1'b0}};
endcase
SHIFT_DR : case (ir_reg)
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, jtag_TDI}; // in = out
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bit
REG_DMI : shift_reg <= {jtag_TDI, shift_reg[SHIFT_REG_BITS - 1:1]}; // right shift 1 bit
default:
shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}} , jtag_TDI};
endcase
endcase
end
// start access DM module
always @(posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dtm_req_valid <= 1'b0;
dtm_req_data <= {DTM_REQ_BITS{1'b0}};
end else begin
if (jtag_state == UPDATE_DR) begin
if (ir_reg == REG_DMI) begin
// if DM can be access
if (!is_busy & tx_idle) begin
dtm_req_valid <= 1'b1;
dtm_req_data <= shift_reg;
end
end
end else begin
dtm_req_valid <= 1'b0;
end
end
end
assign tx_valid = dtm_req_valid;
assign tx_data = dtm_req_data;
// DTM reset
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
sticky_busy <= 1'b0;
end else begin
if (jtag_state == UPDATE_DR) begin
if (ir_reg == REG_DTMCS & dtm_reset) begin
sticky_busy <= 1'b0;
end
end else if (jtag_state == CAPTURE_DR) begin
if (ir_reg == REG_DMI) begin
sticky_busy <= is_busy;
end
end
end
end
// receive DM response data
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dm_resp_data <= {DM_RESP_BITS{1'b0}};
end else begin
if (rx_valid) begin
dm_resp_data <= rx_data;
end
end
end
// tx busy
always @ (posedge jtag_TCK or negedge rst_n) begin
if (!rst_n) begin
dm_is_busy <= 1'b0;
end else begin
if (dtm_req_valid) begin
dm_is_busy <= 1'b1;
end else if (rx_valid) begin
dm_is_busy <= 1'b0;
end
end
end
// TAP reset
always @(negedge jtag_TCK) begin
if (jtag_state == TEST_LOGIC_RESET) begin
ir_reg <= REG_IDCODE;
end else if (jtag_state == UPDATE_IR) begin
ir_reg <= shift_reg[IR_BITS - 1:0];
end
end
// TDO output
always @(negedge jtag_TCK) begin
if (jtag_state == SHIFT_IR) begin
jtag_TDO <= shift_reg[0];
end else if (jtag_state == SHIFT_DR) begin
jtag_TDO <= shift_reg[0];
end else begin
jtag_TDO <= 1'b0;
end
end
full_handshake_tx #(
.DW(DTM_REQ_BITS)
) tx(
.clk(jtag_TCK),
.rst_n(rst_n),
.ack_i(dm_ack_i),
.req_i(tx_valid),
.req_data_i(tx_data),
.idle_o(tx_idle),
.req_o(dtm_req_valid_o),
.req_data_o(dtm_req_data_o)
);
full_handshake_rx #(
.DW(DM_RESP_BITS)
) rx(
.clk(jtag_TCK),
.rst_n(rst_n),
.req_i(dm_resp_i),
.req_data_i(dm_resp_data_i),
.ack_o(dtm_ack_o),
.recv_data_o(rx_data),
.recv_rdy_o(rx_valid)
);
endmodule

187
rtl/debug/jtag_dtm.sv Normal file
View File

@ -0,0 +1,187 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "jtag_def.sv"
module jtag_dtm #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2,
localparam TAP_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
localparam DTM_RESP_BITS = TAP_REQ_BITS,
localparam DTM_REQ_BITS = DTM_RESP_BITS,
localparam DMI_RESP_BITS = DTM_REQ_BITS
)(
input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_trst_ni, // JTAG test reset pad
// to jtag_dmi
output wire [DTM_REQ_BITS-1:0] dtm_data_o,
output wire dtm_valid_o,
// from jtag_dmi
input wire dmi_ready_i,
// from jtag_dmi
input wire [DMI_RESP_BITS-1:0] dmi_data_i,
input wire dmi_valid_i,
// to jtag_dmi
output wire dtm_ready_o,
// from jtag_tap
input wire tap_req_i,
input wire [TAP_REQ_BITS-1:0] tap_data_i,
// to jtag_tap
output wire [DTM_RESP_BITS-1:0] data_o,
output wire [31:0] idcode_o,
output wire [31:0] dtmcs_o
);
localparam IDCODE_VERSION = 4'h1;
localparam IDCODE_PART_NUMBER = 16'he200;
localparam IDCODE_MANUFLD = 11'h537;
localparam DTM_VERSION = 4'h1;
localparam S_IDLE = 5'b00001;
localparam S_READ = 5'b00010;
localparam S_WAIT_READ = 5'b00100;
localparam S_WRITE = 5'b01000;
localparam S_WAIT_WRITE = 5'b10000;
reg[4:0] state_d;
reg[4:0] state_q;
reg dtm_valid;
reg[DTM_REQ_BITS-1:0] dtm_data_q;
reg[DTM_REQ_BITS-1:0] dtm_data_d;
reg[DTM_RESP_BITS-1:0] resp_tap_data_q;
reg is_busy;
wire[DTM_RESP_BITS-1:0] busy_response;
wire dtm_busy;
wire[DMI_OP_BITS-1:0] op;
wire[1:0] dtm_state;
wire[DMI_ADDR_BITS-1:0] addr_bits = DMI_ADDR_BITS[5:0];
assign idcode_o = {IDCODE_VERSION, IDCODE_PART_NUMBER, IDCODE_MANUFLD, 1'h1};
assign dtmcs_o = {14'b0,
1'b0, // dmihardreset
1'b0, // dmireset
1'b0,
3'h5, // idle
dtm_state, // dmistat
addr_bits, // abits
DTM_VERSION}; // version
assign busy_response = {{(DMI_ADDR_BITS + DMI_DATA_BITS){1'b0}}, {(DMI_OP_BITS){1'b1}}}; // op = 2'b11
assign dtm_state = is_busy ? 2'b01 : 2'b00;
assign op = tap_data_i[DMI_OP_BITS-1:0];
always @ (*) begin
state_d = state_q;
dtm_valid = 1'b0;
dtm_data_d = dtm_data_q;
case (state_q)
S_IDLE: begin
if (tap_req_i) begin
if (op == `DMI_OP_READ) begin
state_d = S_READ;
dtm_data_d = tap_data_i;
end else if (op == `DMI_OP_WRITE) begin
state_d = S_WRITE;
dtm_data_d = tap_data_i;
end else begin
state_d = S_IDLE;
end
end else begin
state_d = S_IDLE;
end
end
S_READ: begin
dtm_valid = 1'b1;
if (dmi_ready_i) begin
state_d = S_WAIT_READ;
end
end
S_WAIT_READ: begin
if (dmi_valid_i) begin
dtm_data_d = dmi_data_i;
state_d = S_IDLE;
end
end
S_WRITE: begin
dtm_valid = 1'b1;
if (dmi_ready_i) begin
state_d = S_WAIT_WRITE;
end
end
S_WAIT_WRITE: begin
if (dmi_valid_i) begin
dtm_data_d = dmi_data_i;
state_d = S_IDLE;
end
end
default: begin
dtm_data_d = {DTM_REQ_BITS{1'b0}};
state_d = S_IDLE;
end
endcase
end
assign dtm_valid_o = dtm_valid;
assign dtm_data_o = dtm_data_q;
// we will always be ready to core request
assign dtm_ready_o = 1'b1;
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
state_q <= S_IDLE;
dtm_data_q <= {DTM_REQ_BITS{1'b0}};
end else begin
state_q <= state_d;
dtm_data_q <= dtm_data_d;
end
end
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
resp_tap_data_q <= {DTM_RESP_BITS{1'b0}};
is_busy <= 1'b0;
end else begin
if (state_q != S_IDLE) begin
resp_tap_data_q <= busy_response;
is_busy <= 1'b1;
end else begin
resp_tap_data_q <= dtm_data_q;
is_busy <= 1'b0;
end
end
end
assign data_o = resp_tap_data_q;
endmodule

194
rtl/debug/jtag_mem.sv Normal file
View File

@ -0,0 +1,194 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_mem #(
)(
input wire clk,
input wire rst_n,
output wire halted_o,
output wire resumeack_o,
output wire cmdbusy_o,
input wire clear_resumeack_i,
input wire resumereq_i,
input wire haltreq_i,
input wire req_i,
input wire we_i,
input wire [31:0] addr_i,
input wire [3:0] be_i,
input wire [31:0] wdata_i,
output wire [31:0] rdata_o
);
// 16KB
localparam DbgAddressBits = 12;
// x10/a0
localparam LoadBaseAddr = 5'd10;
localparam DataBaseAddr = `DataAddr;
localparam DataEndAddr = (`DataAddr + 4 * `DataCount - 1);
localparam ProgBufBaseAddr = (`DataAddr - 4 * `ProgBufSize);
localparam ProgBufEndAddr = (`DataAddr - 1);
localparam AbstractCmdBaseAddr = (ProgBufBaseAddr - 4 * 10);
localparam AbstractCmdEndAddr = (ProgBufBaseAddr - 1);
localparam WhereToAddr = 12'h300;
localparam FlagsBaseAddr = 12'h400;
localparam FlagsEndAddr = 12'h7FF;
localparam HaltedAddr = 12'h100;
localparam GoingAddr = 12'h104;
localparam ResumingAddr = 12'h108;
localparam ExceptionAddr = 12'h10C;
localparam S_IDLE = 4'b0001;
localparam S_RESUME = 4'b0010;
localparam S_GO = 4'b0100;
localparam S_CMD_EXECUTING = 4'b1000;
reg[3:0] state_d, state_q;
reg[31:0] rdata_d, rdata_q;
reg halted_d, halted_q;
reg resuming_d, resuming_q;
reg resume, go, going;
reg fwd_rom_q;
reg word_enable32_q;
wire fwd_rom_d;
wire[63:0] rom_rdata;
// word mux for 32bit and 64bit buses
wire [63:0] word_mux;
assign word_mux = fwd_rom_q ? rom_rdata : rdata_q;
assign rdata_o = (word_enable32_q) ? word_mux[32 +: 32] : word_mux[0 +: 32];
assign halted_o = halted_q;
assign resumeack_o = resuming_q;
assign cmdbusy_o = 1'b0;
always @ (*) begin
state_d = state_q;
resume = 1'b0;
go = 1'b0;
case (state_q)
S_IDLE: begin
if (resumereq_i && (!resuming_q) &&
halted_q && (!haltreq_i)) begin
state_d = S_RESUME;
end
end
S_RESUME: begin
resume = 1'b1;
if (resuming_q) begin
state_d = S_IDLE;
end
end
default:;
endcase
end
always @ (*) begin
rdata_d = rdata_q;
halted_d = halted_q;
resuming_d = resuming_q;
if (clear_resumeack_i) begin
resuming_d = 1'b0;
end
// write
if (we_i) begin
case (addr_i[DbgAddressBits-1:0])
HaltedAddr: begin
halted_d = 1'b1;
end
GoingAddr: begin
end
ResumingAddr: begin
halted_d = 1'b0;
resuming_d = 1'b1;
end
ExceptionAddr: begin
end
default:;
endcase
// read
end else begin
case (addr_i[DbgAddressBits-1:0])
// harts are polling for flags here
FlagsBaseAddr: begin
rdata_d = {30'b0, resume, go};
end
default:;
endcase
end
end
wire[63:0] rom_addr;
assign rom_addr = {32'h0, addr_i};
assign fwd_rom_d = addr_i[DbgAddressBits-1:0] >= `HaltAddress;
debug_rom u_debug_rom (
.clk_i ( clk ),
.req_i ( 1'b1 ),
.addr_i ( rom_addr ),
.rdata_o ( rom_rdata )
);
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
rdata_q <= 32'h0;
fwd_rom_q <= 1'b0;
word_enable32_q <= 1'b0;
halted_q <= 1'b0;
resuming_q <= 1'b0;
end else begin
rdata_q <= rdata_d;
fwd_rom_q <= fwd_rom_d;
word_enable32_q <= addr_i[2];
halted_q <= halted_d;
resuming_q <= resuming_d;
end
end
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_q <= S_IDLE;
end else begin
state_q <= state_d;
end
end
endmodule

View File

@ -1,57 +1,47 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module vld_rdy #(
parameter CUT_READY = 0)(
input wire clk,
input wire rst_n,
input wire vld_i,
output wire rdy_o,
input wire rdy_i,
output wire vld_o
);
wire vld_set;
wire vld_clr;
wire vld_ena;
wire vld_r;
wire vld_nxt;
// The valid will be set when input handshaked
assign vld_set = vld_i & rdy_o;
// The valid will be clr when output handshaked
assign vld_clr = vld_o & rdy_i;
assign vld_ena = vld_set | vld_clr;
assign vld_nxt = vld_set | (~vld_clr);
gen_en_dff #(1) vld_dff(clk, rst_n, vld_ena, vld_nxt, vld_r);
assign vld_o = vld_r;
if (CUT_READY == 1) begin
// If cut ready, then only accept when stage is not full
assign rdy_o = (~vld_r);
end else begin
// If not cut ready, then can accept when stage is not full or it is popping
assign rdy_o = (~vld_r) | vld_clr;
end
endmodule
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_sba #(
)(
input wire clk,
input wire rst_n,
output wire sbbusy_o,
output wire master_req_o,
input wire master_gnt_i,
input wire master_rvalid_i,
output wire master_we_o,
output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
output wire [31:0] master_wdata_o,
input wire [31:0] master_rdata_i,
input wire master_err_i
);
assign sbbusy_o = 1'b0;
assign master_req_o = 1'b0;
assign master_we_o = 1'b0;
endmodule

175
rtl/debug/jtag_tap.sv Normal file
View File

@ -0,0 +1,175 @@
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_tap #(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32,
parameter DMI_OP_BITS = 2,
parameter IR_BITS = 5,
localparam TAP_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
localparam DTM_RESP_BITS = TAP_REQ_BITS
)(
input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_tdi_i, // JTAG test data input pad
input wire jtag_tms_i, // JTAG test mode select pad
input wire jtag_trst_ni, // JTAG test reset pad
output wire jtag_tdo_o, // JTAG test data output pad
output wire tap_req_o,
output wire[TAP_REQ_BITS-1:0] tap_data_o,
input wire[DTM_RESP_BITS-1:0] dtm_data_i,
input wire[31:0] idcode_i,
input wire[31:0] dtmcs_i
);
localparam SHIFT_REG_BITS = TAP_REQ_BITS;
localparam TEST_LOGIC_RESET = 16'h0001;
localparam RUN_TEST_IDLE = 16'h0002;
localparam SELECT_DR = 16'h0004;
localparam CAPTURE_DR = 16'h0008;
localparam SHIFT_DR = 16'h0010;
localparam EXIT1_DR = 16'h0020;
localparam PAUSE_DR = 16'h0040;
localparam EXIT2_DR = 16'h0080;
localparam UPDATE_DR = 16'h0100;
localparam SELECT_IR = 16'h0200;
localparam CAPTURE_IR = 16'h0400;
localparam SHIFT_IR = 16'h0800;
localparam EXIT1_IR = 16'h1000;
localparam PAUSE_IR = 16'h2000;
localparam EXIT2_IR = 16'h4000;
localparam UPDATE_IR = 16'h8000;
// DTM regs
localparam REG_BYPASS = 5'b11111;
localparam REG_IDCODE = 5'b00001;
localparam REG_DMI = 5'b10001;
localparam REG_DTMCS = 5'b10000;
reg[IR_BITS-1:0] ir_reg;
reg[SHIFT_REG_BITS-1:0] shift_reg;
reg[15:0] tap_state;
reg[15:0] next_state;
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
tap_state <= TEST_LOGIC_RESET;
end else begin
tap_state <= next_state;
end
end
// state switch
always @ (*) begin
case (tap_state)
TEST_LOGIC_RESET : next_state = jtag_tms_i ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
RUN_TEST_IDLE : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
SELECT_DR : next_state = jtag_tms_i ? SELECT_IR : CAPTURE_DR;
CAPTURE_DR : next_state = jtag_tms_i ? EXIT1_DR : SHIFT_DR;
SHIFT_DR : next_state = jtag_tms_i ? EXIT1_DR : SHIFT_DR;
EXIT1_DR : next_state = jtag_tms_i ? UPDATE_DR : PAUSE_DR;
PAUSE_DR : next_state = jtag_tms_i ? EXIT2_DR : PAUSE_DR;
EXIT2_DR : next_state = jtag_tms_i ? UPDATE_DR : SHIFT_DR;
UPDATE_DR : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
SELECT_IR : next_state = jtag_tms_i ? TEST_LOGIC_RESET : CAPTURE_IR;
CAPTURE_IR : next_state = jtag_tms_i ? EXIT1_IR : SHIFT_IR;
SHIFT_IR : next_state = jtag_tms_i ? EXIT1_IR : SHIFT_IR;
EXIT1_IR : next_state = jtag_tms_i ? UPDATE_IR : PAUSE_IR;
PAUSE_IR : next_state = jtag_tms_i ? EXIT2_IR : PAUSE_IR;
EXIT2_IR : next_state = jtag_tms_i ? UPDATE_IR : SHIFT_IR;
UPDATE_IR : next_state = jtag_tms_i ? SELECT_DR : RUN_TEST_IDLE;
default : next_state = TEST_LOGIC_RESET;
endcase
end
// IR or DR shift
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
shift_reg <= {SHIFT_REG_BITS{1'b0}};
end else begin
case (tap_state)
// IR
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}}, 1'b1}; //JTAG spec says it must be 2'b01
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS-IR_BITS){1'b0}}, jtag_tdi_i, shift_reg[IR_BITS-1:1]}; // right shift 1 bit
// DR
CAPTURE_DR: case (ir_reg)
REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, idcode_i};
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, dtmcs_i};
REG_DMI : shift_reg <= dtm_data_i;
default : shift_reg <= {(SHIFT_REG_BITS){1'b0}};
endcase
SHIFT_DR : case (ir_reg)
REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}}, jtag_tdi_i}; // in = out
REG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, jtag_tdi_i, shift_reg[31:1]}; // right shift 1 bit
REG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS-DMI_DATA_BITS){1'b0}}, jtag_tdi_i, shift_reg[31:1]}; // right shift 1 bit
REG_DMI : shift_reg <= {jtag_tdi_i, shift_reg[SHIFT_REG_BITS-1:1]}; // right shift 1 bit
default : shift_reg <= {{(SHIFT_REG_BITS-1){1'b0}} , jtag_tdi_i};
endcase
endcase
end
end
reg tap_req_q;
reg[TAP_REQ_BITS-1:0] tap_data_q;
// send request to DTM module
always @ (posedge jtag_tck_i or negedge jtag_trst_ni) begin
if (!jtag_trst_ni) begin
tap_req_q <= 1'b0;
tap_data_q <= {TAP_REQ_BITS{1'b0}};
end else begin
if ((tap_state == UPDATE_DR) && (ir_reg == REG_DMI)) begin
tap_req_q <= 1'b1;
tap_data_q <= shift_reg;
end else begin
tap_req_q <= 1'b0;
end
end
end
assign tap_req_o = tap_req_q;
assign tap_data_o = tap_data_q;
// ir_reg
always @ (negedge jtag_tck_i) begin
if (tap_state == TEST_LOGIC_RESET) begin
ir_reg <= REG_IDCODE;
end else if (tap_state == UPDATE_IR) begin
ir_reg <= shift_reg[IR_BITS-1:0];
end
end
reg jtag_tdo_q;
// TDO output
always @ (negedge jtag_tck_i) begin
if ((tap_state == SHIFT_IR) || (tap_state == SHIFT_DR)) begin
jtag_tdo_q <= shift_reg[0];
end else begin
jtag_tdo_q <= 1'b0;
end
end
assign jtag_tdo_o = jtag_tdo_q;
endmodule

View File

@ -1,117 +1,161 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "../core/defines.sv"
// JTAG顶层模块
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,
input wire jtag_pin_TMS,
input wire jtag_pin_TDI,
output wire jtag_pin_TDO,
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 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[3:0] mem_sel_o,
output wire req_valid_o,
input wire req_ready_i,
input wire rsp_valid_i,
output wire rsp_ready_o,
output wire halt_req_o,
output wire reset_req_o
);
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;
// jtag_driver输出信号
wire dtm_ack_o;
wire dtm_req_valid_o;
wire[DTM_REQ_BITS - 1:0] dtm_req_data_o;
// jtag_dm输出信号
wire dm_ack_o;
wire[DM_RESP_BITS-1:0] dm_resp_data_o;
wire dm_resp_valid_o;
wire dm_halt_req_o;
wire dm_reset_req_o;
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),
.jtag_TMS(jtag_pin_TMS),
.jtag_TDO(jtag_pin_TDO),
.dm_resp_i(dm_resp_valid_o),
.dm_resp_data_i(dm_resp_data_o),
.dtm_ack_o(dtm_ack_o),
.dm_ack_i(dm_ack_o),
.dtm_req_valid_o(dtm_req_valid_o),
.dtm_req_data_o(dtm_req_data_o)
);
jtag_dm #(
.DMI_ADDR_BITS(DMI_ADDR_BITS),
.DMI_DATA_BITS(DMI_DATA_BITS),
.DMI_OP_BITS(DMI_OP_BITS)
) u_jtag_dm(
.clk(clk),
.rst_n(jtag_rst_n),
.dm_ack_o(dm_ack_o),
.dtm_req_valid_i(dtm_req_valid_o),
.dtm_req_data_i(dtm_req_data_o),
.dtm_ack_i(dtm_ack_o),
.dm_resp_data_o(dm_resp_data_o),
.dm_resp_valid_o(dm_resp_valid_o),
.dm_reg_we_o(reg_we_o),
.dm_reg_addr_o(reg_addr_o),
.dm_reg_wdata_o(reg_wdata_o),
.dm_reg_rdata_i(reg_rdata_i),
.dm_mem_we_o(mem_we_o),
.dm_mem_addr_o(mem_addr_o),
.dm_mem_wdata_o(mem_wdata_o),
.dm_mem_rdata_i(mem_rdata_i),
.dm_mem_sel_o(mem_sel_o),
.req_valid_o(req_valid_o),
.req_ready_i(req_ready_i),
.rsp_valid_i(rsp_valid_i),
.rsp_ready_o(rsp_ready_o),
.dm_halt_req_o(halt_req_o),
.dm_reset_req_o(reset_req_o)
);
endmodule
/*
Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
module jtag_top #(
)(
input wire clk_i,
input wire rst_ni,
output wire debug_req_o,
output wire ndmreset_o,
input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_tdi_i, // JTAG test data input pad
input wire jtag_tms_i, // JTAG test mode select pad
input wire jtag_trst_ni, // JTAG test reset pad
output wire jtag_tdo_o, // JTAG test data output pad
output wire master_req_o,
input wire master_gnt_i,
input wire master_rvalid_i,
output wire master_we_o,
output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
output wire [31:0] master_wdata_o,
input wire [31:0] master_rdata_i,
input wire master_err_i,
input wire slave_req_i,
input wire slave_we_i,
input wire [31:0] slave_addr_i,
input wire [3:0] slave_be_i,
input wire [31:0] slave_wdata_i,
output wire [31:0] slave_rdata_o
);
// addr + data + op = 6 + 32 + 2 = 40
localparam DMI_DATA_WIDTH = 40;
wire [DMI_DATA_WIDTH-1:0] dm_to_dmi_data;
wire dm_to_dmi_valid;
wire dm_to_dmi_ready;
wire [DMI_DATA_WIDTH-1:0] dmi_to_dm_data;
wire dmi_to_dm_valid;
wire dmi_to_dm_ready;
jtag_dm #(
) u_jtag_dm (
.clk (clk_i),
.rst_n (rst_ni),
.dmi_data_i (dmi_to_dm_data),
.dmi_valid_i (dmi_to_dm_valid),
.dm_ready_o (dm_to_dmi_ready),
.dm_data_o (dm_to_dmi_data),
.dm_valid_o (dm_to_dmi_valid),
.dmi_ready_i (dmi_to_dm_ready),
.debug_req_o (debug_req_o),
.ndmreset_o (ndmreset_o),
.master_req_o (master_req_o),
.master_gnt_i (master_gnt_i),
.master_rvalid_i(master_rvalid_i),
.master_we_o (master_we_o),
.master_be_o (master_be_o),
.master_addr_o (master_addr_o),
.master_wdata_o (master_wdata_o),
.master_rdata_i (master_rdata_i),
.master_err_i (master_err_i),
.slave_req_i (slave_req_i),
.slave_we_i (slave_we_i),
.slave_addr_i (slave_addr_i),
.slave_be_i (slave_be_i),
.slave_wdata_i (slave_wdata_i),
.slave_rdata_o (slave_rdata_o)
);
wire [DMI_DATA_WIDTH-1:0] dtm_to_dmi_data;
wire dtm_to_dmi_valid;
wire dtm_to_dmi_ready;
wire [DMI_DATA_WIDTH-1:0] dmi_to_dtm_data;
wire dmi_to_dtm_valid;
wire dmi_to_dtm_ready;
jtag_dmi #(
) u_jtag_dmi (
.jtag_tck_i (jtag_tck_i),
.jtag_trst_ni (jtag_trst_ni),
.jtag_data_i (dtm_to_dmi_data),
.jtag_valid_i (dtm_to_dmi_valid),
.jtag_ready_o (dmi_to_dtm_ready),
.jtag_data_o (dmi_to_dtm_data),
.jtag_valid_o (dmi_to_dtm_valid),
.jtag_ready_i (dtm_to_dmi_ready),
.clk_i (clk_i),
.rst_ni (rst_ni),
.core_data_i (dm_to_dmi_data),
.core_valid_i (dm_to_dmi_valid),
.core_ready_o (dmi_to_dm_ready),
.core_data_o (dmi_to_dm_data),
.core_valid_o (dmi_to_dm_valid),
.core_ready_i (dm_to_dmi_ready)
);
wire tap_to_dtm_req;
wire [DMI_DATA_WIDTH-1:0] tap_to_dtm_data;
wire [DMI_DATA_WIDTH-1:0] dtm_to_tap_data;
wire [31:0] idcode;
wire [31:0] dtmcs;
jtag_dtm #(
) u_jtag_dtm (
.jtag_tck_i (jtag_tck_i),
.jtag_trst_ni (jtag_trst_ni),
.dtm_data_o (dtm_to_dmi_data),
.dtm_valid_o (dtm_to_dmi_valid),
.dmi_ready_i (dmi_to_dtm_ready),
.dmi_data_i (dmi_to_dtm_data),
.dmi_valid_i (dmi_to_dtm_valid),
.dtm_ready_o (dtm_to_dmi_ready),
.tap_req_i (tap_to_dtm_req),
.tap_data_i (tap_to_dtm_data),
.data_o (dtm_to_tap_data),
.idcode_o (idcode),
.dtmcs_o (dtmcs)
);
jtag_tap #(
) u_jtag_tap (
.jtag_tck_i (jtag_tck_i),
.jtag_tdi_i (jtag_tdi_i),
.jtag_tms_i (jtag_tms_i),
.jtag_trst_ni (jtag_trst_ni),
.jtag_tdo_o (jtag_tdo_o),
.tap_req_o (tap_to_dtm_req),
.tap_data_o (tap_to_dtm_data),
.dtm_data_i (dtm_to_tap_data),
.idcode_i (idcode),
.dtmcs_i (dtmcs)
);
endmodule

View File

@ -1,373 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// RIB总线模块
module rib #(
parameter MASTER_NUM = 3,
parameter SLAVE_NUM = 2)(
input wire clk,
input wire rst_n,
// master 0 interface
input wire[31:0] m0_addr_i,
input wire[31:0] m0_data_i,
input wire[3:0] m0_sel_i,
input wire m0_req_vld_i,
input wire m0_rsp_rdy_i,
input wire m0_we_i,
output wire m0_req_rdy_o,
output wire m0_rsp_vld_o,
output wire[31:0] m0_data_o,
// master 1 interface
input wire[31:0] m1_addr_i,
input wire[31:0] m1_data_i,
input wire[3:0] m1_sel_i,
input wire m1_req_vld_i,
input wire m1_rsp_rdy_i,
input wire m1_we_i,
output wire m1_req_rdy_o,
output wire m1_rsp_vld_o,
output wire[31:0] m1_data_o,
// master 2 interface
input wire[31:0] m2_addr_i,
input wire[31:0] m2_data_i,
input wire[3:0] m2_sel_i,
input wire m2_req_vld_i,
input wire m2_rsp_rdy_i,
input wire m2_we_i,
output wire m2_req_rdy_o,
output wire m2_rsp_vld_o,
output wire[31:0] m2_data_o,
// master 3 interface
input wire[31:0] m3_addr_i,
input wire[31:0] m3_data_i,
input wire[3:0] m3_sel_i,
input wire m3_req_vld_i,
input wire m3_rsp_rdy_i,
input wire m3_we_i,
output wire m3_req_rdy_o,
output wire m3_rsp_vld_o,
output wire[31:0] m3_data_o,
// slave 0 interface
input wire[31:0] s0_data_i,
input wire s0_req_rdy_i,
input wire s0_rsp_vld_i,
output wire[31:0] s0_addr_o,
output wire[31:0] s0_data_o,
output wire[3:0] s0_sel_o,
output wire s0_req_vld_o,
output wire s0_rsp_rdy_o,
output wire s0_we_o,
// slave 1 interface
input wire[31:0] s1_data_i,
input wire s1_req_rdy_i,
input wire s1_rsp_vld_i,
output wire[31:0] s1_addr_o,
output wire[31:0] s1_data_o,
output wire[3:0] s1_sel_o,
output wire s1_req_vld_o,
output wire s1_rsp_rdy_o,
output wire s1_we_o,
// slave 2 interface
input wire[31:0] s2_data_i,
input wire s2_req_rdy_i,
input wire s2_rsp_vld_i,
output wire[31:0] s2_addr_o,
output wire[31:0] s2_data_o,
output wire[3:0] s2_sel_o,
output wire s2_req_vld_o,
output wire s2_rsp_rdy_o,
output wire s2_we_o,
// slave 3 interface
input wire[31:0] s3_data_i,
input wire s3_req_rdy_i,
input wire s3_rsp_vld_i,
output wire[31:0] s3_addr_o,
output wire[31:0] s3_data_o,
output wire[3:0] s3_sel_o,
output wire s3_req_vld_o,
output wire s3_rsp_rdy_o,
output wire s3_we_o,
// slave 4 interface
input wire[31:0] s4_data_i,
input wire s4_req_rdy_i,
input wire s4_rsp_vld_i,
output wire[31:0] s4_addr_o,
output wire[31:0] s4_data_o,
output wire[3:0] s4_sel_o,
output wire s4_req_vld_o,
output wire s4_rsp_rdy_o,
output wire s4_we_o
);
/////////////////////////////// mux master //////////////////////////////
wire[MASTER_NUM-1:0] master_req;
wire[31:0] master_addr[MASTER_NUM-1:0];
wire[31:0] master_data[MASTER_NUM-1:0];
wire[3:0] master_sel[MASTER_NUM-1:0];
wire[MASTER_NUM-1:0] master_rsp_rdy;
wire[MASTER_NUM-1:0] master_we;
genvar i;
generate
if (MASTER_NUM == 2) begin: if_m_num_2
assign master_req = {m0_req_vld_i, m1_req_vld_i};
assign master_rsp_rdy = {m0_rsp_rdy_i, m1_rsp_rdy_i};
assign master_we = {m0_we_i, m1_we_i};
wire[32*MASTER_NUM-1:0] m_addr = {m0_addr_i, m1_addr_i};
wire[32*MASTER_NUM-1:0] m_data = {m0_data_i, m1_data_i};
wire[4*MASTER_NUM-1:0] m_sel = {m0_sel_i, m1_sel_i};
for (i = 0; i < MASTER_NUM; i = i + 1) begin: for_m_num_2
assign master_addr[i] = m_addr[(i+1)*32-1:32*i];
assign master_data[i] = m_data[(i+1)*32-1:32*i];
assign master_sel[i] = m_sel[(i+1)*4-1:4*i];
end
end
if (MASTER_NUM == 3) begin: if_m_num_3
assign master_req = {m0_req_vld_i, m1_req_vld_i, m2_req_vld_i};
assign master_rsp_rdy = {m0_rsp_rdy_i, m1_rsp_rdy_i, m2_rsp_rdy_i};
assign master_we = {m0_we_i, m1_we_i, m2_we_i};
wire[32*MASTER_NUM-1:0] m_addr = {m0_addr_i, m1_addr_i, m2_addr_i};
wire[32*MASTER_NUM-1:0] m_data = {m0_data_i, m1_data_i, m2_data_i};
wire[4*MASTER_NUM-1:0] m_sel = {m0_sel_i, m1_sel_i, m2_sel_i};
for (i = 0; i < MASTER_NUM; i = i + 1) begin: for_m_num_3
assign master_addr[i] = m_addr[(i+1)*32-1:32*i];
assign master_data[i] = m_data[(i+1)*32-1:32*i];
assign master_sel[i] = m_sel[(i+1)*4-1:4*i];
end
end
if (MASTER_NUM == 4) begin: if_m_num_4
assign master_req = {m0_req_vld_i, m1_req_vld_i, m2_req_vld_i, m3_req_vld_i};
assign master_rsp_rdy = {m0_rsp_rdy_i, m1_rsp_rdy_i, m2_rsp_rdy_i, m3_rsp_rdy_i};
assign master_we = {m0_we_i, m1_we_i, m2_we_i, m3_we_i};
wire[32*MASTER_NUM-1:0] m_addr = {m0_addr_i, m1_addr_i, m2_addr_i, m3_addr_i};
wire[32*MASTER_NUM-1:0] m_data = {m0_data_i, m1_data_i, m2_data_i, m3_data_i};
wire[4*MASTER_NUM-1:0] m_sel = {m0_sel_i, m1_sel_i, m2_sel_i, m3_sel_i};
for (i = 0; i < MASTER_NUM; i = i + 1) begin: for_m_num_4
assign master_addr[i] = m_addr[(i+1)*32-1:32*i];
assign master_data[i] = m_data[(i+1)*32-1:32*i];
assign master_sel[i] = m_sel[(i+1)*4-1:4*i];
end
end
wire[MASTER_NUM-1:0] master_req_vec;
wire[MASTER_NUM-1:0] master_sel_vec;
// 优先级仲裁机制LSB优先级最高MSB优先级最低
for (i = 0; i < MASTER_NUM; i = i + 1) begin: m_arb
if (i == 0) begin: m_is_0
assign master_req_vec[i] = 1'b1;
end else begin: m_is_not_0
assign master_req_vec[i] = ~(|master_req[i-1:0]);
end
assign master_sel_vec[i] = master_req_vec[i] & master_req[i];
end
reg[31:0] mux_m_addr;
reg[31:0] mux_m_data;
reg[3:0] mux_m_sel;
reg mux_m_req_vld;
reg mux_m_rsp_rdy;
reg mux_m_we;
integer j;
always @ (*) begin: m_out
mux_m_addr = 32'h0;
mux_m_data = 32'h0;
mux_m_sel = 4'h0;
mux_m_req_vld = 1'b0;
mux_m_rsp_rdy = 1'b0;
mux_m_we = 1'b0;
for (j = 0; j < MASTER_NUM; j = j + 1) begin: m_sig_out
mux_m_addr = mux_m_addr | ({32{master_sel_vec[j]}} & master_addr[j]);
mux_m_data = mux_m_data | ({32{master_sel_vec[j]}} & master_data[j]);
mux_m_sel = mux_m_sel | ({4 {master_sel_vec[j]}} & master_sel[j]);
mux_m_req_vld = mux_m_req_vld | ({1 {master_sel_vec[j]}} & master_req[j]);
mux_m_rsp_rdy = mux_m_rsp_rdy | ({1 {master_sel_vec[j]}} & master_rsp_rdy[j]);
mux_m_we = mux_m_we | ({1 {master_sel_vec[j]}} & master_we[j]);
end
end
/////////////////////////////// mux slave /////////////////////////////////
wire[SLAVE_NUM-1:0] slave_sel;
// 访问地址的最高4位决定要访问的是哪一个从设备
// 因此最多支持16个从设备
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: s_sel
assign slave_sel[i] = (mux_m_addr[31:28] == i);
end
wire[SLAVE_NUM-1:0] slave_req_rdy;
wire[SLAVE_NUM-1:0] slave_rsp_vld;
wire[31:0] slave_data[SLAVE_NUM-1:0];
if (SLAVE_NUM == 2) begin: if_s_num_2
assign slave_req_rdy = {s1_req_rdy_i, s0_req_rdy_i};
assign slave_rsp_vld = {s1_rsp_vld_i, s0_rsp_vld_i};
wire[32*SLAVE_NUM-1:0] s_data = {s1_data_i, s0_data_i};
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_2
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
end
end
if (SLAVE_NUM == 3) begin: if_s_num_3
assign slave_req_rdy = {s2_req_rdy_i, s1_req_rdy_i, s0_req_rdy_i};
assign slave_rsp_vld = {s2_rsp_vld_i, s1_rsp_vld_i, s0_rsp_vld_i};
wire[32*SLAVE_NUM-1:0] s_data = {s2_data_i, s1_data_i, s0_data_i};
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_3
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
end
end
if (SLAVE_NUM == 4) begin: if_s_num_4
assign slave_req_rdy = {s3_req_rdy_i, s2_req_rdy_i, s1_req_rdy_i, s0_req_rdy_i};
assign slave_rsp_vld = {s3_rsp_vld_i, s2_rsp_vld_i, s1_rsp_vld_i, s0_rsp_vld_i};
wire[32*SLAVE_NUM-1:0] s_data = {s3_data_i, s2_data_i, s1_data_i, s0_data_i};
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_4
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
end
end
if (SLAVE_NUM == 5) begin: if_s_num_5
assign slave_req_rdy = {s4_req_rdy_i, s3_req_rdy_i, s2_req_rdy_i, s1_req_rdy_i, s0_req_rdy_i};
assign slave_rsp_vld = {s4_rsp_vld_i, s3_rsp_vld_i, s2_rsp_vld_i, s1_rsp_vld_i, s0_rsp_vld_i};
wire[32*SLAVE_NUM-1:0] s_data = {s4_data_i, s3_data_i, s2_data_i, s1_data_i, s0_data_i};
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: for_s_num_5
assign slave_data[i] = s_data[(i+1)*32-1:32*i];
end
end
reg[31:0] mux_s_data;
reg mux_s_req_rdy;
reg mux_s_rsp_vld;
always @ (*) begin: s_out
mux_s_data = 32'h0;
mux_s_req_rdy = 1'b0;
mux_s_rsp_vld = 1'b0;
for (j = 0; j < SLAVE_NUM; j = j + 1) begin: s_sig_out
mux_s_data = mux_s_data | ({32{slave_sel[j]}} & slave_data[j]);
mux_s_req_rdy = mux_s_req_rdy | ({1 {slave_sel[j]}} & slave_req_rdy[j]);
mux_s_rsp_vld = mux_s_rsp_vld | ({1 {slave_sel[j]}} & slave_rsp_vld[j]);
end
end
/////////////////////////////// demux master //////////////////////////////
wire[MASTER_NUM-1:0] demux_m_req_rdy;
wire[MASTER_NUM-1:0] demux_m_rsp_vld;
wire[32*MASTER_NUM-1:0] demux_m_data;
for (i = 0; i < MASTER_NUM; i = i + 1) begin: demux_m_sig
assign demux_m_req_rdy[i] = {1 {master_sel_vec[i]}} & mux_s_req_rdy;
assign demux_m_rsp_vld[i] = {1 {master_sel_vec[i]}} & mux_s_rsp_vld;
assign demux_m_data[(i+1)*32-1:32*i] = {32{master_sel_vec[i]}} & mux_s_data;
end
if (MASTER_NUM == 2) begin: demux_m_sig_2
assign {m0_req_rdy_o, m1_req_rdy_o} = demux_m_req_rdy;
assign {m0_rsp_vld_o, m1_rsp_vld_o} = demux_m_rsp_vld;
assign {m0_data_o, m1_data_o} = demux_m_data;
end
if (MASTER_NUM == 3) begin: demux_m_sig_3
assign {m0_req_rdy_o, m1_req_rdy_o, m2_req_rdy_o} = demux_m_req_rdy;
assign {m0_rsp_vld_o, m1_rsp_vld_o, m2_rsp_vld_o} = demux_m_rsp_vld;
assign {m0_data_o, m1_data_o, m2_data_o} = demux_m_data;
end
if (MASTER_NUM == 4) begin: demux_m_sig_4
assign {m0_req_rdy_o, m1_req_rdy_o, m2_req_rdy_o, m3_req_rdy_o} = demux_m_req_rdy;
assign {m0_rsp_vld_o, m1_rsp_vld_o, m2_rsp_vld_o, m3_rsp_vld_o} = demux_m_rsp_vld;
assign {m0_data_o, m1_data_o, m2_data_o, m3_data_o} = demux_m_data;
end
/////////////////////////////// demux slave //////////////////////////////
wire[32*SLAVE_NUM-1:0] demux_s_addr;
wire[32*SLAVE_NUM-1:0] demux_s_data;
wire[4*SLAVE_NUM-1:0] demux_s_sel;
wire[SLAVE_NUM-1:0] demux_s_req_vld;
wire[SLAVE_NUM-1:0] demux_s_rsp_rdy;
wire[SLAVE_NUM-1:0] demux_s_we;
for (i = 0; i < SLAVE_NUM; i = i + 1) begin: demux_s_sig
// 去掉外设基地址只保留offset
assign demux_s_addr[(i+1)*32-1:32*i] = {32{slave_sel[i]}} & {4'h0, mux_m_addr[27:0]};
assign demux_s_data[(i+1)*32-1:32*i] = {32{slave_sel[i]}} & mux_m_data;
assign demux_s_sel[(i+1)*4-1:4*i] = {4 {slave_sel[i]}} & mux_m_sel;
assign demux_s_req_vld[i] = {1 {slave_sel[i]}} & mux_m_req_vld;
assign demux_s_rsp_rdy[i] = {1 {slave_sel[i]}} & mux_m_rsp_rdy;
assign demux_s_we[i] = {1 {slave_sel[i]}} & mux_m_we;
end
if (SLAVE_NUM == 2) begin: demux_s_sig_2
assign {s1_addr_o, s0_addr_o} = demux_s_addr;
assign {s1_data_o, s0_data_o} = demux_s_data;
assign {s1_sel_o, s0_sel_o} = demux_s_sel;
assign {s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
assign {s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
assign {s1_we_o, s0_we_o} = demux_s_we;
end
if (SLAVE_NUM == 3) begin: demux_s_sig_3
assign {s2_addr_o, s1_addr_o, s0_addr_o} = demux_s_addr;
assign {s2_data_o, s1_data_o, s0_data_o} = demux_s_data;
assign {s2_sel_o, s1_sel_o, s0_sel_o} = demux_s_sel;
assign {s2_req_vld_o, s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
assign {s2_rsp_rdy_o, s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
assign {s2_we_o, s1_we_o, s0_we_o} = demux_s_we;
end
if (SLAVE_NUM == 4) begin: demux_s_sig_4
assign {s3_addr_o, s2_addr_o, s1_addr_o, s0_addr_o} = demux_s_addr;
assign {s3_data_o, s2_data_o, s1_data_o, s0_data_o} = demux_s_data;
assign {s3_sel_o, s2_sel_o, s1_sel_o, s0_sel_o} = demux_s_sel;
assign {s3_req_vld_o, s2_req_vld_o, s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
assign {s3_rsp_rdy_o, s2_rsp_rdy_o, s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
assign {s3_we_o, s2_we_o, s1_we_o, s0_we_o} = demux_s_we;
end
if (SLAVE_NUM == 5) begin: demux_s_sig_5
assign {s4_addr_o, s3_addr_o, s2_addr_o, s1_addr_o, s0_addr_o} = demux_s_addr;
assign {s4_data_o, s3_data_o, s2_data_o, s1_data_o, s0_data_o} = demux_s_data;
assign {s4_sel_o, s3_sel_o, s2_sel_o, s1_sel_o, s0_sel_o} = demux_s_sel;
assign {s4_req_vld_o, s3_req_vld_o, s2_req_vld_o, s1_req_vld_o, s0_req_vld_o} = demux_s_req_vld;
assign {s4_rsp_rdy_o, s3_rsp_rdy_o, s2_rsp_rdy_o, s1_rsp_rdy_o, s0_rsp_rdy_o} = demux_s_rsp_rdy;
assign {s4_we_o, s3_we_o, s2_we_o, s1_we_o, s0_we_o} = demux_s_we;
end
endgenerate
endmodule

View File

@ -15,6 +15,7 @@
*/
`include "../core/defines.sv"
`include "../debug/jtag_def.sv"
// tinyriscv soc顶层模块
module tinyriscv_soc_top(
@ -38,14 +39,18 @@ module tinyriscv_soc_top(
localparam int MASTERS = 2; //Number of master ports
localparam int SLAVES = 2; //Number of slave ports
localparam int MASTERS = 3; // Number of master ports
localparam int SLAVES = 3; // Number of slave ports
localparam int CoreD = 0;
localparam int CoreI = 1;
// masters
localparam int CoreD = 0;
localparam int JtagHost = 1;
localparam int CoreI = 2;
localparam int Rom = 0;
localparam int Ram = 1;
// slaves
localparam int Rom = 0;
localparam int Ram = 1;
localparam int JtagDevice = 2;
wire master_req [MASTERS];
@ -80,12 +85,12 @@ module tinyriscv_soc_top(
wire ndmreset;
wire ndmreset_n;
wire debug_req;
assign ndmreset = 1'b0;
tinyriscv_core #(
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + 16'h800),
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + 16'h808)
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + `HaltAddress),
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + `ExceptionAddress)
) u_tinyriscv_core (
.clk(clk),
.rst_n(ndmreset_n),
@ -111,9 +116,8 @@ module tinyriscv_soc_top(
.irq_timer_i(1'b0),
.irq_external_i(1'b0),
.irq_fast_i(15'b0),
.irq_nm_i(1'b0),
.debug_req_i(1'b0)
.debug_req_i(debug_req)
);
@ -182,7 +186,37 @@ module tinyriscv_soc_top(
.rst_no(ndmreset_n)
);
assign slave_addr_mask[JtagDevice] = `DEBUG_ADDR_MASK;
assign slave_addr_base[JtagDevice] = `DEBUG_ADDR_BASE;
// JTAG module
jtag_top #(
) u_jtag_top (
.clk_i (clk),
.rst_ni (rst_ext_ni),
.debug_req_o (debug_req),
.ndmreset_o (ndmreset),
.jtag_tck_i (sim_jtag_tck),
.jtag_tdi_i (sim_jtag_tdi),
.jtag_tms_i (sim_jtag_tms),
.jtag_trst_ni (sim_jtag_trstn),
.jtag_tdo_o (sim_jtag_tdo),
.master_req_o (master_req[JtagHost]),
.master_gnt_i (master_gnt[JtagHost]),
.master_rvalid_i (master_rvalid[JtagHost]),
.master_we_o (master_we[JtagHost]),
.master_be_o (master_be[JtagHost]),
.master_addr_o (master_addr[JtagHost]),
.master_wdata_o (master_wdata[JtagHost]),
.master_rdata_i (master_rdata[JtagHost]),
.master_err_i (1'b0),
.slave_req_i (slave_req[JtagDevice]),
.slave_we_i (slave_we[JtagDevice]),
.slave_addr_i (slave_addr[JtagDevice]),
.slave_be_i (slave_be[JtagDevice]),
.slave_wdata_i (slave_wdata[JtagDevice]),
.slave_rdata_o (slave_rdata[JtagDevice])
);
`ifdef VERILATOR
sim_jtag #(
@ -191,7 +225,7 @@ module tinyriscv_soc_top(
) u_sim_jtag (
.clock ( clk ),
.reset ( ~rst_ext_ni ),
.enable ( 1'b0 ),
.enable ( 1'b1 ),
.init_done ( rst_ext_ni ),
.jtag_TCK ( sim_jtag_tck ),
.jtag_TMS ( sim_jtag_tms ),

175
rtl/utils/cdc_2phase.sv Normal file
View File

@ -0,0 +1,175 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A two-phase clock domain crossing.
///
/// CONSTRAINT: Requires max_delay of min_period(src_clk_i, dst_clk_i) through
/// the paths async_req, async_ack, async_data.
/* verilator lint_off DECLFILENAME */
module cdc_2phase #(
parameter DATA_WIDTH = 32
)(
input wire src_rst_ni,
input wire src_clk_i,
input wire [DATA_WIDTH-1:0] src_data_i,
input wire src_valid_i,
output wire src_ready_o,
input wire dst_rst_ni,
input wire dst_clk_i,
output wire [DATA_WIDTH-1:0] dst_data_o,
output wire dst_valid_o,
input wire dst_ready_i
);
// Asynchronous handshake signals.
(* dont_touch = "true" *) wire async_req;
(* dont_touch = "true" *) wire async_ack;
(* dont_touch = "true" *) wire[DATA_WIDTH-1:0] async_data;
// The sender in the source domain.
cdc_2phase_src #(.DATA_WIDTH(DATA_WIDTH)) i_src (
.rst_ni ( src_rst_ni ),
.clk_i ( src_clk_i ),
.data_i ( src_data_i ),
.valid_i ( src_valid_i ),
.ready_o ( src_ready_o ),
.async_req_o ( async_req ),
.async_ack_i ( async_ack ),
.async_data_o ( async_data )
);
// The receiver in the destination domain.
cdc_2phase_dst #(.DATA_WIDTH(DATA_WIDTH)) i_dst (
.rst_ni ( dst_rst_ni ),
.clk_i ( dst_clk_i ),
.data_o ( dst_data_o ),
.valid_o ( dst_valid_o ),
.ready_i ( dst_ready_i ),
.async_req_i ( async_req ),
.async_ack_o ( async_ack ),
.async_data_i ( async_data )
);
endmodule
/// Half of the two-phase clock domain crossing located in the source domain.
module cdc_2phase_src #(
parameter DATA_WIDTH = 32
)(
input wire rst_ni,
input wire clk_i,
input wire [DATA_WIDTH-1:0] data_i,
input wire valid_i,
output wire ready_o,
output wire async_req_o,
input wire async_ack_i,
output wire [DATA_WIDTH-1:0] async_data_o
);
(* dont_touch = "true" *)
reg req_src_q, ack_src_q, ack_q;
(* dont_touch = "true" *)
reg[DATA_WIDTH-1:0] data_src_q;
// The req_src and data_src registers change when a new data item is accepted.
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
req_src_q <= 0;
data_src_q <= {DATA_WIDTH{1'b0}};
end else if (valid_i && ready_o) begin
req_src_q <= ~req_src_q;
data_src_q <= data_i;
end
end
// The ack_src and ack registers act as synchronization stages.
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ack_src_q <= 0;
ack_q <= 0;
end else begin
ack_src_q <= async_ack_i;
ack_q <= ack_src_q;
end
end
// Output assignments.
assign ready_o = (req_src_q == ack_q);
assign async_req_o = req_src_q;
assign async_data_o = data_src_q;
endmodule
/// Half of the two-phase clock domain crossing located in the destination
/// domain.
module cdc_2phase_dst #(
parameter DATA_WIDTH = 32
)(
input wire rst_ni,
input wire clk_i,
output wire [DATA_WIDTH-1:0] data_o,
output wire valid_o,
input wire ready_i,
input wire async_req_i,
output wire async_ack_o,
input wire [DATA_WIDTH-1:0] async_data_i
);
(* dont_touch = "true" *)
(* async_reg = "true" *)
reg req_dst_q, req_q0, req_q1, ack_dst_q;
(* dont_touch = "true" *)
reg[DATA_WIDTH-1:0] data_dst_q;
// The ack_dst register changes when a new data item is accepted.
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ack_dst_q <= 0;
end else if (valid_o && ready_i) begin
ack_dst_q <= ~ack_dst_q;
end
end
// The data_dst register changes when a new data item is presented. This is
// indicated by the async_req line changing levels.
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
data_dst_q <= '0;
end else if (req_q0 != req_q1 && !valid_o) begin
data_dst_q <= async_data_i;
end
end
// The req_dst and req registers act as synchronization stages.
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
req_dst_q <= 0;
req_q0 <= 0;
req_q1 <= 0;
end else begin
req_dst_q <= async_req_i;
req_q0 <= req_dst_q;
req_q1 <= req_q0;
end
end
// Output assignments.
assign valid_o = (ack_dst_q != req_q1);
assign data_o = data_dst_q;
assign async_ack_o = ack_dst_q;
endmodule
/* verilator lint_on DECLFILENAME */

View File

@ -1,128 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 数据接收端模块
// 跨时钟域传输,全(四次)握手协议
// req = 1
// ack_o = 1
// req = 0
// ack_o = 0
module full_handshake_rx #(
parameter DW = 32)( // RX要接收数据的位宽
input wire clk, // RX端时钟信号
input wire rst_n, // RX端复位信号
// from tx
input wire req_i, // TX端请求信号
input wire[DW-1:0] req_data_i, // TX端输入数据
// to tx
output wire ack_o, // RX端应答TX端信号
// to rx
output wire[DW-1:0] recv_data_o,// RX端接收到的数据
output wire recv_rdy_o // RX端是否接收到数据信号
);
localparam STATE_IDLE = 2'b01;
localparam STATE_DEASSERT = 2'b10;
reg[1:0] state;
reg[1:0] state_next;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= STATE_IDLE;
end else begin
state <= state_next;
end
end
always @ (*) begin
case (state)
// 等待TX请求信号req=1
STATE_IDLE: begin
if (req == 1'b1) begin
state_next = STATE_DEASSERT;
end else begin
state_next = STATE_IDLE;
end
end
// 等待req=0
STATE_DEASSERT: begin
if (req) begin
state_next = STATE_DEASSERT;
end else begin
state_next = STATE_IDLE;
end
end
default: begin
state_next = STATE_IDLE;
end
endcase
end
reg req_d;
reg req;
// 将请求信号打两拍进行同步
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
req_d <= 1'b0;
req <= 1'b0;
end else begin
req_d <= req_i;
req <= req_d;
end
end
reg[DW-1:0] recv_data;
reg recv_rdy;
reg ack;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
ack <= 1'b0;
recv_rdy <= 1'b0;
recv_data <= {(DW){1'b0}};
end else begin
case (state)
STATE_IDLE: begin
if (req == 1'b1) begin
ack <= 1'b1;
recv_rdy <= 1'b1; // 这个信号只会持续一个时钟
recv_data <= req_data_i; // 这个信号只会持续一个时钟
end
end
STATE_DEASSERT: begin
recv_rdy <= 1'b0;
recv_data <= {(DW){1'b0}};
// req撤销后ack也撤销
if (req == 1'b0) begin
ack <= 1'b0;
end
end
endcase
end
end
assign ack_o = ack;
assign recv_rdy_o = recv_rdy;
assign recv_data_o = recv_data;
endmodule

View File

@ -1,147 +0,0 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 数据发送端模块
// 跨时钟域传输,全(四次)握手协议
// req_o = 1
// ack = 1
// req_o = 0
// ack = 0
module full_handshake_tx #(
parameter DW = 32)( // TX要发送数据的位宽
input wire clk, // TX端时钟信号
input wire rst_n, // TX端复位信号
// from rx
input wire ack_i, // RX端应答信号
// from tx
input wire req_i, // TX端请求信号只需持续一个时钟
input wire[DW-1:0] req_data_i, // TX端要发送的数据只需持续一个时钟
// to tx
output wire idle_o, // TX端是否空闲信号空闲才能发数据
// to rx
output wire req_o, // TX端请求信号
output wire[DW-1:0] req_data_o // TX端要发送的数据
);
localparam STATE_IDLE = 3'b001;
localparam STATE_ASSERT = 3'b010;
localparam STATE_DEASSERT = 3'b100;
reg[2:0] state;
reg[2:0] state_next;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= STATE_IDLE;
end else begin
state <= state_next;
end
end
always @ (*) begin
case (state)
STATE_IDLE: begin
if (req_i == 1'b1) begin
state_next = STATE_ASSERT;
end else begin
state_next = STATE_IDLE;
end
end
// 等待ack=1
STATE_ASSERT: begin
if (!ack) begin
state_next = STATE_ASSERT;
end else begin
state_next = STATE_DEASSERT;
end
end
// 等待ack=0
STATE_DEASSERT: begin
if (!ack) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_DEASSERT;
end
end
default: begin
state_next = STATE_IDLE;
end
endcase
end
reg ack_d;
reg ack;
// 将应答信号打两拍进行同步
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
ack_d <= 1'b0;
ack <= 1'b0;
end else begin
ack_d <= ack_i;
ack <= ack_d;
end
end
reg req;
reg[DW-1:0] req_data;
reg idle;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
idle <= 1'b1;
req <= 1'b0;
req_data <= {(DW){1'b0}};
end else begin
case (state)
// 锁存TX请求数据在收到ack之前一直保持有效
STATE_IDLE: begin
if (req_i == 1'b1) begin
idle <= 1'b0;
req <= req_i;
req_data <= req_data_i;
end else begin
idle <= 1'b1;
req <= 1'b0;
end
end
// 收到RX的ack之后撤销TX请求
STATE_ASSERT: begin
if (ack == 1'b1) begin
req <= 1'b0;
req_data <= {(DW){1'b0}};
end
end
STATE_DEASSERT: begin
if (!ack) begin
idle <= 1'b1;
end
end
endcase
end
end
assign idle_o = idle;
assign req_o = req;
assign req_data_o = req_data;
endmodule

View File

@ -1,46 +1,46 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 将输入打DP拍后输出
module gen_ticks_sync #(
parameter DP = 2,
parameter DW = 32)(
input wire rst_n,
input wire clk,
input wire[DW-1:0] din,
output wire[DW-1:0] dout
);
wire[DW-1:0] sync_dat[DP-1:0];
genvar i;
generate
for (i = 0; i < DP; i = i + 1) begin: ticks_sync
if (i == 0) begin: dp_is_0
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, din, sync_dat[0]);
end else begin: dp_is_not_0
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, sync_dat[i-1], sync_dat[i]);
end
end
endgenerate
assign dout = sync_dat[DP-1];
endmodule
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 将输入打DP拍后输出
module gen_ticks_sync #(
parameter DP = 2,
parameter DW = 32)(
input wire rst_n,
input wire clk,
input wire[DW-1:0] din,
output wire[DW-1:0] dout
);
wire[DW-1:0] sync_dat[DP-1:0];
genvar i;
generate
for (i = 0; i < DP; i = i + 1) begin: ticks_sync
if (i == 0) begin: dp_is_0
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, din, sync_dat[0]);
end else begin: dp_is_not_0
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, sync_dat[i-1], sync_dat[i]);
end
end
endgenerate
assign dout = sync_dat[DP-1];
endmodule

View File

@ -1,173 +1,173 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 带默认值和控制信号的流水线触发器
module gen_pipe_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire hold_en,
input wire[DW-1:0] def_val,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n | hold_en) begin
qout_r <= def_val;
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 复位后输出为0的触发器
module gen_rst_0_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= {DW{1'b0}};
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 复位后输出为1的触发器
module gen_rst_1_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= {DW{1'b1}};
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 复位后输出为默认值的触发器
module gen_rst_def_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire[DW-1:0] def_val,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= def_val;
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 带使能端、复位后输出为0的触发器
module gen_en_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire en,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= {DW{1'b0}};
end else if (en == 1'b1) begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 带使能端、没有复位的触发器
module gen_en_dffnr #(
parameter DW = 32)(
input wire clk,
input wire en,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk) begin
if (en == 1'b1) begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 带默认值和控制信号的流水线触发器
module gen_pipe_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire hold_en,
input wire[DW-1:0] def_val,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n | hold_en) begin
qout_r <= def_val;
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 复位后输出为0的触发器
module gen_rst_0_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= {DW{1'b0}};
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 复位后输出为1的触发器
module gen_rst_1_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= {DW{1'b1}};
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 复位后输出为默认值的触发器
module gen_rst_def_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire[DW-1:0] def_val,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= def_val;
end else begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 带使能端、复位后输出为0的触发器
module gen_en_dff #(
parameter DW = 32)(
input wire clk,
input wire rst_n,
input wire en,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
qout_r <= {DW{1'b0}};
end else if (en == 1'b1) begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule
// 带使能端、没有复位的触发器
module gen_en_dffnr #(
parameter DW = 32)(
input wire clk,
input wire en,
input wire[DW-1:0] din,
output wire[DW-1:0] qout
);
reg[DW-1:0] qout_r;
always @ (posedge clk) begin
if (en == 1'b1) begin
qout_r <= din;
end
end
assign qout = qout_r;
endmodule

View File

@ -1,72 +1,72 @@
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "../core/defines.sv"
module gen_ram #(
parameter DP = 512,
parameter DW = 32,
parameter MW = 4,
parameter AW = 32)(
input wire clk,
input wire[AW-1:0] addr_i,
input wire[DW-1:0] data_i,
input wire[MW-1:0] sel_i,
input wire we_i,
output wire[DW-1:0] data_o
);
reg[DW-1:0] ram [0:DP-1];
reg[AW-1:0] addr_r;
wire[MW-1:0] wen;
wire ren;
assign ren = (~we_i);
assign wen = ({MW{we_i}} & sel_i);
always @ (posedge clk) begin
if (ren) begin
addr_r <= addr_i;
end
end
assign data_o = ram[addr_r];
genvar i;
generate
for (i = 0; i < MW; i = i + 1) begin: sel_width
if ((8 * i + 8) > DW) begin: i_gt_8
always @ (posedge clk) begin: i_gt_8_ff
if (wen[i]) begin: gt_8_wen
ram[addr_i][DW-1:8*i] <= data_i[DW-1:8*i];
end
end
end else begin: i_lt_8
always @ (posedge clk) begin: i_lt_8_ff
if (wen[i]) begin: lt_8_wen
ram[addr_i][8*i+7:8*i] <= data_i[8*i+7:8*i];
end
end
end
end
endgenerate
endmodule
/*
Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
`include "../core/defines.sv"
module gen_ram #(
parameter DP = 512,
parameter DW = 32,
parameter MW = 4,
parameter AW = 32)(
input wire clk,
input wire[AW-1:0] addr_i,
input wire[DW-1:0] data_i,
input wire[MW-1:0] sel_i,
input wire we_i,
output wire[DW-1:0] data_o
);
reg[DW-1:0] ram [0:DP-1];
reg[AW-1:0] addr_r;
wire[MW-1:0] wen;
wire ren;
assign ren = (~we_i);
assign wen = ({MW{we_i}} & sel_i);
always @ (posedge clk) begin
if (ren) begin
addr_r <= addr_i;
end
end
assign data_o = ram[addr_r];
genvar i;
generate
for (i = 0; i < MW; i = i + 1) begin: sel_width
if ((8 * i + 8) > DW) begin: i_gt_8
always @ (posedge clk) begin: i_gt_8_ff
if (wen[i]) begin: gt_8_wen
ram[addr_i][DW-1:8*i] <= data_i[DW-1:8*i];
end
end
end else begin: i_lt_8
always @ (posedge clk) begin: i_lt_8_ff
if (wen[i]) begin: lt_8_wen
ram[addr_i][8*i+7:8*i] <= data_i[8*i+7:8*i];
end
end
end
end
endgenerate
endmodule

View File

@ -0,0 +1,30 @@
debug_level 2
adapter_khz 10000
interface remote_bitbang
remote_bitbang_host localhost
remote_bitbang_port 9999
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1e200a6f
foreach t [jtag names] {
puts [format "TAP: %s\n" $t]
}
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
riscv set_reset_timeout_sec 2000
riscv set_command_timeout_sec 2000
# prefer to use sba for system bus access
riscv set_prefer_sba on
# dump jtag chain
scan_chain
init
riscv test_compliance
shutdown

31
sim/jtag_debug.cfg Normal file
View File

@ -0,0 +1,31 @@
debug_level 2
adapter_khz 10000
interface remote_bitbang
remote_bitbang_host localhost
remote_bitbang_port 9999
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1e200a6f
foreach t [jtag names] {
puts [format "TAP: %s\n" $t]
}
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
riscv set_reset_timeout_sec 2000
riscv set_command_timeout_sec 2000
# prefer to use sba for system bus access
riscv set_prefer_sba on
# dump jtag chain
scan_chain
init
halt
echo "Ready for Remote Connections"

View File

@ -34,7 +34,7 @@ module tb_top_verilator #(
$display("No firmware specified");
end
end
/*
always @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
@ -65,7 +65,7 @@ module tb_top_verilator #(
end
end
end
*/
tinyriscv_soc_top u_tinyriscv_soc_top(
.clk(clk_i),
.rst_ext_ni(rst_ni)