diff options
| author | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
|---|---|---|
| committer | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
| commit | dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f (patch) | |
| tree | b47203aa281bdd959def4451c84d310cd9cf2e12 /sources/hdl | |
| download | dram-bender-dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f.tar.gz | |
Initial commit
Diffstat (limited to 'sources/hdl')
22 files changed, 4074 insertions, 0 deletions
diff --git a/sources/hdl/header_verilog/encoding.vh b/sources/hdl/header_verilog/encoding.vh new file mode 100644 index 0000000..f5d5697 --- /dev/null +++ b/sources/hdl/header_verilog/encoding.vh @@ -0,0 +1,103 @@ +// SoftMC instructions +`define FU_CODE_OFFSET 48 +`define BRANCH_OFFSET 62 +`define DDR_OFFSET 63 +`define INFO_OFFSET 61 +`define MEM_OFFSET 60 +`define BW_OFFSET 59 +`define DEC_RS1 0 +`define DEC_RS2 4 +`define DEC_IMD1 4 +`define DEC_IMD2 0 +`define DEC_IMD3 24 +`define DEC_RT 20 +`define DEC_WO 20 +`define DEC_JUMP_OFFSET 0 +`define DEC_SLEEP_OFFSET 0 +`define DEC_BR_TGT_OFFSET 8 +`define SR_OFFSET 56 +// DDR related +`define DDR_CODE_OFFSET 12 +`define DEC_CAR 4 +`define DEC_BAR 0 +`define DEC_RAR 4 +`define DEC_INC_BAR 10 +`define DEC_PRE_ALL 11 +`define DEC_INC_RAR 11 +`define DEC_INC_CAR 11 +`define DEC_AP 9 +`define DEC_BL4 8 +// function codes - exe +`define ADD 0 +`define ADDI 1 +`define SUB 2 +`define SUBI 3 +`define MV 4 +`define SRC 5 +`define LI 6 +`define LDWD 7 +`define LDPC 8 +`define SRE 0 //DDR command but no space left in ISA DDR instructions. +`define SRX 1 //DDR command but no space left in ISA DDR instructions. +`define BL 0 +`define BEQ 1 +`define JUMP 2 +`define SLEEP 3 +`define LD 0 +`define ST 1 +`define AND 0 +`define OR 1 +`define XOR 2 +// function codes - ddr +`define WRITE 0 +`define READ 1 +`define PRE 2 +`define ACT 3 +`define ZQ 4 +`define REF 5 +`define NOP 7 + +// SoftMC ddr uops +`define IS_WRITE 0 +`define IS_READ 1 +`define IS_PRE 2 +`define IS_ACT 3 +`define IS_ZQ 4 +`define IS_REF 5 +`define CAR 6 // column address register identifier +`define RAR 10 // row address register identifier +`define BAR 14 // bank address register identifier +`define PRE_ALL 18 +`define INC_CAR 19 // increment CAR after executing this +`define INC_RAR 20 +`define INC_BAR 21 +`define IS_NOP 22 +`define IS_BL4 23 +`define DO_AP 24 +`define IS_SRE 25 +`define IS_SRX 26 +// SoftMC exe uops +`define IS_ADD 0 +`define IS_SUB 1 +`define IS_MOV 2 +`define IS_LI 3 +`define IS_LDWD 4 +`define HAS_IMD 5 +`define IS_BL 6 +`define IS_BEQ 7 +`define IS_JUMP 8 +`define IS_SLEEP 9 +`define RS1 10 +`define RS2 14 +`define RT 18 +`define IMD 22 +`define IMD2 38 +`define IS_SRC 54 +`define IS_MEM 55 +`define IS_LD 56 +`define IS_ST 57 +`define IS_AND 58 +`define IS_OR 59 +`define IS_XOR 60 +`define IS_LDPC 61 + diff --git a/sources/hdl/header_verilog/parameters.vh b/sources/hdl/header_verilog/parameters.vh new file mode 100644 index 0000000..916c973 --- /dev/null +++ b/sources/hdl/header_verilog/parameters.vh @@ -0,0 +1,21 @@ +// Fetch +`define INSTR_WIDTH 64 +`define IMEM_ADDR_WIDTH 11 + +// Decode - Execute +`define DDR_UOP_WIDTH 27 +`define EXE_UOP_WIDTH 62 +`define BG_WIDTH 2 +`define BANK_WIDTH 2 +`define COL_WIDTH 10 +`define ROW_WIDTH 17 + +//Frontend +`define XDMA_AXI_DATA_WIDTH 256 +`define IMEM_RD_LATENCY 1 +//`define IMEM_SR // please only define when IMEM_RD_LATENCY > 1 + +//Common +`define HIGH 1'b1 +`define LOW 1'b0 + diff --git a/sources/hdl/sim_verilog/example_top.sv b/sources/hdl/sim_verilog/example_top.sv new file mode 100644 index 0000000..dbf4fea --- /dev/null +++ b/sources/hdl/sim_verilog/example_top.sv @@ -0,0 +1,557 @@ + +`ifdef MODEL_TECH + `ifndef CALIB_SIM + `define SIMULATION + `endif +`elsif INCA + `ifndef CALIB_SIM + `define SIMULATION + `endif +`elsif VCS + `ifndef CALIB_SIM + `define SIMULATION + `endif +`elsif XILINX_SIMULATOR + `ifndef CALIB_SIM + `define SIMULATION + `endif +`endif + +`timescale 1ps/1ps + +// Fetch +`define INSTR_WIDTH 64 +`define IMEM_ADDR_WIDTH 11 + +// Decode - Execute +`define DDR_UOP_WIDTH 27 +`define EXE_UOP_WIDTH 62 +`define BG_WIDTH 2 +`define BANK_WIDTH 2 +`define COL_WIDTH 10 +`define ROW_WIDTH 17 + +//Frontend +`define XDMA_AXI_DATA_WIDTH 256 +`define IMEM_RD_LATENCY 1 +//`define IMEM_SR // please only define when IMEM_RD_LATENCY > 1 + +//Common +`define HIGH 1'b1 +`define LOW 1'b0 + + + +`define UDIMM_x8 + +`define DQ_WIDTH 64 +`define ODT_WIDTH 2 +`define CS_WIDTH 2 +`define CKE_WIDTH 2 +`define CK_WIDTH 1 +`define ROW_ADDR_WIDTH 17 + + +module example_top # + ( + parameter SIMULATION = "FALSE" + ) + ( + + // common signals + input c0_sys_clk_p, + input c0_sys_clk_n, + input sys_rst, + + // iob <> ddr4 sdram ip signals + output c0_ddr4_act_n, + output [`ROW_ADDR_WIDTH-1:0] c0_ddr4_adr, + output [1:0] c0_ddr4_ba, + output [1:0] c0_ddr4_bg, + output [`CKE_WIDTH-1:0] c0_ddr4_cke, + output [`ODT_WIDTH-1:0] c0_ddr4_odt, + output [`CS_WIDTH-1:0] c0_ddr4_cs_n, + output [`CK_WIDTH-1:0] c0_ddr4_ck_t, + output [`CK_WIDTH-1:0] c0_ddr4_ck_c, + output c0_ddr4_reset_n, + + `ifdef RDIMM_x4 + inout [17:0] c0_ddr4_dqs_c, + inout [17:0] c0_ddr4_dqs_t, + inout [71:0] c0_ddr4_dq, + output c0_ddr4_parity, + `elsif UDIMM_x8 + inout [7:0] c0_ddr4_dqs_c, + inout [7:0] c0_ddr4_dqs_t, + inout [63:0] c0_ddr4_dq, + inout [7:0] c0_ddr4_dm_dbi_n, + output c0_ddr4_parity, + `elsif RDIMM_x8 + inout [8:0] c0_ddr4_dqs_c, + inout [8:0] c0_ddr4_dqs_t, + inout [71:0] c0_ddr4_dq, + inout [8:0] c0_ddr4_dm_dbi_n, + output c0_ddr4_parity, + `endif + + output c0_init_calib_complete, + output c0_data_compare_error +); + + `ifdef RDIMM_x4 + assign c0_ddr4_odt[1] = 1'b0; + assign c0_ddr4_cs_n[1] = 1'b1; + assign c0_ddr4_cke[1] = 1'b0; + `elsif RDIMM_x8 + assign c0_ddr4_odt[1] = 1'b0; + assign c0_ddr4_cs_n[1] = 1'b1; + assign c0_ddr4_cke[1] = 1'b0; + //assign c0_ddr4_parity = 1'b0; + `elsif UDIMM_x8 + assign c0_ddr4_odt[1] = 1'b0; + assign c0_ddr4_cs_n[1] = 1'b1; + assign c0_ddr4_cke[1] = 1'b0; + assign c0_ddr4_parity = 1'b0; + `endif + + // Frontend control signals + wire softmc_fin; + wire user_rst; + + // Frontend <-> Fetch signals + wire [`IMEM_ADDR_WIDTH-1:0] fr_addr_in; + wire fr_valid_in; + wire [`INSTR_WIDTH-1:0] fr_data_out; + wire fr_valid_out; + wire [`IMEM_ADDR_WIDTH-1:0] fr_addr_out; + wire fr_ready_out; + + // Frontend <-> misc. control signals + wire per_rd_init; + wire per_zq_init; + wire rbe_switch_mode; + + // AXI streaming ports + wire [`XDMA_AXI_DATA_WIDTH-1:0] m_axis_h2c_tdata_0,xdma_h2c_tdata_0; + wire m_axis_h2c_tlast_0, xdma_h2c_tlast_0; + wire m_axis_h2c_tvalid_0, xdma_h2c_tvalid_0; + wire m_axis_h2c_tready_0, xdma_h2c_tready_0; + wire [`XDMA_AXI_DATA_WIDTH/8-1:0] m_axis_h2c_tkeep_0, xdma_h2c_tkeep_0; + wire [`XDMA_AXI_DATA_WIDTH-1:0] s_axis_c2h_tdata_0, xdma_c2h_tdata_0; + wire s_axis_c2h_tlast_0, xdma_c2h_tlast_0; + wire s_axis_c2h_tvalid_0, xdma_c2h_tvalid_0; + wire s_axis_c2h_tready_0, xdma_c2h_tready_0; + wire [`XDMA_AXI_DATA_WIDTH/8-1:0] s_axis_c2h_tkeep_0, xdma_c2h_tkeep_0; + + // ddr_pipeline <-> outer module if + wire [3:0] ddr_write; + wire [3:0] ddr_read; + wire [3:0] ddr_pre; + wire [3:0] ddr_act; + wire [3:0] ddr_ref; + wire [3:0] ddr_zq; + wire [3:0] ddr_nop; + wire [3:0] ddr_sre; + wire [3:0] ddr_srx; + wire [3:0] ddr_ap; + wire [3:0] ddr_pall; + wire [3:0] ddr_half_bl; + wire [4*`BG_WIDTH-1:0] ddr_bg; + wire [4*`BANK_WIDTH-1:0] ddr_bank; + wire [4*`COL_WIDTH-1:0] ddr_col; + wire [4*`ROW_WIDTH-1:0] ddr_row; + wire [511:0] ddr_wdata; + + // periodic maintenance signals + wire ddr_maint_read; + + // phy <-> ddr adapter and dlltoggler signals + // dlltoggler + wire clk_sel = 0; + wire [7:0] dllt_mc_ACT_n; + wire [135:0] dllt_mc_ADR; + wire [15:0] dllt_mc_BA; + wire [15:0] dllt_mc_BG; + wire [7:0] dllt_mc_CKE; + wire [7:0] dllt_mc_CS_n; + wire dllt_done; + // adapter + wire [4:0] dBufAdr; + wire [`DQ_WIDTH*8-1:0] wrData; + wire [`DQ_WIDTH-1:0] wrDataMask; + wire [511:0] rdData; + wire [4:0] rdDataAddr; + wire [0:0] rdDataEn; + wire [0:0] rdDataEnd; + wire [0:0] per_rd_done; + wire [0:0] rmw_rd_done; + wire [4:0] wrDataAddr; + wire [0:0] wrDataEn; + wire [7:0] mc_ACT_n; + wire [135:0] mc_ADR; + wire [15:0] mc_BA; + wire [15:0] mc_BG; + wire [`CKE_WIDTH*8-1:0] mc_CKE; + wire [`CS_WIDTH*8-1:0] mc_CS_n; + wire [`ODT_WIDTH*8-1:0] mc_ODT; + wire [0:0] mcRdCAS; + wire [0:0] mcWrCAS; + wire [0:0] winInjTxn; + wire [0:0] winRmw; + wire [4:0] winBuf; + wire [1:0] winRank; + wire [5:0] tCWL; + wire dbg_clk; + wire c0_wr_rd_complete; + wire c0_ddr4_clk; + wire c0_ddr4_dll_off_clk; + wire ddr4_ui_clk; + wire c0_ddr4_rst; + wire [511:0] dbg_bus; + wire [1:0] mcCasSlot; + wire mcCasSlot2; + wire gt_data_ready; + + wire read_seq_incoming; // next few instructions will read from DRAM + wire [11:0] incoming_reads; // how many reads next few instructions will issue + wire [11:0] buffer_space; // remaining buffer size + + // There is a possibility that these signals are on + // the critical path as observed in + // the previous iteration of SoftMC + reg c0_init_calib_complete_r, sys_rst_r; + wire iq_full, processing_iseq, rdback_fifo_empty; + reg dllt_active = 1'b0; + + reg toggle_dll = 1'b0; + reg dont = 1'b1; + + always @(posedge c0_ddr4_clk) begin + c0_init_calib_complete_r <= c0_init_calib_complete; + sys_rst_r <= sys_rst; + `ifdef ENABLE_DLL_TOGGLER + if(c0_init_calib_complete_r && dont) begin + toggle_dll <= 1'b1; + dont <= 1'b0; + end + if(toggle_dll) begin + dllt_active <= ~dllt_active; + toggle_dll <= 1'b0; + end + if(dllt_done) begin + dllt_active <= ~dllt_active; + end + `endif + end + + + `ifdef UDIMM_x8 + phy_ddr4_udimm phy_ddr4_i( + .sys_rst (sys_rst), + .c0_sys_clk_p (c0_sys_clk_p), + .c0_sys_clk_n (c0_sys_clk_n), + + `ifdef ENABLE_DLL_TOGGLER + .c0_ddr4_ui_clk (ddr4_ui_clk), + .addn_ui_clkout1 (c0_ddr4_dll_off_clk), + `else + .c0_ddr4_ui_clk (c0_ddr4_clk), + `endif + .c0_ddr4_ui_clk_sync_rst (c0_ddr4_rst), + .c0_init_calib_complete (c0_init_calib_complete), + .dbg_clk (dbg_clk), + .c0_ddr4_act_n (c0_ddr4_act_n), + .c0_ddr4_adr (c0_ddr4_adr), + .c0_ddr4_ba (c0_ddr4_ba), + .c0_ddr4_bg (c0_ddr4_bg), + .c0_ddr4_cke (c0_ddr4_cke), + .c0_ddr4_odt (c0_ddr4_odt), + .c0_ddr4_cs_n (c0_ddr4_cs_n), + .c0_ddr4_ck_t (c0_ddr4_ck_t), + .c0_ddr4_ck_c (c0_ddr4_ck_c), + .c0_ddr4_reset_n (c0_ddr4_reset_n), + //.ddr4_par (c0_ddr4_parity), + .c0_ddr4_dq (c0_ddr4_dq), + .c0_ddr4_dqs_c (c0_ddr4_dqs_c), + .c0_ddr4_dqs_t (c0_ddr4_dqs_t), + .c0_ddr4_dm_dbi_n (c0_ddr4_dm_dbi_n), + + .dBufAdr (dBufAdr), + .wrData (wrData), + .rdData (rdData), + .rdDataAddr (rdDataAddr), + .rdDataEn (rdDataEn), + .rdDataEnd (rdDataEnd), + .per_rd_done (per_rd_done), + .rmw_rd_done (rmw_rd_done), + .wrDataAddr (wrDataAddr), + .wrDataEn (wrDataEn), + .wrDataMask (wrDataMask), + + .mc_ACT_n (dllt_active ? dllt_mc_ACT_n : mc_ACT_n), + .mc_ADR (dllt_active ? dllt_mc_ADR : mc_ADR), + .mc_BA (dllt_active ? dllt_mc_BA : mc_BA), + .mc_BG (dllt_active ? dllt_mc_BG : mc_BG), + // DRAM CKE. 8 bits for each DRAM pin. The mc_CKE signal is always set to '1'. + .mc_CKE (dllt_active ? dllt_mc_CKE : {8{1'b1}}), + .mc_CS_n (dllt_active ? dllt_mc_CS_n : mc_CS_n), + .mc_ODT (mc_ODT), + // CAS command slot select. Slot0 is enabled for example design. + .mcCasSlot (dllt_active ? 0 : mcCasSlot), + // CAS slot 2 select. mcCasSlot2 serves a similar purpose as the mcCasSlot[1:0] signal, but mcCasSlot2 is used in timing + // critical logic in the Phy. Slot0 is enabled for example design. + .mcCasSlot2 (dllt_active ? 0 : mcCasSlot2), + .mcRdCAS (dllt_active ? 0 : mcRdCAS), + .mcWrCAS (dllt_active ? 0 : mcWrCAS), + // Optional read command type indication. The winInjTxn signal is set to '0' for example design. + .winInjTxn ({1{1'b0}}), + // Optional read command type indication. The winRmw signal is set to '0' for example design. + .winRmw ({1{1'b0}}), + // Update VT Tracking. The gt_data_ready signal is set to '0' in this example design. + // This signal must be asserted periodically to keep the DQS Gate aligned as voltage and temperature drift. + // For more information, Refer to PG150 document. + .gt_data_ready (gt_data_ready), + .winBuf (winBuf), + .winRank (winRank), + .tCWL (tCWL), + // Debug Port + .dbg_bus (dbg_bus) + ); + `endif + + `ifdef ENABLE_DLL_TOGGLER + //BUFGMUX:GeneralClockMuxBuffer + //UltraScale + //XilinxHDLLibrariesGuide, version2014.4 + BUFGMUX#(.CLK_SEL_TYPE("SYNC") //ASYNC,SYNC + )BUFGMUX_inst( + .O(c0_ddr4_clk), //1-bitoutput:Clockoutput + .I0(ddr4_ui_clk), //1-bitinput:Clockinput(S=0) + .I1(c0_ddr4_dll_off_clk), //1-bitinput:Clockinput(S=1) + .S(clk_sel) //1-bitinput:Clockselect + ); + //End of BUFGMUX_inst instantiation + `endif + + softmc_pipeline pipeline( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst || ~c0_init_calib_complete_r), + + .softmc_end(softmc_fin), + .read_size(incoming_reads), + .read_seq_incoming(read_seq_incoming), + .buffer_space(buffer_space), + + .addr_out(fr_addr_in), + .valid_out(fr_valid_in), + .data_in(fr_data_out), + .valid_in(fr_valid_out), + .addr_in(fr_addr_out), + .ready_out(fr_ready_out), + + .ddr_write(ddr_write), + .ddr_read(ddr_read), + .ddr_pre(ddr_pre), + .ddr_act(ddr_act), + .ddr_ref(ddr_ref), + .ddr_zq(ddr_zq), + .ddr_nop(ddr_nop), + .ddr_sre(ddr_sre), + .ddr_srx(ddr_srx), + .ddr_ap(ddr_ap), + .ddr_pall(ddr_pall), + .ddr_half_bl(ddr_half_bl), + .ddr_bg(ddr_bg), + .ddr_bank(ddr_bank), + .ddr_col(ddr_col), + .ddr_row(ddr_row), + .ddr_wdata(ddr_wdata) + ); + + wire frontend_ready; + + reg keep_frontend_reset = 1'b1; + + `ifdef ENABLE_DLL_TOGGLER + always @(posedge c0_ddr4_clk) begin + keep_frontend_reset <= c0_init_calib_complete_r; + end + `endif + + frontend #(.SIM_MEM("true"))frontend( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || ~keep_frontend_reset || ~c0_init_calib_complete_r || dllt_active), + + .init_calib_complete(c0_init_calib_complete_r), + .softmc_fin(softmc_fin), + .user_rst(user_rst), + //.dllt_begin(toggle_dll), + + // indicates read_back unit is ready for the next iseq + .frontend_ready(frontend_ready), + + // frontend <-> fetch stage if + .addr_in(fr_addr_in), + .valid_in(fr_valid_in), + .data_out(fr_data_out), + .valid_out(fr_valid_out), + .addr_out(fr_addr_out), + .ready_in(fr_ready_out), + + // frontend <-> xdma interface + .h2c_tdata_0(m_axis_h2c_tdata_0), + .h2c_tlast_0(m_axis_h2c_tlast_0), + .h2c_tvalid_0(m_axis_h2c_tvalid_0), + .h2c_tready_0(m_axis_h2c_tready_0), + .h2c_tkeep_0(m_axis_h2c_tkeep_0), + + .per_rd_init(per_rd_init), + .per_zq_init(per_zq_init), + .rbe_switch_mode(rbe_switch_mode) + ); + + ddr4_adapter #( + .DQ_WIDTH(`DQ_WIDTH) + ) ddr4_adapter + ( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst || ~c0_init_calib_complete_r), + .init_calib_complete(c0_init_calib_complete_r), + //.io_config_strobe, + //.io_config, + .dBufAdr(dBufAdr), // Reserved. Should be tied low. + .wrData(wrData), // DRAM write data. There are 8 bits for each DQ lane on the DRAM bus. + .wrDataMask(wrDataMask),// DRAM write DM/DBI port.There is one bit for each byte of the wrData port. + .wrDataEn(wrDataEn), // Write data Enable. The Phy will assert this port for one cycle for each write CAS command. + .mc_ACT_n(mc_ACT_n), // DRAM ACT_n command signal for four DRAM clock cycles. + .mc_ADR(mc_ADR), // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus. + .mc_BA(mc_BA), // DRAM bank address. 8 bits for each DRAM bank address. + .mc_BG(mc_BG), // DRAM bank group address. + .mc_CS_n(mc_CS_n), // DRAM CS_n + //.mc_CKE(mc_CKE), // DRAM CKE + //.mc_ODT(mc_ODT), // DRAM ODT + .mcRdCAS(mcRdCAS), // Read CAS command issued. + .mcWrCAS(mcWrCAS), // Write CAS command issued. + .winRank(winRank), // Target rank for CAS commands. This value indicates which rank a CAS command is issued to. + .winBuf(winBuf), // Optional control signal. When either mcRdCAS or mcWrCAS is asserted, the Phy will store the value on the winBuf signal. + //.rdData(rdData), // DRAM read data. + .rdDataEn(rdDataEn), // Read data valid. This signal asserts for one fabric cycle for each completed read operation. + .rdDataEnd(rdDataEnd), // Unused. Tied high. + .mcCasSlot(mcCasSlot), + .mcCasSlot2(mcCasSlot2), + .gt_data_ready(gt_data_ready), + .ddr_write(ddr_write), + .ddr_read(ddr_read), + .ddr_pre(ddr_pre), + .ddr_act(ddr_act), + .ddr_ref(ddr_ref), + .ddr_zq(ddr_zq), + .ddr_nop(ddr_nop), + //.ddr_sre(ddr_sre), + //.ddr_srx(ddr_srx), + .ddr_ap(ddr_ap), + .ddr_pall(ddr_pall), + .ddr_half_bl(ddr_half_bl), + .ddr_bg(ddr_bg), + .ddr_bank(ddr_bank), + .ddr_col(ddr_col), + .ddr_row(ddr_row), + .ddr_wdata(ddr_wdata), + + .ddr_maint_read(per_rd_init) + ); + + localparam ODTWRDEL = 5'd9; + localparam ODTWRDUR = 4'd6; + localparam ODTWRODEL = 5'd9; + localparam ODTWRODUR = 4'd6; + localparam ODTRDDEL = 5'd10; + localparam ODTRDDUR = 4'd6; + localparam ODTRDODEL = 5'd9; + localparam ODTRDODUR = 4'd6; + localparam ODTNOP = 16'h0000; + localparam ODTWR = 16'h0001; + localparam ODTRD = 16'h0000; + + + wire tranSentC; + assign tranSentC = mcRdCAS | mcWrCAS; + + //synthesis translate_on + //******************************************************************************* + ddr4_mc_odt # ( + .ODTWR (ODTWR) + ,.ODTWRDEL (ODTWRDEL) + ,.ODTWRDUR (ODTWRDUR) + ,.ODTWRODEL (ODTWRODEL) + ,.ODTWRODUR (ODTWRODUR) + + ,.ODTRD (ODTRD) + ,.ODTRDDEL (ODTRDDEL) + ,.ODTRDDUR (ODTRDDUR) + ,.ODTRDODEL (ODTRDODEL) + ,.ODTRDODUR (ODTRDODUR) + + ,.ODTNOP (ODTNOP) + ,.ODTBITS (`ODT_WIDTH) + ,.TCQ (0.1) + )u_ddr_tb_odt( + .clk (c0_ddr4_clk) + ,.rst (c0_ddr4_rst) + ,.mc_ODT (mc_ODT) + ,.casSlot (mcCasSlot) + ,.casSlot2 (mcCasSlot2) + ,.rank (winRank) + ,.winRead (mcRdCAS) + ,.winWrite (mcWrCAS) + ,.tranSentC (tranSentC) + ); + + readback_engine rbe( + + // common signals + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst || ~c0_init_calib_complete_r), + + // other ctrl signals + .flush(frontend_ready), + .switch_mode(rbe_switch_mode), + .read_seq_incoming(read_seq_incoming), // next few instructions will read from DRAM + .incoming_reads(incoming_reads), // how many reads next few instructions will issue + .buffer_space(buffer_space), // remaining buffer size + // DRAM <-> engine if + .rd_data(rdData), + .rd_valid(rdDataEn), + + // rbe <-> rf interface + .ddr_wdata(ddr_wdata), + + .per_rd_init(per_rd_init), + .per_zq_init(per_zq_init), + + // rbe <-> xdma if + .c2h_tdata_0(s_axis_c2h_tdata_0), + .c2h_tlast_0(s_axis_c2h_tlast_0), + .c2h_tvalid_0(s_axis_c2h_tvalid_0), + .c2h_tready_0(1'b1), + .c2h_tkeep_0(s_axis_c2h_tkeep_0) + + ); + + `ifdef ENABLE_DLL_TOGGLER + dll_toggler dllt + ( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst || ~c0_init_calib_complete_r), + .toggle_valid(toggle_dll), + .dllt_done(dllt_done), + .mc_ACT_n(dllt_mc_ACT_n), // DRAM ACT_n command signal for four DRAM clock cycles. + .mc_ADR(dllt_mc_ADR), // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus. + .mc_BA(dllt_mc_BA), // DRAM bank address. 8 bits for each DRAM bank address. + .mc_BG(dllt_mc_BG), // DRAM bank group address. + .mc_CS_n(dllt_mc_CS_n), // DRAM CS_n + .mc_CKE(dllt_mc_CKE), + .clk_sel(clk_sel) + ); + `endif +endmodule diff --git a/sources/hdl/sim_verilog/tb_decode_stage.v b/sources/hdl/sim_verilog/tb_decode_stage.v new file mode 100644 index 0000000..1842cf7 --- /dev/null +++ b/sources/hdl/sim_verilog/tb_decode_stage.v @@ -0,0 +1,26 @@ +module tb_decode_stage( + + ); + + reg [63:0] instr; + reg [11:0] instr_pc; + reg instr_valid; + + decode_stage ds( + .instr(instr), + .instr_pc(instr_pc), + .instr_valid(instr_valid) + ); + + reg clk = 0, rst = 1; + + initial begin + #100; + rst = 0; + end + + always begin + #5; + clk = ~clk; + end +endmodule diff --git a/sources/hdl/sim_verilog/tb_frontend.v b/sources/hdl/sim_verilog/tb_frontend.v new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/sources/hdl/sim_verilog/tb_frontend.v diff --git a/sources/hdl/sim_verilog/tb_softmc_top.v b/sources/hdl/sim_verilog/tb_softmc_top.v new file mode 100644 index 0000000..6a61f44 --- /dev/null +++ b/sources/hdl/sim_verilog/tb_softmc_top.v @@ -0,0 +1,42 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 12/06/2018 05:43:09 PM +// Design Name: +// Module Name: tb_softmc_top +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module tb_only_softmc( + + ); + + reg clk = 0, rst = 1; + softmc_top smct( + .clk(clk), + .rst(rst) + ); + + initial begin + #50; + rst = 0; + end + + always begin + #5; + clk = ~clk; + end +endmodule diff --git a/sources/hdl/verilog/ddr_pipeline.v b/sources/hdl/verilog/ddr_pipeline.v new file mode 100644 index 0000000..f8ae5aa --- /dev/null +++ b/sources/hdl/verilog/ddr_pipeline.v @@ -0,0 +1,206 @@ +`include "parameters.vh" +`include "encoding.vh" + +module ddr_pipeline( + + // common signals + input clk, + input rst, + + // execute_stage <-> ddr_pipeline if + input ddr_valid, + input [`DDR_UOP_WIDTH*4-1:0] ddr_uop, + + // ddr_pipeline <-> outer DDRX IP interface + output [3:0] ddr_write, + output [3:0] ddr_read, + output [3:0] ddr_pre, + output [3:0] ddr_act, + output [3:0] ddr_ref, + output [3:0] ddr_zq, + output [3:0] ddr_nop, + output [3:0] ddr_sre, + output [3:0] ddr_srx, + output [3:0] ddr_ap, + output [3:0] ddr_pall, + output [3:0] ddr_half_bl, + output [4*`BG_WIDTH-1:0] ddr_bg, + output [4*`BANK_WIDTH-1:0] ddr_bank, + output [4*`COL_WIDTH-1:0] ddr_col, + output [4*`ROW_WIDTH-1:0] ddr_row, + output [511:0] ddr_wdata, + + // ddr_pipeline <-> regfile interface + input [511:0] wide_reg, + output [7:0] update_en, + output [4*8-1:0] update_ids, + output [32*8-1:0] update_vals, + input [`COL_WIDTH-1:0] casr, + input [`BANK_WIDTH+`BG_WIDTH-1:0] basr, + input [`ROW_WIDTH-1:0] rasr, + output [4*8-1:0] reg_ids, // registers we need to read + input [32*8-1:0] reg_vals // register values + ); + + //Split input uop into four ways + wire [`DDR_UOP_WIDTH-1:0] uop [3:0]; + genvar uops; + generate + for(uops = 0 ; uops < 4 ; uops = uops + 1) begin: split_uops + assign uop[uops] = ddr_uop[`DDR_UOP_WIDTH*uops +: `DDR_UOP_WIDTH]; + end + endgenerate + + // Figure out reg ids in the bubble cycle + reg [4*8-1:0] reg_ids_ns, reg_ids_r; + + reg s2_valid; + reg [`DDR_UOP_WIDTH-1:0] s2_uop [3:0]; + reg [7:0] s2_update_en; // which registers will we update + reg [8*32-1:0] s2_update_val; + + reg [3:0] ddr_write_ns, ddr_write_r; + reg [3:0] ddr_read_ns, ddr_read_r; + reg [3:0] ddr_pre_ns, ddr_pre_r; + reg [3:0] ddr_act_ns, ddr_act_r; + reg [3:0] ddr_ref_ns, ddr_ref_r; + reg [3:0] ddr_sre_ns, ddr_sre_r; + reg [3:0] ddr_srx_ns, ddr_srx_r; + reg [3:0] ddr_zq_ns, ddr_zq_r; + reg [3:0] ddr_nop_ns, ddr_nop_r; + reg [3:0] ddr_ap_ns, ddr_ap_r; + reg [3:0] ddr_pall_ns, ddr_pall_r; + reg [3:0] ddr_half_bl_ns, ddr_half_bl_r; + reg [4*`BG_WIDTH-1:0] ddr_bg_ns, ddr_bg_r; + reg [4*`BANK_WIDTH-1:0] ddr_bank_ns, ddr_bank_r; + reg [4*`COL_WIDTH-1:0] ddr_col_ns, ddr_col_r; + reg [4*`ROW_WIDTH-1:0] ddr_row_ns, ddr_row_r; + reg [511:0] ddr_data_r; + + assign update_vals = s2_update_val; + assign update_en = s2_update_en; + assign update_ids = reg_ids_r; + assign reg_ids = reg_ids_r; + // these values are registered before + // being offloaded to the outer module + assign ddr_write = ddr_write_r; + assign ddr_read = ddr_read_r; + assign ddr_pre = ddr_pre_r; + assign ddr_act = ddr_act_r; + assign ddr_ref = ddr_ref_r; + assign ddr_sre = ddr_sre_r; + assign ddr_srx = ddr_srx_r; + assign ddr_zq = ddr_zq_r; + assign ddr_nop = ddr_nop_r; + assign ddr_ap = ddr_ap_r; + assign ddr_pall = ddr_pall_r; + assign ddr_half_bl = ddr_half_bl_r; + assign ddr_bg = ddr_bg_r; + assign ddr_bank = ddr_bank_r; + assign ddr_col = ddr_col_r; + assign ddr_row = ddr_row_r; + assign ddr_wdata = ddr_data_r; + + integer i; + always @* begin + ddr_nop_ns = {4{`HIGH}}; + s2_update_en = {4{`LOW}}; + reg_ids_ns = reg_ids_r; + s2_update_val = 8*32'bX; + for(i = 0 ; i < 4 ; i = i + 1) begin: gen_ddrx_sigs + // Decide which registers to read in stage 1 + if(uop[i][`IS_WRITE] || uop[i][`IS_READ]) begin + reg_ids_ns[i*8 +: 4] = uop[i][`BAR +: 4]; + reg_ids_ns[i*8+4 +: 4] = uop[i][`CAR +: 4]; + end + if(uop[i][`IS_PRE]) begin + reg_ids_ns[i*8 +: 4] = uop[i][`BAR +: 4]; + end + if(uop[i][`IS_ACT]) begin + reg_ids_ns[i*8 +: 4] = uop[i][`BAR +: 4]; + reg_ids_ns[i*8+4 +: 4] = uop[i][`RAR +: 4]; + end + // stage 2 control sigs + ddr_pall_ns[i] = s2_uop[i][`PRE_ALL] & s2_uop[i][`IS_PRE]; + ddr_write_ns[i] = s2_uop[i][`IS_WRITE]; + ddr_read_ns[i] = s2_uop[i][`IS_READ]; + ddr_pre_ns[i] = s2_uop[i][`IS_PRE]; + ddr_act_ns[i] = s2_uop[i][`IS_ACT]; + ddr_zq_ns[i] = s2_uop[i][`IS_ZQ]; + ddr_ref_ns[i] = s2_uop[i][`IS_REF]; + ddr_sre_ns[i] = s2_uop[i][`IS_SRE]; + ddr_srx_ns[i] = s2_uop[i][`IS_SRX]; + ddr_ap_ns[i] = s2_uop[i][`DO_AP] & (s2_uop[i][`IS_WRITE] | s2_uop[i][`IS_READ]); + ddr_half_bl_ns[i] = s2_uop[i][`IS_BL4] & (s2_uop[i][`IS_WRITE] | s2_uop[i][`IS_READ]); + ddr_nop_ns[i] = s2_valid ? s2_uop[i][`IS_NOP] : {4{`HIGH}}; + // stage 2 address calculation + ddr_row_ns[i*`ROW_WIDTH +: `ROW_WIDTH] + = reg_vals[i*64+32 +: `ROW_WIDTH]; + ddr_bank_ns[i*`BANK_WIDTH +: `BANK_WIDTH] + = reg_vals[i*64 +: `BANK_WIDTH]; + ddr_bg_ns[i*`BG_WIDTH +: `BG_WIDTH] + = reg_vals[i*64+`BANK_WIDTH +: `BG_WIDTH]; + ddr_col_ns[i*`COL_WIDTH +: `COL_WIDTH] + = reg_vals[i*64+32 +: `COL_WIDTH]; + // stage 2 reg update + if(s2_uop[i][`INC_CAR] & (s2_uop[i][`IS_WRITE] | s2_uop[i][`IS_READ])) begin + s2_update_en[i*2+1] = `HIGH; + s2_update_val[i*64+32 +: 32] = reg_vals[i*64+32 +: `COL_WIDTH] + + casr; + end + else if(s2_uop[i][`INC_RAR] & (s2_uop[i][`IS_ACT])) begin + s2_update_en[i*2+1] = `HIGH; + s2_update_val[i*64+32 +: 32] = reg_vals[i*64+32 +: `ROW_WIDTH] + + rasr; + end + if(s2_uop[i][`INC_BAR]) begin + s2_update_en[i*2] = `HIGH; + s2_update_val[i*64 +: 32] = reg_vals[i*64 +: `BANK_WIDTH+`BG_WIDTH] + + basr; + end + end // for + end + + always @(posedge clk) begin + if(rst) begin + s2_valid <= `LOW; + for(i = 0 ; i < 4 ; i = i + 1) + s2_uop[i] <= {`DDR_UOP_WIDTH{`LOW}}; + ddr_write_r <= {4{`LOW}}; + ddr_read_r <= {4{`LOW}}; + ddr_pre_r <= {4{`LOW}}; + ddr_act_r <= {4{`LOW}}; + ddr_ref_r <= {4{`LOW}}; + ddr_sre_r <= {4{`LOW}}; + ddr_srx_r <= {4{`LOW}}; + ddr_zq_r <= {4{`LOW}}; + ddr_nop_r <= {4{`HIGH}}; + ddr_ap_r <= {4{`LOW}}; + ddr_half_bl_r <= {4{`LOW}}; + end + else begin + reg_ids_r <= reg_ids_ns; + s2_valid <= ddr_valid; + for(i = 0 ; i < 4 ; i = i + 1) + s2_uop[i] <= uop[i]; + ddr_write_r <= ddr_write_ns; + ddr_read_r <= ddr_read_ns; + ddr_pre_r <= ddr_pre_ns; + ddr_act_r <= ddr_act_ns; + ddr_ref_r <= ddr_ref_ns; + ddr_sre_r <= ddr_sre_ns; + ddr_srx_r <= ddr_srx_ns; + ddr_zq_r <= ddr_zq_ns; + ddr_nop_r <= ddr_nop_ns; + ddr_ap_r <= ddr_ap_ns; + ddr_pall_r <= ddr_pall_ns; + ddr_half_bl_r <= ddr_half_bl_ns; + ddr_bg_r <= ddr_bg_ns; + ddr_bank_r <= ddr_bank_ns; + ddr_col_r <= ddr_col_ns; + ddr_row_r <= ddr_row_ns; + ddr_data_r <= wide_reg; + end + end + +endmodule diff --git a/sources/hdl/verilog/decode_stage.v b/sources/hdl/verilog/decode_stage.v new file mode 100644 index 0000000..7f40cba --- /dev/null +++ b/sources/hdl/verilog/decode_stage.v @@ -0,0 +1,318 @@ +`include "parameters.vh" +`include "encoding.vh" + +module decode_stage( + + input clk, + input rst, + + // fetch stage <-> decode stage interface + input [`INSTR_WIDTH-1:0] instr, + input [`IMEM_ADDR_WIDTH-1:0] instr_pc, + input instr_valid, + + // decode stage <-> execute stage interface + output ddr_valid, + output exe_valid, + output [`DDR_UOP_WIDTH*4-1:0] ddr_uop, + output [`EXE_UOP_WIDTH-1:0] exe_uop, + output [`IMEM_ADDR_WIDTH-1:0] exe_pc, + output [32*7-1:0] ddr_stat + ); + + reg ddr_valid_r, ddr_valid_ns; + reg exe_valid_r, exe_valid_ns; + reg [`IMEM_ADDR_WIDTH-1:0] exe_pc_r; + + reg [`DDR_UOP_WIDTH-1:0] ddr_uop_r [3:0], ddr_uop_ns [3:0]; + reg [`EXE_UOP_WIDTH-1:0] exe_uop_r, exe_uop_ns; + reg[31:0] ddr_stat_r[0:6]; //WRITE, READ, PRE, ACT, ZQ, REF, CYC counts + + // split the instr into four individual insts + localparam div = 16; + wire [`INSTR_WIDTH/4-1:0] ddr_insts [3:0]; + assign ddr_insts[0] = instr [0 +: div]; + assign ddr_insts[1] = instr [div +: div]; + assign ddr_insts[2] = instr [div*2 +: div]; + assign ddr_insts[3] = instr [div*3 +: div]; + // gather all ddr uops into one output (¯\_(ツ)_/¯) + // verilog does not let us define output vectors + genvar uops; + generate + for(uops = 0 ; uops < 4 ; uops = uops + 1) begin: gather_uops + assign ddr_uop[uops*`DDR_UOP_WIDTH +: `DDR_UOP_WIDTH] = + ddr_uop_r[uops]; + end + endgenerate + assign exe_uop = exe_uop_r; + assign exe_pc = exe_pc_r; + assign ddr_valid = ddr_valid_r; + assign exe_valid = exe_valid_r; + assign ddr_stat = {ddr_stat_r[6], ddr_stat_r[5], + ddr_stat_r[4], ddr_stat_r[3], + ddr_stat_r[2], ddr_stat_r[1], + ddr_stat_r[0]}; + + reg is_started = 0; + reg[26:0] imd; + integer i; + + always @* begin + ddr_valid_ns = `LOW; + exe_valid_ns = `LOW; + exe_uop_ns = {`EXE_UOP_WIDTH{`LOW}}; + for(i = 0 ; i < 4 ; i = i + 1) + ddr_uop_ns[i] = {`DDR_UOP_WIDTH{`LOW}}; + if(instr_valid) begin + // Decoding a DDR packet + if(instr[`DDR_OFFSET]) begin + ddr_valid_ns = `HIGH; + for(i = 0 ; i < 4 ; i = i + 1) begin: gen_ddr_uops + case(ddr_insts[i][`DDR_CODE_OFFSET +: 3]) + `WRITE: begin + ddr_uop_ns[i][`IS_WRITE] = `HIGH; + ddr_uop_ns[i][`INC_CAR] = ddr_insts[i][`DEC_INC_CAR]; + ddr_uop_ns[i][`INC_BAR] = ddr_insts[i][`DEC_INC_BAR]; + ddr_uop_ns[i][`CAR+:4] = ddr_insts[i][`DEC_CAR+:4]; + ddr_uop_ns[i][`BAR+:4] = ddr_insts[i][`DEC_BAR+:4]; + ddr_uop_ns[i][`DO_AP] = ddr_insts[i][`DEC_AP]; + ddr_uop_ns[i][`IS_BL4] = ddr_insts[i][`DEC_BL4]; + end + `READ: begin + ddr_uop_ns[i][`IS_READ] = `HIGH; + ddr_uop_ns[i][`INC_CAR] = ddr_insts[i][`DEC_INC_CAR]; + ddr_uop_ns[i][`INC_BAR] = ddr_insts[i][`DEC_INC_BAR]; + ddr_uop_ns[i][`CAR+:4] = ddr_insts[i][`DEC_CAR+:4]; + ddr_uop_ns[i][`BAR+:4] = ddr_insts[i][`DEC_BAR+:4]; + ddr_uop_ns[i][`DO_AP] = ddr_insts[i][`DEC_AP]; + ddr_uop_ns[i][`IS_BL4] = ddr_insts[i][`DEC_BL4]; + end + `PRE: begin + ddr_uop_ns[i][`IS_PRE] = `HIGH; + ddr_uop_ns[i][`PRE_ALL] = ddr_insts[i][`DEC_PRE_ALL]; + ddr_uop_ns[i][`INC_BAR] = ddr_insts[i][`DEC_INC_BAR]; + ddr_uop_ns[i][`BAR+:4] = ddr_insts[i][`DEC_BAR+:4]; + end + `ACT: begin + ddr_uop_ns[i][`IS_ACT] = `HIGH; + ddr_uop_ns[i][`INC_RAR] = ddr_insts[i][`DEC_INC_RAR]; + ddr_uop_ns[i][`INC_BAR] = ddr_insts[i][`DEC_INC_BAR]; + ddr_uop_ns[i][`RAR+:4] = ddr_insts[i][`DEC_RAR+:4]; + ddr_uop_ns[i][`BAR+:4] = ddr_insts[i][`DEC_BAR+:4]; + end + `ZQ: begin + ddr_uop_ns[i][`IS_ZQ] = `HIGH; + end + `REF: begin + ddr_uop_ns[i][`IS_REF] = `HIGH; + end + `NOP: begin + ddr_uop_ns[i][`IS_NOP] = `HIGH; + end + endcase + end + end + else if(instr[`SR_OFFSET]) begin + ddr_valid_ns = `HIGH; + case(instr[`FU_CODE_OFFSET]) + `SRE: begin + ddr_uop_ns[0][`IS_SRE] = `HIGH; + ddr_uop_ns[1][`IS_NOP] = `HIGH; + ddr_uop_ns[2][`IS_NOP] = `HIGH; + ddr_uop_ns[3][`IS_NOP] = `HIGH; + end + `SRX: begin + ddr_uop_ns[0][`IS_SRX] = `HIGH; + ddr_uop_ns[1][`IS_NOP] = `HIGH; + ddr_uop_ns[2][`IS_NOP] = `HIGH; + ddr_uop_ns[3][`IS_NOP] = `HIGH; + end + endcase + end + else begin + exe_valid_ns = `HIGH; + // Decoding a branch instruction + if(instr[`BRANCH_OFFSET]) begin + case(instr[`FU_CODE_OFFSET +: 8]) + `BL: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`IMD +: 19] = instr[`DEC_BR_TGT_OFFSET +: 19]; + exe_uop_ns[`IS_BL] = `HIGH; + end + `BEQ: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`IMD +: 19] = instr[`DEC_BR_TGT_OFFSET +: 19]; + exe_uop_ns[`IS_BEQ] = `HIGH; + end + `JUMP: begin + exe_uop_ns[`IMD +: 27] = instr[`DEC_JUMP_OFFSET +: 27]; + exe_uop_ns[`IS_JUMP] = `HIGH; + end + `SLEEP: begin + exe_uop_ns[`IS_SLEEP] = `HIGH; + exe_uop_ns[`IMD +: 27] = instr[`DEC_SLEEP_OFFSET +: 27]; + end + endcase + end + else if(instr[`MEM_OFFSET]) begin + case(instr[`FU_CODE_OFFSET +: 8]) + `LD: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IMD +: 16] = instr[`DEC_IMD1 +: 16]; + exe_uop_ns[`IS_MEM] = `HIGH; + exe_uop_ns[`IS_LD] = `HIGH; + exe_uop_ns[`HAS_IMD] = `HIGH; + end + `ST: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; // The address base to write to + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RT +: 4]; // The value to write + exe_uop_ns[`IMD +: 16] = instr[`DEC_IMD1 +: 16]; + exe_uop_ns[`IS_MEM] = `HIGH; + exe_uop_ns[`IS_ST] = `HIGH; + exe_uop_ns[`HAS_IMD] = `HIGH; + end + endcase + end + else if(instr[`BW_OFFSET]) begin + case(instr[`FU_CODE_OFFSET +: 8]) + `AND: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_AND] = `HIGH; + end + `OR: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_OR] = `HIGH; + end + `XOR: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_XOR] = `HIGH; + end + endcase + end + // Decoding a normal instruction + else begin + case(instr[`FU_CODE_OFFSET +: 8]) + `ADD: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_ADD] = `HIGH; + end + `ADDI: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`IMD +: 16] = instr[`DEC_IMD1 +: 16]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_ADD] = `HIGH; + exe_uop_ns[`HAS_IMD] = `HIGH; + end + `SUB: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RS2 +: 4] = instr[`DEC_RS2 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_SUB] = `HIGH; + end + `SUBI: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`IMD +: 16] = instr[`DEC_IMD1 +: 16]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_SUB] = `HIGH; + exe_uop_ns[`HAS_IMD] = `HIGH; + end + `MV: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_MOV] = `HIGH; + end + `SRC: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_SRC] = `HIGH; + end + `LI: begin + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_LI] = `HIGH; + exe_uop_ns[`IMD +: 16] = instr[`DEC_IMD1 +: 16]; + exe_uop_ns[`IMD2 +: 16]= instr[`DEC_IMD3 +: 16]; + exe_uop_ns[`HAS_IMD] = `HIGH; + end + `LDWD: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + // used to select word offset in wide write data register + exe_uop_ns[`RT +: 4] = instr[`DEC_WO +: 4]; + exe_uop_ns[`IS_LDWD] = `HIGH; + end + `LDPC: begin + exe_uop_ns[`RS1 +: 4] = instr[`DEC_RS1 +: 4]; + exe_uop_ns[`RT +: 4] = instr[`DEC_RT +: 4]; + exe_uop_ns[`IS_LDPC] = `HIGH; + end + endcase + end + end + end + end + + always @(posedge clk) begin + + if(rst) begin + exe_pc_r <= {`IMEM_ADDR_WIDTH{`LOW}}; + exe_uop_r <= {`EXE_UOP_WIDTH{`LOW}}; + exe_valid_r <= `LOW; + ddr_valid_r <= `LOW; + for(i = 0 ; i < 4 ; i = i + 1) + ddr_uop_r[i] <= {`DDR_UOP_WIDTH{`LOW}}; + is_started <= `LOW; + end + else begin + exe_uop_r <= exe_uop_ns; + exe_valid_r <= exe_valid_ns; + ddr_valid_r <= ddr_valid_ns; + for(i = 0 ; i < 4 ; i = i + 1) + ddr_uop_r[i] <= ddr_uop_ns[i]; + exe_pc_r <= instr_pc; + end + + if(~is_started) begin + for(i = 0 ; i < 7 ; i = i + 1) begin + ddr_stat_r[i] <= 0; + end + if(instr_pc == 1) + is_started <= 1; + end + else begin + ddr_stat_r[6] <= ddr_stat_r[6] + 1; + if(instr_valid) begin + if(instr[`DDR_OFFSET]) begin + for(i = 0 ; i < 4 ; i = i + 1) begin + case(ddr_insts[i][`DDR_CODE_OFFSET +: 3]) + `WRITE: + ddr_stat_r[0] <= ddr_stat_r[0] + 1; + `READ: + ddr_stat_r[1] <= ddr_stat_r[1] + 1; + `PRE: + ddr_stat_r[2] <= ddr_stat_r[2] + 1; + `ACT: + ddr_stat_r[3] <= ddr_stat_r[3] + 1; + `ZQ: + ddr_stat_r[4] <= ddr_stat_r[4] + 1; + `REF: + ddr_stat_r[5] <= ddr_stat_r[5] + 1; + endcase + end + end + end + end + end + + + +endmodule diff --git a/sources/hdl/verilog/diff_shift_reg.v b/sources/hdl/verilog/diff_shift_reg.v new file mode 100644 index 0000000..ae39c3a --- /dev/null +++ b/sources/hdl/verilog/diff_shift_reg.v @@ -0,0 +1,69 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 12/19/2018 01:07:06 PM +// Design Name: +// Module Name: diff_shift_reg +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module diff_shift_reg( + input clk, + input rst, + + input flush, + + input [15:0] in, + input in_valid, + + output[511:0] out, + output out_valid + ); + + reg [4:0] ctr_r; + reg [511:0] shift_r; + reg valid_r; + + always @(posedge clk) begin + if(rst) begin + shift_r <= 512'bX; + ctr_r <= 5'b0; + valid_r <= 1'b0; + end + else begin + if(flush) begin + valid_r <= `HIGH; + ctr_r <= 5'b0; + end + else begin + if(in_valid) begin + shift_r[16 +: 16*31] <= shift_r[0 +: 16*31]; + shift_r[0 +: 16] <= in; + ctr_r <= ctr_r + 1; + end + else begin + ctr_r <= ctr_r; + shift_r <= shift_r; + end + valid_r <= (|ctr_r) && in_valid; + end + end + end + + assign out_valid = valid_r; + assign out = shift_r; + +endmodule diff --git a/sources/hdl/verilog/dll_toggler.v b/sources/hdl/verilog/dll_toggler.v new file mode 100644 index 0000000..a6cb5bf --- /dev/null +++ b/sources/hdl/verilog/dll_toggler.v @@ -0,0 +1,206 @@ +`include "parameters.vh" + +module dll_toggler #(parameter CKE_WIDTH = 1, RANK_WIDTH = 1, DQ_WIDTH = 64, DRAM_CMD_SLOTS = 4, + DATA_BUF_ADDR_WIDTH = 5, DBUF_WIDTH = 4, DQ_BURST = 8) + +( + + input clk, + input rst, + input toggle_valid, + output reg dllt_done, + + // ---------- DDR4 Signals ---------- + output [7:0] mc_ACT_n, // DRAM ACT_n command signal for four DRAM clock cycles. + output [`ADDR_WIDTH*8-1:0] mc_ADR, // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus. + output [`BANK_WIDTH*8-1:0] mc_BA, // DRAM bank address. 8 bits for each DRAM bank address. + output [`BG_WIDTH*8-1:0] mc_BG, // DRAM bank group address. + output [`CS_WIDTH*8-1:0] mc_CS_n, // DRAM CS_n + + // NOTE: CKE is transmitted within another clock domain that is 4x faster than fabric clock. + output [`CKE_WIDTH*8-1:0] mc_CKE, + output clk_sel + + ); + + wire [13:0] MR1_CONF = 14'b00001100000000; + + reg [`ADDR_WIDTH*8-1:0] ADR_ns, ADR_r; + reg [`BANK_WIDTH*8-1:0] BA_ns, BA_r; + reg [`BG_WIDTH*8-1:0] BG_ns, BG_r; + reg [`CS_WIDTH*8-1:0] CS_n_ns, CS_n_r; + reg [`ODT_WIDTH*8-1:0] ODT_ns, ODT_r; + reg [`CKE_WIDTH*8-1:0] CKE_ns, CKE_r; + + reg clk_sel_ns, clk_sel_r; + + assign mc_ACT_n = {8{`HIGH}}; + assign mc_ADR = ADR_r; + assign mc_BA = BA_r; + assign mc_BG = BG_r; + assign mc_CS_n = CS_n_r; + assign mc_CKE = CKE_r; + assign clk_sel = clk_sel_r; + + + // TODO we need to implement the following routine (TO TURN DLL OFF ONLY) + // 1 - Precharge all banks (IDLE STATE) + // 2 - Set MR1 A0 to 1 (DISABLE DLL), wait tMOD + // 3 - Enter self-refresh mode, wait until tCKSRE/tCKSRE_PAR + // 4 - Change clock frequency + // 5 - Wait at least tCKSRX (until clock signal stabilizes) + // 6 - Exit self-refresh mode, keep CKE high from now on + // if any ODT feature was enabled in self-ref. mode + // ODT signal must be LOW. + // 7 - Wait tXS and set mode registers to appropriate values + // (UG says that CL, CWL and WR may need to be updated), + // wait for another tMOD + + localparam IDLE_S = 0; + localparam IDLE_WAIT_S = 1; + localparam SET_MR_1_S = 2; + localparam WAIT_MR_1_S = 3; + localparam ENTER_SELF_REF_S = 4; + localparam WAIT_ENTER_SELF_REF_S = 5; + localparam CHANGE_CLK_FREQ_S = 6; + localparam WAIT_CHANGE_CLK_FREQ_S = 7; + localparam EXIT_SELF_REF_S = 8; + localparam WAIT_EXIT_SELF_REF_S = 9; + + localparam T_PRECHARGE = 5; // in terms of MC cycles (which is 4x less frequent than the DDR4) + localparam T_MOD = 24; // Max(24CK,15ns) + localparam T_CKSRE = 300; // Max(5CK,10ns) + localparam T_CKSRX = 300; // Max(5CK, 10ns) + additional room for clock to stabilize; + localparam T_XS = 1000; + + + reg[3:0] state_r, state_ns; + + reg[9:0] wait_r, wait_ns; + + integer adr_bit_i; + + always @* begin + // Set bank and bank group signals + dllt_done = `LOW; + ADR_ns = {`ADDR_WIDTH*8{`HIGH}}; + BG_ns = {`BG_WIDTH*8{`LOW}}; + BA_ns = {`BANK_WIDTH*8{`LOW}}; + CS_n_ns = {`CS_WIDTH*8{`HIGH}}; // by default we don't issue any commands + CKE_ns = CKE_r; // register this signal because it needs to be LOW during self-ref. + wait_ns = wait_r; + state_ns = state_r; + clk_sel_ns = clk_sel_r; + case (state_r) + IDLE_S: begin + if(toggle_valid) begin + CS_n_ns[1:0] = {2*`CS_WIDTH{`LOW}}; + ADR_ns[`ADDR_WIDTH*8-3*8 +: 2] = {2{`LOW}}; // WE + ADR_ns[`ADDR_WIDTH*8-2*8 +: 2] = {2{`HIGH}}; // ~CAS + ADR_ns[`ADDR_WIDTH*8-8 +: 2] = {2{`LOW}}; // RAS + ADR_ns[10*8 +: 2] = {2{`HIGH}}; // Pre ALL + wait_ns = T_PRECHARGE; + state_ns = IDLE_WAIT_S; + end + end + IDLE_WAIT_S: begin + if(wait_r > 0) + wait_ns = wait_r - 1'b1; + else + state_ns = SET_MR_1_S; + end + SET_MR_1_S: begin + CS_n_ns[1:0] = {2*`CS_WIDTH{`LOW}}; + ADR_ns[`ADDR_WIDTH*8-3*8 +: 2] = {2{`LOW}}; // WE + ADR_ns[`ADDR_WIDTH*8-2*8 +: 2] = {2{`LOW}}; // CAS + ADR_ns[`ADDR_WIDTH*8-8 +: 2] = {2{`LOW}}; // RAS + for(adr_bit_i = 0 ; adr_bit_i < 14 ; adr_bit_i = adr_bit_i + 1) begin + ADR_ns[adr_bit_i*8 +: 2] = + {2{MR1_CONF[adr_bit_i]}}; + end + // Bank + Bank group bits indicate which register this MRS is writing to. + BA_ns[0 +: 2] = {2{`HIGH}}; // Select MR1 + ADR_ns[0 +: 2] = {2{`LOW}}; // Set A0 to 0 + state_ns = WAIT_MR_1_S; + wait_ns = T_MOD; + end + WAIT_MR_1_S: begin + if(wait_r > 0) + wait_ns = wait_r - 1'b1; + else + state_ns = ENTER_SELF_REF_S; + end + ENTER_SELF_REF_S: begin + CKE_ns = `LOW; + CS_n_ns[1:0] = {2*`CS_WIDTH{`LOW}}; + ADR_ns[`ADDR_WIDTH*8-3*8 +: 2] = {2{`HIGH}}; // ~WE + ADR_ns[`ADDR_WIDTH*8-2*8 +: 2] = {2{`LOW}}; // CAS + ADR_ns[`ADDR_WIDTH*8-8 +: 2] = {2{`LOW}}; // RAS + state_ns = WAIT_ENTER_SELF_REF_S; + wait_ns = T_CKSRE; + end + WAIT_ENTER_SELF_REF_S: begin + if(wait_r > 0) + wait_ns = wait_r - 1'b1; + else begin + state_ns = CHANGE_CLK_FREQ_S; + end + end + CHANGE_CLK_FREQ_S: begin + clk_sel_ns = ~clk_sel_r; + wait_ns = T_CKSRX; + state_ns = WAIT_CHANGE_CLK_FREQ_S; + end + WAIT_CHANGE_CLK_FREQ_S: begin + if(wait_r > 0) + wait_ns = wait_r - 1'b1; + else begin + state_ns = EXIT_SELF_REF_S; + end + end + EXIT_SELF_REF_S: begin + CKE_ns = {`CKE_WIDTH*8{`HIGH}}; + CS_n_ns[7:0] = {8*`CS_WIDTH{`HIGH}}; + ADR_ns[`ADDR_WIDTH*8-3*8 +: 2] = {2{`HIGH}}; // ~WE + ADR_ns[`ADDR_WIDTH*8-2*8 +: 2] = {2{`HIGH}}; // CAS + ADR_ns[`ADDR_WIDTH*8-8 +: 2] = {2{`HIGH}}; // RAS + state_ns = WAIT_EXIT_SELF_REF_S; + wait_ns = T_XS; + end + WAIT_EXIT_SELF_REF_S: begin + CS_n_ns[7:0] = {8*`CS_WIDTH{`HIGH}}; + if(wait_r > 0) + wait_ns = wait_r - 1'b1; + else begin + state_ns = IDLE_S; + dllt_done = `HIGH; + end + end + endcase + + end + + always @(posedge clk) begin + if(rst) begin + state_r <= IDLE_S; + wait_r <= `LOW; + clk_sel_r <= `LOW; + CKE_r <= {`CKE_WIDTH*8{`HIGH}}; + ADR_r = {`ADDR_WIDTH*8{`LOW}}; + BG_r = {`BG_WIDTH*8{`LOW}}; + BA_r = {`BANK_WIDTH*8{`LOW}}; + CS_n_r = {`CS_WIDTH*8{`HIGH}}; + end + else begin + state_r <= state_ns; + wait_r <= wait_ns; + clk_sel_r <= clk_sel_ns; + CKE_r <= CKE_ns; + ADR_r <= ADR_ns; + BA_r <= BA_ns; + BG_r <= BG_ns; + CS_n_r <= CS_n_ns; + end + end + +endmodule diff --git a/sources/hdl/verilog/exe_pipeline.v b/sources/hdl/verilog/exe_pipeline.v new file mode 100644 index 0000000..e2111a3 --- /dev/null +++ b/sources/hdl/verilog/exe_pipeline.v @@ -0,0 +1,191 @@ +`include "parameters.vh" +`include "encoding.vh" + +module exe_pipeline( + // common signals + input clk, + input rst, + + // exe_pipeline <-> execution stage if + input exe_valid, + input [`EXE_UOP_WIDTH-1:0] exe_uop, + input [`IMEM_ADDR_WIDTH-1:0] exe_pc, + + // branch unit if + output br_resolve, + output [`IMEM_ADDR_WIDTH-1:0] br_target, + + // exe_pipeline <-> register file if + output wide_wen, + output [31:0] rf_wdata, + output rf_wen, + output [7:0] rf_raddr, + output [3:0] rf_waddr, + input [2*32-1:0] rf_rdata, + input [32*7-1:0] ddr_stat, + + // exe_pipeline <-> scratchpad + output mem_wen, + output mem_ren, + output [9:0] mem_addr, + output [31:0] mem_wdata, + input [31:0] mem_rdata + ); + + // calculated at stage one, registers + reg s2_valid; + reg [`EXE_UOP_WIDTH-1:0] s2_uop; + reg [`IMEM_ADDR_WIDTH-1:0] s2_pc; + reg [3:0] s2_rs1; + reg [3:0] s2_rs2; + reg [3:0] s2_rt; + reg s2_wen; + reg s2_mem_ren; + reg s2_mem_wen; + reg s3_wen; // for loads + reg [3:0] s3_rt; // for loads + reg s2_wide_wen; + reg [31:0] s2_imd_r, s2_imd_ns; + + // delayed branch resolution signals + // calculated at stage two, registers + reg s3_br_resolve; + reg [`IMEM_ADDR_WIDTH-1:0] s3_br_target; + + // combinational elements + reg [31:0] s2_wdata; + wire [31:0] s2_rs1_data, s2_rs2_data; + reg [31:0] s2_mem_wdata; + reg [`IMEM_ADDR_WIDTH-1:0] fetch_pc; + + assign wide_wen = s2_wide_wen; + assign rf_wdata = s3_wen ? mem_rdata : s2_wdata; + assign rf_wen = s2_wen || s3_wen; + assign rf_raddr[0+:4] = s2_rs1; + assign rf_raddr[4+:4] = s2_rs2; + assign rf_waddr = s3_wen ? s3_rt : s2_rt; + + assign s2_rs1_data = rf_rdata[0+:32]; + assign s2_rs2_data = rf_rdata[32+:32]; + assign br_resolve = s3_br_resolve; + assign br_target = s3_br_target; + + assign mem_addr = s2_rs1_data + s2_imd_r; + assign mem_wen = s2_mem_wen; + assign mem_ren = s2_mem_ren; + assign mem_wdata = s2_mem_wdata; + + always @* begin + // stage one, decode immediate value + s2_mem_wen = `LOW; + s2_imd_ns = s2_imd_r; + fetch_pc = {`IMEM_ADDR_WIDTH{1'bX}}; + s2_wdata = 32'bX; + s2_mem_wen = `LOW; + s2_mem_ren = `LOW; + if(exe_uop[`HAS_IMD]) begin + s2_imd_ns[15:0] = exe_uop[`IMD +: 16]; + s2_imd_ns[31:16] = {16{`LOW}}; + end + if(exe_uop[`IS_LI]) begin + s2_imd_ns[31:16] = exe_uop[`IMD2 +: 16]; + end + if(exe_uop[`IS_BL] | exe_uop[`IS_BEQ]) begin + s2_imd_ns[31:0] = exe_uop[`IMD +: 19]; + end + if(exe_uop[`IS_JUMP]) begin + s2_imd_ns[31:0] = exe_uop[`IMD +: 27]; + end + // stage two, actual computation + if(s2_uop[`IS_ADD]) begin + if(s2_uop[`HAS_IMD]) + s2_wdata = s2_rs1_data + s2_imd_r; + else + s2_wdata = s2_rs1_data + s2_rs2_data; + end + if(s2_uop[`IS_SUB]) begin + if(s2_uop[`HAS_IMD]) + s2_wdata = s2_rs1_data - s2_imd_r; + else + s2_wdata = s2_rs1_data - s2_rs2_data; + end + if(s2_uop[`IS_MOV] || s2_uop[`IS_LDWD]) begin + s2_wdata = s2_rs1_data; + end + if(s2_uop[`IS_LI]) begin + s2_wdata = s2_imd_r; + end + if(s2_uop[`IS_LDPC]) begin + s2_wdata = ddr_stat[s2_rs1*32 +: 32]; + end + if(s2_uop[`IS_SRC]) begin + s2_wdata[30:0] = s2_rs1_data[31:1]; + s2_wdata[31] = s2_rs1_data[0]; + end + // Bitwise ops + if(s2_uop[`IS_AND]) begin + s2_wdata = s2_rs1_data & s2_rs2_data; + end + if(s2_uop[`IS_OR]) begin + s2_wdata = s2_rs1_data | s2_rs2_data; + end + if(s2_uop[`IS_XOR]) begin + s2_wdata = s2_rs1_data ^ s2_rs2_data; + end + // mem unit + if(s2_uop[`IS_LD]) begin + s2_mem_ren = `HIGH; + end + if(s2_uop[`IS_ST]) begin + s2_mem_wdata = s2_rs2_data; + s2_mem_wen = `HIGH; + end + + // branch unit + if(s2_uop[`IS_BL]) begin + if(s2_rs1_data < s2_rs2_data) + fetch_pc = s2_imd_r; + else // not taken + fetch_pc = s2_pc + 1; + end + if(s2_uop[`IS_BEQ]) begin + if(s2_rs1_data == s2_rs2_data) + fetch_pc = s2_imd_r; + else // not taken + fetch_pc = s2_pc + 1; + end + if(s2_uop[`IS_JUMP]) begin + fetch_pc = s2_imd_r; + end + if(s2_uop[`IS_SLEEP]) begin + // not implemented + // frontent/fetch handles api sleeps + end + + end + + always @(posedge clk) begin + // stage one, further decode + s2_valid <= exe_valid; + s2_uop <= exe_uop; + s2_pc <= exe_pc; + s2_rs1 <= exe_uop[`RS1 +: 4]; + s2_rs2 <= exe_uop[`RS2 +: 4]; + s2_rt <= exe_uop[`RT +: 4]; + s2_imd_r <= s2_imd_ns; + s2_wen <= exe_uop[`IS_ADD] || exe_uop[`IS_SUB] || + exe_uop[`IS_MOV] || exe_uop[`IS_LI] || + exe_uop[`IS_LDWD] || exe_uop[`IS_SRC] || + exe_uop[`IS_AND] || exe_uop[`IS_OR] || + exe_uop[`IS_XOR] || exe_uop[`IS_LDPC]; + s2_wide_wen <= exe_uop[`IS_LDWD]; + // stage two, delayed branch signals + s3_br_resolve <= s2_valid && (s2_uop[`IS_BL] || + s2_uop[`IS_BEQ] || + s2_uop[`IS_JUMP]); + s3_br_target <= fetch_pc; + s3_wen <= s2_uop[`IS_LD]; // write path for loads + s3_rt <= s2_uop[`RT +: 4]; + end + +endmodule diff --git a/sources/hdl/verilog/execute_stage.v b/sources/hdl/verilog/execute_stage.v new file mode 100644 index 0000000..0b690f8 --- /dev/null +++ b/sources/hdl/verilog/execute_stage.v @@ -0,0 +1,194 @@ +`include "parameters.vh" + +module execute_stage( + + // common signals + input clk, + input rst, + + // decode stage <-> execute stage if + input ddr_valid, + input exe_valid, + input [`DDR_UOP_WIDTH*4-1:0] ddr_uop, + input [`EXE_UOP_WIDTH-1:0] exe_uop, + input [`IMEM_ADDR_WIDTH-1:0] exe_pc, + + // branch unit <-> fetch stage if + output br_resolve, + output [`IMEM_ADDR_WIDTH-1:0] br_target, + + // execute <-> outer DDRX IP interface + output [3:0] ddr_write, + output [3:0] ddr_read, + output [3:0] ddr_pre, + output [3:0] ddr_act, + output [3:0] ddr_ref, + output [3:0] ddr_sre, + output [3:0] ddr_srx, + output [3:0] ddr_zq, + output [3:0] ddr_nop, + output [3:0] ddr_ap, + output [3:0] ddr_pall, + output [3:0] ddr_half_bl, + output [4*`BG_WIDTH-1:0] ddr_bg, + output [4*`BANK_WIDTH-1:0] ddr_bank, + output [4*`COL_WIDTH-1:0] ddr_col, + output [4*`ROW_WIDTH-1:0] ddr_row, + output [511:0] ddr_wdata, + + // execute <-> reg file if + output rf_wide_wen, + output [3:0] rf_wide_offset, + input [32*8-1:0] rf_rdata, + output [32*8-1:0] rf_wdata, + output [7:0] rf_wen, + output [4*8-1:0] rf_raddr, + output [4*8-1:0] rf_waddr, + input [`COL_WIDTH-1:0] casr, + input [`BANK_WIDTH+`BG_WIDTH-1:0] basr, + input [`ROW_WIDTH-1:0] rasr, + input [511:0] wide_reg, + + // update stride registers, wen is OH (3'b001 = update rasr) + output [31:0] srf_value, + output [2:0] srf_wen, + input [32*7-1:0] ddr_stat + ); + + reg s2_exe; // exe_pipeline has regfile ports + + // ddr operations can optionally update + // registers. TODO when do we read the + // stride values? + wire [7:0] rf_wen_ddr; + wire [4*8-1:0] rf_waddr_ddr; + wire [32*8-1:0] rf_wdata_ddr; + wire [4*8-1:0] rf_raddr_ddr; + + ddr_pipeline dp( + .clk(clk), + .rst(rst), + + // execute <-> ddr_pipe if + .ddr_valid(ddr_valid), + .ddr_uop(ddr_uop), + + // ddr_pipeline <-> outer DDRX IP interface + .ddr_write(ddr_write), + .ddr_read(ddr_read), + .ddr_pre(ddr_pre), + .ddr_act(ddr_act), + .ddr_ref(ddr_ref), + .ddr_sre(ddr_sre), + .ddr_srx(ddr_srx), + .ddr_zq(ddr_zq), + .ddr_nop(ddr_nop), + .ddr_ap(ddr_ap), + .ddr_pall(ddr_pall), + .ddr_half_bl(ddr_half_bl), + .ddr_bg(ddr_bg), + .ddr_bank(ddr_bank), + .ddr_col(ddr_col), + .ddr_row(ddr_row), + .ddr_wdata(ddr_wdata), + // ddr_pipeline <-> regfile interface + .update_en(rf_wen_ddr), + .update_ids(rf_waddr_ddr), + .update_vals(rf_wdata_ddr), + .casr(casr), + .basr(basr), + .rasr(rasr), + .reg_ids(rf_raddr_ddr), // registers we need to read + .reg_vals(rf_rdata), // register values + .wide_reg(wide_reg) // write data register + ); + + + wire[31:0] rf_wdata_exe; + wire[7:0] rf_raddr_exe; + wire[3:0] rf_waddr_exe; + wire rf_wen_exe; + wire rf_wide_wen_exe; + + wire mem_wen; + wire mem_ren; + wire[9:0] mem_addr; + wire[31:0] mem_wdata; + wire[31:0] mem_rdata; + + exe_pipeline ep( + .clk(clk), + .rst(rst), + + // exe_pipeline <-> execute stage if + .exe_valid(exe_valid), + .exe_uop(exe_uop), + .exe_pc(exe_pc), + + // branch unit <-> fetch stage if + .br_resolve(br_resolve), + .br_target(br_target), + + // exe_pipeline <-> regfile if + .wide_wen(rf_wide_wen_exe), + .rf_wdata(rf_wdata_exe), + .rf_wen(rf_wen_exe), + .rf_raddr(rf_raddr_exe), + .rf_rdata(rf_rdata[0 +: 32*2]), + .rf_waddr(rf_waddr_exe), + + // exe_pipeline <-> data_mem + .mem_wen(mem_wen), + .mem_ren(mem_ren), + .mem_addr(mem_addr), + .mem_wdata(mem_wdata), + .mem_rdata(mem_rdata), + .ddr_stat(ddr_stat) + + ); +`ifdef XILINX_SIMULATOR + reg_mem data_mem( + .addr(mem_addr), + .clk(clk), + .din(mem_wdata), + .dout(mem_rdata), + .en(mem_wen || mem_ren), + .we(mem_wen) + ); +`else + scratchpad data_mem( + .addra(mem_addr), + .clka(clk), + .dina(mem_wdata), + .douta(mem_rdata), + .ena(mem_wen || mem_ren), + .wea(mem_wen) + ); +`endif + + wire exe_target_srf = rf_waddr_exe == 4'b0000 || + rf_waddr_exe == 4'b0001 || + rf_waddr_exe == 4'b0010; + + assign rf_wide_wen = rf_wide_wen_exe; + assign rf_wide_offset = rf_waddr_exe; + assign rf_wdata[32 +: 7*32] = rf_wdata_ddr[32 +: 7*32]; + assign rf_wdata[0 +: 32] = rf_wen_exe ? rf_wdata_exe : rf_wdata_ddr[0 +: 32]; + assign rf_wen = (rf_wen_exe & ~rf_wide_wen_exe & ~exe_target_srf) | rf_wen_ddr; + assign rf_raddr[8 +: 6*4] = rf_raddr_ddr[8 +: 6*4]; + assign rf_raddr[0 +: 2*4] = s2_exe ? rf_raddr_exe : rf_raddr_ddr[0 +: 2*8]; + assign rf_waddr[4 +: 7*4] = rf_waddr_ddr[4 +: 7*4]; + assign rf_waddr[0 +: 4] = rf_wen_exe ? rf_waddr_exe : rf_waddr_ddr[0 +: 4]; + + // First 3 register ids implicitly target stride registers + assign srf_wen[0] = rf_wen_exe & ~rf_wide_wen_exe & (rf_waddr_exe == 4'b0000); + assign srf_wen[1] = rf_wen_exe & ~rf_wide_wen_exe & (rf_waddr_exe == 4'b0001); + assign srf_wen[2] = rf_wen_exe & ~rf_wide_wen_exe & (rf_waddr_exe == 4'b0010); + + assign srf_value = rf_wdata_exe; + + always @(posedge clk) begin + s2_exe <= exe_valid; + end + +endmodule diff --git a/sources/hdl/verilog/fetch_stage.v b/sources/hdl/verilog/fetch_stage.v new file mode 100644 index 0000000..bd72fe5 --- /dev/null +++ b/sources/hdl/verilog/fetch_stage.v @@ -0,0 +1,147 @@ +`include "parameters.vh" + +module fetch_stage( + // common signals + input clk, + input rst, + + // other control signals + output softmc_end, + output [11:0] read_size, + output reg read_seq_incoming, + input [11:0] buffer_space, + + // branch unit <-> fetch stage interface + input br_resolve, + input [`IMEM_ADDR_WIDTH-1:0] br_target, + + // fetch stage <-> frontend interface + output [`IMEM_ADDR_WIDTH-1:0] addr_out, + output valid_out, + input [`INSTR_WIDTH-1:0] data_in, + input valid_in, + input [`IMEM_ADDR_WIDTH-1:0] addr_in, + input ready_out, // frontend is ready for a valid request + + // fetch stage <-> decode stage interface + output [`INSTR_WIDTH-1:0] instr, + output [`IMEM_ADDR_WIDTH-1:0] instr_pc, + output instr_valid + ); + + wire inst_is_br, is_end, is_ddr_start, need_flush, is_sleep; + + reg [31:0] sleep_ctr_r, sleep_ctr_ns; + + localparam WAIT_RESOLVE_S = 0; + localparam FETCH_NEXT_LINE_S = 1; + localparam WAIT_BUFFER_SPACE_S = 2; + localparam WAIT_SLEEP_S = 3; + + reg [2:0] state_r, state_ns; + + // kind of confusing but these PCs map to + // an instruction instead of to a byte. + // i.e. each PC addresses an instruction. + reg [`IMEM_ADDR_WIDTH-1:0] pc_r, pc_ns; + + // register outputs, decode will receive + // stuff we've received with one cycle latency + // i.e. marks the end of fetch_stage cycle + reg [`IMEM_ADDR_WIDTH-1:0] instr_pc_r, instr_pc_ns; + reg [`INSTR_WIDTH-1:0] instr_r, instr_ns; + reg instr_valid_r, instr_valid_ns; + + pre_decode pdec( + .buffer_space(buffer_space), + .read_size(read_size), + .instruction(state_r == WAIT_BUFFER_SPACE_S ? instr_r : data_in), + .is_branch(inst_is_br), + .is_end(is_end), + .is_ddr_start(is_ddr_start), + .need_flush(need_flush), + .is_sleep(is_sleep) + ); + + assign instr = instr_r; + assign instr_valid = instr_valid_r; + assign instr_pc = instr_pc_r; + + // request instr @ pc from frontend + assign valid_out = ready_out && (state_r == FETCH_NEXT_LINE_S) && ~need_flush && ~(valid_in && is_sleep); + assign addr_out = pc_r; + + assign softmc_end = is_end && valid_in && (state_r == FETCH_NEXT_LINE_S); + + always @* begin + sleep_ctr_ns = sleep_ctr_r; + state_ns = state_r; + pc_ns = pc_r; + instr_ns = instr_r; + instr_pc_ns = instr_pc_r; + instr_valid_ns = ~is_end && valid_in && (state_r == FETCH_NEXT_LINE_S) + && ~is_ddr_start; + read_seq_incoming = `LOW; + case(state_r) + WAIT_RESOLVE_S: begin + if(br_resolve) begin + state_ns = FETCH_NEXT_LINE_S; + pc_ns = br_target; + end + end + FETCH_NEXT_LINE_S: begin + if(ready_out && valid_out) + pc_ns = pc_r + 1; + if(valid_in) begin + instr_ns = data_in; + instr_pc_ns = addr_in; + if(is_sleep) begin + sleep_ctr_ns = data_in[31:0]; + state_ns = WAIT_SLEEP_S; + end + if(is_ddr_start && ~need_flush && (|data_in[9:0])) + read_seq_incoming = `HIGH; + if(inst_is_br && ~is_sleep) // we don't have the ability to perform well + state_ns = WAIT_RESOLVE_S; + else if(is_end) + pc_ns = {`IMEM_ADDR_WIDTH{`LOW}}; + else if(need_flush) begin + state_ns = WAIT_BUFFER_SPACE_S; + pc_ns = addr_in; // register the info packet + // as the next instruction to fetch + end + end + end + WAIT_BUFFER_SPACE_S: begin + if(~need_flush) begin + state_ns = FETCH_NEXT_LINE_S; + end + end + WAIT_SLEEP_S: begin + sleep_ctr_ns = sleep_ctr_r - 1; + if(sleep_ctr_r == 32'b1) + state_ns = FETCH_NEXT_LINE_S; + end + endcase + end + + always @(posedge clk) begin + if (rst) begin + pc_r <= {`IMEM_ADDR_WIDTH{`LOW}}; + state_r <= FETCH_NEXT_LINE_S; + instr_valid_r <= `LOW; + instr_r <= {`INSTR_WIDTH{`LOW}}; + instr_pc_r <= {`IMEM_ADDR_WIDTH{`LOW}}; + sleep_ctr_r <= {32{`LOW}}; + end + else begin + state_r <= state_ns; + pc_r <= pc_ns; + instr_r <= instr_ns; + instr_pc_r <= instr_pc_ns; + instr_valid_r <= instr_valid_ns; + sleep_ctr_r <= sleep_ctr_ns; + end + end + +endmodule diff --git a/sources/hdl/verilog/frontend.v b/sources/hdl/verilog/frontend.v new file mode 100644 index 0000000..9225bd9 --- /dev/null +++ b/sources/hdl/verilog/frontend.v @@ -0,0 +1,237 @@ +`include "parameters.vh" +/* + * This module is responsible for the interface + * between XDMA IP and the fetch stage. + * This module encapsulates a X KiB BRAM which + * is used as an instruction memory. + */ +module frontend#(parameter SIM_MEM = "false")( + // common signals + input clk, + input rst, + + // other control signals + input softmc_fin, + output user_rst, + input init_calib_complete, + output reg rbe_switch_mode, + output reg dllt_begin, + output frontend_ready, + + // frontend <-> fetch stage interface + input [`IMEM_ADDR_WIDTH-1:0] addr_in, + input valid_in, + output [`INSTR_WIDTH-1:0] data_out, + output valid_out, + output [`IMEM_ADDR_WIDTH-1:0] addr_out, + output ready_in, + + // frontend <-> xdma interface + input [`XDMA_AXI_DATA_WIDTH-1:0] h2c_tdata_0, + input h2c_tlast_0, + input h2c_tvalid_0, + output h2c_tready_0, + input [`XDMA_AXI_DATA_WIDTH/8-1:0] h2c_tkeep_0, + + // maintenance signals + output per_rd_init, + output per_zq_init, + output per_ref_init + ); + + reg[31:0] delay_fin; + + always @(posedge clk) begin + if(rst || user_rst) + delay_fin <= 32'b0; + else + delay_fin[1+:31] <= delay_fin[0+:31]; + delay_fin[0] <= softmc_fin; + end + + assign frontend_ready = delay_fin[31]; + + wire imem_wr_en, imem_rd_en; + wire [`IMEM_ADDR_WIDTH-1:0] imem_addr; + wire [`INSTR_WIDTH-1:0] imem_wr_data, imem_rd_data; + + generate + if(SIM_MEM == "true") begin + instr_blk_mem_sim imem( + .addra(imem_addr), + .clka(clk), + .dina(imem_wr_data), + .douta(imem_rd_data), + .ena(imem_rd_en || imem_wr_en), + .wea(imem_wr_en) + ); + end + else begin + instr_blk_mem imem( + .addra(imem_addr), + .clka(clk), + .dina(imem_wr_data), + .douta(imem_rd_data), + .ena(imem_rd_en || imem_wr_en), + .wea(imem_wr_en) + ); + end + endgenerate + + wire [`INSTR_WIDTH-1:0] maint_inst; + wire maint_valid; + wire [`IMEM_ADDR_WIDTH-1:0] maint_addr; + wire maint_req; + reg maint_ack; + wire maint_process; + wire program_process; + reg aref_en; + reg aref_en_valid; + + maintenance_controller maint_ctrl + ( + .clk(clk), + .rst(rst | user_rst), + + .init_calib_complete(init_calib_complete), + .softmc_fin(softmc_fin), + + .aref_en(aref_en), + .aref_en_valid(aref_en_valid), + .maint_req(maint_req), + .maint_ack(maint_ack), + .per_rd_init(per_rd_init), + .per_zq_init(per_zq_init), + .per_ref_init(per_ref_init), + .maint_process(maint_process), + .program_process(program_process), + + .in_addr(addr_in), + .in_valid(valid_in), + + .out_data(maint_inst), + .out_valid(maint_valid), + .out_addr(maint_addr) + ); + + localparam IDLE_S = 2'd0; + localparam INIT_MEM_S = 2'd1; + localparam EXECUTE_S = 2'd2; + + reg [1:0] state_r, state_ns; + + reg [4:0] rst_ctr_ns, rst_ctr_r; + reg [`IMEM_ADDR_WIDTH-1:0] xfer_ctr_r, xfer_ctr_ns; + reg [`IMEM_RD_LATENCY-1:0] valid_out_sr; + reg [(`IMEM_RD_LATENCY * `IMEM_ADDR_WIDTH)-1:0] addr_out_sr; + + assign user_rst = (|rst_ctr_r); + + // imem <-> xdma interface + // TODO do we need tkeep? + assign h2c_tready_0 = state_r == INIT_MEM_S; + assign imem_wr_en = h2c_tvalid_0 && (state_r == INIT_MEM_S); + assign imem_wr_data = h2c_tdata_0[`INSTR_WIDTH-1:0]; + assign imem_addr = state_r == INIT_MEM_S ? xfer_ctr_r : addr_in; + // imem <-> pipeline interface + assign imem_rd_en = valid_in && (program_process); + assign data_out = program_process ? imem_rd_data : maint_inst; + assign valid_out = program_process ? valid_out_sr[0] : maint_valid; + assign addr_out = program_process ? addr_out_sr[`IMEM_ADDR_WIDTH-1:0] : maint_addr; + + generate + if(SIM_MEM=="false") + assign ready_in = state_r == EXECUTE_S; + else + assign ready_in = state_r == EXECUTE_S && ~rst; + endgenerate + assign program_process = (state_r == EXECUTE_S) && ~maint_process; + + always @* begin + aref_en_valid = `LOW; + aref_en = `LOW; + state_ns = state_r; + xfer_ctr_ns = xfer_ctr_r; + rst_ctr_ns = {5{`LOW}}; + maint_ack = `LOW; + rbe_switch_mode = `LOW; + dllt_begin = `LOW; + case (state_r) + IDLE_S: begin + if(~((|delay_fin) || softmc_fin)) begin + if(h2c_tvalid_0) + state_ns = INIT_MEM_S; + else begin + if(maint_req) begin + maint_ack = `HIGH; + state_ns = EXECUTE_S; + end + end + end + end + INIT_MEM_S: begin + if(h2c_tvalid_0) begin + if(h2c_tdata_0[`INSTR_WIDTH]) //indicates a reset + rst_ctr_ns = {5{1'b1}}; + else if(h2c_tdata_0[`INSTR_WIDTH+1]) // indicate switch between readback modes + rbe_switch_mode = `HIGH; + else if(h2c_tdata_0[`INSTR_WIDTH+2]) // indicate dll toggle off WIP + dllt_begin = `HIGH; + else if(h2c_tdata_0[`INSTR_WIDTH+3]) begin // enable-disable autoref + aref_en_valid = `HIGH; + aref_en = h2c_tdata_0[0]; + state_ns = IDLE_S; + end + else begin + xfer_ctr_ns = xfer_ctr_r + 1; + if(h2c_tlast_0) begin + state_ns = EXECUTE_S; + xfer_ctr_ns = {`IMEM_ADDR_WIDTH{`LOW}}; + end + end + end + end + EXECUTE_S: begin + if(h2c_tvalid_0) begin + if(h2c_tdata_0[`INSTR_WIDTH]) //indicates a reset + rst_ctr_ns = {5{1'b1}}; + end + if(softmc_fin) + state_ns = IDLE_S; + end + endcase + + end + + always @(posedge clk) begin + if(rst || (|rst_ctr_r)) begin + if(SIM_MEM == "false") + state_r <= IDLE_S; + else + state_r <= EXECUTE_S; + xfer_ctr_r <= {`IMEM_ADDR_WIDTH{`LOW}}; + valid_out_sr <= {`IMEM_RD_LATENCY{`LOW}}; + addr_out_sr <= 0; + if(rst_ctr_r > 0) + rst_ctr_r <= rst_ctr_r - 1; + else + rst_ctr_r <= 0; + end + else begin + state_r <= state_ns; + xfer_ctr_r <= xfer_ctr_ns; + rst_ctr_r <= rst_ctr_ns; + // compute when we should assert valid data to + // fetch stage. + valid_out_sr[`IMEM_RD_LATENCY-1] <= valid_in && (state_r == EXECUTE_S); + addr_out_sr[`IMEM_RD_LATENCY*`IMEM_ADDR_WIDTH-1 : + (`IMEM_RD_LATENCY-1)*`IMEM_ADDR_WIDTH] <= addr_in; + `ifdef IMEM_SR + valid_out_sr[`IMEM_RD_LATENCY-1:0] <= valid_out_sr >> 1; + addr_out_sr[(`IMEM_RD_LATENCY-1)*`IMEM_ADDR_WIDTH-1:0] + <= addr_out_sr >> `IMEM_ADDR_WIDTH; + `endif + end + end +endmodule + diff --git a/sources/hdl/verilog/maintenance_controller.v b/sources/hdl/verilog/maintenance_controller.v new file mode 100644 index 0000000..9354d17 --- /dev/null +++ b/sources/hdl/verilog/maintenance_controller.v @@ -0,0 +1,265 @@ +`include "parameters.vh" + +module maintenance_controller#(parameter tCK = 1500)( + + input clk, + input rst, + + input init_calib_complete, + input softmc_fin, + + input aref_en, + input aref_en_valid, + + input maint_ack, + output maint_req, + output per_rd_init, + output per_zq_init, + output per_ref_init, + output maint_process, + input program_process, + + input [`IMEM_ADDR_WIDTH-1:0] in_addr, + input in_valid, + + output [`INSTR_WIDTH-1:0] out_data, + output reg out_valid, + output [`IMEM_ADDR_WIDTH-1:0] out_addr + ); + + wire zq_ack, per_rd_ack, ref_ack; + reg zq_request, zq_process; + reg per_rd_request, per_rd_process; + reg pr_ref_request, pr_ref_process; + + wire [`INSTR_WIDTH-1 : 0] pr_read_out, pr_zq_out, pr_ref_out; + + assign maint_req = per_rd_request | zq_request | pr_ref_request; + assign out_addr = {`IMEM_ADDR_WIDTH{`HIGH}}; + assign out_data = zq_process ? pr_zq_out : per_rd_process ? pr_read_out : pr_ref_out; + assign per_ref_init = maint_ack && pr_ref_request && ~per_rd_request && ~zq_request; + assign per_rd_init = maint_ack && per_rd_request && ~zq_request; + assign per_zq_init = maint_ack && zq_request; + assign maint_process = zq_process || per_rd_process || pr_ref_process; + + assign zq_ack = softmc_fin && zq_process; + assign per_rd_ack = softmc_fin && per_rd_process; + assign ref_ack = softmc_fin && pr_ref_process; + + pr_read_mem prm + ( + .addra(in_addr[3:0]), + .clka(clk), + .douta(pr_read_out), + .dina(64'bX), + .wea(`LOW), + .ena(in_valid && per_rd_process) + ); + + zq_calib_mem pzm + ( + .addra(in_addr[5:0]), + .clka(clk), + .douta(pr_zq_out), + .dina(64'bX), + .wea(`LOW), + .ena(in_valid && zq_process) + ); + + pr_ref_mem prefm + ( + .addra(in_addr[6:0]), + .clka(clk), + .douta(pr_ref_out), + .dina(64'bX), + .wea(`LOW), + .ena(in_valid && pr_ref_process) + ); + + always @(posedge clk) begin + if(rst) begin + zq_process <= `LOW; + per_rd_process <= `LOW; + out_valid <= `LOW; + pr_ref_process <= `LOW; + end + else begin + if(softmc_fin) begin + if(zq_process) + zq_process <= `LOW; + if(per_rd_process) + per_rd_process <= `LOW; + if(pr_ref_process) + pr_ref_process <= `LOW; + out_valid <= `LOW; + end + else if(maint_ack) begin + if(zq_request) + zq_process <= `HIGH; + else if(per_rd_request) + per_rd_process <= `HIGH; + else if(pr_ref_request) + pr_ref_process <= `HIGH; + out_valid <= `LOW; + end + else begin + zq_process <= zq_process; + per_rd_process <= per_rd_process; + pr_ref_process <= pr_ref_process; + if(maint_process) + out_valid <= in_valid; + else + out_valid <= `LOW; + end + end + end + + // Maintenance control logic + // Set request bits according to timers + + localparam MAINT_PRESCALER_PERIOD = 500_000; // .5 us + + function integer clogb2 (input integer size); // ceiling logb2 + begin + size = size - 1; + for (clogb2=1; size>1; clogb2=clogb2+1) + size = size >> 1; + end + endfunction // clogb2 + + localparam MAINT_PRESCALER_DIV = MAINT_PRESCALER_PERIOD/(tCK * 4); // softmc is clocked 4 times slower than the memory interface + localparam MAINT_PRESCALER_WIDTH = clogb2(MAINT_PRESCALER_DIV + 1); + localparam ONE = 1; + + reg maint_prescaler_tick_r_lcl; + reg [MAINT_PRESCALER_WIDTH-1:0] maint_prescaler_r; + reg [MAINT_PRESCALER_WIDTH-1:0] maint_prescaler_ns; + + wire maint_prescaler_tick_ns = (maint_prescaler_r == ONE[MAINT_PRESCALER_WIDTH-1:0]); + + always @(/*AS*/init_calib_complete or maint_prescaler_r + or maint_prescaler_tick_ns) begin + maint_prescaler_ns = maint_prescaler_r; + if (~init_calib_complete || maint_prescaler_tick_ns) + maint_prescaler_ns = MAINT_PRESCALER_DIV[MAINT_PRESCALER_WIDTH-1:0]; + else if (|maint_prescaler_r) + maint_prescaler_ns = maint_prescaler_r - ONE[MAINT_PRESCALER_WIDTH-1:0]; + end + + always @(posedge clk) maint_prescaler_r <= maint_prescaler_ns; + + always @(posedge clk) maint_prescaler_tick_r_lcl <= maint_prescaler_tick_ns; + + localparam tPRDI = 1_000_000; + localparam PERIODIC_RD_TIMER_DIV = tPRDI/MAINT_PRESCALER_PERIOD; + localparam PERIODIC_RD_TIMER_WIDTH = clogb2(PERIODIC_RD_TIMER_DIV + /*idle state*/ 1); + + reg [PERIODIC_RD_TIMER_WIDTH-1:0] periodic_rd_timer_r, periodic_rd_timer; + + always @* begin + periodic_rd_timer = periodic_rd_timer_r; + + if(~init_calib_complete) begin + periodic_rd_timer = {PERIODIC_RD_TIMER_WIDTH{1'b0}}; + end + else if (per_rd_ack || program_process) begin + periodic_rd_timer = PERIODIC_RD_TIMER_DIV[0+:PERIODIC_RD_TIMER_WIDTH]; + end + else if (|periodic_rd_timer_r && maint_prescaler_tick_r_lcl) begin + periodic_rd_timer = periodic_rd_timer_r - ONE[0+:PERIODIC_RD_TIMER_WIDTH]; + end + end //always + + wire periodic_rd_timer_one = maint_prescaler_tick_r_lcl && (periodic_rd_timer_r == ONE[0+:PERIODIC_RD_TIMER_WIDTH]); + + wire periodic_rd_request = ~rst && (/*((PERIODIC_RD_TIMER_DIV != 0) && ~dfi_init_complete) ||*/ + (~per_rd_ack && (per_rd_request || periodic_rd_timer_one))); + + always @(posedge clk) begin + if(~init_calib_complete) + periodic_rd_timer_r <= PERIODIC_RD_TIMER_DIV[0+:PERIODIC_RD_TIMER_WIDTH]; + else + periodic_rd_timer_r <= periodic_rd_timer; + per_rd_request <= periodic_rd_request; + end //always + + // ZQ timebase. Nominally 128 mS + localparam MAINT_PRESCALER_PERIOD_NS = MAINT_PRESCALER_PERIOD / 1000; + localparam tZQI = 128_000_000; + localparam ZQ_TIMER_DIV = tZQI/MAINT_PRESCALER_PERIOD_NS; + localparam ZQ_TIMER_WIDTH = clogb2(ZQ_TIMER_DIV + 1); + + generate + begin : zq_cntrl + reg zq_tick = 1'b0; + + if (ZQ_TIMER_DIV !=0) begin : zq_timer + reg [ZQ_TIMER_WIDTH-1:0] zq_timer_r; + reg [ZQ_TIMER_WIDTH-1:0] zq_timer_ns; + + always @(/*AS*/init_calib_complete or maint_prescaler_tick_r_lcl or zq_tick or zq_timer_r or program_process) begin + zq_timer_ns = zq_timer_r; + if (~init_calib_complete || zq_tick || program_process) + zq_timer_ns = ZQ_TIMER_DIV[ZQ_TIMER_WIDTH-1:0]; + else if (|zq_timer_r && maint_prescaler_tick_r_lcl) + zq_timer_ns = zq_timer_r - ONE[ZQ_TIMER_WIDTH-1:0]; + end + + always @(posedge clk) zq_timer_r <= zq_timer_ns; + + always @(/*AS*/maint_prescaler_tick_r_lcl or zq_timer_r) + zq_tick = (zq_timer_r == ONE[ZQ_TIMER_WIDTH-1:0] && maint_prescaler_tick_r_lcl); + end // zq_timer + + // ZQ request. Set request with timer tick, and when exiting PHY init. Never + // request if ZQ_TIMER_DIV == 0. + begin : zq_request_logic + wire zq_clear = zq_ack; + reg zq_request_r; + wire zq_request_ns = ~rst && ((~init_calib_complete && (ZQ_TIMER_DIV != 0)) || + (zq_request_r && ~zq_clear) || zq_tick); + + always @(posedge clk) zq_request_r <= zq_request_ns; + + always @(/*AS*/init_calib_complete or zq_request_r) + zq_request = init_calib_complete && zq_request_r; + end // zq_request_logic + end + endgenerate + + localparam tAREF = 7_800; + localparam PERIODIC_REF_TIMER_DIV = tAREF/MAINT_PRESCALER_PERIOD_NS; + localparam PERIODIC_REF_TIMER_WIDTH = clogb2(PERIODIC_REF_TIMER_DIV + /*idle state*/ 1); + + reg [PERIODIC_REF_TIMER_WIDTH-1:0] autoref_timer_r, autoref_timer; + reg aref_switch_ns, aref_switch_r; + + always @* begin + aref_switch_ns = aref_en_valid ? aref_en : aref_switch_r; + pr_ref_request = `LOW; + autoref_timer = autoref_timer_r; + if(~aref_switch_r || ~init_calib_complete) + autoref_timer = PERIODIC_REF_TIMER_DIV[PERIODIC_REF_TIMER_WIDTH-1:0]; + else begin + if(autoref_timer_r > 1 && maint_prescaler_tick_r_lcl) // you were here + autoref_timer = autoref_timer_r - ONE[PERIODIC_REF_TIMER_WIDTH-1:0]; + else if(autoref_timer_r == 1) begin + pr_ref_request = `HIGH; + if(ref_ack) + autoref_timer = PERIODIC_REF_TIMER_DIV[PERIODIC_REF_TIMER_WIDTH-1:0]; + end + end + end + + always @(posedge clk) begin + if(rst) begin + aref_switch_r <= `LOW; + autoref_timer_r = PERIODIC_REF_TIMER_DIV[PERIODIC_REF_TIMER_WIDTH-1:0]; + end + else begin + aref_switch_r <= aref_switch_ns; + autoref_timer_r <= autoref_timer; + end + end + +endmodule diff --git a/sources/hdl/verilog/pop_count4.v b/sources/hdl/verilog/pop_count4.v new file mode 100644 index 0000000..80bea46 --- /dev/null +++ b/sources/hdl/verilog/pop_count4.v @@ -0,0 +1,68 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 12/19/2018 10:51:52 AM +// Design Name: +// Module Name: pop_count4 +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module pop_count4( + input [3:0] in, + output [2:0] out + ); + + reg [2:0] out_r; + + always @* begin + out_r = 3'd0; + case(in) + 4'b0000: + out_r = 3'd0; + 4'b0001: + out_r = 3'd1; + 4'b0010: + out_r = 3'd1; + 4'b0011: + out_r = 3'd2; + 4'b0100: + out_r = 3'd1; + 4'b0101: + out_r = 3'd2; + 4'b0110: + out_r = 3'd2; + 4'b0111: + out_r = 3'd3; + 4'b1000: + out_r = 3'd1; + 4'b1001: + out_r = 3'd2; + 4'b1010: + out_r = 3'd2; + 4'b1011: + out_r = 3'd3; + 4'b1100: + out_r = 3'd2; + 4'b1101: + out_r = 3'd3; + 4'b1111: + out_r = 3'd4; + endcase + end + + assign out = out_r; + +endmodule diff --git a/sources/hdl/verilog/pre_decode.v b/sources/hdl/verilog/pre_decode.v new file mode 100644 index 0000000..7621b24 --- /dev/null +++ b/sources/hdl/verilog/pre_decode.v @@ -0,0 +1,39 @@ +`include "parameters.vh" +`include "encoding.vh" + +/* + * This combinational logic will output + * whether or not an instruction is a branch + * or not, for now. + */ +module pre_decode( + input [`INSTR_WIDTH-1:0] instruction, + // available readback_fifo entries in terms of read count + input [11:0] buffer_space, + output [11:0] read_size, + output is_branch, + output is_end, + output is_ddr_start, + output need_flush, + output is_sleep + ); + + // When an instruction is non_ddr and has + // is_branch flag set + assign is_branch = instruction[`BRANCH_OFFSET] + && ~instruction[`DDR_OFFSET]; + + assign is_end = &(~instruction); + + // encountered a ddr command segments + assign is_ddr_start = instruction[`INFO_OFFSET] + && ~instruction[`DDR_OFFSET]; + + assign read_size = instruction[9:0]; + // if there are more reads than we can buffer + assign need_flush = is_ddr_start && (read_size > buffer_space); + + assign is_sleep = instruction[`BRANCH_OFFSET] && + instruction[`FU_CODE_OFFSET +: 8] == `SLEEP; + +endmodule diff --git a/sources/hdl/verilog/readback_engine.v b/sources/hdl/verilog/readback_engine.v new file mode 100644 index 0000000..496d83e --- /dev/null +++ b/sources/hdl/verilog/readback_engine.v @@ -0,0 +1,244 @@ +`include "parameters.vh" + +// Process data coming from DRAM before sending it to the host. +module readback_engine( + + // common signals + input clk, + input rst, + + // other control signals + input flush, + input read_seq_incoming, // next few instructions will read from DRAM + input [11:0] incoming_reads, // how many reads next few instructions will issue + output[11:0] buffer_space, // remaining buffer size + input switch_mode, + + // DRAM <-> engine if + input [511:0] rd_data, + input rd_valid, + + input per_rd_init, + input per_zq_init, + input per_ref_init, + + // engine <-> regfile if + input [511:0] ddr_wdata, // to compare read data against + + // readback <-> XDMA if + output [`XDMA_AXI_DATA_WIDTH-1:0] c2h_tdata_0, + output c2h_tlast_0, + output c2h_tvalid_0, + input c2h_tready_0, + output [`XDMA_AXI_DATA_WIDTH/8-1:0] c2h_tkeep_0 + + ); + + + localparam READ_MODE = 0; + localparam DIFF_MODE = 1; + reg mode_r, mode_ns; // Switch between diff count and read modes + + reg rd_valid_r; + reg ignore_read_r, ignore_read_ns; + reg ignore_flush_r, ignore_flush_ns; + + // Popcount computation part + reg[511:0] read_diff; + reg diff_valid; + always @(posedge clk) begin + if(rst) begin + read_diff <= 512'bX; + diff_valid <= `LOW; + end + read_diff <= rd_valid ? rd_data ^ ddr_wdata : read_diff; + diff_valid <= rd_valid && ~ignore_read_r && mode_r == DIFF_MODE ? `HIGH : `LOW; + end + + genvar pcs; // popcount modules + + wire[2:0] pc_out [127:0]; + reg[3:0] pc_out_l2 [63:0]; + reg[4:0] pc_out_l3 [31:0]; + reg[5:0] pc_out_l4 [15:0]; + reg[6:0] pc_out_l5 [7:0]; + reg[7:0] pc_out_l6 [3:0]; + reg[8:0] pc_out_l7 [1:0]; + reg[15:0] pop_count_value; + reg pop_count_valid; + + generate + for(pcs = 0 ; pcs < 128 ; pcs = pcs + 1) begin: gen_pcs + pop_count4 pci + ( + .in(read_diff[pcs*4 +: 4]), + .out(pc_out[pcs]) + ); + end + endgenerate + + integer l1, l2, l3, l4, l5, l6; + always @* begin + for(l1 = 0 ; l1 < 64 ; l1 = l1+1) + pc_out_l2[l1] = pc_out[2*l1] + pc_out[2*l1+1]; + for(l2 = 0 ; l2 < 32 ; l2 = l2+1) + pc_out_l3[l2] = pc_out_l2[2*l2] + pc_out_l2[2*l2+1]; + for(l3 = 0 ; l3 < 16 ; l3 = l3+1) + pc_out_l4[l3] = pc_out_l3[2*l3] + pc_out_l3[2*l3+1]; + for(l4 = 0 ; l4 < 8 ; l4 = l4+1) + pc_out_l5[l4] = pc_out_l4[2*l4] + pc_out_l4[2*l4+1]; + for(l5 = 0 ; l5 < 4 ; l5 = l5+1) + pc_out_l6[l5] = pc_out_l5[2*l5] + pc_out_l5[2*l5+1]; + for(l6 = 0 ; l6 < 2 ; l6 = l6+1) + pc_out_l7[l6] = pc_out_l6[2*l6] + pc_out_l6[2*l6+1]; + end + + always @(posedge clk) begin + if(rst) begin + pop_count_value <= 16'bX; + pop_count_valid <= `LOW; + end + else begin + pop_count_value <= diff_valid ? pc_out_l7[0] + pc_out_l7[1] : pop_count_value; + pop_count_valid <= diff_valid ? `HIGH : `LOW; + end + end + + wire[511:0] dsr_out; + wire dsr_valid; + // We put popcounted data into a shift register + // to fill up 512 bit I/O fifo. + diff_shift_reg dsr( + .clk(clk), + .rst(rst), + + .in(pop_count_value), + .in_valid(pop_count_valid), + + .flush(flush&~ignore_flush_r), + + .out(dsr_out), + .out_valid(dsr_valid) + ); + // End popcount computation part + + // Count up to 1024 32-byte transfers + reg[9:0] xctr_r; + + reg tlast; // indicating c2h's last transfer + + // We read DQ_WIDTH*DQ_BURST (512 as of now) bits + // from DRAM, and have to pipe 256 bit partitions of + // it to the PCI. We may read data each cycle from + // DRAM and have to buffer some of those. + wire rbf_empty, rbf_rd_valid, fifo_almost_full, fifo_valid; + (*KEEP = "TRUE"*) wire rbf_full; + (*KEEP = "TRUE"*) reg [19:0] dbg_rd_ctr; + rdback_fifo rbf( + .full(rbf_full), + .prog_full(fifo_almost_full), + .empty(rbf_empty), + .wr_en(mode_r == READ_MODE ? rd_valid && ~ignore_read_r: dsr_valid), + // shuffle data because fifo outputs them on wrong order + .din(mode_r == READ_MODE ? {rd_data[255:0],rd_data[511:256]} : {dsr_out[255:0],dsr_out[511:256]}), + .rd_en(c2h_tready_0), + .dout(c2h_tdata_0), + .valid(fifo_valid), + .clk(clk), + .srst(rst) + ); + + reg proc_flush_ns, proc_flush_r; + // we count the remaining space in terms of + // AXI transactions + // e.g. 1024 reads will take up 2048 + reg [11:0] buffer_space_ns, buffer_space_r; + + always @* begin + tlast = `LOW; + ignore_read_ns = ignore_read_r; + ignore_flush_ns = ignore_flush_r; + buffer_space_ns = buffer_space_r; + if(per_rd_init || per_zq_init || per_ref_init) begin + ignore_read_ns = per_rd_init; + ignore_flush_ns = `HIGH; + end + if(rd_valid_r) + ignore_read_ns = `LOW; + proc_flush_ns = proc_flush_r; + if(flush) begin + if(ignore_flush_r) + ignore_flush_ns = `LOW; + else + proc_flush_ns = `HIGH; + end + mode_ns = mode_r; + if(switch_mode) + mode_ns = ~mode_r; + if(&xctr_r && (c2h_tready_0 && c2h_tvalid_0)) begin + tlast = `HIGH; + end + // Send what's remaining in the fifo + // to host with a random length transfer + // (tlast is not based on the counter value) + if(proc_flush_r) begin + if(c2h_tready_0 && rbf_empty && ~dsr_valid) begin + tlast = `HIGH; + proc_flush_ns = `LOW; + end + else + proc_flush_ns = `HIGH; + end + if(read_seq_incoming) begin + if(c2h_tvalid_0 && c2h_tready_0) begin + buffer_space_ns = (buffer_space_r - (incoming_reads << 1)) + 1; + end + else begin + buffer_space_ns = (buffer_space_r - (incoming_reads << 1)); + end + end + else begin + if(c2h_tvalid_0 && c2h_tready_0) begin + if(~(proc_flush_r && rbf_empty && ~dsr_valid)) + buffer_space_ns = buffer_space_r + 1; + end + end + end + + always @(posedge clk) begin + if(rst) begin + dbg_rd_ctr <= 20'b0; + xctr_r <= 15'b0; + proc_flush_r <= `LOW; + mode_r <= READ_MODE; + ignore_read_r <= 1'b0; + ignore_flush_r <= 1'b0; + rd_valid_r <= 1'b0; + buffer_space_r <= 12'd2048; + end + else begin + if(rd_valid && ~ignore_read_r && ~rbf_full) + dbg_rd_ctr <= dbg_rd_ctr + 1'b1; + else + dbg_rd_ctr <= dbg_rd_ctr; + buffer_space_r <= buffer_space_ns; + mode_r <= mode_ns; + rd_valid_r <= rd_valid; + ignore_read_r <= ignore_read_ns; + ignore_flush_r <= ignore_flush_ns; + if(proc_flush_r && tlast) + xctr_r <= 15'b0; + else if(c2h_tready_0 && c2h_tvalid_0) begin + xctr_r <= xctr_r + 1; + end + proc_flush_r <= proc_flush_ns; + end + end + + assign c2h_tkeep_0 = {(`XDMA_AXI_DATA_WIDTH/8){1'b1}}; + assign c2h_tlast_0 = tlast; + assign c2h_tvalid_0 = proc_flush_r && rbf_empty && ~dsr_valid ? `HIGH : fifo_valid; + + assign buffer_space = buffer_space_r >> 1; + +endmodule diff --git a/sources/hdl/verilog/reg_mem.v b/sources/hdl/verilog/reg_mem.v new file mode 100644 index 0000000..a8d37cd --- /dev/null +++ b/sources/hdl/verilog/reg_mem.v @@ -0,0 +1,33 @@ +`timescale 1ns / 1ps + +module reg_mem( + input [9:0] addr, + input clk, + input [31:0] din, + output [31:0] dout, + input en, + input we + ); + + reg [31:0] mem [1023:0]; + + integer i; + initial + begin + for(i=0; i<1024; i=i+1) + mem[i]=0; + end + + reg [31:0] out; + + assign dout=out; + + always @(posedge clk) + begin + if(we) + mem[addr]<=din; + else if(en) + out<=mem[addr]; + end + +endmodule diff --git a/sources/hdl/verilog/register_file.v b/sources/hdl/verilog/register_file.v new file mode 100644 index 0000000..2d3b693 --- /dev/null +++ b/sources/hdl/verilog/register_file.v @@ -0,0 +1,92 @@ +`include "parameters.vh" + +/* + * An 8 read 8 write port reg file + * satisfying ddr pipeline's needs + */ +module register_file( + + // common signals + input clk, + input rst, + + // execute stage <-> reg file if + input rf_wide_wen, + input [3:0] rf_wide_offset, + output [511:0] rf_wide_data, + output [32*8-1:0] rf_rdata, + input [32*8-1:0] rf_wdata, + input [7:0] rf_wen, + input [4*8-1:0] rf_raddr, + input [4*8-1:0] rf_waddr, + output [`COL_WIDTH-1:0] casr, + output [`BANK_WIDTH+`BG_WIDTH-1:0] basr, + output [`ROW_WIDTH-1:0] rasr, + // update stride registers, wen is OH (3'b001 = update rasr) + input [31:0] srf_value, + input [2:0] srf_wen + ); + + // Stride registers + reg [31:0] casr_r, basr_r, rasr_r; + + assign casr = casr_r; + assign basr = basr_r; + assign rasr = rasr_r; + + // Update stride registers + always @(posedge clk) begin + if(srf_wen[0]) begin + casr_r <= srf_value; + end + if(srf_wen[1]) begin + basr_r <= srf_value; + end + if(srf_wen[2]) begin + rasr_r <= srf_value; + end + end + + // General purpose registers + reg [31:0] reg_file [15:0]; + + // split r&w data signals into human readable form + // also drive rdata with appropriate register values + wire [31:0] wdata [7:0]; + wire wen [7:0]; + wire [3:0] waddr [7:0]; + wire [3:0] raddr [7:0]; + genvar i; + generate + for(i = 0 ; i < 8 ; i = i + 1) begin: gen_ports + assign wdata[i] = rf_wdata[32*i +: 32]; + assign wen[i] = rf_wen[i]; + assign waddr[i] = rf_waddr[4*i +: 4]; + assign raddr[i] = rf_raddr[4*i +: 4]; + // TODO will this compile? + assign rf_rdata[32*i +: 32] = raddr[i] == 0 ? casr_r : + raddr[i] == 1 ? basr_r : + raddr[i] == 2 ? rasr_r : reg_file[raddr[i]]; + end + endgenerate + + integer j; + // Write to the register file + always @(posedge clk) begin + for(j = 0 ; j < 8 ; j = j+1) begin: regfile_write + if(wen[j]) + reg_file[waddr[j]] <= wdata[j]; + end + end + + // DDR4 8-burst write data register + reg [511:0] wide_reg; + always @(posedge clk) begin + // TODO this probably won't compile + if(rf_wide_wen) + wide_reg[rf_wide_offset*32 +: 32] <= wdata[0]; + end + + assign rf_wide_data = wide_reg; + +endmodule diff --git a/sources/hdl/verilog/softmc_pipeline.v b/sources/hdl/verilog/softmc_pipeline.v new file mode 100644 index 0000000..07c106e --- /dev/null +++ b/sources/hdl/verilog/softmc_pipeline.v @@ -0,0 +1,178 @@ +`include "parameters.vh" + +module softmc_pipeline( + + // common signals + input clk, + input rst, + + // readback <-> fetch_stage backpressure + + output softmc_end, + output [11:0] read_size, + output read_seq_incoming, + input [11:0] buffer_space, + + // frontend <-> fetch stage interface + output [`IMEM_ADDR_WIDTH-1:0] addr_out, + output valid_out, + input [`INSTR_WIDTH-1:0] data_in, + input valid_in, + input [`IMEM_ADDR_WIDTH-1:0] addr_in, + input ready_out, + + // ddr_pipeline <-> outer DDR module + output [3:0] ddr_write, + output [3:0] ddr_read, + output [3:0] ddr_pre, + output [3:0] ddr_act, + output [3:0] ddr_ref, + output [3:0] ddr_sre, + output [3:0] ddr_srx, + output [3:0] ddr_zq, + output [3:0] ddr_nop, + output [3:0] ddr_ap, + output [3:0] ddr_pall, + output [3:0] ddr_half_bl, + output [4*`BG_WIDTH-1:0] ddr_bg, + output [4*`BANK_WIDTH-1:0] ddr_bank, + output [4*`COL_WIDTH-1:0] ddr_col, + output [4*`ROW_WIDTH-1:0] ddr_row, + output [511:0] ddr_wdata + ); + + wire br_resolve; + wire [`IMEM_ADDR_WIDTH-1:0] br_target; + + wire [`INSTR_WIDTH-1:0] dec_instr; + wire dec_instr_valid; + wire [`IMEM_ADDR_WIDTH-1:0] dec_instr_pc; + + fetch_stage fs( + .clk(clk), + .rst(rst), + + .softmc_end(softmc_end), + .read_size(read_size), + .read_seq_incoming(read_seq_incoming), + .buffer_space(buffer_space), + + + .addr_out(addr_out), + .valid_out(valid_out), + .data_in(data_in), + .valid_in(valid_in), + .addr_in(addr_in), + .ready_out(ready_out), + + .br_resolve(br_resolve), + .br_target(br_target), + + .instr(dec_instr), + .instr_pc(dec_instr_pc), + .instr_valid(dec_instr_valid) + ); + + wire ddr_valid, exe_valid; + wire [`DDR_UOP_WIDTH*4-1:0] ddr_uop; + wire [`EXE_UOP_WIDTH-1:0] exe_uop; + wire [`IMEM_ADDR_WIDTH-1:0] exe_pc; + wire [32*7-1:0] ddr_stat; + + decode_stage ds( + .clk(clk), + .rst(rst), + + .instr(dec_instr), + .instr_pc(dec_instr_pc), + .instr_valid(dec_instr_valid), + + .ddr_valid(ddr_valid), + .exe_valid(exe_valid), + .ddr_uop(ddr_uop), + .exe_uop(exe_uop), + .exe_pc(exe_pc), + .ddr_stat(ddr_stat) + ); + + wire rf_wide_wen; + wire [3:0] rf_wide_offset; + wire [511:0] rf_wide_data; + wire [32*8-1:0] rf_rdata; + wire [32*8-1:0] rf_wdata; + wire [7:0] rf_wen; + wire [4*8-1:0] rf_raddr; + wire [4*8-1:0] rf_waddr; + wire [`COL_WIDTH-1:0] casr; + wire [`BANK_WIDTH+`BG_WIDTH-1:0] basr; + wire [`ROW_WIDTH-1:0] rasr; + wire [31:0] srf_value; + wire [2:0] srf_wen; + + execute_stage es( + .clk(clk), + .rst(rst), + + .br_resolve(br_resolve), + .br_target(br_target), + + .ddr_valid(ddr_valid), + .exe_valid(exe_valid), + .ddr_uop(ddr_uop), + .exe_uop(exe_uop), + .exe_pc(exe_pc), + + .rf_wide_wen(rf_wide_wen), + .rf_wide_offset(rf_wide_offset), + .wide_reg(rf_wide_data), + .rf_rdata(rf_rdata), + .rf_wdata(rf_wdata), + .rf_wen(rf_wen), + .rf_raddr(rf_raddr), + .rf_waddr(rf_waddr), + .casr(casr), + .basr(basr), + .rasr(rasr), + .srf_value(srf_value), + .srf_wen(srf_wen), + .ddr_stat(ddr_stat), + + .ddr_write(ddr_write), + .ddr_read(ddr_read), + .ddr_pre(ddr_pre), + .ddr_act(ddr_act), + .ddr_ref(ddr_ref), + .ddr_sre(ddr_sre), + .ddr_srx(ddr_srx), + .ddr_zq(ddr_zq), + .ddr_nop(ddr_nop), + .ddr_ap(ddr_ap), + .ddr_pall(ddr_pall), + .ddr_half_bl(ddr_half_bl), + .ddr_bg(ddr_bg), + .ddr_bank(ddr_bank), + .ddr_col(ddr_col), + .ddr_row(ddr_row), + .ddr_wdata(ddr_wdata) + ); + + register_file rf( + .clk(clk), + .rst(rst), + + .rf_wide_wen(rf_wide_wen), + .rf_wide_offset(rf_wide_offset), + .rf_wide_data(rf_wide_data), + .rf_rdata(rf_rdata), + .rf_wdata(rf_wdata), + .rf_wen(rf_wen), + .rf_raddr(rf_raddr), + .rf_waddr(rf_waddr), + .casr(casr), + .basr(basr), + .rasr(rasr), + .srf_value(srf_value), + .srf_wen(srf_wen) + ); + +endmodule diff --git a/sources/hdl/verilog/softmc_top.v b/sources/hdl/verilog/softmc_top.v new file mode 100644 index 0000000..c5b1c76 --- /dev/null +++ b/sources/hdl/verilog/softmc_top.v @@ -0,0 +1,838 @@ +`include "parameters.vh" +`include "project.vh" + +`ifdef XUPP3R_x4 + `define XUPP3R +`elsif XUPP3R_x8 + `define XUPP3R +`elsif XUPP3R_x8_1R_UDIMM + `define XUPP3R +`endif + + +module softmc_top #(parameter tCK = 1500, SIM = "false") + ( + // common signals + input c0_sys_clk_p, + input c0_sys_clk_n, + input sys_rst_l, + + // iob <> ddr4 sdram ip signals + output c0_ddr4_act_n, + output [16:0] c0_ddr4_adr, + output [1:0] c0_ddr4_ba, + output [1:0] c0_ddr4_bg, + output [`CKE_WIDTH-1:0] c0_ddr4_cke, + output [`ODT_WIDTH-1:0] c0_ddr4_odt, + output [`CS_WIDTH-1:0] c0_ddr4_cs_n, + output [`CK_WIDTH-1:0] c0_ddr4_ck_t, + output [`CK_WIDTH-1:0] c0_ddr4_ck_c, + output c0_ddr4_reset_n, + `ifdef XUPP3R_x4 + inout [17:0] c0_ddr4_dqs_c, + inout [17:0] c0_ddr4_dqs_t, + inout [71:0] c0_ddr4_dq, + output c0_ddr4_parity, + `elsif XUPP3R_x8 + inout [8:0] c0_ddr4_dm_dbi_n, + inout [71:0] c0_ddr4_dq, + inout [8:0] c0_ddr4_dqs_c, + inout [8:0] c0_ddr4_dqs_t, + output c0_ddr4_parity, + `else + inout [7:0] c0_ddr4_dm_dbi_n, + inout [63:0] c0_ddr4_dq, + inout [7:0] c0_ddr4_dqs_c, + inout [7:0] c0_ddr4_dqs_t, + `endif + // xdma signals + input clk_ref_p, + input clk_ref_n, + input pcie_rst, + output [7:0] pci_exp_txp, + output [7:0] pci_exp_txn, + input [7:0] pci_exp_rxp, + input [7:0] pci_exp_rxn + + ); + + // Frontend control signals + wire softmc_fin; + wire user_rst; + + // Frontend <-> Fetch signals + wire [`IMEM_ADDR_WIDTH-1:0] fr_addr_in; + wire fr_valid_in; + wire [`INSTR_WIDTH-1:0] fr_data_out; + wire fr_valid_out; + wire [`IMEM_ADDR_WIDTH-1:0] fr_addr_out; + wire fr_ready_out; + + // Frontend <-> misc. control signals + wire per_rd_init; + wire per_zq_init; + wire per_ref_init; + wire rbe_switch_mode; + wire toggle_dll; + + // AXI streaming ports + wire [`XDMA_AXI_DATA_WIDTH-1:0] m_axis_h2c_tdata_0,xdma_h2c_tdata_0; + wire m_axis_h2c_tlast_0, xdma_h2c_tlast_0; + wire m_axis_h2c_tvalid_0, xdma_h2c_tvalid_0; + wire m_axis_h2c_tready_0, xdma_h2c_tready_0; + wire [`XDMA_AXI_DATA_WIDTH/8-1:0] m_axis_h2c_tkeep_0, xdma_h2c_tkeep_0; + wire [`XDMA_AXI_DATA_WIDTH-1:0] s_axis_c2h_tdata_0, xdma_c2h_tdata_0; + wire s_axis_c2h_tlast_0, xdma_c2h_tlast_0; + wire s_axis_c2h_tvalid_0, xdma_c2h_tvalid_0; + wire s_axis_c2h_tready_0, xdma_c2h_tready_0; + wire [`XDMA_AXI_DATA_WIDTH/8-1:0] s_axis_c2h_tkeep_0, xdma_c2h_tkeep_0; + + // ddr_pipeline <-> outer module if + wire [3:0] ddr_write; + wire [3:0] ddr_read; + wire [3:0] ddr_pre; + wire [3:0] ddr_act; + wire [3:0] ddr_ref; + wire [3:0] ddr_sre; + wire [3:0] ddr_srx; + wire [3:0] ddr_zq; + wire [3:0] ddr_nop; + wire [3:0] ddr_ap; + wire [3:0] ddr_pall; + wire [3:0] ddr_half_bl; + wire [4*`BG_WIDTH-1:0] ddr_bg; + wire [4*`BANK_WIDTH-1:0] ddr_bank; + wire [4*`COL_WIDTH-1:0] ddr_col; + wire [4*`ROW_WIDTH-1:0] ddr_row; + wire [511:0] ddr_wdata; + + // periodic maintenance signals + wire ddr_maint_read; + + // phy <-> ddr adapter and xdma app signals + // dlltoggler + wire clk_sel = 0; + wire [7:0] dllt_mc_ACT_n; + wire [135:0] dllt_mc_ADR; + wire [15:0] dllt_mc_BA; + wire [15:0] dllt_mc_BG; + wire [7:0] dllt_mc_CKE; + wire [7:0] dllt_mc_CS_n; + wire dllt_done; + // ddr adapter + wire [4:0] dBufAdr; + wire [`DQ_WIDTH*8-1:0] wrData; + wire [`DQ_WIDTH-1:0] wrDataMask; + wire [511:0] rdData; + wire [4:0] rdDataAddr; + wire [0:0] rdDataEn; + wire [0:0] rdDataEnd; + wire [0:0] per_rd_done; + wire [0:0] rmw_rd_done; + wire [4:0] wrDataAddr; + wire [0:0] wrDataEn; + wire [7:0] mc_ACT_n; + wire [135:0] mc_ADR; + wire [15:0] mc_BA; + wire [15:0] mc_BG; + wire [`CKE_WIDTH*8-1:0] mc_CKE; + wire [`CS_WIDTH*8-1:0] mc_CS_n; + wire [`ODT_WIDTH*8-1:0] mc_ODT; + wire [0:0] mcRdCAS; + wire [0:0] mcWrCAS; + wire [0:0] winInjTxn; + wire [0:0] winRmw; + wire [4:0] winBuf; + wire [1:0] winRank; + wire [5:0] tCWL; + wire dbg_clk; + wire c0_wr_rd_complete; + wire c0_ddr4_clk; + wire c0_ddr4_dll_off_clk; + wire ddr4_ui_clk; + wire c0_ddr4_rst; + wire [511:0] dbg_bus; + wire [1:0] mcCasSlot; + wire mcCasSlot2; + wire gt_data_ready; + + wire read_seq_incoming; // next few instructions will read from DRAM + wire [11:0] incoming_reads; // how many reads next few instructions will issue + wire [11:0] buffer_space; // remaining buffer size + + wire sys_rst = ~sys_rst_l; // low active signal + wire c0_init_calib_complete; + + // There is a possibility that these signals are on + // the critical path as observed in + // the previous iteration of SoftMC + reg c0_init_calib_complete_r, sys_rst_r; + wire iq_full, processing_iseq, rdback_fifo_empty; + + always @(posedge c0_ddr4_clk) begin + c0_init_calib_complete_r <= c0_init_calib_complete; + sys_rst_r <= sys_rst; + end + + reg dllt_active = 1'b0; + + `ifdef ENABLE_DLL_TOGGLER + always @(posedge c0_ddr4_clk) begin + if(toggle_dll) begin + dllt_active <= ~dllt_active; + end + if(dllt_done) begin + dllt_active <= ~dllt_active; + end + end + `endif + + `ifdef XUPP3R_x8 + phy_ddr4_x8 phy_ddr4_i( + .sys_rst (sys_rst), + .c0_sys_clk_p (c0_sys_clk_p), + .c0_sys_clk_n (c0_sys_clk_n), + `ifdef ENABLE_DLL_TOGGLER + .c0_ddr4_ui_clk (ddr4_ui_clk), + .addn_ui_clkout1 (c0_ddr4_dll_off_clk), + `else + .c0_ddr4_ui_clk (c0_ddr4_clk), + `endif + .c0_ddr4_ui_clk_sync_rst (c0_ddr4_rst), + .c0_init_calib_complete (c0_init_calib_complete), + .dbg_clk (dbg_clk), + .c0_ddr4_act_n (c0_ddr4_act_n), + .c0_ddr4_adr (c0_ddr4_adr), + .c0_ddr4_ba (c0_ddr4_ba), + .c0_ddr4_bg (c0_ddr4_bg), + .c0_ddr4_cke (c0_ddr4_cke), + .c0_ddr4_odt (c0_ddr4_odt), + .c0_ddr4_cs_n (c0_ddr4_cs_n), + .c0_ddr4_ck_t (c0_ddr4_ck_t), + .c0_ddr4_ck_c (c0_ddr4_ck_c), + .c0_ddr4_reset_n (c0_ddr4_reset_n), + .c0_ddr4_parity (c0_ddr4_parity), + .wrDataMask (wrDataMask), + .c0_ddr4_dm_dbi_n (c0_ddr4_dm_dbi_n), + .c0_ddr4_dq (c0_ddr4_dq), + .c0_ddr4_dqs_c (c0_ddr4_dqs_c), + .c0_ddr4_dqs_t (c0_ddr4_dqs_t), + + .dBufAdr (dBufAdr), + .wrData (wrData), + .rdData (rdData), + .rdDataAddr (rdDataAddr), + .rdDataEn (rdDataEn), + .rdDataEnd (rdDataEnd), + .per_rd_done (per_rd_done), + .rmw_rd_done (rmw_rd_done), + .wrDataAddr (wrDataAddr), + .wrDataEn (wrDataEn), + + .mc_ACT_n (dllt_active ? dllt_mc_ACT_n : mc_ACT_n), + .mc_ADR (dllt_active ? dllt_mc_ADR : mc_ADR), + .mc_BA (dllt_active ? dllt_mc_BA : mc_BA), + .mc_BG (dllt_active ? dllt_mc_BG : mc_BG), + .mc_CKE (dllt_active ? dllt_mc_CKE : mc_CKE), + .mc_CS_n (dllt_active ? dllt_mc_CS_n : mc_CS_n), + .mc_ODT (mc_ODT), + // CAS command slot select. Slot0 is enabled for example design. + .mcCasSlot (dllt_active ? 2'b0 : mcCasSlot), + // CAS slot 2 select. mcCasSlot2 serves a similar purpose as the mcCasSlot[1:0] signal, but mcCasSlot2 is used in timing + // critical logic in the Phy. Slot0 is enabled for example design. + .mcCasSlot2 (dllt_active ? 1'b0 : mcCasSlot2), + .mcRdCAS (dllt_active ? 1'b0 : mcRdCAS), + .mcWrCAS (dllt_active ? 1'b0 : mcWrCAS), + // Optional read command type indication. The winInjTxn signal is set to '0' for example design. + .winInjTxn ({1{1'b0}}), + // Optional read command type indication. The winRmw signal is set to '0' for example design. + .winRmw ({1{1'b0}}), + // Update VT Tracking. The gt_data_ready signal is set to '0' in this example design. + // This signal must be asserted periodically to keep the DQS Gate aligned as voltage and temperature drift. + // For more information, Refer to PG150 document. + .gt_data_ready (gt_data_ready), + .winBuf (winBuf), + .winRank (winRank), + .tCWL (tCWL), + // Debug Port + .dbg_bus (dbg_bus) + ); + `elsif XUPP3R_x4 + phy_ddr4 phy_ddr4_i( + .sys_rst (sys_rst), + .c0_sys_clk_p (c0_sys_clk_p), + .c0_sys_clk_n (c0_sys_clk_n), + + `ifdef ENABLE_DLL_TOGGLER + .c0_ddr4_ui_clk (ddr4_ui_clk), + .addn_ui_clkout1 (c0_ddr4_dll_off_clk), + `else + .c0_ddr4_ui_clk (c0_ddr4_clk), + `endif + .c0_ddr4_ui_clk_sync_rst (c0_ddr4_rst), + .c0_init_calib_complete (c0_init_calib_complete), + .dbg_clk (dbg_clk), + .c0_ddr4_act_n (c0_ddr4_act_n), + .c0_ddr4_adr (c0_ddr4_adr), + .c0_ddr4_ba (c0_ddr4_ba), + .c0_ddr4_bg (c0_ddr4_bg), + .c0_ddr4_cke (c0_ddr4_cke), + .c0_ddr4_odt (c0_ddr4_odt), + .c0_ddr4_cs_n (c0_ddr4_cs_n), + .c0_ddr4_ck_t (c0_ddr4_ck_t), + .c0_ddr4_ck_c (c0_ddr4_ck_c), + .c0_ddr4_reset_n (c0_ddr4_reset_n), + .c0_ddr4_parity (c0_ddr4_parity), + .c0_ddr4_dq (c0_ddr4_dq), + .c0_ddr4_dqs_c (c0_ddr4_dqs_c), + .c0_ddr4_dqs_t (c0_ddr4_dqs_t), + + .dBufAdr (dBufAdr), + .wrData (wrData), + .rdData (rdData), + .rdDataAddr (rdDataAddr), + .rdDataEn (rdDataEn), + .rdDataEnd (rdDataEnd), + .per_rd_done (per_rd_done), + .rmw_rd_done (rmw_rd_done), + .wrDataAddr (wrDataAddr), + .wrDataEn (wrDataEn), + + .mc_ACT_n (dllt_active ? dllt_mc_ACT_n : mc_ACT_n), + .mc_ADR (dllt_active ? dllt_mc_ADR : mc_ADR), + .mc_BA (dllt_active ? dllt_mc_BA : mc_BA), + .mc_BG (dllt_active ? dllt_mc_BG : mc_BG), + .mc_CKE (dllt_active ? dllt_mc_CKE : mc_CKE), + .mc_CS_n (dllt_active ? dllt_mc_CS_n : mc_CS_n), + .mc_ODT (mc_ODT), + // CAS command slot select. Slot0 is enabled for example design. + .mcCasSlot (dllt_active ? 0 : mcCasSlot), + // CAS slot 2 select. mcCasSlot2 serves a similar purpose as the mcCasSlot[1:0] signal, but mcCasSlot2 is used in timing + // critical logic in the Phy. Slot0 is enabled for example design. + .mcCasSlot2 (dllt_active ? 0 : mcCasSlot2), + .mcRdCAS (dllt_active ? 0 : mcRdCAS), + .mcWrCAS (dllt_active ? 0 : mcWrCAS), + // Optional read command type indication. The winInjTxn signal is set to '0' for example design. + .winInjTxn ({1{1'b0}}), + // Optional read command type indication. The winRmw signal is set to '0' for example design. + .winRmw ({1{1'b0}}), + // Update VT Tracking. The gt_data_ready signal is set to '0' in this example design. + // This signal must be asserted periodically to keep the DQS Gate aligned as voltage and temperature drift. + // For more information, Refer to PG150 document. + .gt_data_ready (gt_data_ready), + .winBuf (winBuf), + .winRank (winRank), + .tCWL (tCWL), + // Debug Port + .dbg_bus (dbg_bus) + ); + `elsif XUPP3R_x8_1R_UDIMM + phy_ddr4_udimm phy_ddr4_i( + .sys_rst (sys_rst), + .c0_sys_clk_p (c0_sys_clk_p), + .c0_sys_clk_n (c0_sys_clk_n), + `ifdef ENABLE_DLL_TOGGLER + .c0_ddr4_ui_clk (ddr4_ui_clk), + .addn_ui_clkout1 (c0_ddr4_dll_off_clk), + `else + .c0_ddr4_ui_clk (c0_ddr4_clk), + `endif + .c0_ddr4_ui_clk_sync_rst (c0_ddr4_rst), + .c0_init_calib_complete (c0_init_calib_complete), + .dbg_clk (dbg_clk), + .c0_ddr4_act_n (c0_ddr4_act_n), + .c0_ddr4_adr (c0_ddr4_adr), + .c0_ddr4_ba (c0_ddr4_ba), + .c0_ddr4_bg (c0_ddr4_bg), + .c0_ddr4_cke (c0_ddr4_cke), + .c0_ddr4_odt (c0_ddr4_odt), + .c0_ddr4_cs_n (c0_ddr4_cs_n), + .c0_ddr4_ck_t (c0_ddr4_ck_t), + .c0_ddr4_ck_c (c0_ddr4_ck_c), + .c0_ddr4_reset_n (c0_ddr4_reset_n), + .wrDataMask (wrDataMask), + .c0_ddr4_dm_dbi_n (c0_ddr4_dm_dbi_n), + .c0_ddr4_dq (c0_ddr4_dq), + .c0_ddr4_dqs_c (c0_ddr4_dqs_c), + .c0_ddr4_dqs_t (c0_ddr4_dqs_t), + + .dBufAdr (dBufAdr), + .wrData (wrData), + .rdData (rdData), + .rdDataAddr (rdDataAddr), + .rdDataEn (rdDataEn), + .rdDataEnd (rdDataEnd), + .per_rd_done (per_rd_done), + .rmw_rd_done (rmw_rd_done), + .wrDataAddr (wrDataAddr), + .wrDataEn (wrDataEn), + + .mc_ACT_n (dllt_active ? dllt_mc_ACT_n : mc_ACT_n), + .mc_ADR (dllt_active ? dllt_mc_ADR : mc_ADR), + .mc_BA (dllt_active ? dllt_mc_BA : mc_BA), + .mc_BG (dllt_active ? dllt_mc_BG : mc_BG), + .mc_CKE (dllt_active ? dllt_mc_CKE : mc_CKE), + .mc_CS_n (dllt_active ? dllt_mc_CS_n : mc_CS_n), + .mc_ODT (mc_ODT), + // CAS command slot select. Slot0 is enabled for example design. + .mcCasSlot (dllt_active ? 2'b0 : mcCasSlot), + // CAS slot 2 select. mcCasSlot2 serves a similar purpose as the mcCasSlot[1:0] signal, but mcCasSlot2 is used in timing + // critical logic in the Phy. Slot0 is enabled for example design. + .mcCasSlot2 (dllt_active ? 1'b0 : mcCasSlot2), + .mcRdCAS (dllt_active ? 1'b0 : mcRdCAS), + .mcWrCAS (dllt_active ? 1'b0 : mcWrCAS), + // Optional read command type indication. The winInjTxn signal is set to '0' for example design. + .winInjTxn ({1{1'b0}}), + // Optional read command type indication. The winRmw signal is set to '0' for example design. + .winRmw ({1{1'b0}}), + // Update VT Tracking. The gt_data_ready signal is set to '0' in this example design. + // This signal must be asserted periodically to keep the DQS Gate aligned as voltage and temperature drift. + // For more information, Refer to PG150 document. + .gt_data_ready (gt_data_ready), + .winBuf (winBuf), + .winRank (winRank), + .tCWL (tCWL), + // Debug Port + .dbg_bus (dbg_bus) + ); + `else + phy_ddr4 phy_ddr4_i( + .sys_rst (sys_rst), + .c0_sys_clk_p (c0_sys_clk_p), + .c0_sys_clk_n (c0_sys_clk_n), + + `ifdef ENABLE_DLL_TOGGLER + .c0_ddr4_ui_clk (ddr4_ui_clk), + .addn_ui_clkout1 (c0_ddr4_dll_off_clk), + `else + .c0_ddr4_ui_clk (c0_ddr4_clk), + `endif + .c0_ddr4_ui_clk_sync_rst (c0_ddr4_rst), + .c0_init_calib_complete (c0_init_calib_complete), + .dbg_clk (dbg_clk), + .c0_ddr4_act_n (c0_ddr4_act_n), + .c0_ddr4_adr (c0_ddr4_adr), + .c0_ddr4_ba (c0_ddr4_ba), + .c0_ddr4_bg (c0_ddr4_bg), + .c0_ddr4_cke (c0_ddr4_cke), + .c0_ddr4_odt (c0_ddr4_odt), + .c0_ddr4_cs_n (c0_ddr4_cs_n), + .c0_ddr4_ck_t (c0_ddr4_ck_t), + .c0_ddr4_ck_c (c0_ddr4_ck_c), + .c0_ddr4_reset_n (c0_ddr4_reset_n), + .wrDataMask (wrDataMask), + .c0_ddr4_dm_dbi_n (c0_ddr4_dm_dbi_n), + .c0_ddr4_dq (c0_ddr4_dq), + .c0_ddr4_dqs_c (c0_ddr4_dqs_c), + .c0_ddr4_dqs_t (c0_ddr4_dqs_t), + + .dBufAdr (dBufAdr), + .wrData (wrData), + .rdData (rdData), + .rdDataAddr (rdDataAddr), + .rdDataEn (rdDataEn), + .rdDataEnd (rdDataEnd), + .per_rd_done (per_rd_done), + .rmw_rd_done (rmw_rd_done), + .wrDataAddr (wrDataAddr), + .wrDataEn (wrDataEn), + + .mc_ACT_n (dllt_active ? dllt_mc_ACT_n : mc_ACT_n), + .mc_ADR (dllt_active ? dllt_mc_ADR : mc_ADR), + .mc_BA (dllt_active ? dllt_mc_BA : mc_BA), + .mc_BG (dllt_active ? dllt_mc_BG : mc_BG), + .mc_CKE (dllt_active ? dllt_mc_CKE : mc_CKE), + .mc_CS_n (dllt_active ? dllt_mc_CS_n : mc_CS_n), + .mc_ODT (mc_ODT), + // CAS command slot select. Slot0 is enabled for example design. + .mcCasSlot (dllt_active ? 0 : mcCasSlot), + // CAS slot 2 select. mcCasSlot2 serves a similar purpose as the mcCasSlot[1:0] signal, but mcCasSlot2 is used in timing + // critical logic in the Phy. Slot0 is enabled for example design. + .mcCasSlot2 (dllt_active ? 0 : mcCasSlot2), + .mcRdCAS (dllt_active ? 0 : mcRdCAS), + .mcWrCAS (dllt_active ? 0 : mcWrCAS), + // Optional read command type indication. The winInjTxn signal is set to '0' for example design. + .winInjTxn ({1{1'b0}}), + // Optional read command type indication. The winRmw signal is set to '0' for example design. + .winRmw ({1{1'b0}}), + // Update VT Tracking. The gt_data_ready signal is set to '0' in this example design. + // This signal must be asserted periodically to keep the DQS Gate aligned as voltage and temperature drift. + // For more information, Refer to PG150 document. + .gt_data_ready (gt_data_ready), + .winBuf (winBuf), + .winRank (winRank), + .tCWL (tCWL), + // Debug Port + .dbg_bus (dbg_bus) + ); + `endif + + softmc_pipeline pipeline( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst), + + .softmc_end(softmc_fin), + .read_size(incoming_reads), + .read_seq_incoming(read_seq_incoming), + .buffer_space(buffer_space), + + .addr_out(fr_addr_in), + .valid_out(fr_valid_in), + .data_in(fr_data_out), + .valid_in(fr_valid_out), + .addr_in(fr_addr_out), + .ready_out(fr_ready_out), + + .ddr_write(ddr_write), + .ddr_read(ddr_read), + .ddr_pre(ddr_pre), + .ddr_act(ddr_act), + .ddr_ref(ddr_ref), + .ddr_sre(ddr_sre), + .ddr_srx(ddr_srx), + .ddr_zq(ddr_zq), + .ddr_nop(ddr_nop), + .ddr_ap(ddr_ap), + .ddr_pall(ddr_pall), + .ddr_half_bl(ddr_half_bl), + .ddr_bg(ddr_bg), + .ddr_bank(ddr_bank), + .ddr_col(ddr_col), + .ddr_row(ddr_row), + .ddr_wdata(ddr_wdata) + ); + + `ifdef ENABLE_DLL_TOGGLER + //BUFGMUX:GeneralClockMuxBuffer + //UltraScale + //XilinxHDLLibrariesGuide, version2014.4 + BUFGMUX#(.CLK_SEL_TYPE("SYNC") //ASYNC,SYNC + )BUFGMUX_inst( + .O(c0_ddr4_clk), //1-bitoutput:Clockoutput + .I0(ddr4_ui_clk), //1-bitinput:Clockinput(S=0) + .I1(c0_ddr4_dll_off_clk), //1-bitinput:Clockinput(S=1) + .S(clk_sel) //1-bitinput:Clockselect + ); + //End of BUFGMUX_inst instantiation + `endif + + + wire frontend_ready; + + frontend #(.SIM_MEM(SIM)) frontend( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst), + + .init_calib_complete(c0_init_calib_complete_r), + .softmc_fin(softmc_fin), + .user_rst(user_rst), + + .dllt_begin(toggle_dll), + + // indicates read_back unit is ready for the next iseq + .frontend_ready(frontend_ready), + + // frontend <-> fetch stage if + .addr_in(fr_addr_in), + .valid_in(fr_valid_in), + .data_out(fr_data_out), + .valid_out(fr_valid_out), + .addr_out(fr_addr_out), + .ready_in(fr_ready_out), + + // frontend <-> xdma interface + .h2c_tdata_0(m_axis_h2c_tdata_0), + .h2c_tlast_0(m_axis_h2c_tlast_0), + .h2c_tvalid_0(m_axis_h2c_tvalid_0), + .h2c_tready_0(m_axis_h2c_tready_0), + .h2c_tkeep_0(m_axis_h2c_tkeep_0), + + .per_rd_init(per_rd_init), + .per_zq_init(per_zq_init), + .per_ref_init(per_ref_init), + .rbe_switch_mode(rbe_switch_mode) + ); + + ddr4_adapter#( + `ifdef XUPP3R + `ifdef XUPP3R_x8_1R_UDIMM + .DQ_WIDTH(64) + `else + .DQ_WIDTH(72) + `endif + `endif + ) ddr4_adapter + ( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst), + .init_calib_complete(c0_init_calib_complete_r), + //.io_config_strobe, + //.io_config, + .dBufAdr(dBufAdr), // Reserved. Should be tied low. + .wrData(wrData), // DRAM write data. There are 8 bits for each DQ lane on the DRAM bus. + .wrDataMask(wrDataMask),// DRAM write DM/DBI port.There is one bit for each byte of the wrData port. + .wrDataEn(wrDataEn), // Write data Enable. The Phy will assert this port for one cycle for each write CAS command. + .mc_ACT_n(mc_ACT_n), // DRAM ACT_n command signal for four DRAM clock cycles. + .mc_ADR(mc_ADR), // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus. + .mc_BA(mc_BA), // DRAM bank address. 8 bits for each DRAM bank address. + .mc_BG(mc_BG), // DRAM bank group address. + .mc_CS_n(mc_CS_n), // DRAM CS_n + .mc_CKE(mc_CKE), // DRAM CKE + //.mc_ODT(mc_ODT), // DRAM ODT + .mcRdCAS(mcRdCAS), // Read CAS command issued. + .mcWrCAS(mcWrCAS), // Write CAS command issued. + .winRank(winRank), // Target rank for CAS commands. This value indicates which rank a CAS command is issued to. + .winBuf(winBuf), // Optional control signal. When either mcRdCAS or mcWrCAS is asserted, the Phy will store the value on the winBuf signal. + //.rdData(rdData), // DRAM read data. + .rdDataEn(rdDataEn), // Read data valid. This signal asserts for one fabric cycle for each completed read operation. + .rdDataEnd(rdDataEnd), // Unused. Tied high. + .mcCasSlot(mcCasSlot), + .mcCasSlot2(mcCasSlot2), + .gt_data_ready(gt_data_ready), + .ddr_write(ddr_write), + .ddr_read(ddr_read), + .ddr_pre(ddr_pre), + .ddr_act(ddr_act), + .ddr_ref(ddr_ref), + .ddr_sre(ddr_sre), + .ddr_srx(ddr_srx), + .ddr_zq(ddr_zq), + .ddr_nop(ddr_nop), + .ddr_ap(ddr_ap), + .ddr_pall(ddr_pall), + .ddr_half_bl(ddr_half_bl), + .ddr_bg(ddr_bg), + .ddr_bank(ddr_bank), + .ddr_col(ddr_col), + .ddr_row(ddr_row), + .ddr_wdata(ddr_wdata), + + .ddr_maint_read(per_rd_init) + ); + `ifdef XUPP3R_x8 + localparam ODTWRDEL = 5'd9; + localparam ODTWRDUR = 4'd6; + localparam ODTWRODEL = 5'd9; + localparam ODTWRODUR = 4'd6; + localparam ODTRDDEL = 5'd10; + localparam ODTRDDUR = 4'd6; + localparam ODTRDODEL = 5'd9; + localparam ODTRDODUR = 4'd6; + localparam ODTNOP = 16'h0000; + localparam ODTWR = 16'h0021; + localparam ODTRD = 16'h0012; + `elsif XUPP3R_x8_1R_UDIMM + localparam ODTWRDEL = 5'd9; + localparam ODTWRDUR = 4'd6; + localparam ODTWRODEL = 5'd9; + localparam ODTWRODUR = 4'd6; + localparam ODTRDDEL = 5'd9; + localparam ODTRDDUR = 4'd6; + localparam ODTRDODEL = 5'd9; + localparam ODTRDODUR = 4'd6; + localparam ODTNOP = 16'h0000; + localparam ODTWR = 16'h0001; + localparam ODTRD = 16'h0000; + `else + localparam ODTWRDEL = 5'd11; + localparam ODTWRDUR = 4'd6; + localparam ODTWRODEL = 5'd9; + localparam ODTWRODUR = 4'd6; + localparam ODTRDDEL = 5'd11; + localparam ODTRDDUR = 4'd6; + localparam ODTRDODEL = 5'd9; + localparam ODTRDODUR = 4'd6; + localparam ODTNOP = 16'h0000; + localparam ODTWR = 16'h0001; + localparam ODTRD = 16'h0000; + `endif + + wire tranSentC; + assign tranSentC = mcRdCAS | mcWrCAS; + + //synthesis translate_on + //******************************************************************************* + ddr4_mc_odt # ( + .ODTWR (ODTWR) + ,.ODTWRDEL (ODTWRDEL) + ,.ODTWRDUR (ODTWRDUR) + ,.ODTWRODEL (ODTWRODEL) + ,.ODTWRODUR (ODTWRODUR) + + ,.ODTRD (ODTRD) + ,.ODTRDDEL (ODTRDDEL) + ,.ODTRDDUR (ODTRDDUR) + ,.ODTRDODEL (ODTRDODEL) + ,.ODTRDODUR (ODTRDODUR) + + ,.ODTNOP (ODTNOP) + ,.ODTBITS (`ODT_WIDTH) + ,.TCQ (0.1) + )u_ddr_tb_odt( + .clk (c0_ddr4_clk) + ,.rst (c0_ddr4_rst) + ,.mc_ODT (mc_ODT) + ,.casSlot (mcCasSlot) + ,.casSlot2 (mcCasSlot2) + ,.rank (winRank) + ,.winRead (mcRdCAS) + ,.winWrite (mcWrCAS) + ,.tranSentC (tranSentC) + ); + + wire sys_clk, sys_clk_gt; + wire [2:0] msi_vector_width; + wire msi_enable; + wire user_lnk_up, usr_irq_req, usr_irq_ack; + `ifdef XUPP3R + IBUFDS_GTE4 refclk_ibuf (.O(sys_clk_gt), .ODIV2(sys_clk), .I(clk_ref_p), .CEB(1'b0), .IB(clk_ref_n)); + `else + IBUFDS_GTE3 # (.REFCLK_HROW_CK_SEL(2'b01)) refclk_ibuf (.O(sys_clk_gt), .ODIV2(sys_clk), .I(clk_ref_p), .CEB(1'b0), .IB(clk_ref_n)); + `endif + wire axi_clk, axi_rst; + + xdma xdma_i + ( + //---------------------------------------------------------------------------------------// + // PCI Express (pci_exp) Interface // + //---------------------------------------------------------------------------------------// + .sys_rst_n ( pcie_rst ), + .sys_clk ( sys_clk ), + .sys_clk_gt ( sys_clk_gt), + + // Tx + .pci_exp_txn ( pci_exp_txn ), + .pci_exp_txp ( pci_exp_txp ), + + // Rx + .pci_exp_rxn ( pci_exp_rxn ), + .pci_exp_rxp ( pci_exp_rxp ), + + // AXI streaming ports + .s_axis_c2h_tdata_0(xdma_c2h_tdata_0), + .s_axis_c2h_tlast_0(xdma_c2h_tlast_0), + .s_axis_c2h_tvalid_0(xdma_c2h_tvalid_0), + .s_axis_c2h_tready_0(xdma_c2h_tready_0), + .s_axis_c2h_tkeep_0(xdma_c2h_tkeep_0), + .m_axis_h2c_tdata_0(xdma_h2c_tdata_0), + .m_axis_h2c_tlast_0(xdma_h2c_tlast_0), + .m_axis_h2c_tvalid_0(xdma_h2c_tvalid_0), + .m_axis_h2c_tready_0(xdma_h2c_tready_0), + .m_axis_h2c_tkeep_0(xdma_h2c_tkeep_0), + + .usr_irq_req (1'b0), + .usr_irq_ack (usr_irq_ack), + .msi_enable (msi_enable), + .msi_vector_width (msi_vector_width), + + + // Config managemnet interface + .cfg_mgmt_addr ( 19'b0 ), + .cfg_mgmt_write ( 1'b0 ), + .cfg_mgmt_write_data ( 32'b0 ), + .cfg_mgmt_byte_enable ( 4'b0 ), + .cfg_mgmt_read ( 1'b0 ), + .cfg_mgmt_read_data (), + .cfg_mgmt_read_write_done (), + `ifndef XUPP3R + .cfg_mgmt_type1_cfg_reg_access ( 1'b0 ), + //---------- Shared Logic Internal ------------------------- + .int_qpll1lock_out ( ), + .int_qpll1outrefclk_out ( ), + .int_qpll1outclk_out ( ), + `endif + + //-- AXI Global + .axi_aclk (axi_clk), // AXI i-face clock driven from pcie clk + .axi_aresetn (axi_rst), // reset synchronous to axi_clk + + .user_lnk_up ( user_lnk_up ) + ); + + // Clock converter for the c2h interface + axis_clock_converter axis_clk_conv_i0 + ( + .s_axis_tvalid(s_axis_c2h_tvalid_0), + .s_axis_tlast(s_axis_c2h_tlast_0), + .s_axis_tdata(s_axis_c2h_tdata_0), + .s_axis_tkeep(s_axis_c2h_tkeep_0), + .s_axis_tready(s_axis_c2h_tready_0), + .m_axis_tvalid(xdma_c2h_tvalid_0), + .m_axis_tlast(xdma_c2h_tlast_0), + .m_axis_tdata(xdma_c2h_tdata_0), + .m_axis_tkeep(xdma_c2h_tkeep_0), + .m_axis_tready(xdma_c2h_tready_0), + .s_axis_aresetn(~c0_ddr4_rst), + .s_axis_aclk(c0_ddr4_clk), + .m_axis_aresetn(axi_rst), + .m_axis_aclk(axi_clk) + ); + + // Clock converter for the h2c interface + axis_clock_converter axis_clk_conv_i1 + ( + .m_axis_tvalid(m_axis_h2c_tvalid_0), + .m_axis_tlast(m_axis_h2c_tlast_0), + .m_axis_tdata(m_axis_h2c_tdata_0), + .m_axis_tkeep(m_axis_h2c_tkeep_0), + .m_axis_tready(m_axis_h2c_tready_0), + .s_axis_tvalid(xdma_h2c_tvalid_0), + .s_axis_tlast(xdma_h2c_tlast_0), + .s_axis_tdata(xdma_h2c_tdata_0), + .s_axis_tkeep(xdma_h2c_tkeep_0), + .s_axis_tready(xdma_h2c_tready_0), + .m_axis_aresetn(~c0_ddr4_rst), + .m_axis_aclk(c0_ddr4_clk), + .s_axis_aresetn(axi_rst), + .s_axis_aclk(axi_clk) + ); + + readback_engine rbe( + + // common signals + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst), + + // other ctrl signals + .flush(frontend_ready), + .switch_mode(rbe_switch_mode), + .read_seq_incoming(read_seq_incoming), // next few instructions will read from DRAM + .incoming_reads(incoming_reads), // how many reads next few instructions will issue + .buffer_space(buffer_space), // remaining buffer size + // DRAM <-> engine if + .rd_data(rdData), + .rd_valid(rdDataEn), + + // rbe <-> rf interface + .ddr_wdata(ddr_wdata), + + .per_rd_init(per_rd_init), + .per_zq_init(per_zq_init), + .per_ref_init(per_ref_init), + + // rbe <-> xdma if + .c2h_tdata_0(s_axis_c2h_tdata_0), + .c2h_tlast_0(s_axis_c2h_tlast_0), + .c2h_tvalid_0(s_axis_c2h_tvalid_0), + .c2h_tready_0(s_axis_c2h_tready_0), + .c2h_tkeep_0(s_axis_c2h_tkeep_0) + + ); + + `ifdef ENABLE_DLL_TOGGLER + dll_toggler dllt + ( + .clk(c0_ddr4_clk), + .rst(c0_ddr4_rst || user_rst || ~c0_init_calib_complete_r), + .toggle_valid(toggle_dll), + .mc_ACT_n(dllt_mc_ACT_n), // DRAM ACT_n command signal for four DRAM clock cycles. + .mc_ADR(dllt_mc_ADR), // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus. + .mc_BA(dllt_mc_BA), // DRAM bank address. 8 bits for each DRAM bank address. + .mc_BG(dllt_mc_BG), // DRAM bank group address. + .mc_CS_n(dllt_mc_CS_n), // DRAM CS_n + .mc_CKE(dllt_mc_CKE), + .clk_sel(clk_sel), + .dllt_done(dllt_done) + ); + `endif +endmodule |
