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/core
+incdir+../rtl/debug
../rtl/core/clint.sv
../rtl/core/csr_reg.sv ../rtl/core/csr_reg.sv
../rtl/core/csr.sv ../rtl/core/csr.sv
../rtl/core/defines.sv ../rtl/core/defines.sv
../rtl/core/divider.sv ../rtl/core/divider.sv
../rtl/core/exception.sv
../rtl/core/exu.sv ../rtl/core/exu.sv
../rtl/core/exu_alu_datapath.sv ../rtl/core/exu_alu_datapath.sv
../rtl/core/exu_commit.sv ../rtl/core/exu_commit.sv
@ -22,9 +22,15 @@
../rtl/core/tinyriscv_core.sv ../rtl/core/tinyriscv_core.sv
../rtl/core/tracer.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_dm.sv
../rtl/debug/jtag_driver.sv ../rtl/debug/jtag_mem.sv
../rtl/debug/jtag_sba.sv
../rtl/debug/jtag_top.sv ../rtl/debug/jtag_top.sv
../rtl/debug/debug_rom.sv
../rtl/perips/gpio.sv ../rtl/perips/gpio.sv
../rtl/perips/ram.sv ../rtl/perips/ram.sv
@ -32,18 +38,13 @@
../rtl/perips/timer.sv ../rtl/perips/timer.sv
../rtl/perips/uart.sv ../rtl/perips/uart.sv
../rtl/sys_bus/rib.sv
../rtl/sys_bus/obi_interconnect.sv ../rtl/sys_bus/obi_interconnect.sv
../rtl/sys_bus/obi_interconnect_master_sel.sv ../rtl/sys_bus/obi_interconnect_master_sel.sv
../rtl/sys_bus/obi_interconnect_slave_sel.sv ../rtl/sys_bus/obi_interconnect_slave_sel.sv
../rtl/top/tinyriscv_soc_top.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_buf.sv
../rtl/utils/gen_dff.sv ../rtl/utils/gen_dff.sv
../rtl/utils/gen_ram.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] mtvec_o, // mtvec寄存器值
output wire[31:0] mepc_o, // mepc寄存器值 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; reg[31:0] mhartid_d;
wire[31:0] mhartid_q; wire[31:0] mhartid_q;
reg mhartid_we; reg mhartid_we;
reg[31:0] dpc_d;
wire[31:0] dpc_q;
reg dpc_we;
reg[63:0] cycle; reg[63:0] cycle;
@ -83,6 +88,8 @@ module csr_reg(
assign mtvec_o = mtvec_q; assign mtvec_o = mtvec_q;
assign mepc_o = mepc_q; assign mepc_o = mepc_q;
assign mstatus_o = mstatus_q; assign mstatus_o = mstatus_q;
assign mie_o = mie_q;
assign dpc_o = dpc_q;
reg[31:0] exu_rdata; reg[31:0] exu_rdata;
@ -122,6 +129,9 @@ module csr_reg(
`CSR_MHARTID: begin `CSR_MHARTID: begin
exu_rdata = mhartid_q; exu_rdata = mhartid_q;
end end
`CSR_DPC: begin
exu_rdata = dpc_q;
end
default: begin default: begin
exu_rdata = 32'h0; exu_rdata = 32'h0;
end end
@ -154,6 +164,8 @@ module csr_reg(
dscratch1_we = 1'b0; dscratch1_we = 1'b0;
mhartid_d = mhartid_q; mhartid_d = mhartid_q;
mhartid_we = 1'b0; mhartid_we = 1'b0;
dpc_d = dpc_q;
dpc_we = 1'b0;
if (we) begin if (we) begin
case (waddr[11:0]) case (waddr[11:0])
@ -193,6 +205,10 @@ module csr_reg(
mhartid_d = wdata; mhartid_d = wdata;
mhartid_we = 1'b1; mhartid_we = 1'b1;
end end
`CSR_DPC: begin
dpc_d = wdata;
dpc_we = 1'b1;
end
default:; default:;
endcase endcase
end end
@ -297,4 +313,15 @@ module csr_reg(
.rdata_o(mhartid_q) .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 endmodule

View File

@ -54,6 +54,7 @@
`define INST_MRET 32'h30200073 `define INST_MRET 32'h30200073
`define INST_ECALL 32'h00000073 `define INST_ECALL 32'h00000073
`define INST_EBREAK 32'h00100073 `define INST_EBREAK 32'h00100073
`define INST_DRET 32'h7b200073
// 指令译码信息 // 指令译码信息
`define DECINFO_GRP_BUS 2:0 `define DECINFO_GRP_BUS 2:0
@ -118,12 +119,13 @@
`define DECINFO_MEM_SH (`DECINFO_GRP_WIDTH+6) `define DECINFO_MEM_SH (`DECINFO_GRP_WIDTH+6)
`define DECINFO_MEM_SW (`DECINFO_GRP_WIDTH+7) `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_ECALL (`DECINFO_GRP_WIDTH+0)
`define DECINFO_SYS_EBREAK (`DECINFO_GRP_WIDTH+1) `define DECINFO_SYS_EBREAK (`DECINFO_GRP_WIDTH+1)
`define DECINFO_SYS_NOP (`DECINFO_GRP_WIDTH+2) `define DECINFO_SYS_NOP (`DECINFO_GRP_WIDTH+2)
`define DECINFO_SYS_MRET (`DECINFO_GRP_WIDTH+3) `define DECINFO_SYS_MRET (`DECINFO_GRP_WIDTH+3)
`define DECINFO_SYS_FENCE (`DECINFO_GRP_WIDTH+4) `define DECINFO_SYS_FENCE (`DECINFO_GRP_WIDTH+4)
`define DECINFO_SYS_DRET (`DECINFO_GRP_WIDTH+5)
// 最长的那组 // 最长的那组
`define DECINFO_WIDTH `DECINFO_CSR_BUS_WIDTH `define DECINFO_WIDTH `DECINFO_CSR_BUS_WIDTH
@ -137,6 +139,8 @@
`define CSR_MIE 12'h304 `define CSR_MIE 12'h304
`define CSR_MSTATUS 12'h300 `define CSR_MSTATUS 12'h300
`define CSR_MSCRATCH 12'h340 `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_DSCRATCH0 12'h7b2
`define CSR_DSCRATCH1 12'h7b3 `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_ecall_o, // ecall指令
output wire inst_ebreak_o, // ebreak指令 output wire inst_ebreak_o, // ebreak指令
output wire inst_mret_o, // mret指令 output wire inst_mret_o, // mret指令
output wire inst_dret_o, // dret指令
// mem // mem
input wire[31:0] mem_rdata_i, // 内存输入数据 input wire[31:0] mem_rdata_i, // 内存输入数据
@ -143,6 +144,7 @@ module exu(
wire sys_op_ecall_o; wire sys_op_ecall_o;
wire sys_op_ebreak_o; wire sys_op_ebreak_o;
wire sys_op_fence_o; wire sys_op_fence_o;
wire sys_op_dret_o;
exu_dispatch u_exu_dispatch( exu_dispatch u_exu_dispatch(
// input // input
@ -219,12 +221,14 @@ module exu(
.sys_op_mret_o(sys_op_mret_o), .sys_op_mret_o(sys_op_mret_o),
.sys_op_ecall_o(sys_op_ecall_o), .sys_op_ecall_o(sys_op_ecall_o),
.sys_op_ebreak_o(sys_op_ebreak_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_ecall_o = sys_op_ecall_o;
assign inst_ebreak_o = sys_op_ebreak_o; assign inst_ebreak_o = sys_op_ebreak_o;
assign inst_mret_o = sys_op_mret_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] alu_res_o;
wire[31:0] bjp_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_mret_o,
output wire sys_op_ecall_o, output wire sys_op_ecall_o,
output wire sys_op_ebreak_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_ecall_o = sys_info[`DECINFO_SYS_ECALL];
assign sys_op_ebreak_o = sys_info[`DECINFO_SYS_EBREAK]; assign sys_op_ebreak_o = sys_info[`DECINFO_SYS_EBREAK];
assign sys_op_fence_o = sys_info[`DECINFO_SYS_FENCE]; assign sys_op_fence_o = sys_info[`DECINFO_SYS_FENCE];
assign sys_op_dret_o = sys_info[`DECINFO_SYS_DRET];
endmodule endmodule

View File

@ -156,6 +156,7 @@ module idu(
wire inst_remu = opcode_0110011 & funct3_111 & funct7_0000001; wire inst_remu = opcode_0110011 & funct3_111 & funct7_0000001;
wire inst_nop = (inst_i == `INST_NOP); wire inst_nop = (inst_i == `INST_NOP);
wire inst_mret = (inst_i == `INST_MRET); wire inst_mret = (inst_i == `INST_MRET);
wire inst_dret = (inst_i == `INST_DRET);
// 将指令分类 // 将指令分类
wire inst_type_load = opcode_0000011; 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_EBREAK] = inst_ebreak;
assign dec_sys_info_bus[`DECINFO_SYS_NOP] = inst_nop; 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_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; 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_bjp = inst_jal | inst_jalr | inst_type_branch;
wire op_muldiv = inst_type_muldiv; wire op_muldiv = inst_type_muldiv;
wire op_csr = inst_csrrw | inst_csrrwi | inst_csrrs | inst_csrrsi | inst_csrrc | inst_csrrci; 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; 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}) | 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_timer_i,
input wire irq_external_i, input wire irq_external_i,
input wire[14:0] irq_fast_i, input wire[14:0] irq_fast_i,
input wire irq_nm_i,
// debug req signal // debug req signal
input wire debug_req_i input wire debug_req_i
@ -114,6 +113,7 @@ module tinyriscv_core #(
wire ex_inst_ecall_o; wire ex_inst_ecall_o;
wire ex_inst_ebreak_o; wire ex_inst_ebreak_o;
wire ex_inst_mret_o; wire ex_inst_mret_o;
wire ex_inst_dret_o;
wire ex_inst_valid_o; wire ex_inst_valid_o;
// gpr_reg模块输出信号 // gpr_reg模块输出信号
@ -126,6 +126,8 @@ module tinyriscv_core #(
wire[31:0] csr_mtvec_o; wire[31:0] csr_mtvec_o;
wire[31:0] csr_mepc_o; wire[31:0] csr_mepc_o;
wire[31:0] csr_mstatus_o; wire[31:0] csr_mstatus_o;
wire[31:0] csr_mie_o;
wire[31:0] csr_dpc_o;
// pipe_ctrl模块输出信号 // pipe_ctrl模块输出信号
wire[31:0] ctrl_flush_addr_o; wire[31:0] ctrl_flush_addr_o;
@ -197,7 +199,9 @@ module tinyriscv_core #(
.clint_wdata_i(clint_csr_wdata_o), .clint_wdata_i(clint_csr_wdata_o),
.mtvec_o(csr_mtvec_o), .mtvec_o(csr_mtvec_o),
.mepc_o(csr_mepc_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( ifu_idu u_ifu_idu(
@ -283,6 +287,7 @@ module tinyriscv_core #(
.inst_ecall_o(ex_inst_ecall_o), .inst_ecall_o(ex_inst_ecall_o),
.inst_ebreak_o(ex_inst_ebreak_o), .inst_ebreak_o(ex_inst_ebreak_o),
.inst_mret_o(ex_inst_mret_o), .inst_mret_o(ex_inst_mret_o),
.inst_dret_o(ex_inst_dret_o),
.int_stall_i(clint_stall_flag_o), .int_stall_i(clint_stall_flag_o),
.csr_raddr_o(ex_csr_raddr_o), .csr_raddr_o(ex_csr_raddr_o),
.csr_rdata_i(csr_ex_data_o), .csr_rdata_i(csr_ex_data_o),
@ -300,19 +305,26 @@ module tinyriscv_core #(
.rd_we_i(ie_rd_we_o) .rd_we_i(ie_rd_we_o)
); );
clint u_clint( exception u_exception(
.clk(clk), .clk(clk),
.rst_n(rst_n), .rst_n(rst_n),
.int_flag_i(`INT_NONE), .inst_valid_i(ex_inst_valid_o),
.inst_ecall_i(ex_inst_ecall_o), .inst_ecall_i(ex_inst_ecall_o),
.inst_ebreak_i(ex_inst_ebreak_o), .inst_ebreak_i(ex_inst_ebreak_o),
.inst_mret_i(ex_inst_mret_o), .inst_mret_i(ex_inst_mret_o),
.inst_dret_i(ex_inst_dret_o),
.inst_addr_i(ie_dec_pc_o), .inst_addr_i(ie_dec_pc_o),
.jump_flag_i(ex_jump_flag_o), .mtvec_i(csr_mtvec_o),
.mem_access_misaligned_i(ex_mem_access_misaligned_o), .mepc_i(csr_mepc_o),
.csr_mtvec_i(csr_mtvec_o), .mstatus_i(csr_mstatus_o),
.csr_mepc_i(csr_mepc_o), .mie_i(csr_mie_o),
.csr_mstatus_i(csr_mstatus_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_we_o(clint_csr_we_o),
.csr_waddr_o(clint_csr_waddr_o), .csr_waddr_o(clint_csr_waddr_o),
.csr_wdata_o(clint_csr_wdata_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 Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
`define DTM_OP_NOP 2'b00 `include "jtag_def.sv"
`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,
module jtag_dm #( parameter DMI_OP_BITS = 2,
parameter DMI_ADDR_BITS = 6, localparam DMI_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS,
parameter DMI_DATA_BITS = 32, localparam DMI_RESP_BITS = DMI_REQ_BITS
parameter DMI_OP_BITS = 2)( )(
clk, input wire clk,
rst_n, input wire rst_n,
// rx // from DMI
dm_ack_o, input wire [DMI_REQ_BITS-1:0] dmi_data_i,
dtm_req_valid_i, input wire dmi_valid_i,
dtm_req_data_i, output wire dm_ready_o,
// tx // to DMI
dtm_ack_i, output wire [DMI_RESP_BITS-1:0] dm_data_o,
dm_resp_data_o, output wire dm_valid_o,
dm_resp_valid_o, input wire dmi_ready_i,
dm_reg_we_o, output wire debug_req_o,
dm_reg_addr_o, output wire ndmreset_o,
dm_reg_wdata_o,
dm_reg_rdata_i, // jtag access mem devices(DM as master)
dm_mem_we_o, output wire master_req_o,
dm_mem_addr_o, input wire master_gnt_i,
dm_mem_wdata_o, input wire master_rvalid_i,
dm_mem_rdata_i, output wire master_we_o,
dm_mem_sel_o, output wire [3:0] master_be_o,
output wire [31:0] master_addr_o,
req_valid_o, output wire [31:0] master_wdata_o,
req_ready_i, input wire [31:0] master_rdata_i,
rsp_valid_i, input wire master_err_i,
rsp_ready_o,
// core fetch instr or mem(DM as slave)
dm_halt_req_o, input wire slave_req_i,
dm_reset_req_o 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,
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS; output wire [31:0] slave_rdata_o
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
parameter SHIFT_REG_BITS = DTM_REQ_BITS; );
// 输入输出信号 localparam HARTINFO = {8'h0, 4'h2, 3'b0, 1'b1, `DataCount, `DataAddr};
input wire clk;
input wire rst_n; wire halted;
output wire dm_ack_o; wire resumeack;
input wire dtm_req_valid_i; wire sbbusy;
input wire[DTM_REQ_BITS-1:0] dtm_req_data_i; wire[DMI_OP_BITS-1:0] dm_op;
input wire dtm_ack_i; wire[DMI_ADDR_BITS-1:0] dm_op_addr;
output wire[DM_RESP_BITS-1:0] dm_resp_data_o; wire[DMI_DATA_BITS-1:0] dm_op_data;
output wire dm_resp_valid_o;
output wire dm_reg_we_o; reg havereset_d, havereset_q;
output wire[4:0] dm_reg_addr_o; reg clear_resumeack;
output wire[31:0] dm_reg_wdata_o; reg sbaddress_write_valid;
input wire[31:0] dm_reg_rdata_i; reg sbdata_write_valid;
output wire dm_mem_we_o; reg[31:0] dm_resp_data_d, dm_resp_data_q;
output wire[31:0] dm_mem_addr_o; wire[31:0] sba_sbaddress;
output wire[31:0] dm_mem_wdata_o; wire[31:0] dm_sbaddress;
input wire[31:0] dm_mem_rdata_i; wire resumereq;
output wire[3:0] dm_mem_sel_o; wire cmdbusy;
output wire req_valid_o;
input wire req_ready_i; // DM regs
input wire rsp_valid_i; reg[31:0] dmstatus;
output wire rsp_ready_o; reg[31:0] dmcontrol_d, dmcontrol_q;
output wire dm_halt_req_o; reg[31:0] abstractcs;
output wire dm_reset_req_o; reg[31:0] sbcs_d, sbcs_q;
reg[31:0] sbdata0_d, sbdata0_q;
// DM模块寄存器 reg[31:0] sbaddress0_d, sbaddress0_q;
reg[31:0] dcsr; reg[31:0] command_d, command_q;
reg[31:0] dmstatus; reg[31:0] data0_d, data0_q;
reg[31:0] dmcontrol; reg[2:0] cmderr_d, cmderr_q;
reg[31:0] hartinfo;
reg[31:0] abstractcs; assign dm_sbaddress = sbaddress0_q;
reg[31:0] data0;
reg[31:0] sbcs; assign dm_op = dmi_data_i[DMI_OP_BITS-1:0];
reg[31:0] sbaddress0; assign dm_op_addr = dmi_data_i[DMI_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS];
reg[31:0] sbdata0; assign dm_op_data = dmi_data_i[DMI_DATA_BITS+DMI_OP_BITS-1:DMI_OP_BITS];
reg[31:0] command;
// DM模块寄存器地址 localparam S_REQ = 2'b01;
localparam DCSR = 16'h7b0; localparam S_RESP = 2'b10;
localparam DMSTATUS = 6'h11;
localparam DMCONTROL = 6'h10; reg[2:0] req_state_d, req_state_q;
localparam HARTINFO = 6'h12; reg dm_valid_d, dm_valid_q;
localparam ABSTRACTCS = 6'h16;
localparam DATA0 = 6'h04; // response FSM
localparam SBCS = 6'h38; always @ (*) begin
localparam SBADDRESS0 = 6'h39; req_state_d = req_state_q;
localparam SBDATA0 = 6'h3C; dm_valid_d = dm_valid_q;
localparam COMMAND = 6'h17;
localparam DPC = 16'h7b1; case (req_state_q)
S_REQ: begin
localparam OP_SUCC = 2'b00; if (dmi_valid_i & dm_ready_o) begin
req_state_d = S_RESP;
localparam STATE_IDLE = 3'b001; dm_valid_d = 1'b1;
localparam STATE_EXE = 3'b010; end
localparam STATE_END = 3'b100; end
reg[2:0] state; S_RESP: begin
reg[31:0] read_data; if (dmi_ready_i) begin
reg dm_reg_we; dm_valid_d = 1'b0;
reg[4:0] dm_reg_addr; req_state_d = S_REQ;
reg[31:0] dm_reg_wdata; end
reg dm_mem_we; end
reg[31:0] dm_mem_addr;
reg[31:0] dm_mem_wdata; default:;
reg[31:0] dm_mem_rdata; endcase
reg dm_halt_req; end
reg dm_reset_req;
reg need_resp; always @ (posedge clk or negedge rst_n) begin
reg is_read_reg; if (!rst_n) begin
wire rx_valid; req_state_q <= S_REQ;
wire[DTM_REQ_BITS-1:0] rx_data; // driver请求数据 dm_valid_q <= 1'b0;
reg[DTM_REQ_BITS-1:0] rx_data_r; end else begin
req_state_q <= req_state_d;
wire[3:0] dm_mem_sel = (sbcs[19:17] == 3'd0)? 4'b0001: dm_valid_q <= dm_valid_d;
(sbcs[19:17] == 3'd1)? 4'b0011: end
4'b1111; end
wire[2:0] address_inc_step = (sbcs[19:17] == 3'd0)? 3'd1:
(sbcs[19:17] == 3'd1)? 3'd2: // we always ready to receive dmi request
3'd4; assign dm_ready_o = 1'b1;
wire[31:0] sbaddress0_next = sbaddress0 + {29'h0, address_inc_step}; assign dm_valid_o = dm_valid_q;
wire[DM_RESP_BITS-1:0] dm_resp_data; assign dm_data_o = {{DMI_ADDR_BITS{1'b0}}, dm_resp_data_q, 2'b00}; // response successfully
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]; // DMI read or write operation
wire[DMI_ADDR_BITS-1:0] address = rx_data_r[DTM_REQ_BITS-1:DMI_DATA_BITS+DMI_OP_BITS]; always @ (*) begin
// dmstatus
wire req_sys_bus = ~(address == DMSTATUS); dmstatus = 32'h0;
dmstatus[`Version] = `DbgVersion013;
always @ (posedge clk or negedge rst_n) begin dmstatus[`Authenticated] = 1'b1;
if (!rst_n) begin dmstatus[`Allresumeack] = resumeack;
dm_mem_we <= 1'b0; dmstatus[`Anyresumeack] = resumeack;
dm_reg_we <= 1'b0; dmstatus[`Allhavereset] = havereset_q;
dm_halt_req <= 1'b0; dmstatus[`Anyhavereset] = havereset_q;
dm_reset_req <= 1'b0; dmstatus[`Allhalted] = halted;
dm_mem_addr <= 32'h0; dmstatus[`Anyhalted] = halted;
dm_reg_addr <= 5'h0; dmstatus[`Allrunning] = ~halted;
sbaddress0 <= 32'h0; dmstatus[`Anyrunning] = ~halted;
dcsr <= 32'h0;
hartinfo <= 32'h0; // abstractcs
sbcs <= 32'h20040404; cmderr_d = cmderr_q;
dmcontrol <= 32'h0; abstractcs = 32'h0;
abstractcs <= 32'h1000003; abstractcs[`Datacount] = `DataCount;
data0 <= 32'h0; abstractcs[`Progbufsize] = `ProgBufSize;
sbdata0 <= 32'h0; abstractcs[`Busy] = cmdbusy;
command <= 32'h0; abstractcs[`Cmderr] = cmderr_q;
dm_reg_wdata <= 32'h0;
dm_mem_wdata <= 32'h0; havereset_d = havereset_q;
dm_mem_rdata <= 32'h0; sbaddress0_d = sba_sbaddress;
dmstatus <= 32'h430c82; dmcontrol_d = dmcontrol_q;
is_read_reg <= 1'b0; clear_resumeack = 1'b0;
read_data <= 32'h0; sbaddress_write_valid = 1'b0;
need_resp <= 1'b0; sbdata_write_valid = 1'b0;
state <= STATE_IDLE;
end else begin data0_d = data0_q;
case (state) sbcs_d = sbcs_q;
STATE_IDLE: begin sbdata0_d = sbdata0_q;
// 接收到driver的请求 dm_resp_data_d = dm_resp_data_q;
if (rx_valid) begin
rx_data_r <= rx_data; if (dmi_valid_i & dm_ready_o) begin
state <= STATE_EXE; // read
end if (dm_op == `DMI_OP_READ) begin
end case (dm_op_addr)
STATE_EXE: begin `DMStatus: dm_resp_data_d = dmstatus;
state <= STATE_END; `DMControl: dm_resp_data_d = dmcontrol_q;
need_resp <= 1'b1; `Hartinfo: dm_resp_data_d = HARTINFO;
case (op) `SBCS: dm_resp_data_d = sbcs_q;
`DTM_OP_READ: begin `AbstractCS:dm_resp_data_d = abstractcs;
case (address) default:;
DMSTATUS: begin endcase
read_data <= dmstatus;
end // write
DMCONTROL: begin end else if (dm_op == `DMI_OP_WRITE) begin
read_data <= dmcontrol; case (dm_op_addr)
end `DMControl: begin
HARTINFO: begin dmcontrol_d = dm_op_data;
read_data <= hartinfo; if (dmcontrol_d[`Ackhavereset]) begin
end havereset_d = 1'b0;
SBCS: begin end
read_data <= sbcs; end
end
ABSTRACTCS: begin `Data0: begin
read_data <= abstractcs; data0_d = dm_op_data;
end end
DATA0: begin
if (is_read_reg == 1'b1) begin `SBCS: begin
read_data <= dm_reg_rdata_i; if (sbbusy) begin
end else begin sbcs_d[`Sbbusyerror] = 1'b1;
read_data <= data0; end else begin
end sbcs_d = dm_op_data;
is_read_reg <= 1'b0; // write 1 to clear
end sbcs_d[`Sbbusyerror] = sbcs_q[`Sbbusyerror] & (~sbcs_d[`Sbbusyerror]);
SBDATA0: begin sbcs_d[`Sberror] = sbcs_q[`Sberror] & (~sbcs_d[`Sberror]);
read_data <= dm_mem_rdata; end
if (sbcs[16] == 1'b1) begin end
sbaddress0 <= sbaddress0_next;
end `SBAddress0: begin
if (sbcs[15] == 1'b1) begin if (sbbusy | sbcs_d[`Sbbusyerror]) begin
dm_mem_addr <= sbaddress0_next; sbcs_d[`Sbbusyerror] = 1'b1;
end end else begin
end sbaddress0_d = dm_op_data;
default: begin sbaddress_write_valid = (sbcs_q[`Sberror] == 3'b0);
read_data <= {(DMI_DATA_BITS){1'b0}}; end
end end
endcase
end `SBData0: begin
if (sbbusy | sbcs_d[`Sbbusyerror]) begin
`DTM_OP_WRITE: begin sbcs_d[`Sbbusyerror] = 1'b1;
read_data <= {(DMI_DATA_BITS){1'b0}}; end else begin
case (address) sbdata0_d = dm_op_data;
DMCONTROL: begin sbdata_write_valid = (sbcs_q[`Sberror] == 3'b0);
// reset DM module end
if (data[0] == 1'b0) begin end
dcsr <= 32'hc0;
dmstatus <= 32'h430c82; // not halted, all running `AbstractCS: begin
hartinfo <= 32'h0;
sbcs <= 32'h20040404; end
abstractcs <= 32'h1000003;
dmcontrol <= data; default:;
dm_halt_req <= 1'b0; endcase
dm_reset_req <= 1'b0; // nop
// DM is active end else begin
end else begin
// we have only one hart end
dmcontrol <= (data & ~(32'h3fffc0)) | 32'h10000; end
// halt
if (data[31] == 1'b1) begin // dmcontrol
dm_halt_req <= 1'b1; dmcontrol_d[`Hasel] = 1'b0;
// clear ALLRUNNING ANYRUNNING and set ALLHALTED dmcontrol_d[`Hartreset] = 1'b0;
dmstatus <= {dmstatus[31:12], 4'h3, dmstatus[7:0]}; dmcontrol_d[`Setresethaltreq] = 1'b0;
// reset dmcontrol_d[`Clrresethaltreq] = 1'b0;
end else if (data[1] == 1'b1) begin dmcontrol_d[`Ackhavereset] = 1'b0;
dm_reset_req <= 1'b1; dmcontrol_d[`Hartsello] = 10'h1;
dm_halt_req <= 1'b0; dmcontrol_d[`Hartselhi] = 10'h0;
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]}; // 收到resume请求后清resume应答
// resume if (!dmcontrol_q[`Resumereq] && dmcontrol_d[`Resumereq]) begin
end else if (dm_halt_req == 1'b1 && data[30] == 1'b1) begin clear_resumeack = 1'b1;
dm_halt_req <= 1'b0; end
// set ALLRUNNING ANYRUNNING and clear ALLHALTED // 发出resume后并且收到应答
dmstatus <= {dmstatus[31:12], 4'hc, dmstatus[7:0]}; if (dmcontrol_q[`Resumereq] && resumeack) begin
end // 清resume请求位
end dmcontrol_d[`Resumereq] = 1'b0;
end end
COMMAND: begin
// access reg // sbcs
if (data[31:24] == 8'h0) begin sbcs_d[`Sbversion] = 3'd1;
if (data[22:20] > 3'h2) begin sbcs_d[`Sbbusy] = sbbusy;
abstractcs <= abstractcs | (1'b1 << 9); sbcs_d[`Sbasize] = 7'd32;
end else begin sbcs_d[`Sbaccess128] = 1'b0;
abstractcs <= abstractcs & (~(3'h7 << 8)); sbcs_d[`Sbaccess64] = 1'b0;
// read or write sbcs_d[`Sbaccess32] = 1'b1;
if (data[18] == 1'b0) begin sbcs_d[`Sbaccess16] = 1'b0;
dm_reg_addr <= data[15:0] - 16'h1000; sbcs_d[`Sbaccess8] = 1'b0;
// read sbcs_d[`Sbaccess] = 3'd2;
if (data[16] == 1'b0) begin
if (data[15:0] == DCSR) begin // set the havereset flag when we did a ndmreset
data0 <= dcsr; if (ndmreset_o) begin
end else if (data[15:0] < 16'h1020) begin havereset_d = 1'b1;
is_read_reg <= 1'b1; end
end end
// write
end else begin
if (data[15:0] < 16'h1020) begin assign debug_req_o = dmcontrol_q[`Haltreq];
dm_reg_we <= 1'b1; assign ndmreset_o = dmcontrol_q[`Ndmreset];
dm_reg_wdata <= data0; assign resumereq = dmcontrol_q[`Resumereq];
end
end
end always @ (posedge clk or negedge rst_n) begin
end if (!rst_n) begin
end dmcontrol_q <= 32'h0;
end havereset_q <= 1'b1;
DATA0: begin data0_q <= 32'h0;
data0 <= data; sbcs_q <= 32'h0;
end sbaddress0_q <= 32'h0;
SBCS: begin sbdata0_q <= 32'h0;
sbcs <= data; dm_resp_data_q <= 32'h0;
end cmderr_q <= 3'h0;
SBADDRESS0: begin end else begin
sbaddress0 <= data; if (!dmcontrol_q[`Dmactive]) begin
if (sbcs[20] == 1'b1) begin dmcontrol_q[`Haltreq] <= 1'b0;
dm_mem_addr <= data; dmcontrol_q[`Resumereq] <= 1'b0;
end dmcontrol_q[`Hartreset] <= 1'b0;
end dmcontrol_q[`Ackhavereset] <= 1'b0;
SBDATA0: begin dmcontrol_q[`Hasel] <= 1'b0;
sbdata0 <= data; dmcontrol_q[`Hartsello] <= 10'b0;
dm_mem_addr <= sbaddress0; dmcontrol_q[`Hartselhi] <= 10'b0;
dm_mem_wdata <= data; dmcontrol_q[`Setresethaltreq] <= 1'b0;
dm_mem_we <= 1'b1; dmcontrol_q[`Clrresethaltreq] <= 1'b0;
if (sbcs[16] == 1'b1) begin dmcontrol_q[`Ndmreset] <= 1'b0;
sbaddress0 <= sbaddress0_next; dmcontrol_q[`Dmactive] <= dmcontrol_d[`Dmactive];
end data0_q <= 32'h0;
end sbcs_q <= 32'h0;
endcase sbaddress0_q <= 32'h0;
end sbdata0_q <= 32'h0;
dm_resp_data_q <= 32'h0;
`DTM_OP_NOP: begin cmderr_q <= 3'h0;
read_data <= {(DMI_DATA_BITS){1'b0}}; end else begin
end dmcontrol_q <= dmcontrol_d;
endcase data0_q <= data0_d;
end sbcs_q <= sbcs_d;
STATE_END: begin sbaddress0_q <= sbaddress0_d;
state <= STATE_IDLE; sbdata0_q <= sbdata0_d;
dm_mem_rdata <= dm_mem_rdata_i; dm_resp_data_q <= dm_resp_data_d;
need_resp <= 1'b0; cmderr_q <= cmderr_d;
dm_mem_we <= 1'b0; end
dm_reg_we <= 1'b0; havereset_q <= havereset_d;
dm_reset_req <= 1'b0; end
end end
endcase
end jtag_mem #(
end
) u_jtag_mem (
wire jtag_req_hsked = (req_valid_o & req_ready_i); .clk(clk),
wire jtag_rsp_hsked = (rsp_valid_i & rsp_ready_o); .rst_n(rst_n),
assign rsp_ready_o = (~rst_n)? 1'b0: 1'b1; .halted_o(halted),
assign dm_mem_sel_o = dm_mem_sel; .resumeack_o(resumeack),
.clear_resumeack_i(clear_resumeack),
.resumereq_i(resumereq),
assign dm_reg_we_o = dm_reg_we; .haltreq_i(debug_req_o),
assign dm_reg_addr_o = dm_reg_addr; .cmdbusy_o(cmdbusy),
assign dm_reg_wdata_o = dm_reg_wdata;
assign dm_mem_we_o = dm_mem_we; .req_i(slave_req_i),
assign dm_mem_addr_o = dm_mem_addr; .we_i(slave_we_i),
assign dm_mem_wdata_o = dm_mem_wdata; .addr_i(slave_addr_i),
.be_i(slave_be_i),
assign req_valid_o = (state != STATE_IDLE) & req_sys_bus; .wdata_i(slave_wdata_i),
assign dm_halt_req_o = dm_halt_req; .rdata_o(slave_rdata_o)
assign dm_reset_req_o = dm_reset_req; );
assign dm_resp_data = {address, read_data, OP_SUCC}; jtag_sba #(
) u_jtag_sba (
full_handshake_tx #( .clk(clk),
.DW(DM_RESP_BITS) .rst_n(rst_n),
) tx( .sbbusy_o(sbbusy),
.clk(clk), .master_req_o(master_req_o),
.rst_n(rst_n), .master_gnt_i(master_gnt_i),
.ack_i(dtm_ack_i), .master_rvalid_i(master_rvalid_i),
.req_i(need_resp), .master_we_o(master_we_o),
.req_data_i(dm_resp_data), .master_be_o(master_be_o),
.idle_o(), .master_addr_o(master_addr_o),
.req_o(dm_resp_valid_o), .master_wdata_o(master_wdata_o),
.req_data_o(dm_resp_data_o) .master_rdata_i(master_rdata_i),
); .master_err_i(master_err_i)
);
full_handshake_rx #(
.DW(DTM_REQ_BITS) endmodule
) 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

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

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 Copyright 2021 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
`include "../core/defines.sv"
module jtag_top #(
// JTAG顶层模块
module jtag_top #( )(
parameter DMI_ADDR_BITS = 6,
parameter DMI_DATA_BITS = 32, input wire clk_i,
parameter DMI_OP_BITS = 2)( input wire rst_ni,
input wire clk, output wire debug_req_o,
input wire jtag_rst_n, output wire ndmreset_o,
input wire jtag_pin_TCK, input wire jtag_tck_i, // JTAG test clock pad
input wire jtag_pin_TMS, input wire jtag_tdi_i, // JTAG test data input pad
input wire jtag_pin_TDI, input wire jtag_tms_i, // JTAG test mode select pad
output wire jtag_pin_TDO, input wire jtag_trst_ni, // JTAG test reset pad
output wire jtag_tdo_o, // JTAG test data output pad
output wire reg_we_o,
output wire[4:0] reg_addr_o, output wire master_req_o,
output wire[31:0] reg_wdata_o, input wire master_gnt_i,
input wire[31:0] reg_rdata_i, input wire master_rvalid_i,
output wire master_we_o,
output wire mem_we_o, output wire [3:0] master_be_o,
output wire[31:0] mem_addr_o, output wire [31:0] master_addr_o,
output wire[31:0] mem_wdata_o, output wire [31:0] master_wdata_o,
input wire[31:0] mem_rdata_i, input wire [31:0] master_rdata_i,
output wire[3:0] mem_sel_o, input wire master_err_i,
output wire req_valid_o, input wire slave_req_i,
input wire req_ready_i, input wire slave_we_i,
input wire rsp_valid_i, input wire [31:0] slave_addr_i,
output wire rsp_ready_o, input wire [3:0] slave_be_i,
input wire [31:0] slave_wdata_i,
output wire halt_req_o, output wire [31:0] slave_rdata_o
output wire reset_req_o
);
);
// addr + data + op = 6 + 32 + 2 = 40
parameter DM_RESP_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS; localparam DMI_DATA_WIDTH = 40;
parameter DTM_REQ_BITS = DMI_ADDR_BITS + DMI_DATA_BITS + DMI_OP_BITS;
// jtag_driver输出信号 wire [DMI_DATA_WIDTH-1:0] dm_to_dmi_data;
wire dtm_ack_o; wire dm_to_dmi_valid;
wire dtm_req_valid_o; wire dm_to_dmi_ready;
wire[DTM_REQ_BITS - 1:0] dtm_req_data_o; wire [DMI_DATA_WIDTH-1:0] dmi_to_dm_data;
wire dmi_to_dm_valid;
// jtag_dm输出信号 wire dmi_to_dm_ready;
wire dm_ack_o;
wire[DM_RESP_BITS-1:0] dm_resp_data_o; jtag_dm #(
wire dm_resp_valid_o;
wire dm_halt_req_o; ) u_jtag_dm (
wire dm_reset_req_o; .clk (clk_i),
.rst_n (rst_ni),
jtag_driver #( .dmi_data_i (dmi_to_dm_data),
.DMI_ADDR_BITS(DMI_ADDR_BITS), .dmi_valid_i (dmi_to_dm_valid),
.DMI_DATA_BITS(DMI_DATA_BITS), .dm_ready_o (dm_to_dmi_ready),
.DMI_OP_BITS(DMI_OP_BITS) .dm_data_o (dm_to_dmi_data),
) u_jtag_driver( .dm_valid_o (dm_to_dmi_valid),
.rst_n(jtag_rst_n), .dmi_ready_i (dmi_to_dm_ready),
.jtag_TCK(jtag_pin_TCK), .debug_req_o (debug_req_o),
.jtag_TDI(jtag_pin_TDI), .ndmreset_o (ndmreset_o),
.jtag_TMS(jtag_pin_TMS), .master_req_o (master_req_o),
.jtag_TDO(jtag_pin_TDO), .master_gnt_i (master_gnt_i),
.dm_resp_i(dm_resp_valid_o), .master_rvalid_i(master_rvalid_i),
.dm_resp_data_i(dm_resp_data_o), .master_we_o (master_we_o),
.dtm_ack_o(dtm_ack_o), .master_be_o (master_be_o),
.dm_ack_i(dm_ack_o), .master_addr_o (master_addr_o),
.dtm_req_valid_o(dtm_req_valid_o), .master_wdata_o (master_wdata_o),
.dtm_req_data_o(dtm_req_data_o) .master_rdata_i (master_rdata_i),
); .master_err_i (master_err_i),
.slave_req_i (slave_req_i),
jtag_dm #( .slave_we_i (slave_we_i),
.DMI_ADDR_BITS(DMI_ADDR_BITS), .slave_addr_i (slave_addr_i),
.DMI_DATA_BITS(DMI_DATA_BITS), .slave_be_i (slave_be_i),
.DMI_OP_BITS(DMI_OP_BITS) .slave_wdata_i (slave_wdata_i),
) u_jtag_dm( .slave_rdata_o (slave_rdata_o)
.clk(clk), );
.rst_n(jtag_rst_n),
.dm_ack_o(dm_ack_o), wire [DMI_DATA_WIDTH-1:0] dtm_to_dmi_data;
.dtm_req_valid_i(dtm_req_valid_o), wire dtm_to_dmi_valid;
.dtm_req_data_i(dtm_req_data_o), wire dtm_to_dmi_ready;
.dtm_ack_i(dtm_ack_o), wire [DMI_DATA_WIDTH-1:0] dmi_to_dtm_data;
.dm_resp_data_o(dm_resp_data_o), wire dmi_to_dtm_valid;
.dm_resp_valid_o(dm_resp_valid_o), wire dmi_to_dtm_ready;
.dm_reg_we_o(reg_we_o),
.dm_reg_addr_o(reg_addr_o), jtag_dmi #(
.dm_reg_wdata_o(reg_wdata_o),
.dm_reg_rdata_i(reg_rdata_i), ) u_jtag_dmi (
.dm_mem_we_o(mem_we_o), .jtag_tck_i (jtag_tck_i),
.dm_mem_addr_o(mem_addr_o), .jtag_trst_ni (jtag_trst_ni),
.dm_mem_wdata_o(mem_wdata_o), .jtag_data_i (dtm_to_dmi_data),
.dm_mem_rdata_i(mem_rdata_i), .jtag_valid_i (dtm_to_dmi_valid),
.dm_mem_sel_o(mem_sel_o), .jtag_ready_o (dmi_to_dtm_ready),
.req_valid_o(req_valid_o), .jtag_data_o (dmi_to_dtm_data),
.req_ready_i(req_ready_i), .jtag_valid_o (dmi_to_dtm_valid),
.rsp_valid_i(rsp_valid_i), .jtag_ready_i (dtm_to_dmi_ready),
.rsp_ready_o(rsp_ready_o), .clk_i (clk_i),
.dm_halt_req_o(halt_req_o), .rst_ni (rst_ni),
.dm_reset_req_o(reset_req_o) .core_data_i (dm_to_dmi_data),
); .core_valid_i (dm_to_dmi_valid),
.core_ready_o (dmi_to_dm_ready),
endmodule .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 "../core/defines.sv"
`include "../debug/jtag_def.sv"
// tinyriscv soc顶层模块 // tinyriscv soc顶层模块
module tinyriscv_soc_top( module tinyriscv_soc_top(
@ -38,14 +39,18 @@ module tinyriscv_soc_top(
localparam int MASTERS = 2; //Number of master ports localparam int MASTERS = 3; // Number of master ports
localparam int SLAVES = 2; //Number of slave ports localparam int SLAVES = 3; // Number of slave ports
localparam int CoreD = 0; // masters
localparam int CoreI = 1; localparam int CoreD = 0;
localparam int JtagHost = 1;
localparam int CoreI = 2;
localparam int Rom = 0; // slaves
localparam int Ram = 1; localparam int Rom = 0;
localparam int Ram = 1;
localparam int JtagDevice = 2;
wire master_req [MASTERS]; wire master_req [MASTERS];
@ -80,12 +85,12 @@ module tinyriscv_soc_top(
wire ndmreset; wire ndmreset;
wire ndmreset_n; wire ndmreset_n;
wire debug_req;
assign ndmreset = 1'b0;
tinyriscv_core #( tinyriscv_core #(
.DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + 16'h800), .DEBUG_HALT_ADDR(`DEBUG_ADDR_BASE + `HaltAddress),
.DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + 16'h808) .DEBUG_EXCEPTION_ADDR(`DEBUG_ADDR_BASE + `ExceptionAddress)
) u_tinyriscv_core ( ) u_tinyriscv_core (
.clk(clk), .clk(clk),
.rst_n(ndmreset_n), .rst_n(ndmreset_n),
@ -111,9 +116,8 @@ module tinyriscv_soc_top(
.irq_timer_i(1'b0), .irq_timer_i(1'b0),
.irq_external_i(1'b0), .irq_external_i(1'b0),
.irq_fast_i(15'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) .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 `ifdef VERILATOR
sim_jtag #( sim_jtag #(
@ -191,7 +225,7 @@ module tinyriscv_soc_top(
) u_sim_jtag ( ) u_sim_jtag (
.clock ( clk ), .clock ( clk ),
.reset ( ~rst_ext_ni ), .reset ( ~rst_ext_ni ),
.enable ( 1'b0 ), .enable ( 1'b1 ),
.init_done ( rst_ext_ni ), .init_done ( rst_ext_ni ),
.jtag_TCK ( sim_jtag_tck ), .jtag_TCK ( sim_jtag_tck ),
.jtag_TMS ( sim_jtag_tms ), .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 Copyright 2020 Blue Liang, liangkangnan@163.com
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// 将输入打DP拍后输出 // 将输入打DP拍后输出
module gen_ticks_sync #( module gen_ticks_sync #(
parameter DP = 2, parameter DP = 2,
parameter DW = 32)( parameter DW = 32)(
input wire rst_n, input wire rst_n,
input wire clk, input wire clk,
input wire[DW-1:0] din, input wire[DW-1:0] din,
output wire[DW-1:0] dout output wire[DW-1:0] dout
); );
wire[DW-1:0] sync_dat[DP-1:0]; wire[DW-1:0] sync_dat[DP-1:0];
genvar i; genvar i;
generate generate
for (i = 0; i < DP; i = i + 1) begin: ticks_sync for (i = 0; i < DP; i = i + 1) begin: ticks_sync
if (i == 0) begin: dp_is_0 if (i == 0) begin: dp_is_0
gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, din, sync_dat[0]); gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, din, sync_dat[0]);
end else begin: dp_is_not_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]); gen_rst_0_dff #(DW) rst_0_dff(clk, rst_n, sync_dat[i-1], sync_dat[i]);
end end
end end
endgenerate endgenerate
assign dout = sync_dat[DP-1]; assign dout = sync_dat[DP-1];
endmodule endmodule

View File

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

View File

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