URL
https://opencores.org/ocsvn/spicxif/spicxif/trunk
Subversion Repositories spicxif
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/spicxif/trunk/RTL/SPIxIF.v
0,0 → 1,484
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright 2008-2013 by Michael A. Morris, dba M. A. Morris & Associates |
// |
// All rights reserved. The source code contained herein is publicly released |
// under the terms and conditions of the GNU Lesser Public License. No part of |
// this source code may be reproduced or transmitted in any form or by any |
// means, electronic or mechanical, including photocopying, recording, or any |
// information storage and retrieval system in violation of the license under |
// which the source code is released. |
// |
// The source code contained herein is free; it may be redistributed and/or |
// modified in accordance with the terms of the GNU Lesser General Public |
// License as published by the Free Software Foundation; either version 2.1 of |
// the GNU Lesser General Public License, or any later version. |
// |
// The source code contained herein is freely released WITHOUT ANY WARRANTY; |
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
// PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for |
// more details.) |
// |
// A copy of the GNU Lesser General Public License should have been received |
// along with the source code contained herein; if not, a copy can be obtained |
// by writing to: |
// |
// Free Software Foundation, Inc. |
// 51 Franklin Street, Fifth Floor |
// Boston, MA 02110-1301 USA |
// |
// Further, no use of this source code is permitted in any form or means |
// without inclusion of this banner prominently in any derived works. |
// |
// Michael A. Morris |
// Huntsville, AL |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
`timescale 1ns / 1ps |
|
//////////////////////////////////////////////////////////////////////////////// |
// Company: M. A. Morris & Associates |
// Engineer: Michael A. Morris |
// |
// Create Date: 20:31:58 03/17/2008 |
// Design Name: Serial Peripheral Interconnect (SPI) Master Interface |
// Module Name: SPIxIF.v |
// Project Name: VerilogComponentsLib\SPI and SSP Components\SPI Master |
// Target Devices: FPGA |
// Tool versions: ISE 10.1i SP3 |
// |
// Description: |
// |
// This module implements a full-duplex (Master) SPI interface. It is a major |
// revision of the previous implementation which basically implemented the SPI |
// operating modes within a Synchronous Serial Peripheral (SSP) as used in NXP |
// ARM LPC21xx microcontrollers. In an NXP SSP, an SPI-like peripheral is used |
// that has a programmable length shift register which performs serial I/O |
// data transfers in a single cycle: Slave Select (SS) is asserted and de- |
// asserted for each data transfer cycle. The only SPI-like feature of the pre- |
// vious implementation was the ability to program the clock idle state and the |
// data sampling edge, i.e. the SPI operating modes. Because a transfer cycle |
// always deasserted SS, the original implementation would require substan- |
// tial modification in order to be useful with standard SPI-compatible devices |
// such as Serial EEPROMs, serial FRAMs/MRAMs, ADCs/DACs, UARTs, I/O expanders, |
// etc. |
// |
// This module will implement an SPI Master interface that avoids the limita- |
// tions of the previous implementation. It will use a fixed 8-bit interface, |
// but it will support variable length cycles. To operate in this manner, the |
// basic control interface will support an interface that can be easily attach- |
// ed to FIFOs. (The transmit FIFO will use a 9-bit interface, and the receive |
// FIFO will use an 8-bit interface.) An SPI data transfer cycle will start |
// when the transmit FIFO EF indicates that there is data to transmit, and the |
// SPI transfer cycle will terminate when the last bit is shifted out and the |
// transmit FIFO EF indicates that it is empty. |
// |
// The 9th bit of the transmit data will be used to enable the writing of the |
// receive data into the receive FIFO. If the bit is not set, the data shifted |
// in during an 8-bit SPI shift cycle is not captured into the receive FIFO. |
// If the 9th bit is set, then the data shifted into the SPI shift register is |
// captured into the receive FIFO. The 9th bit is expected to be part of the |
// transmit FIFO, so it can be set or cleared for each 8-bit SPI transfer cy- |
// cle. (Note: the 9th bit can be implemented separate from the transmit FIFO, |
// but it would need to be merged into the transmit data bus by the external |
// logic.) |
// |
// The explicit read capability provided by the 9th bit is useful when working |
// with SPI devices such as SPI memory devices which do not return any data |
// until a command code and an address have been written. Generally, these |
// devices require several command codes and address bytes to be sent to it |
// before it enables its serial output signal driver and returns the requested |
// data. Therefore, for these devices, the 9th bit is cleared when the command |
// and address bytes are being sent, and the 9th bit set while dummy data is |
// written to and the data received from the device is written into the receive |
// FIFO. |
// |
// On the other hand, there are many devices where the data on MISO is consi- |
// dered valid from the onset of a transfer cycle. Devices such as ADCs provide |
// data on MISO that is valid while the conversion command for the next sample |
// is being simultaneously shifted out to the ADC on MOSI. For these devices, |
// the 9th bit is set in the transmit FIFO for each output byte. This causes |
// each received byte to be written to the receive FIFO. |
// |
// The SPI interface operates in four modes: Mode 0, 1, 2, and 3. Generally, |
// the mode is selected by two control signals, CPOL and CPHA. CPHA determines |
// the idle state of the SPI clock signal, SCK. The interface shifts data at |
// the beginning of each bit cell. The four operating SPI modes are tabulated |
// in the following table: |
// |
// Mode CPOL CPHA : SCK Idle Level Sample Edge |
// 0 0 0 : 0 Rising |
// 1 0 1 : 1 Falling |
// 2 1 0 : 0 Falling |
// 3 1 1 : 1 Rising |
// |
// Examining the table, the sampling edge is set to rising when CPOL and CPHA |
// are the same logic level, and it is set to falling when CPOL and CPHA are |
// complementary logic levels. In other words, the rising edge of SCK occurs in |
// the middle of the bit cell when (CPOL XNOR CPHA) == 1, and the falling edge |
// occurs in the middle of the bit cell when (CPOL XOR CPHA) == 1. |
// |
// Two internal signals derived from Mode[1:0] determine the idle state of |
// SCK, SCK_Lvl, and the polarity of SCK used for data sampling, SCK_Inv. A |
// change-of-state (COS) detector is used to dynamically detect changes in the |
// value of SCK_Lvl, and to load the SCK register with the appropriate value |
// when the SPI interface idle, i.e. SS == 0. SCK_Lvl is taken from Mode[0], |
// and SCK_Inv is the XOR of Mode[1] and Mode[0], as indicated in the table |
// above. |
// |
// The implementation shifts at one half of the CE frequency. The shift direc- |
// tion is programmable, but MSB first is the default. |
// |
// The module contains the SCK generator. A three bit rate select input deter- |
// mines the rate of the SPI clock signal. A 50% duty cycle clock is produced, |
// and two separate clock enables are generated internally for loading and |
// shifting (propagating) the transmit data, and for shifting and writing the |
// receive data. The basic frequency is set by the equation: |
// |
// F(SCK) = Clk / (2**(Rate + 1)) |
// |
// If rate is set to 0, then the frequency of SCK is one half that of the |
// module's input clock frequency. With Rate set to 7, the SCK frequecy is |
// Clk/256. |
// |
// The output shift enable always asserts at the trailing edge of the bit cell, |
// and the input shift enable always asserts in the middle of the bit cell. |
// These shift enables are independent of the sampling and propagating edges |
// of SCK. The leading edge of the initial output is generated by the output |
// shift register load signal, which is itself generated by a rising edge |
// detector monitoring the DAV signal while slave select is not asserted. Once |
// SS is asserted, the output shift register is synchronously loaded on the TC |
// of the bit counter coincident with output shift register enable signal, |
// CE_OSR. This event also extends SS and reloads the receive enable signal, |
// RdEn. (RdEn was discussed above, and is determined by the 9th of the trans- |
// mit data.) If there is no more data to transmit, SS and RdEn are both de- |
// asserted. |
// |
// All of the module control signals are resampled while SS is not asserted. |
// The control signals are held for the duration of a transfer cycle, which is |
// determined by the number of bytes loaded into the external transmit FIFO. |
// To limit the logic complexity, the module does not make prevent the control |
// signals from being changed as the initial transmit data is written. It is |
// necessary for the client of the module to ensure that the control signals |
// signals are stable at least one clock cycle before transmit data is availa- |
// ble. |
// |
// With that limitation in mind, the control signals can be changed at any time |
// during a transfer cycle. They will be processed by the module with a one cy- |
// cle delay when SS is not asserted. In this manner, the client logic can dy- |
// namically change the shift direction, SCK operating mode, and SCK operating |
// frequency. This allows the module to be used in situations where the SPI |
// slave devices change modes, rates, and shift directions. For example, a sin- |
// gle SPI interface can be used to support both SPI memory devices (mode 0/3) |
// and SPI ADCs (mode 2) devices. |
// |
// Dependencies: none |
// |
// Revision History: |
// |
// 0.01 08C17 MAM File Created |
// |
// 0.02 08C18 MAM Modified to incorporate SCK_Lvl and a COS detector |
// on SCK_Lvl to allow the Idle State SCK state to be |
// dynamically changed. |
// |
// 0.03 08E09 MAM Changed comment to reflect that this module is an |
// SPI Master Interface. |
// |
// 1.00 12I07 MAM Modified to bring into compliance with Verilog 2001. |
// Modified the interface to use standard control sig- |
// nals {CPOL, CPHA} and to map the SCK_Lvl and SCK_Inv |
// signals to the standard SPI modes. To do this, the |
// standard mode control signals, {CPOL, CPHA}, are run |
// through a mapping function at the beginning of the |
// module. |
// |
// 1.10 12I09 MAM Restored use of separate transmit and receive shift |
// registers. Single, combined shift register can't be |
// used because input data is shifted on the opposite |
// edge from that used to shift the output data. |
// |
// 1.20 12I10 MAM Converted FRE and FWE output signals to FFs. FRE now |
// pulsed one cycle after the OSR is loaded. FWE now |
// pulsed one cycle after the last bit is loaded into |
// the ISR. Converted CE_Cntr from up counter to a down |
// counter. CE remains a combinatorial signal, but the |
// CE counter is loaded from a ROM when CE asserts on |
// basis of the rate captured before SS asserts. CE now |
// asserts on a fixed value, 0, and the counter is re- |
// loaded from a ROM. This contrasts with up-counter |
// implementation which reloaded a fixed value, 0, and |
// terminated on a variable value. The variable decode |
// of the counter for CE apparently caused an issue in |
// simulation that the new down counter resolves. |
// |
// 1.30 13G06 MAM Removed code previously commented out. Corrected the |
// SCK equation. A Rst_SCK was being generated at the |
// end of every 8 bits. This introduced a discontinuity |
// in SCK which does not allow frames greater than 8 |
// bits in length to be transmitted. With the removal |
// the incorrect conditional logic in Rst_SCK, the SSP |
// Slave and UART modules operate in either SPI Mode 0 |
// or Mode 3. |
// |
// Additional Comments: |
// |
// The module control signals, LSB, Mode, and Rate, must be set at least one |
// clock cycle before DAV is asserted. Changing these control signals at the |
// same time that DAV is asserted will result in incorrect operation. |
// |
//////////////////////////////////////////////////////////////////////////////// |
|
module SPIxIF ( |
input Rst, // System Reset (synchronous) |
input Clk, // System Clk |
// |
input LSB, // SPI LSB First Shift Direction |
input [1:0] Mode, // SPI Operating Mode |
input [2:0] Rate, // SPI Shift Rate Select: SCK = Clk/2**(Rate+1) |
// |
input DAV, // SPI Transmit Data Available |
output reg FRE, // SPI Transmit FIFO Read Enable |
input [8:0] TD, // SPI Transmit Data |
// |
output reg FWE, // SPI Receive FIFO Write Enable |
output [7:0] RD, // SPI Receive Data |
// |
output reg SS, // SPI Slave Select |
output reg SCK, // SPI Shift Clock |
output MOSI, // SPI Master Out, Slave In: Serial Data Output |
input MISO // SPI Master In, Slave Out: Serial Data In |
); |
|
//////////////////////////////////////////////////////////////////////////////// |
// |
// Module Parameters |
// |
|
//////////////////////////////////////////////////////////////////////////////// |
// |
// Module Declarations |
// |
|
reg Dir; // Shift Register Shift Direction |
|
reg SCK_Lvl, SCK_Inv, COS_SCK_Lvl; // SCK level and edge control |
|
reg [2:0] rRate; // SPI SCK Rate Select Register |
reg [6:0] CE_Cntr; // SPI CE Counter (2x SCK) |
wire CE; // SPI Clock Enable (TC CE_Cntr) |
|
wire CE_SCK, Rst_SCK; // SCK generator control signals |
|
reg Ld; // SPI Transfer Cycle Start Pulse |
|
wire CE_OSR, CE_ISR; // SPI Shift Register Clock Enables |
reg [7:0] OSR, ISR; // SPI Output/Input Shift Registers |
reg RdEn; // SPI Read Enable (9th bit in TD) |
|
reg [2:0] BitCnt; // SPI Transfer Cycle Length Cntr |
wire TC_BitCnt; // SPI Bit Counter Terminal Count |
|
//////////////////////////////////////////////////////////////////////////////// |
// |
// Implementation |
// |
|
// Capture the shift direction and hold until end of transfer cycle |
|
always @(posedge Clk) |
begin |
if(Rst) |
Dir <= #1 0; // Default to MSB first |
else if(~SS) |
Dir <= #1 LSB; // Set shift direction for transfer cycle |
end |
|
// Assign SCK idle level and invert control signals based on Mode |
|
always @(posedge Clk) |
begin |
if(Rst) begin |
SCK_Inv <= #1 0; |
SCK_Lvl <= #1 0; |
end else if(~SS) begin |
SCK_Inv <= #1 ^Mode; // Invert SCK if Mode == 1 or Mode == 2 |
SCK_Lvl <= #1 Mode[0]; // Set SCK idle level from LSB of Mode |
end |
end |
|
// Generate change of state pulse when SPI clock idle level changes |
// while Slave Select not asserted |
|
always @(posedge Clk) |
begin |
if(Rst) |
COS_SCK_Lvl <= #1 0; |
else |
COS_SCK_Lvl <= #1 ((~SS) ? (SCK_Lvl ^ Mode[0]) : 0); |
end |
|
// Capture SCK rate and hold until the transfer cycle is complete |
|
always @(posedge Clk) |
begin |
if(Rst) |
rRate <= #1 ~0; // Default to slowest rate |
else if(~SS) |
rRate <= #1 Rate; |
end |
|
// |
// SPI Transfer Cycle Load Pulse Generator |
// |
|
always @(posedge Clk) |
begin |
if(Rst) |
Ld <= #1 0; |
else if(~SS) |
Ld <= #1 DAV & ~Ld; |
else if(Ld) |
Ld <= #1 0; |
end |
|
// |
// Serial SPI Clock Generator |
// |
|
always @(posedge Clk) |
begin |
if(Rst) |
CE_Cntr <= #1 ~0; |
else if(CE) |
case(rRate) |
3'b000 : CE_Cntr <= #1 0; |
3'b001 : CE_Cntr <= #1 1; |
3'b010 : CE_Cntr <= #1 3; |
3'b011 : CE_Cntr <= #1 7; |
3'b100 : CE_Cntr <= #1 15; |
3'b101 : CE_Cntr <= #1 31; |
3'b110 : CE_Cntr <= #1 63; |
3'b111 : CE_Cntr <= #1 127; |
endcase |
else if(SS) |
CE_Cntr <= #1 (CE_Cntr - 1); |
end |
|
assign CE = (Ld | (~|CE_Cntr)); |
|
assign CE_SCK = CE & SS; // Clock starts with Slave Select Strobe |
assign Rst_SCK = Rst | Ld | (COS_SCK_Lvl & ~SS) | (TC_BitCnt & CE_OSR & ~DAV); |
|
always @(posedge Clk) |
begin |
if(Rst_SCK) |
#1 SCK <= (Ld ? SCK_Inv : SCK_Lvl); |
else if(CE_SCK) |
#1 SCK <= ~SCK; |
end |
|
// |
// SPI Output Shift Register |
// |
|
assign CE_OSR = CE_SCK & (SCK_Inv ^ SCK); |
assign Ld_OSR = Ld | (TC_BitCnt & CE_OSR); |
|
always @(posedge Clk) |
begin |
if(Rst) |
OSR <= #1 0; |
else if(Ld_OSR) |
OSR <= #1 TD; |
else if(CE_OSR) |
OSR <= #1 ((Dir) ? {SCK_Lvl, OSR[7:1]} : {OSR[6:0], SCK_Lvl}); |
end |
|
assign MOSI = SS & ((Dir) ? OSR[0] : OSR[7]); |
|
// |
// SPI Input Shift Register |
// |
|
assign CE_ISR = CE_SCK & (SCK_Inv ^ ~SCK); |
|
always @(posedge Clk) |
begin |
if(Rst) |
ISR <= #1 0; |
else if(Ld) |
ISR <= #1 0; |
else if(CE_ISR) |
ISR <= #1 ((Dir) ? {MISO, ISR[7:1]} : {ISR[6:0], MISO}); |
end |
|
// |
// SPI SR Bit Counter |
// |
|
assign CE_BitCnt = CE_OSR & SS; |
assign Rst_BitCnt = Rst | Ld | (TC_BitCnt & CE_OSR); |
|
always @(posedge Clk) |
begin |
if(Rst_BitCnt) |
BitCnt <= #1 7; |
else if(CE_BitCnt) |
BitCnt <= #1 (BitCnt - 1); |
end |
|
assign TC_BitCnt = ~|BitCnt; |
|
// |
// SPI Slave Select Generator |
// |
|
always @(posedge Clk) |
begin |
if(Rst) |
SS <= #1 0; |
else if(Ld_OSR) |
SS <= #1 DAV; |
end |
|
// |
// SPI MISO Read Enable Register |
// |
|
always @(posedge Clk) |
begin |
if(Rst) |
RdEn <= #1 0; |
else if(Ld_OSR) |
RdEn <= #1 ((DAV) ? TD[8] : 0); |
end |
|
// |
// SPI Transmit FIFO Read Pulse Generator |
// |
|
always @(posedge Clk) |
begin |
if(Rst) |
FRE <= #1 0; |
else |
FRE <= #1 (Ld | (DAV & (TC_BitCnt & CE_OSR))); |
end |
|
// |
// SPI Receive FIFO Write Pulse Generator |
// |
|
always @(posedge Clk) |
begin |
if(Rst) |
FWE <= #1 0; |
else |
FWE <= #1 (RdEn & (TC_BitCnt & CE_ISR)); |
end |
|
assign RD = ISR; |
|
endmodule |
/spicxif/trunk/Sim/tb_SPIxIF.v
0,0 → 1,536
/////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright 2008-2013 by Michael A. Morris, dba M. A. Morris & Associates |
// |
// All rights reserved. The source code contained herein is publicly released |
// under the terms and conditions of the GNU Lesser Public License. No part of |
// this source code may be reproduced or transmitted in any form or by any |
// means, electronic or mechanical, including photocopying, recording, or any |
// information storage and retrieval system in violation of the license under |
// which the source code is released. |
// |
// The source code contained herein is free; it may be redistributed and/or |
// modified in accordance with the terms of the GNU Lesser General Public |
// License as published by the Free Software Foundation; either version 2.1 of |
// the GNU Lesser General Public License, or any later version. |
// |
// The source code contained herein is freely released WITHOUT ANY WARRANTY; |
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
// PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for |
// more details.) |
// |
// A copy of the GNU Lesser General Public License should have been received |
// along with the source code contained herein; if not, a copy can be obtained |
// by writing to: |
// |
// Free Software Foundation, Inc. |
// 51 Franklin Street, Fifth Floor |
// Boston, MA 02110-1301 USA |
// |
// Further, no use of this source code is permitted in any form or means |
// without inclusion of this banner prominently in any derived works. |
// |
// Michael A. Morris |
// Huntsville, AL |
// |
///////////////////////////////////////////////////////////////////////////////`timescale 1ns / 1ps |
|
`timescale 1ns / 1ps |
|
/////////////////////////////////////////////////////////////////////////////// |
// Company: M. A. Morris & Associates |
// Engineer: Michael A. Morris |
// |
// Create Date: 07:30:59 03/18/2008 |
// Design Name: SPIxIF.v |
// Module Name: tb_SPIx.v |
// Project Name: 4020 HAWK ZAOM Upgrade, 0420-HAWKIF |
// Target Device: XC2S150-5PQ208I |
// Tool versions: ISE 8.2i |
// |
// Description: Testbench for the modified SPIxIF.v module. |
// |
// |
// Verilog Test Fixture created by ISE for module: SPIxIF.v |
// |
// Dependencies: None |
// |
// Revision: |
// |
// 0.01 08C18 MAM File Created |
// |
// 1.00 12I09 MAM Modified to support updated SPIxIF.v module |
// |
// Additional Comments: |
// |
/////////////////////////////////////////////////////////////////////////////// |
|
module tb_SPIxIF; |
|
// Inputs |
reg Rst; |
reg Clk; |
|
reg LSB; |
reg [1:0] Mode; |
reg [2:0] Rate; |
|
reg DAV; |
wire FRE; |
reg [8:0] TD; |
|
wire FWE; |
wire [7:0] RD; |
|
wire SSEL; |
wire SCK; |
wire MOSI; |
//wire MISO; |
|
integer i = 0; |
integer SS_Len = 0; |
|
// Instantiate the Unit Under Test (UUT) |
|
SPIxIF uut ( |
.Rst(Rst), |
.Clk(Clk), |
|
.LSB(LSB), |
.Mode(Mode), |
.Rate(Rate), |
|
.DAV(DAV), |
.FRE(FRE), |
.TD(TD), |
|
.FWE(FWE), |
.RD(RD), |
|
.SS(SS), |
.SCK(SCK), |
.MOSI(MOSI), |
.MISO(MOSI) |
); |
|
initial begin |
// Initialize Inputs |
Rst = 1; |
Clk = 0; |
|
LSB = 0; |
Mode = 0; |
Rate = 0; |
|
DAV = 0; |
TD = 0; |
|
// Wait 100 ns for global reset to finish |
|
#101 Rst = 0; |
|
// Add stimulus here |
|
$display("Testing: MSB first, all four SPI modes, fastest SPI SCK rate\n"); |
|
Mode = 0; Rate = 0; LSB = 0; |
|
$display("\tTest - Mode 0\n"); |
#1; |
if(SCK != 0) begin |
$display("\t\tError: SCK did not idle low in Mode 0\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled low in Mode 0\n"); |
end |
@(posedge Clk) #1; |
DAV = 1; TD = 9'h1AB; |
@(posedge FRE) DAV = 0; |
#1; |
if(SCK != 0) begin |
$display("\t\tError: SCK did not start low in Mode 0\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK started low in Mode 0\n"); |
end |
@(negedge FWE) Mode = 1; |
#1; |
if(SCK != 0) begin |
$display("\t\tError: SCK did not idle low in Mode 0\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled low in Mode 0\n"); |
end |
if(RD != TD[7:0]) begin |
$display("\t\tError: RD not equal to TD\n"); |
$stop; |
end else begin |
$display("\t\tPass: RD equal to TD\n"); |
end |
if(SS_Len != 16) begin |
$display("\t\tError: SS Length != 16; SCK rate incorrect\n"); |
$stop; |
end else begin |
$display("\t\tPass: SS Length == 16; SCK rate correct\n"); |
end |
|
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
$display("\tTest - Mode 1\n"); |
#1; |
if(SCK != 1) begin |
$display("\t\tError: SCK did not idle high in Mode 1\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled high in Mode 1\n"); |
end |
@(posedge Clk) #1; |
DAV = 1; TD = 9'h15A; |
@(posedge FRE) DAV = 0; |
#1; |
if(SCK != 1) begin |
$display("\t\tError: SCK did not start high in Mode 1\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK started high in Mode 1\n"); |
end |
@(negedge FWE) Mode = 2; |
if(SCK != 1) begin |
$display("\t\tError: SCK did not idle high in Mode 1\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled high in Mode 1\n"); |
end |
if(RD != TD[7:0]) begin |
$display("\t\tError: RD not equal to TD\n"); |
$stop; |
end else begin |
$display("\t\tPass: RD equal to TD\n"); |
end |
if(SS_Len != 16) begin |
$display("\t\tError: SS Length != 16; SCK rate incorrect\n"); |
$stop; |
end else begin |
$display("\t\tPass: SS Length == 16; SCK rate correct\n"); |
end |
|
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
$display("\tTest - Mode 2\n"); |
#1; |
if(SCK != 0) begin |
$display("\t\tError: SCK did not idle low in Mode 2\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled low in Mode 2\n"); |
end |
@(posedge Clk) #1; |
DAV = 1; TD = 9'h1A5; |
@(posedge FRE) DAV = 0; |
#1; |
if(SCK != 1) begin |
$display("\t\tError: SCK did not start high in Mode 2\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK started high in Mode 2\n"); |
end |
@(negedge FWE) Mode = 3; |
if(SCK != 0) begin |
$display("\t\tError: SCK did not idle low in Mode 2\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled low in Mode 2\n"); |
end |
if(RD != TD[7:0]) begin |
$display("\t\tError: RD not equal to TD\n"); |
$stop; |
end else begin |
$display("\t\tPass: RD equal to TD\n"); |
end |
if(SS_Len != 16) begin |
$display("\t\tError: SS Length != 16; SCK rate incorrect\n"); |
$stop; |
end else begin |
$display("\t\tPass: SS Length == 16; SCK rate correct\n"); |
end |
|
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
$display("\tTest - Mode 3\n"); |
#1; |
if(SCK != 1) begin |
$display("\t\tError: SCK did not idle high in Mode 3\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled high in Mode 3\n"); |
end |
@(posedge Clk) #1; |
DAV = 1; TD = 9'h169; |
@(posedge FRE) DAV = 0; |
#1; |
if(SCK != 0) begin |
$display("\t\tError: SCK did not start low in Mode 3\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK started low in Mode 3\n"); |
end |
@(negedge FWE) Mode = 0; |
if(SCK != 1) begin |
$display("\t\tError: SCK did not idle high in Mode 3\n"); |
$stop; |
end else begin |
$display("\t\tPass: SCK idled high in Mode 3\n"); |
end |
if(RD != TD[7:0]) begin |
$display("\t\tError: RD not equal to TD\n"); |
$stop; |
end else begin |
$display("\t\tPass: RD equal to TD\n"); |
end |
if(SS_Len != 16) begin |
$display("\t\tError: SS Length != 16; SCK rate incorrect\n"); |
$stop; |
end else begin |
$display("\t\tPass: SS Length == 16; SCK rate correct\n"); |
end |
|
$display("Testing multi-cycle transfer\n"); |
@(posedge Clk) #1; |
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 64) begin |
$display("\tError: SS Length != 64; Incorrect number of transfers\n"); |
$stop; |
end else begin |
$display("\tPass: SS Length == 64; Correct number of transfers\n"); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 1)\n"); |
Rate = 1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 128) begin |
$display("\tError: SS Length != 128; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 2)\n"); |
Rate = 2; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 256) begin |
$display("\tError: SS Length != 256; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 3)\n"); |
Rate = 3; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 512) begin |
$display("\tError: SS Length != 512; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 4)\n"); |
Rate = 4; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 1024) begin |
$display("\tError: SS Length != 1024; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 5)\n"); |
Rate = 5; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 2048) begin |
$display("\tError: SS Length != 2048; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 6)\n"); |
Rate = 6; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 4096) begin |
$display("\tError: SS Length != 4096; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
$display("Testing multi-cycle transfer with (Rate == 7)\n"); |
Rate = 7; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
DAV = 1; |
TD = 9'h002; |
@(negedge FRE); |
TD = 9'h000; |
@(negedge FRE); |
TD = 9'h0AA; |
@(negedge FRE); |
TD = 9'h055; |
@(negedge FRE); |
TD = 9'h000; |
DAV = 0; |
@(negedge SS) #1; |
if(SS_Len != 8192) begin |
$display("\tError: SS Length != 8192; SS_Len = %d\n", SS_Len); |
$stop; |
end else begin |
$display("\tPass: SS Length == %d\n", SS_Len); |
end |
|
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
@(posedge Clk) #1; |
|
$stop; |
end |
|
//////////////////////////////////////////////////////////////////////////////// |
// |
// Define Clocks |
// |
|
always #5 Clk = ~Clk; |
|
//////////////////////////////////////////////////////////////////////////////// |
|
always @(negedge SS) SS_Len = i; |
|
always @(posedge Clk or negedge SS) |
begin |
if(~SS) |
#10 i = 0; |
else |
i = i + 1; |
end |
|
endmodule |