123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- /*
- * hram_top.v
- *
- * vim: ts=4 sw=4
- *
- * Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
- * All rights reserved.
- *
- * BSD 3-clause, see LICENSE.bsd
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the <organization> nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- `default_nettype none
- module hram_top (
- // PHY interface
- output reg [ 1:0] phy_ck_en,
- input wire [ 3:0] phy_rwds_in,
- output reg [ 3:0] phy_rwds_out,
- output reg [ 1:0] phy_rwds_oe,
- input wire [31:0] phy_dq_in,
- output reg [31:0] phy_dq_out,
- output reg [ 1:0] phy_dq_oe,
- output reg [ 3:0] phy_cs_n,
- output wire phy_rst_n,
- // PHY configuration
- output wire [ 7:0] phy_cfg_wdata,
- input wire [ 7:0] phy_cfg_rdata,
- output wire phy_cfg_stb,
- // Memory interface
- input wire [ 1:0] mi_addr_cs,
- input wire [31:0] mi_addr,
- input wire [ 6:0] mi_len,
- input wire mi_rw, /* 0=Write, 1=Read */
- input wire mi_linear, /* 0=Wrapped burst, 1=Linear */
- input wire mi_valid,
- output wire mi_ready,
- input wire [31:0] mi_wdata,
- input wire [ 3:0] mi_wmsk,
- output wire mi_wack,
- output wire mi_wlast,
- output wire [31:0] mi_rdata,
- output wire mi_rstb,
- output wire mi_rlast,
- // Wishbone interface
- input wire [31:0] wb_wdata,
- output reg [31:0] wb_rdata,
- input wire [ 3:0] wb_addr,
- input wire wb_we,
- input wire wb_cyc,
- output wire wb_ack,
- // Clock / Reset
- input wire clk,
- input wire rst
- );
- // FSM
- // ---
- localparam
- ST_IDLE_CFG = 0,
- ST_IDLE_RUN = 1,
- ST_CMD_ADDR_MSB = 2,
- ST_CMD_ADDR_LSB = 3,
- ST_LATENCY = 4,
- ST_DATA_WRITE = 5,
- ST_DATA_READ = 6,
- ST_DONE = 7;
- reg [3:0] state;
- reg [3:0] state_nxt;
- // Signals
- // -------
- // Control
- wire running;
- reg [ 3:0] lat_cnt;
- wire lat_last;
- reg [ 7:0] xfer_cnt;
- wire xfer_last;
- reg [95:0] sr_data;
- reg [11:0] sr_mask;
- reg [ 5:0] sr_oe;
- reg [ 1:0] sr_src;
- reg [ 1:0] sr_ce;
- wire [ 1:0] cap_in;
- wire [ 1:0] cap_out;
- // Current transaction
- reg cmd_is_read;
- reg cmd_is_reg;
- reg cmd_is_wb;
- reg [ 3:0] cmd_cs;
- // Wishbone interface
- reg wb_ack_i;
- reg wbi_we_csr;
- reg wbi_we_exec;
- reg wbi_we_wq_data;
- reg wbi_ae_wq_data;
- reg wbi_we_wq_attr;
- wire wbi_cmd_now;
- wire [3:0] wbi_cmd_len;
- wire [3:0] wbi_cmd_lat;
- wire [1:0] wbi_cmd_cs;
- wire wbi_cmd_is_reg;
- wire wbi_cmd_is_read;
- reg [15:0] wbi_csr;
- wire [31:0] wbi_csr_rd;
- reg [ 5:0] wbi_attr;
- // FSM
- // ---
- // State register
- always @(posedge clk)
- if (rst)
- state <= ST_IDLE_CFG;
- else
- state <= state_nxt;
- // Next-State logic
- always @(*)
- begin
- // Default is to stay put
- state_nxt = state;
- // Transisions
- case (state)
- ST_IDLE_CFG:
- if (wbi_cmd_now)
- state_nxt = ST_CMD_ADDR_MSB;
- else if (running)
- state_nxt = ST_IDLE_RUN;
- ST_IDLE_RUN:
- if (mi_valid)
- state_nxt = ST_CMD_ADDR_MSB;
- else if (!running)
- state_nxt = ST_IDLE_CFG;
- ST_CMD_ADDR_MSB:
- state_nxt = ST_CMD_ADDR_LSB;
- ST_CMD_ADDR_LSB:
- state_nxt = (cmd_is_reg & ~cmd_is_read) ? ST_DONE : ST_LATENCY;
- ST_LATENCY:
- if (lat_last)
- state_nxt = cmd_is_read ? ST_DATA_READ : ST_DATA_WRITE;
- ST_DATA_WRITE:
- if (xfer_last)
- state_nxt = ST_DONE;
- ST_DATA_READ:
- if (xfer_last)
- state_nxt = ST_DONE;
- ST_DONE:
- state_nxt = running ? ST_IDLE_RUN : ST_IDLE_CFG;
- endcase
- end
- // Control
- // -------
- // State
- assign running = wbi_csr[0];
- // Command latch
- always @(posedge clk)
- begin
- if ((state == ST_IDLE_RUN) & mi_valid)
- begin
- cmd_is_read <= mi_rw;
- cmd_is_reg <= 1'b0;
- cmd_is_wb <= 1'b0;
- cmd_cs <= 4'hf ^ (1 << mi_addr_cs);
- end
- else if ((state == ST_IDLE_CFG) & wbi_cmd_now)
- begin
- cmd_is_read <= wbi_cmd_is_read;
- cmd_is_reg <= wbi_cmd_is_reg;
- cmd_is_wb <= 1'b1;
- cmd_cs <= 4'hf ^ (1 << wbi_cmd_cs);
- end
- end
- // Shift register control
- always @(*)
- begin
- // Defaults
- sr_ce[1] = 1'b0;
- sr_ce[0] = 1'b0;
- sr_src[1] = 1'b0;
- sr_src[0] = 1'b0;
- // Memory interface Command accept
- if ((state == ST_IDLE_RUN) & mi_valid)
- begin
- sr_ce[1] = 1'b1;
- sr_src[1] = 1'b1;
- end
- // Wishbone accesses
- if (wbi_ae_wq_data)
- begin
- sr_ce[1] = 1'b1;
- sr_ce[0] = 1'b1;
- sr_src[1] = 1'b0;
- sr_src[0] = 1'b1;
- end
- // Config mode capture
- if (cap_out == 2'b01)
- begin
- sr_ce[1] = 1'b1;
- sr_ce[0] = 1'b1;
- sr_src[1] = 1'b0;
- sr_src[0] = 1'b0;
- end
- // Normal "shift"
- if ((state == ST_CMD_ADDR_MSB) || (state == ST_CMD_ADDR_LSB))
- begin
- sr_ce[1] = 1'b1;
- sr_ce[0] = 1'b1;
- sr_src[1] = 1'b0;
- sr_src[0] = 1'b0;
- end
- end
- // Shift register
- always @(posedge clk)
- begin
- // MSBs [95:32]
- if (sr_ce[1])
- begin
- sr_oe [ 5: 2] <= sr_src[1] ? 4'b1110 : sr_oe [3:0];
- sr_mask[11: 4] <= sr_src[1] ? 8'h00 : sr_mask[7:0];
- sr_data[95:32] <= sr_src[1] ?
- { mi_rw, 1'b0, mi_linear, mi_addr[31:3], 13'h0000, mi_addr[2:0], 16'h0000 } :
- sr_data[63:0];
- end
- // LSBs [31: 0]
- if (sr_ce[0])
- begin
- sr_oe [ 1:0] <= sr_src[0] ? wbi_attr[5:4] : 2'b11;
- sr_mask[ 3:0] <= sr_src[0] ? wbi_attr[3:0] : phy_rwds_in;
- sr_data[31:0] <= sr_src[0] ? wb_wdata : phy_dq_in;
- end
- end
- // Latency counter
- always @(posedge clk)
- begin
- if (state == ST_IDLE_RUN)
- lat_cnt <= wbi_csr[11:8] - 1;
- else if (state == ST_IDLE_CFG)
- lat_cnt <= wbi_cmd_lat - 1;
- else if (state == ST_LATENCY)
- lat_cnt <= lat_cnt - 1;
- end
- assign lat_last = lat_cnt[3];
- // Transfer counter
- always @(posedge clk)
- begin
- if (state == ST_IDLE_RUN)
- xfer_cnt <= { 1'b0, mi_len } - 1;
- else if (state == ST_IDLE_CFG)
- xfer_cnt <= { 4'h0, wbi_cmd_len } - 1;
- else if ((state == ST_DATA_WRITE) || (state == ST_DATA_READ))
- xfer_cnt <= xfer_cnt - 1;
- end
- assign xfer_last = xfer_cnt[7];
- // Input capture
- // 00 - Nothing
- // 01 - Capture WB
- // 10 - Capture MemIF
- // 11 - Capture MemIF last
- assign cap_in[1] = (state == ST_DATA_READ) & ~cmd_is_wb;
- assign cap_in[0] = (state == ST_DATA_READ) & (cmd_is_wb | xfer_last);
- hram_dline #(
- .N(3)
- ) cap_I[1:0] (
- .di(cap_in),
- .do(cap_out),
- .delay(wbi_csr[14:12]),
- .clk(clk)
- );
- // PHY drive
- // ---------
- // Main signals
- always @(*)
- begin
- // Defaults
- phy_ck_en = 2'b00;
- phy_rwds_out = 4'h0;
- phy_rwds_oe = 2'b00;
- phy_dq_out = sr_data[95:64];
- phy_dq_oe = 2'b00;
- phy_cs_n = 4'hf;
- // Special per-state overrides
- case (state)
- ST_CMD_ADDR_MSB: begin
- phy_ck_en = 2'b11;
- phy_dq_oe = sr_oe[5:4];
- phy_cs_n = cmd_cs;
- end
- ST_CMD_ADDR_LSB: begin
- phy_ck_en = 2'b11;
- phy_dq_oe = sr_oe[5:4];
- phy_cs_n = cmd_cs;
- end
- ST_LATENCY: begin
- phy_ck_en = 2'b11;
- phy_cs_n = cmd_cs;
- end
- ST_DATA_WRITE: begin
- phy_ck_en = 2'b11;
- phy_dq_oe = 2'b11;
- phy_rwds_oe = 2'b11;
- phy_dq_out = cmd_is_wb ? sr_data[95:64] : mi_wdata;
- phy_rwds_out = cmd_is_wb ? sr_mask[11: 8] : mi_wmsk;
- phy_cs_n = cmd_cs;
- end
- ST_DATA_READ: begin
- phy_ck_en = 2'b11;
- phy_cs_n = cmd_cs;
- end
- ST_DONE: begin
- phy_cs_n = cmd_cs;
- end
- endcase
- end
- // OOB
- assign phy_rst_n = ~wbi_csr[1];
- // Memory interface
- // ----------------
- assign mi_ready = (state == ST_IDLE_RUN);
- assign mi_wack = (state == ST_DATA_WRITE) & ~cmd_is_wb;
- assign mi_wlast = xfer_last;
- assign mi_rdata = phy_dq_in;
- assign mi_rstb = cap_out[1];
- assign mi_rlast = cap_out[0];
- // Wishbone interface
- // ------------------
- // Ack
- always @(posedge clk)
- wb_ack_i <= wb_cyc & ~wb_ack_i;
- assign wb_ack = wb_ack_i;
- // Read Mux
- always @(posedge clk)
- if (~wb_cyc | wb_ack)
- wb_rdata <= 32'h00000000;
- else
- case (wb_addr[1:0])
- 2'b00: wb_rdata <= wbi_csr_rd;
- 2'b10: wb_rdata <= sr_data[95:64];
- 2'b11: wb_rdata <= { 26'h0000000, sr_oe[5:4], sr_mask[11:8] };
- default: wb_rdata <= 32'hxxxxxxxx;
- endcase
- assign wbi_csr_rd[31:16] = { 8'h00, phy_cfg_rdata };
- assign wbi_csr_rd[15: 0] = (wbi_csr & 16'hff03) | {
- 12'h000,
- (state == ST_IDLE_RUN),
- (state == ST_IDLE_CFG),
- 2'b00
- };
- // Read/Write/Access Enables
- always @(posedge clk)
- begin
- if (wb_ack) begin
- wbi_we_csr <= 1'b0;
- wbi_we_exec <= 1'b0;
- wbi_we_wq_data <= 1'b0;
- wbi_ae_wq_data <= 1'b0;
- wbi_we_wq_attr <= 1'b0;
- end else begin
- wbi_we_csr <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b00);
- wbi_we_exec <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b01);
- wbi_we_wq_data <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b10);
- wbi_ae_wq_data <= wb_cyc & (wb_addr[1:0] == 2'b10);
- wbi_we_wq_attr <= wb_cyc & wb_we & (wb_addr[1:0] == 2'b11);
- end
- end
- // CSR
- always @(posedge clk)
- if (rst)
- wbi_csr <= 16'h0000;
- else if (wbi_we_csr)
- wbi_csr <= wb_wdata[15:0];
- // PHY config
- assign phy_cfg_wdata = wb_wdata[23:16];
- assign phy_cfg_stb = wbi_we_csr;
- // Attrs
- always @(posedge clk)
- if (wbi_we_wq_attr)
- wbi_attr <= wb_wdata[5:0];
- // Command execute
- assign wbi_cmd_now = wbi_we_exec;
- assign wbi_cmd_len = wb_wdata[11:8];
- assign wbi_cmd_lat = wb_wdata[ 7:4];
- assign wbi_cmd_cs = wb_wdata[ 3:2];
- assign wbi_cmd_is_reg = wb_wdata[1];
- assign wbi_cmd_is_read = wb_wdata[0];
- endmodule
|