├── Makefile ├── README.md ├── blackice.pcf ├── clockdiv.v ├── dvid_tb.v ├── mystorm.pdf ├── ram.pdf ├── sram.png ├── sram.v ├── sram_tb.v └── top.v /Makefile: -------------------------------------------------------------------------------- 1 | PROJ = sram 2 | PIN_DEF = blackice.pcf 3 | DEVICE = 8k 4 | 5 | SRC = top.v sram.v clockdiv.v 6 | 7 | all: $(PROJ).rpt $(PROJ).bin 8 | 9 | %.blif: %.v $(SRC) 10 | yosys -p "synth_ice40 -top top -blif $@" $^ 11 | 12 | %.asc: $(PIN_DEF) %.blif 13 | arachne-pnr -d $(subst hx,,$(subst lp,,$(DEVICE))) --package tq144:4k -o $@ -p $^ 14 | 15 | %.bin: %.asc 16 | icepack $< $@ 17 | 18 | %.rpt: %.asc 19 | icetime -d hx8k -mtr $@ $< 20 | 21 | debug-sram: 22 | iverilog -o sram sram.v sram_tb.v 23 | vvp sram -fst 24 | gtkwave test.vcd gtk-sram.gtkw 25 | 26 | prog: 27 | bash -c "cat sram.bin > /dev/ttyUSB0" 28 | 29 | clean: 30 | rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin 31 | 32 | .SECONDARY: 33 | .PHONY: all prog clean 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SRAM on the mystorm blackice 2 | 3 | [mystorm](https://mystorm.uk/) blackice has 0.5MByte SRAM on the back of the board 4 | 5 | [datasheet for SRAM](ram.pdf) 6 | 7 | [mystorm blackice schematic](mystorm.pdf) 8 | 9 | From datasheet: ISSI IS62WV25616DALL and IS62/65WV25616DBLL are high-speed, low power, 4M bit SRAMs organized as 256K words by 16 bits. 10 | 11 | ## verilog 12 | 13 | * extremely simple test of the SRAM 14 | * state machine for read and write 15 | * everything done in 1 cycle as 1 cycle at 12MHz is slower than max read/write 16 | time of the SRAM. 17 | 18 | [sram.v](sram.v) 19 | 20 | ## current status 21 | 22 | * working at 12MHz system clock 23 | * test reads then writes to first 2^16 words 24 | * data written is the current address 25 | * bits 14:11 of the data is shown on the boards's 4 leds 26 | * [boring test video](https://goo.gl/photos/QZVVtneaXWpWAp4N6) 27 | 28 | ## testbench 29 | 30 | [sram_tb.v](sram_tb.v) 31 | 32 | ![gtkwave screenshot](sram.png) 33 | 34 | ## problems 35 | 36 | 2 pins on the data bus collide with pins of the PLLs. When the PLL is 37 | activated, those pins can no longer be inout, they must be either in or out. 38 | [More details here](https://github.com/cseed/arachne-pnr/issues/64#issuecomment-310877601) 39 | -------------------------------------------------------------------------------- /blackice.pcf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## # 3 | ## Copyright 2016 myStorm Copyright and related # 4 | ## rights are licensed under the Solderpad Hardware License, Version 0.51 # 5 | ## (the “License”); you may not use this file except in compliance with # 6 | ## the License. You may obtain a copy of the License at # 7 | ## http://solderpad.org/licenses/SHL-0.51. Unless required by applicable # 8 | ## law or agreed to in writing, software, hardware and materials # 9 | ## distributed under this License is distributed on an “AS IS” BASIS, # 10 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # 11 | ## implied. See the License for the specific language governing # 12 | ## permissions and limitations under the License. # 13 | ## # 14 | ################################################################################ 15 | # 16 | ## User Constraint File for myStorm 17 | # 18 | ##pmod 1 19 | # 20 | #set_io PMOD[0] 94 # rd6 21 | #set_io PMOD[1] 91 # rd4 22 | #set_io PMOD[2] 88 # rd2 23 | #set_io PMOD[3] 85 # rd0 24 | # 25 | ##pmod 2 26 | #set_io PMOD[4] 95 # rd7 27 | #set_io PMOD[5] 93 # rd5 28 | #set_io PMOD[6] 90 # rd3 29 | #set_io PMOD[7] 87 # rd1 30 | # 31 | ##pmod 3 GPIO 32 | #set_io PMOD[8] 105 # c5 33 | #set_io PMOD[9] 102 # c3 34 | #set_io PMOD[10] 99 # c1 35 | #set_io PMOD[11] 97 # i_tx 36 | # 37 | ##pmod 4 38 | #set_io PMOD[12] 104 # c4 39 | #set_io PMOD[13] 101 # c2 40 | #set_io PMOD[14] 98 # c0 41 | #set_io PMOD[15] 96 # i_rx 42 | # 43 | ##pmod 5 GPIO 44 | #set_io PMOD[16] 143 #g2 45 | #set_io PMOD[17] 114 #c11 46 | #set_io PMOD[18] 112 #c9 47 | #set_io PMOD[19] 107 #c7 48 | # 49 | ##pmod 6 GPIO 50 | #set_io PMOD[20] 144 #G1 51 | #set_io PMOD[21] 113 #C10 52 | #set_io PMOD[22] 110 #C8 53 | #set_io PMOD[23] 106 #C6 54 | # 55 | ##pmod 7 lvds pairs 2 & 5 56 | #set_io PMOD[24] 10 # 5b 57 | #set_io PMOD[25] 9 # 5a 58 | #set_io PMOD[26] 2 # 2b 59 | #set_io PMOD[27] 1 # 2a 60 | # 61 | ##pmod 8 lvds pairs 3 & 4 62 | #set_io PMOD[28] 8 # 4b 63 | #set_io PMOD[29] 7 # 4a 64 | #set_io PMOD[30] 4 # 3b 65 | #set_io PMOD[31] 3 # 3a 66 | # 67 | ##pmod 9 lvds pairs 10 & 13 68 | #set_io PMOD[32] 20 # 13b 69 | #set_io PMOD[33] 19 # 13a 70 | #set_io PMOD[34] 16 # 10b 71 | #set_io PMOD[35] 15 # 10a 72 | # 73 | ##pmod 10 lvds pairs 8 & 12 74 | #set_io PMOD[36] 18 # 12b 75 | #set_io PMOD[37] 17 # 12a 76 | #set_io PMOD[38] 12 # 8b 77 | #set_io PMOD[39] 11 # 8a 78 | # 79 | ##pmod 11 lvds pairs 14 & 25 80 | #set_io PMOD[40] 34 # 25b 81 | #set_io PMOD[41] 33 # 25a 82 | #set_io PMOD[42] 22 # 14B 83 | #set_io PMOD[43] 21 # 14a 84 | # 85 | ##pmod 12 lvds pairs 18 & 24 86 | #set_io PMOD[44] 32 # 24b 87 | #set_io PMOD[45] 31 # 24a 88 | #set_io PMOD[46] 26 # 18b 89 | #set_io PMOD[47] 25 # 18a 90 | # 91 | ##pmod 13 lvds pairs 17 & 23 92 | #set_io PMOD[48] 29 # 23b 93 | #set_io PMOD[49] 28 # 23a 94 | #set_io PMOD[50] 24 # 17b 95 | #set_io PMOD[51] 23 # 17a 96 | # 97 | #pmod 14 SPI muxed with leds 98 | #set_io PMOD[52] 71 #LD4,!SS,p14_1 99 | #set_io PMOD[53] 67 #LD3,MISO,p14_2 100 | #set_io PMOD[54] 68 #LD2,MOSI,p14_3 101 | #set_io PMOD[55] 70 #LD1,SCL,p14_4 102 | # 103 | # SRAM 104 | set_io ADR[0] 137 105 | set_io ADR[1] 138 106 | set_io ADR[2] 139 107 | set_io ADR[3] 141 108 | set_io ADR[4] 142 109 | set_io ADR[5] 42 110 | set_io ADR[6] 43 111 | set_io ADR[7] 44 112 | set_io ADR[8] 73 113 | set_io ADR[9] 74 114 | set_io ADR[10] 75 115 | set_io ADR[11] 76 116 | set_io ADR[12] 115 117 | set_io ADR[13] 116 118 | set_io ADR[14] 117 119 | set_io ADR[15] 118 120 | set_io ADR[16] 119 121 | set_io ADR[17] 78 122 | #set_io ADR[18] 62 123 | 124 | set_io DAT[0] 135 125 | set_io DAT[1] 134 126 | set_io DAT[2] 130 127 | set_io DAT[3] 128 128 | set_io DAT[4] 125 129 | set_io DAT[5] 124 130 | set_io DAT[6] 122 131 | set_io DAT[7] 121 132 | set_io DAT[8] 61 133 | set_io DAT[9] 60 134 | set_io DAT[10] 56 135 | set_io DAT[11] 55 136 | set_io DAT[12] 52 137 | set_io DAT[13] 49 138 | set_io DAT[14] 48 139 | set_io DAT[15] 47 140 | 141 | set_io RAMOE 45 142 | set_io RAMWE 120 143 | set_io RAMCS 136 144 | 145 | ## Onboard 12Mhz oscillator 146 | set_io clk 129 147 | set_io PMOD[0] 71 #LD4,!SS,p14_1 148 | set_io PMOD[1] 67 #LD3,MISO,p14_2 149 | set_io PMOD[2] 68 #LD2,MOSI,p14_3 150 | set_io PMOD[3] 70 #LD1,SCL,p14_4 151 | # 152 | -------------------------------------------------------------------------------- /clockdiv.v: -------------------------------------------------------------------------------- 1 | module clk_divn #( 2 | parameter WIDTH = 3, 3 | parameter N = 5) 4 | 5 | (clk,reset, clk_out); 6 | 7 | input clk; 8 | input reset; 9 | output clk_out; 10 | 11 | reg [WIDTH-1:0] pos_count, neg_count; 12 | wire [WIDTH-1:0] r_nxt; 13 | 14 | always @(posedge clk) 15 | if (reset) 16 | pos_count <=0; 17 | else if (pos_count ==N-1) pos_count <= 0; 18 | else pos_count<= pos_count +1; 19 | 20 | always @(negedge clk) 21 | if (reset) 22 | neg_count <=0; 23 | else if (neg_count ==N-1) neg_count <= 0; 24 | else neg_count<= neg_count +1; 25 | 26 | assign clk_out = ((pos_count > (N>>1)) | (neg_count > (N>>1))); 27 | endmodule 28 | -------------------------------------------------------------------------------- /dvid_tb.v: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | reg clk = 0; 4 | reg clkx5 = 0; 5 | wire hsync; 6 | wire vsync; 7 | wire blank; 8 | wire [2:0] red; 9 | wire [2:0] green; 10 | wire [2:0] blue; 11 | 12 | /* Make a reset that pulses once. */ 13 | initial begin 14 | $dumpfile("test.vcd"); 15 | $dumpvars(0, 16 | dvid_test.ctls[0], 17 | dvid_test.symbols[0], 18 | dvid_test.symbols[1], 19 | dvid_test.symbols[2], 20 | dvid_test.symbols[3], 21 | dvid_test.high_speed_sr[0], 22 | dvid_test.high_speed_sr[1], 23 | dvid_test.high_speed_sr[2], 24 | dvid_test.high_speed_sr[3], 25 | dvid_test.output_bits[0], 26 | dvid_test.output_bits[1], 27 | dvid_test.output_bits[2], 28 | dvid_test.output_bits[3], 29 | test); 30 | // $dumpoff; 31 | // # 2000000; 32 | $dumpon; 33 | # 20000; 34 | $finish; 35 | end 36 | 37 | vga vga_test(.clk(clk), .hsync(hsync), .vsync(vsync), .blank(blank), .red(red), .green(green), .blue(blue)); 38 | 39 | dvid dvid_test(.clk(clk), .clkx5(clkx5), .hsync(hsync), .vsync(vsync), .blank(blank), .red(red), .green(green), .blue(blue)); 40 | 41 | /* Make a regular pulsing clock. */ 42 | always #1 clkx5 = !clkx5; 43 | always #5 clk = !clk; 44 | 45 | endmodule // test 46 | 47 | -------------------------------------------------------------------------------- /mystorm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattvenn/fpga-sram/8dbcb2dcdfd2619d03f841a24796ab8a9e6810e0/mystorm.pdf -------------------------------------------------------------------------------- /ram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattvenn/fpga-sram/8dbcb2dcdfd2619d03f841a24796ab8a9e6810e0/ram.pdf -------------------------------------------------------------------------------- /sram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattvenn/fpga-sram/8dbcb2dcdfd2619d03f841a24796ab8a9e6810e0/sram.png -------------------------------------------------------------------------------- /sram.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | module sram ( 3 | input wire reset, 4 | // 50ns max for data read/write. at 12MHz, each clock cycle is 83ns, so write in 1 cycle 5 | input wire clk, 6 | input wire write, 7 | input wire read, 8 | input wire [15:0] data_write, // the data to write 9 | output wire [15:0] data_read, // the data that's been read 10 | input wire [17:0] address, // address to write to 11 | output wire ready, // high when ready for next operation 12 | output wire data_pins_out_en, // when to switch between in and out on data pins 13 | 14 | // SRAM pins 15 | output wire [17:0] address_pins, // address pins of the SRAM 16 | input wire [15:0] data_pins_in, 17 | output wire [15:0] data_pins_out, 18 | output wire OE, // output enable - low to enable 19 | output wire WE, // write enable - low to enable 20 | output wire CS // chip select - low to enable 21 | ); 22 | 23 | localparam STATE_IDLE = 0; 24 | localparam STATE_WRITE = 1; 25 | localparam STATE_WRITE_SETUP = 4; 26 | localparam STATE_READ_SETUP = 2; 27 | localparam STATE_READ = 3; 28 | 29 | reg output_enable; 30 | reg write_enable; 31 | reg chip_select; 32 | 33 | reg [4:0] state; 34 | reg [15:0] data_read_reg; 35 | reg [15:0] data_write_reg; 36 | 37 | assign data_pins_out_en = (state == STATE_WRITE) ? 1 : 0; // turn on output pins when writing data 38 | assign address_pins = address; 39 | assign data_pins_out = data_write_reg; 40 | assign data_read = data_read_reg; 41 | assign OE = output_enable; 42 | assign WE = write_enable; 43 | assign CS = chip_select; 44 | 45 | assign ready = (!reset && state == STATE_IDLE) ? 1 : 0; 46 | 47 | initial begin 48 | state <= STATE_IDLE; 49 | output_enable <= 1; 50 | chip_select <= 1; 51 | write_enable <= 1; 52 | end 53 | 54 | always@(posedge clk) begin 55 | if( reset == 1 ) begin 56 | state <= STATE_IDLE; 57 | output_enable <= 1; 58 | chip_select <= 1; 59 | write_enable <= 1; 60 | end 61 | else begin 62 | case(state) 63 | STATE_IDLE: begin 64 | output_enable <= 1; 65 | chip_select <= 1; 66 | write_enable <= 1; 67 | if(write) state <= STATE_WRITE_SETUP; 68 | else if(read) state <= STATE_READ_SETUP; 69 | end 70 | STATE_WRITE_SETUP: begin 71 | chip_select <= 0; 72 | data_write_reg <= data_write; 73 | state <= STATE_WRITE; 74 | end 75 | STATE_WRITE: begin 76 | write_enable <= 0; 77 | state <= STATE_IDLE; 78 | end 79 | STATE_READ_SETUP: begin 80 | output_enable <= 0; 81 | chip_select <= 0; 82 | state <= STATE_READ; 83 | end 84 | STATE_READ: begin 85 | data_read_reg <= data_pins_in; 86 | state <= STATE_IDLE; 87 | end 88 | endcase 89 | end 90 | end 91 | 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /sram_tb.v: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | reg clk = 0; 4 | reg reset = 0; 5 | reg write = 0; 6 | reg read = 0; 7 | wire ready; 8 | reg [17:0] address; 9 | wire [15:0] data_read; 10 | reg [15:0] data_write; 11 | output [15:0] data_pins_out; 12 | input [15:0] data_pins_in; 13 | 14 | wire CS; 15 | wire OE; 16 | wire WE; 17 | 18 | reg set_data = 0; 19 | assign data_pins_in = set_data ? 16'h0A0A : 16'hzz; 20 | initial begin 21 | $dumpfile("test.vcd"); 22 | $dumpvars(0,test); 23 | $dumpon; 24 | # 1 reset = 1; 25 | # 2 reset = 0; 26 | // write 27 | # 1 address = 17'h0; 28 | # 1 data_write = 16'hAAAA; 29 | # 2 write = 1; 30 | # 2 write = 0; 31 | wait(ready == 1); 32 | // read 33 | # 1 set_data <= 1; 34 | # 2 read = 1; 35 | # 2 read = 0; 36 | # 20 37 | $finish; 38 | end 39 | 40 | sram sram_test(.clk(clk), .address(address), .data_read(data_read), .data_write(data_write), .write(write), .read(read), .reset(reset), .ready(ready), .data_pins_out(data_pins_out), .data_pins_in(data_pins_in), .OE(OE), .CS(CS), .WE(WE)); 41 | 42 | always #1 clk = !clk; 43 | 44 | endmodule // test 45 | -------------------------------------------------------------------------------- /top.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | module top ( 4 | input clk, 5 | output [3:0] PMOD, 6 | output [17:0] ADR, 7 | inout [15:0] DAT, 8 | output RAMOE, 9 | output RAMWE, 10 | output RAMCS 11 | ); 12 | 13 | wire [15:0] data_pins_in; 14 | wire [15:0] data_pins_out; 15 | wire data_pins_out_en; 16 | 17 | SB_IO #( 18 | .PIN_TYPE(6'b 1010_01), 19 | ) sram_data_pins [15:0] ( 20 | .PACKAGE_PIN(DAT), 21 | .OUTPUT_ENABLE(data_pins_out_en), 22 | .D_OUT_0(data_pins_out), 23 | .D_IN_0(data_pins_in), 24 | ); 25 | 26 | reg slow_clk; 27 | reg [17:0] address; 28 | wire [15:0] data_read; 29 | reg [15:0] data_write; 30 | reg read; 31 | reg write; 32 | reg reset; 33 | reg ready; 34 | reg [15:0] counter; 35 | reg read_write; 36 | 37 | initial begin 38 | read_write <= 0; 39 | read <= 0; 40 | write <= 0; 41 | reset <= 0; 42 | address <= 0; 43 | data_write <= 16'hAAAA; 44 | end 45 | 46 | wire [15:0] data_pins_in; 47 | wire [15:0] data_pins_out; 48 | wire set_data_pins; 49 | 50 | assign PMOD = data_read[14:11]; 51 | 52 | sram sram_test(.clk(clk), .address(address), .data_read(data_read), .data_write(data_write), .write(write), .read(read), .reset(reset), .ready(ready), 53 | .data_pins_in(data_pins_in), 54 | .data_pins_out(data_pins_out), 55 | .data_pins_out_en(data_pins_out_en), 56 | .address_pins(ADR), 57 | .OE(RAMOE), .WE(RAMWE), .CS(RAMCS)); 58 | 59 | clk_divn #(.WIDTH(32), .N(1000)) 60 | clockdiv_slow(.clk(clk), .clk_out(slow_clk)); 61 | 62 | always @(posedge slow_clk) begin 63 | address <= counter; 64 | if(read_write) begin 65 | if(ready) begin 66 | counter <= counter + 1; 67 | read <= 1; 68 | end else 69 | read <= 0; 70 | end else begin 71 | if(ready) begin 72 | data_write <= counter; 73 | counter <= counter + 1; 74 | write <= 1; 75 | end else 76 | write <= 0; 77 | end 78 | // flip each cycle of the counter 79 | if(counter == 0) 80 | read_write <= read_write ? 0 : 1; 81 | end 82 | endmodule 83 | --------------------------------------------------------------------------------