lm32_ram.v

Sun, 04 Apr 2010 20:40:03 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 04 Apr 2010 20:40:03 +0100
changeset 0
cd0b58aa6f83
child 2
a61bb364ae1f
child 26
73de224304c1
permissions
-rw-r--r--

add lm32 source

philpem@0 1 // =============================================================================
philpem@0 2 // COPYRIGHT NOTICE
philpem@0 3 // Copyright 2006 (c) Lattice Semiconductor Corporation
philpem@0 4 // ALL RIGHTS RESERVED
philpem@0 5 // This confidential and proprietary software may be used only as authorised by
philpem@0 6 // a licensing agreement from Lattice Semiconductor Corporation.
philpem@0 7 // The entire notice above must be reproduced on all authorized copies and
philpem@0 8 // copies may only be made to the extent permitted by a licensing agreement from
philpem@0 9 // Lattice Semiconductor Corporation.
philpem@0 10 //
philpem@0 11 // Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
philpem@0 12 // 5555 NE Moore Court 408-826-6000 (other locations)
philpem@0 13 // Hillsboro, OR 97124 web : http://www.latticesemi.com/
philpem@0 14 // U.S.A email: techsupport@latticesemi.com
philpem@0 15 // =============================================================================/
philpem@0 16 // FILE DETAILS
philpem@0 17 // Project : LatticeMico32
philpem@0 18 // File : lm32_ram.v
philpem@0 19 // Title : Pseudo dual-port RAM.
philpem@0 20 // Version : 6.1.17
philpem@0 21 // : Initial Release
philpem@0 22 // Version : 7.0SP2, 3.0
philpem@0 23 // : No Change
philpem@0 24 // Version : 3.1
philpem@0 25 // : Options added to select EBRs (True-DP, Psuedo-DP, DQ, or
philpem@0 26 // : Distributed RAM).
philpem@0 27 // Version : 3.2
philpem@0 28 // : EBRs use SYNC resets instead of ASYNC resets.
philpem@0 29 // Version : 3.5
philpem@0 30 // : Added read-after-write hazard resolution when using true
philpem@0 31 // : dual-port EBRs
philpem@0 32 // =============================================================================
philpem@0 33
philpem@0 34 `include "lm32_include.v"
philpem@0 35
philpem@0 36 /////////////////////////////////////////////////////
philpem@0 37 // Module interface
philpem@0 38 /////////////////////////////////////////////////////
philpem@0 39
philpem@0 40 module lm32_ram
philpem@0 41 (
philpem@0 42 // ----- Inputs -------
philpem@0 43 read_clk,
philpem@0 44 write_clk,
philpem@0 45 reset,
philpem@0 46 enable_read,
philpem@0 47 read_address,
philpem@0 48 enable_write,
philpem@0 49 write_address,
philpem@0 50 write_data,
philpem@0 51 write_enable,
philpem@0 52 // ----- Outputs -------
philpem@0 53 read_data
philpem@0 54 );
philpem@0 55
philpem@0 56 /*----------------------------------------------------------------------
philpem@0 57 Parameters
philpem@0 58 ----------------------------------------------------------------------*/
philpem@0 59 parameter data_width = 1; // Width of the data ports
philpem@0 60 parameter address_width = 1; // Width of the address ports
philpem@0 61 parameter RAM_IMPLEMENTATION = "AUTO"; // Implement memory in EBRs, else
philpem@0 62 // let synthesis tool select best
philpem@0 63 // possible solution (EBR or LUT)
philpem@0 64 parameter RAM_TYPE = "RAM_DP"; // Type of EBR to be used
philpem@0 65
philpem@0 66 /*----------------------------------------------------------------------
philpem@0 67 Inputs
philpem@0 68 ----------------------------------------------------------------------*/
philpem@0 69 input read_clk; // Read clock
philpem@0 70 input write_clk; // Write clock
philpem@0 71 input reset; // Reset
philpem@0 72
philpem@0 73 input enable_read; // Access enable
philpem@0 74 input [address_width-1:0] read_address; // Read/write address
philpem@0 75 input enable_write; // Access enable
philpem@0 76 input [address_width-1:0] write_address;// Read/write address
philpem@0 77 input [data_width-1:0] write_data; // Data to write to specified address
philpem@0 78 input write_enable; // Write enable
philpem@0 79
philpem@0 80 /*----------------------------------------------------------------------
philpem@0 81 Outputs
philpem@0 82 ----------------------------------------------------------------------*/
philpem@0 83 output [data_width-1:0] read_data; // Data read from specified addess
philpem@0 84 wire [data_width-1:0] read_data;
philpem@0 85
philpem@0 86 generate
philpem@0 87
philpem@0 88 if ( RAM_IMPLEMENTATION == "EBR" )
philpem@0 89 begin
philpem@0 90 if ( RAM_TYPE == "RAM_DP" )
philpem@0 91 begin
philpem@0 92 pmi_ram_dp
philpem@0 93 #(
philpem@0 94 // ----- Parameters -----
philpem@0 95 .pmi_wr_addr_depth(1<<address_width),
philpem@0 96 .pmi_wr_addr_width(address_width),
philpem@0 97 .pmi_wr_data_width(data_width),
philpem@0 98 .pmi_rd_addr_depth(1<<address_width),
philpem@0 99 .pmi_rd_addr_width(address_width),
philpem@0 100 .pmi_rd_data_width(data_width),
philpem@0 101 .pmi_regmode("noreg"),
philpem@0 102 .pmi_gsr("enable"),
philpem@0 103 .pmi_resetmode("sync"),
philpem@0 104 .pmi_init_file("none"),
philpem@0 105 .pmi_init_file_format("binary"),
philpem@0 106 .pmi_family(`LATTICE_FAMILY),
philpem@0 107 .module_type("pmi_ram_dp")
philpem@0 108 )
philpem@0 109 lm32_ram_inst
philpem@0 110 (
philpem@0 111 // ----- Inputs -----
philpem@0 112 .Data(write_data),
philpem@0 113 .WrAddress(write_address),
philpem@0 114 .RdAddress(read_address),
philpem@0 115 .WrClock(write_clk),
philpem@0 116 .RdClock(read_clk),
philpem@0 117 .WrClockEn(enable_write),
philpem@0 118 .RdClockEn(enable_read),
philpem@0 119 .WE(write_enable),
philpem@0 120 .Reset(reset),
philpem@0 121 // ----- Outputs -----
philpem@0 122 .Q(read_data)
philpem@0 123 );
philpem@0 124 end
philpem@0 125 else
philpem@0 126 begin
philpem@0 127 // True Dual-Port EBR
philpem@0 128 wire [data_width-1:0] read_data_A, read_data_B;
philpem@0 129 reg [data_width-1:0] raw_data, raw_data_nxt;
philpem@0 130 reg raw, raw_nxt;
philpem@0 131
philpem@0 132 /*----------------------------------------------------------------------
philpem@0 133 Is a read being performed in the same cycle as a write? Indicate this
philpem@0 134 event with a RAW hazard signal that is released only when a new read
philpem@0 135 or write occurs later.
philpem@0 136 ----------------------------------------------------------------------*/
philpem@0 137 always @(/*AUTOSENSE*/enable_read or enable_write
philpem@0 138 or raw or raw_data or read_address
philpem@0 139 or write_address or write_data
philpem@0 140 or write_enable)
philpem@0 141 if (// Read
philpem@0 142 enable_read
philpem@0 143 // Write
philpem@0 144 && enable_write && write_enable
philpem@0 145 // Read and write address match
philpem@0 146 && (read_address == write_address))
philpem@0 147 begin
philpem@0 148 raw_data_nxt = write_data;
philpem@0 149 raw_nxt = 1'b1;
philpem@0 150 end
philpem@0 151 else
philpem@0 152 if (raw && (enable_read == 1'b0) && (enable_write == 1'b0))
philpem@0 153 begin
philpem@0 154 raw_data_nxt = raw_data;
philpem@0 155 raw_nxt = 1'b1;
philpem@0 156 end
philpem@0 157 else
philpem@0 158 begin
philpem@0 159 raw_data_nxt = raw_data;
philpem@0 160 raw_nxt = 1'b0;
philpem@0 161 end
philpem@0 162
philpem@0 163 // Send back write data in case of a RAW hazard; else send back
philpem@0 164 // data from memory
philpem@0 165 assign read_data = raw ? raw_data : read_data_B;
philpem@0 166
philpem@0 167 /*----------------------------------------------------------------------
philpem@0 168 Sequential Logic
philpem@0 169 ----------------------------------------------------------------------*/
philpem@0 170 always @(posedge read_clk)
philpem@0 171 if (reset)
philpem@0 172 begin
philpem@0 173 raw_data <= #1 0;
philpem@0 174 raw <= #1 1'b0;
philpem@0 175 end
philpem@0 176 else
philpem@0 177 begin
philpem@0 178 raw_data <= #1 raw_data_nxt;
philpem@0 179 raw <= #1 raw_nxt;
philpem@0 180 end
philpem@0 181
philpem@0 182 pmi_ram_dp_true
philpem@0 183 #(
philpem@0 184 // ----- Parameters -----
philpem@0 185 .pmi_addr_depth_a(1<<address_width),
philpem@0 186 .pmi_addr_width_a(address_width),
philpem@0 187 .pmi_data_width_a(data_width),
philpem@0 188 .pmi_addr_depth_b(1<<address_width),
philpem@0 189 .pmi_addr_width_b(address_width),
philpem@0 190 .pmi_data_width_b(data_width),
philpem@0 191 .pmi_regmode_a("noreg"),
philpem@0 192 .pmi_regmode_b("noreg"),
philpem@0 193 .pmi_gsr("enable"),
philpem@0 194 .pmi_resetmode("sync"),
philpem@0 195 .pmi_init_file("none"),
philpem@0 196 .pmi_init_file_format("binary"),
philpem@0 197 .pmi_family(`LATTICE_FAMILY),
philpem@0 198 .module_type("pmi_ram_dp_true")
philpem@0 199 )
philpem@0 200 lm32_ram_inst
philpem@0 201 (
philpem@0 202 // ----- Inputs -----
philpem@0 203 .DataInA(write_data),
philpem@0 204 .DataInB(write_data),
philpem@0 205 .AddressA(write_address),
philpem@0 206 .AddressB(read_address),
philpem@0 207 .ClockA(write_clk),
philpem@0 208 .ClockB(read_clk),
philpem@0 209 .ClockEnA(enable_write),
philpem@0 210 .ClockEnB(enable_read),
philpem@0 211 .WrA(write_enable),
philpem@0 212 .WrB(`FALSE),
philpem@0 213 .ResetA(reset),
philpem@0 214 .ResetB(reset),
philpem@0 215 // ----- Outputs -----
philpem@0 216 .QA(read_data_A),
philpem@0 217 .QB(read_data_B)
philpem@0 218 );
philpem@0 219 end
philpem@0 220 end
philpem@0 221 else if ( RAM_IMPLEMENTATION == "SLICE" )
philpem@0 222 begin
philpem@0 223 reg [address_width-1:0] ra; // Registered read address
philpem@0 224
philpem@0 225 pmi_distributed_dpram
philpem@0 226 #(
philpem@0 227 // ----- Parameters -----
philpem@0 228 .pmi_addr_depth(1<<address_width),
philpem@0 229 .pmi_addr_width(address_width),
philpem@0 230 .pmi_data_width(data_width),
philpem@0 231 .pmi_regmode("noreg"),
philpem@0 232 .pmi_init_file("none"),
philpem@0 233 .pmi_init_file_format("binary"),
philpem@0 234 .pmi_family(`LATTICE_FAMILY),
philpem@0 235 .module_type("pmi_distributed_dpram")
philpem@0 236 )
philpem@0 237 pmi_distributed_dpram_inst
philpem@0 238 (
philpem@0 239 // ----- Inputs -----
philpem@0 240 .WrAddress(write_address),
philpem@0 241 .Data(write_data),
philpem@0 242 .WrClock(write_clk),
philpem@0 243 .WE(write_enable),
philpem@0 244 .WrClockEn(enable_write),
philpem@0 245 .RdAddress(ra),
philpem@0 246 .RdClock(read_clk),
philpem@0 247 .RdClockEn(enable_read),
philpem@0 248 .Reset(reset),
philpem@0 249 // ----- Outputs -----
philpem@0 250 .Q(read_data)
philpem@0 251 );
philpem@0 252
philpem@0 253 always @(posedge read_clk)
philpem@0 254 if (enable_read)
philpem@0 255 ra <= read_address;
philpem@0 256 end
philpem@0 257
philpem@0 258 else
philpem@0 259 begin
philpem@0 260 /*----------------------------------------------------------------------
philpem@0 261 Internal nets and registers
philpem@0 262 ----------------------------------------------------------------------*/
philpem@0 263 reg [data_width-1:0] mem[0:(1<<address_width)-1]; // The RAM
philpem@0 264 reg [address_width-1:0] ra; // Registered read address
philpem@0 265
philpem@0 266 /*----------------------------------------------------------------------
philpem@0 267 Combinational Logic
philpem@0 268 ----------------------------------------------------------------------*/
philpem@0 269 // Read port
philpem@0 270 assign read_data = mem[ra];
philpem@0 271
philpem@0 272 /*----------------------------------------------------------------------
philpem@0 273 Sequential Logic
philpem@0 274 ----------------------------------------------------------------------*/
philpem@0 275 // Write port
philpem@0 276 always @(posedge write_clk)
philpem@0 277 if ((write_enable == `TRUE) && (enable_write == `TRUE))
philpem@0 278 mem[write_address] <= write_data;
philpem@0 279
philpem@0 280 // Register read address for use on next cycle
philpem@0 281 always @(posedge read_clk)
philpem@0 282 if (enable_read)
philpem@0 283 ra <= read_address;
philpem@0 284
philpem@0 285 end
philpem@0 286
philpem@0 287 endgenerate
philpem@0 288
philpem@0 289 endmodule