lm32_ram.v

Sun, 04 Apr 2010 20:52:32 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 04 Apr 2010 20:52:32 +0100
changeset 2
a61bb364ae1f
parent 0
cd0b58aa6f83
permissions
-rw-r--r--

Disable Lattice-specific stuff by default

To build on Lattice platforms, `define PLATFORM_LATTICE in lm32_include.v.
Otherwise, non-optimal "platform independent" HDL will be used.
This means LM32 can now be built for non-Lattice FPGAs.

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@2 61 `ifdef PLATFORM_LATTICE
philpem@0 62 parameter RAM_IMPLEMENTATION = "AUTO"; // Implement memory in EBRs, else
philpem@0 63 // let synthesis tool select best
philpem@0 64 // possible solution (EBR or LUT)
philpem@0 65 parameter RAM_TYPE = "RAM_DP"; // Type of EBR to be used
philpem@2 66 `endif
philpem@0 67
philpem@0 68 /*----------------------------------------------------------------------
philpem@0 69 Inputs
philpem@0 70 ----------------------------------------------------------------------*/
philpem@0 71 input read_clk; // Read clock
philpem@0 72 input write_clk; // Write clock
philpem@0 73 input reset; // Reset
philpem@0 74
philpem@0 75 input enable_read; // Access enable
philpem@0 76 input [address_width-1:0] read_address; // Read/write address
philpem@0 77 input enable_write; // Access enable
philpem@0 78 input [address_width-1:0] write_address;// Read/write address
philpem@0 79 input [data_width-1:0] write_data; // Data to write to specified address
philpem@0 80 input write_enable; // Write enable
philpem@0 81
philpem@0 82 /*----------------------------------------------------------------------
philpem@0 83 Outputs
philpem@0 84 ----------------------------------------------------------------------*/
philpem@0 85 output [data_width-1:0] read_data; // Data read from specified addess
philpem@0 86 wire [data_width-1:0] read_data;
philpem@2 87
philpem@2 88 `ifdef PLATFORM_LATTICE
philpem@0 89 generate
philpem@0 90
philpem@0 91 if ( RAM_IMPLEMENTATION == "EBR" )
philpem@0 92 begin
philpem@0 93 if ( RAM_TYPE == "RAM_DP" )
philpem@0 94 begin
philpem@0 95 pmi_ram_dp
philpem@0 96 #(
philpem@0 97 // ----- Parameters -----
philpem@0 98 .pmi_wr_addr_depth(1<<address_width),
philpem@0 99 .pmi_wr_addr_width(address_width),
philpem@0 100 .pmi_wr_data_width(data_width),
philpem@0 101 .pmi_rd_addr_depth(1<<address_width),
philpem@0 102 .pmi_rd_addr_width(address_width),
philpem@0 103 .pmi_rd_data_width(data_width),
philpem@0 104 .pmi_regmode("noreg"),
philpem@0 105 .pmi_gsr("enable"),
philpem@0 106 .pmi_resetmode("sync"),
philpem@0 107 .pmi_init_file("none"),
philpem@0 108 .pmi_init_file_format("binary"),
philpem@0 109 .pmi_family(`LATTICE_FAMILY),
philpem@0 110 .module_type("pmi_ram_dp")
philpem@0 111 )
philpem@0 112 lm32_ram_inst
philpem@0 113 (
philpem@0 114 // ----- Inputs -----
philpem@0 115 .Data(write_data),
philpem@0 116 .WrAddress(write_address),
philpem@0 117 .RdAddress(read_address),
philpem@0 118 .WrClock(write_clk),
philpem@0 119 .RdClock(read_clk),
philpem@0 120 .WrClockEn(enable_write),
philpem@0 121 .RdClockEn(enable_read),
philpem@0 122 .WE(write_enable),
philpem@0 123 .Reset(reset),
philpem@0 124 // ----- Outputs -----
philpem@0 125 .Q(read_data)
philpem@0 126 );
philpem@0 127 end
philpem@0 128 else
philpem@0 129 begin
philpem@0 130 // True Dual-Port EBR
philpem@0 131 wire [data_width-1:0] read_data_A, read_data_B;
philpem@0 132 reg [data_width-1:0] raw_data, raw_data_nxt;
philpem@0 133 reg raw, raw_nxt;
philpem@0 134
philpem@0 135 /*----------------------------------------------------------------------
philpem@0 136 Is a read being performed in the same cycle as a write? Indicate this
philpem@0 137 event with a RAW hazard signal that is released only when a new read
philpem@0 138 or write occurs later.
philpem@0 139 ----------------------------------------------------------------------*/
philpem@0 140 always @(/*AUTOSENSE*/enable_read or enable_write
philpem@0 141 or raw or raw_data or read_address
philpem@0 142 or write_address or write_data
philpem@0 143 or write_enable)
philpem@0 144 if (// Read
philpem@0 145 enable_read
philpem@0 146 // Write
philpem@0 147 && enable_write && write_enable
philpem@0 148 // Read and write address match
philpem@0 149 && (read_address == write_address))
philpem@0 150 begin
philpem@0 151 raw_data_nxt = write_data;
philpem@0 152 raw_nxt = 1'b1;
philpem@0 153 end
philpem@0 154 else
philpem@0 155 if (raw && (enable_read == 1'b0) && (enable_write == 1'b0))
philpem@0 156 begin
philpem@0 157 raw_data_nxt = raw_data;
philpem@0 158 raw_nxt = 1'b1;
philpem@0 159 end
philpem@0 160 else
philpem@0 161 begin
philpem@0 162 raw_data_nxt = raw_data;
philpem@0 163 raw_nxt = 1'b0;
philpem@0 164 end
philpem@0 165
philpem@0 166 // Send back write data in case of a RAW hazard; else send back
philpem@0 167 // data from memory
philpem@0 168 assign read_data = raw ? raw_data : read_data_B;
philpem@0 169
philpem@0 170 /*----------------------------------------------------------------------
philpem@0 171 Sequential Logic
philpem@0 172 ----------------------------------------------------------------------*/
philpem@0 173 always @(posedge read_clk)
philpem@0 174 if (reset)
philpem@0 175 begin
philpem@0 176 raw_data <= #1 0;
philpem@0 177 raw <= #1 1'b0;
philpem@0 178 end
philpem@0 179 else
philpem@0 180 begin
philpem@0 181 raw_data <= #1 raw_data_nxt;
philpem@0 182 raw <= #1 raw_nxt;
philpem@0 183 end
philpem@0 184
philpem@0 185 pmi_ram_dp_true
philpem@0 186 #(
philpem@0 187 // ----- Parameters -----
philpem@0 188 .pmi_addr_depth_a(1<<address_width),
philpem@0 189 .pmi_addr_width_a(address_width),
philpem@0 190 .pmi_data_width_a(data_width),
philpem@0 191 .pmi_addr_depth_b(1<<address_width),
philpem@0 192 .pmi_addr_width_b(address_width),
philpem@0 193 .pmi_data_width_b(data_width),
philpem@0 194 .pmi_regmode_a("noreg"),
philpem@0 195 .pmi_regmode_b("noreg"),
philpem@0 196 .pmi_gsr("enable"),
philpem@0 197 .pmi_resetmode("sync"),
philpem@0 198 .pmi_init_file("none"),
philpem@0 199 .pmi_init_file_format("binary"),
philpem@0 200 .pmi_family(`LATTICE_FAMILY),
philpem@0 201 .module_type("pmi_ram_dp_true")
philpem@0 202 )
philpem@0 203 lm32_ram_inst
philpem@0 204 (
philpem@0 205 // ----- Inputs -----
philpem@0 206 .DataInA(write_data),
philpem@0 207 .DataInB(write_data),
philpem@0 208 .AddressA(write_address),
philpem@0 209 .AddressB(read_address),
philpem@0 210 .ClockA(write_clk),
philpem@0 211 .ClockB(read_clk),
philpem@0 212 .ClockEnA(enable_write),
philpem@0 213 .ClockEnB(enable_read),
philpem@0 214 .WrA(write_enable),
philpem@0 215 .WrB(`FALSE),
philpem@0 216 .ResetA(reset),
philpem@0 217 .ResetB(reset),
philpem@0 218 // ----- Outputs -----
philpem@0 219 .QA(read_data_A),
philpem@0 220 .QB(read_data_B)
philpem@0 221 );
philpem@0 222 end
philpem@0 223 end
philpem@0 224 else if ( RAM_IMPLEMENTATION == "SLICE" )
philpem@0 225 begin
philpem@0 226 reg [address_width-1:0] ra; // Registered read address
philpem@0 227
philpem@0 228 pmi_distributed_dpram
philpem@0 229 #(
philpem@0 230 // ----- Parameters -----
philpem@0 231 .pmi_addr_depth(1<<address_width),
philpem@0 232 .pmi_addr_width(address_width),
philpem@0 233 .pmi_data_width(data_width),
philpem@0 234 .pmi_regmode("noreg"),
philpem@0 235 .pmi_init_file("none"),
philpem@0 236 .pmi_init_file_format("binary"),
philpem@0 237 .pmi_family(`LATTICE_FAMILY),
philpem@0 238 .module_type("pmi_distributed_dpram")
philpem@0 239 )
philpem@0 240 pmi_distributed_dpram_inst
philpem@0 241 (
philpem@0 242 // ----- Inputs -----
philpem@0 243 .WrAddress(write_address),
philpem@0 244 .Data(write_data),
philpem@0 245 .WrClock(write_clk),
philpem@0 246 .WE(write_enable),
philpem@0 247 .WrClockEn(enable_write),
philpem@0 248 .RdAddress(ra),
philpem@0 249 .RdClock(read_clk),
philpem@0 250 .RdClockEn(enable_read),
philpem@0 251 .Reset(reset),
philpem@0 252 // ----- Outputs -----
philpem@0 253 .Q(read_data)
philpem@0 254 );
philpem@0 255
philpem@0 256 always @(posedge read_clk)
philpem@0 257 if (enable_read)
philpem@0 258 ra <= read_address;
philpem@0 259 end
philpem@0 260
philpem@0 261 else
philpem@0 262 begin
philpem@2 263 `endif
philpem@0 264 /*----------------------------------------------------------------------
philpem@0 265 Internal nets and registers
philpem@0 266 ----------------------------------------------------------------------*/
philpem@0 267 reg [data_width-1:0] mem[0:(1<<address_width)-1]; // The RAM
philpem@0 268 reg [address_width-1:0] ra; // Registered read address
philpem@0 269
philpem@0 270 /*----------------------------------------------------------------------
philpem@0 271 Combinational Logic
philpem@0 272 ----------------------------------------------------------------------*/
philpem@0 273 // Read port
philpem@0 274 assign read_data = mem[ra];
philpem@0 275
philpem@0 276 /*----------------------------------------------------------------------
philpem@0 277 Sequential Logic
philpem@0 278 ----------------------------------------------------------------------*/
philpem@0 279 // Write port
philpem@0 280 always @(posedge write_clk)
philpem@0 281 if ((write_enable == `TRUE) && (enable_write == `TRUE))
philpem@0 282 mem[write_address] <= write_data;
philpem@0 283
philpem@0 284 // Register read address for use on next cycle
philpem@0 285 always @(posedge read_clk)
philpem@0 286 if (enable_read)
philpem@0 287 ra <= read_address;
philpem@0 288
philpem@2 289 `ifdef PLATFORM_LATTICE
philpem@0 290 end
philpem@0 291
philpem@0 292 endgenerate
philpem@2 293 `endif
philpem@0 294 endmodule