Skip to content

Instantly share code, notes, and snippets.

@gregdavill
Last active June 17, 2018 10:54
Show Gist options
  • Save gregdavill/5e2be11abf8e0554248f4b61a3da1c5d to your computer and use it in GitHub Desktop.
Save gregdavill/5e2be11abf8e0554248f4b61a3da1c5d to your computer and use it in GitHub Desktop.
Simple Bindings for BML's HyperRAM into PicoSoC
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
* 2018 Gregory Davill <greg.davill@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/*
* HyperRAM connections:
* - HRAM_CK = Clock input to HyperRAM (CK[0] is positive ck, CK[1] is negative ck)
* - HRAM_DQ = Bidirectional DDR databus to HyperRAM
* - HRAM_CS = Chip Select. Active LOW
* - HRAM_RESET = Reset. Active LOW
* - HRAM_RWDS = Read Write Data Strobe, (Also Latency indicator.)
*/
/*
* For use with PicoSOC: https://github.com/cliffordwolf/picorv32/tree/master/picosoc
*/
module ecp5demo (
input clk_input,
output ser_tx,
input ser_rx,
output led,
output flash_csb,
//output flash_clk, /* CLK pin requires special USRMCLK module */
inout flash_io0,
inout flash_io1,
/* HYPER RAM SIGNALS */
inout [1:0] HRAM_CK,
output HRAM_CS,
inout HRAM_RWDS,
inout [7:0] HRAM_DQ,
output HRAM_RESET,
);
wire clk;
assign clk = clk_input;
reg [10:0] reset_cnt = 0;
wire resetn = &reset_cnt;
always @(posedge clk) begin
reset_cnt <= reset_cnt + !resetn;
end
wire flash_io0_oe, flash_io0_do, flash_io0_di;
wire flash_io1_oe, flash_io1_do, flash_io1_di;
wire flash_clk;
/* Flash IO buffers */
USRMCLK u1 (.USRMCLKI(flash_clk), .USRMCLKTS(!resetn)) /* synthesis syn_noprune=1 */;
BBPU flash_io_buf[1:0] (
.B({flash_io1, flash_io0}),
.T({!flash_io1_oe, !flash_io0_oe}),
.I({flash_io1_do, flash_io0_do}),
.O({flash_io1_di, flash_io0_di})
);
wire iomem_valid;
reg iomem_ready;
wire [3:0] iomem_wstrb;
wire [31:0] iomem_addr;
wire [31:0] iomem_wdata;
reg [31:0] iomem_rdata;
reg [31:0] gpio;
assign led = gpio[0];
reg [31:0] hyperram_ctrl_addr;
reg hyperram_ctrl;
reg [7:0] latency_1x;
reg [7:0] latency_2x;
reg rd_jk;
reg rd_req;
reg wr_req;
wire [31:0] addr;
wire [31:0] wr_d;
wire [31:0] rd_d;
wire rd_rdy;
wire busy;
always @(posedge clk) begin
if (!resetn) begin
gpio <= 0;
hyperram_ctrl <= 0;
hyperram_ctrl_addr <= 0;
latency_1x <= 8'h12;
latency_2x <= 8'h16;
end else begin
iomem_ready <= 0;
if(iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin
/* GPIO outputs [0x0300 0000]*/
if (iomem_addr[7:0] == 8'h 00) begin
iomem_ready <= 1;
iomem_rdata <= {gpio[31:0]};
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end
/* hyperram_ctrl_a [0x0300 0010] */
if(iomem_addr[7:0] == 8'h 10) begin
iomem_ready <= 1;
iomem_rdata <= {16'b0,latency_2x,latency_1x};
if (iomem_wstrb[0]) latency_1x <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) latency_2x <= iomem_wdata[15: 8];
end
/* hyperram_ctrl_b [0x0300 0014] */
if(iomem_addr[7:0] == 8'h 14) begin
/* Write */
if (|iomem_wstrb) begin
if(!busy) begin
hyperram_ctrl <= 1;
hyperram_ctrl_addr <= 32'h0000_0800;
wr_req <= 1;
end
if(wr_req) begin
wr_req <= 0;
iomem_ready <= 1; /* No need to wait for writes */
hyperram_ctrl <= 0;
end
end else begin
if(!busy) begin
hyperram_ctrl <= 1;
hyperram_ctrl_addr <= 32'h0000_0800;
rd_jk <= 1;
end
if(rd_rdy) begin
iomem_ready <= 1;
rd_jk <= 0;
hyperram_ctrl <= 0;
end
iomem_rdata <= rd_d;
end
end
end
/* HyperRAM mem-map [0x0400 0000+] */
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 04 ) begin
if (|iomem_wstrb) begin
if(!busy) begin
wr_req <= 1;
end
if(wr_req) begin
wr_req <= 0;
iomem_ready <= 1; /* No need to wait for writes */
end
end else begin
rd_jk <= !busy;
if(rd_rdy) begin
iomem_ready <= 1;
rd_jk <= 0;
end
iomem_rdata <= rd_d;
end
end
end
end
picosoc soc (
.clk (clk ),
.resetn (resetn ),
.ser_tx (ser_tx ),
.ser_rx (ser_rx ),
.flash_csb (flash_csb ),
.flash_clk (flash_clk ),
.flash_io0_oe (flash_io0_oe),
.flash_io1_oe (flash_io1_oe),
.flash_io0_do (flash_io0_do),
.flash_io1_do (flash_io1_do),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.irq_5 (1'b0 ),
.irq_6 (1'b0 ),
.irq_7 (1'b0 ),
.iomem_valid (iomem_valid ),
.iomem_ready (iomem_ready ),
.iomem_wstrb (iomem_wstrb ),
.iomem_addr (iomem_addr ),
.iomem_wdata (iomem_wdata ),
.iomem_rdata (iomem_rdata )
);
/* Module to IO */
wire [7:0] dram_dq_in;
wire [7:0] dram_dq_out;
wire dram_dq_oe_l;
wire dram_rwds_in;
wire dram_rwds_out;
wire dram_rwds_oe_l;
wire dram_ck;
wire dram_rst_l;
wire dram_cs_l;
assign addr = hyperram_ctrl ? hyperram_ctrl_addr : {10'b0, iomem_addr[23:2]};
assign wr_d = iomem_wdata;
/* rd_req pulse generator */
reg rd_jk_sr;
always @(posedge clk) begin
if (!resetn) begin
rd_jk_sr <= 0;
end
rd_jk_sr <= rd_jk;
rd_req <= 0;
if(!rd_jk_sr && rd_jk)
rd_req <= 1;
end
/* BML's HyperRAM module
* https://github.com/blackmesalabs/hyperram
*/
hyper_xface u_hyper_xface
(
.reset ( !resetn ),
.clk ( clk ),
.rd_req ( rd_req ),
.wr_req ( wr_req ),
.mem_or_reg ( hyperram_ctrl ),
.wr_byte_en ( 4'hF ),
.addr ( addr[31:0] ),
.rd_num_dwords ( 6'b000001 ),
.wr_d ( wr_d[31:0] ),
.rd_d ( rd_d[31:0] ),
.rd_rdy ( rd_rdy ),
.burst_wr_rdy ( burst_wr_rdy ),
.busy ( busy ),
.latency_1x ( latency_1x ),
.latency_2x ( latency_2x ),
.dram_dq_in ( dram_dq_in[7:0] ),
.dram_dq_out ( dram_dq_out[7:0] ),
.dram_dq_oe_l ( dram_dq_oe_l ),
.dram_rwds_in ( dram_rwds_in ),
.dram_rwds_out ( dram_rwds_out ),
.dram_rwds_oe_l ( dram_rwds_oe_l ),
.dram_ck ( dram_ck ),
.dram_rst_l ( dram_rst_l ),
.dram_cs_l ( dram_cs_l )
);
/* IO bindings OB - OutputBuffer, BB - BidirectionalBuffer */
OB hyperram_cs (
.O(HRAM_CS),
.I(dram_cs_l)
);
OB hyperram_reset (
.O(HRAM_RESET),
.I(dram_rst_l)
);
BB hyperram_rwds (
.B ( HRAM_RWDS ),
.T ( dram_rwds_oe_l),
.I (dram_rwds_out),
.O (dram_rwds_in)
);
OB hyperram_ck [1:0] (
.O ( HRAM_CK ),
.I ({~dram_ck, dram_ck})
);
BB hyperram_dq [7:0] (
.B ( HRAM_DQ ),
.T ( dram_dq_oe_l),
.I (dram_dq_out),
.O (dram_dq_in)
);
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment