aboutsummaryrefslogtreecommitdiffstats
path: root/sources/hdl/verilog/frontend.v
blob: 9225bd974fa7725218aaf5b09894c44fd28b5d6d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
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