blob: fcff5b52a24bc20f5c2d7210fb774352c9eb0543 [file] [log] [blame]
// *******************************************************************************************************
// ** **
// ** 23LC512.v - 23LC512 512 KBIT SPI SERIAL SRAM (VCC = +2.5V TO +5.5V) **
// ** **
// *******************************************************************************************************
// ** **
// ** This information is distributed under license from Young Engineering. **
// ** COPYRIGHT (c) 2014 YOUNG ENGINEERING **
// ** ALL RIGHTS RESERVED **
// ** **
// ** **
// ** Young Engineering provides design expertise for the digital world **
// ** Started in 1990, Young Engineering offers products and services for your electronic design **
// ** project. We have the expertise in PCB, FPGA, ASIC, firmware, and software design. **
// ** From concept to prototype to production, we can help you. **
// ** **
// ** http://www.young-engineering.com/ **
// ** **
// *******************************************************************************************************
// ** **
// ** This information is provided to you for your convenience and use with Microchip products only. **
// ** Microchip disclaims all liability arising from this information and its use. **
// ** **
// ** THIS INFORMATION IS PROVIDED "AS IS." MICROCHIP MAKES NO REPRESENTATION OR WARRANTIES OF **
// ** ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO **
// ** THE INFORMATION PROVIDED TO YOU, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, **
// ** PERFORMANCE, MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR PURPOSE. **
// ** MICROCHIP IS NOT LIABLE, UNDER ANY CIRCUMSTANCES, FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL **
// ** DAMAGES, FOR ANY REASON WHATSOEVER. **
// ** **
// ** It is your responsibility to ensure that your application meets with your specifications. **
// ** **
// *******************************************************************************************************
// ** **
// ** Revision : 1.0 **
// ** Modified Date : 04/23/2014 **
// ** Revision History: **
// ** **
// ** 04/23/2014: Initial design **
// ** Modified Date : 5/5/2014 **
// ** Revision History: **
// ** Based on the 23LC1024.v model a 512k bit model for the 23LC512 is drafted below **
// *******************************************************************************************************
// ** TABLE OF CONTENTS **
// *******************************************************************************************************
// **---------------------------------------------------------------------------------------------------**
// ** DECLARATIONS **
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// ** INITIALIZATION **
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// ** CORE LOGIC **
// **---------------------------------------------------------------------------------------------------**
// ** 1.01: Internal Reset Logic **
// ** 1.02: Input Data Shifter **
// ** 1.03: Clock Cycle Counter **
// ** 1.04: Instruction Register **
// ** 1.05: Address Register **
// ** 1.06: Status Register Write **
// ** 1.07: I/O Mode Instructions **
// ** 1.08: Array Write **
// ** 1.09: Output Data Shifter **
// ** 1.10: Output Data Buffer **
// ** **
// **---------------------------------------------------------------------------------------------------**
// ** DEBUG LOGIC **
// **---------------------------------------------------------------------------------------------------**
// ** 2.01: Memory Data Bytes **
// ** **
// **---------------------------------------------------------------------------------------------------**
// ** TIMING CHECKS **
// **---------------------------------------------------------------------------------------------------**
// ** **
// *******************************************************************************************************
`timescale 1ns/10ps
module M23LC512 (SI_SIO0, SO_SIO1, SCK, CS_N, SIO2, HOLD_N_SIO3, RESET);
inout SI_SIO0; // serial data input/output
input SCK; // serial data clock
input CS_N; // chip select - active low
inout SIO2; // serial data input/output
inout HOLD_N_SIO3; // interface suspend - active low/
// serial data input/output
input RESET; // model reset/power-on reset
inout SO_SIO1; // serial data input/output
// *******************************************************************************************************
// ** DECLARATIONS **
// *******************************************************************************************************
reg [07:00] DataShifterI; // serial input data shifter
reg [07:00] DataShifterO; // serial output data shifter
reg [31:00] ClockCounter; // serial input clock counter
reg [07:00] InstRegister; // instruction register
reg [15:00] AddrRegister; // address register modified for 16 bit addresses
wire InstructionREAD; // decoded instruction byte
wire InstructionRDMR; // decoded instruction byte
wire InstructionWRMR; // decoded instruction byte
wire InstructionWRITE; // decoded instruction byte
wire InstructionEDIO; // decoded instruction byte
wire InstructionEQIO; // decoded instruction byte
wire InstructionRSTIO; // decoded instruction byte
reg [01:00] OpMode; // operation mode
reg [01:00] IOMode; // I/O mode
wire Hold; // hold function
reg [07:00] MemoryBlock [0:65535]; // SRAM data memory array (65536x8)
reg [03:00] SO_DO; // serial output data - data
wire SO_OE; // serial output data - output enable
reg SO_Enable; // serial data output enable
wire OutputEnable1; // timing accurate output enable
wire OutputEnable2; // timing accurate output enable
wire OutputEnable3; // timing accurate output enable
integer tV; // timing parameter
integer tHZ; // timing parameter
integer tHV; // timing parameter
integer tDIS; // timing parameter
`define READ 8'b0000_0011 // Read instruction
`define WRMR 8'b0000_0001 // Write Mode Register instruction
`define WRITE 8'b0000_0010 // Write instruction
`define RDMR 8'b0000_0101 // Read Mode Register instruction
`define EDIO 8'b0011_1011 // Enter Dual I/O instruction
`define EQIO 8'b0011_1000 // Enter Quad I/O instruction
`define RSTIO 8'b1111_1111 // Reset Dual and Quad I/O instruction
`define BYTEMODE 2'b00 // Byte operation mode
`define PAGEMODE 2'b10 // Page operation mode
`define SEQMODE 2'b01 // Sequential operation mode
`define SPIMODE 2'b00 // SPI I/O mode
`define SDIMODE 2'b01 // SDI I/O mode
`define SQIMODE 2'b10 // SQI I/O mode
// *******************************************************************************************************
// ** INITIALIZATION **
// *******************************************************************************************************
initial begin
`ifdef TEMP_INDUSTRIAL
tV = 25; // output valid from SCK low
tHZ = 10; // HOLD_N low to output high-z
tHV = 50; // HOLD_N high to output valid
tDIS = 20; // CS_N high to output disable
`else
`ifdef TEMP_EXTENDED
tV = 32; // output valid from SCK low
tHZ = 10; // HOLD_N low to output high-z
tHV = 50; // HOLD_N high to output valid
tDIS = 20; // CS_N high to output disable
`else
tV = 25; // output valid from SCK low
tHZ = 10; // HOLD_N low to output high-z
tHV = 50; // HOLD_N high to output valid
tDIS = 20; // CS_N high to output disable
`endif
`endif
end
initial begin
OpMode = `SEQMODE;
IOMode = `SPIMODE;
end
assign Hold = (HOLD_N_SIO3 == 0) & (IOMode == `SPIMODE);
// *******************************************************************************************************
// ** CORE LOGIC **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
// 1.01: Internal Reset Logic
// -------------------------------------------------------------------------------------------------------
always @(negedge CS_N) ClockCounter <= 0;
always @(negedge CS_N) SO_Enable <= 0;
// -------------------------------------------------------------------------------------------------------
// 1.02: Input Data Shifter
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin
if (Hold == 0) begin
if (CS_N == 0) begin
case (IOMode)
`SPIMODE: DataShifterI <= {DataShifterI[06:00],SI_SIO0};
`SDIMODE: DataShifterI <= {DataShifterI[05:00],SO_SIO1,SI_SIO0};
`SQIMODE: DataShifterI <= {DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0};
default: $error("IOMode set to invalid value.");
endcase
end
end
end
// -------------------------------------------------------------------------------------------------------
// 1.03: Clock Cycle Counter
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin
if (Hold == 0) begin
if (CS_N == 0) ClockCounter <= ClockCounter + 1;
end
end
// -------------------------------------------------------------------------------------------------------
// 1.04: Instruction Register
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin
if (Hold == 0) begin
case (IOMode)
`SPIMODE: begin
if (ClockCounter == 7) InstRegister <= {DataShifterI[06:00],SI_SIO0};
end
`SDIMODE: begin
if (ClockCounter == 3) InstRegister <= {DataShifterI[05:00],SO_SIO1,SI_SIO0};
end
`SQIMODE: begin
if (ClockCounter == 1) InstRegister <= {DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0};
end
default: $error("IOMode set to invalid value.");
endcase
end
end
assign InstructionREAD = (InstRegister[7:0] == `READ);
assign InstructionRDMR = (InstRegister[7:0] == `RDMR);
assign InstructionWRMR = (InstRegister[7:0] == `WRMR);
assign InstructionWRITE = (InstRegister[7:0] == `WRITE);
assign InstructionEDIO = (InstRegister[7:0] == `EDIO);
assign InstructionEQIO = (InstRegister[7:0] == `EQIO);
assign InstructionRSTIO = (InstRegister[7:0] == `RSTIO);
// -------------------------------------------------------------------------------------------------------
// 1.05: Address Register
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin
if (Hold == 0 & (InstructionREAD | InstructionWRITE)) begin
case (IOMode)
`SPIMODE: begin
if (ClockCounter == 15) AddrRegister[15:08] <= {DataShifterI[06:00],SI_SIO0};
else if (ClockCounter == 23) AddrRegister[07:00] <= {DataShifterI[06:00],SI_SIO0};
end
`SDIMODE: begin
if (ClockCounter == 7) AddrRegister[15:08] <= {DataShifterI[05:00],SO_SIO1,SI_SIO0};
else if (ClockCounter == 11) AddrRegister[07:00] <= {DataShifterI[05:00],SO_SIO1,SI_SIO0};
end
`SQIMODE: begin
if (ClockCounter == 3) AddrRegister[15:08] <= {DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0};
else if (ClockCounter == 5) AddrRegister[07:00] <= {DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0};
end
default: $error("IOMode set to invalid value.");
endcase
end
end
// -------------------------------------------------------------------------------------------------------
// 1.06: Status Register Write
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin
if (Hold == 0 & InstructionWRMR) begin
case (IOMode)
`SPIMODE: begin
if (ClockCounter == 15) OpMode <= DataShifterI[06:05]; //datashifter is missing one bit
end
`SDIMODE: begin
if (ClockCounter == 7) OpMode <= DataShifterI[05:04]; //datashifter is missing two bits
end
`SQIMODE: begin
if (ClockCounter == 3) OpMode <= DataShifterI[03:02]; //...missing a nibble
end
default: $error("IOMode set to invalid value.");
endcase
end
end
// -------------------------------------------------------------------------------------------------------
// 1.07: I/O Mode Instructions
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin //changes io mode.
case (IOMode)
`SPIMODE: begin
if (ClockCounter == 7) begin
if ({DataShifterI[06:00],SI_SIO0} == `EDIO) IOMode <= `SDIMODE;
else if ({DataShifterI[06:00],SI_SIO0} == `EQIO) IOMode <= `SQIMODE;
end
end
`SDIMODE: begin
if (ClockCounter == 3) begin
if ({DataShifterI[05:00],SO_SIO1,SI_SIO0} == `EQIO) IOMode <= `SQIMODE;
else if ({DataShifterI[05:00],SO_SIO1,SI_SIO0} == `RSTIO) IOMode <= `SPIMODE;
end
end
`SQIMODE: begin
if (ClockCounter == 1) begin
if ({DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0} == `EDIO) IOMode <= `SDIMODE;
else if ({DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0} == `RSTIO) IOMode <= `SPIMODE;
end
end
endcase
end
// -------------------------------------------------------------------------------------------------------
// 1.08: Array Write
// -------------------------------------------------------------------------------------------------------
always @(posedge SCK) begin
if (Hold == 0 & InstructionWRITE) begin
case (IOMode)
`SPIMODE: begin
if ((ClockCounter >= 31) & (ClockCounter[2:0] == 3'b111)) begin //every odd clock, where odd means %8=7
MemoryBlock[AddrRegister[15:00]] <= {DataShifterI[06:00],SI_SIO0};
case (OpMode)
`PAGEMODE: AddrRegister[04:00] <= AddrRegister[04:00] + 1;
`SEQMODE: AddrRegister[15:00] <= AddrRegister[15:00] + 1;
endcase
end
end
`SDIMODE: begin
if ((ClockCounter >= 15) & (ClockCounter[1:0] == 2'b11)) begin
MemoryBlock[AddrRegister[15:00]] <= {DataShifterI[05:00],SO_SIO1,SI_SIO0};
case (OpMode)
`PAGEMODE: AddrRegister[04:00] <= AddrRegister[04:00] + 1;
`SEQMODE: AddrRegister[15:00] <= AddrRegister[15:00] + 1;
endcase
end
end
`SQIMODE: begin
if ((ClockCounter >= 7) & (ClockCounter[0] == 1'b1)) begin
MemoryBlock[AddrRegister[15:00]] <= {DataShifterI[03:00],HOLD_N_SIO3,SIO2,SO_SIO1,SI_SIO0};
case (OpMode)
`PAGEMODE: AddrRegister[04:00] <= AddrRegister[04:00] + 1;
`SEQMODE: AddrRegister[15:00] <= AddrRegister[15:00] + 1;
endcase
end
end
default: $error("IOMode set to invalid value.");
endcase
end
end
// -------------------------------------------------------------------------------------------------------
// 1.09: Output Data Shifter
// -------------------------------------------------------------------------------------------------------
always @(negedge SCK) begin
if (Hold == 0) begin
if (InstructionREAD) begin
case (IOMode)
`SPIMODE: begin
if ((ClockCounter >= 24) & (ClockCounter[2:0] == 3'b000)) begin
DataShifterO <= MemoryBlock[AddrRegister[15:00]];
SO_Enable <= 1;
case (OpMode)
`PAGEMODE: AddrRegister[04:00] <= AddrRegister[04:00] + 1;
`SEQMODE: AddrRegister[15:00] <= AddrRegister[15:00] + 1;
endcase
end
else DataShifterO <= DataShifterO << 1;
end
`SDIMODE: begin
if ((ClockCounter >= 16) & (ClockCounter[1:0] == 2'b00)) begin
DataShifterO <= MemoryBlock[AddrRegister[15:00]];
SO_Enable <= 1;
case (OpMode)
`PAGEMODE: AddrRegister[04:00] <= AddrRegister[04:00] + 1;
`SEQMODE: AddrRegister[15:00] <= AddrRegister[15:00] + 1;
endcase
end
else DataShifterO <= DataShifterO << 2;
end
`SQIMODE: begin
if ((ClockCounter >= 8) & (ClockCounter[0] == 1'b0)) begin
DataShifterO <= MemoryBlock[AddrRegister[15:00]];
SO_Enable <= 1;
case (OpMode)
`PAGEMODE: AddrRegister[04:00] <= AddrRegister[04:00] + 1;
`SEQMODE: AddrRegister[15:00] <= AddrRegister[15:00] + 1;
endcase
end
else DataShifterO <= DataShifterO << 4;
end
default: $error("IOMode set to invalid value.");
endcase
end
else if (InstructionRDMR) begin
case (IOMode)
`SPIMODE: begin
if ((ClockCounter > 7) & (ClockCounter[2:0] == 3'b000)) begin
DataShifterO <= {OpMode,6'b000000};
SO_Enable <= 1;
end
else DataShifterO <= DataShifterO << 1;
end
`SDIMODE: begin
if ((ClockCounter > 3) & (ClockCounter[1:0] == 2'b00)) begin
DataShifterO <= {OpMode,6'b000000};
SO_Enable <= 1;
end
else DataShifterO <= DataShifterO << 2;
end
`SQIMODE: begin
if ((ClockCounter > 1) & (ClockCounter[0] == 1'b0)) begin
DataShifterO <= {OpMode,6'b000000};
SO_Enable <= 1;
end
else DataShifterO <= DataShifterO << 4;
end
default: $error("IOMode set to invalid value.");
endcase
end
end
end
// -------------------------------------------------------------------------------------------------------
// 1.10: Output Data Buffer
// -------------------------------------------------------------------------------------------------------
// Buffer for SPI mode
bufif1 (SO_SIO1, SO_DO[0], SO_OE & (IOMode == `SPIMODE));
// Buffers for SDI mode
bufif1 (SI_SIO0, SO_DO[0], SO_OE & (IOMode == `SDIMODE));
bufif1 (SO_SIO1, SO_DO[1], SO_OE & (IOMode == `SDIMODE));
// Buffers for SQI Mode
bufif1 (SI_SIO0, SO_DO[0], SO_OE & (IOMode == `SQIMODE));
bufif1 (SO_SIO1, SO_DO[1], SO_OE & (IOMode == `SQIMODE));
bufif1 (SIO2, SO_DO[2], SO_OE & (IOMode == `SQIMODE));
bufif1 (HOLD_N_SIO3, SO_DO[3], SO_OE & (IOMode == `SQIMODE));
always @(DataShifterO) begin
case (IOMode)
`SPIMODE: begin
SO_DO[0] <= #(tV) DataShifterO[07];
end
`SDIMODE: begin
SO_DO[1] <= #(tV) DataShifterO[07];
SO_DO[0] <= #(tV) DataShifterO[06];
end
`SQIMODE: begin
SO_DO[3] <= #(tV) DataShifterO[07];
SO_DO[2] <= #(tV) DataShifterO[06];
SO_DO[1] <= #(tV) DataShifterO[05];
SO_DO[0] <= #(tV) DataShifterO[04];
end
endcase
end
bufif1 #(tV,0) (OutputEnable1, SO_Enable, 1);
notif1 #(tDIS) (OutputEnable2, CS_N, 1);
bufif1 #(tHV,tHZ) (OutputEnable3, HOLD_N_SIO3 | !(IOMode == `SPIMODE), 1);
assign SO_OE = OutputEnable1 & OutputEnable2 & OutputEnable3;
// *******************************************************************************************************
// ** DEBUG LOGIC **
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
// 2.01: Memory Data Bytes
// -------------------------------------------------------------------------------------------------------
wire [07:00] MemoryByte00000 = MemoryBlock[000000];
wire [07:00] MemoryByte00001 = MemoryBlock[000001];
wire [07:00] MemoryByte00002 = MemoryBlock[000002];
wire [07:00] MemoryByte00003 = MemoryBlock[000003];
wire [07:00] MemoryByte00004 = MemoryBlock[000004];
wire [07:00] MemoryByte00005 = MemoryBlock[000005];
wire [07:00] MemoryByte00006 = MemoryBlock[000006];
wire [07:00] MemoryByte00007 = MemoryBlock[000007];
wire [07:00] MemoryByte00008 = MemoryBlock[000008];
wire [07:00] MemoryByte00009 = MemoryBlock[000009];
wire [07:00] MemoryByte0000A = MemoryBlock[000010];
wire [07:00] MemoryByte0000B = MemoryBlock[000011];
wire [07:00] MemoryByte0000C = MemoryBlock[000012];
wire [07:00] MemoryByte0000D = MemoryBlock[000013];
wire [07:00] MemoryByte0000E = MemoryBlock[000014];
wire [07:00] MemoryByte0000F = MemoryBlock[000015];
wire [07:00] MemoryByte0FFF0 = MemoryBlock[65519];
wire [07:00] MemoryByte0FFF1 = MemoryBlock[65520];
wire [07:00] MemoryByte0FFF2 = MemoryBlock[65521];
wire [07:00] MemoryByte0FFF3 = MemoryBlock[65522];
wire [07:00] MemoryByte0FFF4 = MemoryBlock[65523];
wire [07:00] MemoryByte0FFF5 = MemoryBlock[65524];
wire [07:00] MemoryByte0FFF6 = MemoryBlock[65525];
wire [07:00] MemoryByte0FFF7 = MemoryBlock[65526];
wire [07:00] MemoryByte0FFF8 = MemoryBlock[65527];
wire [07:00] MemoryByte0FFF9 = MemoryBlock[65528];
wire [07:00] MemoryByte0FFFA = MemoryBlock[65529];
wire [07:00] MemoryByte0FFFB = MemoryBlock[65530];
wire [07:00] MemoryByte0FFFC = MemoryBlock[65531];
wire [07:00] MemoryByte0FFFD = MemoryBlock[65532];
wire [07:00] MemoryByte0FFFE = MemoryBlock[65534];
wire [07:00] MemoryByte0FFFF = MemoryBlock[65535];
// *******************************************************************************************************
// ** TIMING CHECKS **
// *******************************************************************************************************
wire TimingCheckEnable = (RESET == 0) & (CS_N == 0);
wire SPITimingCheckEnable = TimingCheckEnable & (IOMode == `SPIMODE);
wire SDITimingCheckEnable = TimingCheckEnable & (IOMode == `SDIMODE) & (SO_Enable == 0);
wire SQITimingCheckEnable = TimingCheckEnable & (IOMode == `SQIMODE) & (SO_Enable == 0);
specify
`ifdef TEMP_INDUSTRIAL
specparam
tHI = 25, // Clock high time
tLO = 25, // Clock low time
tSU = 10, // Data setup time
tHD = 10, // Data hold time
tHS = 10, // HOLD_N setup time
tHH = 10, // HOLD_N hold time
tCSD = 25, // CS_N disable time
tCSS = 25, // CS_N setup time
tCSH = 50, // CS_N hold time
tCLD = 25; // Clock delay time
`else
`ifdef TEMP_EXTENDED
specparam
tHI = 32, // Clock high time
tLO = 32, // Clock low time
tSU = 10, // Data setup time
tHD = 10, // Data hold time
tHS = 10, // HOLD_N setup time
tHH = 10, // HOLD_N hold time
tCSD = 32, // CS_N disable time
tCSS = 32, // CS_N setup time
tCSH = 50, // CS_N hold time
tCLD = 32; // Clock delay time
`else
specparam
tHI = 25, // Clock high time
tLO = 25, // Clock low time
tSU = 10, // Data setup time
tHD = 10, // Data hold time
tHS = 10, // HOLD_N setup time
tHH = 10, // HOLD_N hold time
tCSD = 25, // CS_N disable time
tCSS = 25, // CS_N setup time
tCSH = 50, // CS_N hold time
tCLD = 25; // Clock delay time
`endif
`endif
$width (posedge SCK, tHI);
$width (negedge SCK, tLO);
$width (posedge CS_N, tCSD);
$setup (negedge CS_N, posedge SCK &&& TimingCheckEnable, tCSS);
$setup (posedge CS_N, posedge SCK &&& TimingCheckEnable, tCLD);
$hold (posedge SCK &&& TimingCheckEnable, posedge CS_N, tCSH);
// SPI-specific timing checks
$setup (SI_SIO0, posedge SCK &&& SPITimingCheckEnable, tSU);
$setup (negedge SCK, negedge HOLD_N_SIO3 &&& SPITimingCheckEnable, tHS);
$hold (posedge SCK &&& SPITimingCheckEnable, SI_SIO0, tHD);
$hold (posedge HOLD_N_SIO3 &&& SPITimingCheckEnable, posedge SCK, tHH);
// SDI-specific timing checks
$setup (SI_SIO0, posedge SCK &&& SDITimingCheckEnable, tSU);
$setup (SO_SIO1, posedge SCK &&& SDITimingCheckEnable, tSU);
$hold (posedge SCK &&& SDITimingCheckEnable, SI_SIO0, tHD);
$hold (posedge SCK &&& SDITimingCheckEnable, SO_SIO1, tHD);
// SQI-specific timing checks
$setup (SI_SIO0, posedge SCK &&& SQITimingCheckEnable, tSU);
$setup (SO_SIO1, posedge SCK &&& SQITimingCheckEnable, tSU);
$setup (SIO2, posedge SCK &&& SQITimingCheckEnable, tSU);
$setup (HOLD_N_SIO3, posedge SCK &&& SQITimingCheckEnable, tSU);
$hold (posedge SCK &&& SQITimingCheckEnable, SI_SIO0, tHD);
$hold (posedge SCK &&& SQITimingCheckEnable, SO_SIO1, tHD);
$hold (posedge SCK &&& SQITimingCheckEnable, SIO2, tHD);
$hold (posedge SCK &&& SQITimingCheckEnable, HOLD_N_SIO3, tHD);
endspecify
endmodule