URL
https://opencores.org/ocsvn/common/common/trunk
Subversion Repositories common
Compare Revisions
- This comparison shows the changes necessary to convert path
/common
- from Rev 47 to Rev 48
- ↔ Reverse comparison
Rev 47 → Rev 48
/trunk/opencores_coding_guidelines.doc
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
trunk/opencores_coding_guidelines.doc
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/opencores_coding_guidelines.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/opencores_coding_guidelines.pdf
===================================================================
--- trunk/opencores_coding_guidelines.pdf (nonexistent)
+++ trunk/opencores_coding_guidelines.pdf (revision 48)
trunk/opencores_coding_guidelines.pdf
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/generic_memories/rtl/verilog/generic_dpram.v
===================================================================
--- trunk/generic_memories/rtl/verilog/generic_dpram.v (nonexistent)
+++ trunk/generic_memories/rtl/verilog/generic_dpram.v (revision 48)
@@ -0,0 +1,501 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Generic Dual-Port Synchronous RAM ////
+//// ////
+//// This file is part of memory library available from ////
+//// http://www.opencores.org/cvsweb.shtml/generic_memories/ ////
+//// ////
+//// Description ////
+//// This block is a wrapper with common dual-port ////
+//// synchronous memory interface for different ////
+//// types of ASIC and FPGA RAMs. Beside universal memory ////
+//// interface it also provides behavioral model of generic ////
+//// dual-port synchronous RAM. ////
+//// It also contains a fully synthesizeable model for FPGAs. ////
+//// It should be used in all OPENCORES designs that want to be ////
+//// portable accross different target technologies and ////
+//// independent of target memory. ////
+//// ////
+//// Supported ASIC RAMs are: ////
+//// - Artisan Dual-Port Sync RAM ////
+//// - Avant! Two-Port Sync RAM (*) ////
+//// - Virage 2-port Sync RAM ////
+//// ////
+//// Supported FPGA RAMs are: ////
+//// - Generic FPGA (VENDOR_FPGA) ////
+//// Tested RAMs: Altera, Xilinx ////
+//// Synthesis tools: LeonardoSpectrum, Synplicity ////
+//// - Xilinx (VENDOR_XILINX) ////
+//// - Altera (VENDOR_ALTERA) ////
+//// ////
+//// To Do: ////
+//// - fix Avant! ////
+//// - add additional RAMs (VS etc) ////
+//// ////
+//// Author(s): ////
+//// - Richard Herveille, richard@asics.ws ////
+//// - Damjan Lampret, lampret@opencores.org ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Authors and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from http://www.opencores.org/lgpl.shtml ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.3 2001/11/09 00:34:18 samg
+// minor changes: unified with all common rams
+//
+// Revision 1.2 2001/11/08 19:11:31 samg
+// added valid checks to behvioral model
+//
+// Revision 1.1.1.1 2001/09/14 09:57:10 rherveille
+// Major cleanup.
+// Files are now compliant to Altera & Xilinx memories.
+// Memories are now compatible, i.e. drop-in replacements.
+// Added synthesizeable generic FPGA description.
+// Created "generic_memories" cvs entry.
+//
+// Revision 1.1.1.2 2001/08/21 13:09:27 damjan
+// *** empty log message ***
+//
+// Revision 1.1 2001/08/20 18:23:20 damjan
+// Initial revision
+//
+// Revision 1.1 2001/08/09 13:39:33 lampret
+// Major clean-up.
+//
+// Revision 1.2 2001/07/30 05:38:02 lampret
+// Adding empty directories required by HDL coding guidelines
+//
+//
+
+//`include "timescale.v"
+
+//`define VENDOR_FPGA
+//`define VENDOR_XILINX
+//`define VENDOR_ALTERA
+
+module generic_dpram(
+ // Generic synchronous dual-port RAM interface
+ rclk, rrst, rce, oe, raddr, do,
+ wclk, wrst, wce, we, waddr, di
+);
+
+ //
+ // Default address and data buses width
+ //
+ parameter aw = 5; // number of bits in address-bus
+ parameter dw = 16; // number of bits in data-bus
+
+ //
+ // Generic synchronous double-port RAM interface
+ //
+ // read port
+ input rclk; // read clock, rising edge trigger
+ input rrst; // read port reset, active high
+ input rce; // read port chip enable, active high
+ input oe; // output enable, active high
+ input [aw-1:0] raddr; // read address
+ output [dw-1:0] do; // data output
+
+ // write port
+ input wclk; // write clock, rising edge trigger
+ input wrst; // write port reset, active high
+ input wce; // write port chip enable, active high
+ input we; // write enable, active high
+ input [aw-1:0] waddr; // write address
+ input [dw-1:0] di; // data input
+
+ //
+ // Module body
+ //
+
+`ifdef VENDOR_FPGA
+ //
+ // Instantiation synthesizeable FPGA memory
+ //
+ // This code has been tested using LeonardoSpectrum and Synplicity.
+ // The code correctly instantiates Altera EABs and Xilinx BlockRAMs.
+ //
+ reg [dw-1:0] mem [(1< ////
+//// ////
+//// Module Description: ////
+//// Example of how to convert 8B data to 10B data. ////
+//// Example of how to convert 10B data to 8B data. ////
+//// ////
+//// NOTE: ////
+//// The IBM Patent grew up in a world where the Least ////
+//// Significant Bit of a word was written to the Left. ////
+//// These modules use the LSB as Bit 0, and it will ////
+//// typically be written as the Rightmost bit in a field. ////
+//// ////
+//// NOTE: ////
+//// These modules are based on information contained in ////
+//// "Implementing an 8B/10B Encoder/Decoder for Gigabit ////
+//// Ethernet" by Daniel Elftmann and Jing Hua Ma of Altera. ////
+//// The paper was given in the International IC Tiapei ////
+//// conferance in 1999. ////
+//// ////
+//// A second source of information is XAPP336 titled "Design ////
+//// of a 16B/20B Encoder/Decoder using a Coolrunner CPLD" ////
+//// found on the Xilinx web sire www.xilinx.com ////
+//// ////
+//// The best article describing this is at wildpackets.com ////
+//// http://www.wildpackets.com/compendium/GB/L1-GbEn.html ////
+//// ////
+//// Finally, this is covered in US patent 4,665,517. ////
+//// Unfortunately the US Patent Office online copy has ////
+//// missing figures and the tables are un-readable. ////
+//// ////
+//// Author(s): ////
+//// - Anonymous ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Anonymous and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// $Id: encode_8b_10b.v,v 1.6 2001-11-29 09:22:08 bbeaver Exp $
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.19 2001/11/29 09:31:11 Blue Beaver
+// no message
+//
+// Revision 1.18 2001/10/26 10:39:43 Blue Beaver
+// no message
+//
+// Revision 1.17 2001/10/26 10:38:05 Blue Beaver
+// no message
+//
+// Revision 1.16 2001/10/25 11:43:03 Blue Beaver
+// no message
+//
+// Revision 1.14 2001/10/25 11:33:51 Blue Beaver
+// no message
+//
+// Revision 1.13 2001/10/24 11:38:02 Blue Beaver
+// no message
+//
+// Revision 1.12 2001/10/24 09:47:40 Blue Beaver
+// no message
+//
+// Revision 1.11 2001/10/24 08:49:02 Blue Beaver
+// no message
+//
+// Revision 1.10 2001/10/24 07:28:08 Blue Beaver
+// no message
+//
+// Revision 1.9 2001/10/23 10:34:50 Blue Beaver
+// no message
+//
+// Revision 1.8 2001/10/23 08:12:37 Blue Beaver
+// no message
+//
+// Revision 1.7 2001/10/22 12:36:12 Blue Beaver
+// no message
+//
+// Revision 1.6 2001/10/22 11:54:58 Blue Beaver
+// no message
+//
+// Revision 1.5 2001/10/21 11:37:28 Blue Beaver
+// no message
+//
+// Revision 1.4 2001/10/21 10:17:34 Blue Beaver
+// no message
+//
+// Revision 1.3 2001/10/21 03:40:52 Blue Beaver
+// no message
+//
+// Revision 1.2 2001/10/21 02:27:39 Blue Beaver
+// no message
+//
+// Revision 1.1 2001/10/21 01:36:14 Blue Beaver
+// no message
+//
+//
+//
+
+`timescale 1ns/1ps
+
+
+// These are the codes which are valid to use as control codes.
+// I believe that they have names, but I don't know them.
+// Note K_28_1, K_28_5, and K_28_7 contain Singular Commas.
+`define K_28_0 8'b000_11100
+`define K_28_1 8'b001_11100
+`define K_28_2 8'b010_11100
+`define K_28_3 8'b011_11100
+`define K_28_4 8'b100_11100
+`define K_28_5 8'b101_11100
+`define K_28_6 8'b110_11100
+`define K_28_7 8'b111_11100
+
+`define K_23_7 8'b111_10111
+`define K_27_7 8'b111_11011
+`define K_29_7 8'b111_11101
+`define K_30_7 8'b111_11110
+
+// Convert 8-bit binary or 8-bit control code to 10-bit code
+
+module encode_8b_10b (
+ eight_bit_data_or_control_in,
+ input_is_control,
+ mess_up_link_disparity,
+ ten_bit_encoded_data_out,
+ invalid_control,
+ clk,
+ reset
+);
+
+ input [7:0] eight_bit_data_or_control_in;
+ input input_is_control;
+ input mess_up_link_disparity;
+ output [9:0] ten_bit_encoded_data_out;
+ output invalid_control;
+ input clk, reset;
+
+// Data is treated as 2 fields. The 3 MSB bits are treated as 1 field, and
+// the 5 LSB bits are treated as another field.
+// The 5 LSB bits are encoded as 6 bits. The 3 MSB bits are encoded as 4 bits.
+// The encodings are chosen so that the 10 bits together have either
+// 1) 5 1's and 5 0's,
+// 2) 4 1's and 6 0's,
+// 3 6 1's and 4 0's
+// There are alternative encodings for the cases that the number of 1's and 0's
+// are not balanced. The 8B/10B encoder keeps track of the running disparity
+// between the number of 1's and 0's, and uses alternate encodings to keep
+// the serial signal balanced with no disparity on average.
+//
+// TABLE I 5B/6B ENCODING (NOTE LSB TO LEFT)
+// NAME ABCDE K D-1 abcdei DO ALTERNATE
+// ______________________________________
+// D.0 00000 0 + 011000 - 100111
+// D.1 10000 0 + 100010 - 011101 !
+// D.2 01000 0 + 010010 - 101101 !
+// D.3 11000 0 x 110001 0 !
+// D.4 00100 0 + 001010 - 110101 !
+// D.5 10100 0 x 101001 0 !
+// D.6 01100 0 x 011001 0 !
+// D.7 11100 0 - 111000 0 000111 !
+// D.8 00010 0 + 000110 - 111001 !
+// D.9 10010 0 x 100101 0 !
+// D.10 01010 0 x 010101 0 !
+// D.11 11010 0 x 110100 0 !
+// D.12 00110 0 x 001101 0 !
+// D.13 10110 0 x 101100 0 !
+// D.14 01110 0 x 011100 0 !
+// D.15 11110 0 + 101000 - 010111
+// D.16 00001 0 - 011011 + 100100
+// D.17 10001 0 x 100011 0 !
+// D.18 01001 0 x 010011 0 !
+// D.19 11001 0 x 110010 0 !
+// D.20 00101 0 x 001011 0 !
+// D.21 10101 0 x 101010 0 !
+// D.22 01101 0 x 011010 0 !
+// D.23 11101 x - 111010 + 000101 !
+// D.24 00011 0 + 001100 - 110011
+// D.25 10011 0 x 100110 0 !
+// D.26 01011 0 x 010110 0 !
+// D.27 11011 x - 110110 + 001001 !
+// D.28 00111 0 x 001110 0 !
+// D.29 10111 x - 101110 + 010001 !
+// D.30 01111 x - 011110 + 100001 !
+// D.31 11111 0 - 101011 + 010100
+//
+// K.23 11101 x - 111010 + 000101 !
+// K.27 11011 x - 110110 + 001001 !
+// K.28 00111 1 - 001111 + 110000 !
+// K.29 10111 x - 101110 + 010001 !
+// K.30 01111 x - 011110 + 100001 !
+//
+// TABLE II 3B/4B ENCODING (NOTE LSB TO LEFT)
+// NAME FGH K D-1 fghj DO ALTERNATE
+// ______________________________________
+// D.x.0 000 x + 0100 - 1011
+// D.x.1 100 0 x 1001 0 !
+// D.x.2 010 0 x 0101 0 !
+// D.x.3 110 x - 1100 0 0011 !
+// D.x.4 001 x + 0010 - 1101 !
+// D.x.5 101 0 x 1010 0 !
+// D.x.6 011 0 x 0110 0 !
+// D.x.P7 111 0 - 1110 + 0001 ! Primary
+// D.x.A7 111 x - 0111 + 1000 Alternate
+//
+// K.28.0 000 x + 0100 - 1011
+// K.28.1 100 1 + 1001 0 0110 ! Singular Comma
+// K.28.2 010 1 + 0101 0 1010 !
+// K.28.3 110 x - 1100 0 0011 !
+// K.28.4 001 x + 0010 - 1101 !
+// K.28.5 101 1 + 1010 0 0101 ! Singular Comma
+// K.28.6 011 1 + 0110 0 1001 !
+// K.28.7 111 x - 0111 + 1000 Singular Comma
+//
+// K.23.7 111 x - 0111 + 1000
+// K.27.7 111 x - 0111 + 1000
+// K.29.7 111 x - 0111 + 1000
+// K.30.7 111 x - 0111 + 1000
+//
+// The alternate Data encoding D.x.A7 is used in the case
+// that e = i = 1 and negative running disparity,
+// or e = i = 0 and positive running disparity,
+// or a Control signal is being sent,
+// all while encoding 7 in the MSB.
+//
+// This exception to the simple rule guarantees that there
+// aren't a run of 5 1's or 5 0's in the first 6 bits
+// concatinated with the last 4 bits.
+//
+// The special sequence starting at "a" of 2 0's followed by
+// 5 1's, or 2 1's followed by 5 0's, is called a
+// "Singular Comma".
+// A Singular Comma does not occur in any valid code EXCEPT
+// K.28.1 or K.28.5 or K.28.7.
+//
+// The web says K.28.5 is the Fiber Channel Comma Character.
+//
+// NOTE that K.28.7 is a bad comma character, because it
+// can be followed by a FALSE comma character when followed
+// by any character starting with 2 1's or 0's, like K.11
+// The false comma character is part in the K.28.7 and part
+// in the following data byte. Bad.
+//
+// The following info is found in www.wildpackets.com/compendium/GB/L1-GbEn.html,
+// in a document headed:
+// "Gigabit Ethernet is Closely Related to Fibre Channel Technology,
+// going back to 1988!"
+//
+// 8B-10B characters are described as Dn.m, where n gives the low order
+// 5 bits in decimal, and m gives the top 3 bits.
+//
+// Configuration data is transferred as an alternating sequence of:
+// (flips disparity: "C1") K28.5/D21.5/Config_reg[7:0]/Config_reg[15:8]
+// (leaves disparity: "C2") K28.5/D2.2/Config_reg[7:0]/Config_reg[15:8]
+//
+// Idle status is transmitted when ther eis nothing else to send.
+// The link is left in negative disparity. If it is positive, first
+// "I1" K28.5/D5.6 is sent, which knocks the displarity to negative
+// "I2" K28.5/D16.2 is sent repeatitively to maintain the negative disparity
+//
+// Start of Packet delimiter "S" K27.7
+// End of Packet delimiter "T" K29.7
+// Carrier Extend "R" K23.7
+//
+// An End Of Packet consists of either T/R/I or T/R/R
+// The second is used when a packet follows the previous packet in a burst.
+// "R" is also sent so that a subsequent "I" follows on an even-numbered
+// code boundry.
+//
+// Error propagation "V" K30.7
+
+
+// Accumulate the new data. First, calculate ignoring the running disparity;
+ wire [9:0] first_level_encoded_data;
+
+// Calculate the values for the 5 -> 6 encoding
+
+// Discover important details about the incoming numbers.
+ wire [1:0] LSB_02_Population = eight_bit_data_or_control_in[0] // half adder
+ + eight_bit_data_or_control_in[1];
+ wire [1:0] LSB_34_Population = eight_bit_data_or_control_in[2] // half adder
+ + eight_bit_data_or_control_in[3];
+ wire [2:0] LSB_Population = {1'b0, LSB_02_Population[1:0]}
+ + {1'b0, LSB_34_Population[1:0]};
+
+// As can be seen, in many of the LSB encodings the bottom
+// 4 of the encoded data are identical to the input
+// data. (These are noted with a trailing "!")
+//
+// There are several exceptions to this in the LSB. Decode these.
+ wire LSB_all_zero = (LSB_Population[2:0] == 3'h0);
+ wire LSB_contains_one_one = (LSB_Population[2:0] == 3'h1);
+ wire LSB_contains_two_ones = (LSB_Population[2:0] == 3'h2);
+ wire LSB_contains_three_ones = (LSB_Population[2:0] == 3'h3);
+ wire LSB_all_one = (LSB_Population[2:0] == 3'h4);
+
+ wire LSB_is_7 = (eight_bit_data_or_control_in[4:0] == 5'h07); // 7
+ wire LSB_is_24 = (eight_bit_data_or_control_in[4:0] == 5'h18); // 24
+ wire LSB_is_28 = (eight_bit_data_or_control_in[4:0] == 5'h1C); // 28
+ wire LSB_is_23_27_29_30 = (eight_bit_data_or_control_in[4:0] == 5'h17) // 23
+ | (eight_bit_data_or_control_in[4:0] == 5'h1B) // 27
+ | (eight_bit_data_or_control_in[4:0] == 5'h1D) // 29
+ | (eight_bit_data_or_control_in[4:0] == 5'h1E); // 30
+ wire LSB_contains_other_i = (eight_bit_data_or_control_in[3:0] == 4'h0)
+ | (eight_bit_data_or_control_in[3:0] == 4'h1)
+ | (eight_bit_data_or_control_in[3:0] == 4'h2)
+ | (eight_bit_data_or_control_in[3:0] == 4'h4);
+
+// Notice that the bottom bit of the encoded LSB data is the same as
+// the input LSB data.
+ assign first_level_encoded_data[0] = eight_bit_data_or_control_in[0];
+
+// If the bottom 4 bits are 0s, force 0110 (LSB is the left bit)
+// If the bottom 5 bits are 24, force 0011 (LSB is the left bit)
+// If the bottom 4 bits are 1s, force 1010 (LSB is the left bit)
+ assign first_level_encoded_data[1] = ( eight_bit_data_or_control_in[1]
+ & ~LSB_all_one)
+ | LSB_all_zero;
+ assign first_level_encoded_data[2] = eight_bit_data_or_control_in[2]
+ | LSB_all_zero
+ | LSB_is_24;
+ assign first_level_encoded_data[3] = ( eight_bit_data_or_control_in[3]
+ & ~LSB_all_one);
+
+// Bits "e" and "i" are chosen to guarantee that there are enough transitions,
+// and to control the disparity caused by each pattern.
+
+ assign first_level_encoded_data[4] =
+ (LSB_contains_one_one | eight_bit_data_or_control_in[4])
+ & ~LSB_is_24;
+
+ assign first_level_encoded_data[5] =
+ (LSB_contains_two_ones & ~eight_bit_data_or_control_in[4])
+ | ( ( LSB_contains_other_i | LSB_all_one)
+ & eight_bit_data_or_control_in[4])
+ | (input_is_control & LSB_is_28);
+
+// Now calculate the other information needed to produce the LSB output data
+ wire LSB_code_has_positive_disparity =
+ | ( ( LSB_all_zero
+ | LSB_contains_three_ones
+ | LSB_all_one)
+ & (eight_bit_data_or_control_in[4] == 1'b1) )
+ | (input_is_control & LSB_is_28);
+
+ wire LSB_code_has_negative_disparity =
+ ( ( LSB_all_zero
+ | LSB_contains_one_one
+ | LSB_all_one)
+ & (eight_bit_data_or_control_in[4] == 1'b0) )
+ | LSB_is_24;
+
+ wire invert_LSB_if_input_disparity_is_positive =
+ LSB_code_has_positive_disparity
+ | LSB_is_7;
+
+ wire invert_LSB_if_input_disparity_is_negative =
+ LSB_code_has_negative_disparity;
+
+ wire LSB_toggle_running_disparity =
+ LSB_code_has_positive_disparity
+ | LSB_code_has_negative_disparity;
+
+// Calculate the values for the 3 -> 4 encoding
+
+// An alternate encoding of the MSB for an input of 0x7 is used to
+// prevent accidental use of a pattern with 5 0's or 1's in a row.
+// The alternate Data encoding D.x.A7 is used in the case
+// that e = i = 0 and positive running disparity,
+// or e = i = 1 and negative running disparity,
+// or a Control signal is being sent,
+// all while encoding 7 in the MSB.
+
+ reg Running_Disparity; // forward reference
+
+ wire use_alternate_encoding =
+ ( input_is_control
+ | ( (Running_Disparity == 1'b0)
+ & ( (eight_bit_data_or_control_in[4:0] == 5'h11) // 17
+ | (eight_bit_data_or_control_in[4:0] == 5'h12) // 18
+ | (eight_bit_data_or_control_in[4:0] == 5'h14) // 20
+ ))
+ | ( (Running_Disparity == 1'b1)
+ & ( (eight_bit_data_or_control_in[4:0] == 5'h0B) // 11
+ | (eight_bit_data_or_control_in[4:0] == 5'h0D) // 13
+ | (eight_bit_data_or_control_in[4:0] == 5'h0E) // 14
+ ))
+ )
+ & (eight_bit_data_or_control_in[7:5] == 3'h7);
+
+// The low bit of the MSB is a pass-through, except when the alternate
+// encoding of the value is used to prevent unintentional long runs.
+ assign first_level_encoded_data[6] = eight_bit_data_or_control_in[5]
+ & ~use_alternate_encoding;
+
+// The second bit of the MSB is a pass-through except when the input
+// is all 0's.
+ assign first_level_encoded_data[7] = eight_bit_data_or_control_in[6]
+ | (eight_bit_data_or_control_in[7:5] == 3'h0);
+
+// The top bit of the encoded MSB data is the same as the input MSB data.
+ assign first_level_encoded_data[8] = eight_bit_data_or_control_in[7];
+
+// Bit "j" is chosen to guarantee that there are enough transitions,
+// and to control the disparity caused by each pattern.
+ assign first_level_encoded_data[9] =
+ (eight_bit_data_or_control_in[7:5] == 3'h1)
+ | (eight_bit_data_or_control_in[7:5] == 3'h2)
+ | use_alternate_encoding;
+
+// Now calculate the other information needed to produce the MSB output data
+ wire invert_MSB_if_LSB_disparity_is_positive =
+ (eight_bit_data_or_control_in[7:5] == 3'h3)
+ | (eight_bit_data_or_control_in[7:5] == 3'h7);
+
+ wire invert_MSB_if_LSB_disparity_is_negative =
+ (eight_bit_data_or_control_in[7:5] == 3'h0)
+ | (eight_bit_data_or_control_in[7:5] == 3'h4)
+ | ( input_is_control
+ & ( (eight_bit_data_or_control_in[7:5] == 3'h1)
+ | (eight_bit_data_or_control_in[7:5] == 3'h2)
+ | (eight_bit_data_or_control_in[7:5] == 3'h5)
+ | (eight_bit_data_or_control_in[7:5] == 3'h6)
+ )
+ );
+
+ wire MSB_toggle_running_disparity =
+ (eight_bit_data_or_control_in[7:5] == 3'h0)
+ | (eight_bit_data_or_control_in[7:5] == 3'h4)
+ | (eight_bit_data_or_control_in[7:5] == 3'h7);
+
+// Keep track of the running disparity. If 1'b1, the disparity is positive.
+ always @(posedge clk)
+ begin
+ if (reset == 1'b1)
+ begin
+ Running_Disparity <= 1'b0; // start negative
+ end
+ else
+ begin
+ Running_Disparity <= Running_Disparity
+ ^ LSB_toggle_running_disparity
+ ^ MSB_toggle_running_disparity;
+ end
+ end
+
+// Decide whether to invert the encoded data;
+ wire Invert_LSB = ( (Running_Disparity == 1'b1)
+ & (invert_LSB_if_input_disparity_is_positive == 1'b1) )
+ | ( (Running_Disparity == 1'b0)
+ & (invert_LSB_if_input_disparity_is_negative == 1'b1) );
+
+ wire Invert_MSB = ( ((Running_Disparity ^ LSB_toggle_running_disparity) == 1'b1)
+ & (invert_MSB_if_LSB_disparity_is_positive == 1'b1) )
+ | ( ((Running_Disparity ^ LSB_toggle_running_disparity) == 1'b0)
+ & (invert_MSB_if_LSB_disparity_is_negative == 1'b1) );
+
+// Calculate the actual encoded data.
+ reg [9:0] ten_bit_encoded_data_out;
+ reg invalid_control;
+
+ always @(posedge clk)
+ begin
+ if (reset == 1'b1)
+ begin
+ ten_bit_encoded_data_out[9:0] <= 10'h000;
+ invalid_control <= 1'b0;
+ end
+ else
+ begin
+ ten_bit_encoded_data_out[5:0] <=
+ {6{Invert_LSB}} ^ first_level_encoded_data[5:0];
+ ten_bit_encoded_data_out[9:6] <=
+ {4{Invert_MSB}} ^ first_level_encoded_data[9:6];
+ invalid_control <= input_is_control
+ & ~( LSB_is_28 // all MSB bits are valid
+ | ( LSB_is_23_27_29_30
+ & (eight_bit_data_or_control_in[7:5] == 3'h7) // MSB must be 7
+ )
+ );
+ end
+ end
+endmodule
+
+// Convert 10-bit code to 8-bit binary or 8-bit control code
+
+module decode_10b_8b (
+ ten_bit_encoded_data_in,
+ eight_bit_data_or_control_out,
+ output_is_control,
+ invalid_encoded_data,
+ clk,
+ reset
+);
+ input [9:0] ten_bit_encoded_data_in;
+ output [7:0] eight_bit_data_or_control_out;
+ output output_is_control;
+ output invalid_encoded_data;
+ input clk, reset;
+
+// Data is encoded as described in the encode_8b_10b module above.
+// This module tries to extract valid data or control info from the
+// encoded input data.
+//
+// This module depends on the data being correctly 10-bit aligned.
+// the LSB of the input must be the "a" bit as described above.
+//
+// This module tries to detect errors in the code sequence as it arrives.
+// Errors are when an illegal bit sequence arrives, or when the disparity
+// of the input data goes beyond 1 bit. This would happen if the sender
+// did not correctly use alternate encodings of output data.
+
+// Accumulate the new data. Calculate ignoring the running disparity;
+ wire [7:0] decoded_data;
+
+// Calculate the values for the 6 -> 5 decoding
+
+// Discover important details about the incoming numbers.
+ wire [1:0] LSB_02_Population = ten_bit_encoded_data_in[0] // full adder
+ + ten_bit_encoded_data_in[1]
+ + ten_bit_encoded_data_in[2];
+ wire [1:0] LSB_35_Population = ten_bit_encoded_data_in[3] // full adder
+ + ten_bit_encoded_data_in[4]
+ + ten_bit_encoded_data_in[5];
+ wire [2:0] LSB_bottom_4_Population = {1'b0, LSB_02_Population[1:0]}
+ + {2'b00, ten_bit_encoded_data_in[3]};
+ wire [2:0] LSB_Population = {1'b0, LSB_02_Population[1:0]} // allowed: 2, 3, 4
+ + {1'b0, LSB_35_Population[1:0]}; // illegal: 0, 1, 5, 6
+
+// As can be seen, in many of the LSB encodings the bottom
+// 4 of the decoded data are identical to the input
+// data. (These are noted with a trailing "!")
+//
+// The bottom 4 bits can be used directly in these cases (which are all cases
+// where the number of bits in the input are equil to 3 except for 7):
+// 3 5 6 9 10 11 12 13 14 17 18 19 20 21 22 25 26 28
+
+// The bottom 4 bits must be inverted before use in these cases: (MSB right)
+// 011101 101101 110101 111001 000101 001001 010001 100001 000111 110000
+ wire LSB_Invert_Before_Use = ( (ten_bit_encoded_data_in[5:4] == 2'b10)
+ & ( (LSB_bottom_4_Population[2:0] == 3'h1)
+ | (LSB_bottom_4_Population[2:0] == 3'h3) )
+ )
+ | (ten_bit_encoded_data_in[5:0] == 6'b111000) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b000011);
+
+// Values must be substituted in these cases:
+ wire LSB_is_0_16_a = (ten_bit_encoded_data_in[5:0] == 6'b000110) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b110110);
+
+ wire LSB_is_0_16_b = (ten_bit_encoded_data_in[5:0] == 6'b111001) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b001001);
+
+ wire LSB_is_15_31_a = (ten_bit_encoded_data_in[5:0] == 6'b000101) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b110101);
+
+ wire LSB_is_15_31_b = (ten_bit_encoded_data_in[5:0] == 6'b111010) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b001010);
+
+ wire LSB_is_24_a = (ten_bit_encoded_data_in[5:0] == 6'b001100); // LSB to right
+ wire LSB_is_24_b = (ten_bit_encoded_data_in[5:0] == 6'b110011); // LSB to right
+
+// Notice when these codes occur. They are the only time Alternate D.x.7 data
+// can be used. This is looked for below to detect errors.
+ wire LSB_is_11_13_14 = (ten_bit_encoded_data_in[5:0] == 6'b001011) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b001101)
+ | (ten_bit_encoded_data_in[5:0] == 6'b001110);
+
+ wire LSB_is_17_18_20 = (ten_bit_encoded_data_in[5:0] == 6'b110001) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b110010)
+ | (ten_bit_encoded_data_in[5:0] == 6'b110100);
+
+// Control signals must be called out when recognized.
+ wire LSB_is_23_27_29_30 = ( (ten_bit_encoded_data_in[5:4] == 2'b01)
+ & (LSB_bottom_4_Population[2:0] == 3'h3) )
+ | ( (ten_bit_encoded_data_in[5:4] == 2'b10)
+ & (LSB_bottom_4_Population[2:0] == 3'h1) );
+
+ wire LSB_is_K28 = (ten_bit_encoded_data_in[5:0] == 6'b111100) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b000011);
+
+// calculate the bottom 4 bits of decoded data
+ wire [3:0] LSB_XOR_Term = {4{LSB_Invert_Before_Use}} // invert all signals with alternate values
+ | {1'b0, LSB_is_0_16_a, LSB_is_0_16_a, 1'b0} // make 0, 16 into 0
+ | {LSB_is_0_16_b, 1'b0, 1'b0, LSB_is_0_16_b} // make 0, 16 into 0
+ | {LSB_is_15_31_a, 1'b0, LSB_is_15_31_a, 1'b0} // make 15, 31 into 15
+ | {1'b0, LSB_is_15_31_b, 1'b0, LSB_is_15_31_b} // make 15, 31 into 15
+ | {1'b0, LSB_is_24_a, 1'b0, 1'b0} // make 24 into 24
+ | {LSB_is_24_b, 1'b0, LSB_is_24_b, LSB_is_24_b}; // make 24 into 24
+
+ assign decoded_data[3:0] = ten_bit_encoded_data_in[3:0] ^ LSB_XOR_Term[3:0];
+
+// The next bit is harder. I don't know if this is minimal
+ assign decoded_data[4] = (ten_bit_encoded_data_in[5:0] == 6'b001001) // LSB to right
+ | (ten_bit_encoded_data_in[5:0] == 6'b001010)
+ | (ten_bit_encoded_data_in[5:0] == 6'b001100)
+ | (ten_bit_encoded_data_in[5:3] == 3'b110)
+ | ( (ten_bit_encoded_data_in[5:4] == 2'b01)
+ & (LSB_bottom_4_Population[2:0] == 3'h2) )
+ | LSB_is_23_27_29_30
+ | LSB_is_K28;
+
+// Calculate the values for the 4 -> 3 decoding
+
+// The bottom 2 bits of the MSB must always be inverted before use in these
+// cases: (MSB right) 0011, 1101, 0001
+// When the LSB indicate that the byte contains a K28, and the bottom 6 bits
+// have a negative disparity, invert these before using: (MSB right)
+// 0110, 1010, 0101, 1001
+// Only 2 of these are needed to greate singular commas. I don't understand
+// why they made the other special cases. Very odd
+
+ wire MSB_Invert_Before_Use = (ten_bit_encoded_data_in[9:6] == 4'b1100) // LSB to right
+ | (ten_bit_encoded_data_in[9:6] == 4'b1011)
+ | (ten_bit_encoded_data_in[9:6] == 4'b1000)
+ | ( (ten_bit_encoded_data_in[5:0] == 6'b000011)
+ & ( (ten_bit_encoded_data_in[9:6] == 4'b0110)
+ | (ten_bit_encoded_data_in[9:6] == 4'b0101)
+ | (ten_bit_encoded_data_in[9:6] == 4'b1010)
+ | (ten_bit_encoded_data_in[9:6] == 4'b1001)
+ )
+ );
+
+// Values must be substituted in these cases:
+ wire MSB_0_value_a = (ten_bit_encoded_data_in[9:6] == 4'b0010); // LSB to right
+ wire MSB_0_value_b = (ten_bit_encoded_data_in[9:6] == 4'b1101);
+
+ wire alternate_MSB_a = (ten_bit_encoded_data_in[9:6] == 4'b1110); // LSB to right
+ wire alternate_MSB_b = (ten_bit_encoded_data_in[9:6] == 4'b0001);
+
+ wire primary_MSB_a = (ten_bit_encoded_data_in[9:6] == 4'b0111); // LSB to right
+ wire primary_MSB_b = (ten_bit_encoded_data_in[9:6] == 4'b1000);
+
+ wire [2:0] MSB_XOR_Term = {3{MSB_Invert_Before_Use}}
+ | {1'b0, MSB_0_value_a, 1'b0}
+ | {MSB_0_value_b, 1'b0, MSB_0_value_b}
+ | {1'b0, 1'b0, alternate_MSB_a}
+ | {alternate_MSB_b, alternate_MSB_b, 1'b0};
+
+ assign decoded_data[7:5] = ten_bit_encoded_data_in[8:6] ^ MSB_XOR_Term[2:0];
+
+ wire decoded_control = ( LSB_is_23_27_29_30
+ & (alternate_MSB_a | alternate_MSB_b))
+ | LSB_is_K28;
+
+// Keep track of the running disparity. If 1'b1, the disparity is positive.
+
+ wire [1:0] MSB_01_Population = ten_bit_encoded_data_in[6] // half adder
+ + ten_bit_encoded_data_in[7];
+ wire [1:0] MSB_23_Population = ten_bit_encoded_data_in[8] // half adder
+ + ten_bit_encoded_data_in[9];
+ wire [2:0] MSB_Population = {1'b0, MSB_01_Population[1:0]} // 1, 2, 3
+ + {1'b0, MSB_23_Population[1:0]};
+
+ wire [3:0] Code_Population = {1'b0, LSB_Population[2:0]} // 4, 5, 6
+ + {1'b0, MSB_Population[2:0]};
+
+ reg Running_Disparity;
+
+ always @(posedge clk)
+ begin
+ if (reset == 1'b1)
+ begin
+ Running_Disparity <= 1'b0; // start negative
+ end
+ else
+ begin
+ Running_Disparity <= (Code_Population[3:0] == 4'h6)
+ ? 1'b1
+ : ( (Code_Population[3:0] == 4'h4)
+ ? 1'b0
+ : Running_Disparity);
+ end
+ end
+
+// Detect invalid code values.
+
+ wire too_many_bits_in_first_nibble =
+ (LSB_bottom_4_Population[2:0] > 3'h3);
+ wire too_few_bits_in_first_nibble =
+ (LSB_bottom_4_Population[2:0] < 3'h1);
+
+ wire too_many_bits_in_LSB = (LSB_Population[2:0] > 3'h4);
+ wire too_few_bits_in_LSB = (LSB_Population[2:0] < 3'h2);
+
+ wire too_many_bits_in_MSB = (MSB_Population[2:0] > 3'h3);
+ wire too_few_bits_in_MSB = (LSB_Population[2:0] < 3'h1);
+
+ wire too_many_bits_in_entire_code = (Code_Population[3:0] > 4'h6);
+ wire too_few_bits_in_entire_code = (Code_Population[3:0] < 4'h4);
+
+ wire LSB_inconsistent_with_running_disparity =
+ ( (Running_Disparity == 1'b1)
+ & ( (LSB_Population[2:0] == 3'h4)
+ | (ten_bit_encoded_data_in[5:0] == 6'b000111) // X.7 negative disparity
+ ) )
+ | ( (Running_Disparity == 1'b0)
+ & ( (LSB_Population[2:0] == 3'h2)
+ | (ten_bit_encoded_data_in[5:0] == 6'b111000) // X.7 positive disparity
+ ) );
+
+ wire LSB_code_7_positive_but_MSB_inconsistent =
+ (ten_bit_encoded_data_in[5:0] == 6'b111000) // X.7 positive disparity
+ & ( (MSB_Population[2:0] == 3'h3) // too many bits in MSB
+ | (ten_bit_encoded_data_in[9:6] == 4'b0011) // Y.3 negative disparity
+ );
+
+ wire LSB_code_7_negative_but_MSB_inconsistent =
+ (ten_bit_encoded_data_in[5:0] == 6'b000111) // X.7 negative disparity
+ & ( (MSB_Population[2:0] == 3'h1) // too few bits in MSB
+ | (ten_bit_encoded_data_in[9:6] == 4'b1100) // Y.3 positive disparity
+ );
+
+ wire MSB_code_3_positive_but_LSB_inconsistent =
+ (ten_bit_encoded_data_in[9:6] == 4'b1100) // X.7 positive disparity
+ & (LSB_Population[2:0] == 3'h2); // too few bits in LSB
+
+ wire MSB_code_3_negative_but_LSB_inconsistent =
+ (ten_bit_encoded_data_in[9:6] == 4'b0011) // X.7 negative disparity
+ & (LSB_Population[2:0] == 3'h4); // too many bits in LSB
+
+ wire alternate_encoding_not_used_when_required =
+ ((Running_Disparity == 1'b1) & (LSB_is_11_13_14) & primary_MSB_b)
+ | ((Running_Disparity == 1'b0) & (LSB_is_17_18_20) & primary_MSB_a)
+ | (LSB_is_K28 & (primary_MSB_a | primary_MSB_b));
+
+ wire primary_encoding_not_used_when_required =
+ ((Running_Disparity == 1'b0) & (LSB_is_11_13_14) & alternate_MSB_b)
+ | ((Running_Disparity == 1'b1) & (LSB_is_17_18_20) & alternate_MSB_a);
+
+ wire detected_invalid_8b_10b_sequence = too_many_bits_in_first_nibble
+ | too_few_bits_in_first_nibble
+ | too_many_bits_in_LSB
+ | too_few_bits_in_LSB
+ | too_many_bits_in_MSB
+ | too_few_bits_in_MSB
+ | too_many_bits_in_entire_code
+ | too_few_bits_in_entire_code
+ | LSB_inconsistent_with_running_disparity
+ | LSB_code_7_positive_but_MSB_inconsistent
+ | LSB_code_7_negative_but_MSB_inconsistent
+ | MSB_code_3_positive_but_LSB_inconsistent
+ | MSB_code_3_negative_but_LSB_inconsistent
+ | alternate_encoding_not_used_when_required
+ | primary_encoding_not_used_when_required;
+
+// Calculate the actual decoded data.
+ reg [7:0] eight_bit_data_or_control_out;
+ reg output_is_control;
+ reg invalid_encoded_data;
+
+ always @(posedge clk)
+ begin
+ if (reset == 1'b1)
+ begin
+ eight_bit_data_or_control_out[7:0] <= 8'h00;
+ output_is_control <= 1'b0;
+ invalid_encoded_data <= 1'b0;
+ end
+ else
+ begin
+ eight_bit_data_or_control_out[7:0] <= decoded_data[7:0];
+ output_is_control <= decoded_control;
+ invalid_encoded_data <= detected_invalid_8b_10b_sequence
+ & (ten_bit_encoded_data_in[9:0] != 10'b0000_000000) // NOTE TEMPORARY
+ ;
+ end
+ end
+endmodule
+
+// `define TEST_8B_10B
+`ifdef TEST_8B_10B
+// This simulates in between 6 and 7 minutes on a 400 MHz Ultra using verilog XL.
+// This does not complete before filling up the disk on a 300 MHz K6 using Verilogger PRO.
+module test_8b_10b;
+ reg [8:0] test_data;
+ reg [8:0] test_data_second;
+ reg [8:0] limit;
+ reg [7:0] control_byte;
+ reg [7:0] control_byte_second;
+ reg test_control;
+
+ reg [7:0] eight_bit_data_or_control_in;
+ reg input_is_control;
+ reg mess_up_link_disparity;
+ wire [9:0] ten_bit_encoded_data_out;
+ wire invalid_control;
+
+ wire [7:0] eight_bit_data_or_control_out;
+ wire output_is_control;
+ wire invalid_encoded_data;
+
+ reg clk, reset;
+
+ reg found_singular_comma;
+
+task set_to_negative_disparity;
+ begin
+ clk = 1'b0; reset = 1'b1; #1;
+ clk = 1'b1; reset = 1'b1; #1; // do reset, setting sender to negative disparity
+ clk = 1'b0; reset = 1'b1; #1;
+ clk = 1'b0; reset = 1'b0; #1;
+ end
+endtask
+
+task set_to_positive_disparity;
+ begin
+ clk = 1'b0; reset = 1'b1; #1;
+ clk = 1'b1; reset = 1'b1; #1; // do reset, setting sender to negative disparity
+ clk = 1'b0; reset = 1'b1; #1;
+ clk = 1'b0; reset = 1'b0; #1;
+
+ eight_bit_data_or_control_in[7:0] = 8'b111_00011; #1;
+ clk = 1'b1; #1; // switch to a positive running disparity
+ clk = 1'b0; #1;
+ end
+endtask
+
+task check;
+ input disparity;
+ input [7:0] test_data;
+ input do_control;
+ reg [9:0] latched_code;
+ begin
+ if (disparity == 1'b1)
+ set_to_positive_disparity;
+ else
+ set_to_negative_disparity;
+
+ input_is_control = do_control;
+ eight_bit_data_or_control_in[7:0] = test_data[7:0]; #1; // inputs settle
+ clk = 1'b1; #1; // encoded data available
+ clk = 1'b0; #1;
+
+ latched_code[9:0] = ten_bit_encoded_data_out[9:0];
+
+ input_is_control = 1'b0;
+ eight_bit_data_or_control_in[7:0] = 8'b010_00011; #1;
+ clk = 1'b1; #1; // decoded data available
+ clk = 1'b0; #1;
+
+ if ( (eight_bit_data_or_control_out[7:0] !== test_data[7:0])
+ | (output_is_control !== do_control)
+ | (invalid_encoded_data !== 1'b0)
+ )
+ begin
+ $display ("!!! test data, result %d %d %b_%b %x %d %b %b",
+ test_data[7:5], test_data[4:0],
+ latched_code[9:6], latched_code[5:0],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+endtask
+
+function look_for_singular_comma;
+ input [6:0] data;
+ begin
+ if ( (data[0] == data[1])
+ & (data[0] == ~data[2])
+ & (data[0] == ~data[3])
+ & (data[0] == ~data[4])
+ & (data[0] == ~data[5])
+ & (data[0] == ~data[6])
+ )
+ begin
+ look_for_singular_comma = 1'b1;
+ end
+ else
+ begin
+ look_for_singular_comma = 1'b0;
+ end
+ end
+endfunction
+
+task check_pair; // Data then Data or Control then Data
+ input disparity;
+ input [7:0] test_data;
+ input [7:0] test_data_second;
+ input do_control;
+ input want_singular_comma;
+ reg [9:0] latched_code;
+ reg [19:0] two_bytes_of_codes_back_to_back;
+
+ begin
+ if (disparity == 1'b1)
+ set_to_positive_disparity;
+ else
+ set_to_negative_disparity;
+
+ input_is_control = do_control;
+ eight_bit_data_or_control_in[7:0] = test_data[7:0]; #1; // inputs settle
+ clk = 1'b1; #1; // encoded data available
+ clk = 1'b0; #1;
+
+ latched_code[9:0] = ten_bit_encoded_data_out[9:0];
+ two_bytes_of_codes_back_to_back[9:0] = ten_bit_encoded_data_out[9:0];
+
+ input_is_control = 1'b0;
+ eight_bit_data_or_control_in[7:0] = test_data_second[7:0]; #1; // inputs settle
+ clk = 1'b1; #1; // decoded data available
+ clk = 1'b0; #1;
+
+ if ( (eight_bit_data_or_control_out[7:0] !== test_data[7:0])
+ | (output_is_control !== do_control)
+ | (invalid_encoded_data !== 1'b0)
+ )
+ begin
+ $display ("!!! test data, result %d %d %b_%b %x %d %b %b",
+ test_data[7:5], test_data[4:0],
+ latched_code[9:6], latched_code[5:0],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+
+ latched_code[9:0] = ten_bit_encoded_data_out[9:0];
+ two_bytes_of_codes_back_to_back[19:10] = ten_bit_encoded_data_out[9:0];
+
+ input_is_control = 1'b0;
+ eight_bit_data_or_control_in[7:0] = 8'b010_00011; #1;
+ clk = 1'b1; #1; // decoded data available
+ clk = 1'b0; #1;
+
+ if ( (eight_bit_data_or_control_out[7:0] !== test_data_second[7:0])
+ | (output_is_control !== 1'b0)
+ | (invalid_encoded_data !== 1'b0)
+ )
+ begin
+ $display ("!!! test data second, result %d %d %b_%b %x %d %b %b",
+ test_data_second[7:5], test_data_second[4:0],
+ latched_code[9:6], latched_code[5:0],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+
+ if (~want_singular_comma)
+ begin
+ if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) )
+ begin
+ $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+ else // want a singular comma
+ begin
+ if (!look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0]))
+ begin
+ $display ("!!! missing singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) )
+ begin
+ $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+ end
+endtask
+
+task check_pair_2; // Data followed by Control or Control followed by Control
+ input disparity;
+ input [7:0] test_data;
+ input [7:0] test_data_second;
+ input first_control;
+ input want_first_singular_comma;
+ input second_control;
+ input want_second_singular_comma;
+ reg [9:0] latched_code;
+ reg [19:0] two_bytes_of_codes_back_to_back;
+
+ begin
+ if (disparity == 1'b1)
+ set_to_positive_disparity;
+ else
+ set_to_negative_disparity;
+
+ input_is_control = first_control;
+ eight_bit_data_or_control_in[7:0] = test_data[7:0]; #1; // inputs settle
+ clk = 1'b1; #1; // encoded data available
+ clk = 1'b0; #1;
+
+ latched_code[9:0] = ten_bit_encoded_data_out[9:0];
+ two_bytes_of_codes_back_to_back[9:0] = ten_bit_encoded_data_out[9:0];
+
+ input_is_control = second_control;
+ eight_bit_data_or_control_in[7:0] = test_data_second[7:0]; #1; // inputs settle
+ clk = 1'b1; #1; // decoded data available
+ clk = 1'b0; #1;
+
+ if ( (eight_bit_data_or_control_out[7:0] !== test_data[7:0])
+ | (output_is_control !== first_control)
+ | (invalid_encoded_data !== 1'b0)
+ )
+ begin
+ $display ("!!! test data, result %d %d %b_%b %x %d %b %b",
+ test_data[7:5], test_data[4:0],
+ latched_code[9:6], latched_code[5:0],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+
+ latched_code[9:0] = ten_bit_encoded_data_out[9:0];
+ two_bytes_of_codes_back_to_back[19:10] = ten_bit_encoded_data_out[9:0];
+
+ input_is_control = 1'b0;
+ eight_bit_data_or_control_in[7:0] = 8'b010_00011; #1;
+ clk = 1'b1; #1; // decoded data available
+ clk = 1'b0; #1;
+
+ if ( (eight_bit_data_or_control_out[7:0] !== test_data_second[7:0])
+ | (output_is_control !== second_control)
+ | (invalid_encoded_data !== 1'b0)
+ )
+ begin
+ $display ("!!! test data second, result %d %d %b_%b %x %d %b %b",
+ test_data_second[7:5], test_data_second[4:0],
+ latched_code[9:6], latched_code[5:0],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+
+ if (~want_first_singular_comma)
+ begin
+ if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9]) )
+ begin
+ $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+ else // want a singular comma in the first byte
+ begin
+ if (!look_for_singular_comma (two_bytes_of_codes_back_to_back[6:0]))
+ begin
+ $display ("!!! missing singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[7:1])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[8:2])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[9:3])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[10:4])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[11:5])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[12:6])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[13:7])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[14:8])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[15:9]) )
+ begin
+ $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+ if (~want_second_singular_comma)
+ begin
+ if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) )
+ begin
+ $display ("!!! unexpected singular comma, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+ else // want a singular comma in the second byte
+ begin
+ if (!look_for_singular_comma (two_bytes_of_codes_back_to_back[16:10]))
+ begin
+ $display ("!!! missing singular comma 2, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ if ( look_for_singular_comma (two_bytes_of_codes_back_to_back[17:11])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[18:12])
+ | look_for_singular_comma (two_bytes_of_codes_back_to_back[19:13]) )
+ begin
+ $display ("!!! unexpected singular comma 2, result %d %d %b_%b %b_%b %b %b %b %b",
+ test_data[7:0], test_data_second[7:0],
+ two_bytes_of_codes_back_to_back[9:6], two_bytes_of_codes_back_to_back[5:0],
+ two_bytes_of_codes_back_to_back[19:16], two_bytes_of_codes_back_to_back[15:10],
+ eight_bit_data_or_control_out[7:5], eight_bit_data_or_control_out[4:0],
+ output_is_control, invalid_encoded_data);
+ end
+ end
+ end
+endtask
+
+function [7:0] pick_control_byte;
+ input [3:0] index;
+ begin
+ case (index[3:0])
+ 0: pick_control_byte[7:0] = `K_23_7;
+ 1: pick_control_byte[7:0] = `K_27_7;
+ 2: pick_control_byte[7:0] = `K_28_0;
+ 3: pick_control_byte[7:0] = `K_28_1;
+ 4: pick_control_byte[7:0] = `K_28_2;
+ 5: pick_control_byte[7:0] = `K_28_3;
+ 6: pick_control_byte[7:0] = `K_28_4;
+ 7: pick_control_byte[7:0] = `K_28_5;
+ 8: pick_control_byte[7:0] = `K_28_6;
+ 9: pick_control_byte[7:0] = `K_28_7;
+ 10: pick_control_byte[7:0] = `K_29_7;
+ default: pick_control_byte[7:0] = `K_30_7;
+ endcase
+ end
+endfunction
+
+ initial
+ begin
+ mess_up_link_disparity = 1'b0;
+
+ $display ("test 32 LSB data values starting with negative disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h020;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (0, test_data[7:0], 1'b0);
+ end
+
+ $display ("test 8 MSB data values starting with negative disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (0, (test_data[2:0] << 5) | 5'h03, 1'b0);
+ end
+
+ $display ("test 8 MSB data values starting with negative disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (0, (test_data[2:0] << 5) | 5'h0B, 1'b0); // 11
+ end
+
+ $display ("test 8 MSB data values starting with negative disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (0, (test_data[2:0] << 5) | 5'h11, 1'b0); // 17
+ end
+
+ $display ("test control starting with negative disparity");
+ check (0, `K_23_7, 1'b1);
+ check (0, `K_27_7, 1'b1);
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (0, `K_28_0 | (test_data[2:0] << 5), 1'b1);
+ end
+ check (0, `K_29_7, 1'b1);
+ check (0, `K_30_7, 1'b1);
+
+// $display ("invalid control character with negative disparity");
+// check (0, 8'h0, 1'b1);
+
+
+ $display ("test 32 LSB data values starting with positive disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h020;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (1, test_data[7:0], 1'b0);
+ end
+
+ $display ("test 8 MSB data values starting with positive disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (1, (test_data[2:0] << 5) | 5'h03, 1'b0);
+ end
+
+ $display ("test 8 MSB data values starting with positive disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (1, (test_data[2:0] << 5) | 5'h0B, 1'b0); // 11
+ end
+
+ $display ("test 8 MSB data values starting with positive disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (1, (test_data[2:0] << 5) | 5'h11, 1'b0); // 17
+ end
+
+ $display ("test control starting with positive disparity");
+ check (1, `K_23_7, 1'b1);
+ check (1, `K_27_7, 1'b1);
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h008;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ check (1, `K_28_0 | (test_data[2:0] << 5), 1'b1);
+ end
+ check (1, `K_29_7, 1'b1);
+ check (1, `K_30_7, 1'b1);
+
+// $display ("invalid control character with positive disparity");
+// check (1, 8'h0, 1'b1);
+
+ limit[8:0] = 9'h100; # 1;
+
+ $display ("trying all byte pairs starting with negative disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ for (test_data_second[8:0] = 9'h000; test_data_second[8:0] < limit[8:0];
+ test_data_second[8:0] = test_data_second[8:0] + 9'h001)
+ begin
+ check_pair (0, test_data[7:0], test_data_second[7:0], 1'b0, 1'b0);
+ end
+ end
+
+ $display ("trying all controls then bytes with negative disparity");
+ $display ("This finds 24 unexpected extra singular commas when sending K_28_7");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC;
+ test_data_second[3:0] = test_data_second[3:0] + 4'h1)
+ begin
+ check_pair (0, pick_control_byte(test_data_second[3:0]), test_data[7:0], 1'b1,
+ (test_data_second[3:0] == 4'h3)
+ | (test_data_second[3:0] == 4'h7)
+ | (test_data_second[3:0] == 4'h9) );
+ end
+ end
+
+ $display ("trying all bytes then controls with negative disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC;
+ test_data_second[3:0] = test_data_second[3:0] + 4'h1)
+ begin
+ check_pair_2 (0, test_data[7:0], pick_control_byte(test_data_second[3:0]),
+ 1'b0, 1'b0,
+ 1'b1, (test_data_second[3:0] == 4'h3)
+ | (test_data_second[3:0] == 4'h7)
+ | (test_data_second[3:0] == 4'h9) );
+ end
+ end
+
+ $display ("trying all controls then controls with negative disparity");
+ $display ("This finds 8 unexpected extra singular commas when sending K_28_7");
+ for (test_data[3:0] = 9'h000; test_data[3:0] < 4'hC;
+ test_data[3:0] = test_data[3:0] + 4'h1)
+ begin
+ for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC;
+ test_data_second[3:0] = test_data_second[3:0] + 4'h1)
+ begin
+ check_pair_2 (0, pick_control_byte(test_data[3:0]),
+ pick_control_byte(test_data_second[3:0]),
+ 1'b1, (test_data[3:0] == 4'h3)
+ | (test_data[3:0] == 4'h7)
+ | (test_data[3:0] == 4'h9),
+ 1'b1, (test_data_second[3:0] == 4'h3)
+ | (test_data_second[3:0] == 4'h7)
+ | (test_data_second[3:0] == 4'h9) );
+ end
+ end
+
+ $display ("trying all byte pairs starting with positive disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ for (test_data_second[8:0] = 9'h000; test_data_second[8:0] < limit[8:0];
+ test_data_second[8:0] = test_data_second[8:0] + 9'h001)
+ begin
+ check_pair (1, test_data[7:0], test_data_second[7:0], 1'b0, 1'b0);
+ end
+ end
+
+ $display ("trying all controls then bytes with positive disparity");
+ $display ("This finds 24 unexpected extra singular commas when sending K_28_7");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC;
+ test_data_second[3:0] = test_data_second[3:0] + 4'h1)
+ begin
+ check_pair (1, pick_control_byte(test_data_second[3:0]), test_data[7:0], 1'b1,
+ (test_data_second[3:0] == 4'h3)
+ | (test_data_second[3:0] == 4'h7)
+ | (test_data_second[3:0] == 4'h9) );
+ end
+ end
+
+ $display ("trying all bytes then controls with positive disparity");
+ for (test_data[8:0] = 9'h000; test_data[8:0] < 9'h100;
+ test_data[8:0] = test_data[8:0] + 9'h001)
+ begin
+ for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC;
+ test_data_second[3:0] = test_data_second[3:0] + 4'h1)
+ begin
+ check_pair_2 (1, test_data[7:0], pick_control_byte(test_data_second[3:0]),
+ 1'b0, 1'b0,
+ 1'b1, (test_data_second[3:0] == 4'h3)
+ | (test_data_second[3:0] == 4'h7)
+ | (test_data_second[3:0] == 4'h9) );
+ end
+ end
+
+ $display ("trying all controls then controls with positive disparity");
+ $display ("This finds 8 unexpected extra singular commas when sending K_28_7");
+ for (test_data[3:0] = 9'h000; test_data[3:0] < 4'hC;
+ test_data[3:0] = test_data[3:0] + 4'h1)
+ begin
+ for (test_data_second[3:0] = 4'h0; test_data_second[3:0] < 4'hC;
+ test_data_second[3:0] = test_data_second[3:0] + 4'h1)
+ begin
+ check_pair_2 (1, pick_control_byte(test_data[3:0]),
+ pick_control_byte(test_data_second[3:0]),
+ 1'b1, (test_data[3:0] == 4'h3)
+ | (test_data[3:0] == 4'h7)
+ | (test_data[3:0] == 4'h9),
+ 1'b1, (test_data_second[3:0] == 4'h3)
+ | (test_data_second[3:0] == 4'h7)
+ | (test_data_second[3:0] == 4'h9) );
+ end
+ end
+ end
+
+encode_8b_10b encode_8b_10b (
+ .eight_bit_data_or_control_in (eight_bit_data_or_control_in[7:0]),
+ .input_is_control (input_is_control),
+ .mess_up_link_disparity (mess_up_link_disparity),
+ .ten_bit_encoded_data_out (ten_bit_encoded_data_out[9:0]),
+ .invalid_control (invalid_control),
+ .clk (clk),
+ .reset (reset)
+);
+
+decode_10b_8b decode_10b_8b (
+ .ten_bit_encoded_data_in (ten_bit_encoded_data_out[9:0]),
+ .eight_bit_data_or_control_out (eight_bit_data_or_control_out[7:0]),
+ .output_is_control (output_is_control),
+ .invalid_encoded_data (invalid_encoded_data),
+ .clk (clk),
+ .reset (reset)
+);
+endmodule
+`endif // TEST_8B_10B
+
+// `define DISCOVER_WHICH_CODES_ARE_ILLEGAL
+`ifdef DISCOVER_WHICH_CODES_ARE_ILLEGAL
+module figure_out_error_patterns;
+
+// NOTE: For the purpose of comparing with the patent, this exploration
+// module uses the notation that the LEFTMOST BIT is the LSB.
+// All other modules use the more normal Rightmost Bit == bit 0 == LSB
+
+ reg [10:0] i;
+
+ reg [9:0] full_addr;
+ reg [4095:0] valid; // storage
+ reg [4095:0] invalid; // storage
+
+task do_one;
+ input [3:0] high_addr;
+ begin
+ full_addr[3:0] = high_addr[3:0]; // note LSB to left
+ valid[full_addr[9:0]] = 1'b1;
+ end
+endtask
+
+task mark_both;
+ begin
+// both
+ do_one (4'b1001);
+ do_one (4'b0101);
+ do_one (4'b1010);
+ do_one (4'b0110);
+ end
+endtask
+
+// The alternate Data encoding D.x.A7 is used in the case
+// that e = i = 0 and positive running disparity,
+// or e = i = 1 and negative running disparity,
+// or a Control signal is being sent,
+// all while encoding 7 in the MSB.
+
+task mark_positive;
+ begin
+// positive list
+ do_one (4'b0100);
+ do_one (4'b0011);
+ do_one (4'b0010);
+ if (full_addr[5:4] != 2'b00)
+ do_one (4'b0001); // P
+ else
+ do_one (4'b1000); // A
+ end
+endtask
+
+task mark_negative;
+ begin
+// negative list
+ do_one (4'b1011);
+ do_one (4'b1100);
+ do_one (4'b1101);
+ if (full_addr[5:4] != 2'b11)
+ do_one (4'b1110); // P
+ else
+ do_one (4'b0111); // A
+ end
+endtask
+
+task mark_all;
+ begin
+ mark_positive;
+ mark_negative;
+ mark_both;
+ end
+endtask
+
+task mark;
+ input [5:0] val;
+ input type;
+ integer type;
+
+ begin
+ full_addr[9:4] = val[5:0]; // note LSB to left
+ if (type == 0)
+ begin
+ mark_all;
+ end
+ else if (type == 1)
+ begin
+ mark_positive;
+ mark_both;
+ end
+ else
+ begin
+ mark_negative;
+ mark_both;
+ end
+ end
+endtask
+
+initial
+ begin
+
+// Clear all bits
+ for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001)
+ begin
+ valid[i[9:0]] = 1'b0;
+ invalid[full_addr[9:0]] = 1'b0;
+ end
+
+// Mark patterns which are parts of valid codes
+ mark (6'b110001, 0);
+ mark (6'b101001, 0);
+ mark (6'b011001, 0);
+ mark (6'b100101, 0);
+ mark (6'b010101, 0);
+ mark (6'b110100, 0);
+ mark (6'b001101, 0);
+ mark (6'b101100, 0);
+ mark (6'b011100, 0);
+ mark (6'b100011, 0);
+ mark (6'b010011, 0);
+ mark (6'b110010, 0);
+ mark (6'b001011, 0);
+ mark (6'b101010, 0);
+ mark (6'b011010, 0);
+ mark (6'b100110, 0);
+ mark (6'b010110, 0);
+ mark (6'b001110, 0);
+
+ mark (6'b011000, -1);
+ mark (6'b100010, -1);
+ mark (6'b010010, -1);
+ mark (6'b001010, -1);
+ mark (6'b111000, -1);
+ mark (6'b000110, -1);
+ mark (6'b101000, -1);
+ mark (6'b100100, -1);
+ mark (6'b000101, -1);
+ mark (6'b001100, -1);
+ mark (6'b001001, -1);
+ mark (6'b010001, -1);
+ mark (6'b100001, -1);
+ mark (6'b010100, -1);
+
+ mark (6'b100111, +1);
+ mark (6'b011101, +1);
+ mark (6'b101101, +1);
+ mark (6'b110101, +1);
+ mark (6'b000111, +1);
+ mark (6'b111001, +1);
+ mark (6'b010111, +1);
+ mark (6'b011011, +1);
+ mark (6'b111010, +1);
+ mark (6'b110011, +1);
+ mark (6'b110110, +1);
+ mark (6'b101110, +1);
+ mark (6'b011110, +1);
+ mark (6'b101011, +1);
+
+// Mark patterns which are control codes.
+ valid[ 10'b111010_1000] = 1'b1;
+ valid[ 10'b110110_1000] = 1'b1;
+ valid[ 10'b101110_1000] = 1'b1;
+ valid[ 10'b011110_1000] = 1'b1;
+
+ valid[ 10'b001111_0100] = 1'b1;
+ valid[ 10'b001111_1001] = 1'b1;
+ valid[ 10'b001111_0101] = 1'b1;
+ valid[ 10'b001111_0011] = 1'b1;
+ valid[ 10'b001111_0010] = 1'b1;
+ valid[ 10'b001111_1010] = 1'b1;
+ valid[ 10'b001111_0110] = 1'b1;
+ valid[ 10'b001111_1000] = 1'b1;
+
+ valid[~10'b111010_1000] = 1'b1;
+ valid[~10'b110110_1000] = 1'b1;
+ valid[~10'b101110_1000] = 1'b1;
+ valid[~10'b011110_1000] = 1'b1;
+
+ valid[~10'b001111_0100] = 1'b1;
+ valid[~10'b001111_1001] = 1'b1;
+ valid[~10'b001111_0101] = 1'b1;
+ valid[~10'b001111_0011] = 1'b1;
+ valid[~10'b001111_0010] = 1'b1;
+ valid[~10'b001111_1010] = 1'b1;
+ valid[~10'b001111_0110] = 1'b1;
+ valid[~10'b001111_1000] = 1'b1;
+
+ for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001)
+ begin
+// Get rid of patterns in the 6 LSB with less than 2 or greater than 4 bits set.
+ if ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) < 2)
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ if ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) > 4)
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+// Get rid of patterns in the 4 MSB with less than 1 or greater than 3 bits set.
+ if ((i[3:0] == 4'h0) | (i[3:0] == 4'hF))
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+// Get rid of total patterns with less than 4 or greater than 6 bits set.
+ if ((i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9]) < 4)
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ if ((i[0] + i[1] + i[2] + i[3] + i[4] + i[5] + i[6] + i[7] + i[8] + i[9]) > 6)
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+// Get rid of patterns with the 4 LSB all 0 or all 1
+ if ((i[9:6] == 4'b0000) | (i[9:6] == 4'b1111))
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+// Get rid of patterns which use D.7.y with the wrong disparity. 8
+ if ((i[9:4] == 6'b111000) & (i[3] + i[2] + i[1] + i[0] == 1)) // minus then minus
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ if ((i[9:4] == 6'b000111) & (i[3] + i[2] + i[1] + i[0] == 3)) // plus then plus
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+// Get rid of patterns which use D.x.3 with the wrong disparity. 28
+ if ( (i[3:0] == 4'b0011)
+ & ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) == 2))
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ if ( (i[3:0] == 4'b1100)
+ & ((i[9] + i[8] + i[7] + i[6] + i[5] + i[4]) == 4))
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ end
+
+// Get rid of case when D.x.3 and D.7.y are used together as D.7.3
+ valid[10'b111000_0011] = 1'b1;
+ valid[10'b000111_1100] = 1'b1;
+
+ for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001)
+ begin
+// Get rid of non-control codes which use alternate encoding inappropriately. 32
+// These are all the data items except 23, 27, 29, and 30 which do not end in
+// 00 or 11 as the MSB. This excludes control codes, which use alternate encoding.
+ if ( (i[9:4] != 6'b111010) & (i[9:4] != 6'b000101) // 23
+ & (i[9:4] != 6'b110110) & (i[9:4] != 6'b001001) // 27
+ & (i[9:4] != 6'b101110) & (i[9:4] != 6'b010001) // 29
+ & (i[9:4] != 6'b011110) & (i[9:4] != 6'b100001) // 30
+ & (i[9:4] != 6'b001111) & (i[9:4] != 6'b110000) // K28
+ & (i[9:4] != 6'b110100) // 11
+ & (i[9:4] != 6'b101100) // 13
+ & (i[9:4] != 6'b011100) // 14
+ & (i[9:4] != 6'b100011) // 17
+ & (i[9:4] != 6'b010011) // 18
+ & (i[9:4] != 6'b001011) // 20
+ )
+ begin
+ if ((i[3:0] == 4'b0111) | (i[3:0] == 4'b1000))
+ begin
+ invalid[i[9:0]] = 1'b1; // not a candidate for alternate D7 at all
+ end
+ end
+
+ if ( (i[9:4] == 6'b110000) // K28
+ | (i[9:4] == 6'b001111) // K28
+ | (i[9:4] == 6'b110100) // 11
+ | (i[9:4] == 6'b101100) // 13
+ | (i[9:4] == 6'b011100) // 14
+ )
+ begin
+ if (i[3:0] == 4'b0001) // cant use normal +
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ end
+
+ if ( (i[9:4] == 6'b100011) // 17
+ | (i[9:4] == 6'b010011) // 18
+ | (i[9:4] == 6'b001011) // 20
+ )
+ begin
+ if (i[3:0] == 4'b1000) // cant use alternate +
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ end
+
+ if ( (i[9:4] == 6'b110000) // K28
+ | (i[9:4] == 6'b001111) // K28
+ | (i[9:4] == 6'b100011) // 17
+ | (i[9:4] == 6'b010011) // 18
+ | (i[9:4] == 6'b001011) // 20
+ )
+ begin
+ if (i[3:0] == 4'b1110) // cant use normal -
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ end
+
+ if ( (i[9:4] == 6'b110100) // 11
+ | (i[9:4] == 6'b101100) // 13
+ | (i[9:4] == 6'b011100) // 14
+ )
+ begin
+ if (i[3:0] == 4'b0111) // cant use alternate -
+ begin
+ invalid[i[9:0]] = 1'b1;
+ end
+ end
+ end
+
+ $display ("LSB is to the left");
+ for (i[10:0] = 11'h000; i[10:0] < 11'h400; i[10:0] = i[10:0] + 11'h001)
+ begin
+ if ((valid[i[9:0]] !== 1'b1) & (invalid[i[9:0]] !== 1'b1))
+ begin
+ $display ("not set %b", i[9:0]);
+ end
+ if ((valid[i[9:0]] === 1'b1) & (invalid[i[9:0]] === 1'b1))
+ begin
+ $display ("both set %b", i[9:0]);
+ end
+ end
+
+ end
+endmodule
+`endif // DISCOVER_WHICH_CODES_ARE_ILLEGAL
Index: trunk/ddr_2_dram_for_debugging.v
===================================================================
--- trunk/ddr_2_dram_for_debugging.v (nonexistent)
+++ trunk/ddr_2_dram_for_debugging.v (revision 48)
@@ -0,0 +1,2550 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// ddr_2_dram #(frequency, latency, ////
+//// num_addr_bits, num_col_bits, ////
+//// num_data_bits, num_words_in_test_memory) ////
+//// ////
+//// This file is part of the general opencores effort. ////
+//// ////
+//// ////
+//// Module Description: ////
+//// A fake DDR DRAM with a small amount of memory. Useful in ////
+//// getting a DDR DRAM controller working. ////
+//// ////
+//// The DDR DRAM uses a tricky clocking scheme. Unfortunately, ////
+//// this will require a tricky controller. ////
+//// ////
+//// The CLK_P and CLK_N signals provide a time-base for the ////
+//// external IO pins on the DRAM, and may or may not be used ////
+//// as a timebase for internal DRAM activity. ////
+//// ////
+//// The DDR DRAM transfers data on both edges of the CLK_*. ////
+//// However, in order to make the design insensitive to layout ////
+//// and loading concerns, the data is NOT latched by the CLK_P ////
+//// activity. ////
+//// ////
+//// Instead the new signal DQS is used as a clock which runs in ////
+//// parallel with, and uses the same loading as, the Data ////
+//// wires DQ. ////
+//// ////
+//// In the case of writes from a controller to the DDR DRAM, the ////
+//// controller is responsible for placing the edges of DQS so ////
+//// that the edges arrive in the MIDDLE of the data valid ////
+//// period at the DRAMs. ////
+//// ////
+//// The DDR DRAM specs seem to call out that the controller will ////
+//// place the DQS transitions between 0.75 and 1.25 of a clock ////
+//// period after the rising edge of CLK_* which initiates a ////
+//// write. The obvious place to put the DQS signal is right ////
+//// at that edge. This means that the DATA for the write must ////
+//// be sent 1/4 clock EARLIER! ////
+//// ////
+//// In the case of reads from a DDR DRAM to a controller, the ////
+//// DRAM sends out data and data clock (DQ and DQS) with the ////
+//// same timing. The edges for these signals should be at the ////
+//// same time. The Controller has to internally delay the DQS ////
+//// signal by 1/2 of a bit time, and then use the INTERNAL ////
+//// DELAYED DQS signal to latch the DQ wires. ////
+//// ////
+//// The DDR DRAM specs seem to call out that the DRAM will drive ////
+//// DQS between -0.75 and +0.75 nSec of the edges of CLK_*. ////
+//// Of course, it will get to the controller some time later ////
+//// than that. ////
+//// ////
+//// To provide bad timing, this DRAM model will measure the ////
+//// period of the CLK_P clock (assuming that it is 50% duty ////
+//// cycle). It will then deliver data from 0.75 nSec AFTER ////
+//// the clock changes till 0.75 nSec BEFORE it changes again. ////
+//// This will prevent the controller from using the CLK_* ////
+//// signal to latch the data. ////
+//// ////
+//// Author(s): ////
+//// - Anonymous ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Anonymous and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// $Id: ddr_2_dram_for_debugging.v,v 1.8 2001-11-06 12:33:15 bbeaver Exp $
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.10 2001/11/06 12:41:27 Blue Beaver
+// no message
+//
+// Revision 1.9 2001/11/02 11:59:30 Blue Beaver
+// no message
+//
+// Revision 1.8 2001/11/01 13:33:03 Blue Beaver
+// no message
+//
+// Revision 1.7 2001/11/01 12:44:03 Blue Beaver
+// no message
+//
+// Revision 1.6 2001/11/01 11:33:04 Blue Beaver
+// no message
+//
+// Revision 1.5 2001/11/01 09:38:43 Blue Beaver
+// no message
+//
+// Revision 1.4 2001/10/31 12:30:01 Blue Beaver
+// no message
+//
+// Revision 1.3 2001/10/30 12:44:03 Blue Beaver
+// no message
+//
+// Revision 1.2 2001/10/30 08:56:18 Blue Beaver
+// no message
+//
+// Revision 1.1 2001/10/29 13:45:02 Blue Beaver
+// no message
+//
+
+`timescale 1ns / 1ps
+
+module ddr_2_dram (
+ DQ, DQS,
+ DM,
+ A, BA,
+ RAS_L,
+ CAS_L,
+ WE_L,
+ CS_L,
+ CKE,
+ CLK_P, CLK_N
+);
+
+// Constant Parameters
+parameter FREQUENCY = 133.0; // might be 100, 125, 166, any other frequency
+parameter LATENCY = 2.0; // might be 2.0, 2.5, 3.0, 3.5, 4.0
+parameter NUM_ADDR_BITS = 13;
+parameter NUM_COL_BITS = 11;
+parameter NUM_DATA_BITS = 4;
+parameter NUM_WORDS_IN_TEST_MEMORY = 32;
+parameter ENABLE_TIMING_CHECKS = 1;
+
+ inout [NUM_DATA_BITS - 1 : 0] DQ;
+ inout DQS;
+ input DM;
+ input [NUM_ADDR_BITS - 1 : 0] A;
+ input [1 : 0] BA;
+ input RAS_L;
+ input CAS_L;
+ input WE_L;
+ input CS_L;
+ input CKE;
+ input CLK_P, CLK_N;
+
+// These signals can be accessed by upper scopes to detect chip-to-chip OE conflicts.
+ wire DEBUG_DQ_OE, DEBUG_DQS_OE;
+
+// Try to measure the input clock, to correctly apply X's on
+// the data wires near when the outputs change.
+// I have to try to make X's BEFORE the next clock edge!
+// This measurement is irrespective of the frequency parameter,
+// which is used only to set the number of cycles between events.
+
+ time present_rising_time, high_period;
+ time present_falling_time, low_period;
+ reg data_delay1, data_delay2;
+
+ initial
+ begin
+ present_rising_time = 0;
+ present_falling_time = 0;
+ high_period = 0;
+ low_period = 0;
+ data_delay1 = 1'b0;
+ data_delay2 = 1'b0;
+ end
+
+ always @(CLK_P)
+ begin
+ if (CLK_P === 1'b1) // rising edge
+ begin
+ present_rising_time = $time;
+ if ((present_rising_time !== 0) & (present_falling_time !== 0))
+ begin
+ high_period = present_rising_time - present_falling_time - (2 * 750);
+ end
+ end
+ if (CLK_P === 1'b0) // falling edge
+ begin
+ present_falling_time = $time;
+ if ((present_rising_time !== 0) & (present_falling_time !== 0))
+ begin
+ low_period = present_falling_time - present_rising_time - (2 * 750);
+ end
+ end
+ end
+
+// Once the period of the clock is known, start making X's whenever possible
+ always @(posedge CLK_P)
+ begin
+ if (high_period !== 0)
+ begin // Make X's after rising edge, and before falling edge
+ #750 data_delay1 = 1'b1;
+ #high_period data_delay2 = 1'b1;
+ end
+ else
+ begin
+ data_delay1 = 1'b1;
+ data_delay2 = 1'b1;
+ end
+ if (CLK_N !== 1'b0)
+ begin
+ $display ("*** %m DDR DRAM needs to have CLK_N transition with CLK_P at time %t", $time);
+ end
+ end
+
+ always @(negedge CLK_P)
+ begin
+ if (low_period !== 0)
+ begin // Make X's after falling edge, and before rising edge
+ #750 data_delay1 = 1'b0;
+ #low_period data_delay2 = 1'b0;
+ end
+ else
+ begin
+ data_delay1 = 1'b0;
+ data_delay2 = 1'b0;
+ end
+ if (CLK_N !== 1'b1)
+ begin
+ $display ("*** %m DDR DRAM needs to have CLK_N transition with CLK_P at time %t", $time);
+ end
+ end
+
+ wire force_x = (data_delay1 == data_delay2);
+
+// Watch for cases where both banks are driving the Data bus at once.
+// Normally, the second read would terminate the first read. This
+// module, since it is only for debugging, only understands complete
+// 4-word burst transfers.
+
+ wire [NUM_DATA_BITS - 1 : 0] DQ_E_out_0;
+ wire [NUM_DATA_BITS - 1 : 0] DQ_O_out_0;
+ wire DQ_E_oe_0, DQS_E_out_0, DQS_E_oe_0, Timing_Error_0;
+ wire DQ_O_oe_0, DQS_O_out_0, DQS_O_oe_0;
+
+ wire [NUM_DATA_BITS - 1 : 0] DQ_E_out_1;
+ wire [NUM_DATA_BITS - 1 : 0] DQ_O_out_1;
+ wire DQ_E_oe_1, DQS_E_out_1, DQS_E_oe_1, Timing_Error_1;
+ wire DQ_O_oe_1, DQS_O_out_1, DQS_O_oe_1;
+
+ wire [NUM_DATA_BITS - 1 : 0] DQ_E_out_2;
+ wire [NUM_DATA_BITS - 1 : 0] DQ_O_out_2;
+ wire DQ_E_oe_2, DQS_E_out_2, DQS_E_oe_2, Timing_Error_2;
+ wire DQ_O_oe_2, DQS_O_out_2, DQS_O_oe_2;
+
+ wire [NUM_DATA_BITS - 1 : 0] DQ_E_out_3;
+ wire [NUM_DATA_BITS - 1 : 0] DQ_O_out_3;
+ wire DQ_E_oe_3, DQS_E_out_3, DQS_E_oe_3, Timing_Error_3;
+ wire DQ_O_oe_3, DQS_O_out_3, DQS_O_oe_3;
+
+ always @( DQ_E_oe_0 or DQ_E_oe_1 or DQ_E_oe_2 or DQ_E_oe_3
+ or DQS_E_out_0 or DQS_E_out_1 or DQS_E_out_2 or DQS_E_out_3
+ or DQS_E_oe_0 or DQS_E_oe_1 or DQS_E_oe_2 or DQS_E_oe_3
+ or DQ_O_oe_0 or DQ_O_oe_1 or DQ_O_oe_2 or DQ_O_oe_3
+ or DQS_O_out_0 or DQS_O_out_1 or DQS_O_out_2 or DQS_O_out_3
+ or DQS_O_oe_0 or DQS_O_oe_1 or DQS_O_oe_2 or DQS_O_oe_3 )
+
+ begin
+ if ( (DQ_E_oe_0 & DQ_E_oe_1) | (DQ_E_oe_0 & DQ_E_oe_2) | (DQ_E_oe_0 & DQ_E_oe_3)
+ | (DQ_E_oe_1 & DQ_E_oe_2) | (DQ_E_oe_1 & DQ_E_oe_3) | (DQ_E_oe_2 & DQ_E_oe_3)
+ | (DQ_O_oe_0 & DQ_O_oe_1) | (DQ_O_oe_0 & DQ_O_oe_2) | (DQ_O_oe_0 & DQ_O_oe_3)
+ | (DQ_O_oe_1 & DQ_O_oe_2) | (DQ_O_oe_1 & DQ_O_oe_3) | (DQ_O_oe_2 & DQ_O_oe_3) )
+
+ begin
+ $display ("*** %m DDR DRAM has multiple banks driving DQ at the same time at %x %t",
+ {DQ_E_oe_3, DQ_O_oe_3, DQ_E_oe_2, DQ_O_oe_2, DQ_E_oe_1, DQ_O_oe_1, DQ_E_oe_0, DQ_O_oe_0}, $time);
+ end
+ if ( ((DQS_E_oe_0 & DQS_E_oe_1) & ((DQS_E_out_0 != 1'b0) | (DQS_E_out_1 != 1'b0)))
+ | ((DQS_E_oe_0 & DQS_E_oe_2) & ((DQS_E_out_0 != 1'b0) | (DQS_E_out_2 != 1'b0)))
+ | ((DQS_E_oe_0 & DQS_E_oe_3) & ((DQS_E_out_0 != 1'b0) | (DQS_E_out_3 != 1'b0)))
+ | ((DQS_E_oe_1 & DQS_E_oe_2) & ((DQS_E_out_1 != 1'b0) | (DQS_E_out_2 != 1'b0)))
+ | ((DQS_E_oe_1 & DQS_E_oe_3) & ((DQS_E_out_1 != 1'b0) | (DQS_E_out_3 != 1'b0)))
+ | ((DQS_E_oe_2 & DQS_E_oe_3) & ((DQS_E_out_2 != 1'b0) | (DQS_E_out_3 != 1'b0))) )
+ begin
+ $display ("*** %m DDR DRAM Even has multiple banks driving DQS at the same time at %x %x %t",
+ {DQS_E_oe_3, DQS_E_oe_2, DQS_E_oe_1, DQS_E_oe_0},
+ {DQS_E_out_3, DQS_E_out_2, DQS_E_out_1, DQS_E_out_0}, $time);
+ end
+ if ( ((DQS_O_oe_0 & DQS_O_oe_1) & ((DQS_O_out_0 != 1'b0) | (DQS_O_out_1 != 1'b0)))
+ | ((DQS_O_oe_0 & DQS_O_oe_2) & ((DQS_O_out_0 != 1'b0) | (DQS_O_out_2 != 1'b0)))
+ | ((DQS_O_oe_0 & DQS_O_oe_3) & ((DQS_O_out_0 != 1'b0) | (DQS_O_out_3 != 1'b0)))
+ | ((DQS_O_oe_1 & DQS_O_oe_2) & ((DQS_O_out_1 != 1'b0) | (DQS_O_out_2 != 1'b0)))
+ | ((DQS_O_oe_1 & DQS_O_oe_3) & ((DQS_O_out_1 != 1'b0) | (DQS_O_out_3 != 1'b0)))
+ | ((DQS_O_oe_2 & DQS_O_oe_3) & ((DQS_O_out_2 != 1'b0) | (DQS_O_out_3 != 1'b0))) )
+ begin
+ $display ("*** %m DDR DRAM Odd has multiple banks driving DQS at the same time at %x %x %t",
+ {DQS_O_oe_3, DQS_O_oe_2, DQS_O_oe_1, DQS_O_oe_0},
+ {DQS_O_out_3, DQS_O_out_2, DQS_O_out_1, DQS_O_out_0}, $time);
+ end
+ end
+
+ assign DEBUG_DQ_OE = DQ_E_oe_0 | DQ_E_oe_1 | DQ_E_oe_2 | DQ_E_oe_3
+ | DQ_O_oe_0 | DQ_O_oe_1 | DQ_O_oe_2 | DQ_O_oe_3;
+ assign DEBUG_DQS_OE = DQS_E_oe_0 | DQS_E_oe_1 | DQS_E_oe_2 | DQS_E_oe_3
+ | DQS_O_oe_0 | DQS_O_oe_1 | DQS_O_oe_2 | DQS_O_oe_3;
+
+// The top-level code here is responsible for delaying the data as needed
+// to meet the LATENCY requirement.
+
+// LATENCY,
+//parameter LATENCY = 2.0; // might be 2.0, 2.5, 3.0, 3.5, 4.0
+
+ddr_2_dram_single_bank
+# ( FREQUENCY,
+ LATENCY,
+ NUM_ADDR_BITS,
+ NUM_COL_BITS,
+ NUM_DATA_BITS,
+ NUM_WORDS_IN_TEST_MEMORY,
+ 1 // enable_timing_checks
+ ) ddr_2_dram_single_bank_0 (
+ .DQ (DQ[NUM_DATA_BITS - 1 : 0]),
+ .DQS (DQS),
+ .DQ_E_out (DQ_E_out_0[NUM_DATA_BITS - 1 : 0]),
+ .DQ_O_out (DQ_O_out_0[NUM_DATA_BITS - 1 : 0]),
+ .DQ_E_oe (DQ_E_oe_0),
+ .DQ_O_oe (DQ_O_oe_0),
+ .DQS_E_out (DQS_E_out_0),
+ .DQS_O_out (DQS_O_out_0),
+ .DQS_E_oe (DQS_E_oe_0),
+ .DQS_O_oe (DQS_O_oe_0),
+ .Timing_Error (Timing_Error_0),
+ .DM (DM),
+ .A (A[12:0]),
+ .BA (BA[1:0]),
+ .RAS_L (RAS_L),
+ .CAS_L (CAS_L),
+ .WE_L (WE_L),
+ .CS_L (CS_L),
+ .CKE (CKE),
+ .CLK_P (CLK_P),
+ .CLK_N (CLK_N),
+ .bank_num (2'b00)
+);
+
+ddr_2_dram_single_bank
+# ( FREQUENCY,
+ LATENCY,
+ NUM_ADDR_BITS,
+ NUM_COL_BITS,
+ NUM_DATA_BITS,
+ NUM_WORDS_IN_TEST_MEMORY,
+ 0 // enable_timing_checks
+ ) ddr_2_dram_single_bank_1 (
+ .DQ (DQ[NUM_DATA_BITS - 1 : 0]),
+ .DQS (DQS),
+ .DQ_E_out (DQ_E_out_1[NUM_DATA_BITS - 1 : 0]),
+ .DQ_O_out (DQ_O_out_1[NUM_DATA_BITS - 1 : 0]),
+ .DQ_E_oe (DQ_E_oe_1),
+ .DQ_O_oe (DQ_O_oe_1),
+ .DQS_E_out (DQS_E_out_1),
+ .DQS_O_out (DQS_O_out_1),
+ .DQS_E_oe (DQS_E_oe_1),
+ .DQS_O_oe (DQS_O_oe_1),
+ .Timing_Error (Timing_Error_1),
+ .DM (DM),
+ .A (A[12:0]),
+ .BA (BA[1:0]),
+ .RAS_L (RAS_L),
+ .CAS_L (CAS_L),
+ .WE_L (WE_L),
+ .CS_L (CS_L),
+ .CKE (CKE),
+ .CLK_P (CLK_P),
+ .CLK_N (CLK_N),
+ .bank_num (2'b01)
+);
+
+ddr_2_dram_single_bank
+# ( FREQUENCY,
+ LATENCY,
+ NUM_ADDR_BITS,
+ NUM_COL_BITS,
+ NUM_DATA_BITS,
+ NUM_WORDS_IN_TEST_MEMORY,
+ 0 // enable_timing_checks
+ ) ddr_2_dram_single_bank_2 (
+ .DQ (DQ[NUM_DATA_BITS - 1 : 0]),
+ .DQS (DQS),
+ .DQ_E_out (DQ_E_out_2[NUM_DATA_BITS - 1 : 0]),
+ .DQ_O_out (DQ_O_out_2[NUM_DATA_BITS - 1 : 0]),
+ .DQ_E_oe (DQ_E_oe_2),
+ .DQ_O_oe (DQ_O_oe_2),
+ .DQS_E_out (DQS_E_out_2),
+ .DQS_O_out (DQS_O_out_2),
+ .DQS_E_oe (DQS_E_oe_2),
+ .DQS_O_oe (DQS_O_oe_2),
+ .Timing_Error (Timing_Error_2),
+ .DM (DM),
+ .A (A[12:0]),
+ .BA (BA[1:0]),
+ .RAS_L (RAS_L),
+ .CAS_L (CAS_L),
+ .WE_L (WE_L),
+ .CS_L (CS_L),
+ .CKE (CKE),
+ .CLK_P (CLK_P),
+ .CLK_N (CLK_N),
+ .bank_num (2'b10)
+);
+
+ddr_2_dram_single_bank
+# ( FREQUENCY,
+ LATENCY,
+ NUM_ADDR_BITS,
+ NUM_COL_BITS,
+ NUM_DATA_BITS,
+ NUM_WORDS_IN_TEST_MEMORY,
+ 0 // enable_timing_checks
+ ) ddr_2_dram_single_bank_3 (
+ .DQ (DQ[NUM_DATA_BITS - 1 : 0]),
+ .DQS (DQS),
+ .DQ_E_out (DQ_E_out_3[NUM_DATA_BITS - 1 : 0]),
+ .DQ_O_out (DQ_O_out_3[NUM_DATA_BITS - 1 : 0]),
+ .DQ_E_oe (DQ_E_oe_3),
+ .DQ_O_oe (DQ_O_oe_3),
+ .DQS_E_out (DQS_E_out_3),
+ .DQS_O_out (DQS_O_out_3),
+ .DQS_E_oe (DQS_E_oe_3),
+ .DQS_O_oe (DQS_O_oe_3),
+ .Timing_Error (Timing_Error_3),
+ .DM (DM),
+ .A (A[12:0]),
+ .BA (BA[1:0]),
+ .RAS_L (RAS_L),
+ .CAS_L (CAS_L),
+ .WE_L (WE_L),
+ .CS_L (CS_L),
+ .CKE (CKE),
+ .CLK_P (CLK_P),
+ .CLK_N (CLK_N),
+ .bank_num (2'b11)
+);
+
+endmodule
+
+module ddr_2_dram_single_bank (
+ DQ, DQS,
+ DQ_E_out, DQ_O_out, DQ_E_oe, DQ_O_oe,
+ DQS_E_out, DQS_O_out, DQS_E_oe, DQS_O_oe,
+ Timing_Error,
+ DM,
+ A, BA,
+ RAS_L,
+ CAS_L,
+ WE_L,
+ CS_L,
+ CKE,
+ CLK_P, CLK_N,
+ bank_num
+);
+
+// Constant Parameters
+parameter FREQUENCY = 133.0; // might be 100, 125, 166, any other frequency
+parameter LATENCY = 2.0; // might be 2.0, 2.5, 3.0, 3.5, 4.0, 4.5
+parameter NUM_ADDR_BITS = 13;
+parameter NUM_COL_BITS = 12;
+parameter NUM_DATA_BITS = 4;
+parameter NUM_WORDS_IN_TEST_MEMORY = 32;
+parameter ENABLE_TIMING_CHECKS = 1;
+
+ input [NUM_DATA_BITS - 1 : 0] DQ;
+ input DQS;
+ output [NUM_DATA_BITS - 1 : 0] DQ_E_out;
+ output [NUM_DATA_BITS - 1 : 0] DQ_O_out;
+ output DQ_E_oe, DQ_O_oe;
+ output DQS_E_out, DQS_O_out, DQS_E_oe, DQS_O_oe;
+ output Timing_Error;
+ input DM;
+ input [NUM_ADDR_BITS - 1 : 0] A;
+ input [1 : 0] BA;
+ input RAS_L;
+ input CAS_L;
+ input WE_L;
+ input CS_L;
+ input CKE;
+ input CLK_P, CLK_N;
+ input [1:0] bank_num;
+
+// DDR DRAMs always capture their command on the RISING EDGE of CLK_P;
+// This fake DDR DRAM understands: Idle, Activate, Read, Write, Automatic Refresh
+// This fake DDR DRAM assumes that all Reads and Writes do automatic precharge.
+// This fake DDR DRAM understands writes to the control register
+// This fake DDR DRAM always does 4-word bursts. The first word of data
+// is always the legal one. The next 3 are that first word inverted.
+// DDR DRAMs always capture their data on BOTH EDGES of DQS
+// DDR DRAMs always output enable the DQS wire to 1'h0 1 clock before
+// they start sending data
+// DDR DRAMs will be allowed to have a latency of 2, 2.5, 3, 3.5, 4, 4.5
+// from the read command.
+
+// DDR DRAM commands are made by using the following sighals:
+// {CKE, CS_L, RAS_L, CAS_L, WS_L}
+// 0 X X X X power-down
+// 1 1 X X X NOOP
+// 1 0 1 1 1 NOOP
+// 1 0 0 1 1 ACTIVATE
+// 1 0 1 0 1 READ (A10)
+// 1 0 1 0 0 WRITE (A10)
+// 1 0 0 1 0 PRECHARGE (A10)
+// 1 0 0 0 1 AUTO REFRESH
+// 1 0 0 0 0 LOAD MODE REGISTER
+// 1 0 1 1 0 not used?
+
+parameter NOOP = 5'h17;
+parameter LOAD_MODE = 5'h10;
+parameter ACTIVATE_BANK = 5'h13;
+parameter READ_BANK = 5'h15;
+parameter WRITE_BANK = 5'h14;
+parameter PRECHARGE_BANK = 5'h12;
+parameter REFRESH_BANK = 5'h11;
+
+ wire [4:0] control_wires = {CKE, CS_L, RAS_L, CAS_L, WE_L};
+
+// This simple-minded DRAM assumes that all transactions are valid.
+// Therefore, it always captures RAS and CAS address information, even
+// if there is an obvious protocol violation.
+
+ reg [NUM_ADDR_BITS - 1 : 0] Captured_RAS_Address;
+ reg [1:0] Captured_RAS_Bank_Selects;
+
+ reg [NUM_ADDR_BITS - 1 : 0] Captured_CAS_Address;
+ reg [1:0] Captured_CAS_Bank_Selects;
+
+ reg RAS_Address_Valid;
+ reg Full_Address_Valid;
+ reg DRAM_Read_Requested;
+
+// synopsys translate_off
+ initial
+ begin // only for debug
+ RAS_Address_Valid <= 1'b0;
+ Full_Address_Valid <= 1'b0;
+ end
+// synopsys translate_on
+
+// Capture RAS and CAS address information
+ always @(posedge CLK_P)
+ begin
+ if ((control_wires[4:0] == ACTIVATE_BANK) & (BA[1:0] == bank_num[1:0]))
+ begin
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0] <= A[NUM_ADDR_BITS - 1 : 0];
+ Captured_RAS_Bank_Selects[1:0] <= BA[1 : 0];
+ RAS_Address_Valid <= 1'b1;
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_CAS_Bank_Selects[1:0] <= Captured_CAS_Bank_Selects[1:0];
+ DRAM_Read_Requested <= 1'b0;
+ Full_Address_Valid <= 1'b0;
+ end
+ else if ((control_wires[4:0] == READ_BANK) & (BA[1:0] == bank_num[1:0]))
+ begin
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_RAS_Bank_Selects[1:0] <= Captured_RAS_Bank_Selects[1:0];
+ if (A[10] == 1'b1) // automatic precharge
+ RAS_Address_Valid <= 1'b0;
+ else
+ RAS_Address_Valid <= 1'b1;
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0] <= A[NUM_ADDR_BITS - 1 : 0];
+ Captured_CAS_Bank_Selects[1:0] <= BA[1 : 0];
+ DRAM_Read_Requested <= 1'b1;
+ Full_Address_Valid <= 1'b1;
+ if (RAS_Address_Valid == 1'b0)
+ begin
+ $display ("*** %m DRAM accessed for Read without first doing an Activate %t", $time);
+ end
+ end
+ else if ((control_wires[4:0] == WRITE_BANK) & (BA[1:0] == bank_num[1:0]))
+ begin
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_RAS_Bank_Selects[1:0] <= Captured_RAS_Bank_Selects[1:0];
+ if (A[10] == 1'b1) // automatic precharge
+ RAS_Address_Valid <= 1'b0;
+ else
+ RAS_Address_Valid <= 1'b1;
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0] <= A[NUM_ADDR_BITS - 1 : 0];
+ Captured_CAS_Bank_Selects[1:0] <= BA[1 : 0];
+ DRAM_Read_Requested <= 1'b0;
+ Full_Address_Valid <= 1'b1;
+ if (RAS_Address_Valid == 1'b0)
+ begin
+ $display ("*** %m DRAM accessed for Write without first doing an Activate %t", $time);
+ end
+ end
+ else if ( (control_wires[4:0] == PRECHARGE_BANK)
+ & ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1)))
+ begin
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_RAS_Bank_Selects[1:0] <= Captured_RAS_Bank_Selects[1:0];
+ RAS_Address_Valid <= 1'b0;
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_CAS_Bank_Selects[1:0] <= Captured_CAS_Bank_Selects[1:0];
+ DRAM_Read_Requested <= 1'b0;
+ Full_Address_Valid <= 1'b0;
+ end
+ else // NOOP, Load Mode Register, Refresh, Unallocated
+ begin
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_RAS_Bank_Selects[1:0] <= Captured_RAS_Bank_Selects[1:0];
+ RAS_Address_Valid <= RAS_Address_Valid;
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0] <=
+ Captured_CAS_Address[NUM_ADDR_BITS - 1 : 0];
+ Captured_CAS_Bank_Selects[1:0] <= Captured_CAS_Bank_Selects[1:0];
+ DRAM_Read_Requested <= 1'b0;
+ Full_Address_Valid <= 1'b0;
+ end
+ end
+
+// This debugging DRAM requires that entire 4-word bursts be done.
+// At present, this design does not implement DM masking.
+// This debugging DRAM captures data using the DQS signals. It
+// immediately moves the data into the CLK_P positive edge clock domain.
+
+ reg [NUM_DATA_BITS - 1 : 0] DQS_Captured_Write_Data_Even;
+ reg [NUM_DATA_BITS - 1 : 0] DQS_Captured_Write_Data_Odd;
+ reg DQS_Captured_Write_DM_Even, DQS_Captured_Write_DM_Odd;
+ reg [NUM_DATA_BITS - 1 : 0] Delay_Write_Data_Even;
+ reg [NUM_DATA_BITS - 1 : 0] Sync_Write_Data_Even;
+ reg [NUM_DATA_BITS - 1 : 0] Sync_Write_Data_Odd;
+ reg Delay_Write_DM_Even, Sync_Write_DM_Even, Sync_Write_DM_Odd;
+
+// Capture data on rising edge of DQS
+ always @(posedge DQS)
+ begin
+ DQS_Captured_Write_Data_Even[NUM_DATA_BITS - 1 : 0] <= DQ[NUM_DATA_BITS - 1 : 0];
+ DQS_Captured_Write_DM_Even <= DM;
+ end
+
+// Delay data captured on rising edge so that it can be captured the NEXT rising edge
+ always @(negedge CLK_P)
+ begin
+ Delay_Write_Data_Even[NUM_DATA_BITS - 1 : 0] <=
+ DQS_Captured_Write_Data_Even[NUM_DATA_BITS - 1 : 0];
+ Delay_Write_DM_Even <= DQS_Captured_Write_DM_Even;
+ end
+
+// Capture data on falling edge of DQS
+ always @(negedge DQS)
+ begin
+ DQS_Captured_Write_Data_Odd[NUM_DATA_BITS - 1 : 0] <= DQ[NUM_DATA_BITS - 1 : 0];
+ DQS_Captured_Write_DM_Odd <= DM;
+ end
+
+// Capture a data item pair into the positive edge clock domain.
+ always @(posedge CLK_P)
+ begin
+ Sync_Write_Data_Even[NUM_DATA_BITS - 1 : 0] <=
+ Delay_Write_Data_Even[NUM_DATA_BITS - 1 : 0];
+ Sync_Write_Data_Odd[NUM_DATA_BITS - 1 : 0] <=
+ DQS_Captured_Write_Data_Odd[NUM_DATA_BITS - 1 : 0];
+ Sync_Write_DM_Even <= Delay_Write_DM_Even;
+ Sync_Write_DM_Odd <= DQS_Captured_Write_DM_Odd;
+ end
+
+// For Writes, the CAS Address comes in at time T0.
+// Data is available on the external DQ wires at time T1 and T2;
+// Data is available as Sync_Write_Data at times T2 and T3
+// The SRAM can be written as soon as the last data is available,
+// which seems to be at T4.
+//
+// For Reads, the Address comes in at time T0.
+// The DQS signal needs to start being driven to 1'b0 at T1
+// The DQ signals need to start being driven with valid data at T2
+// Both DQS and DQ need to be valid until the beginning of T4
+//
+// At first glance, it would seem that the Read Data needs to be
+// grabbed out of the DRAM before, or at the same time, as the
+// data is written into the DRAM.
+// Fortunately, the parameter TWTR says that there must be 1 extra
+// clock between a Write and a Read to serve as a Write Recovery
+// time. Write data is available out of the internal Sync DRAM
+// storage element in plenty of time to get to the bus.
+
+ reg [NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0] DRAM_Address_T1;
+ reg [NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0] DRAM_Address_T2;
+ reg [NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0] DRAM_Address_T3;
+ reg [1:0] BANK_Address_T1, BANK_Address_T2, BANK_Address_T3;
+ reg DRAM_Read_T1, DRAM_Read_T2, DRAM_Read_T3;
+ reg DRAM_Full_Addr_Valid_T1, DRAM_Full_Addr_Valid_T2, DRAM_Full_Addr_Valid_T3;
+ reg [NUM_DATA_BITS - 1 : 0] Delayed_Sync_Write_Data_Even_T3;
+ reg [NUM_DATA_BITS - 1 : 0] Delayed_Sync_Write_Data_Odd_T3;
+
+// Pipeline delay the Read and Write address so that it stays available
+// all the way up to the time the data is available and the whole
+// lot of it is written to storage.
+
+ always @(posedge CLK_P)
+ begin
+ DRAM_Address_T1[NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0] <=
+ {Captured_RAS_Address[NUM_ADDR_BITS - 1 : 0],
+ Captured_CAS_Address[NUM_COL_BITS - 1 : 11], // skip address bit 10
+ Captured_CAS_Address[9 : 0]};
+ DRAM_Address_T2[NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0] <=
+ DRAM_Address_T1[NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0];
+ DRAM_Address_T3[NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0] <=
+ DRAM_Address_T2[NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0];
+ BANK_Address_T1[1:0] <= Captured_CAS_Bank_Selects[1:0];
+ BANK_Address_T2[1:0] <= BANK_Address_T1[1:0];
+ BANK_Address_T3[1:0] <= BANK_Address_T2[1:0];
+ DRAM_Read_T1 <= DRAM_Read_Requested;
+ DRAM_Read_T2 <= DRAM_Read_T1;
+ DRAM_Read_T3 <= DRAM_Read_T2;
+ DRAM_Full_Addr_Valid_T1 <= Full_Address_Valid;
+ DRAM_Full_Addr_Valid_T2 <= DRAM_Full_Addr_Valid_T1;
+ DRAM_Full_Addr_Valid_T3 <= DRAM_Full_Addr_Valid_T2;
+ Delayed_Sync_Write_Data_Even_T3[NUM_DATA_BITS - 1 : 0] <=
+ Sync_Write_Data_Even[NUM_DATA_BITS - 1 : 0];
+ Delayed_Sync_Write_Data_Odd_T3[NUM_DATA_BITS - 1 : 0] <=
+ Sync_Write_Data_Odd[NUM_DATA_BITS - 1 : 0];
+ end
+
+
+ assign DQ_E_oe = 1'b0;
+ assign DQ_O_oe = 1'b0;
+ assign DQS_E_oe = 1'b0;
+ assign DQS_O_oe = 1'b0;
+
+// Storage
+
+ wire [(4 * NUM_DATA_BITS) - 1 : 0] write_data =
+ {Sync_Write_Data_Odd[NUM_DATA_BITS - 1 : 0],
+ Sync_Write_Data_Even[NUM_DATA_BITS - 1 : 0],
+ Delayed_Sync_Write_Data_Odd_T3[NUM_DATA_BITS - 1 : 0],
+ Delayed_Sync_Write_Data_Even_T3[NUM_DATA_BITS - 1 : 0]};
+ wire [(4 * NUM_DATA_BITS) - 1 : 0] read_data;
+
+sram_for_debugging_sync
+# ( NUM_ADDR_BITS + NUM_COL_BITS,
+ 4 * NUM_DATA_BITS // NUM_DATA_BITS
+ ) storage (
+ .data_out (read_data[(4 * NUM_DATA_BITS) - 1 : 0]),
+ .data_in (write_data[(4 * NUM_DATA_BITS) - 1 : 0]),
+ .address (DRAM_Address_T3[NUM_ADDR_BITS + NUM_COL_BITS - 1 : 0]),
+ .read_enable (DRAM_Full_Addr_Valid_T3 & DRAM_Read_T3),
+ .write_enable (DRAM_Full_Addr_Valid_T3 & ~DRAM_Read_T3),
+ .clk (CLK_P)
+);
+
+// These are the important DDR DRAM timing specs in nanoseconds:
+parameter LOAD_MODE_REGISTER_PERIOD_TMRD = 15.0; // stay idle after load mode
+parameter ACT_A_TO_ACT_B_TRRD = 15.0; // Activate-to-activate minimum time
+parameter ACT_TO_READ_OR_WRITE_TRCD = 20.0;
+parameter ACT_TO_PRECHARGE_TRAS = 40.0;
+parameter ACT_TO_REFRESH_TRC = 65.0;
+parameter ACT_A_TO_ACT_A_TRC = 65.0; // needed if failover
+parameter WRITE_RECOVERY_TO_PRECHARGE_TWR = 15.0;
+parameter PRECHARGE_PERIOD_TRP = 20.0;
+parameter REFRESH_PERIOD_TRFC = 75.0;
+
+parameter CLOCK_PERIOD = (1.0 / FREQUENCY);
+
+// These timing requirements become CYCLE requirements, depending on the
+// operating frequency. Note that 133.333 MHz = 7.5 nSec;
+// These calculations assume that 133 MHz is the fastest this circuit will run.
+// These are calculated by doing (N * 1/period) for N big enough to result in > 85 MHz.
+// Each 1/period gives a frequency to test for, and each N gives the cycle count.
+// Example: 20 nSec gives N * 50 MHz. So for N == 2, that gives 100 MHz > 85 MHz.
+// If FREQUENCY > 100 MHz, use N = 2, else use N = 1;
+// The cycle count is the number of cycles to HOLD OFF doing the next command.
+// p.s. Note I don't know how to take the integer part of something in verilog!
+
+parameter LOAD_MODE_REGISTER_CYCLES = (FREQUENCY > 133.334) ? 3 : 2;
+parameter ACT_A_TO_ACT_B_CYCLES = (FREQUENCY > 133.334) ? 3 : 2;
+parameter ACT_TO_READ_OR_WRITE_CYCLES = (FREQUENCY > 100.000) ? 3 : 2;
+parameter ACT_TO_PRECHARGE_CYCLES = (FREQUENCY > 125.000) ? 6
+ : ((FREQUENCY > 100.000) ? 5 : 4);
+// parameter ACK_TO_REFRESH_CYCLES = (FREQUENCY > 123.075) ? 9
+// : ((FREQUENCY > 107.690) ? 8
+// : ((FREQUENCY > 92.300) ? 7 : 6));
+parameter ACT_A_TO_ACT_A_CYCLES = (FREQUENCY > 123.075) ? 9
+ : ((FREQUENCY > 107.690) ? 8
+ : ((FREQUENCY > 92.300) ? 7 : 6));
+parameter READ_TO_WRITE_CYCLES = (LATENCY > 4.0) ? 5
+ : ((LATENCY > 3.0) ? 4
+ : ((LATENCY > 2.0) ? 3 : 2));
+parameter WRITE_TO_READ_CYCLES = 2;
+parameter WRITE_RECOVERY_TO_PRECHARGE_CYCLES = (FREQUENCY > 133.334) ? 3 : 2;
+parameter PRECHARGE_CYCLES = (FREQUENCY > 100.000) ? 3 : 2;
+parameter REFRESH_CYCLES = (FREQUENCY > 133.334) ? 11
+ : ((FREQUENCY > 120.000) ? 10
+ : ((FREQUENCY > 106.667) ? 9
+ : ((FREQUENCY > 93.330) ? 8 : 7)));
+
+// The DDR-II DRAM has 4 banks. Each bank can operate independently, with
+// only a few exceptions.
+//
+// Each bank needs counters to
+// 1) prevent refresh too soon after activate
+// 2) prevent activate to same bank too soon after activate
+// 3) prevent activate to alternate bank too soon after activate
+// 4) prevent (or notice) precharge too soon after activate
+// 5) count out autorefresh delay
+
+ reg [3:0] load_mode_delay_counter;
+ reg [3:0] act_a_to_act_b_counter;
+ reg [3:0] act_to_read_or_write_counter;
+ reg [3:0] act_to_precharge_counter;
+ reg [3:0] act_a_to_act_a_counter; // double use for act_to_refresh and act_a_to_act_a
+ reg [3:0] burst_counter;
+ reg [3:0] read_to_write_counter;
+ reg [3:0] write_to_read_counter;
+ reg [3:0] write_recovery_counter;
+ reg [3:0] precharge_counter;
+ reg [3:0] refresh_counter;
+
+parameter POWER_ON = 0;
+parameter WRITING_REG = 1;
+parameter BANK_IDLE = 2;
+parameter ACTIVATING = 3;
+parameter WRITING = 4;
+parameter WRITING_PRECHARGE = 5;
+parameter READING = 6;
+parameter READING_PRECHARGE = 7;
+parameter PRECHARGING = 8;
+parameter REFRESHING = 9;
+parameter WAITING_FOR_AUTO_PRECHARGE = 10;
+
+parameter BANK_STATE_WIDTH = 4;
+
+ reg [BANK_STATE_WIDTH - 1 : 0] bank_state;
+ reg Timing_Error;
+
+ initial
+ begin // nail state to known at the start of simulation
+ bank_state[BANK_STATE_WIDTH - 1 : 0] = POWER_ON; // nail it to known at the start of simulation
+ end
+
+ always @(posedge CLK_P)
+ begin
+ if (ENABLE_TIMING_CHECKS != 0)
+ begin // if out the entire case statement!
+ case (bank_state[BANK_STATE_WIDTH - 1 : 0])
+ POWER_ON:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= POWER_ON;
+ Timing_Error <= 1'b0;
+ end
+ else if (control_wires[4:0] == LOAD_MODE) // no bank involved
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_REG;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM needs to have a LOAD MODE REGISTER before any other command %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= POWER_ON;
+ Timing_Error <= 1'b1;
+ end
+ load_mode_delay_counter[3:0] <= LOAD_MODE_REGISTER_CYCLES;
+ act_a_to_act_b_counter[3:0] <= 4'h0;
+ act_to_read_or_write_counter[3:0] <= 4'h0;
+ act_to_precharge_counter[3:0] <= 4'h0;
+ act_a_to_act_a_counter[3:0] <= 4'h0;
+ burst_counter[3:0] <= 4'h0;
+ read_to_write_counter [3:0] <= 4'h0;
+ write_to_read_counter [3:0] <= 4'h0;
+ write_recovery_counter[3:0] <= 4'h0;
+ precharge_counter[3:0] <= 4'h0;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ WRITING_REG:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (load_mode_delay_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_REG;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else // nothing else legal until load mode finished
+ begin
+ if (load_mode_delay_counter[3:0] > 4'h2) // looping
+ begin
+ $display ("*** %m DDR DRAM cannot accept any other command while doing a LOAD MODE REGISTER command %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_REG;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM cannot accept any other command while doing a LOAD MODE REGISTER command %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ end
+ end
+ load_mode_delay_counter[3:0] <= (load_mode_delay_counter[3:0] != 4'h0)
+ ? (load_mode_delay_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_b_counter[3:0] <= 4'h0;
+ act_to_read_or_write_counter[3:0] <= 4'h0;
+ act_to_precharge_counter[3:0] <= 4'h0;
+ act_a_to_act_a_counter[3:0] <= 4'h0;
+ burst_counter[3:0] <= 4'h0;
+ read_to_write_counter [3:0] <= 4'h0;
+ write_to_read_counter [3:0] <= 4'h0;
+ write_recovery_counter[3:0] <= 4'h0;
+ precharge_counter[3:0] <= 4'h0;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+// All interesting work starts here, except for read, write followed by read, write, precharge
+ BANK_IDLE:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == LOAD_MODE) // no bank involved
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_REG;
+ Timing_Error <= 1'b0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ if (act_a_to_act_a_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an ACT too soon after another ACT to the same bank %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ act_a_to_act_b_counter[3:0] <= ACT_A_TO_ACT_B_CYCLES;
+ act_to_read_or_write_counter[3:0] <= ACT_TO_READ_OR_WRITE_CYCLES;
+ act_to_precharge_counter[3:0] <= ACT_TO_PRECHARGE_CYCLES;
+ act_a_to_act_a_counter[3:0] <= ACT_A_TO_ACT_A_CYCLES;
+ end
+ end
+ else // some other bank
+ begin
+ if (act_a_to_act_b_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an ACT too soon after another ACT to the same bank %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ end
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ end
+ else if ((control_wires[4:0] == READ_BANK) & (BA[1:0] != bank_num[1:0]))
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if ((control_wires[4:0] == WRITE_BANK) & (BA[1:0] != bank_num[1:0]))
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK)
+ begin
+ if ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1))
+ begin
+ if (act_to_precharge_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an PRECHARGE too soon after ACTIVATE %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ end
+ else // ignore precharges when in idle state
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ end
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == REFRESH_BANK) // all already precharged
+ begin
+ if (act_a_to_act_a_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an REFRESH too soon after ACTIVATE %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ Timing_Error <= 1'b0;
+ end
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only do Activate, Refresh, Precharge, or Load Mode Register from Idle %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ end
+ load_mode_delay_counter[3:0] <= LOAD_MODE_REGISTER_CYCLES;
+ burst_counter[3:0] <= 4'h0;
+ read_to_write_counter [3:0] <= 4'h0;
+ write_to_read_counter [3:0] <= 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= (precharge_counter[3:0] != 4'h0)
+ ? (precharge_counter[3:0] - 4'h1) : 4'h0;
+ refresh_counter[3:0] <= REFRESH_CYCLES;
+ end
+
+ ACTIVATING:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is already Activated %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ if (act_a_to_act_b_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a different bank too soon after this bank is Activated %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ end
+ else if (control_wires[4:0] == READ_BANK) // no bank involved
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ if (act_to_read_or_write_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait from Activate to Read %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else if (write_to_read_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait from Write to Read %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ if (A[10] == 1'b1)
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ else
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == WRITE_BANK) // no bank involved
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ if (act_to_read_or_write_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait from Activate to Write %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else if (read_to_write_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait from Read to Write %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ if (A[10] == 1'b1)
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ else
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // only do precharge if this bank is addressed
+ begin
+ if ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1))
+ begin
+ if (act_to_precharge_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait from Activate to Precharge %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else if (write_recovery_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait from end of Write to Precharge %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only do Read, Write, or Precharge from Activated %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b1;
+ end
+ load_mode_delay_counter[3:0] <= 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ burst_counter[3:0] <= 4'h2;
+ read_to_write_counter [3:0] <= (read_to_write_counter[3:0] != 4'h0)
+ ? (read_to_write_counter[3:0] - 4'h1) : 4'h0;
+ write_to_read_counter [3:0] <= (write_to_read_counter[3:0] != 4'h0)
+ ? (write_to_read_counter[3:0] - 4'h1) : 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= PRECHARGE_CYCLES;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ WRITING:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being Written %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ if (act_a_to_act_b_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a different bank too soon after this bank is Activated %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == READ_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Read until Write completes plus recovery %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == WRITE_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do a Write to a bank until the previous Write completes %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING; // might want to go to activate!
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ if (A[10] == 1'b1)
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ else
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ Timing_Error <= 1'b0;
+ burst_counter[3:0] <= 4'h2;
+ end
+ end
+ else // was to a different bank. We are done
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // do idles when it is safe to do so
+ begin
+ if ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1))
+ begin
+ $display ("*** %m DDR DRAM cannot do a Precharge until Write completes plus recovery %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only do Read, Write, or Precharge from Write %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ load_mode_delay_counter[3:0] <= 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ read_to_write_counter [3:0] <= (read_to_write_counter[3:0] != 4'h0)
+ ? (read_to_write_counter[3:0] - 4'h1) : 4'h0;
+ write_to_read_counter [3:0] <= WRITE_TO_READ_CYCLES;
+ write_recovery_counter[3:0] <= WRITE_RECOVERY_TO_PRECHARGE_CYCLES + 1; // to let write finish!
+ precharge_counter[3:0] <= PRECHARGE_CYCLES;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ WRITING_PRECHARGE:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being Written %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ if (act_a_to_act_b_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a different bank too soon after this bank is Activated %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == READ_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Read until Write_precharge completes precharge %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == WRITE_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Write until Write_precharge completes precharge %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // do idles when it is safe to do so
+ begin
+ if ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1))
+ begin
+ $display ("*** %m DDR DRAM cannot do a Precharge until Write_precharge completes plus recovery %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else // was to a different bank. We are done
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only wait from Write_precharge %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WRITING_PRECHARGE;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ load_mode_delay_counter[3:0] <= 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ read_to_write_counter [3:0] <= (read_to_write_counter[3:0] != 4'h0)
+ ? (read_to_write_counter[3:0] - 4'h1) : 4'h0;
+ write_to_read_counter [3:0] <= WRITE_TO_READ_CYCLES;
+ write_recovery_counter[3:0] <= WRITE_RECOVERY_TO_PRECHARGE_CYCLES + 1; // to let write finish!
+ precharge_counter[3:0] <= PRECHARGE_CYCLES;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ READING:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ Timing_Error <= 1'b0;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being Read %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ if (act_a_to_act_b_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a different bank too soon after this bank is Activated %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == READ_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do a Read to a bank until the previous Read completes %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ if (A[10] == 1'b1)
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ else
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b0;
+ burst_counter[3:0] <= 4'h2;
+ end
+ end
+ else // was to a different bank. We are done
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ end
+ else if (control_wires[4:0] == WRITE_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Read until Write completes plus recovery %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else // was to a different bank. We are done
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // do idles when it is safe to do so
+ begin
+ if ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1))
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM cannot do a Precharge to a bank until the previous Read completes %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ if (act_to_precharge_counter[3:0] > 4'h1)
+ begin
+ $display ("*** %m DDR DRAM has to wait during READ from Activate to Precharge %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ end
+ else // was to a different bank. We are done
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= ACTIVATING;
+ end
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only do Read, Write, or Precharge from Read %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ load_mode_delay_counter[3:0] <= (load_mode_delay_counter[3:0] != 4'h0)
+ ? (load_mode_delay_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ read_to_write_counter [3:0] <= READ_TO_WRITE_CYCLES;
+ write_to_read_counter [3:0] <= (write_to_read_counter[3:0] != 4'h0)
+ ? (write_to_read_counter[3:0] - 4'h1) : 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= PRECHARGE_CYCLES;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ READING_PRECHARGE:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being Read %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == READ_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Read until Read_precharge completes precharge %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == WRITE_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Write until Read_precharge completes precharge %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // do idles when it is safe to do so
+ begin
+ if ((BA[1:0] == bank_num[1:0]) | (A[10] == 1'b1))
+ begin
+ $display ("*** %m DDR DRAM cannot do a Precharge until Read_precharge completes plus recovery %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else // was to a different bank. We are done
+ begin
+ if (burst_counter[3:0] > 4'h1)
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ end
+ end
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only do Read, Write, or Precharge from Read %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= READING_PRECHARGE;
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ load_mode_delay_counter[3:0] <= (load_mode_delay_counter[3:0] != 4'h0)
+ ? (load_mode_delay_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ read_to_write_counter [3:0] <= READ_TO_WRITE_CYCLES;
+ write_to_read_counter [3:0] <= (write_to_read_counter[3:0] != 4'h0)
+ ? (write_to_read_counter[3:0] - 4'h1) : 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= PRECHARGE_CYCLES;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ WAITING_FOR_AUTO_PRECHARGE:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if ( (write_recovery_counter[3:0] > 4'h1)
+ | (act_to_precharge_counter[3:0] > 4'h1) )
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being auto_precharging %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ if ( (write_recovery_counter[3:0] > 4'h1)
+ | (act_to_precharge_counter[3:0] > 4'h1) )
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == READ_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Read until bank completes precharge %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if ( (write_recovery_counter[3:0] > 4'h1)
+ | (act_to_precharge_counter[3:0] > 4'h1) )
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == WRITE_BANK)
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do a Write until bank completes precharge %t", $time);
+ Timing_Error <= 1'b1;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ end
+ if ( (write_recovery_counter[3:0] > 4'h1)
+ | (act_to_precharge_counter[3:0] > 4'h1) )
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // do idles when it is safe to do so
+ begin
+ if ( (write_recovery_counter[3:0] > 4'h1)
+ | (act_to_precharge_counter[3:0] > 4'h1) )
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can only wait from Write_precharge %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= WAITING_FOR_AUTO_PRECHARGE;
+ Timing_Error <= 1'b1;
+ end
+ load_mode_delay_counter[3:0] <= 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ read_to_write_counter [3:0] <= (read_to_write_counter[3:0] != 4'h0)
+ ? (read_to_write_counter[3:0] - 4'h1) : 4'h0;
+ write_to_read_counter [3:0] <= (write_to_read_counter[3:0] != 4'h0)
+ ? (write_to_read_counter[3:0] - 4'h1) : 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= PRECHARGE_CYCLES;
+ refresh_counter[3:0] <= 4'h0;
+ end
+
+ PRECHARGING:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (precharge_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being Precharged %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ if (precharge_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else if (control_wires[4:0] == READ_BANK) // no bank involved
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Read to a bank which is being Precharged %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ if (precharge_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else if (control_wires[4:0] == WRITE_BANK) // no bank involved
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Write to a bank which is being Precharged %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ if (precharge_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // ignore extra precharges
+ begin
+ Timing_Error <= 1'b0;
+ if (precharge_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can't do anything from Precharge %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= PRECHARGING;
+ Timing_Error <= 1'b1;
+ end
+ load_mode_delay_counter[3:0] <= (load_mode_delay_counter[3:0] != 4'h0)
+ ? (load_mode_delay_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ read_to_write_counter [3:0] <= (read_to_write_counter[3:0] != 4'h0)
+ ? (read_to_write_counter[3:0] - 4'h1) : 4'h0;
+ write_to_read_counter [3:0] <= (write_to_read_counter[3:0] != 4'h0)
+ ? (write_to_read_counter[3:0] - 4'h1) : 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= (precharge_counter[3:0] != 4'h0)
+ ? (precharge_counter[3:0] - 4'h1) : 4'h0;
+ refresh_counter[3:0] <= (refresh_counter[3:0] != 4'h0)
+ ? (refresh_counter[3:0] - 4'h1) : 4'h0;
+ end
+
+ REFRESHING:
+ begin
+ if ( (control_wires[4] == 1'b0) // powered off
+ | (control_wires[3] == 1'b1) // not selected
+ | (control_wires[4:0] == NOOP) ) // noop
+ begin
+ if (refresh_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ Timing_Error <= 1'b0;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b0;
+ end
+ end
+ else if (control_wires[4:0] == ACTIVATE_BANK) // activate only if this bank is addressed
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Activate to a bank which is being Refreshed %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ if (refresh_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else if (control_wires[4:0] == READ_BANK) // no bank involved
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Read to a bank which is being Refreshed %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ if (refresh_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else if (control_wires[4:0] == WRITE_BANK) // no bank involved
+ begin
+ if (BA[1:0] == bank_num[1:0])
+ begin
+ $display ("*** %m DDR DRAM cannot do an Write to a bank which is being Refreshed %t", $time);
+ Timing_Error <= 1'b1;
+ end
+ else
+ begin
+ Timing_Error <= 1'b0;
+ end
+ if (refresh_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else if (control_wires[4:0] == PRECHARGE_BANK) // ignore extra precharges
+ begin
+ Timing_Error <= 1'b0;
+ if (refresh_counter[3:0] > 4'h2) // looping
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ end
+ else
+ begin
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ end
+ end
+ else
+ begin
+ $display ("*** %m DDR DRAM can't do anything from Refresh %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= REFRESHING;
+ Timing_Error <= 1'b1;
+ end
+ load_mode_delay_counter[3:0] <= (load_mode_delay_counter[3:0] != 4'h0)
+ ? (load_mode_delay_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_b_counter[3:0] <= (act_a_to_act_b_counter[3:0] != 4'h0)
+ ? (act_a_to_act_b_counter[3:0] - 4'h1) : 4'h0;
+ act_to_read_or_write_counter[3:0] <= (act_to_read_or_write_counter[3:0] != 4'h0)
+ ? (act_to_read_or_write_counter[3:0] - 4'h1) : 4'h0;
+ act_to_precharge_counter[3:0] <= (act_to_precharge_counter[3:0] != 4'h0)
+ ? (act_to_precharge_counter[3:0] - 4'h1) : 4'h0;
+ act_a_to_act_a_counter[3:0] <= (act_a_to_act_a_counter[3:0] != 4'h0)
+ ? (act_a_to_act_a_counter[3:0] - 4'h1) : 4'h0;
+ burst_counter[3:0] <= (burst_counter[3:0] != 4'h0)
+ ? (burst_counter[3:0] - 4'h1) : 4'h0;
+ write_recovery_counter[3:0] <= (write_recovery_counter[3:0] != 4'h0)
+ ? (write_recovery_counter[3:0] - 4'h1) : 4'h0;
+ precharge_counter[3:0] <= (precharge_counter[3:0] != 4'h0)
+ ? (precharge_counter[3:0] - 4'h1) : 4'h0;
+ refresh_counter[3:0] <= (refresh_counter[3:0] != 4'h0)
+ ? (refresh_counter[3:0] - 4'h1) : 4'h0;
+ end
+
+ default:
+ begin
+ $display ("*** %m DDR DRAM default jump should be impossible %t", $time);
+ bank_state[BANK_STATE_WIDTH - 1 : 0] <= BANK_IDLE;
+ Timing_Error <= 1'b1;
+ end
+ endcase
+ end // if out the entire case statement!
+ end
+endmodule
+
+`define TEST_DDR_2_DRAM
+`ifdef TEST_DDR_2_DRAM
+module test_ddr_2_dram;
+ reg CLK_P, CLK_N;
+
+ initial
+ begin
+ CLK_P <= 1'b0;
+ CLK_N <= 1'b1;
+ # 10_000 ; // make times be even
+ while (1'b1)
+ begin
+ #10_000 ; // 10 nSec
+ CLK_P <= ~CLK_P;
+ CLK_N <= ~CLK_N;
+ end
+ end
+
+ initial
+ begin
+ #2000_000 $finish;
+ end
+
+// hook up sequential test bench to instantiation of DDR DRAM for test
+parameter DATA_BUS_WIDTH = 4;
+
+ wire [DATA_BUS_WIDTH - 1 : 0] DQ;
+ wire DQS;
+
+ reg DM;
+ reg [12:0] A;
+ reg [1:0] BA;
+ reg RAS_L, CAS_L, WE_L, CS_L, CKE;
+ reg [DATA_BUS_WIDTH - 1 : 0] DQ_out_0;
+ reg [DATA_BUS_WIDTH - 1 : 0] DQ_out_1;
+ reg DQ_oe_0, DQ_oe_1;
+ reg DQS_out;
+ reg DQS_oe;
+
+// MUX the two data items together based on clock phase
+ wire [DATA_BUS_WIDTH - 1 : 0] DQ_out = CLK_P
+ ? DQ_out_1[DATA_BUS_WIDTH - 1 : 0]
+ : DQ_out_0[DATA_BUS_WIDTH - 1 : 0];
+
+// Either send data or tristate the bus
+ assign DQ[DATA_BUS_WIDTH - 1 : 0] = DQ_oe
+ ? DQ_out[DATA_BUS_WIDTH - 1 : 0]
+ : {DATA_BUS_WIDTH{1'bZ}};
+
+// The DQS signal is OE'd BEFORE the Data. Called the preamble.
+ assign DQS = DQS_oe ? DQS_out : 1'bZ;
+
+// {CKE, CS_L, RAS_L, CAS_L, WE_L}
+parameter NOOP = 5'h17;
+parameter ACTIVATE = 5'h13;
+parameter READ = 5'h15;
+parameter WRITE = 5'h14;
+parameter PRECHARGE = 5'h12;
+parameter REFRESH = 5'h11;
+parameter LOAD_MODE = 5'h10;
+
+ initial
+ begin
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+DQ_oe_0 <= 1'b0;
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+DQ_oe_1 <= 1'b0;
+
+ CKE <= 1'b1;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ DQ_oe <= 1'b0; DQS_oe <= 1'b0;
+ @ (posedge CLK_P) ; // noop
+
+A[12:0] <= 13'h1555; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= LOAD_MODE;
+ @ (posedge CLK_P) ; // write reg
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= ACTIVATE;
+ @ (posedge CLK_P) ; // activate
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= WRITE;
+ @ (posedge CLK_P) ; // write DRAM
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'h1;
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'h2;
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hE;
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= WRITE;
+ @ (posedge CLK_P) ; // write DRAM
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'h3;
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hD;
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'h4;
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hC;
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hB;
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_1[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= READ;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= READ;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= PRECHARGE;
+ @ (posedge CLK_P) ; // noop
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= ACTIVATE;
+ @ (posedge CLK_P) ; // activate
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= READ;
+ @ (posedge CLK_P) ; // read
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data //
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= WRITE;
+ @ (posedge CLK_P) ; // write
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hE;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hD;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= PRECHARGE;
+ @ (posedge CLK_P) ; // noop
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= REFRESH;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= ACTIVATE;
+ @ (posedge CLK_P) ; // activate
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h400; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= WRITE;
+ @ (posedge CLK_P) ; // write
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hB;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'h7;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+DQ_out_0[DATA_BUS_WIDTH - 1 : 0] <= 4'hZ;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= ACTIVATE;
+ @ (posedge CLK_P) ; // activate
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h400; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= READ;
+ @ (posedge CLK_P) ; // write
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+A[12:0] <= 13'h0; BA[1:0] <= 2'h0;
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= ACTIVATE;
+ @ (posedge CLK_P) ; // activate
+
+ {CKE, CS_L, RAS_L, CAS_L, WE_L} <= NOOP;
+ @ (posedge CLK_P) ; // noop + data
+
+ end
+
+
+
+
+ assign DQ[DATA_BUS_WIDTH - 1 : 0] =
+ ( (DQ_out_0[DATA_BUS_WIDTH - 1 : 0] !== {DATA_BUS_WIDTH{1'bZ}})
+ & (CLK_N == 1'b1) )
+ ? DQ_out_0[DATA_BUS_WIDTH - 1 : 0]
+ : ( ( (DQ_out_1[DATA_BUS_WIDTH - 1 : 0] !== {DATA_BUS_WIDTH{1'bZ}})
+ & (CLK_P == 1'b1) )
+ ? DQ_out_1[DATA_BUS_WIDTH - 1 : 0]
+ : {DATA_BUS_WIDTH{1'bZ}});
+
+ddr_2_dram
+# ( 100.0, // frequency
+ 2.0, // latency
+ 13, // num_addr_bits
+ 12, // num_col_bits
+ 4 * DATA_BUS_WIDTH, // num_data_bits
+ 32, // num_words_in_test_memory
+ 1
+ ) ddr_2_dram (
+ .DQ ({DQ[DATA_BUS_WIDTH - 1 : 0], DQ[DATA_BUS_WIDTH - 1 : 0],
+ DQ[DATA_BUS_WIDTH - 1 : 0], DQ[DATA_BUS_WIDTH - 1 : 0]}),
+ .DQS (DQS),
+ .DM (DM),
+ .A (A[12:0]),
+ .BA (BA[1:0]),
+ .RAS_L (RAS_L),
+ .CAS_L (CAS_L),
+ .WE_L (WE_L),
+ .CS_L (CS_L),
+ .CKE (CKE),
+ .CLK_P (CLK_P),
+ .CLK_N (CLK_N)
+);
+
+ wire [3:0] BANK_STATE_0 = ddr_2_dram.ddr_2_dram_single_bank_0.bank_state[3:0];
+ wire [3:0] BANK_STATE_1 = ddr_2_dram.ddr_2_dram_single_bank_1.bank_state[3:0];
+ wire [3:0] BANK_STATE_2 = ddr_2_dram.ddr_2_dram_single_bank_2.bank_state[3:0];
+ wire [3:0] BANK_STATE_3 = ddr_2_dram.ddr_2_dram_single_bank_3.bank_state[3:0];
+
+endmodule
+`endif // TEST_DDR_2_DRAM
Index: trunk/sram_for_debugging_sync.v
===================================================================
--- trunk/sram_for_debugging_sync.v (nonexistent)
+++ trunk/sram_for_debugging_sync.v (revision 48)
@@ -0,0 +1,307 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// sram_for_debugging_sync #(NUM_ADDR_BITS, NUM_DATA_BITS) ////
+//// ////
+//// This file is part of the general opencores effort. ////
+//// ////
+//// ////
+//// Module Description: ////
+//// An SRAM model which contains only 32 entries. ////
+//// This SRAM trades off time for storage. By only storing ////
+//// a very few entries, this SRAM takes constant storage ////
+//// independent of how many address lines it exports. ////
+//// The limited storage means that the entries must be read ////
+//// soon after it is written. If too many writes happen ////
+//// before an entry is read, the entry returns X's. ////
+//// This SRAM has 1 other debugging feature. When a write ////
+//// is executed, the SRAM ;atches the bit number of the ////
+//// least significant bit of the address which is HIGH. ////
+//// The special address 0xAA00..., with the top 8 bits being ////
+//// 8'b1010_1010, returns the stored number when read. ////
+//// As an example, assume that a write is done to location ////
+//// 20'h0_0040. ////
+//// After the write, but before any other write, the user ////
+//// can read location 20'hC_C000. The read returns 4'h5. ////
+//// ////
+//// Author(s): ////
+//// - Anonymous ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Anonymous and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// $Id: sram_for_debugging_sync.v,v 1.2 2001-11-06 12:33:15 bbeaver Exp $
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.3 2001/11/06 12:41:27 Blue Beaver
+// no message
+//
+// Revision 1.2 2001/10/02 06:22:08 Blue Beaver
+// no message
+//
+//
+
+`timescale 1ns/1ps
+
+// instantiate as "sram_for_debugging_sync #(NUM_ADDR_BITS, NUM_DATA_BITS) instance ()"
+
+module sram_for_debugging_sync (
+ data_out,
+ data_in,
+ address,
+ read_enable,
+ write_enable,
+ clk
+);
+ parameter NUM_ADDR_BITS = 1;
+ parameter NUM_DATA_BITS = 1;
+
+ output [NUM_DATA_BITS - 1 : 0] data_out;
+ input [NUM_DATA_BITS - 1 : 0] data_in;
+ input [NUM_ADDR_BITS - 1 : 0] address;
+ input read_enable;
+ input write_enable;
+ input clk;
+
+ reg [NUM_DATA_BITS - 1 : 0] data_storage [31:0]; // 32 entries of SRAM storage
+ reg [NUM_ADDR_BITS - 1 : 0] address_storage [31:0]; // 32 entries of SRAM storage
+ reg [5:0] write_counter; // enough to count to 63
+ reg [NUM_DATA_BITS - 1 : 0] stored_write_address; // store bit number of address LSB set to 1
+
+ integer i, j, k, l;
+
+// synopsys translate_off
+ initial
+ begin
+ for (i = 6'h00; i != 6'h20; i = i + 6'h01)
+ begin
+ address_storage[i] = {NUM_ADDR_BITS{1'bX}};
+ data_storage[i] = {NUM_DATA_BITS{1'bX}};
+ stored_write_address[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ write_counter[5:0] = 6'h00;
+ end
+ end
+// synopsys translate_on
+
+// Write to next address, remember which LSB write address bit was ~0
+ always @(posedge clk)
+ begin
+ if (write_enable == 1'b1)
+ begin
+ $display ("writing %x at %x %t", data_in[NUM_DATA_BITS - 1 : 0], address[NUM_ADDR_BITS - 1 : 0], $time);
+ address_storage[write_counter[4:0]] = address[NUM_ADDR_BITS - 1 : 0];
+ data_storage[write_counter[4:0]] = data_in[NUM_DATA_BITS - 1 : 0];
+ for (j = 0; j < NUM_ADDR_BITS; j = j + 1)
+ begin
+ if (((address[NUM_ADDR_BITS - 1 : 0] >> j) & 1'b1) != 1'b0)
+ begin
+ stored_write_address[NUM_DATA_BITS - 1 : 0] = j;
+ j = NUM_ADDR_BITS + 1; // only remember the FIRST bit set
+ end
+ end
+ if (j == NUM_ADDR_BITS) // NO bit was set
+ begin
+ stored_write_address[NUM_DATA_BITS - 1 : 0] = NUM_ADDR_BITS;
+ end
+ write_counter[5:0] = (write_counter[5:0] + 6'h01) & 6'h1F;
+ end
+ end
+
+// Starting at the newest, search back to oldest to find if the word has been written
+ reg [NUM_DATA_BITS - 1 : 0] data_out;
+ reg [4:0] read_address;
+
+ always @(posedge clk)
+ begin
+ if ((read_enable !== 1'b1) | ((^address[NUM_ADDR_BITS - 1 : 0]) === 1'bX)) // no read, return X's
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ end
+ else
+ if ((read_enable == 1'b1) && (write_enable == 1'b1))
+ begin
+ $display ("*** %m sram_for_debugging_sync cannot handle a read and a write at the same time");
+ data_out[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ end
+ else if ((read_enable == 1'b1) && (write_enable == 1'b0))
+ begin
+ if ((address[NUM_ADDR_BITS - 1 : 0] >> (NUM_ADDR_BITS - 8)) == 8'hAA) // read magic location, return Address Bit Number
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = stored_write_address[NUM_DATA_BITS - 1 : 0];
+ end
+ else // otherwise search history to see if the word has been written recently
+ begin
+ k = write_counter[5:0];
+ for (l = k + 6'h1F; // half way around, same as last minus 1;
+ l >= k; // write address not valid
+ l = l - 1)
+ begin
+ read_address[4:0] = l;
+ if (address[NUM_ADDR_BITS - 1 : 0] === address_storage[read_address[4:0]])
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = data_storage[read_address[4:0]];
+ l = k - 2;
+ end
+ end
+ if (l == (k - 1)) // didn't find it at all!
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ end
+ end
+ end
+ end
+
+// synopsys translate_off
+ initial
+ begin
+ if (NUM_ADDR_BITS < 8)
+ begin
+ $display ("*** Exiting because %m sram_for_debugging_sync Number of Address bits %d < 8",
+ NUM_ADDR_BITS);
+ $finish;
+ end
+ if (NUM_DATA_BITS < 8)
+ begin
+ $display ("*** Exiting because %m sram_for_debugging_sync Number of Data bits %d < 8",
+ NUM_DATA_BITS);
+ $finish;
+ end
+ end
+// synopsys translate_on
+endmodule
+
+`define TEST_SRAM
+`ifdef TEST_SRAM
+module test_sram;
+ reg [11:0] address;
+ reg [8:0] data_in;
+ reg read_enable, write_enable;
+ wire [8:0] data_out;
+ reg clk;
+
+ integer i;
+
+ initial
+ begin
+ read_enable = 1'b0;
+ write_enable = 1'b0;
+ clk = 1'b0;
+ for (i = 0; i < 12; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = (12'h001 << i);
+ data_in[8:0] = i + 4;
+ # 0; write_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0; write_enable = 1'b0;
+ # 0; clk = 1'b0;
+ # 0;
+ address[11:0] = 12'hAA0;
+ # 0; read_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0;
+ if (data_out[8:0] !== i)
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ # 0; clk = 1'b0;
+ end
+
+ for (i = 0; i < 12; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = (12'h001 << i);
+ # 0; read_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0;
+ if (data_out[8:0] !== (i + 4))
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ # 0; clk = 1'b0;
+ end
+
+ # 0;
+ address[11:0] = 12'hXXX;
+ # 0; read_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0;
+ if (data_out[8:0] !== 9'hXXX)
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ # 0; clk = 1'b0;
+
+ # 0;
+ address[11:0] = 12'h003;
+ # 0; read_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0;
+ if (data_out[8:0] !== 9'hXXX)
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ # 0; clk = 1'b0;
+
+ for (i = 0; i < 32; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = i;
+ data_in[8:0] = i + 32;
+ # 0; write_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0; write_enable = 1'b0;
+ # 0; clk = 1'b0;
+ end
+
+ for (i = 0; i < 32; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = i;
+ # 0; read_enable = 1'b1;
+ # 0; clk = 1'b1;
+ # 0;
+ if (data_out[8:0] !== (i + 32))
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ # 0; clk = 1'b0;
+ end
+
+ end
+
+sram_for_debugging_sync
+#(12, // NUM_ADDR_BITS
+ 9 // NUM_DATA_BITS
+ ) test_this_one (
+ .data_out (data_out[8:0]),
+ .data_in (data_in[8:0]),
+ .address (address[11:0]),
+ .read_enable (read_enable),
+ .write_enable (write_enable),
+ .clk (clk)
+);
+
+endmodule
+`endif // TEST_SRAM
+
Index: trunk/sram_for_debugging_async.v
===================================================================
--- trunk/sram_for_debugging_async.v (nonexistent)
+++ trunk/sram_for_debugging_async.v (revision 48)
@@ -0,0 +1,283 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// sram_for_debugging_async #(NUM_ADDR_BITS, NUM_DATA_BITS) ////
+//// ////
+//// This file is part of the general opencores effort. ////
+//// ////
+//// ////
+//// Module Description: ////
+//// An SRAM model which contains only 32 entries. ////
+//// This SRAM trades off time for storage. By only storing ////
+//// a very few entries, this SRAM takes constant storage ////
+//// independent of how many address lines it exports. ////
+//// The limited storage means that the entries must be read ////
+//// soon after it is written. If too many writes happen ////
+//// before an entry is read, the entry returns X's. ////
+//// This SRAM has 1 other debugging feature. When a write ////
+//// is executed, the SRAM ;atches the bit number of the ////
+//// least significant bit of the address which is HIGH. ////
+//// The special address 0xAA00..., with the top 8 bits being ////
+//// 8'b1010_1010, returns the stored number when read. ////
+//// As an example, assume that a write is done to location ////
+//// 20'h0_0040. ////
+//// After the write, but before any other write, the user ////
+//// can read location 20'hC_C000. The read returns 4'h5. ////
+//// ////
+//// Author(s): ////
+//// - Anonymous ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Anonymous and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// $Id: sram_for_debugging_async.v,v 1.2 2001-11-06 12:33:15 bbeaver Exp $
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.1 2001/10/02 05:23:27 Blue Beaver
+// no message
+//
+// Revision 1.3 2001/09/27 08:05:43 Blue Beaver
+// no message
+//
+// Revision 1.2 2001/09/26 09:46:20 Blue Beaver
+// no message
+//
+// Revision 1.1 2001/09/25 10:49:34 Blue Beaver
+// no message
+//
+
+`timescale 1ns/1ps
+
+// instantiate as "sram_for_debugging_async #(NUM_ADDR_BITS, NUM_DATA_BITS) instance ()"
+
+module sram_for_debugging_async (
+ data_out,
+ data_in,
+ address,
+ read_enable,
+ write_enable
+);
+ parameter NUM_ADDR_BITS = 1;
+ parameter NUM_DATA_BITS = 1;
+
+ output [NUM_DATA_BITS - 1 : 0] data_out;
+ input [NUM_DATA_BITS - 1 : 0] data_in;
+ input [NUM_ADDR_BITS - 1 : 0] address;
+ input read_enable;
+ input write_enable;
+
+ reg [NUM_DATA_BITS - 1 : 0] data_storage [31:0]; // 32 entries of SRAM storage
+ reg [NUM_ADDR_BITS - 1 : 0] address_storage [31:0]; // 32 entries of SRAM storage
+ reg [5:0] write_counter; // enough to count to 63
+ reg [NUM_DATA_BITS - 1 : 0] stored_write_address; // store bit number of address LSB set to 1
+
+ integer i, j, k, l;
+
+// synopsys translate_off
+ initial
+ begin
+ for (i = 6'h00; i != 6'h20; i = i + 6'h01)
+ begin
+ address_storage[i] = {NUM_ADDR_BITS{1'bX}};
+ data_storage[i] = {NUM_DATA_BITS{1'bX}};
+ stored_write_address[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ write_counter[5:0] = 6'h00;
+ end
+ end
+// synopsys translate_on
+
+// Write to next address, remember which LSB write address bit was ~0
+ always @(posedge write_enable)
+ begin
+ address_storage[write_counter[4:0]] = address[NUM_ADDR_BITS - 1 : 0];
+ data_storage[write_counter[4:0]] = data_in[NUM_DATA_BITS - 1 : 0];
+ for (j = 0; j < NUM_ADDR_BITS; j = j + 1)
+ begin
+ if (((address[NUM_ADDR_BITS - 1 : 0] >> j) & 1'b1) != 1'b0)
+ begin
+ stored_write_address[NUM_DATA_BITS - 1 : 0] = j;
+ j = NUM_ADDR_BITS + 1; // only remember the FIRST bit set
+ end
+ end
+ if (j == NUM_ADDR_BITS) // NO bit was set
+ begin
+ stored_write_address[NUM_DATA_BITS - 1 : 0] = NUM_ADDR_BITS;
+ end
+ write_counter[5:0] = (write_counter[5:0] + 6'h01) & 6'h1F;
+ end
+
+// Starting at the newest, search back to oldest to find if the word has been written
+ reg [NUM_DATA_BITS - 1 : 0] data_out;
+ reg [4:0] read_address;
+
+ always @(read_enable)
+ begin
+ if ((read_enable !== 1'b1) | ((^address[NUM_DATA_BITS - 1 : 0]) === 1'bX)) // no read, return X's
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ end
+ else
+ begin
+ if ((address[NUM_ADDR_BITS - 1 : 0] >> (NUM_ADDR_BITS - 8)) == 8'hAA) // read magic location, return Address Bit Number
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = stored_write_address[NUM_DATA_BITS - 1 : 0];
+ end
+ else // otherwise search history to see if the word has been written recently
+ begin
+ k = write_counter[5:0];
+ for (l = k + 6'h1F; // half way around, same as last minus 1;
+ l >= k; // write address not valid
+ l = l - 1)
+ begin
+ read_address[4:0] = l;
+ if (address[NUM_ADDR_BITS - 1 : 0] === address_storage[read_address[4:0]])
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = data_storage[read_address[4:0]];
+ l = k - 2;
+ end
+ end
+ if (l == (k - 1)) // didn't find it at all!
+ begin
+ data_out[NUM_DATA_BITS - 1 : 0] = {NUM_DATA_BITS{1'bX}};
+ end
+ end
+ end
+ end
+
+// synopsys translate_off
+ initial
+ begin
+ if (NUM_ADDR_BITS < 8)
+ begin
+ $display ("*** Exiting because %m sram_for_debugging_async Number of Address bits %d < 8",
+ NUM_ADDR_BITS);
+ $finish;
+ end
+ if (NUM_DATA_BITS < 8)
+ begin
+ $display ("*** Exiting because %m sram_for_debugging_async Number of Data bits %d < 8",
+ NUM_DATA_BITS);
+ $finish;
+ end
+ end
+// synopsys translate_on
+endmodule
+
+`define TEST_SRAM
+`ifdef TEST_SRAM
+module test_sram;
+ reg [11:0] address;
+ reg [8:0] data_in;
+ reg read_enable, write_enable;
+ wire [8:0] data_out;
+
+ integer i;
+
+ initial
+ begin
+ read_enable = 1'b0;
+ write_enable = 1'b0;
+ for (i = 0; i < 12; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = (12'h001 << i);
+ data_in[8:0] = i + 4;
+ # 0; write_enable = 1'b1;
+ # 0; write_enable = 1'b0;
+ # 0;
+ address[11:0] = 12'hAA0;
+ # 0; read_enable = 1'b1;
+ # 0;
+ if (data_out[8:0] !== i)
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ end
+
+ for (i = 0; i < 12; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = (12'h001 << i);
+ # 0; read_enable = 1'b1;
+ # 0;
+ if (data_out[8:0] !== (i + 4))
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ end
+
+ # 0;
+ address[11:0] = 12'hXXX;
+ # 0; read_enable = 1'b1;
+ # 0;
+ if (data_out[8:0] !== 9'hXXX)
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+
+ # 0;
+ address[11:0] = 12'h003;
+ # 0; read_enable = 1'b1;
+ # 0;
+ if (data_out[8:0] !== 9'hXXX)
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+
+ for (i = 0; i < 32; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = i;
+ data_in[8:0] = i + 32;
+ # 0; write_enable = 1'b1;
+ # 0; write_enable = 1'b0;
+ end
+
+ for (i = 0; i < 32; i = i + 1)
+ begin
+ # 0;
+ address[11:0] = i;
+ # 0; read_enable = 1'b1;
+ # 0;
+ if (data_out[8:0] !== (i + 32))
+ $display ("*** Debug SRAM read failed %x %x", i, data_out[8:0]);
+ # 0; read_enable = 1'b0;
+ end
+
+ end
+
+sram_for_debugging_async
+#(12, // NUM_ADDR_BITS
+ 9 // NUM_DATA_BITS
+ ) test_this_one (
+ .data_out (data_out[8:0]),
+ .data_in (data_in[8:0]),
+ .address (address[11:0]),
+ .read_enable (read_enable),
+ .write_enable (write_enable)
+);
+
+endmodule
+`endif // TEST_SRAM
+
Index: trunk/ddr_2_dimm_for_debugging.v
===================================================================
--- trunk/ddr_2_dimm_for_debugging.v (nonexistent)
+++ trunk/ddr_2_dimm_for_debugging.v (revision 48)
@@ -0,0 +1,94 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// ddr_2_dimm ////
+//// ////
+//// This file is part of the general opencores effort. ////
+//// ////
+//// ////
+//// Module Description: ////
+//// A fake DDR DIMM containing a number of fake DDR DRAMs. ////
+//// Useful in getting a DDR DRAM controller working. ////
+//// ////
+//// Author(s): ////
+//// - Anonymous ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Anonymous and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// $Id: ddr_2_dimm_for_debugging.v,v 1.2 2001-10-29 13:37:57 bbeaver Exp $
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.1 2001/10/29 13:45:02 Blue Beaver
+// no message
+//
+// Revision 1.1 2001/10/28 11:15:47 Blue Beaver
+// no message
+//
+
+`timescale 1ns / 1ps
+
+module ddr_2_dimm (
+ DQ, DQS,
+ DM,
+ A, BA,
+ RAS_L,
+ CAS_L,
+ WE_L,
+ CS_L,
+ CKE,
+ clk_p, clk_n
+);
+
+// Constant Parameters
+parameter num_addr_bits = 13;
+parameter num_col_bits = 11;
+parameter num_data_bits = 4;
+parameter num_words_in_test_memory = 32;
+
+ inout [num_data_bits - 1 : 0] DQ;
+ inout DQS;
+ input DM;
+ input [num_addr_bits - 1 : 0] A;
+ input [1 : 0] BA;
+ input RAS_L;
+ input CAS_L;
+ input WE_L;
+ input CS_L;
+ input CKE;
+ input clk_p;
+ input clk_n;
+
+
+// Storage
+ reg [num_data_bits - 1 : 0] bank0 [0 : num_words_in_test_memory - 1];
+ reg [num_data_bits - 1 : 0] bank1 [0 : num_words_in_test_memory - 1];
+ reg [num_data_bits - 1 : 0] bank2 [0 : num_words_in_test_memory - 1];
+ reg [num_data_bits - 1 : 0] bank3 [0 : num_words_in_test_memory - 1];
+
+endmodule
Index: trunk/grey_to_binary.v
===================================================================
--- trunk/grey_to_binary.v (nonexistent)
+++ trunk/grey_to_binary.v (revision 48)
@@ -0,0 +1,306 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// grey_to_binary #(N), binary_to_grey #(N) ////
+//// ////
+//// This file is part of the general opencores effort. ////
+//// ////
+//// ////
+//// Module Description: ////
+//// Example of how to convert Grey Code to Binary. ////
+//// Example of how to convert Binary to Grey Code. ////
+//// ////
+//// CRITICAL USAGE NOTE: ////
+//// These functions produce combinational outputs which ////
+//// have glitches. To use these safely, the outputs ////
+//// must be latched using the same clock before and ////
+//// after the combinational function. ////
+//// ////
+//// There are other sequences of numbers which share the ////
+//// property of Grey Code that only 1 bit transitions per ////
+//// value change. ////
+//// The sequence 0x00, 0x1, 0x3, 0x2, 0x6, 0x4 is one such ////
+//// sequence. ////
+//// It should be possible to make a library which counts ////
+//// in sequences less than 2**n long, yet which still ////
+//// change only 1 bot per increment. ////
+//// ////
+//// To Do: ////
+//// Might make this handle more than 16 bits. ////
+//// ////
+//// Author(s): ////
+//// - Anonymous ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000 Anonymous and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// $Id: grey_to_binary.v,v 1.5 2001-10-22 12:29:08 bbeaver Exp $
+//
+// CVS Revision History
+//
+// $Log: not supported by cvs2svn $
+// Revision 1.3 2001/09/03 12:12:44 Blue Beaver
+// no message
+//
+// Revision 1.2 2001/09/03 12:09:24 Blue Beaver
+// no message
+//
+//
+
+`timescale 1ns/1ps
+
+// Convert 2-bit up to 16-bit binary value into same sized grey-code value
+
+module bin_to_grey_code (
+ grey_code_out,
+ binary_in
+);
+ parameter NUM_BITS = 1; // instantiate as "bin_to_grey_code #(width) instance ()"
+
+ output [NUM_BITS - 1 : 0] grey_code_out;
+ input [NUM_BITS - 1 : 0] binary_in;
+
+// Consider the sequences
+// Binary Grey Code
+// 00 00
+// 01 01
+// 10 11
+// 11 10
+// It seems that G[1] = B[1], and G[0] = B[1] ^ B[0];
+// Now consider the sequences
+// Binary Grey Code
+// 000 000
+// 001 001
+// 010 011
+// 011 010
+// 100 110
+// 101 111
+// 110 101
+// 111 100
+// It seems that G[2] = B[2], and
+// G[1] = B[2] ^ B[1], and
+// G[0] = B[1] ^ B[0];
+//
+// But how to write that using a parameter? Well, instead of
+// figuring it out, how about just making something which works
+// for a range of widths, like 2 to 16?
+
+ wire [15:0] widened_input = {binary_in[NUM_BITS - 1 : 0], {16 - NUM_BITS{1'b0}}};
+
+ wire [15:0] widened_output = {
+ widened_input[15],
+ widened_input[15] ^ widened_input[14],
+ widened_input[14] ^ widened_input[13],
+ widened_input[13] ^ widened_input[12],
+ widened_input[12] ^ widened_input[11],
+ widened_input[11] ^ widened_input[10],
+ widened_input[10] ^ widened_input[9],
+ widened_input[9] ^ widened_input[8],
+ widened_input[8] ^ widened_input[7],
+ widened_input[7] ^ widened_input[6],
+ widened_input[6] ^ widened_input[5],
+ widened_input[5] ^ widened_input[4],
+ widened_input[4] ^ widened_input[3],
+ widened_input[3] ^ widened_input[2],
+ widened_input[2] ^ widened_input[1],
+ widened_input[1] ^ widened_input[0]
+ };
+
+ assign grey_code_out[NUM_BITS - 1 : 0] = widened_output[15 : 16 - NUM_BITS];
+
+// synopsys translate_off
+ initial
+ begin
+ if (NUM_BITS < 2)
+ begin
+ $display ("*** Exiting because %m bin_to_grey_code Number of bits %d < 2",
+ NUM_BITS);
+ $finish;
+ end
+ if (NUM_BITS > 16)
+ begin
+ $display ("*** Exiting because %m bin_to_grey_code Number of bits %d > 16",
+ NUM_BITS);
+ $finish;
+ end
+ end
+// synopsys translate_on
+endmodule
+
+// Convert 2-bit up to 16-bit binary value into same sized grey-code value
+
+module grey_code_to_bin (
+ binary_out,
+ grey_code_in
+);
+ parameter NUM_BITS = 1; // instantiate as "grey_code_to_bin #(width) instance ()"
+
+ output [NUM_BITS - 1 : 0] binary_out;
+ input [NUM_BITS - 1 : 0] grey_code_in;
+
+// Consider the sequences
+// Grey Code Binary
+// 00 00
+// 01 01
+// 11 10
+// 10 11
+// It seems that B[1] = G[1], and B[0] = G[1] ^ G[0];
+// Now consider the sequences
+// Grey Code Binary
+// 000 000
+// 001 001
+// 011 010
+// 010 011
+// 110 100
+// 111 101
+// 101 110
+// 100 111
+// It seems that B[2] = G[2], and
+// B[1] = G[2] ^ G[1], and
+// B[0] = G[2] ^ G[1] ^ G[0];
+//
+// But how to write that using a parameter? Well, instead of
+// figuring it out, how about just making something which works
+// for a range of widths, like 2 to 16?
+
+ wire [15:0] widened_input = {grey_code_in[NUM_BITS - 1 : 0], {16 - NUM_BITS{1'b0}}};
+ wire xor_15_12 = widened_input[15] ^ widened_input[14]
+ ^ widened_input[13] ^ widened_input[12];
+ wire xor_11_10 = widened_input[11] ^ widened_input[10];
+ wire xor_11_8 = widened_input[11] ^ widened_input[10]
+ ^ widened_input[9] ^ widened_input[8];
+ wire xor_7_6 = widened_input[7] ^ widened_input[6];
+ wire xor_7_4 = widened_input[7] ^ widened_input[6]
+ ^ widened_input[5] ^ widened_input[4];
+ wire xor_3_2 = widened_input[3] ^ widened_input[2];
+ wire xor_1_0 = widened_input[1] ^ widened_input[0];
+
+ wire [15:0] widened_output = {
+ widened_input[15],
+ widened_input[15] ^ widened_input[14],
+ widened_input[15] ^ widened_input[14] ^ widened_input[13],
+ xor_15_12,
+ xor_15_12 ^ widened_input[11],
+ xor_15_12 ^ xor_11_10,
+ xor_15_12 ^ xor_11_10 ^ widened_input[9],
+ xor_15_12 ^ xor_11_8,
+ xor_15_12 ^ xor_11_8 ^ widened_input[7],
+ xor_15_12 ^ xor_11_8 ^ xor_7_6,
+ xor_15_12 ^ xor_11_8 ^ xor_7_6 ^ widened_input[5],
+ xor_15_12 ^ xor_11_8 ^ xor_7_4,
+ xor_15_12 ^ xor_11_8 ^ xor_7_4 ^ widened_input[3],
+ xor_15_12 ^ xor_11_8 ^ xor_7_4 ^ xor_3_2,
+ xor_15_12 ^ xor_11_8 ^ xor_7_4 ^ xor_3_2 ^ widened_input[1],
+ xor_15_12 ^ xor_11_8 ^ xor_7_4 ^ xor_3_2 ^ xor_1_0
+ };
+
+ assign binary_out[NUM_BITS - 1 : 0] = widened_output[15 : 16 - NUM_BITS];
+
+// synopsys translate_off
+ initial
+ begin
+ if (NUM_BITS < 2)
+ begin
+ $display ("*** Exiting because %m grey_code_to_bin Number of bits %d < 2",
+ NUM_BITS);
+ $finish;
+ end
+ if (NUM_BITS > 16)
+ begin
+ $display ("*** Exiting because %m grey_code_to_bin Number of bits %d > 16",
+ NUM_BITS);
+ $finish;
+ end
+ end
+// synopsys translate_on
+endmodule
+
+ `define TEST_GREY_CODE
+`ifdef TEST_GREY_CODE
+module test_grey_code;
+ reg [7:0] test_val;
+ wire [1:0] grey_2;
+ wire [2:0] grey_3;
+ wire [3:0] grey_4;
+
+ wire [1:0] bin_2;
+ wire [2:0] bin_3;
+ wire [3:0] bin_4;
+
+ initial
+ begin
+ for (test_val = 8'h00; test_val < 8'h04; test_val = test_val + 8'h01)
+ begin
+ # 0; $display ("test val, result %x %x %x", test_val[1:0], grey_2[1:0], bin_2[1:0]);
+ if (test_val[1:0] !== bin_2[1:0])
+ $display ("*** Encode, Decode failed %x %x", test_val[1:0], bin_2[1:0]);
+ end
+ $display (" ");
+ for (test_val = 8'h00; test_val < 8'h08; test_val = test_val + 8'h01)
+ begin
+ # 0; $display ("test val, result %x %x %x", test_val[2:0], grey_3[2:0], bin_3[2:0]);
+ if (test_val[2:0] !== bin_3[2:0])
+ $display ("*** Encode, Decode failed %x %x", test_val[2:0], bin_3[2:0]);
+ end
+ $display (" ");
+ for (test_val = 8'h00; test_val < 8'h10; test_val = test_val + 8'h01)
+ begin
+ # 0; $display ("test val, result %x %x %x", test_val[3:0], grey_4[3:0], bin_4[3:0]);
+ if (test_val[3:0] !== bin_4[3:0])
+ $display ("*** Encode, Decode failed %x %x", test_val[3:0], bin_4[3:0]);
+ end
+
+ end
+
+bin_to_grey_code #(2) bin_to_grey_code_2 (
+ .grey_code_out (grey_2[1:0]),
+ .binary_in (test_val[1:0])
+);
+bin_to_grey_code #(3) bin_to_grey_code_3 (
+ .grey_code_out (grey_3[2:0]),
+ .binary_in (test_val[2:0])
+);
+bin_to_grey_code #(4) bin_to_grey_code_4 (
+ .grey_code_out (grey_4[3:0]),
+ .binary_in (test_val[3:0])
+);
+
+grey_code_to_bin #(2) grey_code_to_bin_2 (
+ .binary_out (bin_2[1:0]),
+ .grey_code_in (grey_2[1:0])
+);
+grey_code_to_bin #(3) grey_code_to_bin_3 (
+ .binary_out (bin_3[2:0]),
+ .grey_code_in (grey_3[2:0])
+);
+grey_code_to_bin #(4) grey_code_to_bin_4 (
+ .binary_out (bin_4[3:0]),
+ .grey_code_in (grey_4[3:0])
+);
+
+endmodule
+`endif // TEST_GREY_CODE
+
Index: trunk/specification_template.dot
===================================================================
--- trunk/specification_template.dot (nonexistent)
+++ trunk/specification_template.dot (revision 48)
@@ -0,0 +1,1259 @@
+ÐÏࡱá > þÿ Ê Ì þÿÿÿ È É Ï Ð Ñ Ò Ó ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿì¥Á Y ¿ ³ bjbjóWóW } ‘= ‘= ¨ ô ÿÿ ÿÿ ÿÿ ] 2 2 2 2 ‚ ‚ ‚ 4 ¶ ¶ ¶ ¶ h , J ¼ ¶ ^1 n Z 6 Ê Z Z p j é ¼ ¥ ` #1 %1 %1 %1 %1 %1 %1 $ Ì2 ô À4 ¬ I1 ‚ ? @ I1 y# 2 2 Z p Ï Z y# y# y# Þ 2 8 Z ‚ p #1 ¶ ¶ 2 2 2 2 #1 y# € y# ù% 2 9/ ¼ j ‚ #1 p T ñCs©ZÁ¶ ¶ ã! – õ0 .
+Sample IP CoreSpecification
+
+
+
+Author: Lior Shtram
+lior.shtram@flextronicssemi.com
+
+
+
+
+Rev. 0.8
+ TIME \@ "MMMM d, yyyy" October 22, 2001
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+This page has been intentionally left blank.
+Revision History
+Rev.DateAuthorDescription0.130/1/01Lior ShtramFirst Draft0.22/201Rudolf UsselmannRemoved Header and Footer on Title Page.
+Changed Page numbering to start after Title Page.
+Changed Document Title Font to Times.0.306/02/01Richard HerveilleChanged OpenCores.com to OpenCores.org.
+Changed tables so WISHBONE signals fit into cells, centered width column.
+Changed page-numbering, start counting from Introduction page using Arabic numbers. Use Roman numbers for other pages.
+Changed date on title page to autoupdate.
+Added Contents page, used crosslinks for automatic header and page number generation.0.413/3/01Yair AmitayAdded “Clocks” section.0.53/5/01Jeanne WiegelmannCapitalized and modified headings.
+Added shadings to tables.
+Saved template as ‘dot’.0.613/5/01Jeanne WiegelmannModified document styles.
+Created new Table of Contents.0.615/5/01Jeanne WiegelmannAdded Appendix and Index.0.729/5/01Damjan LampretChanged chapter order. Added OC logo.0.822/10/01Damjan LampretChanged all port names as per new coding guidelines convention.
+Contents
+ TOC \t "Heading 3,2,Index,1,Appendix A,1,Heading 2 name,1,Appendix B,1" Introduction PAGEREF _Toc518887500 \h 3
+Architecture PAGEREF _Toc518887501 \h 3
+Operation PAGEREF _Toc518887502 \h 3
+Registers PAGEREF _Toc518887503 \h 3
+List of Registers PAGEREF _Toc518887504 \h 3
+Register 1 – Description PAGEREF _Toc518887505 \h 3
+Clocks PAGEREF _Toc518887506 \h 3
+IO Ports PAGEREF _Toc518887507 \h 3
+Appendix A PAGEREF _Toc518887508 \h 3
+Appendix B PAGEREF _Toc518887509 \h 3
+Index PAGEREF _Toc518887510 \h 3
+
+
+Introduction
+This section contains the introduction to the core, describing its use and features.
+
+
+Architecture
+This section describes the architecture of the block. A block diagram should be included describing the top level of the design.
+
+
+
+Operation
+This section describes the operation of the core. Specific sequences, such as startup sequences, as well as the modes and states of the block should be described.
+
+
+Registers
+This section specifies all internal registers. It should completely cover the interface between the core and the host as seen from the software view.
+List of Registers
+NameAddressWidthAccessDescriptionTable SEQ Table \* ARABIC 1: List of registers
+Register 1 – Description
+(You shall choose the style of register you prefer. Do not use both options in one and the same document.)
+Bit #AccessDescriptionReset Value:
+ Reg_Name: 0000h
+
+31302928...876543210Table SEQ Table \* ARABIC 2: Description of registers
+Reset Value:
+ Reg_Name: 0000h
+
+Clocks
+This section specifies all the clocks. All clocks, clock domain passes and the clock relations should be described.
+
+NameSourceRates (MHz)RemarksDescriptionMaxMinResolutionclk_pad_iInput Pad1040.1Duty cycle 70/30.For external interface.wb_clk_IPLL200--Must be synchronized to sm_clk_iSystem clock.sm_clk_iInput port55401There are multi-clocks paths.Clock 55MHz for State machine.Table SEQ Table \* ARABIC 3: List of clocks
+
+
+IO Ports
+This section specifies the core IO ports.
+
+PortWidthDirectionDescriptionwb_clk_i1InputBlock’s WISHBONE Clock Inputwb_rst_i1InputBlock’s WISHBONE Reset Inputwb_sel_i4InputBlock’s WISHBONE Select Inputsfoo_pad_o1OutputBlock’s foo output to output pad…Table SEQ Table \* ARABIC 4: List of IO ports
+
+
+Name
+This section may be added to outline different specifications.
+
+Name
+This section may be added to outline different specifications.
+
+
+This section contains an alphabetical list of helpful document entries with their corresponding page numbers.
+ OpenCores TITLE \* MERGEFORMAT Specifications Template DATE \* MERGEFORMAT 10/22/01
+
+
+
+HYPERLINK "http://www.opencores.org/"www.opencores.org Rev 0.8 Preliminary PAGE ii
+
+ OpenCores TITLE \* MERGEFORMAT Specifications Template DATE \* MERGEFORMAT 10/22/01
+
+
+
+HYPERLINK "http://www.opencores.org/"www.opencores.org Rev 0.8 Preliminary PAGE iv
+
+
+
+
+
+HYPERLINK "http://www.opencores.org/"www.opencores.org Rev 0.8 Preliminary PAGE 9 of SECTIONPAGES9
+
+
+ EMBED PBrush
+
+
+
+ " U V Z c d | } Ž ’ Ÿ Ì Í Þ û < ì $ D { } ¾ ¿ ' ( q r € š › œ ž ¬ Ç È É Ê Ë Ö × ñ ò ó ô õ
+
+
+ ú öò òîåîåßåîò ÙÖÎÌ É É É É É Áú ú¾·¾·¾·¾·¾£·¾·¾·¾™·¾·¾·¾ jú UmH j} UmH j UmH
+j UmH mH 5CJH OJ QJ mH 55CJ$ OJ QJ CJ(
+6B*CJ 5CJ mH j 5CJ U 5CJ 6CJ 5CJ4 j U : ! " 6 V W X Y Z c ‘ ’ “ ” • – — ˜ ™ š › œ ž ý û ô ô ô ñ ñ ô ô ô ô ô ô ô ô ý ý ý ý ý ý ý ý ï ý ý ý 3 $ $
+Æ f! ! " 6 V W X Y Z c ‘ ’ “ ” • – — ˜ ™ š › œ ž Ÿ Ì Þ ã è ï û ü ! % + < e — ½ ¾  ý û ù öóðéâÛÔÐÉ»´°©¢›”†‚{ "
+àþÿÿ áþÿÿ"
+ÿÿÿ "
+9ÿÿÿ "
+bÿÿÿ "
+sÿÿÿ "
+yÿÿÿ "
+}ÿÿÿ ~ÿÿÿ"
+Šÿÿÿ "
+–ÿÿÿ "
+žÿÿÿ "
+¢ÿÿÿ £ÿÿÿ"
+¯ÿÿÿ "
+¶ÿÿÿ "
+»ÿÿÿ "
+Àÿÿÿ Òÿÿÿÿÿÿÿ 3 0ž Ÿ Ì Þ ã è ï û ü ý ú ó ð ð ð ð ¢” ð ð ð ð M $$–l 4
+t ¯ Ö Ö\ ”ÿÐ3¶
+À! < c ƒ
+ Ö ˜ ˜ ˜ ˜" $ $¤à¤ð $ ! % + < e — ½ ¾ Â Ë Ý ¸t µ µ µ µ µ µ n$ µ µ µ µ F $$–l
+t ¯ Ö Ö\ ”ÿÐ3¶
+À! < c ƒ
+ " $ F $$–l
+t ¯ Ö Ö\ ”ÿÐ3¶
+À! <ÿÿÿÿ cÿÿÿÿ ƒÿÿÿÿ
+ÿÿÿÿ Â Ë Ý O Æ ð F G K S _ w x | ƒ • ¸ Ò ë ì ð ø
+ $ C D H P ùòëäÝÖÏËĽ¶¯«¤–ˆ}vohaZVOH"
+Vüÿÿ "
+Züÿÿ [üÿÿ"
+züÿÿ "
+”üÿÿ "
+¦üÿÿ "
+®üÿÿ "
+²üÿÿ ³üÿÿ"
+Ìüÿÿ "
+æüÿÿ "
+ ýÿÿ "
+ýÿÿ "
+"ýÿÿ "
+&ýÿÿ