Hazard3/test/sim/tb_cxxrtl/tb_multicore.v

325 lines
11 KiB
Verilog

// An integration of JTAG-DTM + DM + 2 single-ported CPUs for openocd to poke
// at over a remote bitbang socket
`default_nettype none
module tb #(
parameter W_ADDR = 32, // do not modify
parameter W_DATA = 32 // do not modify
) (
// Global signals
input wire clk,
input wire rst_n,
// JTAG port
input wire tck,
input wire trst_n,
input wire tms,
input wire tdi,
output wire tdo,
// Core 0 bus (named I for consistency with 1-core 2-port tb)
output wire [W_ADDR-1:0] i_haddr,
output wire i_hwrite,
output wire [1:0] i_htrans,
output wire i_hexcl,
output wire [2:0] i_hsize,
output wire [2:0] i_hburst,
output wire [3:0] i_hprot,
output wire i_hmastlock,
input wire i_hready,
input wire i_hresp,
input wire i_hexokay,
output wire [W_DATA-1:0] i_hwdata,
input wire [W_DATA-1:0] i_hrdata,
// Core 1 bus (named D for consistency with 1-core 2-port tb)
output wire [W_ADDR-1:0] d_haddr,
output wire d_hwrite,
output wire [1:0] d_htrans,
output wire d_hexcl,
output wire [2:0] d_hsize,
output wire [2:0] d_hburst,
output wire [3:0] d_hprot,
output wire d_hmastlock,
input wire d_hready,
input wire d_hresp,
input wire d_hexokay,
output wire [W_DATA-1:0] d_hwdata,
input wire [W_DATA-1:0] d_hrdata,
// Level-sensitive interrupt sources
input wire [NUM_IRQS-1:0] irq, // -> mip.meip
input wire [1:0] soft_irq, // -> mip.msip
input wire timer_irq // -> mip.mtip
);
// JTAG-DTM IDCODE, selected after TAP reset, would normally be a
// JEP106-compliant ID
localparam IDCODE = 32'hdeadbeef;
wire dmi_psel;
wire dmi_penable;
wire dmi_pwrite;
wire [8:0] dmi_paddr;
wire [31:0] dmi_pwdata;
reg [31:0] dmi_prdata;
wire dmi_pready;
wire dmi_pslverr;
wire dmihardreset_req;
wire assert_dmi_reset = !rst_n || dmihardreset_req;
wire rst_n_dmi;
hazard3_reset_sync dmi_reset_sync_u (
.clk (clk),
.rst_n_in (!assert_dmi_reset),
.rst_n_out (rst_n_dmi)
);
hazard3_jtag_dtm #(
.IDCODE (IDCODE)
) inst_hazard3_jtag_dtm (
.tck (tck),
.trst_n (trst_n),
.tms (tms),
.tdi (tdi),
.tdo (tdo),
.dmihardreset_req (dmihardreset_req),
.clk_dmi (clk),
.rst_n_dmi (rst_n_dmi),
.dmi_psel (dmi_psel),
.dmi_penable (dmi_penable),
.dmi_pwrite (dmi_pwrite),
.dmi_paddr (dmi_paddr),
.dmi_pwdata (dmi_pwdata),
.dmi_prdata (dmi_prdata),
.dmi_pready (dmi_pready),
.dmi_pslverr (dmi_pslverr)
);
localparam N_HARTS = 2;
localparam XLEN = 32;
wire sys_reset_req;
wire sys_reset_done;
wire [N_HARTS-1:0] hart_reset_req;
wire [N_HARTS-1:0] hart_reset_done;
wire [N_HARTS-1:0] hart_req_halt;
wire [N_HARTS-1:0] hart_req_halt_on_reset;
wire [N_HARTS-1:0] hart_req_resume;
wire [N_HARTS-1:0] hart_halted;
wire [N_HARTS-1:0] hart_running;
wire [N_HARTS*XLEN-1:0] hart_data0_rdata;
wire [N_HARTS*XLEN-1:0] hart_data0_wdata;
wire [N_HARTS-1:0] hart_data0_wen;
wire [N_HARTS*XLEN-1:0] hart_instr_data;
wire [N_HARTS-1:0] hart_instr_data_vld;
wire [N_HARTS-1:0] hart_instr_data_rdy;
wire [N_HARTS-1:0] hart_instr_caught_exception;
wire [N_HARTS-1:0] hart_instr_caught_ebreak;
wire [31:0] sbus_addr;
wire sbus_write;
wire [1:0] sbus_size;
wire sbus_vld;
wire sbus_rdy;
wire sbus_err;
wire [31:0] sbus_wdata;
wire [31:0] sbus_rdata;
hazard3_dm #(
.N_HARTS (N_HARTS),
.HAVE_SBA (1),
.NEXT_DM_ADDR (0)
) dm (
.clk (clk),
.rst_n (rst_n),
.dmi_psel (dmi_psel),
.dmi_penable (dmi_penable),
.dmi_pwrite (dmi_pwrite),
.dmi_paddr (dmi_paddr),
.dmi_pwdata (dmi_pwdata),
.dmi_prdata (dmi_prdata),
.dmi_pready (dmi_pready),
.dmi_pslverr (dmi_pslverr),
.sys_reset_req (sys_reset_req),
.sys_reset_done (sys_reset_done),
.hart_reset_req (hart_reset_req),
.hart_reset_done (hart_reset_done),
.hart_req_halt (hart_req_halt),
.hart_req_halt_on_reset (hart_req_halt_on_reset),
.hart_req_resume (hart_req_resume),
.hart_halted (hart_halted),
.hart_running (hart_running),
.hart_data0_rdata (hart_data0_rdata),
.hart_data0_wdata (hart_data0_wdata),
.hart_data0_wen (hart_data0_wen),
.hart_instr_data (hart_instr_data),
.hart_instr_data_vld (hart_instr_data_vld),
.hart_instr_data_rdy (hart_instr_data_rdy),
.hart_instr_caught_exception (hart_instr_caught_exception),
.hart_instr_caught_ebreak (hart_instr_caught_ebreak),
.sbus_addr (sbus_addr),
.sbus_write (sbus_write),
.sbus_size (sbus_size),
.sbus_vld (sbus_vld),
.sbus_rdy (sbus_rdy),
.sbus_err (sbus_err),
.sbus_wdata (sbus_wdata),
.sbus_rdata (sbus_rdata)
);
// Generate resynchronised reset for CPU based on upstream reset and
// on reset requests from DM.
wire assert_cpu_reset0 = !rst_n || sys_reset_req || hart_reset_req[0];
wire assert_cpu_reset1 = !rst_n || sys_reset_req || hart_reset_req[1];
wire rst_n_cpu0;
wire rst_n_cpu1;
hazard3_reset_sync cpu0_reset_sync (
.clk (clk),
.rst_n_in (!assert_cpu_reset0),
.rst_n_out (rst_n_cpu0)
);
hazard3_reset_sync cpu1_reset_sync (
.clk (clk),
.rst_n_in (!assert_cpu_reset1),
.rst_n_out (rst_n_cpu1)
);
// Still some work to be done on the reset handshake -- this ought to be
// resynchronised to DM's reset domain here, and the DM should wait for a
// rising edge after it has asserted the reset pulse, to make sure the tail
// of the previous "done" is not passed on.
assign sys_reset_done = rst_n_cpu0 && rst_n_cpu1;
assign hart_reset_done = {rst_n_cpu1, rst_n_cpu0};
`ifndef CONFIG_HEADER
`define CONFIG_HEADER "config_default.vh"
`endif
`include `CONFIG_HEADER
hazard3_cpu_1port #(
.MHARTID_VAL (32'h0000_0000),
`define HAZARD3_CONFIG_INST_NO_MHARTID
`include "hazard3_config_inst.vh"
) cpu0 (
.clk (clk),
.rst_n (rst_n_cpu0),
.haddr (i_haddr),
.hexcl (i_hexcl),
.hwrite (i_hwrite),
.htrans (i_htrans),
.hsize (i_hsize),
.hburst (i_hburst),
.hprot (i_hprot),
.hmastlock (i_hmastlock),
.hready (i_hready),
.hresp (i_hresp),
.hexokay (i_hexokay),
.hwdata (i_hwdata),
.hrdata (i_hrdata),
.dbg_req_halt (hart_req_halt [0]),
.dbg_req_halt_on_reset (hart_req_halt_on_reset [0]),
.dbg_req_resume (hart_req_resume [0]),
.dbg_halted (hart_halted [0]),
.dbg_running (hart_running [0]),
.dbg_data0_rdata (hart_data0_rdata [0 * XLEN +: XLEN]),
.dbg_data0_wdata (hart_data0_wdata [0 * XLEN +: XLEN]),
.dbg_data0_wen (hart_data0_wen [0]),
.dbg_instr_data (hart_instr_data [0 * XLEN +: XLEN]),
.dbg_instr_data_vld (hart_instr_data_vld [0]),
.dbg_instr_data_rdy (hart_instr_data_rdy [0]),
.dbg_instr_caught_exception (hart_instr_caught_exception[0]),
.dbg_instr_caught_ebreak (hart_instr_caught_ebreak [0]),
// SBA is routed through core 1, so tie off on core 0
.dbg_sbus_addr (32'h0),
.dbg_sbus_write (1'b0),
.dbg_sbus_size (2'h0),
.dbg_sbus_vld (1'b0),
.dbg_sbus_rdy (),
.dbg_sbus_err (),
.dbg_sbus_wdata (32'h0),
.dbg_sbus_rdata (),
.irq (irq),
.soft_irq (soft_irq[0]),
.timer_irq (timer_irq)
);
hazard3_cpu_1port #(
.MHARTID_VAL (32'h0000_0001),
`define HAZARD3_CONFIG_INST_NO_MHARTID
`include "hazard3_config_inst.vh"
) cpu1 (
.clk (clk),
.rst_n (rst_n_cpu1),
.haddr (d_haddr),
.hexcl (d_hexcl),
.hwrite (d_hwrite),
.htrans (d_htrans),
.hsize (d_hsize),
.hburst (d_hburst),
.hprot (d_hprot),
.hmastlock (d_hmastlock),
.hready (d_hready),
.hresp (d_hresp),
.hexokay (d_hexokay),
.hwdata (d_hwdata),
.hrdata (d_hrdata),
.dbg_req_halt (hart_req_halt [1]),
.dbg_req_halt_on_reset (hart_req_halt_on_reset [1]),
.dbg_req_resume (hart_req_resume [1]),
.dbg_halted (hart_halted [1]),
.dbg_running (hart_running [1]),
.dbg_data0_rdata (hart_data0_rdata [1 * XLEN +: XLEN]),
.dbg_data0_wdata (hart_data0_wdata [1 * XLEN +: XLEN]),
.dbg_data0_wen (hart_data0_wen [1]),
.dbg_instr_data (hart_instr_data [1 * XLEN +: XLEN]),
.dbg_instr_data_vld (hart_instr_data_vld [1]),
.dbg_instr_data_rdy (hart_instr_data_rdy [1]),
.dbg_instr_caught_exception (hart_instr_caught_exception[1]),
.dbg_instr_caught_ebreak (hart_instr_caught_ebreak [1]),
.dbg_sbus_addr (sbus_addr),
.dbg_sbus_write (sbus_write),
.dbg_sbus_size (sbus_size),
.dbg_sbus_vld (sbus_vld),
.dbg_sbus_rdy (sbus_rdy),
.dbg_sbus_err (sbus_err),
.dbg_sbus_wdata (sbus_wdata),
.dbg_sbus_rdata (sbus_rdata),
.irq (irq),
.soft_irq (soft_irq[1]),
.timer_irq (timer_irq)
);
endmodule