aboutsummaryrefslogtreecommitdiffstats
path: root/sources/hdl/verilog/frontend.v
diff options
context:
space:
mode:
Diffstat (limited to 'sources/hdl/verilog/frontend.v')
-rw-r--r--sources/hdl/verilog/frontend.v237
1 files changed, 237 insertions, 0 deletions
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
+