DV update
diff --git a/verilog/dv/caravel/user_proj_example/23LC512.v b/verilog/dv/caravel/user_proj_example/23LC512.v
new file mode 100644
index 0000000..fcff5b5
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/23LC512.v
@@ -0,0 +1,627 @@
+// *******************************************************************************************************
+// ** **
+// ** 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
\ No newline at end of file
diff --git a/verilog/dv/caravel/user_proj_example/24LC16B.v b/verilog/dv/caravel/user_proj_example/24LC16B.v
new file mode 100644
index 0000000..786243e
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/24LC16B.v
@@ -0,0 +1,633 @@
+// *******************************************************************************************************
+// ** **
+// ** 24LC16B.v - Microchip 24LC16B 16K-BIT I2C SERIAL EEPROM (VCC = +2.5V TO +5.5V) **
+// ** **
+// *******************************************************************************************************
+// ** **
+// ** This information is distributed under license from Young Engineering. **
+// ** COPYRIGHT (c) 2003 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 : 12/04/2006 **
+// ** Revision History: **
+// ** **
+// ** 12/04/2006: Initial design **
+// ** **
+// *******************************************************************************************************
+// ** TABLE OF CONTENTS **
+// *******************************************************************************************************
+// **---------------------------------------------------------------------------------------------------**
+// ** DECLARATIONS **
+// **---------------------------------------------------------------------------------------------------**
+// **---------------------------------------------------------------------------------------------------**
+// ** INITIALIZATION **
+// **---------------------------------------------------------------------------------------------------**
+// **---------------------------------------------------------------------------------------------------**
+// ** CORE LOGIC **
+// **---------------------------------------------------------------------------------------------------**
+// ** 1.01: START Bit Detection **
+// ** 1.02: STOP Bit Detection **
+// ** 1.03: Input Shift Register **
+// ** 1.04: Input Bit Counter **
+// ** 1.05: Control Byte Register **
+// ** 1.06: Byte Address Register **
+// ** 1.07: Write Data Buffer **
+// ** 1.08: Acknowledge Generator **
+// ** 1.09: Acknowledge Detect **
+// ** 1.10: Write Cycle Timer **
+// ** 1.11: Write Cycle Processor **
+// ** 1.12: Read Data Multiplexor **
+// ** 1.13: Read Data Processor **
+// ** 1.14: SDA Data I/O Buffer **
+// ** **
+// **---------------------------------------------------------------------------------------------------**
+// ** DEBUG LOGIC **
+// **---------------------------------------------------------------------------------------------------**
+// ** 2.01: Memory Data Bytes **
+// ** 2.02: Write Data Buffer **
+// ** **
+// **---------------------------------------------------------------------------------------------------**
+// ** TIMING CHECKS **
+// **---------------------------------------------------------------------------------------------------**
+// ** **
+// *******************************************************************************************************
+
+
+`timescale 1ns/10ps
+
+module M24LC16B (A0, A1, A2, WP, SDA, SCL, RESET);
+
+ input A0; // unconnected pin
+ input A1; // unconnected pin
+ input A2; // unconnected pin
+
+ input WP; // write protect pin
+
+ inout SDA; // serial data I/O
+ input SCL; // serial data clock
+
+ input RESET; // system reset
+
+
+// *******************************************************************************************************
+// ** DECLARATIONS **
+// *******************************************************************************************************
+
+ reg SDA_DO; // serial data - output
+ reg SDA_OE; // serial data - output enable
+
+ wire SDA_DriveEnable; // serial data output enable
+ reg SDA_DriveEnableDlyd; // serial data output enable - delayed
+
+ reg [03:00] BitCounter; // serial bit counter
+
+ reg START_Rcvd; // START bit received flag
+ reg STOP_Rcvd; // STOP bit received flag
+ reg CTRL_Rcvd; // control byte received flag
+ reg ADDR_Rcvd; // byte address received flag
+ reg MACK_Rcvd; // master acknowledge received flag
+
+ reg WrCycle; // memory write cycle
+ reg RdCycle; // memory read cycle
+
+ reg [07:00] ShiftRegister; // input data shift register
+
+ reg [07:00] ControlByte; // control byte register
+ wire [02:00] BlockSelect; // memory block select
+ wire RdWrBit; // read/write control bit
+
+ reg [10:00] StartAddress; // memory access starting address
+ reg [03:00] PageAddress; // memory page address
+
+ reg [07:00] WrDataByte [0:15]; // memory write data buffer
+ wire [07:00] RdDataByte; // memory read data
+
+ reg [15:00] WrCounter; // write buffer counter
+
+ reg [03:00] WrPointer; // write buffer pointer
+ reg [10:00] RdPointer; // read address pointer
+
+ reg WriteActive; // memory write cycle active
+
+ reg [07:00] MemoryBlock0 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock1 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock2 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock3 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock4 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock5 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock6 [0:255]; // EEPROM data memory array
+ reg [07:00] MemoryBlock7 [0:255]; // EEPROM data memory array
+
+ integer LoopIndex; // iterative loop index
+
+ integer tAA; // timing parameter
+ integer tWC; // timing parameter
+
+
+// *******************************************************************************************************
+// ** INITIALIZATION **
+// *******************************************************************************************************
+
+ initial tAA = 900; // SCL to SDA output delay
+ initial tWC = 5_000;//5_000_000; // memory write cycle time // updated for SoC simulation
+
+ initial begin
+ SDA_DO = 0;
+ SDA_OE = 0;
+ end
+
+ initial begin
+ START_Rcvd = 0;
+ STOP_Rcvd = 0;
+ CTRL_Rcvd = 0;
+ ADDR_Rcvd = 0;
+ MACK_Rcvd = 0;
+ end
+
+ initial begin
+ BitCounter = 0;
+ ControlByte = 0;
+ end
+
+ initial begin
+ WrCycle = 0;
+ RdCycle = 0;
+
+ WriteActive = 0;
+ end
+
+
+// *******************************************************************************************************
+// ** CORE LOGIC **
+// *******************************************************************************************************
+// -------------------------------------------------------------------------------------------------------
+// 1.01: START Bit Detection
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SDA) begin
+ if (SCL == 1) begin
+ START_Rcvd <= 1;
+ STOP_Rcvd <= 0;
+ CTRL_Rcvd <= 0;
+ ADDR_Rcvd <= 0;
+ MACK_Rcvd <= 0;
+
+ WrCycle <= #1 0;
+ RdCycle <= #1 0;
+
+ BitCounter <= 0;
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.02: STOP Bit Detection
+// -------------------------------------------------------------------------------------------------------
+
+ always @(posedge SDA) begin
+ if (SCL == 1) begin
+ START_Rcvd <= 0;
+ STOP_Rcvd <= 1;
+ CTRL_Rcvd <= 0;
+ ADDR_Rcvd <= 0;
+ MACK_Rcvd <= 0;
+
+ WrCycle <= #1 0;
+ RdCycle <= #1 0;
+
+ BitCounter <= 10;
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.03: Input Shift Register
+// -------------------------------------------------------------------------------------------------------
+
+ always @(posedge SCL) begin
+ ShiftRegister[00] <= SDA;
+ ShiftRegister[01] <= ShiftRegister[00];
+ ShiftRegister[02] <= ShiftRegister[01];
+ ShiftRegister[03] <= ShiftRegister[02];
+ ShiftRegister[04] <= ShiftRegister[03];
+ ShiftRegister[05] <= ShiftRegister[04];
+ ShiftRegister[06] <= ShiftRegister[05];
+ ShiftRegister[07] <= ShiftRegister[06];
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.04: Input Bit Counter
+// -------------------------------------------------------------------------------------------------------
+
+ always @(posedge SCL) begin
+ if (BitCounter < 10) BitCounter <= BitCounter + 1;
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.05: Control Byte Register
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SCL) begin
+ if (START_Rcvd & (BitCounter == 8)) begin
+ if (!WriteActive & (ShiftRegister[07:04] == 4'b1010)) begin
+ if (ShiftRegister[00] == 0) WrCycle <= 1;
+ if (ShiftRegister[00] == 1) RdCycle <= 1;
+
+ ControlByte <= ShiftRegister[07:00];
+
+ CTRL_Rcvd <= 1;
+ end
+
+ START_Rcvd <= 0;
+ end
+ end
+
+ assign BlockSelect = ControlByte[03:01];
+ assign RdWrBit = ControlByte[00];
+
+// -------------------------------------------------------------------------------------------------------
+// 1.06: Byte Address Register
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SCL) begin
+ if (CTRL_Rcvd & (BitCounter == 8)) begin
+ if (RdWrBit == 0) begin
+ StartAddress <= {BlockSelect[02:00],ShiftRegister[07:00]};
+ RdPointer <= {BlockSelect[02:00],ShiftRegister[07:00]};
+
+ ADDR_Rcvd <= 1;
+ end
+
+ WrCounter <= 0;
+ WrPointer <= 0;
+
+ CTRL_Rcvd <= 0;
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.07: Write Data Buffer
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SCL) begin
+ if (ADDR_Rcvd & (BitCounter == 8)) begin
+ if ((WP == 0) & (RdWrBit == 0)) begin
+ WrDataByte[WrPointer] <= ShiftRegister[07:00];
+
+ WrCounter <= WrCounter + 1;
+ WrPointer <= WrPointer + 1;
+ end
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.08: Acknowledge Generator
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SCL) begin
+ if (!WriteActive) begin
+ if (BitCounter == 8) begin
+ if (WrCycle | (START_Rcvd & (ShiftRegister[07:04] == 4'b1010))) begin
+ SDA_DO <= 0;
+ SDA_OE <= 1;
+ end
+ end
+ if (BitCounter == 9) begin
+ BitCounter <= 0;
+
+ if (!RdCycle) begin
+ SDA_DO <= 0;
+ SDA_OE <= 0;
+ end
+ end
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.09: Acknowledge Detect
+// -------------------------------------------------------------------------------------------------------
+
+ always @(posedge SCL) begin
+ if (RdCycle & (BitCounter == 8)) begin
+ if ((SDA == 0) & (SDA_OE == 0)) MACK_Rcvd <= 1;
+ end
+ end
+
+ always @(negedge SCL) MACK_Rcvd <= 0;
+
+// -------------------------------------------------------------------------------------------------------
+// 1.10: Write Cycle Timer
+// -------------------------------------------------------------------------------------------------------
+
+ always @(posedge STOP_Rcvd) begin
+ if (WrCycle & (WP == 0) & (WrCounter > 0)) begin
+ WriteActive = 1;
+ #(tWC);
+ WriteActive = 0;
+ end
+ end
+
+ always @(posedge STOP_Rcvd) begin
+ #(1.0);
+ STOP_Rcvd = 0;
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.11: Write Cycle Processor
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge WriteActive) begin
+ for (LoopIndex = 0; LoopIndex < WrCounter; LoopIndex = LoopIndex + 1) begin
+ PageAddress = StartAddress[03:00] + LoopIndex;
+
+ case (StartAddress[10:08])
+ 3'b000 : MemoryBlock0[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b001 : MemoryBlock1[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b010 : MemoryBlock2[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b011 : MemoryBlock3[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b100 : MemoryBlock4[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b101 : MemoryBlock5[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b110 : MemoryBlock6[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ 3'b111 : MemoryBlock7[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
+ endcase
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.12: Read Data Multiplexor
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SCL) begin
+ if (BitCounter == 8) begin
+ if (WrCycle & ADDR_Rcvd) begin
+ RdPointer <= StartAddress + WrPointer + 1;
+ end
+ if (RdCycle) begin
+ RdPointer <= RdPointer + 1;
+ end
+ end
+ end
+
+ assign RdDataByte = {8{(RdPointer[10:08] == 0)}} & MemoryBlock0[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 1)}} & MemoryBlock1[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 2)}} & MemoryBlock2[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 3)}} & MemoryBlock3[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 4)}} & MemoryBlock4[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 5)}} & MemoryBlock5[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 6)}} & MemoryBlock6[RdPointer[07:00]]
+ | {8{(RdPointer[10:08] == 7)}} & MemoryBlock7[RdPointer[07:00]];
+
+// -------------------------------------------------------------------------------------------------------
+// 1.13: Read Data Processor
+// -------------------------------------------------------------------------------------------------------
+
+ always @(negedge SCL) begin
+ if (RdCycle) begin
+ if (BitCounter == 8) begin
+ SDA_DO <= 0;
+ SDA_OE <= 0;
+ end
+ else if (BitCounter == 9) begin
+ SDA_DO <= RdDataByte[07];
+
+ if (MACK_Rcvd) SDA_OE <= 1;
+ end
+ else begin
+ SDA_DO <= RdDataByte[7-BitCounter];
+ end
+ end
+ end
+
+// -------------------------------------------------------------------------------------------------------
+// 1.14: SDA Data I/O Buffer
+// -------------------------------------------------------------------------------------------------------
+
+ bufif1 (SDA, 1'b0, SDA_DriveEnableDlyd);
+
+ assign SDA_DriveEnable = !SDA_DO & SDA_OE;
+ always @(SDA_DriveEnable) SDA_DriveEnableDlyd <= #(tAA) SDA_DriveEnable;
+
+
+// *******************************************************************************************************
+// ** DEBUG LOGIC **
+// *******************************************************************************************************
+// -------------------------------------------------------------------------------------------------------
+// 2.01: Memory Data Bytes
+// -------------------------------------------------------------------------------------------------------
+
+ wire [07:00] MemoryByte0_00 = MemoryBlock0[00];
+ wire [07:00] MemoryByte0_01 = MemoryBlock0[01];
+ wire [07:00] MemoryByte0_02 = MemoryBlock0[02];
+ wire [07:00] MemoryByte0_03 = MemoryBlock0[03];
+ wire [07:00] MemoryByte0_04 = MemoryBlock0[04];
+ wire [07:00] MemoryByte0_05 = MemoryBlock0[05];
+ wire [07:00] MemoryByte0_06 = MemoryBlock0[06];
+ wire [07:00] MemoryByte0_07 = MemoryBlock0[07];
+
+ wire [07:00] MemoryByte0_08 = MemoryBlock0[08];
+ wire [07:00] MemoryByte0_09 = MemoryBlock0[09];
+ wire [07:00] MemoryByte0_0A = MemoryBlock0[10];
+ wire [07:00] MemoryByte0_0B = MemoryBlock0[11];
+ wire [07:00] MemoryByte0_0C = MemoryBlock0[12];
+ wire [07:00] MemoryByte0_0D = MemoryBlock0[13];
+ wire [07:00] MemoryByte0_0E = MemoryBlock0[14];
+ wire [07:00] MemoryByte0_0F = MemoryBlock0[15];
+
+ wire [07:00] MemoryByte1_00 = MemoryBlock1[00];
+ wire [07:00] MemoryByte1_01 = MemoryBlock1[01];
+ wire [07:00] MemoryByte1_02 = MemoryBlock1[02];
+ wire [07:00] MemoryByte1_03 = MemoryBlock1[03];
+ wire [07:00] MemoryByte1_04 = MemoryBlock1[04];
+ wire [07:00] MemoryByte1_05 = MemoryBlock1[05];
+ wire [07:00] MemoryByte1_06 = MemoryBlock1[06];
+ wire [07:00] MemoryByte1_07 = MemoryBlock1[07];
+
+ wire [07:00] MemoryByte1_08 = MemoryBlock1[08];
+ wire [07:00] MemoryByte1_09 = MemoryBlock1[09];
+ wire [07:00] MemoryByte1_0A = MemoryBlock1[10];
+ wire [07:00] MemoryByte1_0B = MemoryBlock1[11];
+ wire [07:00] MemoryByte1_0C = MemoryBlock1[12];
+ wire [07:00] MemoryByte1_0D = MemoryBlock1[13];
+ wire [07:00] MemoryByte1_0E = MemoryBlock1[14];
+ wire [07:00] MemoryByte1_0F = MemoryBlock1[15];
+
+ wire [07:00] MemoryByte2_00 = MemoryBlock2[00];
+ wire [07:00] MemoryByte2_01 = MemoryBlock2[01];
+ wire [07:00] MemoryByte2_02 = MemoryBlock2[02];
+ wire [07:00] MemoryByte2_03 = MemoryBlock2[03];
+ wire [07:00] MemoryByte2_04 = MemoryBlock2[04];
+ wire [07:00] MemoryByte2_05 = MemoryBlock2[05];
+ wire [07:00] MemoryByte2_06 = MemoryBlock2[06];
+ wire [07:00] MemoryByte2_07 = MemoryBlock2[07];
+
+ wire [07:00] MemoryByte2_08 = MemoryBlock2[08];
+ wire [07:00] MemoryByte2_09 = MemoryBlock2[09];
+ wire [07:00] MemoryByte2_0A = MemoryBlock2[10];
+ wire [07:00] MemoryByte2_0B = MemoryBlock2[11];
+ wire [07:00] MemoryByte2_0C = MemoryBlock2[12];
+ wire [07:00] MemoryByte2_0D = MemoryBlock2[13];
+ wire [07:00] MemoryByte2_0E = MemoryBlock2[14];
+ wire [07:00] MemoryByte2_0F = MemoryBlock2[15];
+
+ wire [07:00] MemoryByte3_00 = MemoryBlock3[00];
+ wire [07:00] MemoryByte3_01 = MemoryBlock3[01];
+ wire [07:00] MemoryByte3_02 = MemoryBlock3[02];
+ wire [07:00] MemoryByte3_03 = MemoryBlock3[03];
+ wire [07:00] MemoryByte3_04 = MemoryBlock3[04];
+ wire [07:00] MemoryByte3_05 = MemoryBlock3[05];
+ wire [07:00] MemoryByte3_06 = MemoryBlock3[06];
+ wire [07:00] MemoryByte3_07 = MemoryBlock3[07];
+
+ wire [07:00] MemoryByte3_08 = MemoryBlock3[08];
+ wire [07:00] MemoryByte3_09 = MemoryBlock3[09];
+ wire [07:00] MemoryByte3_0A = MemoryBlock3[10];
+ wire [07:00] MemoryByte3_0B = MemoryBlock3[11];
+ wire [07:00] MemoryByte3_0C = MemoryBlock3[12];
+ wire [07:00] MemoryByte3_0D = MemoryBlock3[13];
+ wire [07:00] MemoryByte3_0E = MemoryBlock3[14];
+ wire [07:00] MemoryByte3_0F = MemoryBlock3[15];
+
+ wire [07:00] MemoryByte4_00 = MemoryBlock4[00];
+ wire [07:00] MemoryByte4_01 = MemoryBlock4[01];
+ wire [07:00] MemoryByte4_02 = MemoryBlock4[02];
+ wire [07:00] MemoryByte4_03 = MemoryBlock4[03];
+ wire [07:00] MemoryByte4_04 = MemoryBlock4[04];
+ wire [07:00] MemoryByte4_05 = MemoryBlock4[05];
+ wire [07:00] MemoryByte4_06 = MemoryBlock4[06];
+ wire [07:00] MemoryByte4_07 = MemoryBlock4[07];
+
+ wire [07:00] MemoryByte4_08 = MemoryBlock4[08];
+ wire [07:00] MemoryByte4_09 = MemoryBlock4[09];
+ wire [07:00] MemoryByte4_0A = MemoryBlock4[10];
+ wire [07:00] MemoryByte4_0B = MemoryBlock4[11];
+ wire [07:00] MemoryByte4_0C = MemoryBlock4[12];
+ wire [07:00] MemoryByte4_0D = MemoryBlock4[13];
+ wire [07:00] MemoryByte4_0E = MemoryBlock4[14];
+ wire [07:00] MemoryByte4_0F = MemoryBlock4[15];
+
+ wire [07:00] MemoryByte5_00 = MemoryBlock5[00];
+ wire [07:00] MemoryByte5_01 = MemoryBlock5[01];
+ wire [07:00] MemoryByte5_02 = MemoryBlock5[02];
+ wire [07:00] MemoryByte5_03 = MemoryBlock5[03];
+ wire [07:00] MemoryByte5_04 = MemoryBlock5[04];
+ wire [07:00] MemoryByte5_05 = MemoryBlock5[05];
+ wire [07:00] MemoryByte5_06 = MemoryBlock5[06];
+ wire [07:00] MemoryByte5_07 = MemoryBlock5[07];
+
+ wire [07:00] MemoryByte5_08 = MemoryBlock5[08];
+ wire [07:00] MemoryByte5_09 = MemoryBlock5[09];
+ wire [07:00] MemoryByte5_0A = MemoryBlock5[10];
+ wire [07:00] MemoryByte5_0B = MemoryBlock5[11];
+ wire [07:00] MemoryByte5_0C = MemoryBlock5[12];
+ wire [07:00] MemoryByte5_0D = MemoryBlock5[13];
+ wire [07:00] MemoryByte5_0E = MemoryBlock5[14];
+ wire [07:00] MemoryByte5_0F = MemoryBlock5[15];
+
+ wire [07:00] MemoryByte6_00 = MemoryBlock6[00];
+ wire [07:00] MemoryByte6_01 = MemoryBlock6[01];
+ wire [07:00] MemoryByte6_02 = MemoryBlock6[02];
+ wire [07:00] MemoryByte6_03 = MemoryBlock6[03];
+ wire [07:00] MemoryByte6_04 = MemoryBlock6[04];
+ wire [07:00] MemoryByte6_05 = MemoryBlock6[05];
+ wire [07:00] MemoryByte6_06 = MemoryBlock6[06];
+ wire [07:00] MemoryByte6_07 = MemoryBlock6[07];
+
+ wire [07:00] MemoryByte6_08 = MemoryBlock6[08];
+ wire [07:00] MemoryByte6_09 = MemoryBlock6[09];
+ wire [07:00] MemoryByte6_0A = MemoryBlock6[10];
+ wire [07:00] MemoryByte6_0B = MemoryBlock6[11];
+ wire [07:00] MemoryByte6_0C = MemoryBlock6[12];
+ wire [07:00] MemoryByte6_0D = MemoryBlock6[13];
+ wire [07:00] MemoryByte6_0E = MemoryBlock6[14];
+ wire [07:00] MemoryByte6_0F = MemoryBlock6[15];
+
+ wire [07:00] MemoryByte7_00 = MemoryBlock7[00];
+ wire [07:00] MemoryByte7_01 = MemoryBlock7[01];
+ wire [07:00] MemoryByte7_02 = MemoryBlock7[02];
+ wire [07:00] MemoryByte7_03 = MemoryBlock7[03];
+ wire [07:00] MemoryByte7_04 = MemoryBlock7[04];
+ wire [07:00] MemoryByte7_05 = MemoryBlock7[05];
+ wire [07:00] MemoryByte7_06 = MemoryBlock7[06];
+ wire [07:00] MemoryByte7_07 = MemoryBlock7[07];
+
+ wire [07:00] MemoryByte7_08 = MemoryBlock7[08];
+ wire [07:00] MemoryByte7_09 = MemoryBlock7[09];
+ wire [07:00] MemoryByte7_0A = MemoryBlock7[10];
+ wire [07:00] MemoryByte7_0B = MemoryBlock7[11];
+ wire [07:00] MemoryByte7_0C = MemoryBlock7[12];
+ wire [07:00] MemoryByte7_0D = MemoryBlock7[13];
+ wire [07:00] MemoryByte7_0E = MemoryBlock7[14];
+ wire [07:00] MemoryByte7_0F = MemoryBlock7[15];
+
+// -------------------------------------------------------------------------------------------------------
+// 2.02: Write Data Buffer
+// -------------------------------------------------------------------------------------------------------
+
+ wire [07:00] WriteData_0 = WrDataByte[00];
+ wire [07:00] WriteData_1 = WrDataByte[01];
+ wire [07:00] WriteData_2 = WrDataByte[02];
+ wire [07:00] WriteData_3 = WrDataByte[03];
+ wire [07:00] WriteData_4 = WrDataByte[04];
+ wire [07:00] WriteData_5 = WrDataByte[05];
+ wire [07:00] WriteData_6 = WrDataByte[06];
+ wire [07:00] WriteData_7 = WrDataByte[07];
+ wire [07:00] WriteData_8 = WrDataByte[08];
+ wire [07:00] WriteData_9 = WrDataByte[09];
+ wire [07:00] WriteData_A = WrDataByte[10];
+ wire [07:00] WriteData_B = WrDataByte[11];
+ wire [07:00] WriteData_C = WrDataByte[12];
+ wire [07:00] WriteData_D = WrDataByte[13];
+ wire [07:00] WriteData_E = WrDataByte[14];
+ wire [07:00] WriteData_F = WrDataByte[15];
+
+
+// *******************************************************************************************************
+// ** TIMING CHECKS **
+// *******************************************************************************************************
+
+ wire TimingCheckEnable = (RESET == 0) & (SDA_OE == 0);
+
+ specify
+ specparam
+ tHI = 600, // SCL pulse width - high
+ tLO = 1300, // SCL pulse width - low
+ tSU_STA = 600, // SCL to SDA setup time
+ tHD_STA = 600, // SCL to SDA hold time
+ tSU_DAT = 100, // SDA to SCL setup time
+ tSU_STO = 600, // SCL to SDA setup time
+ tBUF = 1300; // Bus free time
+
+ $width (posedge SCL, tHI);
+ $width (negedge SCL, tLO);
+
+ $width (posedge SDA &&& SCL, tBUF);
+
+ $setup (posedge SCL, negedge SDA &&& TimingCheckEnable, tSU_STA);
+ $setup (SDA, posedge SCL &&& TimingCheckEnable, tSU_DAT);
+ $setup (posedge SCL, posedge SDA &&& TimingCheckEnable, tSU_STO);
+
+ $hold (negedge SDA &&& TimingCheckEnable, negedge SCL, tHD_STA);
+ endspecify
+
+endmodule
diff --git a/verilog/dv/caravel/user_proj_example/DFFRAM_beh.v b/verilog/dv/caravel/user_proj_example/DFFRAM_beh.v
new file mode 100644
index 0000000..3ef1c4e
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/DFFRAM_beh.v
@@ -0,0 +1,41 @@
+module DFFRAM_beh #( parameter COLS=1)
+(
+`ifdef USE_POWER_PINS
+ VPWR,
+ VGND,
+ `endif
+ CLK,
+ WE,
+ EN,
+ Di,
+ Do,
+ A
+);
+ localparam A_WIDTH = 8+$clog2(COLS);
+
+`ifdef USE_POWER_PINS
+ input VPWR;
+ input VGND;
+ `endif
+
+ input wire CLK;
+ input wire [3:0] WE;
+ input wire EN;
+ input wire [31:0] Di;
+ output reg [31:0] Do;
+ input wire [(A_WIDTH - 1): 0] A;
+
+ reg [31:0] RAM[(256*COLS)-1 : 0];
+
+ always @(posedge CLK)
+ if(EN) begin
+ Do <= RAM[A];
+ if(WE[0]) RAM[A][ 7: 0] <= Di[7:0];
+ if(WE[1]) RAM[A][15:8] <= Di[15:8];
+ if(WE[2]) RAM[A][23:16] <= Di[23:16];
+ if(WE[3]) RAM[A][31:24] <= Di[31:24];
+ end
+ else
+ Do <= 32'b0;
+
+endmodule
diff --git a/verilog/dv/caravel/user_proj_example/io_ports/Makefile b/verilog/dv/caravel/user_proj_example/io_ports/Makefile
index d6c2bf6..9b5a8d4 100644
--- a/verilog/dv/caravel/user_proj_example/io_ports/Makefile
+++ b/verilog/dv/caravel/user_proj_example/io_ports/Makefile
@@ -34,14 +34,14 @@
hex: ${PATTERN:=.hex}
-%.vvp: %_tb.v %.hex
+%.vvp: %_tb.v %.hex test.hex
ifeq ($(SIM),RTL)
- iverilog -DFUNCTIONAL -DSIM -I $(BEHAVIOURAL_MODELS) \
- -I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+ iverilog -DFUNCTIONAL -DSIM -DFAST -DUSE_POWER_PINS -I $(BEHAVIOURAL_MODELS) \
+ -I $(PDK_PATH) -I .. -I $(RTL_PATH) \
$< -o $@
else
- iverilog -DFUNCTIONAL -DSIM -DGL -I $(BEHAVIOURAL_MODELS) \
- -I $(PDK_PATH) -I $(IP_PATH) -I $(RTL_PATH) \
+ iverilog -DFUNCTIONAL -DSIM -DUSE_POWER_PINS -DGL_UA -I $(BEHAVIOURAL_MODELS) \
+ -I $(PDK_PATH) -I .. -I $(VERILOG_PATH) -I $(RTL_PATH) \
$< -o $@
endif
@@ -56,6 +56,9 @@
# to fix flash base address
sed -i 's/@10000000/@00000000/g' $@
+test.hex: ../sw/test.c ../sw/crt0.S ../sw/link.ld
+ $(MAKE) -C ../sw/ all
+
%.bin: %.elf
${GCC_PATH}/${GCC_PREFIX}-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
@@ -63,5 +66,5 @@
clean:
rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
-
+ rm -f ../sw/*.bin ../sw/*.hex ../sw/*.elf ../sw/*.lst
.PHONY: clean hex all
diff --git a/verilog/dv/caravel/user_proj_example/io_ports/io_ports.c b/verilog/dv/caravel/user_proj_example/io_ports/io_ports.c
index a159f0a..52c5980 100644
--- a/verilog/dv/caravel/user_proj_example/io_ports/io_ports.c
+++ b/verilog/dv/caravel/user_proj_example/io_ports/io_ports.c
@@ -41,20 +41,78 @@
*/
- // Configure lower 8-IOs as user output
- // Observe counter value in the testbench
- reg_mprj_io_0 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_1 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_2 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_3 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_4 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_5 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_6 = GPIO_MODE_USER_STD_OUTPUT;
- reg_mprj_io_7 = GPIO_MODE_USER_STD_OUTPUT;
+ // GPIOs
+ reg_mprj_io_0 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_1 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_2 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_3 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_4 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_5 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_6 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_7 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
- /* Apply configuration */
- reg_mprj_xfer = 1;
- while (reg_mprj_xfer == 1);
+ reg_mprj_io_8 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_9 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_10 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_11 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_12 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_13 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+
+ // Flash
+ reg_mprj_io_14 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_15 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_16 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_17 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+
+ // Flash CLK and Enable
+ reg_mprj_io_18 = GPIO_MODE_USER_STD_OUTPUT;
+ reg_mprj_io_19 = GPIO_MODE_USER_STD_OUTPUT;
+
+ // UART 0
+ reg_mprj_io_20 = GPIO_MODE_USER_STD_INPUT_NOPULL;
+ reg_mprj_io_21 = GPIO_MODE_USER_STD_OUTPUT;
+
+ // UART 1
+ reg_mprj_io_22 = GPIO_MODE_USER_STD_INPUT_NOPULL;
+ reg_mprj_io_23 = GPIO_MODE_USER_STD_OUTPUT;
+
+ // SPI0
+ reg_mprj_io_24 = GPIO_MODE_USER_STD_INPUT_NOPULL;
+ reg_mprj_io_25 = GPIO_MODE_USER_STD_OUTPUT;
+ reg_mprj_io_26 = GPIO_MODE_USER_STD_OUTPUT;
+ reg_mprj_io_27 = GPIO_MODE_USER_STD_OUTPUT;
+
+ // SPI1
+ reg_mprj_io_28 = GPIO_MODE_USER_STD_INPUT_NOPULL;
+ reg_mprj_io_29 = GPIO_MODE_USER_STD_OUTPUT;
+ reg_mprj_io_30 = GPIO_MODE_USER_STD_OUTPUT;
+ reg_mprj_io_31 = GPIO_MODE_USER_STD_OUTPUT;
+
+ // I2C0
+ reg_mprj_io_32 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_33 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+
+ // I2C1
+ reg_mprj_io_34 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+ reg_mprj_io_35 = GPIO_MODE_USER_STD_BIDIRECTIONAL;
+
+ // PWM
+ reg_mprj_io_36 = GPIO_MODE_USER_STD_OUTPUT;
+ reg_mprj_io_37 = GPIO_MODE_USER_STD_OUTPUT;
+
+ /* Apply configuration */
+ reg_mprj_xfer = 1;
+ while (reg_mprj_xfer == 1);
+
+ // Logic probes: configure LA[9:0] as outputs from the mgmt area
+ /*
+ LA | EL2
+
+ la[1] | NMI | 1'b0
+ la[0] | HResetn | 1'b1
+ */
+ reg_la0_ena = 0x00000000;
+ reg_la0_data = 0x01;
}
diff --git a/verilog/dv/caravel/user_proj_example/io_ports/io_ports_tb.v b/verilog/dv/caravel/user_proj_example/io_ports/io_ports_tb.v
index c680a0b..0ce28f0 100644
--- a/verilog/dv/caravel/user_proj_example/io_ports/io_ports_tb.v
+++ b/verilog/dv/caravel/user_proj_example/io_ports/io_ports_tb.v
@@ -17,17 +17,85 @@
`timescale 1 ns / 1 ps
-`include "caravel.v"
+`define TEST_FILE "../sw/test.hex"
+`define SIM_TIME 1500_000
+`define SIM_LEVEL 0
+
+`define SOC_SETUP_TIME 800*2001
+
+`define NO_HC_CACHE
+
`include "spiflash.v"
+`include "sst26wf080b.v"
+`include "23LC512.v"
+`include "caravel.v"
+
+`ifdef SIM
+
+`ifdef FAST
+ `define USE_DFFRAM_BEH
+ `define NO_HC_CACHE
+ `include "DFFRAM_beh.v"
+`else
+ `ifndef GL_UA
+ `include "user_project/IPs/DFFRAM_4K.v"
+ `include "user_project/IPs/DFFRAMBB.v"
+ `include "user_project/IPs/DMC_32x16.v"
+ `endif
+`endif
+
+`ifdef GL_UA
+ `include "gl/user_project/gl/apb_sys_0.v"
+ `include "gl/user_project/gl/DFFRAM_4K.v"
+ `include "gl/user_project/gl/DMC_32x16.v"
+ `include "gl/user_project/gl/el2_swerv_wrapper.v"
+ `include "gl/user_project/gl/user_project_wrapper.v"
+`else
+
+`include "user_project/AHB_sys_0/AHBlite_sys_0.v"
+`include "user_project/AHB_sys_0/AHBlite_bus0.v"
+`include "user_project/AHB_sys_0/AHBlite_GPIO.v"
+`include "user_project/AHB_sys_0/AHBlite_db_reg.v"
+
+`include "user_project/AHB_sys_0/APB_sys_0/APB_WDT32.v"
+`include "user_project/AHB_sys_0/APB_sys_0/APB_TIMER32.v"
+`include "user_project/AHB_sys_0/APB_sys_0/APB_PWM32.v"
+`include "user_project/AHB_sys_0/APB_sys_0/AHB_2_APB.v"
+`include "user_project/AHB_sys_0/APB_sys_0/APB_bus0.v"
+`include "user_project/AHB_sys_0/APB_sys_0/APB_sys_0.v"
+
+`include "user_project/IPs/TIMER32.v"
+`include "user_project/IPs/PWM32.v"
+`include "user_project/IPs/WDT32.v"
+`include "user_project/IPs/spi_master.v"
+`include "user_project/IPs/i2c_master.v"
+`include "user_project/IPs/GPIO.v"
+`include "user_project/IPs/APB_UART.v"
+`include "user_project/IPs/APB_SPI.v"
+`include "user_project/IPs/APB_I2C.v"
+`include "user_project/IPs/AHBSRAM.v"
+`include "user_project/acc/AHB_SPM.v"
+
+`include "user_project/IPs/QSPI_XIP_CTRL.v"
+`include "user_project/IPs/DMC_32x16.v"
+`include "user_project/IPs/RAM_1024x32.v"
+
+`include "user_project/el2_n5_soc_wrapper.v"
+`include "user_project/el2.v"
+`include "user_project/soc_core.v"
+
+`endif
+`endif
+
module io_ports_tb;
reg clock;
- reg RSTB;
+ reg RSTB;
reg power1, power2;
reg power3, power4;
- wire gpio;
- wire [37:0] mprj_io;
+ wire gpio;
+ wire [37:0] mprj_io;
wire [7:0] mprj_io_0;
assign mprj_io_0 = mprj_io[7:0];
@@ -42,44 +110,70 @@
clock = 0;
end
+ // GPIO Loopback!
+ // wire [13:0] GPIO_PINS;
+ // generate
+ // genvar i;
+ // for(i=0; i<14; i=i+1)
+ // assign GPIO_PINS[i] = GPIOOEN_Sys0_S2[i] ? GPIOOUT_Sys0_S2[i] : 1'bz;
+ // endgenerate
+
+ // assign GPIO_PINS[15:8] = GPIO_PINS[7:0];
+ // assign GPIOIN_Sys0_S2 = GPIO_PINS;
+
+ // Serial Terminal connected to UART0 TX*/
+ terminal term(.rx(mprj_io[21])); // RsTx_Sys0_SS0_S0
+
+ // SPI SRAM connected to SPI0
+ wire SPI_HOLD = 1'b1;
+ M23LC512 SPI_SRAM(
+ .RESET(~RSTB),
+ .SO_SIO1(mprj_io[24]), // MSI_Sys0_SS0_S2
+ .SI_SIO0(mprj_io[25]), // MSO_Sys0_SS0_S2
+ .CS_N(mprj_io[26]), // SSn_Sys0_SS0_S2
+ .SCK(mprj_io[27]), // SCLK_Sys0_SS0_S2
+ .HOLD_N_SIO3(SPI_HOLD)
+ );
+
+ // I2C E2PROM connected to I2C0
+ wire scl, sda;
+ delay m0_scl (scl_oen_o_Sys0_SS0_S4 ? 1'bz : scl_o_Sys0_SS0_S4, scl),
+ m0_sda (sda_oen_o_Sys0_SS0_S4 ? 1'bz : sda_o_Sys0_SS0_S4, sda);
+
+ assign scl_i_Sys0_SS0_S4 = scl;
+ assign sda_i_Sys0_SS0_S4 = sda;
+
+ pullup p1(scl); // pullup scl line
+ pullup p2(sda); // pullup sda line
+
+ M24LC16B I2C_E2PROM(
+ .A0(1'b0),
+ .A1(1'b0),
+ .A2(1'b0),
+ .WP(1'b0),
+ .SDA(sda),
+ .SCL(scl),
+ .RESET(~HRESETn)
+ );
+
+ initial begin
+ // Load the application into the N5 flash memory
+ #1 $readmemh(`TEST_FILE, flash.I0.memory);
+ $display("---------N5 Flash -----------");
+ $display("Memory[0]: %0d, Memory[1]: %0d, Memory[2]: %0d, Memory[3]: %0d",
+ flash.I0.memory[0], flash.I0.memory[1], flash.I0.memory[2], flash.I0.memory[3]);
+ end
+
initial begin
$dumpfile("io_ports.vcd");
$dumpvars(0, io_ports_tb);
- // Repeat cycles of 1000 clock edges as needed to complete testbench
- repeat (25) begin
- repeat (1000) @(posedge clock);
- // $display("+1000 cycles");
- end
- $display("%c[1;31m",27);
- $display ("Monitor: Timeout, Test Mega-Project IO Ports (RTL) Failed");
- $display("%c[0m",27);
- $finish;
- end
-
- initial begin
- // Observe Output pins [7:0]
- wait(mprj_io_0 == 8'h01);
- wait(mprj_io_0 == 8'h02);
- wait(mprj_io_0 == 8'h03);
- wait(mprj_io_0 == 8'h04);
- wait(mprj_io_0 == 8'h05);
- wait(mprj_io_0 == 8'h06);
- wait(mprj_io_0 == 8'h07);
- wait(mprj_io_0 == 8'h08);
- wait(mprj_io_0 == 8'h09);
- wait(mprj_io_0 == 8'h0A);
- wait(mprj_io_0 == 8'hFF);
- wait(mprj_io_0 == 8'h00);
-
- $display("Monitor: Test 1 Mega-Project IO (RTL) Passed");
- $finish;
- end
-
- initial begin
RSTB <= 1'b0;
#2000;
RSTB <= 1'b1; // Release reset
+ #(`SOC_SETUP_TIME);
+ #(`SIM_TIME);
+ $finish;
end
initial begin // Power-up sequence
@@ -97,10 +191,6 @@
power4 <= 1'b1;
end
- always @(mprj_io) begin
- #1 $display("MPRJ-IO state = %b ", mprj_io[7:0]);
- end
-
wire flash_csb;
wire flash_clk;
wire flash_io0;
@@ -129,7 +219,7 @@
.vssd2 (VSS),
.clock (clock),
.gpio (gpio),
- .mprj_io (mprj_io),
+ .mprj_io (mprj_io),
.flash_csb(flash_csb),
.flash_clk(flash_clk),
.flash_io0(flash_io0),
@@ -148,5 +238,33 @@
.io3() // not used
);
+ /* N5 Flash */
+ sst26wf080b flash(
+ .SCK(mprj_io[18]), // fsclk
+ .SIO(mprj_io[17:14]), // fdo
+ .CEb(mprj_io[19]) // fcen
+ );
+
+endmodule
+
+module terminal #(parameter bit_time = 400) (input rx);
+
+ integer i;
+ reg [7:0] char;
+ initial begin
+ forever begin
+ @(negedge rx);
+ i = 0;
+ char = 0;
+ #(3*bit_time/2);
+ for(i=0; i<8; i=i+1) begin
+ char[i] = rx;
+ #bit_time;
+ end
+ $write("%c", char);
+ end
+ end
+
+
endmodule
`default_nettype wire
diff --git a/verilog/dv/caravel/user_proj_example/sst26wf080b.v b/verilog/dv/caravel/user_proj_example/sst26wf080b.v
new file mode 100755
index 0000000..895906a
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sst26wf080b.v
@@ -0,0 +1,2485 @@
+/*
+---------------------------------------------------------------------------
+ Proprietary & Confidental, All right reserved, 2013
+ Silicon Storage Technology, Inc.
+---------------------------------------------------------------------------
+Description : SQI Serial Flash Memory, SST26WF080B 1MB Memory
+Revision Status : 1.0
+---------------------------------------------------------------------------
+
+Important Notes Please Read
+---------------------------
+ (1) This model has several non-volatile memorys.
+ These bits are initalized at time 0 to the default values. To
+ load these memorys with customer data load them after time 0;
+ The below example loads the main flash memory from a file.
+ Example: initial #1 $readmemh(<path>.I0.memory,<file name>); // 080=1M, 016=2M, 032=4M, 064=8M bytes memory
+
+ (2) This model has several non-volatial bits in the status registers. If you want them
+ set to a different initial condition then edit this model defparam commands to
+ change the values.
+
+ (3) For simulation purposes the erase times can be shortened using the 'defparam' command
+ do not shorten to less than 1uS
+ Example: defparam <path>.I0.Tbe = 25_000; // reduce block erase time from 25mS to 25uS
+ Example: defparam <path>.I0.Tse = 25_000; // reduce sector erase time from 25mS to 25uS
+ Example: defparam <path>.I0.Tsce = 25_000; // reduce chip erase time from 50mS to 25uS
+ Example: defparam <path>.I0.Tpp = 25_000; // reduce page program time from 1.5mS to 25uS
+ Example: defparam <path>.I0.Tws = 1000; // reduce suspend to ready time from 10uS to 1uS
+
+ (4) On timing errors all of flash memory will be set to 'xx', timming errors are a fatal problem.
+
+ (5) Parameter MASK_ERRORS is used to inhibit corruption of memory on timing errors at the start of simulation.
+ This allows the unknows to be cleared before corrupting memory on timing checks. The default value is 500nS.
+ To change this value use defparam to increase it to the value you need.
+ Example: defparam <path>.MASK_ERRORS = 1000; // increase time to 1uS
+
+ (6) This model uses a common module for all the SST26VF***B family of products. This
+ module is appended to the top level module code. The module name is "sst26wfxxxb".
+ If more than 1 instance of the SST26VF*B family of products is placed in a design
+ there will be a syntact error that module sst26wfxxxb is defined more than once.
+ if this happens delete the sst26wfxx module definitions from all but one of the Verilog models.
+
+ (7) The below code is the definition of the non-volatile memory used in the chip.
+
+//---------------------------------------------------------------------------
+// Define non-volatile Memory
+//---------------------------------------------------------------------------
+reg [7:0] memory[Memsize-1:0]; // define Flash memory array, non-volitable
+reg [7:0] security_id[(Kilo*2)-1:0]; // Define secutity ID memory addr 0->7 are SST space the rest is user space, non-volitable
+reg [7:0] SFDP[(Kilo*2)-1:0]; // serial flash discoverable parameters
+reg [PROTECT_REG_MSB:0] wlldr_mem; // Define write-lock lock down reg, non-volitable
+reg WPEN; // bit 7 of config register, non-volitable
+reg SEC; // status[5] 1-bit Lockout Security ID, non-volitable
+
+
+
+------------------------------------------------------------------------------------
+ Pin Descriptions
+ Symbol Pin Name Type Function
+------- ------------ ------ -------------------------------------------
+ SCK Serial Clock input Provides clock to device
+ SIO[3:0] Serial Data I/O provide data input and output
+ CEb Chipenable input Active low chip enable
+------------------------------------------------------------------------------------
+*/
+
+`timescale 1ns / 10 ps
+module sst26wf080b(SCK,SIO,CEb);
+input SCK; // device clock
+input CEb; // chip enable active low
+inout [3:0] SIO; // serial 4-bit bus I/O
+reg [31:0] error_cnt; // count timing errors
+ parameter MASK_ERRORS=500; // mask any timing errors before this time
+
+ defparam I0.Ksize = 0; //Size of memory in Kilo bytes
+ defparam I0.Msize = 1; // Size of memory in Mega bites. I.E. 8-bit field size, use S080=1, S016=2, S032=4
+ defparam I0.ADDR_MSB=19; // most significant address bit, 32Mb=21,16Mb=20, 8Mb=19, 4Mb=18;
+ defparam I0.Memory_Capacity = 8'h58; // ID read memory size 32M=52,16M=51,8M=58, JEDEC read value
+ // change below values if you need non-default values on POR
+ defparam I0.WLLD_value = 32'h0000_0000; // init WLLD protection register non-volitale, default to all 0's
+ defparam I0.INIT_WPEN = 1'b0; // value of WPEN, configuration register bit 7 default on POR
+ defparam I0.SECURITY_LOCKOUT_VALUE=1'b0; // Value of SEC, status register bit 5 on POR
+
+ //--------------------------------------------------
+ // Place common sst26wfxxxB model
+ //--------------------------------------------------
+ sst26wfxxxb I0(SCK,SIO,CEb);
+
+ //--------------------------------------------------
+ // Timing checks
+ //--------------------------------------------------
+ wire HOLDb;
+ wire read_slow_flag;
+ wire read_dual_io_flag;
+ wire [3:0] Tds_inhibit;
+ reg notifer_Tsckh,notifer_Tsckl,notifier_Tces,notifier_Tceh,notifier_Tchs,notifier_Tchh;
+ reg notifier_Tcph,notifier_Tds;
+ reg notifier_Fclk;
+ reg notifier_Thls,notifier_Thhs,notifier_Thhh;
+ assign HOLDb = I0.HOLDb; // bring up lower level holdb net
+ assign read_slow_flag = I0.read_slow_flag; // slow timing on SPI read flag I.E. Read cmd '03h'
+ assign read_dual_io_flag = I0.SPI_SDIOR_active; // slow timing on SPI dual I/O read, i.e. cmd 'BBh'
+ assign Tds_inhibit[3] = I0.SIO_IO[3] | CEb; // i/o = input and CEb active
+ assign Tds_inhibit[2] = I0.SIO_IO[2] | CEb; // i/o = input and CEb active
+ assign Tds_inhibit[1] = I0.SIO_IO[1] | CEb; // i/o = input and CEb active
+ assign Tds_inhibit[0] = I0.SIO_IO[0] | CEb; // i/o = input and CEb active
+ specify
+ specparam CellType = "SST26WFxxx";
+
+ specparam Fclk_slow = 24.99; // Min serial clock period during '03h' Read command
+ specparam Tsckh_slow = 11.0; // Min serial clock high time 'SCK' during '03h' Read command
+ specparam Tsckl_slow = 11.0; // Min serial clock low time 'SCK' during '03h' Read command
+
+ specparam Fclk_dual_io = 12.49; // Min serial clock period during 'BBh' Read command
+ specparam Tsckh_dual_io = 5.5; // Min serial clock high time 'SCK' during 'BBh' Read command
+ specparam Tsckl_dual_io = 5.5; // Min serial clock low time 'SCK' during 'BBh' Read command
+
+ specparam Fclk = 9.59; // Min serial clock period
+ specparam Tsckh = 4.5; // Min serial clock high time 'SCK'
+ specparam Tsckl = 4.5; // Min serial clock low time 'SCK'
+ specparam Tces = 5; // CEb falling to SCK rising setup time
+ specparam Tceh = 5; // SCK rising to CEb rising hold time
+ specparam Tchs = 5; // CEb not active setup time
+ specparam Tchh = 5; // CEb not active hold time
+ specparam Tcph = 12.0; // Min CEb high time
+ specparam Tds = 3; // Data in setup time to SCK rising
+ specparam Tdh = 4; // Data in hold time to SCK rising
+ specparam Thls = 5.0; // HOLDb falling to SCK rising setup
+ specparam Thhs = 5.0; // HOLDb rising to SCK risinf setup
+ specparam Thhh = 5.0; // SCK to HOLDb hold time
+
+ // HOLDb timing tests
+ $setup(posedge SCK ,negedge HOLDb,Thls, notifier_Thls);
+ $setup(posedge SCK ,posedge HOLDb,Thhs, notifier_Thhs);
+ $hold (posedge SCK ,negedge HOLDb,Thhh, notifier_Thhh);
+
+
+ // 40Mhz, slow speed read timing checks opcode Read '03h' in SPI mode
+ $period(posedge SCK &&& read_slow_flag==1'b1 ,Fclk_slow,notifier_Fclk);
+ $period(negedge SCK &&& read_slow_flag==1'b1 ,Fclk_slow,notifier_Fclk);
+ $width(negedge SCK &&& read_slow_flag==1'b1,Tsckh_slow,0,notifer_Tsckh);
+ $width(posedge SCK &&& read_slow_flag==1'b1,Tsckl_slow,0,notifer_Tsckl);
+
+ // 80Mhz, read timing checks opcode Read 'BBh' in SPI mode
+ $period(posedge SCK &&& read_dual_io_flag==1'b1 ,Fclk_dual_io,notifier_Fclk);
+ $period(negedge SCK &&& read_dual_io_flag==1'b1 ,Fclk_dual_io,notifier_Fclk);
+ $width(negedge SCK &&& read_dual_io_flag==1'b1,Tsckh_dual_io,0,notifer_Tsckh);
+ $width(posedge SCK &&& read_dual_io_flag==1'b1,Tsckl_dual_io,0,notifer_Tsckl);
+
+ // 104 Mhz timing
+ $period(posedge SCK &&& CEb==1'b0 ,Fclk,notifier_Fclk);
+ $period(negedge SCK &&& CEb==1'b0 ,Fclk,notifier_Fclk);
+ $width(negedge SCK,Tsckh,0,notifer_Tsckh);
+ $width(posedge SCK,Tsckl,0,notifer_Tsckl);
+ $setup(negedge CEb,posedge SCK,Tces, notifier_Tces);
+ $setup(negedge CEb,posedge SCK,Tchh, notifier_Tchh);
+ $hold (posedge SCK,posedge CEb,Tceh, notifier_Tceh);
+ $setup(posedge SCK,posedge CEb,Tchs, notifier_Tchs);
+ $width(posedge CEb,Tcph,0,notifier_Tcph);
+ $setuphold(posedge SCK &&& Tds_inhibit[3]==1'b0, SIO[3],Tds,Tdh,notifier_Tds);
+ $setuphold(posedge SCK &&& Tds_inhibit[2]==1'b0, SIO[2],Tds,Tdh,notifier_Tds);
+ $setuphold(posedge SCK &&& Tds_inhibit[1]==1'b0, SIO[1],Tds,Tdh,notifier_Tds);
+ $setuphold(posedge SCK &&& Tds_inhibit[0]==1'b0, SIO[0],Tds,Tdh,notifier_Tds);
+ endspecify
+
+always @(notifier_Thls or notifier_Thhs or notifier_Thhh) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error for SIO[3] HOLDb timing to SCK rising time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+
+always @(notifier_Fclk) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Fclk time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+
+
+always @(notifier_Tds) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tds/Tdh time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+always @(notifier_Tcph) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tcph time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+always @(notifier_Tchh) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tchh time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+always @(notifier_Tchs) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tchs time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+always @(notifier_Tceh) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tceh time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+always @(notifier_Tces) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tces time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+
+always @( notifer_Tsckh or notifer_Tsckl) begin
+ if($realtime > MASK_ERRORS ) begin
+ $display("\t%m Fatal Timing Error Tsckh or Tsckl CEb width error time=%0.2f",$realtime);
+ corrupt_all; // corrupt memory
+ end
+end
+
+//---------------------------------------------------------------------------
+// corrupt all of memory on timing error
+//---------------------------------------------------------------------------
+task corrupt_all;
+reg [31:0] nn;
+begin
+ error_cnt = error_cnt + 1; // count the number of timing errors
+ $display("\t%m Fatal Error all of memory being set to 'xx' error_cnt=%0d",error_cnt);
+ for(nn=0;nn<I0.Memsize;nn=nn+16) begin
+ I0.memory[nn+0] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+1] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+2] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+3] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+4] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+5] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+6] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+7] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+8] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+9] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+10] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+11] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+12] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+13] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+14] = 8'hxx; // clear main memory to 'xx' on error
+ I0.memory[nn+15] = 8'hxx; // clear main memory to 'xx' on error
+ end
+end
+endtask
+
+endmodule
+
+/* -------------------------------------------------------------------------------
+ Proprietary & Confidental, All right reserved, 2010
+ Silicon Storage Technology, Inc. a subsidiary of Microchip
+----------------------------------------------------------------------------------
+This is the common model for the SST26WFxxxB family of chips
+This model is configured using defparam commands from the chip level module
+This is a serial FLASH memory that can be configured for SPI or SQI bus formats.
+----------------------------------------------------------------------------------
+Block memory definisions
+----------------------------------------------------------------------------------
+top 4 * 8K parameter block
+--- 1 * 32K block
+--- 64k blocks
+--- ...
+--- ...
+--- 64k blocks
+--- 1 * 32K block
+bottom 4 * 8K parameter block
+---------------------------------------------------------------------------
+
+ Pin Descriptions
+ Symbol Pin Name Type Function
+------- ------------ ------ -------------------------------------------
+ SCK Serial Clock input Provides clock to device
+ SIO[3:0] Serial Data I/O Provide data input and output, QUAD/SPI mode
+ SIO[0] = SPI I/O SIO[0]/SI
+ SIO[1] = SPI I/O SIO[1]/SO
+ SIO[2] Quad I/O SIO[2]/WPb
+ SIO[3] Quad I/O SIO[3]/HOLDb
+ CEb Chip Enable input Active low chip enable
+------------------------------------------------------------------------------- */
+
+`timescale 1ns / 10 ps
+module sst26wfxxxb(SCK,SIO,CEb);
+input SCK; // device clock
+input CEb; // chip enable active low
+inout [3:0] SIO; // serial 4-bit bus I/O
+
+parameter True = 1'b1;
+parameter False = 1'b0;
+parameter Kilo = 1024; // size of kilo 2^10
+parameter Mega = (Kilo * Kilo); // Size of mega 2^20
+parameter S080B=1; // size of SST26WF080B 1M bytes
+parameter S016B=2; // size of SST26WF016B 2M bytes
+parameter S032B=4; // size of SST26WF032B 4M bytes
+parameter S040B=0; //For memory size less than 1M
+
+//--------------------------------------------------------------------------------
+// change below parameters to change Memory size or init non-volitale registers
+//--------------------------------------------------------------------------------
+parameter Ksize = 0;
+parameter Msize = S032B; // Size of Memory in Mega bites. use S080B, S016B, S032B
+parameter Memsize = (Msize * Mega ) + (Ksize * Kilo); // Size of Memory in bytes
+parameter ADDR_MSB=21; // most significant address bit, 32Mb=21,16Mb=20, 8Mbit=19
+parameter INIT_WPEN = 1'b0; // For Configuration Register bit[7]/WPEN default value on por
+parameter PROTECT_REG_MSB = ((Memsize/(Kilo*64))+(16-1)); // MSB of protection register, 1M=31, 2M=47, 4M=79
+parameter WLLD_value = 80'h0000_0000_0000_0000_0000; // WLLD non-Volatile memory initial contents
+parameter SECURITY_LOCKOUT_VALUE=1'b0; // value of security lockout bit on default startup, SEC status[5]
+parameter Memory_Capacity=8'h52; // JEDEC device ID 32B=52,16B=51,080B=58
+
+`protect
+//---------------------------------------------------------------------------
+parameter MANUFACTURE=8'hBF; // JEDEC manufacture ID for SST
+parameter Memory_Type = 8'h26; // JEDEC define Memory type
+parameter Sector_MSB=11; // 4k sector size MSB sector address = [11:0]
+parameter Block08k_MSB=12; // MSB of 8K blocks
+parameter Block32k_MSB=14; // MSB of 32K blocks
+parameter Block64k_MSB=15; // MSB of 64K blocks
+parameter SST_SEC_ID_LSB='h18; // bottom address of SST security id space that cannot be written
+parameter ID_MSB=4; // MSB bit of security ID address max address 'h1F
+parameter Burst8_MSB=2; // Burst MSB bit
+parameter Burst16_MSB=3; // Burst MSB bit
+parameter Burst32_MSB=4; // Burst MSB bit
+parameter Burst64_MSB=5; // Burst MSB bit
+parameter Burst8=8'h00; // burst values
+parameter Burst16=8'h01; // burst values
+parameter Burst32=8'h02; // burst values
+parameter Burst64=8'h03; // burst values
+
+parameter AF_MSB = 23; // MSB of serial address field [23:0] i.e. 3 bytes of address data
+parameter Sector_Size = (4 * Kilo); // sector size;
+parameter Block_64k = (64*Kilo); // normal block size
+parameter Block_32k=(32*Kilo); // 32K->64K Memory space/top-32K-->top-64K Memory space
+parameter Block_08k=(8*Kilo); // top/bottom 32k blocks of Memory are in 8K blocks
+parameter Program_Page_Size=(Kilo/4); // program page size 256 bytes
+
+
+//---------------------------------------------------------------------------
+// SPI opcodes
+//---------------------------------------------------------------------------
+parameter SPI_NOP = 8'h00; // NOP command
+parameter SPI_RSTEN = 8'h66; // Reset Enable
+parameter SPI_RST = 8'h99; // Reset Chip
+parameter SPI_EQIO = 8'h38; // Enable QUAD I/O
+parameter SPI_RSTQIO = 8'hFF; // Restet QUAD I/O
+parameter SPI_RDSR = 8'h05; // Read Status Register
+parameter SPI_WRSR = 8'h01; // Write Status Register
+parameter SPI_RDCR = 8'h35; // Read Configuration Register
+parameter SPI_READ = 8'h03; // 50Mhz Read of Memory
+parameter SPI_HS_READ = 8'h0B; // High Speed Read of Memory 80Mhz
+parameter SPI_QUAD_READ = 8'h6B; // SPI QUAD Output Read
+parameter SPI_QUAD_IO_READ = 8'hEB; // SPI QUAD I/O Read
+parameter SPI_SDOR = 8'h3B; // SPI DUAL Output Read
+parameter SPI_SDIOR = 8'hBB; // SPI DUAL I/O Read
+parameter SPI_SB = 8'hC0; // Set Burst Length
+parameter SPI_RBSPI = 8'hEC; // SPI nB Burst with Wrap
+parameter SPI_JEDEC_ID = 8'h9F; // Jedec ID Read
+parameter SPI_SFDP = 8'h5A; // Serial Flash Discoverable Parameters
+parameter SPI_WREN = 8'h06; // Write Enable
+parameter SPI_WRDI = 8'h04; // Write Disable
+parameter SPI_SE = 8'h20; // Sector Erase 4K bytes size
+parameter SPI_BE = 8'hD8; // Block Erase 64K,32K,8K erase
+parameter SPI_CE = 8'hC7; // Chip Erase
+parameter SPI_PP = 8'h02; // Page Program SIO[1] bit used as data in, SIO[0] used as data out
+parameter SPI_QUAD_PP = 8'h32; // SPI QUAD Page Program
+parameter SPI_WRSU = 8'hB0; // Suspend Program/Erase
+parameter SPI_WRRE = 8'h30; // Resume Program/Erase
+parameter SPI_RBPR = 8'h72; // Read Block Protection Register
+parameter SPI_WBPR = 8'h42; // Write Block Protection Register
+parameter SPI_LBPR = 8'h8D; // Lock Down Block Protection Register
+parameter SPI_nVWLDR = 8'hE8; // Non-Volatile Write Lock down Register
+parameter SPI_ULBPR = 8'h98; // Global Block Protection Unlock
+parameter SPI_RSID = 8'h88; // Read Security ID
+parameter SPI_PSID = 8'hA5; // Program User Security ID Area
+parameter SPI_LSID = 8'h85; // Lock Out security ID Programing
+parameter SPI_DPD = 8'hB9; // Enable Deep Power Down mode
+parameter SPI_DPD_RST = 8'hAB; // Disable Deep Power Down mode; output device ID
+
+//---------------------------------------------------------------------------
+// SQI opcodes
+//---------------------------------------------------------------------------
+parameter SQI_NOP = SPI_NOP; // NOP command
+parameter SQI_RSTEN = SPI_RSTEN; // Reset Enable
+parameter SQI_RST = SPI_RST; // Reset Chip
+parameter SQI_RSTQIO = SPI_RSTQIO; // Restet QUAD I/O
+parameter SQI_RDSR = SPI_RDSR; // Read Status Register
+parameter SQI_WRSR = SPI_WRSR; // Write Status Register
+parameter SQI_RDCR = SPI_RDCR; // Read Configuration Register
+parameter SQI_HS_READ = SPI_HS_READ; // High Speed Read of Memory 80Mhz
+parameter SQI_SB = SPI_SB; // Set Burst Length
+parameter SQI_RBSQI = 8'h0C; // SQI nB Burst with Wrap
+parameter SQI_J_ID = 8'hAF; // Quad I/O J-ID Read
+parameter SQI_WREN = SPI_WREN; // Write Enable
+parameter SQI_WRDI = SPI_WRDI; // Write Disable
+parameter SQI_SE = SPI_SE; // Sector Erase 4K bytes size
+parameter SQI_BE = SPI_BE; // Block Erase 64K,32K,8K erase
+parameter SQI_CE = SPI_CE; // Chip Erase
+parameter SQI_PP = SPI_PP; // Page Program SIO[1] bit used as data in, SIO[0] used as data out
+parameter SQI_WRSU = SPI_WRSU; // Suspend Program/Erase
+parameter SQI_WRRE = SPI_WRRE; // Resume Program/Erase
+parameter SQI_RBPR = SPI_RBPR; // Read Block Protection Register
+parameter SQI_WBPR = SPI_WBPR; // Write Block Protection Register
+parameter SQI_LBPR = SPI_LBPR; // Lock Down Block Protection Register
+parameter SQI_nVWLDR = SPI_nVWLDR; // Non-Volatile Write Lock down Register
+parameter SQI_ULBPR = SPI_ULBPR; // Global Block Protection Unlock
+parameter SQI_RSID = SPI_RSID; // Read Security ID
+parameter SQI_PSID = SPI_PSID; // Program User Security ID Area
+parameter SQI_LSID = SPI_LSID; // Lock Out security ID Programing
+parameter SQI_DPD = SPI_DPD; // Enable Deep Power Down mode
+parameter SQI_DPD_RST = SPI_DPD_RST; // Disable Deep Power Down mode; output device ID
+
+`endprotect
+//---------------------------------------------------------------------------
+// Define Timings
+// You can use defparam to change the erase/program times to a shorter value.
+// This may make your simulation run faster Tws, Tse, Tbe, Tpp, minimun value 1000,
+// Tsce min value 2000
+//---------------------------------------------------------------------------
+parameter Tv = 5; // Output valid from SCK falling
+parameter Tclz = 0; // SCK low to low-z output
+parameter Tchz = 12.5; // Chip enable inactive to SIO z-stated
+parameter Tse = 25_000_000; // Sector erase time 25mS
+parameter Tbe = 25_000_000; // Block erase 25mS
+parameter Tsce = 50_000_000; // chip erase time 50mS
+parameter Tpp = 1_500_000; // page program time 1.5mS
+parameter Tws = 10_000; // suspend to ready time 10uS
+parameter Tpsid = 200_000; // Program Security ID time
+parameter Tre = 1_000_000; // reset recovery when reset during program/erase
+parameter Trp = 100_000; // reset recovery when reset during program/erase
+parameter Thz = 7.0; // HOLD falling to SO z-state
+parameter Tlz = 7.0; // HOLD rising to SO not z-state
+parameter Tsbr = 10_000; // recovery from Deep Power Down mode
+
+//---------------------------------------------------------------------------
+// Define non-volatile Memory
+//---------------------------------------------------------------------------
+reg [7:0] memory[Memsize-1:0]; // define Flash Memory array, non-volitable, 1, 2 or 4 Megabytes
+reg [7:0] security_id[(Kilo*2)-1:0]; // Define secutity ID Memory addr 0->7 are SST space the rest is user space, non-volitable
+reg [7:0] SFDP[(Kilo*2)-1:0]; // serial flash discoverable parameters
+reg [PROTECT_REG_MSB:0] wlldr_mem; // Define write-lock lock down reg, non-volitable, [31:0], [47:0], [79:0]
+reg WPEN; // (bit 7 WPEN) of configuration register, non-volitable
+reg SEC; // (status[5] SEC), 1-bit Lockout Security ID, non-volitable
+
+`protect
+//---------------------------------------------------------------------------
+// reg/wire definishions
+//---------------------------------------------------------------------------
+reg [PROTECT_REG_MSB:0] t_wlldr_mem; // Define temp storage, write-lock lock down reg, non-volitable
+reg [PROTECT_REG_MSB:0] protect; // protection register definishion max size for 32M-bit
+wire [PROTECT_REG_MSB:0] protect_or; // combine protection bits protect | wlldr_mem
+wire [7:0] status,config_reg; // status, configuration register
+wire BUSY; // status reg bit 0,7 active high busy signal, program or erase in progress
+reg RES; // reserved status bit
+reg WPLD; // Write protection lock down, status bit 4
+reg WSP; // Program Suspend status, Status Register
+reg WEL; // status bit 1
+reg WSE; // status bit 2, write suspend erase status, 1= suspend in progress
+reg IOC; // config[1]
+reg DPD;
+wire BPNV; // config[3], Block Protection Volatility State
+reg PE; // config[5]
+reg EE; // config[6]
+reg RSTEN; // enable reset command
+reg [7:0] pmem[Program_Page_Size-1:0]; // storage for program Memory 256 bytes
+reg [7:0] x_pmem[Program_Page_Size-1:0]; // tmp storage for program Memory 256 bytes
+reg [7:0] s_pmem[Program_Page_Size-1:0]; // save suspended data here
+reg read_slow_flag; // timing check flag for 40Mhz read
+reg [3:0] SIO_IO; // True if outputing data on SIO[3:0]
+reg [3:0] SIO_OUT; // output data for SIO
+reg [31:0] cnt; // generic counter for loops
+reg clock; // internal SCK
+reg [7:0] spi_count,sqi_count; // SPI clock counter
+reg [7:0] sqi_cmd,spi_cmd,l_spi_cmd; // command input storage
+reg [7:0] RSTQIO_cmd; // storage for the SPI RSTQIO command in SQI mode
+reg [7:0] l_sqi_cmd; // latched sqi command
+wire suspend_act; // True if in suspend mode
+reg SPI_SDIOR_active; // loop active
+reg SPI_SDOR_active; // loop active
+reg SQI_HS_READ_active; // SQI high speed read loop active
+reg SPI_WRSU_active; // suspend active flag
+reg SPI_nVWLDR_active; // loop active
+reg SPI_WRSR_PGM_active; // used to set busy on config reg program
+reg SPI_WRSR_active; // loop active
+reg SPI_LSID_active; // loop active
+reg SPI_PSID_active; // spi PSID loop active
+reg SPI_PSID_ip; // security programing in progress
+reg SPI_RSID_active; // spi read security id active
+reg SPI_DPD_RST_RDID_active; // loop active
+reg erase_active; // SE,BE,CE erase actice
+reg erase_ip; // SE,BE,CE erase in progress
+reg SPI_QUAD_PP_active; // loop active
+reg SPI_RDCR_active; // loop active
+reg SQI_PP_active; // loop active
+reg SPI_PP_active; // loop active
+reg SPI_RBPR_active; // loop active
+reg SPI_WBPR_active; // loop active flag
+reg SPI_nVWLDR_cmd_active; // loop active
+reg SPI_RDSR_active; // loop active
+reg SPI_SFDP_active; // loop active
+reg SPI_JEDEC_ID_active; // loop active
+reg SPI_RBSPI_active; // loop active flag
+reg SPI_SB_active; // loop active flag
+reg SPI_READ_active,SPI_READ_QUAD_active; // read loop is active ir True
+reg SPI_QUAD_IO_READ_active; // loop active
+reg SQI_SPI_mode; // True = QUAD mode False=SPI mode
+reg [7:0] Mode_Configuration; // configuration data for continious read with no opcode
+reg [7:0] burst_length; // burst length 00=8bytes, 01=16bytes, 02=32bytes, 03=64bytes
+wire WBPR_protection_lck; // table 2 for WBPR cammond
+wire WPb; // write protect bar signal
+reg valid_addr; // program address valid, address was read in
+reg valid_data; // program data valid, i.e. at least 1 clock of data
+reg [AF_MSB:0] pgm_addr; // program address
+reg [15:0] pgm_id_addr; // program security id address
+reg [AF_MSB:0] erase_addr; // erase address
+reg [31:0] erase_size,resume_size; // erase size
+reg [AF_MSB:0] suspend_addr,resume_addr; // save program address on suspend
+real start_erase; // start time of erase or program
+real s_time_left; // save time left for nested suspends
+real save_erase_time; // on suspend save realtime in here
+real erase_time; // time needed to erase sector/block/chip
+real time_left; // time left for program/erase to finish
+reg page_program_active; // page program is active
+reg [7:0] wsr_sreg,wsr_creg; // tmp data storage for write status/configuration registers
+wire CONFIG_protection_lck; // configuration write protect
+wire write_protect;
+reg CE_flag,BE_flag,SE_flag; // erase type flags
+reg s_BE_flag,s_SE_flag; // flags saved for suspend
+wire HOLDb, HOLDb_IO; // composit hold control siginals
+reg clockx; // internal clock
+reg pgm_sus_reset;
+
+event reset; // Trigger reset block
+event SPI_READ_trg; // Start spi read operation 50Mhz
+event SPI_QUAD_READ_trg; // Start SPI QUAD read
+event SPI_QUAD_IO_READ_trg; // Start SPI QUAD IO READ
+event SPI_SB_trg; // Start SPI Set Burst Count
+event SPI_RBSPI_trg; // Start SPI Burst Read
+event SPI_JEDEC_ID_trg; // Start JEDEC_ ID read
+event SPI_SFDP_trg; // start SFDP , Serial Flash Discoverable Parameters
+event SPI_RDSR_trg; // Read Status register
+event SPI_WBPR_trg; // Trigger write block protection register
+event SPI_RBPR_trg; // Read block protection register
+event SPI_PP_trg; // Page program trigger
+event SPI_RDCR_trg; // Start read of Configuration Register
+event SPI_QUAD_PP_trg; // Start SPI QUAD page write
+event SPI_SE_trg; // Start sector erase
+event SPI_BE_trg; // Start block erase
+event SPI_CE_trg; // Start Chip erase
+event SPI_RSID_trg; // Spi read security id
+event SPI_PSID_trg; // Spi program user security id space
+event SPI_LSID_trg; // Security ID lockout
+event SPI_DPD_RST_trg; // Deep Power Down Reset
+event SPI_WRSR_trg; // Write status register
+event SPI_nVWLDR_trg; // Write non-volatile block protection register
+event SPI_ULBPR_trg; // Trigger Global Block Protection Unlock
+event SPI_WRSU_trg; // Enter suspend mode
+event SPI_WRRE_trg; // Exit suspend mode , resume
+event SQI_HS_READ_trg; // SQI high speed read trigger
+event SPI_SDOR_trg; // Spi dual output read
+event SPI_SDIOR_trg; // Dual I/O read
+event SPI_LBPR_trg; // Lock down block protection reg
+event SPI_EQIO_trg; // Enable Quad I/O
+
+//---------------------------------------------------------------------------
+// Status/Configuration register definisions, Protection logic
+//---------------------------------------------------------------------------
+assign status = {BUSY,RES,SEC,WPLD,WSP,WSE,WEL,BUSY}; // create status register
+assign config_reg = {WPEN,EE,PE,1'b0,BPNV,1'b0,IOC,1'b0}; // create configuration register
+assign BUSY = page_program_active | erase_ip | SPI_LSID_active | SPI_WRSR_PGM_active | SPI_nVWLDR_active
+ | pgm_sus_reset;
+assign BPNV = ~(|wlldr_mem); // block protection volatility state, configuration reg[3]
+assign WPb = SIO[2]; // rename SIO[2] to WPb for code clairity
+assign protect_or = protect | wlldr_mem; // combine non-volital protect with volital protect
+assign suspend_act = (WSE | WSP); // suspend active net
+
+//---------------------------------------------------------------------------
+// write protection SPI mode configuration reg write only, protection = True
+// Check Table 2 lines 2,4,5,6
+//---------------------------------------------------------------------------
+assign CONFIG_protection_lck = (SQI_SPI_mode===True) ? False : (~WPb & ~IOC & WPEN);
+
+assign write_protect = ~SQI_SPI_mode & ~IOC & WPEN & ~WPb;
+assign WBPR_protection_lck = (SQI_SPI_mode===True) ? WPLD : WPLD | write_protect;
+
+//---------------------------------------------------------------------------
+// I/O assignments
+//---------------------------------------------------------------------------
+assign SIO[0] = (SIO_IO[0]===True && HOLDb_IO===1'b1) ? SIO_OUT[0] : 1'bz; // output data on SIO ? SI
+assign SIO[1] = (SIO_IO[1]===True && HOLDb_IO===1'b1) ? SIO_OUT[1] : 1'bz; // output data on SIO ? SO
+assign SIO[2] = (SIO_IO[2]===True) ? SIO_OUT[2] : 1'bz; // output data on SIO ?
+assign SIO[3] = (SIO_IO[3]===True) ? SIO_OUT[3] : 1'bz; // output data on SIO ?
+
+//---------------------------------------------------------------------------
+// HOLD# setup
+//---------------------------------------------------------------------------
+assign HOLDb = CEb | IOC | SIO[3] | SQI_SPI_mode ; // no timing HOLDb
+assign #(Tlz,Thz) HOLDb_IO = HOLDb; // I/O control timing HOLDb signal
+
+//-------------------------------------------------------
+// Generate internal clock
+//-------------------------------------------------------
+always @(SCK) if(CEb === 1'b0) clockx = SCK;
+ else if (CEb === 1'b1 ) clockx = 1'b0;
+ else clockx = 1'bx;
+
+always @(posedge clockx) if(HOLDb===1'b1) clock = clockx; else clock = 1'b0;
+always @(negedge clockx) clock = clockx;
+
+//-------------------------------------------------------
+// Define begining of command operation
+//-------------------------------------------------------
+always @( negedge CEb ) begin
+ spi_count = 0; // clear spi clock counter
+ sqi_count = 0; // clear sqi clock counter
+ spi_cmd = SPI_NOP; // clear SPI command register
+ sqi_cmd = SQI_NOP; // clear SQI command register
+ RSTQIO_cmd = SPI_NOP; // clear command
+end
+
+//-------------------------------------------------------
+// Terminate still runnung named blocks on CEb inactive
+//-------------------------------------------------------
+always @( posedge CEb ) begin
+ SIO_IO <= #Tchz {False,False,False,False}; // Turn off IO control SIO[3:0]
+ #0 if(SPI_READ_active==True) begin
+ disable SPI_READ_label;
+ SPI_READ_active = False; // read loop is inactive
+ read_slow_flag = False; // set timing checks back to normal
+ end
+ if(SPI_READ_QUAD_active==True) begin
+ disable SPI_QUAD_READ_label;
+ SPI_READ_QUAD_active = False;
+ end
+ if(SPI_QUAD_IO_READ_active===True) begin
+ disable SPI_QUAD_IO_READ_label;
+ SPI_QUAD_IO_READ_active = False;
+ end
+ if(SPI_SB_active===True) begin
+ disable SPI_SB_label;
+ SPI_SB_active = False;
+ end
+ if(SPI_RBSPI_active===True) begin
+ disable SPI_RBSPI_label;
+ SPI_RBSPI_active = False;
+ end
+ if(SPI_JEDEC_ID_active===True) begin
+ disable SPI_JEDEC_ID_label;
+ SPI_JEDEC_ID_active = False;
+ end
+ if(SPI_SFDP_active===True) begin
+ disable SPI_SFDP_label;
+ SPI_SFDP_active = False;
+ end
+ if(SPI_RDSR_active===True) begin
+ disable SPI_RDSR_label;
+ SPI_RDSR_active = False;
+ end
+ if(SPI_RDCR_active===True) begin
+ disable SPI_RDCR_label;
+ SPI_RDCR_active = False;
+ end
+ if(SPI_RBPR_active===True) begin
+ disable SPI_RBPR_label;
+ SPI_RBPR_active = False;
+ end
+ if(SPI_RSID_active ===True) begin
+ disable SPI_RSID_label;
+ SPI_RSID_active = False;
+ end
+ if(SPI_WBPR_active ===True) begin
+ disable SPI_WBPR_label;
+ SPI_WBPR_active = False;
+ end
+ if(SQI_HS_READ_active===True) begin
+ disable SQI_HS_READ_label;
+ SQI_HS_READ_active = False;
+ end
+ if(SPI_SDOR_active===True) begin
+ disable SPI_SDOR_label;
+ SPI_SDOR_active = False;
+ end
+ if(SPI_SDIOR_active ===True) begin
+ disable SPI_SDIOR_label;
+ SPI_SDIOR_active = False;
+ end
+ if(SPI_DPD_RST_RDID_active ===True) begin
+ disable SPI_DPD_RST_RDID_label;
+ SPI_DPD_RST_RDID_active = False;
+ end
+end
+
+//-----------------------------------------------------------
+// Read in hex command stream, SQI mode commands
+//-----------------------------------------------------------
+always @( posedge clock && SQI_SPI_mode === True) begin
+ if(BUSY===False && Mode_Configuration[7:4]===4'hA && sqi_count===8'h00) begin // continue sqi_hs_read command ?
+ sqi_count = 8; // abort this command loop
+ -> SQI_HS_READ_trg; // continue from previous read
+ #1 Mode_Configuration = 8'hFF; // clear mode config
+ end
+ if(sqi_count < 2 ) begin // 1st 2 clocks are command
+ sqi_cmd = sqi_cmd <<4; // shift command data
+ sqi_cmd[3:0] = SIO[3:0]; // load in cmd data
+ end
+ if(sqi_count < 8 ) begin // look for SPI RSTIO cmd
+ RSTQIO_cmd = RSTQIO_cmd <<1; // shift command data
+ RSTQIO_cmd[0] = SIO[0]; // load in cmd data
+ if(BUSY===False && sqi_count===8'h07 && RSTQIO_cmd===SPI_RSTQIO)
+ @(posedge CEb) SQI_SPI_mode=False; // exit SQI mode while in SQI mode using SPI format
+ end
+ if(sqi_count === 8'h01) begin // start of SQI command interperter
+ l_sqi_cmd = sqi_cmd; // latch SQI command
+ if(DPD===False && RSTEN===True && l_sqi_cmd !== SQI_RST) RSTEN = False; // clear reset enable on incorrect sequence
+ if(DPD===False && l_sqi_cmd === SQI_RSTEN) RSTEN = True; // enable reset command
+ else if(DPD===False && l_sqi_cmd===SQI_RST && RSTEN===True) @(posedge CEb) -> reset; // reset chip
+ else if(DPD===False && l_sqi_cmd===SQI_NOP ) RSTEN=False; // NOP command
+ else if(DPD===False && l_sqi_cmd===SQI_RDSR) -> SPI_RDSR_trg; // SQI read status register
+ else if(DPD===False && l_sqi_cmd===SQI_RDCR) -> SPI_RDCR_trg; // SQI read configuration register
+ else if(DPD===False && BUSY===True && l_sqi_cmd===SQI_WRSU) -> SPI_WRSU_trg; // Enter suspend mode
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_RSTQIO) @(posedge CEb) SQI_SPI_mode=False; // Reset to SPI mode
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_WREN) @(posedge CEb) WEL = True; // Write Enable flag set
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_WRDI) @(posedge CEb) WEL = False; // Write Enable flag cleared
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_WRRE ) -> SPI_WRRE_trg; // exit suspend mode resume normal mode
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_RBPR) -> SPI_RBPR_trg; // Read Block Protection Register
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_HS_READ) -> SQI_HS_READ_trg; // normal read, 80Mhz
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_SB) -> SPI_SB_trg; // Set Burst Count
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_RBSQI) -> SPI_RBSPI_trg; // sqi nB Burst with Wrap
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_J_ID) -> SPI_JEDEC_ID_trg; // Read JEDEC ID
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_RSID) -> SPI_RSID_trg; // Read security ID
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_CE && WEL===True) -> SPI_CE_trg; // Chip erase
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_SE && WEL===True) -> SPI_SE_trg; // Sector erase
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_BE && WEL===True) -> SPI_BE_trg; // Block erase
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_LBPR && WEL===True) -> SPI_LBPR_trg; // Lock Down Block Protection Reg.
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_ULBPR && WEL===True) -> SPI_ULBPR_trg; // Global Block Protection Unlock
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_LSID && WEL===True) -> SPI_LSID_trg; // lockout security ID programing
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_WRSR && WEL===True) -> SPI_WRSR_trg; // Write status register
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_PP && WEL===True) -> SPI_QUAD_PP_trg; // SQI page program
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_WBPR && WEL===True) -> SPI_WBPR_trg; // Write Block Protection Register
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_nVWLDR && WEL===True) -> SPI_nVWLDR_trg; // write non-volatile block protection register
+ else if(DPD===False && BUSY===False && l_sqi_cmd===SQI_PSID && WEL===True) -> SPI_PSID_trg; // program Security ID space 2K
+ else if(BUSY===False && l_sqi_cmd===SQI_DPD) @(posedge CEb) DPD = True; // deep power down mode
+ else if(BUSY===False && l_sqi_cmd===SQI_DPD_RST) -> SPI_DPD_RST_trg; // exit deep power down mode
+ else begin
+ if({l_sqi_cmd[7],l_sqi_cmd[3]}!== 2'b11) // check for start of SPI RSTQIO cmd
+ $display("\t%m Warning Illegal SQI Instruction='%h' aborted, time=%0.2f",l_sqi_cmd,$realtime);
+ if(BUSY===True) $display("\t%m Check BUSY most commands don't run during busy");
+ end
+ end
+ if( sqi_count < 9 ) sqi_count = sqi_count + 1; // incremint bit counter for command sample
+end
+
+//-----------------------------------------------------------
+// Read in serial command stream command, SPI mode commands
+//-----------------------------------------------------------
+always @( posedge clock && SQI_SPI_mode === False ) begin
+ if(BUSY===False && Mode_Configuration[7:4]===4'hA && spi_count===8'h00) begin // continue previous command ?
+ spi_count = 8; // abort command loop
+ if(l_spi_cmd === SPI_QUAD_IO_READ) -> SPI_QUAD_IO_READ_trg; // continue from previous read, quad read
+ else if(l_spi_cmd === SPI_SDIOR) -> SPI_SDIOR_trg; // continue from previous read, dual read
+ Mode_Configuration <= #1 8'hFF; // clear mode config
+ end
+ if(spi_count < 8 ) begin // 1st 8 clocks are command
+ spi_cmd = spi_cmd <<1; // shift command data
+ spi_cmd[0] = SIO[0]; // load in cmd data
+ end
+ if( spi_count === 8'h07) begin // start of SPI command interperter
+ l_spi_cmd = spi_cmd; // latch command
+ if(DPD===False && RSTEN===True && l_spi_cmd !== SPI_RST) RSTEN = False; // clear reset enable on incorrect sequence
+
+ if(DPD===False && l_spi_cmd === SPI_RSTEN) RSTEN = True; // enable reset command
+ else if(DPD===False && l_spi_cmd===SPI_NOP ) RSTEN=False; // NOP command
+ else if(DPD===False && l_spi_cmd===SPI_RST && RSTEN===True) @(posedge CEb) -> reset; // reset command
+ else if(DPD===False && l_spi_cmd===SPI_RDSR) -> SPI_RDSR_trg; // SPI read status register
+ else if(DPD===False && l_spi_cmd===SPI_RDCR) -> SPI_RDCR_trg; // SPI read configuration register
+ else if(DPD===False && BUSY===True && l_spi_cmd===SPI_WRSU) -> SPI_WRSU_trg; // Enter suspend mode
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_READ) -> SPI_READ_trg; // normal read, 50Mhz
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_HS_READ) -> SPI_READ_trg; // normal read, 80Mhz
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_RSTQIO) @(posedge CEb) SQI_SPI_mode=False; // This cmd does nothing as already in SPI mode
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_WREN) @(posedge CEb) WEL = True; // Write Enable flag set
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_WRDI) @(posedge CEb) WEL = False; // Write Enable flag cleared
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_SDOR) -> SPI_SDOR_trg; // dual output read
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_SDIOR) -> SPI_SDIOR_trg; // dual I/O output read
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_QUAD_READ) -> SPI_QUAD_READ_trg; // SPI QUAD read
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_QUAD_IO_READ) -> SPI_QUAD_IO_READ_trg; // SPI QUAD IO READ
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_RBSPI) -> SPI_RBSPI_trg; // SPI Burst read
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_EQIO ) -> SPI_EQIO_trg; // enter SQI mode
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_JEDEC_ID) -> SPI_JEDEC_ID_trg; // Read JEDEC ID
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_RBPR) -> SPI_RBPR_trg; // Read Block Protection Register
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_SFDP) -> SPI_SFDP_trg; // Read Serial Flash Discoverable Parameters
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_RSID) -> SPI_RSID_trg; // SPI Read security ID
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_SB) -> SPI_SB_trg; // SPI Set Burst Count
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_WRRE) -> SPI_WRRE_trg; // exit suspend mode resume normal mode
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_QUAD_PP && WEL===True) -> SPI_QUAD_PP_trg; // SPI QUAD page program
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_ULBPR && WEL===True) -> SPI_ULBPR_trg; // Global Block Protection Unlock
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_nVWLDR && WEL===True) -> SPI_nVWLDR_trg; // write non-volatile block protection register
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_WRSR && WEL===True) -> SPI_WRSR_trg; // Write status register
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_LSID && WEL===True) -> SPI_LSID_trg; // lockout security ID programing
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_PP && WEL===True) -> SPI_PP_trg; // SPI page program
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_WBPR && WEL===True) -> SPI_WBPR_trg; // Write Block Protection Register
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_SE && WEL===True) -> SPI_SE_trg; // Sector erase
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_BE && WEL===True) -> SPI_BE_trg; // Block erase
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_CE && WEL===True) -> SPI_CE_trg; // Chip erase
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_PSID && WEL===True) -> SPI_PSID_trg; // program Security ID space 2K
+ else if(DPD===False && BUSY===False && l_spi_cmd===SPI_LBPR && WEL===True) -> SPI_LBPR_trg; // Lock Down Block Protection Reg.
+ else if(BUSY===False && l_spi_cmd===SPI_DPD) @(posedge CEb) DPD = True; // deep power down mode
+ else if(BUSY===False && l_spi_cmd===SPI_DPD_RST) -> SPI_DPD_RST_trg; // exit deep power down mode
+ else begin
+ $display("\t%m Warning Illegal SPI Instruction='%h' aborted, time=%0.2f",l_spi_cmd,$realtime);
+ if(BUSY===True) $display("\t%m Check BUSY most commands not allowed during busy");
+ end
+ end
+ if( spi_count < 9 ) spi_count = spi_count + 1; // incremint bit counter for command sample
+end
+
+//---------------------------------------------------------------------------
+// Enter SQI mode
+//---------------------------------------------------------------------------
+always @(SPI_EQIO_trg) begin
+ @(posedge CEb)
+ if (~write_protect) SQI_SPI_mode = True;
+end
+
+//---------------------------------------------------------------------------
+// Lock Down Block Protection Reg.
+//---------------------------------------------------------------------------
+always @(SPI_LBPR_trg) begin
+ @(posedge CEb) begin
+ WPLD = True; // set WPLD (write protection lock down status[4])
+ WEL = False; // clear status[2] WEL
+ end
+end
+
+//---------------------------------------------------------------------------
+// Resume, exit suspend mode
+//---------------------------------------------------------------------------
+always @(SPI_WRRE_trg) begin :SPI_WRRE_label
+reg [8:0] pcount;
+ if(suspend_act===False) $display("\t%m Warning WRRE(h30) cmd ignnored not in suspend mode, time=%0.2f",$realtime);
+ else begin // suspend_act===True
+ if(WSP === True) begin // resume from Page program ?
+ WSP = False; // clear program suspend flag
+ page_program_active = True; // flags needed to continue PP program
+ valid_data = True; valid_addr = True; // flags needed to continue PP program
+ SPI_PP_active = True; // flags needed to continue PP program
+ time_left = s_time_left; // program time left
+ pgm_addr = resume_addr; // restort program address
+ for(pcount=0;pcount<Program_Page_Size;pcount = pcount+1) pmem[pcount] = s_pmem[pcount]; // restore suspended program data
+ end
+ else if(WSE===True) begin // Erase Suspended ?
+ erase_active = True; // restart erase on CEb inactive
+ WSE = False; // clear erase suspend flag
+ valid_addr = True; // set resume address as valid
+ valid_data = True; // set resume data as valid
+ erase_addr = resume_addr; // restore address
+ erase_size = resume_size; // restore size of erase area
+ time_left = s_time_left; // erase time left
+ BE_flag = s_BE_flag; // restore type of erase
+ SE_flag = s_SE_flag; // restore type of erase
+ end
+ @(posedge CEb) ; // wait for CEb to go inactive, starts erase/program loops
+ end
+end
+
+//---------------------------------------------------------------------------
+// enter suspend mode, WEL=1 already to get here
+//---------------------------------------------------------------------------
+always @(SPI_WRSU_trg) begin :SPI_WRSU_label
+reg [8:0] pcount;
+ @(posedge CEb) ; // wait for CEb to go inactive
+ #0 if((page_program_active === False && erase_ip === False) || SPI_PSID_ip===True ) begin
+ $display("\t%m Warning Write Suspend(hB0), only allowed during PP(h32),PP(h02),BE(hD8),SE(h20) cmds, cmd aborted time=%0.2f",$realtime);
+ end
+ else if(CE_flag===True) begin // no suspend during chip erase
+ $display("\t%m Warning Write Suspend(hB0), not allowed during CE(hC7) cmd, cmd aborted time=%0.2f",$realtime);
+ end
+ else if(suspend_act===True) begin
+ $display("\t%m Warning Write Suspend(hB0), nested suspends not allowed, WRSU(hB0) cmd aborted time=%0.2f",$realtime);
+ end
+ else begin // begin Suspend mode
+ SPI_WRSU_active = True; // this loop is active
+ if(page_program_active === True) begin
+ disable page_program_label; // abort programing on suspend
+ s_time_left = (time_left - ($realtime - start_erase)) + Tws;
+ resume_addr = suspend_addr; // save suspended address
+ for(pcount=0;pcount<Program_Page_Size;pcount = pcount+1) s_pmem[pcount] = pmem[pcount]; // save suspended data program data
+ WSP = True; // set WSE in status register
+ #Tws ; // wait for suspend program complete
+ page_program_active = False; // clear busy
+ WEL = False; // clear WEL write enable
+ end
+ else if( erase_ip === True) begin // Sector/Block erase in progress ?
+ disable erase_label; // abort erase on suspend
+ s_time_left = (time_left - ($realtime - start_erase)) + Tws;
+ resume_addr = suspend_addr; // save suspended address
+ resume_size = erase_size; // save block size to erase
+ WSE = True; // set WSE in status register
+ #Tws ; // wait for suspend of erase complete
+ erase_ip = False; // clear erase loop flag;
+ WEL = False;
+ s_BE_flag = BE_flag; // save type of erase
+ s_SE_flag = SE_flag; // save type of erase
+ BE_flag = False;
+ SE_flag = False;
+ end
+ SPI_WRSU_active = False; // this loop is inactive
+ end
+end
+
+//---------------------------------------------------------------------------
+// Global Block Protection Unlock
+//---------------------------------------------------------------------------
+always @(SPI_ULBPR_trg) begin :SPI_ULBPR_label
+reg [7:0] count; // counter
+ @(posedge CEb) begin
+ if(WBPR_protection_lck === False) begin // check block protect lock down register
+
+ // clear the block write protection
+ for(count=0;count<(PROTECT_REG_MSB-15);count=count+1) protect[count]=1'b0;
+
+ // clear the 8 8K block write protection bits
+ count = PROTECT_REG_MSB-15;
+ repeat(8) begin protect[count] = 1'b0; count = count + 2; end
+ WEL = False; // clear write enable in status reg
+ end
+ else begin
+ $display("\t%m Warning ULBPR(h98) cmd aborted time=%0.2f",$realtime);
+ end
+ end
+end
+
+//---------------------------------------------------------------------------
+// program status/configuration register
+//---------------------------------------------------------------------------
+always @(posedge CEb) begin : SPI_WRSR_PGM
+ if(SPI_WRSR_active===True && suspend_act===False) begin
+ disable SPI_WRSR_label;
+ SPI_WRSR_active = False;
+ if(valid_data===True) begin // 16 clocks of data ?
+ IOC = wsr_creg[1]; // set IOC right away, don't wait for program to finish
+ if(wsr_creg[7]!==WPEN) begin // WPEN <- 0
+ SPI_WRSR_PGM_active = True; // set busy
+ if(wsr_creg[7]===False) begin // WPEN <- 0
+ #Tse WPEN = wsr_creg[7];// program WPEN
+ end
+ else begin // WPEN <- 1
+ #Tpp WPEN = wsr_creg[7];// Erase WPEN
+ end
+ end
+ WEL = False; // clear WEL
+ valid_data = False; // clear valid data flag
+ SPI_WRSR_PGM_active = False; // clear busy
+ end
+ else $display("\t%m Warning WRSR(h01) has invalid data, cmd aborted, time=%0.2f",$realtime);
+ end
+end
+
+//---------------------------------------------------------------------------
+// write status register
+//---------------------------------------------------------------------------
+always @(SPI_WRSR_trg) begin :SPI_WRSR_label
+ if(suspend_act===False && CONFIG_protection_lck===False) begin
+ SPI_WRSR_active = True;
+ valid_data = False; // default valid data
+ if(SQI_SPI_mode === True) begin // SQI bus
+ $display("\t%m Warning do not run cmd WRSR(h01) in SQI mode time=%0.2f",$realtime);
+ @(posedge clock) wsr_sreg[7:4] = SIO[3:0]; // read in status register
+ @(posedge clock) wsr_sreg[3:0] = SIO[3:0];
+ @(posedge clock) wsr_creg[7:4] = SIO[3:0]; // read in configuration register
+ @(posedge clock) wsr_creg[3:0] = SIO[3:0];
+ end
+ else begin // SPI bus
+ repeat(8) @(posedge clock ) begin // read in status register
+ wsr_sreg = wsr_sreg <<1;
+ wsr_sreg[0] = SIO[0];
+ end
+ repeat(8) @(posedge clock ) begin // read in configuration register
+ wsr_creg = wsr_creg <<1;
+ wsr_creg[0] = SIO[0];
+ end
+ end
+ valid_data = True; // set valid data flag
+ forever @(posedge clock ) ; // wait here for CEb rising
+ end
+ else begin
+ if(CONFIG_protection_lck===True) begin
+ $display("\t%m Warning command WRSR('h01) aborted, configuration reg write protected time=%0.2f",$realtime);
+ end
+ if(suspend_act===True ) begin
+ $display("\t%m Warning command WRSR('h01) aborted, not a valid cmd is suspend mode, time=%0.2f",$realtime);
+ end
+ valid_data = False; // default valid data
+ SPI_WRSR_active = False;
+ end
+end
+
+//---------------------------------------------------------------------------
+// Security ID program, lockout
+//---------------------------------------------------------------------------
+always @(SPI_LSID_trg) begin :SPI_LSID_label
+ @(posedge CEb) begin
+ if(suspend_act===False) begin
+ SPI_LSID_active = True; // set busy
+ SEC = True; // program SEC bit of status register
+ #Tpsid
+ WEL = False; // clear write enable in status reg
+ SPI_LSID_active = False; // clear busy
+ end
+ else begin
+ $display("\t%m Warning command LSID(h85) not allowed in suspend mode, aborted time=%0.2f",$realtime);
+ end
+ end
+end
+
+//---------------------------------------------------------------------------
+// Security ID program, Program Security ID Memory when CEb inactive ?
+//---------------------------------------------------------------------------
+always @(posedge CEb) begin :Sec_ID_pgm_label
+reg [AF_MSB:0] nn;
+ if(SPI_PSID_active === True && suspend_act===False ) begin // Page_Program of Security ID is active
+ disable SPI_PSID_label; // disable Security ID page program loop
+ SPI_PSID_active = False; // clear program loop
+ if(valid_data===True && valid_addr===True && suspend_act===False) begin
+ page_program_active = True; // set busy
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ for(nn=0;nn<Program_Page_Size;nn=nn+1) begin // save current data in Memory
+ x_pmem[nn]=security_id[{pgm_id_addr[10:8],nn[7:0]}]; // save security_id data that will be written over
+ security_id[{pgm_id_addr[10:8],nn[7:0]}] = 8'hxx; // make data 'xx'
+ end
+ SPI_PSID_ip = True; // security programing in progress
+ #Tpp for(nn=0;nn<Program_Page_Size;nn=nn+1) begin // Wait Tpp time for program to finish, then update memory
+ security_id[{pgm_id_addr[10:8],nn[7:0]}] = x_pmem[nn] & pmem[nn[7:0]];
+ //$display("\tprogram security_id add=%h, data=%h time=%0.2f",{pgm_id_addr[ADDR_MSB:8],nn[7:0]},(x_pmem[nn] & pmem[nn[7:0]]),
+ //$realtime);
+ end
+ SPI_PSID_ip = False; // security programing complete
+ page_program_active = False; // clear busy
+ WEL = False;
+ end
+ else begin
+ $display("\t%m Warning PSID(hA5) Page Program error, PSID(hA5) cmd aborted time=%0.2f",$realtime);
+ end
+ end
+end
+
+//---------------------------------------------------------------------------
+// Program Security ID , get address and data
+//---------------------------------------------------------------------------
+always @(SPI_PSID_trg) begin : SPI_PSID_label
+reg [8:0] pcount;
+reg [7:0] sdata;
+
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ if(suspend_act === False) begin // check WREN flag, no program on suspend active
+ SPI_PSID_active = True; // program loop is active
+ for(pcount=0;pcount<Program_Page_Size;pcount = pcount+1) pmem[pcount] = 8'hFF; // clear program data to all 1's
+
+ if(SQI_SPI_mode === True) begin
+ repeat(4) begin // read in address, set valid address flag when complete
+ pgm_id_addr = pgm_id_addr <<4;
+ @(posedge clock) pgm_id_addr[3:0]=SIO[3:0]; // read in 1-nibble of address
+ end
+ end
+ else begin
+ repeat(16) begin // read in address, set valid address flag when complete
+ pgm_id_addr = pgm_id_addr <<1;
+ @(posedge clock) pgm_id_addr[0] = SIO[0]; // read in 1-bit of address
+ end
+ end
+ pgm_id_addr = pgm_id_addr & ((Kilo*2)-1); // clear unused upper address bits above 2K memory boundry
+ valid_addr = True; // address read complete set valid address flag
+ if(SEC===False) begin // check for proteced Memory
+ valid_data = False; // no data valid
+ forever begin // Read program data, loop through all data abort on CEb rising
+ if(SQI_SPI_mode === True) begin // SQI mode
+ @(posedge clock) sdata[7:4]=SIO[3:0]; // read high nibble
+ valid_data = True; // at least 1 valid data clock
+ @(posedge clock) sdata[3:0]=SIO[3:0]; // read low nibble
+ end
+ else begin // SPI mode
+ repeat(8) @(posedge clock) begin // read in byte of data
+ valid_data = True; // at least 1 valid data clock
+ sdata = sdata <<1;
+ sdata[0] = SIO[0];
+ end
+ end
+ if(pgm_id_addr >= 'h0008) begin // don't program SST Memory section
+ pmem[pgm_id_addr[7:0]] = sdata; // save byte of data page Memory
+ end
+ pgm_id_addr[7:0]=pgm_id_addr[7:0] + 1; // increment to next addr of page Memory, wrap on 256 byte bountry
+ end
+ end
+ else begin // protected Memory abort program
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ SPI_PSID_active = False; // abort program on protected Memory
+ $display("\t%m Warning PSID(hA5) command aborted SEC=1 Locked Memory address=%h, time %0.2f",
+ pgm_id_addr,$realtime);
+ end
+ SPI_PSID_active = False;
+ end
+ else begin
+ $display("\t%m Warning PSID(hA5) command aborted, PSID does not work in Suspend Mode, time=%0.2f",$realtime);
+ end
+end
+
+
+//----------------------------------------------------------------------------
+// SPI Mode Read Security ID space
+//----------------------------------------------------------------------------
+always @(SPI_RSID_trg ) begin :SPI_RSID_label
+reg [7:0] data;
+reg [15:0] addr; // max value 2K-1
+ SPI_RSID_active = True;
+ if(SQI_SPI_mode === True) begin // SQI mode
+ // read in address[15:0]
+ @(posedge clock) addr[15:12] = SIO[3:0];
+ @(posedge clock) addr[11:8] = SIO[3:0];
+ @(posedge clock) addr[7:4] = SIO[3:0];
+ @(posedge clock) addr[3:0] = SIO[3:0];
+ repeat(6) @(posedge clock) ; // 3 dummy cycles
+ forever begin // output SQI nibble data
+ data = security_id[addr[10:0]]; // read from RSID Memory, limit to 2K address range
+ addr[10:0] = addr[10:0] + 1; // increment address, wrap at 2k boundry
+ @(negedge clock) begin
+ SIO_IO <= #Tclz {True,True,True,True}; // Set I/O controls
+ #Tv SIO_OUT[3:0] = data[7:4]; // send high nibble
+ end
+ @(negedge clock)
+ #Tv SIO_OUT[3:0] = data[3:0]; // send low nibble
+ end
+ end
+ else begin // SPI mode
+ repeat(16) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<1; // shift left address
+ addr[0] = SIO[0]; // read in address bit
+ end
+ end
+ repeat(8) @(posedge clock) ; // dummy cycle
+ forever begin // output SPI serial data
+ data = security_id[addr[10:0]]; // read from RSID Memory, limit to 2K address range
+ addr[10:0] = addr[10:0] + 1; // increment address, wrap at 2k boundry
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ end
+ SPI_RSID_active = False;
+end
+
+
+
+//---------------------------------------------------------------------------
+// erase Memory when CEb inactive ?
+//---------------------------------------------------------------------------
+always @(posedge CEb) begin :erase_label
+reg [31:0] nn;
+ if(erase_active === True) begin
+ erase_ip = True; // set erase in progress flag
+ erase_active = False;
+ disable erase_setup_label;
+ if(valid_addr === True ) begin // check valid address and WSE
+ suspend_addr = erase_addr; // save erase address for possible suspend
+ start_erase = $realtime; // save time of program/erase start
+ for(nn=erase_addr;nn<(erase_addr+erase_size);nn=nn+8) begin // make unknown
+ memory[nn[ADDR_MSB:0]+0] = 8'hxx; memory[nn[ADDR_MSB:0]+1] = 8'hxx;
+ memory[nn[ADDR_MSB:0]+2] = 8'hxx; memory[nn[ADDR_MSB:0]+3] = 8'hxx;
+ memory[nn[ADDR_MSB:0]+4] = 8'hxx; memory[nn[ADDR_MSB:0]+5] = 8'hxx;
+ memory[nn[ADDR_MSB:0]+6] = 8'hxx; memory[nn[ADDR_MSB:0]+7] = 8'hxx;
+ end
+ #time_left for(nn=erase_addr;nn<(erase_addr+erase_size);nn=nn+8) begin // make known at completion of erase
+ memory[nn[ADDR_MSB:0]+0]=8'hFF; memory[nn[ADDR_MSB:0]+1]=8'hFF;
+ memory[nn[ADDR_MSB:0]+2]=8'hFF; memory[nn[ADDR_MSB:0]+3]=8'hFF;
+ memory[nn[ADDR_MSB:0]+4]=8'hFF; memory[nn[ADDR_MSB:0]+5]=8'hFF;
+ memory[nn[ADDR_MSB:0]+6]=8'hFF; memory[nn[ADDR_MSB:0]+7]=8'hFF;
+ WEL = False;
+ end
+ end
+ else if(valid_addr === False) begin
+ $display("\t%m Warning erase address error, erase cmd aborted time=%0.2f",$realtime);
+ end
+ CE_flag = False; BE_flag = False; SE_flag = False;
+ erase_ip = False;
+ end
+end
+//---------------------------------------------------------------------------
+// Erase SE,BE,CE Memory
+//---------------------------------------------------------------------------
+always @(SPI_SE_trg or SPI_BE_trg or SPI_CE_trg) begin :erase_setup_label
+ if(WEL === True && WSE === False) begin // check no suspend of sector/block
+ erase_active = True; // erase loop is active
+ valid_addr = False; // default valid address as bad
+ if(l_spi_cmd===SPI_CE || l_sqi_cmd===SQI_CE) begin // chip erase
+ CE_flag = True; BE_flag=False; SE_flag=False; // set erase type
+ time_left = Tsce; // erase time
+ erase_addr = 0; // chip erase address starts at 0
+ erase_time = Tsce;
+ erase_size = Memsize;
+ if(Chip_proT(erase_addr)===False && suspend_act===False) begin // check protected areas
+ valid_addr = True; // set address as valid
+ end
+ else begin
+ $display("\t%m Warning chip erase error, trying to erase protected Memory cmd aborted time=%0.2f",$realtime);
+ valid_addr = False;
+ end
+ end
+ else begin // read in 24 bit address
+ if(SQI_SPI_mode === False) begin // SPI
+ repeat(24) begin // read in address, set valid address flag when complete
+ erase_addr = erase_addr <<1;
+ @(posedge clock) erase_addr[0] = SIO[0];
+
+ end
+ end
+ else begin // SQI
+ repeat(6) begin // read in address, set valid address flag when complete
+ erase_addr = erase_addr <<4;
+ @(posedge clock) erase_addr[3:0] = SIO[3:0];
+ end
+ end
+ if(Write_proT(erase_addr)===False && PGM_ERASE(erase_addr,resume_addr)===False) valid_addr = True;
+ else begin
+ $display("\t%m Warning erase error, trying to erase protected Memory cmd aborted time=%0.2f",
+ $realtime);
+ valid_addr = False;
+ end
+ end
+ erase_addr = erase_addr & (Memsize-1); // clear unused upper address bits if address is greater tham memory size
+
+ if(l_spi_cmd===SPI_SE || l_sqi_cmd===SQI_SE) begin // Sector Erase ?
+ time_left = Tse; // time left to program
+ SE_flag=True; BE_flag=False; CE_flag = False; // set erase flag for SE
+ erase_size = Sector_Size; // set erase size
+ erase_addr[Sector_MSB:0] = 0; // clear unused lower address bits to 0
+ end
+ else if(l_spi_cmd===SPI_BE || l_sqi_cmd===SQI_BE) begin// Block erase ?
+ BE_flag=True; SE_flag=False; CE_flag = False; // set erase flag for BE
+ time_left = Tbe; // time left to program
+ // set block size, clear unused lower address bits to 0
+ if(erase_addr < (Kilo * 32)) begin erase_size=Block_08k; erase_addr[Block08k_MSB:0]=0; end
+ else if(erase_addr < (Kilo * 64)) begin erase_size=Block_32k; erase_addr[Block32k_MSB:0]=0; end
+ else if(erase_addr >= (Memsize-(Kilo * 32))) begin erase_size=Block_08k; erase_addr[Block08k_MSB:0]=0; end
+ else if(erase_addr >= Memsize-(Kilo * 64)) begin erase_size=Block_32k; erase_addr[Block32k_MSB:0]=0; end
+ else begin erase_size=Block_64k; erase_addr[Block64k_MSB:0]=0; end
+ end
+ forever @(posedge clock) ; // wait here for CEb to become inactice
+
+ erase_active = False; // erase loop is active
+ end
+ else begin
+ $display("\t%m Warning erase error,nested erase not allowed in suspend mode, cmd aborted time=%0.2f",$realtime);
+ end
+end
+
+//---------------------------------------------------------------------------
+// page program Memory when CEb inactive ?
+//---------------------------------------------------------------------------
+always @(posedge CEb) begin :page_program_label
+reg [AF_MSB:0] nn;
+ if(SPI_PP_active === True || SPI_QUAD_PP_active === True) begin // Page_Program is active
+ if(SPI_PP_active === True) begin // Page_Program_label is active
+ disable SPI_PP_label; // disable page program loop
+ SPI_PP_active = False; // clear program loop
+ end
+ else if(SPI_QUAD_PP_active === True) begin // Page_Program_label is active
+ disable SPI_QUAD_PP_label; // disable page program loop
+ SPI_QUAD_PP_active = False; // clear program loop
+ end
+ if(valid_data===True && valid_addr===True ) begin
+ page_program_active = True; // set busy
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ suspend_addr = {pgm_addr[ADDR_MSB:8],8'h00}; // save program address for possible suspend
+ start_erase = $realtime; // save time of program/erase start
+ if (time_left == Tpp) begin
+ for(nn=0;nn<Program_Page_Size;nn=nn+1) begin // save current data in Memory
+ x_pmem[nn] = memory[{pgm_addr[ADDR_MSB:8],nn[7:0]}]; // save Memory data that will be written over
+ memory[{pgm_addr[ADDR_MSB:8],nn[7:0]}] = 8'hxx; // make data 'xx'
+ end
+ end
+ #time_left for(nn=0;nn<Program_Page_Size;nn=nn+1) begin
+ memory[{pgm_addr[ADDR_MSB:8],nn[7:0]}] = x_pmem[nn] & pmem[nn[7:0]];
+ //$display("\tprogram Memory add=%h, data=%h time=%0.2f",{pgm_addr[ADDR_MSB:8],nn[7:0]},(x_pmem[nn] & pmem[nn[7:0]]),$realtime);
+ //$display("\tnn=%h, nn[7:0]=%h, x_pmem[nn]=%h, pmem[nn[7:0]]=%h time=%0.2f",nn,nn[7:0],x_pmem[nn], pmem[nn[7:0]],$realtime);
+ end
+ page_program_active = False; // clear busy
+ WEL = False;
+ end
+ else begin
+ $display("\t%m Warning Page Program error, PP(h02)/PP(h32) cmd aborted time=%0.2f",$realtime);
+ end
+ end
+end
+
+//---------------------------------------------------------------------------
+// QUAD Page program read in address, data, place program data into pgm_addr array
+// When CEb goes high program loop is called using pgm_addr and pmem
+//---------------------------------------------------------------------------
+always @(SPI_QUAD_PP_trg) begin : SPI_QUAD_PP_label
+reg [8:0] pcount;
+reg [7:0] sdata;
+ if((IOC === False) && (SQI_SPI_mode === False)) $display("\t%m Warning SPI QUAD PAGE READ(h32) command aborted when IOC=0 time=%0.2f",$realtime);
+ else begin
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ if(WEL === True && WSP === False) begin // check WSP flag, no program on program suspend active
+ SPI_QUAD_PP_active = True; // program loop is active
+ time_left = Tpp; // time left to program
+ for(pcount=0;pcount<Program_Page_Size;pcount = pcount+1) pmem[pcount] = 8'hFF; // clear program data to all 1's
+
+ repeat(6) begin // read in address, set valid address flag when complete
+ pgm_addr = pgm_addr <<4;
+ @(posedge clock) pgm_addr[3:0] = SIO[3:0];
+ end
+ pgm_addr = pgm_addr & (Memsize-1); // clear upper unused address bits
+ valid_addr = True; // address read complete set valid address flag
+ if(Write_proT(pgm_addr)===False && ERASE_PGM(resume_addr,pgm_addr)===False) begin // check for proteced Memory
+ valid_data = False; // no data valid
+ forever begin // Read program data, loop through all data abort on CEb rising
+ repeat(2) @(posedge clock ) begin // read in byte of data
+ valid_data = True; // at least 1 data clock
+ sdata = sdata <<4;
+ sdata[3:0] = SIO[3:0]; // read data as nibbles
+ end
+ pmem[pgm_addr[7:0]] = sdata; // save byte of page data
+ pgm_addr[7:0] = pgm_addr[7:0] + 1; // increment to next addr of page Memory, wrap on 256 byte bountry
+ end
+ end
+ else begin // protected Memory abort program
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ SPI_QUAD_PP_active = False; // abort program on protected Memory
+ $display("\t%m Warning attempting to program protected page address=%h, PP(h32) cmd aborted time=%0.2f",
+ pgm_addr,$realtime);
+ end
+ SPI_QUAD_PP_active = False;
+ end
+ else begin
+ $display("\t%m Warning Nested Page Program not allowed in program suspend mode time=%0.2f",$realtime);
+ end
+ end
+end
+
+//---------------------------------------------------------------------------
+// Page program read in address, data, place program data into pgm_addr array
+// When CEb goes high program loop is called using pgm_addr and pmem
+//---------------------------------------------------------------------------
+always @(SPI_PP_trg) begin : SPI_PP_label
+reg [8:0] pcount;
+reg [7:0] sdata;
+
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ time_left = Tpp; // time left to program
+ if(WEL === True && WSP === False) begin // check WSP status before programing, no programing on program suspend active
+ SPI_PP_active = True; // program loop is active
+ for(pcount=0;pcount<Program_Page_Size;pcount = pcount+1) pmem[pcount] = 8'hFF; // clear program data to all 1's
+
+ repeat(24) begin // read in address, set valid address flag when complete
+ pgm_addr = pgm_addr <<1;
+ @(posedge clock) pgm_addr[0] = SIO[0];
+ end
+ pgm_addr = pgm_addr & (Memsize-1); // clear upper unused address bits
+ valid_addr = True; // address read complete set valid address flag
+ if(Write_proT(pgm_addr)===False && ERASE_PGM(resume_addr,pgm_addr)===False) begin // check for proteced Memory
+ valid_data = False; // no data valid
+ forever begin // Read program data, loop through all data abort on CEb rising
+ repeat(8) @(posedge clock ) begin // read in byte of data
+ valid_data = True; // at least 1 valid data clock
+ sdata = sdata <<1;
+ sdata[0] = SIO[0];
+ end
+ pmem[pgm_addr[7:0]] = sdata; // save byte of page data
+ pgm_addr[7:0] = pgm_addr[7:0] + 1; // increment to next addr of page Memory, wrap on 256 byte bountry
+ end
+ end
+ else begin // protected Memory abort program
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ SPI_PP_active = False; // abort program on protected Memory
+ if(ERASE_PGM(resume_addr,pgm_addr)===True) begin
+ $display("\t%m Warning attempting to program erase suspended Memory address=%h, PP(h02) cmd aborted time=%0.2f",
+ pgm_addr,$realtime);
+ end
+ else $display("\t%m Warning attempting to program protected page address=%h, PP(h02) cmd aborted time=%0.2f",pgm_addr,$realtime);
+ end
+ SPI_PP_active = False;
+ end
+ else begin
+ $display("\t%m Warning Nested Page Program not allowed in program suspend mode time=%0.2f",$realtime);
+ end
+end
+
+//---------------------------------------------------------------------------
+// SPI Read block protection register
+//---------------------------------------------------------------------------
+always @(SPI_RBPR_trg) begin :SPI_RBPR_label
+reg [PROTECT_REG_MSB:0] tmp_protect; // protection register definishion max size for 32M-bit
+ SPI_RBPR_active = True; // read l status loop is active
+ tmp_protect = protect_or; // copy protection reg
+ if(SQI_SPI_mode === True) begin
+ @(negedge clock) ; // wait here for clock falling
+ @(negedge clock) ; // wait here for clock falling
+ forever begin // out put SPI data bit by
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv begin // output nibble of data
+ SIO_OUT[3]=tmp_protect[PROTECT_REG_MSB]; tmp_protect = tmp_protect <<1; // shift data left
+ SIO_OUT[2]=tmp_protect[PROTECT_REG_MSB]; tmp_protect = tmp_protect <<1; // shift data left
+ SIO_OUT[1]=tmp_protect[PROTECT_REG_MSB]; tmp_protect = tmp_protect <<1; // shift data left
+ SIO_OUT[0]=tmp_protect[PROTECT_REG_MSB]; tmp_protect = tmp_protect <<1; // shift data left
+ end
+ end
+ end
+ else begin
+ forever begin // out put SPI data bit by
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1]=tmp_protect[PROTECT_REG_MSB]; // shift out protection data
+ tmp_protect = tmp_protect <<1; // shift data left
+ end
+ end
+ SPI_RBPR_active = False; // read status loop is inactive
+end
+
+//----------------------------------------------------------------------------
+// Program Block Protection Register volatile -volitale
+//----------------------------------------------------------------------------
+always @(SPI_WBPR_trg ) begin :SPI_WBPR_label
+reg [8:0] ncount;
+reg [7:0] bit_count; // number of bits to read
+ if(suspend_act===False && WBPR_protection_lck===False && WPLD===False) begin // check truth table table 2 in spec
+ SPI_WBPR_active = True; // this loop is active
+ ncount = PROTECT_REG_MSB;
+ if(SQI_SPI_mode === True) begin // SQI mode
+ repeat((PROTECT_REG_MSB+1)/4) begin
+ @(posedge clock) begin
+ protect[ncount] = SIO[3]; ncount = ncount - 1;
+ protect[ncount] = SIO[2]; ncount = ncount - 1;
+ protect[ncount] = SIO[1]; ncount = ncount - 1;
+ protect[ncount] = SIO[0]; ncount = ncount - 1;
+ end
+ end
+ end
+ else begin // SPI mode
+ repeat(PROTECT_REG_MSB+1) begin
+ @(posedge clock) protect[ncount] = SIO[0]; // save protection data
+ ncount = ncount - 1; // count the number of clocks
+ end
+ end
+ WEL = False; // clear WEL on WBPR command
+ forever @(posedge clock) ; // if to many clocks wait here for CEb to go inactive
+ end
+ else begin
+ if(WEL === False)
+ $display("\t%m Warning status flag WEL=0, WBPR(h42) cmd aborted time=%0.2f",$realtime);
+ else if(suspend_act===True)
+ $display("\t%m Warning WBPR not allowed in suspend mode, WBPR[h42) cmd aborted time=%0.2f",$realtime);
+ else if(WBPR_protection_lck === True)
+ $display("\t%m Warning Block Protection Reg protected, WBPR(h42) cmd aborted time=%0.2f",$realtime);
+ end
+ SPI_WBPR_active = False; // this loop is inactive
+end
+//----------------------------------------------------------------------------
+// Program Block Protection Register non-volitale
+//----------------------------------------------------------------------------
+always @(SPI_nVWLDR_trg) begin :SPI_nVWLDR_cmd_label
+reg [8:0] ncount;
+reg [7:0] bit_count; // number of bits to read
+ t_wlldr_mem = wlldr_mem; // save current value of wlldr_mem
+ if(suspend_act===False && WBPR_protection_lck === False) begin // check truth table table 2 in spec
+ SPI_nVWLDR_cmd_active = True; // this loop is active
+ ncount = PROTECT_REG_MSB;
+
+ if(SQI_SPI_mode === True) begin // SQI mode
+ repeat((PROTECT_REG_MSB+1)/4) begin
+ @(posedge clock) begin
+ t_wlldr_mem[ncount] = SIO[3]; ncount = ncount - 1;
+ t_wlldr_mem[ncount] = SIO[2]; ncount = ncount - 1;
+ t_wlldr_mem[ncount] = SIO[1]; ncount = ncount - 1;
+ t_wlldr_mem[ncount] = SIO[0]; ncount = ncount - 1;
+ end
+ end
+ end
+ else begin //SPI mode
+ repeat(PROTECT_REG_MSB+1) begin
+ @(posedge clock) t_wlldr_mem[ncount] = SIO[0]; // save non-volatile data
+ ncount = ncount - 1; // count the number of clocks
+ end
+ end
+
+ forever @(posedge clock) ; // if to many clocks wait here for CEb to go inactive
+ end
+ else begin
+ if(WBPR_protection_lck === True)
+ $display("\t%m Warning nVWLDR(hE8) cmd aborted (protected) time=%0.2f",$realtime);
+ else if(suspend_act===True)
+ $display("\t%m Warning nVWLDR(E8) not allowed in suspend mode, nVWLDR(hE8) cmd aborted time=%0.2f",$realtime);
+ end
+ SPI_nVWLDR_cmd_active = False; // this loop is inactive
+end
+
+//---------------------------------------------------------------------------
+// nVWLDR program command, program wlldr_mem[], wait for program complete
+//---------------------------------------------------------------------------
+always @(posedge CEb) begin :SPI_nVWLDR_label
+reg [7:0]nn;
+ if(SPI_nVWLDR_cmd_active===True && suspend_act===False) begin
+ disable SPI_nVWLDR_cmd_label;
+ SPI_nVWLDR_cmd_active = False;
+ SPI_nVWLDR_active = True; // set busy
+ // make sure read protect flags are never set, clear the read flags
+ nn=0; repeat(8) begin t_wlldr_mem[PROTECT_REG_MSB-nn]=False; nn=nn+2; end
+ #Tpp wlldr_mem = wlldr_mem | t_wlldr_mem; // copy tmp data to final data, wait for program to complete
+ SPI_nVWLDR_active = False; // clear busy
+ WEL = False; // clear WEL on WBPR command
+ end
+end
+
+//---------------------------------------------------------------------------
+// SPI Read configuration register
+//---------------------------------------------------------------------------
+always @(SPI_RDCR_trg) begin :SPI_RDCR_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+ SPI_RDCR_active = True; // read l status loop is active
+ if(SQI_SPI_mode === True) begin // SQI mode ?
+ repeat(2) @(negedge clock) ; // dummy cycle
+ forever begin // out put SPI data bit by
+ data = config_reg; // byte boundry, save config register
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output high nibble
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output low nibble
+ end
+ end
+ else begin // SPI mode
+ forever begin // out put SPI data bit by bit
+ data = config_reg; // byte boundry, read configuration register
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ end
+ SPI_RDCR_active = False; // read status loop is inactive
+end
+
+//---------------------------------------------------------------------------
+// SPI Read status register
+//---------------------------------------------------------------------------
+always @(SPI_RDSR_trg) begin :SPI_RDSR_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+ SPI_RDSR_active = True; // read l status loop is active
+ if(SQI_SPI_mode === True) begin // SQI mode ?
+ repeat(2) @(negedge clock) ; // dummy cycle
+ forever begin // out put SPI data bit by
+ data = status; // byte boundry, save status register
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output high nibble data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output low nibble data
+ end
+ end
+ else begin // SPI mode
+ forever begin // out put SPI data bit by
+ data = status; // byte boundry, save status register
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ end
+ SPI_RDSR_active = False; // read status loop is inactive
+end
+
+
+//----------------------------------------------------------------------------
+// SPI Mode Read Serial Flash Discoverable Parameters
+//----------------------------------------------------------------------------
+always @(SPI_SFDP_trg ) begin :SPI_SFDP_label
+reg [7:0] data;
+reg [10:0] addr; // max value 2K-1
+ SPI_SFDP_active = True;
+ repeat(24) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<1; // shift left address
+ addr[0] = SIO[0]; // read in address bit
+ end
+ end
+ repeat(8) @(posedge clock) ; // dummy cycle
+ forever begin // output SPI serial data
+ data = SFDP[addr]; // read from SFDP Memory
+ addr = addr + 1; // increment address
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ SPI_SFDP_active = False;
+end
+
+
+//----------------------------------------------------------------------------
+// SPI Mode Read JDEC registers
+//----------------------------------------------------------------------------
+always @(SPI_JEDEC_ID_trg ) begin :SPI_JEDEC_ID_label
+reg [1:0] ptr;
+reg [7:0] data;
+ SPI_JEDEC_ID_active = True;
+ ptr = 0;
+ if(SQI_SPI_mode === True)
+ begin
+ @(negedge clock) ;
+ @(negedge clock) ;
+ end
+ forever begin // output SPI serial data
+ if(ptr === 2'b00) data = MANUFACTURE;
+ else if(ptr === 2'b01) data = Memory_Type;
+ else if(ptr === 2'b10 ) data = Memory_Capacity;
+ if( ptr === 2'b10) ptr = 0; else ptr = ptr + 1;
+ if(SQI_SPI_mode === True) begin // SQI mode
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output nibble bit data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output 1 nibble data
+ end
+ else begin // SPI mode
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ end
+ SPI_JEDEC_ID_active = False;
+end
+
+//----------------------------------------------------------------------------
+// Deep Power Down Reset Read device ID
+//----------------------------------------------------------------------------
+always @(SPI_DPD_RST_trg ) begin :SPI_DPD_RST_RDID_label
+reg [7:0] data;
+ SPI_DPD_RST_RDID_active = True;
+ forever begin // output SPI serial data
+ data = Memory_Capacity;
+ if(SQI_SPI_mode === True) begin // SQI mode
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output nibble bit data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output 1 nibble data
+ end
+ else begin // SPI mode
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ end
+ SPI_DPD_RST_RDID_active = False;
+end
+
+//----------------------------------------------------------------------------
+// Deep Power Down Reset - Recovery from Deep Power Down Mode
+//----------------------------------------------------------------------------
+always @(SPI_DPD_RST_trg ) begin :SPI_DPD_RST_label
+reg [7:0] data;
+ @(posedge CEb)
+ #Tsbr DPD = False;
+end
+
+//---------------------------------------------------------------------------
+// SPI Read with Burst
+//---------------------------------------------------------------------------
+always @(SPI_RBSPI_trg) begin :SPI_RBSPI_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+ if(IOC === False && SQI_SPI_mode === False) $display("\t%m Warning SPI BURST READ(hEC) command aborted when IOC=0 time=%0.2f",$realtime);
+ else begin
+ SPI_RBSPI_active = True; // read loop is active
+ repeat(6) begin
+ @(posedge clock) ; // wait for clk rising
+ addr = addr <<4; // shift left address
+ addr[3:0] = SIO[3:0]; // read in address nibble
+ end
+ // read mode
+ repeat(6) @(posedge clock) ; // 3 dummy cycles
+
+ forever begin // output SPI data 1 byte
+ data = (Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output 4 bit data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output 4 bit data
+ if(burst_length===Burst8) addr[Burst8_MSB:0]=addr[Burst8_MSB:0] + 1; // inc address with wrap
+ else if(burst_length===Burst16) addr[Burst16_MSB:0]=addr[Burst16_MSB:0] + 1;
+ else if(burst_length===Burst32) addr[Burst32_MSB:0]=addr[Burst32_MSB:0] + 1;
+ else if(burst_length===Burst64) addr[Burst64_MSB:0]=addr[Burst64_MSB:0] + 1;
+ end
+ SPI_RBSPI_active = False; // read loop is inactive
+ end
+end
+
+
+
+//---------------------------------------------------------------------------
+// SPI Set Burst Count
+//---------------------------------------------------------------------------
+always @(SPI_SB_trg) begin :SPI_SB_label
+reg [7:0] bl;
+ SPI_SB_active = True;
+ if(SQI_SPI_mode === True) begin
+ @(posedge clock) bl[7:4] = SIO[3:0];
+ @(posedge clock) bl[3:0] = SIO[3:0];
+ end
+ else begin
+ @(posedge clock) bl[7] = SIO[0]; // MSB bit of burst count
+ @(posedge clock) bl[6] = SIO[0]; // --- bit of burst count
+ @(posedge clock) bl[5] = SIO[0]; // --- bit of burst count
+ @(posedge clock) bl[4] = SIO[0]; // --- bit of burst count
+ @(posedge clock) bl[3] = SIO[0]; // --- bit of burst count
+ @(posedge clock) bl[2] = SIO[0]; // --- bit of burst count
+ @(posedge clock) bl[1] = SIO[0]; // --- bit of burst count
+ @(posedge clock) bl[0] = SIO[0]; // LSB bit of burst count
+ end
+ burst_length = bl; // set register
+
+ if( |burst_length[7:2] !== 1'b0) begin // check for legal values of burst count
+ $display("\t%m Warning SPI Set Burst Instruction has invalid data=%h, time=%0.2f", burst_length,$realtime);
+ $display("\t%m Setting bits[7:2] of Burst Count Register to 0");
+ burst_length[7:2] = 6'b000000; // clear upper bits
+ end
+ forever @(posedge clock) ; // wait for end of operation, Disable cmd will exit this line
+ SPI_SB_active = False;
+end
+
+
+
+//---------------------------------------------------------------------------
+// SQI High Speed Read
+//---------------------------------------------------------------------------
+always @(SQI_HS_READ_trg) begin :SQI_HS_READ_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+reg [7:0] count;
+ SQI_HS_READ_active = True; // Read loop is active
+ if(Mode_Configuration[7:4]===4'hA) begin // if no command header read in 1st address nibble
+ addr[3:0] = SIO[3:0]; count = 5; // read in first address nibble
+ end
+ else count = 6; // read 6 times if command header
+ repeat(count) begin
+ @(posedge clock) // wait for clk rising
+ addr = addr <<4; // shift left address
+ addr[3:0] = SIO[3:0]; // read in address nibble
+ end
+ // read mode
+ @(posedge clock) Mode_Configuration[7:4]=SIO[3:0]; // read in Mode configuration
+ @(posedge clock) Mode_Configuration[3:0]=SIO[3:0]; // read in Mode configuration
+
+ // 4 dummy nibbles
+ repeat(4) @(posedge clock) ; // 2 dummy bytes
+
+ forever begin // output SPI data 1 byte
+ data = (Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output 4 bit data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output 4 bit data
+ addr = addr + 1; // increment to next address on byte boundry
+ end
+ SQI_HS_READ_active = False;
+end
+
+
+
+//---------------------------------------------------------------------------
+// SPI_READ DUAL IO
+//---------------------------------------------------------------------------
+always @(SPI_SDIOR_trg) begin :SPI_SDIOR_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+reg [7:0] count;
+ SPI_SDIOR_active = True;
+ if(Mode_Configuration[7:4]===4'hA) begin // if no command header read in 1st address nibble
+ addr[1:0] = SIO[1:0]; count = 11; // read in first address 2-bits
+ end
+ else count = 12; // read 6 times if command header
+ repeat(count) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<2; // shift left address
+ addr[1:0] = SIO[1:0]; // read in address nibble
+ end
+ end
+ // read mode
+ @(posedge clock) Mode_Configuration[7:6]=SIO[1:0]; // read in Mode configuration
+ @(posedge clock) Mode_Configuration[5:4]=SIO[1:0]; // read in Mode configuration
+ @(posedge clock) Mode_Configuration[3:2]=SIO[1:0]; // read in Mode configuration
+ @(posedge clock) Mode_Configuration[1:0]=SIO[1:0]; // read in Mode configuration
+
+ forever begin // output SPI data 1 byte
+ data = (Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:6]; // output 4 bit data
+ @(negedge clock) #Tv SIO_OUT[3:0] = data[5:4];
+ @(negedge clock) #Tv SIO_OUT[3:0] = data[3:2];
+ @(negedge clock) #Tv SIO_OUT[3:0] = data[1:0];
+ addr = addr + 1; // increment to next address on byte boundry
+ end
+ SPI_SDIOR_active = False;
+end
+
+
+//---------------------------------------------------------------------------
+// SPI_READ QUAD IO
+//---------------------------------------------------------------------------
+always @(SPI_QUAD_IO_READ_trg) begin :SPI_QUAD_IO_READ_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+reg [7:0] count;
+ if(IOC === False) $display("\t%m Warning SPI IO QUAD READ(hEB) command aborted when IOC=0 time=%0.2f",$realtime);
+ else begin
+ SPI_QUAD_IO_READ_active = True;
+ if(Mode_Configuration[7:4]===4'hA) begin // if no command header read in 1st address nibble
+ addr[3:0] = SIO[3:0]; count = 5; // read in first address nibble
+ end
+ else count = 6; // read 6 times if command header
+ repeat(count) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<4; // shift left address
+ addr[3:0] = SIO[3:0]; // read in address nibble
+ end
+ end
+ // read mode
+ @(posedge clock) Mode_Configuration[7:4]=SIO[3:0]; // read in Mode configuration
+ @(posedge clock) Mode_Configuration[3:0]=SIO[3:0]; // read in Mode configuration
+
+ // 2 dummy bytes
+ repeat(4) @(posedge clock) ; // 2 dummy bytes
+
+ forever begin // output SPI data 1 byte
+ data = (Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output 4 bit data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output 4 bit data
+ addr = addr + 1; // increment to next address on byte boundry
+ end
+ SPI_QUAD_IO_READ_active = False;
+ end
+end
+
+//---------------------------------------------------------------------------
+// SPI_READ QUAD
+//---------------------------------------------------------------------------
+always @(SPI_QUAD_READ_trg) begin :SPI_QUAD_READ_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+ if(IOC === False) $display("\t%m Warning SPI QUAD READ(h6B) command aborted when IOC=0 time=%0.2f",$realtime);
+ else begin
+ SPI_READ_QUAD_active = True; // this loop is active
+ repeat(24) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<1; // shift left address
+ addr[0] = SIO[0]; // read in address bit
+ end
+ end
+ // run 8 dummy cycles
+ repeat(8) @(negedge clock) ;
+ forever begin // output SPI data 1 byte
+ data = (Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {True,True,True,True}; // Turn on IO control SIO[3:0]
+ #Tv SIO_OUT[3:0] = data[7:4]; // output 4 bit data
+ @(negedge clock) ; // wait here for clock falling
+ #Tv SIO_OUT[3:0] = data[3:0]; // output 4 bit data
+ addr = addr + 1; // increment to next address on byte boundry
+ end
+ SPI_READ_QUAD_active = False; // this loop is active
+ end
+end
+
+//---------------------------------------------------------------------------
+// SPI_READ dual, SDOR
+//---------------------------------------------------------------------------
+always @(SPI_SDOR_trg) begin :SPI_SDOR_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+ SPI_SDOR_active = True; // read loop is active
+ repeat(24) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<1; // shift left address
+ addr[0] = SIO[0]; // read in address bit
+ end
+ end
+ repeat(8) @(negedge clock) ; // dummy cycle for read
+ forever begin // out put SPI data 2 bits at a time
+ data=(Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ addr = addr + 1; // increment to next address on byte boundry
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,True}; // Turn on IO control SIO[1:0]
+ #Tv SIO_OUT[1:0] = data[7:6]; // output 2 bits data
+ @(negedge clock) #Tv SIO_OUT[1:0] = data[5:4]; // output 2 bits data
+ @(negedge clock) #Tv SIO_OUT[1:0] = data[3:2]; // output 2 bits data
+ @(negedge clock) #Tv SIO_OUT[1:0] = data[1:0]; // output 2 bits data
+ end
+ SPI_SDOR_active = False; // read loop is inactive
+end
+
+//---------------------------------------------------------------------------
+// SPI_READ 80/50Mhz
+//---------------------------------------------------------------------------
+always @(SPI_READ_trg) begin :SPI_READ_label
+reg [AF_MSB:0] addr; // address storage
+reg [7:0] data; // tmp storage of data
+ SPI_READ_active = True; // read loop is active
+ repeat(24) begin
+ @(posedge clock) begin // wait for clk rising
+ addr = addr <<1; // shift left address
+ addr[0] = SIO[0]; // read in address bit
+ end
+ end
+ if(l_spi_cmd === SPI_HS_READ) repeat(8) @(negedge clock) ; // added dummy cycle for high speed read
+ if(l_spi_cmd === SPI_READ) read_slow_flag = True; // set timing checks to slow read for SCK timing check
+ forever begin // out put SPI data bit by
+ data = (Read_proT(addr)===True) ? 8'h00 : memory[addr[ADDR_MSB:0]]; // get data at addr
+ addr = addr + 1; // increment to next address on byte boundry
+ repeat(8) begin
+ @(negedge clock) ; // wait here for clock falling
+ SIO_IO <= #Tclz {False,False,True,False}; // Turn on IO control SIO[1]
+ #Tv SIO_OUT[1] = data[7]; // output 1 bit data
+ data = data <<1; // shift data left
+ end
+ end
+ read_slow_flag = False; // set timing checks back to normal
+ SPI_READ_active = False; // read loop is inactive
+end
+
+//---------------------------------------------------------------------------
+// chip por setup
+//---------------------------------------------------------------------------
+initial begin
+
+ for(cnt=0;cnt<(Kilo*2);cnt=cnt+1) security_id[cnt] = 8'hFF; // init security Memory
+ for(cnt=0;cnt<Memsize;cnt=cnt+8) begin // init flash Memory
+ memory[cnt+0] = 8'hFF; memory[cnt+1] = 8'hFF; memory[cnt+2] = 8'hFF; memory[cnt+3] = 8'hFF;
+ memory[cnt+4] = 8'hFF; memory[cnt+5] = 8'hFF; memory[cnt+6] = 8'hFF; memory[cnt+7] = 8'hFF;
+ end
+
+ wlldr_mem = WLLD_value; // set contents of write-lock lock down register, non-volatile
+ SEC = SECURITY_LOCKOUT_VALUE; // Security ID Status, non-volatile
+ WPLD = False; // write protection lockdown status, non-volatile
+ clock = 1'b0;
+ WPEN = INIT_WPEN; // write protect pin enable, non-volatile bit
+ PE = False; // default unused configuration register bits
+ EE = False; // default unused configuration register bits
+ DPD = False; // deep power down mode
+ pgm_sus_reset = False; // part is busy if reset while programming is suspended
+ #0 ->reset; // call reset block
+
+ // set volatile protect register to initial condition
+ for(cnt=0;cnt<=PROTECT_REG_MSB;cnt=cnt+1) protect[cnt] = 1'b1; // all protect bits set
+ for(cnt=PROTECT_REG_MSB;cnt > (PROTECT_REG_MSB-16); cnt=cnt-2) protect[cnt] = 1'b0; // read protect bits cleared
+
+ // init serial flash discoverable parameters
+ for(cnt=0;cnt<(Kilo*2);cnt=cnt+1) SFDP[cnt] = 8'hFF; // init to all FF
+
+ SFDP['h000] = 8'h53;
+ SFDP['h001] = 8'h46;
+ SFDP['h002] = 8'h44;
+ SFDP['h003] = 8'h50;
+ SFDP['h004] = 8'h06;
+ SFDP['h005] = 8'h01;
+ SFDP['h006] = 8'h02;
+ SFDP['h007] = 8'hFF;
+ SFDP['h008] = 8'h00;
+ SFDP['h009] = 8'h06;
+ SFDP['h00A] = 8'h01;
+ SFDP['h00B] = 8'h10;
+ SFDP['h00C] = 8'h30;
+ SFDP['h00D] = 8'h00;
+ SFDP['h00E] = 8'h00;
+ SFDP['h00F] = 8'hFF;
+ SFDP['h010] = 8'h81;
+ SFDP['h011] = 8'h00;
+ SFDP['h012] = 8'h01;
+ SFDP['h013] = 8'h06;
+ SFDP['h014] = 8'h00;
+ SFDP['h015] = 8'h01;
+ SFDP['h016] = 8'h00;
+ SFDP['h017] = 8'hFF;
+ SFDP['h018] = 8'hBF;
+ SFDP['h019] = 8'h00;
+ SFDP['h01A] = 8'h01;
+ SFDP['h01B] = 8'h18;
+ SFDP['h01C] = 8'h00;
+ SFDP['h01D] = 8'h02;
+ SFDP['h01E] = 8'h00;
+ SFDP['h01F] = 8'h01;
+ SFDP['h030] = 8'hFD;
+ SFDP['h031] = 8'h20;
+ SFDP['h032] = 8'hF1;
+ SFDP['h033] = 8'hFF;
+ SFDP['h034] = 8'hFF;
+ SFDP['h035] = 8'hFF;
+ SFDP['h036] = 8'h7F;
+ SFDP['h037] = 8'h00;
+ SFDP['h038] = 8'h44;
+ SFDP['h039] = 8'hEB;
+ SFDP['h03A] = 8'h08;
+ SFDP['h03B] = 8'h6B;
+ SFDP['h03C] = 8'h08;
+ SFDP['h03D] = 8'h3B;
+ SFDP['h03E] = 8'h80;
+ SFDP['h03F] = 8'hBB;
+ SFDP['h040] = 8'hFE;
+ SFDP['h041] = 8'hFF;
+ SFDP['h042] = 8'hFF;
+ SFDP['h043] = 8'hFF;
+ SFDP['h044] = 8'hFF;
+ SFDP['h045] = 8'hFF;
+ SFDP['h046] = 8'h00;
+ SFDP['h047] = 8'hFF;
+ SFDP['h048] = 8'hFF;
+ SFDP['h049] = 8'hFF;
+ SFDP['h04A] = 8'h44;
+ SFDP['h04B] = 8'h0B;
+ SFDP['h04C] = 8'h0C;
+ SFDP['h04D] = 8'h20;
+ SFDP['h04E] = 8'h0D;
+ SFDP['h04F] = 8'hD8;
+ SFDP['h050] = 8'h0F;
+ SFDP['h051] = 8'hD8;
+ SFDP['h052] = 8'h10;
+ SFDP['h053] = 8'hD8;
+ SFDP['h054] = 8'h20;
+ SFDP['h055] = 8'h91;
+ SFDP['h056] = 8'h48;
+ SFDP['h057] = 8'h24;
+ SFDP['h058] = 8'h80;
+ SFDP['h059] = 8'h6F;
+ SFDP['h05A] = 8'h1D;
+ SFDP['h05B] = 8'h81;
+ SFDP['h05C] = 8'hED;
+ SFDP['h05D] = 8'h0F;
+ SFDP['h05E] = 8'h77;
+ SFDP['h05F] = 8'h38;
+ SFDP['h060] = 8'h30;
+ SFDP['h061] = 8'hB0;
+ SFDP['h062] = 8'h30;
+ SFDP['h063] = 8'hB0;
+ SFDP['h064] = 8'hF7;
+ SFDP['h065] = 8'hA9;
+ SFDP['h066] = 8'hD5;
+ SFDP['h067] = 8'h5C;
+ SFDP['h068] = 8'h29;
+ SFDP['h069] = 8'hC2;
+ SFDP['h06A] = 8'h5C;
+ SFDP['h06B] = 8'hFF;
+ SFDP['h06C] = 8'hF0;
+ SFDP['h06D] = 8'h30;
+ SFDP['h06E] = 8'hC0;
+ SFDP['h06F] = 8'h80;
+ SFDP['h100] = 8'hFF;
+ SFDP['h101] = 8'h00;
+ SFDP['h102] = 8'h04;
+ SFDP['h103] = 8'hFF;
+ SFDP['h104] = 8'hF3;
+ SFDP['h105] = 8'h7F;
+ SFDP['h106] = 8'h00;
+ SFDP['h107] = 8'h00;
+ SFDP['h108] = 8'hF5;
+ SFDP['h109] = 8'h7F;
+ SFDP['h10A] = 8'h00;
+ SFDP['h10B] = 8'h00;
+ SFDP['h10C] = 8'hF9;
+ SFDP['h10D] = 8'hFF;
+ SFDP['h10E] = 8'h0D;
+ SFDP['h10F] = 8'h00;
+ SFDP['h110] = 8'hF5;
+ SFDP['h111] = 8'h7F;
+ SFDP['h112] = 8'h00;
+ SFDP['h113] = 8'h00;
+ SFDP['h114] = 8'hF3;
+ SFDP['h115] = 8'h7F;
+ SFDP['h116] = 8'h00;
+ SFDP['h117] = 8'h00;
+ SFDP['h200] = 8'hBF;
+ SFDP['h201] = 8'h26;
+ SFDP['h202] = 8'h58;
+ SFDP['h203] = 8'hFF;
+ SFDP['h204] = 8'hB9;
+ SFDP['h205] = 8'hDF;
+ SFDP['h206] = 8'hFD;
+ SFDP['h207] = 8'hFF;
+ SFDP['h208] = 8'h65;
+ SFDP['h209] = 8'hF1;
+ SFDP['h20A] = 8'h95;
+ SFDP['h20B] = 8'hF1;
+ SFDP['h20C] = 8'h32;
+ SFDP['h20D] = 8'hFF;
+ SFDP['h20E] = 8'h0A;
+ SFDP['h20F] = 8'h12;
+ SFDP['h210] = 8'h23;
+ SFDP['h211] = 8'h46;
+ SFDP['h212] = 8'hFF;
+ SFDP['h213] = 8'h0F;
+ SFDP['h214] = 8'h19;
+ SFDP['h215] = 8'h32;
+ SFDP['h216] = 8'h0F;
+ SFDP['h217] = 8'h19;
+ SFDP['h218] = 8'h19;
+ SFDP['h219] = 8'h03;
+ SFDP['h21A] = 8'h0A;
+ SFDP['h21B] = 8'hFF;
+ SFDP['h21C] = 8'hFF;
+ SFDP['h21D] = 8'hFF;
+ SFDP['h21E] = 8'hFF;
+ SFDP['h21F] = 8'hFF;
+ SFDP['h220] = 8'h00;
+ SFDP['h221] = 8'h66;
+ SFDP['h222] = 8'h99;
+ SFDP['h223] = 8'h38;
+ SFDP['h224] = 8'hFF;
+ SFDP['h225] = 8'h05;
+ SFDP['h226] = 8'h01;
+ SFDP['h227] = 8'h35;
+ SFDP['h228] = 8'h06;
+ SFDP['h229] = 8'h04;
+ SFDP['h22A] = 8'h02;
+ SFDP['h22B] = 8'h32;
+ SFDP['h22C] = 8'hB0;
+ SFDP['h22D] = 8'h30;
+ SFDP['h22E] = 8'h72;
+ SFDP['h22F] = 8'h42;
+ SFDP['h230] = 8'h8D;
+ SFDP['h231] = 8'hE8;
+ SFDP['h232] = 8'h98;
+ SFDP['h233] = 8'h88;
+ SFDP['h234] = 8'hA5;
+ SFDP['h235] = 8'h85;
+ SFDP['h236] = 8'hC0;
+ SFDP['h237] = 8'h9F;
+ SFDP['h238] = 8'hAF;
+ SFDP['h239] = 8'h5A;
+ SFDP['h23A] = 8'hB9;
+ SFDP['h23B] = 8'hAB;
+ SFDP['h23C] = 8'h06;
+ SFDP['h23D] = 8'hEC;
+ SFDP['h23E] = 8'h06;
+ SFDP['h23F] = 8'h0C;
+ SFDP['h240] = 8'h00;
+ SFDP['h241] = 8'h03;
+ SFDP['h242] = 8'h08;
+ SFDP['h243] = 8'h0B;
+ SFDP['h244] = 8'hFF;
+ SFDP['h245] = 8'hFF;
+ SFDP['h246] = 8'hFF;
+ SFDP['h247] = 8'hFF;
+ SFDP['h248] = 8'hFF;
+ SFDP['h249] = 8'h07;
+ SFDP['h24A] = 8'hFF;
+ SFDP['h24B] = 8'hFF;
+ SFDP['h24C] = 8'h02;
+ SFDP['h24D] = 8'h02;
+ SFDP['h24E] = 8'hFF;
+ SFDP['h24F] = 8'h06;
+ SFDP['h250] = 8'h03;
+ SFDP['h251] = 8'h00;
+ SFDP['h252] = 8'hFD;
+ SFDP['h253] = 8'hFD;
+ SFDP['h254] = 8'h04;
+ SFDP['h255] = 8'h04;
+ SFDP['h256] = 8'h00;
+ SFDP['h257] = 8'hFC;
+ SFDP['h258] = 8'h03;
+ SFDP['h259] = 8'h00;
+ SFDP['h25A] = 8'hFE;
+ SFDP['h25B] = 8'hFE;
+ SFDP['h25C] = 8'h02;
+ SFDP['h25D] = 8'h02;
+ SFDP['h25E] = 8'h07;
+ SFDP['h25F] = 8'h0E;
+end
+
+always @(reset) begin
+
+ IOC = True; //False; // clear IOC status
+ WSE = False; // erase suspend status
+ RSTEN = False; // enable reset disabled
+ read_slow_flag = False;
+ RES = False; // reserved status bit 6
+ SIO_OUT = 4'h0; // turn off SIO drivers
+ spi_count = 0; // clear spi clock counter
+ spi_cmd = SPI_NOP; // clear SPI command register
+ sqi_cmd = SQI_NOP; // clear SQI command register
+ l_sqi_cmd = SQI_NOP;
+ l_spi_cmd = SPI_NOP;
+ RSTQIO_cmd = SPI_NOP;
+ SQI_SPI_mode = False; // set to spi mode
+ s_BE_flag=False; s_SE_flag=False;
+ SPI_READ_active = False;
+ SPI_READ_QUAD_active=False;
+ SPI_SDOR_active = False;
+ SPI_RDSR_active = False;
+ SPI_QUAD_IO_READ_active=False;
+ Mode_Configuration = 8'hFF; // default Mode Configuration
+ CE_flag=False; SE_flag=False; BE_flag=False;
+ SPI_SB_active = False;
+ SPI_JEDEC_ID_active = False;
+ SPI_SFDP_active = False;
+ burst_length=0; // set burst length to 8
+ SPI_PSID_ip = False;
+ SQI_HS_READ_active=False;
+ SPI_WRSR_PGM_active = False;
+ SPI_RBSPI_active=False;
+ SPI_WBPR_active = False;
+ SPI_nVWLDR_cmd_active=False;
+ SPI_RBPR_active = False;
+ SPI_SDIOR_active = False;
+ SPI_PP_active = False;
+ SQI_PP_active = False;
+ valid_addr = False; // default valid address
+ valid_data = False; // default valid data
+ SPI_RDCR_active = False;
+ SPI_QUAD_PP_active = False;
+ SPI_RSID_active = False;
+ erase_active = False; // erase loop is active
+ WEL = False; // clear Write enable latch in status register
+ #0 if(BUSY===True) begin // if busy abort erase/program in progress
+ if(page_program_active === True) begin // abort PP program
+ disable page_program_label; // abort spi page program in progress
+ disable Sec_ID_pgm_label; // Security ID program
+ #Trp page_program_active = False; // clear busy on program , wait for program abort time
+ SPI_PSID_ip = False; // abort security ID program loop
+ end
+ else if( erase_ip === True) begin // abort erase SE,BE,CE
+ WSP = False; // write suspend status
+ disable erase_label;
+ #Tre erase_ip = False;
+ end
+ else if(SPI_LSID_active === True) begin // abort Security ID lockout
+ disable SPI_LSID_label;
+ #Trp SPI_LSID_active = False;
+ SEC = 1'bx;
+ end
+ else if(SPI_WRSR_active===True) begin // reset during status register programing time
+ disable SPI_WRSR_PGM;
+ if(wsr_creg[7]===False) begin // WPEN <- 0
+ #Trp SPI_WRSR_active=False;
+ end
+ else begin // WPEN <- 1
+ #Tre SPI_WRSR_active=False;
+ end
+ end
+ else if(SPI_nVWLDR_active===True) begin // reset during WLLDR programing time
+ disable SPI_nVWLDR_label;
+ #Trp SPI_nVWLDR_active=False;
+ end
+ else if(SPI_WRSU_active===True) begin // reset during suspend #Tws time
+ disable SPI_WRSU_label; // exit suspent loop
+ #Trp SPI_WRSU_active=False; // clear suspend loop active flag
+ end
+ end
+ if (WSP === True) begin
+ WSP = False; // write suspend status
+ pgm_sus_reset = True;
+ #Trp pgm_sus_reset = False;
+ end
+
+ WSP = False; // write suspend status
+ suspend_addr=0; resume_addr=0;
+ SPI_WRSU_active = False;
+ SPI_PSID_active = False;
+ page_program_active = False;
+ erase_ip = False;
+ SPI_LSID_active = False;
+ SPI_WRSR_active=False;
+ SPI_nVWLDR_active=False;
+ SPI_LSID_active = False;
+ WEL = False; // clear Write enable latch in status register
+end
+
+//-------------------------------------------------------------
+// protection functions, return True/False for read protection
+// given and address
+//-------------------------------------------------------------
+function Read_proT;
+input [AF_MSB:0] addr; // address
+reg return_value;
+reg [AF_MSB+1:0] taddr;
+begin
+ // clear upper address bits that are unused
+ taddr = addr & (Memsize-1);
+
+ return_value = True; // set default return value
+ if(taddr < (Memsize-(Kilo*32)) && taddr >= (Kilo*32)) return_value = False; // check Memory that has no protection
+ else if(taddr < (Kilo*8)) return_value = protect[PROTECT_REG_MSB-14]; // check lower 8K
+ else if(taddr < (Kilo*16)) return_value = protect[PROTECT_REG_MSB-12]; // next 8k
+ else if(taddr < (Kilo*24)) return_value = protect[PROTECT_REG_MSB-10]; // next 8k
+ else if(taddr < (Kilo*32)) return_value = protect[PROTECT_REG_MSB-8]; // next 8k
+
+ else if(taddr >= (Memsize-(Kilo*8))) return_value = protect[PROTECT_REG_MSB-0]; // check top 8K
+ else if(taddr >= (Memsize-(Kilo*16))) return_value = protect[PROTECT_REG_MSB-2]; // next 8K
+ else if(taddr >= (Memsize-(Kilo*24))) return_value = protect[PROTECT_REG_MSB-4]; // next 8K
+ else if(taddr >= (Memsize-(Kilo*32))) return_value = protect[PROTECT_REG_MSB-6]; // next 8K
+
+ Read_proT = return_value; // return True/False for read protection at this address
+end
+endfunction
+
+//-------------------------------------------------------------
+// protection functions, return True/False for write protection
+// given and address True = protected
+//-------------------------------------------------------------
+function Write_proT;
+input [AF_MSB:0] addr; // address
+reg [AF_MSB+1:0] address; // address
+reg return_value;
+reg [7:0] index;
+reg [AF_MSB+1:0] taddr;
+begin
+ // clear upper address bits that are unused
+ taddr = addr; taddr = taddr & (Memsize-1);
+
+ return_value = True; // set default return value
+ if(taddr < (Memsize-(Kilo*64)) && taddr >= (Kilo*64)) begin // check address 64K --> Memsize-64K
+ index = 0; // index to bottom of table
+ address=(Kilo*64); // starting address at bottom of table
+ while(address < (Memsize-(Kilo*64)) && return_value===True) begin // loop through each 64K block
+ if(taddr >= address && taddr < (address + (Kilo*64))) begin
+ if(protect_or[index] === False) return_value = False; // check protect flag
+ end
+ index = index + 1; // increment protect array pointer
+ address = address+(Kilo*64); // increment to next 64K protection block
+ end
+ end
+ // check lower 64k of Memory
+ else if(taddr < (Kilo*8) ) begin if(protect_or[PROTECT_REG_MSB-15]==False) return_value = False; end // check lower 8K
+ else if(taddr < (Kilo*16)) begin if(protect_or[PROTECT_REG_MSB-13]==False) return_value = False; end // next 8k
+ else if(taddr < (Kilo*24)) begin if(protect_or[PROTECT_REG_MSB-11]==False) return_value = False; end // next 8k
+ else if(taddr < (Kilo*32)) begin if(protect_or[PROTECT_REG_MSB- 9]==False) return_value = False; end // next 8k
+ else if(taddr < (Kilo*64)) begin if(protect_or[PROTECT_REG_MSB-17]==False) return_value = False; end // next 32k
+ // check upper 64k of Memory
+ else if(taddr >= (Memsize-(Kilo*8)) ) begin if(protect_or[PROTECT_REG_MSB-1]==False) return_value = False; end // check top 8K
+ else if(taddr >= (Memsize-(Kilo*16))) begin if(protect_or[PROTECT_REG_MSB-3]==False) return_value = False; end // next 8K
+ else if(taddr >= (Memsize-(Kilo*24))) begin if(protect_or[PROTECT_REG_MSB-5]==False) return_value = False; end // next 8K
+ else if(taddr >= (Memsize-(Kilo*32))) begin if(protect_or[PROTECT_REG_MSB-7]==False) return_value = False; end // next 8K
+ else if(taddr >= (Memsize-(Kilo*64))) begin if(protect_or[PROTECT_REG_MSB-16]==False) return_value = False; end // next 32K
+ Write_proT = return_value; // return True/False for read protection at this address
+end
+endfunction
+
+//----------------------------------------------------------------
+// check chip for any protection return False if OK to erase chip
+//----------------------------------------------------------------
+function Chip_proT;
+input [AF_MSB:0] addr; // address, always 0
+reg return_value;
+begin
+ return_value = |protect_or[PROTECT_REG_MSB:0];
+ Chip_proT = return_value;
+end
+endfunction
+
+
+//----------------------------------------------------------------------------------------
+// check for program address matches erase address during suspend of block or sector erase
+// in suspend mode verify that the address to be programed does not match suspended
+// sector or block, return True if match
+//----------------------------------------------------------------------------------------
+function ERASE_PGM;
+input [AF_MSB:0] erase_address_in; // erase address of suspended block/sector
+input [AF_MSB:0] pgm_address_in; // address to program, check if it's in suspended sector/block
+reg return_value;
+reg [AF_MSB+1:0] erase_address,pgm_address;
+begin
+ // clear unused upper address bits
+ erase_address = erase_address_in & (Memsize-1);
+ pgm_address = pgm_address_in & (Memsize-1);
+
+ return_value = False; // default to no match
+ if(WSE===True) begin // make sure you are in erase suspend mode
+ if(s_SE_flag === True) begin // check if SE when suspended, I.E. 4K Sector Size
+ if(erase_address[ADDR_MSB:12] === pgm_address[ADDR_MSB:12]) return_value = True;
+ end
+ // ---------------------------------------------------------------------
+ // if block erase you must check address for block size
+ // ---------------------------------------------------------------------
+ else if(s_BE_flag === True) begin // check if BE when suspended
+ if(erase_address < (Kilo * 32)) begin // 8K block size
+ if(erase_address[ADDR_MSB:13] === pgm_address[ADDR_MSB:13]) return_value = True;
+ end
+ else if( erase_address < (Kilo * 64)) begin // 32k Block size
+ if(erase_address[ADDR_MSB:15] === pgm_address[ADDR_MSB:15]) return_value = True;
+ end
+ else if( erase_address >= (Memsize-(Kilo * 32))) begin // 8K block size
+ if(erase_address[ADDR_MSB:13] === pgm_address[ADDR_MSB:13]) return_value = True;
+ end
+ else if( erase_address >= Memsize-(Kilo * 64)) begin // 32k Block size
+ if(erase_address[ADDR_MSB:15] === pgm_address[ADDR_MSB:15]) return_value = True;
+ end
+ else begin // 64K block size
+ if(erase_address[ADDR_MSB:16] === pgm_address[ADDR_MSB:16]) return_value = True;
+ end
+ end
+ end
+ ERASE_PGM = return_value;
+end
+endfunction
+
+//----------------------------------------------------------------------------------------
+// check for program address matches erase address during suspend of page program.
+// In suspend mode verify that the address to be erased does not match suspended
+// program address, return True if addresses match I.E. abort programing
+//----------------------------------------------------------------------------------------
+function PGM_ERASE;
+input [AF_MSB:0] erase_address_in; // erase address of block/sector to be erased
+input [AF_MSB:0] pgm_address_in; // suspended page program address
+reg return_value;
+reg [AF_MSB+1:0] erase_address, pgm_address;
+begin
+ // clear upper unused address bits
+ erase_address = erase_address_in & (Memsize-1);
+ pgm_address = pgm_address_in & (Memsize-1);
+
+ return_value = False; // default to no match
+ if(WSP===True) begin // make sure you are in program suspend mode
+ if(l_spi_cmd===SPI_SE || l_sqi_cmd===SQI_SE) begin // sector erase 4K size ?
+ if(erase_address[AF_MSB:12] === pgm_address[AF_MSB:12]) return_value = True;
+ end
+ // ---------------------------------------------------------------------
+ // if block erase you must check address for block size
+ // ---------------------------------------------------------------------
+ else if(l_spi_cmd===SPI_BE || l_sqi_cmd===SQI_BE) begin
+ if(erase_address < (Kilo * 32)) begin // 8K block size
+ if(erase_address[AF_MSB:13] === pgm_address[AF_MSB:13]) return_value = True;
+ end
+ else if( erase_address < (Kilo * 64)) begin // 32k Block size
+ if(erase_address[AF_MSB:15] === pgm_address[AF_MSB:15]) return_value = True;
+ end
+ else if( erase_address >= (Memsize-(Kilo * 32))) begin // 8K block size
+ if(erase_address[AF_MSB:13] === pgm_address[AF_MSB:13]) return_value = True;
+ end
+ else if( erase_address >= Memsize-(Kilo * 64)) begin // 32k Block size
+ if(erase_address[AF_MSB:15] === pgm_address[AF_MSB:15]) return_value = True;
+ end
+ else begin // 64K block size
+ if(erase_address[AF_MSB:16] === pgm_address[AF_MSB:16]) return_value = True;
+ end
+ end
+ end
+ PGM_ERASE = return_value;
+end
+endfunction
+`endprotect
+
+endmodule
\ No newline at end of file
diff --git a/verilog/dv/caravel/user_proj_example/sw/Makefile b/verilog/dv/caravel/user_proj_example/sw/Makefile
new file mode 100644
index 0000000..32b5433
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/Makefile
@@ -0,0 +1,14 @@
+#GCC_PATH := /ef/apps/bin
+GCC_PATH ?= /usr/local/opt/riscv-gnu-toolchain/bin
+GCC_PREFIX ?= riscv32-unknown-elf
+SIM_SOC ?= 1
+
+name := test
+
+%.hex: $(name).c n5_drv.c crt0.S link.ld
+ $(GCC_PATH)/$(GCC_PREFIX)-gcc -DSIM_SOC=$(SIM_SOC) -g -Wall -falign-functions=4 -march=rv32imc -mabi=ilp32 -nostdlib -mstrict-align -T link.ld -o $(name).elf -lgcc crt0.S n5_drv.c $(name).c -lgcc
+ $(GCC_PATH)/$(GCC_PREFIX)-objcopy -O binary $(name).elf $(name).bin
+ $(GCC_PATH)/$(GCC_PREFIX)-objcopy -O verilog $(name).elf $(name).hex
+ $(GCC_PATH)/$(GCC_PREFIX)-objdump -dS $(name).elf > $(name).lst
+
+all: $(name).hex
diff --git a/verilog/dv/caravel/user_proj_example/sw/README.md b/verilog/dv/caravel/user_proj_example/sw/README.md
new file mode 100644
index 0000000..05e26fe
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/README.md
@@ -0,0 +1,73 @@
+## I/O Map (WIP)
+### GPIO Port (Base: 0x48000000)
+|Register|Offset|Description|
+|----------|---|------------|
+| Data In | 0x00 | 14 pins only|
+| Data Out| 0x04| 14 pins only|
+| Pull Up Enable|0x08| Currently not used|
+| Pull Down Enable|0x0C| Currently not used|
+| Direction|0x10| 1: Input, 0: Output|
+| Interrupt Mask| 0x14||
+
+
+### UART Modules (UART0 Base: 0x40100000, UART1 Base: 0x40200000)
+
+|Register|Offset|Description|
+|----------|---|------------|
+| TX/RX Data | 0x00 | Read/Write from/to RX/TX FIFOs |
+| STATUS |0x04| Read only|
+| CONTROL| 0x04| Write only|
+| PRESCALER|0x08| Prescaler for the baud rate generator|
+| Interrupts Mask| 0x0C||
+| TX FIFO Threshold|0x10||
+| RX FIFO Threshold|0x14||
+
+
+### SPI Modules (SPI0 Base: 0x40200000, SPI1 Base: 0x40300000 )
+
+|Register|Offset|Description|
+|----------|---|------------|
+| Data |||
+| Control |||
+| Configuration |||
+| Status |||
+| Interrupt Mask|||
+
+### I2C Modules (I2C0 Base: 0x40400000, I2C1 Base: 0x40500000)
+
+|Register|Offset|Description|
+|----------|---|------------|
+
+
+### Pulse Width Modulors (PWM0 Base: 0x40600000, PWM1 Base: 0x40700000)
+
+|Register|Offset|Description|
+|----------|---|------------|
+| CMP1 | 0x04| Compare 1 Register (period)|
+| CMP2 | 0x08 | Compare 2 Register (level change) |
+| PRESCALER| 0x10| Prescaler Register, tmr_clk = clk / (PRESCALER+1)|
+| CTRL| 0x20| Control Register, 0: Enable PWM|
+
+
+``PWM Period = (CMP1 + 1)/tmr_clk = (CMP1 + 1)*(PRESCALER + 1)/clk``
+
+``PWM Duty Cyle = 1 - (CMP1 + 1)/(CMP2 + 1)``
+
+
+### 32-bit Timer Modules (Base: 0x40800000, 0x40900000, 0x40A00000, 0x40B00000)
+
+|Register|Offset|Description|
+|----------|---|------------|
+| TIMER | 0x00| Current Count |
+| Prescaler | 0x04| |
+| Compare | 0x08| Compare Register|
+| Status|||
+| Overflow Clear |||
+| Timer Enable |||
+| Interrupt Mask |||
+
+
+
+### 32-bit Watch Dog Timer Modules (Base: 0x40C00000, 0x40D00000)
+|Register|Offset|Description|
+|----------|---|------------|
diff --git a/verilog/dv/caravel/user_proj_example/sw/crt0.S b/verilog/dv/caravel/user_proj_example/sw/crt0.S
new file mode 100755
index 0000000..3f62dde
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/crt0.S
@@ -0,0 +1,170 @@
+#define EXT_MUL
+
+#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
+.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
+
+#define ext_mul(_rd, _rs1, _rs2) \
+r_type_insn(0b0000000, _rs2, _rs1, 0b111, _rd, 0b0001011)
+
+.macro wrtmrcmp reg
+ csrrw zero, 0xC03, \reg
+.endm
+
+.macro wrmie reg
+ csrrw zero, mie, \reg
+.endm
+
+.section .text
+ .global _start
+
+
+ .org 0
+reset_vector:
+ j reset_hand
+
+ .org 4
+nmi_vector:
+ j nmi_hand
+
+ .org 8
+tmr_vector:
+ j tmr_hand
+
+ .org 12
+ecall_vector:
+ j ecall_hand
+
+ .org 16
+ebreak_vector:
+ j ebreak_hand
+
+ .org 24
+ j .
+
+ .org 28
+ j .
+
+ .org 64 # IRQ 0
+ j IRQ
+
+ .org 68 # IRQ 1
+ j IRQ
+
+ .org 72
+ j IRQ
+
+ .org 76
+ j IRQ
+
+ .org 80
+ j IRQ
+
+ .org 84
+ j IRQ
+
+ .org 88
+ j IRQ
+
+ .org 92 # IRQ 7
+ j IRQ
+
+ .org 96 # IRQ 8
+ j IRQ
+
+ .org 100 # IRQ 9
+ j IRQ
+
+ .org 104 # IRQ 10
+ j IRQ
+
+ .org 128
+reset_hand:
+ li t0, 1<<(4*2+1)
+ csrw 0x7c0,t0 # make IO region (4) side effect
+ # disable interrupts
+ li t0, 0 #disable interrupts; use 5 to enable interrupts and IRQ
+ wrmie t0
+ _start:
+ li s0, 0x20000000
+ li s1, 55
+ sw s1, 0(s0)
+ addi s1, s1, 10
+ sw s1, 4(s0)
+ lw s2, 0(s0)
+ lw s3, 4(s0)
+
+ li s0, 0
+ li s1, 0
+ li s2, 0
+ li s3, 0
+ li s4, 0
+ li s5, 0
+ li s6, 0
+ li s7, 0
+ li s8, 0
+ li s9, 0
+ li s10, 0
+ li s11, 0
+ j ___App
+
+ .align 8
+
+nmi_hand:
+tmr_hand:
+ecall_hand:
+ebreak_hand:
+irq0_hand:
+ j IRQ
+ #li t0, 0xBAD00BED
+ #mret
+
+.align 8
+#ifdef EXT_MUL
+.global __mulsi3
+__mulsi3:
+ #ext_mul(10, 10, 11)
+ la t0, 0x49000000
+ sw a0, 0(t0)
+ sw a1, 4(t0)
+ lw a0, 0(t0)
+ ret
+#endif
+
+.align 8
+___App:
+ # Initialize the BSS section with 0s
+init_bss:
+ la a0, __bss_start__
+ la a1, __bss_end__
+ bge a0, a1, end_init_bss
+loop_init_bss:
+ sw zero, 0(a0)
+ addi a0, a0, 4
+ blt a0, a1, loop_init_bss
+end_init_bss:
+
+ # Move initialized data to RAM
+init_data:
+ la a0, __idata__
+ la a1, __data_start__
+ la a2, __data_end__
+ bge a1, a2, end_init_data
+loop_init_data:
+ lw a3, 0(a0)
+ sw a3, 0(a1)
+ addi a0, a0, 4
+ addi a1, a1, 4
+ blt a1, a2, loop_init_data
+end_init_data:
+
+ # Initialize the stack pointer!
+ lui sp, %hi(_fstack)
+ addi sp, sp, %lo(_fstack)
+ jal main
+
+end_loop:
+ j end_loop
+
+ .align 8
+
+
diff --git a/verilog/dv/caravel/user_proj_example/sw/link.ld b/verilog/dv/caravel/user_proj_example/sw/link.ld
new file mode 100644
index 0000000..e31cece
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/link.ld
@@ -0,0 +1,43 @@
+ENTRY(_start)
+MEMORY
+{
+ FLASH (x) :
+ ORIGIN = 0x0
+ LENGTH = 1M
+ SRAM (rwx) :
+ ORIGIN = 0x20000000,
+ LENGTH = 8K
+ stack (rw):
+ ORIGIN = 0x20000000 + 6K
+ LENGTH = 2K
+}
+
+PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4);
+
+SECTIONS
+{
+ .text : {
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(8);
+ __idata__ = .;
+ } > FLASH
+
+ .bss (NOLOAD) :
+ {
+ __bss_start__ = .;
+ *(.bss*)
+ *(COMMON)
+ __bss_end__ = .;
+ } > SRAM
+
+ .data :
+ {
+ __data_start__ = .;
+ *(.data*);
+ __data_end__ = .;
+
+ } > SRAM AT > FLASH
+
+}
+
diff --git a/verilog/dv/caravel/user_proj_example/sw/n5_drv.c b/verilog/dv/caravel/user_proj_example/sw/n5_drv.c
new file mode 100644
index 0000000..41e1cb6
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/n5_drv.c
@@ -0,0 +1,415 @@
+#include "n5_regs.h"
+#include "n5_drv.h"
+
+/* GPIO */
+void gpio_set_dir(unsigned int d) {
+ *GPIO_DIR = d;
+}
+
+void gpio_write(unsigned int d) {
+ *GPIO_DOUT = d;
+}
+
+unsigned int gpio_read() {
+ return *GPIO_DIN;
+}
+
+void gpio_pull (unsigned char d){
+ *GPIO_PD = 0;
+ *GPIO_PU = 0;
+ if(d==0) *GPIO_PD = 1;
+ else *GPIO_PU = 1;
+}
+
+void gpio_im(unsigned int im){
+ *GPIO_IM = im;
+}
+
+/* UART */
+int uart_init(unsigned int n, unsigned int prescaler){
+ if(n>1) return -1;
+ if(n==1){
+ *UART1_PRESCALER = prescaler;
+ *UART1_IM = 0;
+ *UART1_CTRL = 1;
+ }
+ else {
+ *UART0_PRESCALER = prescaler;
+ *UART0_IM = 0;
+ *UART0_CTRL = 1;
+ }
+}
+
+int uart_puts(unsigned int n, unsigned char *msg, unsigned int len){
+ int i;
+ if(n>1) return -1;
+ if(n==0){
+ for(i=0; i<len; i++){
+ while(*UART0_STATUS&1); // TX Not Full
+ *UART0_DATA = msg[i];
+ }
+ } else {
+ for(i=0; i<len; i++){
+ while(*UART1_STATUS&1); // TX Not Full
+ *UART1_DATA = msg[i];
+ }
+ }
+ return 0;
+}
+
+int uart_gets(unsigned int n, unsigned char *msg, unsigned int len){
+ int i;
+ if(n>1) return -1;
+ if(n==0){
+ for(i=0; i<len; i++){
+ while(*UART0_STATUS&8); // RX Not Empty
+ msg[i] = *UART0_DATA;
+ }
+ } else {
+ for(i=0; i<len; i++){
+ while(*UART1_STATUS&8); // RX Not Empty
+ msg[i] = *UART1_DATA;
+ }
+ }
+ return 0;
+}
+
+/* SPI */
+int spi_init(unsigned int n, unsigned char cpol, unsigned char cpha, unsigned char clkdiv){
+ unsigned int cfg_value = 0;
+ cfg_value |= cpol;
+ cfg_value |= (cpha << 1);
+ cfg_value |= ((unsigned int)clkdiv << 2);
+ if(n>1) return -1;
+ if(n==0) *SPI0_CFG = cfg_value;
+ else *SPI1_CFG = cfg_value;
+}
+
+unsigned int spi_status(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ return *SPI0_STATUS & 1;
+ else
+ return *SPI1_STATUS & 1;
+}
+
+unsigned char spi_read(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ return *SPI0_DATA;
+ else
+ return *SPI1_DATA;
+}
+
+int spi_write(unsigned int n, unsigned char data){
+ if(n>1) return -1;
+ if(n==0) {
+ *SPI0_DATA = data;
+ SET_BIT(*SPI0_CTRL, SPI_GO_BIT);
+ CLR_BIT(*SPI0_CTRL, SPI_GO_BIT);
+ while(!spi_status(n));
+ } else{
+ *SPI1_DATA = data;
+ SET_BIT(*SPI1_CTRL, SPI_GO_BIT);
+ CLR_BIT(*SPI1_CTRL, SPI_GO_BIT);
+ while(!spi_status(n));
+ }
+ return 0;
+}
+
+int spi_start(unsigned int n){
+ if(n>1) return -1;
+ if(n==0) {
+ SET_BIT(*SPI0_CTRL, SPI_SS_BIT);
+ } else {
+ SET_BIT(*SPI1_CTRL, SPI_SS_BIT);
+ }
+ return 0;
+}
+
+int spi_end(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ CLR_BIT(*SPI0_CTRL, SPI_SS_BIT);
+ else
+ CLR_BIT(*SPI1_CTRL, SPI_SS_BIT);
+ return 0;
+}
+
+/* i2c */
+int i2c_init(unsigned int n, unsigned int pre){
+ if(n>1) return -1;
+ if(n==0) {
+ *(I2C0_PRE_LO) = pre & 0xff;
+ *(I2C0_PRE_HI) = pre & 0xff00;
+ *(I2C0_CTRL) = I2C_CTRL_EN | I2C_CTRL_IEN;
+ } else {
+ *(I2C1_PRE_LO) = pre & 0xff;
+ *(I2C1_PRE_HI) = pre & 0xff00;
+ *(I2C1_CTRL) = I2C_CTRL_EN | I2C_CTRL_IEN;
+ }
+}
+
+int i2c_start(unsigned int n, unsigned char control)
+{
+ if(n>1) return -1;
+ if(n==0) {
+ *(I2C0_TX) = control;
+ *(I2C0_CMD) = I2C_CMD_STA | I2C_CMD_WR;
+ while( ((*I2C0_STAT) & I2C_STAT_TIP) != 0 );
+
+ if( ((*I2C0_STAT) & I2C_STAT_RXACK)) {
+ *(I2C0_CMD) = I2C_CMD_STO;
+ return 0;
+ }
+ return 1;
+
+ } else {
+ *(I2C1_TX) = control;
+ *(I2C1_CMD) = I2C_CMD_STA | I2C_CMD_WR;
+ while( ((*I2C1_STAT) & I2C_STAT_TIP) != 0 );
+
+ if( ((*I2C1_STAT) & I2C_STAT_RXACK)) {
+ *(I2C1_CMD) = I2C_CMD_STO;
+ return 0;
+ }
+ return 1;
+ }
+}
+
+int i2c_sendByte(unsigned char b){
+ *(I2C0_TX) = b;
+ *(I2C0_CMD) = I2C_CMD_WR;
+ while( (*I2C0_STAT) & I2C_STAT_TIP );
+ if( ((*I2C0_STAT) & I2C_STAT_RXACK )){
+ *(I2C0_CMD) = I2C_CMD_STO;
+ return 0;
+ }
+ return 1;
+}
+
+int i2c_sendHWord(unsigned int hw){
+ if(i2c_sendByte(hw>>8) == 0)
+ return 0;
+ return i2c_sendByte(hw&0xFF);
+}
+
+int i2c_readByte(){
+ *(I2C0_CMD) = I2C_CMD_RD;
+ while( ((*I2C0_STAT) & I2C_STAT_TIP) != 0 );
+ return *(I2C0_RX);
+}
+
+int i2c_stop(){
+ *(I2C0_CMD) = I2C_CMD_STO;
+}
+
+
+int i2c_send(unsigned int n, unsigned char saddr, unsigned char sdata){
+ if(n>1) return -1;
+ if(n==0) {
+ *(I2C0_TX) = saddr;
+ *(I2C0_CMD) = I2C_CMD_STA | I2C_CMD_WR;
+ while( ((*I2C0_STAT) & I2C_STAT_TIP) != 0 );
+ //(*I2C_STAT) & I2C_STAT_TIP ;
+
+ if( ((*I2C0_STAT) & I2C_STAT_RXACK)) {
+ *(I2C0_CMD) = I2C_CMD_STO;
+ return 0;
+ }
+ *(I2C0_TX) = sdata;
+ *(I2C0_CMD) = I2C_CMD_WR;
+ while( (*I2C0_STAT) & I2C_STAT_TIP );
+ *(I2C0_CMD) = I2C_CMD_STO;
+ if( ((*I2C0_STAT) & I2C_STAT_RXACK ))
+ return 0;
+ else
+ return 1;
+ } else {
+ *(I2C1_TX) = saddr;
+ *(I2C1_CMD) = I2C_CMD_STA | I2C_CMD_WR;
+ while( ((*I2C1_STAT) & I2C_STAT_TIP) != 0 );
+ //(*I2C_STAT) & I2C_STAT_TIP ;
+
+ if( ((*I2C1_STAT) & I2C_STAT_RXACK)) {
+ *(I2C1_CMD) = I2C_CMD_STO;
+ return 0;
+ }
+ *(I2C1_TX) = sdata;
+ *(I2C1_CMD) = I2C_CMD_WR;
+ while( (*I2C1_STAT) & I2C_STAT_TIP );
+ *(I2C1_CMD) = I2C_CMD_STO;
+ if( ((*I2C1_STAT) & I2C_STAT_RXACK ))
+ return 0;
+ else
+ return 1;
+ }
+}
+
+/* PWM */
+int pwm_init(unsigned int n, unsigned int cmp1, unsigned int cmp2, unsigned int pre){
+ if(n>1) return -1;
+ if(n==0) {
+ *PWM0_CMP1 = cmp1;
+ *PWM0_CMP2 = cmp2;
+ *PWM0_PRE = pre;
+ } else {
+ *PWM1_CMP1 = cmp1;
+ *PWM1_CMP2 = cmp2;
+ *PWM1_PRE = pre;
+ }
+ return 0;
+}
+
+int pwm_enable(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *PWM0_CTRL = 0x1;
+ else
+ *PWM0_CTRL = 0x1;
+ return 0;
+}
+
+int pwm_disable(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *PWM0_CTRL = 0x0;
+ else
+ *PWM0_CTRL = 0x0;
+ return 0;
+}
+
+/* Timers */
+int tmr_init(unsigned int n, unsigned int pre, unsigned int cmp){
+ if(n>1) return -1;
+ if(n==0) {
+ *TMR0_CMP = cmp;
+ *TMR0_PRE = pre;
+ *TMR0_OVCLR = 1;
+ *TMR0_OVCLR = 0;
+ } else {
+ *TMR1_CMP = cmp;
+ *TMR1_PRE = pre;
+ *TMR1_OVCLR = 1;
+ *TMR1_OVCLR = 0;
+ }
+ return 0;
+}
+
+int tmr_enable(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *TMR0_EN = 0x1;
+ else
+ *TMR1_EN = 0x1;
+ return 0;
+}
+
+int tmr_disable(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *TMR0_EN = 0x0;
+ else
+ *TMR1_EN = 0x0;
+ return 0;
+}
+
+int tmr_wait(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ while(*TMR0_STATUS == 0);
+ else
+ while(*TMR1_STATUS == 0);
+ return 0;
+}
+
+int tmr_ei(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *TMR0_IM == 1;
+ else
+ *TMR1_IM == 1;
+ return 0;
+}
+
+int tmr_di(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *TMR0_IM == 0;
+ else
+ *TMR1_IM == 0;
+ return 0;
+}
+
+int tmr_clrov(unsigned int n){
+ if(n>1) return -1;
+ if(n==0) {
+ *TMR0_OVCLR == 1;
+ *TMR0_OVCLR == 0;
+ }
+ else{
+ *TMR1_OVCLR == 1;
+ *TMR1_OVCLR == 0;
+ }
+ return 0;
+}
+
+int tmr_read(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ return *TMR0;
+ else
+ return *TMR1;
+ return 0;
+}
+
+/* Watch dog Timers */
+int wdt_init(unsigned int n){
+ if(n>1) return -1;
+ if(n==0) {
+ *WDT0_OVCLR = 1;
+ *WDT0_OVCLR = 0;
+ } else {
+ *WDT1_OVCLR = 1;
+ *WDT1_OVCLR = 0;
+ }
+ return 0;
+}
+
+int wdt_enable(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *WDT0_EN = 0x1;
+ else
+ *WDT1_EN = 0x1;
+ return 0;
+}
+
+int wdt_load(unsigned int n, unsigned int val) {
+ if(n>1) return -1;
+ if(n==0) {
+ *WDT0_LOAD = val;
+ } else {
+ *WDT1_LOAD = val;
+ }
+ return 0;
+}
+
+int wdt_read(unsigned int n){
+ if(n>1) return -1;
+ if(n==0) {
+ return *WDT0_TMR;
+ } else {
+ return *WDT1_TMR;
+ }
+ return 0;
+}
+
+int wdt_disable(unsigned int n){
+ if(n>1) return -1;
+ if(n==0)
+ *WDT0_EN = 0x0;
+ else
+ *WDT1_EN = 0x0;
+ return 0;
+}
\ No newline at end of file
diff --git a/verilog/dv/caravel/user_proj_example/sw/n5_drv.h b/verilog/dv/caravel/user_proj_example/sw/n5_drv.h
new file mode 100644
index 0000000..e6817ef
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/n5_drv.h
@@ -0,0 +1,33 @@
+/* GPIO */
+void gpio_set_dir(unsigned int );
+void gpio_write(unsigned int );
+unsigned int gpio_read();
+void gpio_pull (unsigned char );
+void gpio_im(unsigned int );
+
+/* UART */
+int uart_init(unsigned int , unsigned int );
+int uart_puts(unsigned int , unsigned char *, unsigned int );
+int uart_gets(unsigned int , unsigned char *, unsigned int );
+
+/* SPI */
+int spi_init(unsigned int , unsigned char , unsigned char , unsigned char );
+unsigned int spi_status(unsigned int );
+unsigned char spi_read(unsigned int );
+int spi_write(unsigned int , unsigned char );
+int spi_start(unsigned int );
+int spi_end(unsigned int );
+
+/* i2c */
+int i2c_init(unsigned int , unsigned int );
+int i2c_send(unsigned int , unsigned char , unsigned char );
+int i2c_start(unsigned int , unsigned char );
+int i2c_sendByte(unsigned char );
+int i2c_sendHWord(unsigned int );
+int i2c_readByte();
+int i2c_stop();
+
+/* PWM */
+int pwm_init(unsigned int, unsigned int, unsigned int, unsigned int);
+int pwm_enable(unsigned int);
+int pwm_disable(unsigned int);
diff --git a/verilog/dv/caravel/user_proj_example/sw/n5_int.h b/verilog/dv/caravel/user_proj_example/sw/n5_int.h
new file mode 100644
index 0000000..e097417
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/n5_int.h
@@ -0,0 +1,4 @@
+
+void IRQ (void) __attribute__ ((interrupt ("machine")));
+
+
diff --git a/verilog/dv/caravel/user_proj_example/sw/n5_regs.h b/verilog/dv/caravel/user_proj_example/sw/n5_regs.h
new file mode 100644
index 0000000..5646a67
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/n5_regs.h
@@ -0,0 +1,222 @@
+#define SET_BIT(reg, bit) (reg) = ((reg) | (1<<bit))
+#define CLR_BIT(reg, bit) (reg) = ((reg) & (~(1<<bit)))
+#define CHK_BIT(reg, bit) ((reg) & (1<<bit))
+
+
+#define AHB_GPIO_BASE_ADDR 0x48000000
+
+#define APB_UART_0_BASE_ADDR 0x40000000
+#define APB_UART_1_BASE_ADDR 0x40100000
+#define APB_SPI_0_BASE_ADDR 0x40200000
+#define APB_SPI_1_BASE_ADDR 0x40300000
+#define APB_I2C_0_BASE_ADDR 0x40400000
+#define APB_I2C_1_BASE_ADDR 0x40500000
+#define APB_PWM32_0_BASE_ADDR 0x40600000
+#define APB_PWM32_1_BASE_ADDR 0x40700000
+#define APB_TIMER32_0_BASE_ADDR 0x40800000
+#define APB_TIMER32_1_BASE_ADDR 0x40900000
+#define APB_TIMER32_2_BASE_ADDR 0x40a00000
+#define APB_TIMER32_3_BASE_ADDR 0x40b00000
+#define APB_WDT32_0_BASE_ADDR 0x40c00000
+#define APB_WDT32_1_BASE_ADDR 0x40d00000
+
+/* GPIO */
+#define GPIO_DIN_REG 0x00000000
+#define GPIO_DOUT_REG 0x00000008
+#define GPIO_PU_REG 0x00000010
+#define GPIO_PD_REG 0x00000018
+#define GPIO_DIR_REG 0x00000020
+#define GPIO_IM_REG 0x00000028
+
+unsigned int volatile *const GPIO_DIN = (unsigned int *)(AHB_GPIO_BASE_ADDR + GPIO_DIN_REG);
+unsigned int volatile *const GPIO_DOUT = (unsigned int *)(AHB_GPIO_BASE_ADDR + GPIO_DOUT_REG);
+unsigned int volatile *const GPIO_PU = (unsigned int *)(AHB_GPIO_BASE_ADDR + GPIO_PU_REG);
+unsigned int volatile *const GPIO_PD = (unsigned int *)(AHB_GPIO_BASE_ADDR + GPIO_PD_REG);
+unsigned int volatile *const GPIO_DIR = (unsigned int *)(AHB_GPIO_BASE_ADDR + GPIO_DIR_REG);
+unsigned int volatile *const GPIO_IM = (unsigned int *)(AHB_GPIO_BASE_ADDR + GPIO_IM_REG);
+
+/* UART Modules */
+#define UART_DATA_REG 0x00000000
+#define UART_STATUS_REG 0x00000008
+#define UART_CTRL_REG 0x00000010
+#define UART_PRESCALER_REG 0x00000018
+#define UART_IM_REG 0x00000020
+#define UART_TXFIFOTR_REG 0x00000028
+#define UART_RXFIFOTR_REG 0x00000030
+
+unsigned int volatile *const UART0_DATA = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_DATA_REG);
+unsigned int volatile *const UART0_STATUS = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_STATUS_REG);
+unsigned int volatile *const UART0_CTRL = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_CTRL_REG);
+unsigned int volatile *const UART0_PRESCALER = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_PRESCALER_REG);
+unsigned int volatile *const UART0_IM = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_IM_REG);
+unsigned int volatile *const UART0_TXTH = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_TXFIFOTR_REG);
+unsigned int volatile *const UART0_RXTH = (unsigned int *)(APB_UART_0_BASE_ADDR + UART_RXFIFOTR_REG);
+
+unsigned int volatile *const UART1_DATA = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_DATA_REG);
+unsigned int volatile *const UART1_STATUS = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_STATUS_REG);
+unsigned int volatile *const UART1_CTRL = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_CTRL_REG);
+unsigned int volatile *const UART1_PRESCALER = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_PRESCALER_REG);
+unsigned int volatile *const UART1_IM = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_IM_REG);
+unsigned int volatile *const UART1_TXTH = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_TXFIFOTR_REG);
+unsigned int volatile *const UART1_RXTH = (unsigned int *)(APB_UART_1_BASE_ADDR + UART_RXFIFOTR_REG);
+
+/* SPI Master Controllers */
+#define SPI_DATA_REG 0x00000000
+#define SPI_CFG_REG 0x00000008
+#define SPI_STATUS_REG 0x00000010
+#define SPI_CTRL_REG 0x00000018
+#define SPI_IM_REG 0x00000020
+
+// CTRL register fields
+#define SPI_GO_BIT 0x0
+#define SPI_GO_SIZE 0x1
+#define SPI_SS_BIT 0x1
+#define SPI_SS_SIZE 0x1
+
+// CFG register fields
+#define SPI_CPOL_BIT 0x0
+#define SPI_CPOL_SIZE 0x1
+#define SPI_CPHA_BIT 0x1
+#define SPI_CPHA_SIZE 0x1
+#define SPI_CLKDIV_BIT 0x2
+#define SPI_CLKDIV_SIZE 0x8
+
+// status register fields
+#define SPI_DONE_BIT 0x0
+#define SPI_DONE_SIZE 0x1
+
+unsigned int volatile *const SPI0_CTRL = (unsigned int *)(APB_SPI_0_BASE_ADDR + SPI_CTRL_REG);
+unsigned int volatile *const SPI0_DATA = (unsigned int *)(APB_SPI_0_BASE_ADDR + SPI_DATA_REG);
+unsigned int volatile *const SPI0_STATUS = (unsigned int *)(APB_SPI_0_BASE_ADDR + SPI_STATUS_REG);
+unsigned int volatile *const SPI0_CFG = (unsigned int *)(APB_SPI_0_BASE_ADDR + SPI_CFG_REG);
+unsigned int volatile *const SPI0_IM = (unsigned int *)(APB_SPI_0_BASE_ADDR + SPI_IM_REG);
+
+unsigned int volatile *const SPI1_CTRL = (unsigned int *)(APB_SPI_1_BASE_ADDR + SPI_CTRL_REG);
+unsigned int volatile *const SPI1_DATA = (unsigned int *)(APB_SPI_1_BASE_ADDR + SPI_DATA_REG);
+unsigned int volatile *const SPI1_STATUS = (unsigned int *)(APB_SPI_1_BASE_ADDR + SPI_STATUS_REG);
+unsigned int volatile *const SPI1_CFG = (unsigned int *)(APB_SPI_1_BASE_ADDR + SPI_CFG_REG);
+unsigned int volatile *const SPI1_IM = (unsigned int *)(APB_SPI_1_BASE_ADDR + SPI_IM_REG);
+
+/* I2C Modules: I2C00 & I2C1 */
+#define I2C_PRE_LO_REG 0x00000000
+#define I2C_PRE_HI_REG 0x00000008
+#define I2C_CTRL_REG 0x00000010
+#define I2C_TX_REG 0x00000018
+#define I2C_RX_REG 0x00000020
+#define I2C_CMD_REG 0x00000028
+#define I2C_STAT_REG 0x00000030
+#define I2C_IM_REG 0x00000038
+
+#define I2C_CMD_STA 0x80
+#define I2C_CMD_STO 0x40
+#define I2C_CMD_RD 0x20
+#define I2C_CMD_WR 0x10
+#define I2C_CMD_ACK 0x08
+#define I2C_CMD_IACK 0x01
+
+#define I2C_CTRL_EN 0x80
+#define I2C_CTRL_IEN 0x40
+
+#define I2C_STAT_RXACK 0x80
+#define I2C_STAT_BUSY 0x40
+#define I2C_STAT_AL 0x20
+#define I2C_STAT_TIP 0x02
+#define I2C_STAT_IF 0x01
+
+unsigned int volatile * const I2C0_PRE_LO = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_PRE_LO_REG);
+unsigned int volatile * const I2C0_PRE_HI = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_PRE_HI_REG);
+unsigned int volatile * const I2C0_CTRL = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_CTRL_REG);
+unsigned int volatile * const I2C0_TX = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_TX_REG);
+unsigned int volatile * const I2C0_RX = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_RX_REG);
+unsigned int volatile * const I2C0_CMD = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_CMD_REG);
+unsigned int volatile * const I2C0_STAT = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_STAT_REG);
+unsigned int volatile * const I2C0_IM = (unsigned int *) (APB_I2C_0_BASE_ADDR + I2C_IM_REG);
+
+
+unsigned int volatile * const I2C1_PRE_LO = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_PRE_LO_REG);
+unsigned int volatile * const I2C1_PRE_HI = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_PRE_HI_REG);
+unsigned int volatile * const I2C1_CTRL = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_CTRL_REG);
+unsigned int volatile * const I2C1_TX = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_TX_REG);
+unsigned int volatile * const I2C1_RX = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_RX_REG);
+unsigned int volatile * const I2C1_CMD = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_CMD_REG);
+unsigned int volatile * const I2C1_STAT = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_STAT_REG);
+unsigned int volatile * const I2C1_IM = (unsigned int *) (APB_I2C_1_BASE_ADDR + I2C_IM_REG);
+
+/* PWM Modules: PWM0 & PWM1 */
+#define PWM_CMP1_REG 0x00000008
+#define PWM_CMP2_REG 0x00000010
+#define PWM_CTRL_REG 0x00000018
+#define PWM_PRE_REG 0x00000020
+
+unsigned int volatile *const PWM0_CTRL = (unsigned int *)(APB_PWM32_0_BASE_ADDR + PWM_CTRL_REG);
+unsigned int volatile *const PWM0_PRE = (unsigned int *)(APB_PWM32_0_BASE_ADDR + PWM_PRE_REG);
+unsigned int volatile *const PWM0_CMP1 = (unsigned int *)(APB_PWM32_0_BASE_ADDR + PWM_CMP1_REG);
+unsigned int volatile *const PWM0_CMP2 = (unsigned int *)(APB_PWM32_0_BASE_ADDR + PWM_CMP2_REG);
+
+unsigned int volatile *const PWM1_CTRL = (unsigned int *)(APB_PWM32_1_BASE_ADDR + PWM_CTRL_REG);
+unsigned int volatile *const PWM1_PRE = (unsigned int *)(APB_PWM32_1_BASE_ADDR + PWM_PRE_REG);
+unsigned int volatile *const PWM1_CMP1 = (unsigned int *)(APB_PWM32_1_BASE_ADDR + PWM_CMP1_REG);
+unsigned int volatile *const PWM1_CMP2 = (unsigned int *)(APB_PWM32_1_BASE_ADDR + PWM_CMP2_REG);
+
+/* TIMER32: TMR0, TM1, TMR2 and TMR3 */
+#define TMR_REG 0x00000000
+#define TMR_PRE_REG 0x00000008
+#define TMR_CMP_REG 0x00000010
+#define TMR_STATUS_REG 0x00000018
+#define TMR_OVCLR_REG 0x00000020
+#define TMR_EN_REG 0x00000028
+#define TMR_IM_REG 0x00000030
+
+unsigned int volatile * const TMR0_EN = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_EN_REG);
+unsigned int volatile * const TMR0 = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_REG);
+unsigned int volatile * const TMR0_STATUS = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_STATUS_REG);
+unsigned int volatile * const TMR0_PRE = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_PRE_REG);
+unsigned int volatile * const TMR0_CMP = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_CMP_REG);
+unsigned int volatile * const TMR0_OVCLR = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_OVCLR_REG);
+unsigned int volatile * const TMR0_IM = (unsigned int *) (APB_TIMER32_0_BASE_ADDR + TMR_IM_REG);
+
+unsigned int volatile * const TMR1_EN = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_EN_REG);
+unsigned int volatile * const TMR1 = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_REG);
+unsigned int volatile * const TMR1_STATUS = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_STATUS_REG);
+unsigned int volatile * const TMR1_PRE = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_PRE_REG);
+unsigned int volatile * const TMR1_CMP = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_CMP_REG);
+unsigned int volatile * const TMR1_OVCLR = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_OVCLR_REG);
+unsigned int volatile * const TMR1_IM = (unsigned int *) (APB_TIMER32_1_BASE_ADDR + TMR_IM_REG);
+
+unsigned int volatile * const TMR2_EN = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_EN_REG);
+unsigned int volatile * const TMR2 = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_REG);
+unsigned int volatile * const TMR2_STATUS = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_STATUS_REG);
+unsigned int volatile * const TMR2_PRE = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_PRE_REG);
+unsigned int volatile * const TMR2_CMP = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_CMP_REG);
+unsigned int volatile * const TMR2_OVCLR = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_OVCLR_REG);
+unsigned int volatile * const TMR2_IM = (unsigned int *) (APB_TIMER32_2_BASE_ADDR + TMR_IM_REG);
+
+unsigned int volatile * const TMR3_EN = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_EN_REG);
+unsigned int volatile * const TMR3 = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_REG);
+unsigned int volatile * const TMR3_STATUS = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_STATUS_REG);
+unsigned int volatile * const TMR3_PRE = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_PRE_REG);
+unsigned int volatile * const TMR3_CMP = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_CMP_REG);
+unsigned int volatile * const TMR3_OVCLR = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_OVCLR_REG);
+unsigned int volatile * const TMR3_IM = (unsigned int *) (APB_TIMER32_3_BASE_ADDR + TMR_IM_REG);
+
+/* WDT32: WDT0, WDT1 */
+#define WDT_TMR_REG 0x00000000
+#define WDT_LOAD_REG 0x00000008
+#define WDT_OV_REG 0x00000010
+#define WDT_OVCLR_REG 0x00000018
+#define WDT_EN_REG 0x00000020
+#define WDT_IRQEN_REG 0x00000028
+
+unsigned int volatile *const WDT0_TMR = (unsigned int *)(APB_WDT32_0_BASE_ADDR + WDT_TMR_REG);
+unsigned int volatile *const WDT0_LOAD = (unsigned int *)(APB_WDT32_0_BASE_ADDR + WDT_LOAD_REG);
+unsigned int volatile *const WDT0_OV = (unsigned int *)(APB_WDT32_0_BASE_ADDR + WDT_OV_REG);
+unsigned int volatile *const WDT0_OVCLR = (unsigned int *)(APB_WDT32_0_BASE_ADDR + WDT_OVCLR_REG);
+unsigned int volatile *const WDT0_EN = (unsigned int *)(APB_WDT32_0_BASE_ADDR + WDT_EN_REG);
+unsigned int volatile *const WDT0_IRQEN = (unsigned int *)(APB_WDT32_0_BASE_ADDR + WDT_IRQEN_REG);
+
+unsigned int volatile *const WDT1_TMR = (unsigned int *)(APB_WDT32_1_BASE_ADDR + WDT_TMR_REG);
+unsigned int volatile *const WDT1_LOAD = (unsigned int *)(APB_WDT32_1_BASE_ADDR + WDT_LOAD_REG);
+unsigned int volatile *const WDT1_OV = (unsigned int *)(APB_WDT32_1_BASE_ADDR + WDT_OV_REG);
+unsigned int volatile *const WDT1_OVCLR = (unsigned int *)(APB_WDT32_1_BASE_ADDR + WDT_OVCLR_REG);
+unsigned int volatile *const WDT1_EN = (unsigned int *)(APB_WDT32_1_BASE_ADDR + WDT_EN_REG);
+unsigned int volatile *const WDT1_IRQEN = (unsigned int *)(APB_WDT32_1_BASE_ADDR + WDT_IRQEN_REG);
diff --git a/verilog/dv/caravel/user_proj_example/sw/test.c b/verilog/dv/caravel/user_proj_example/sw/test.c
new file mode 100644
index 0000000..42ee022
--- /dev/null
+++ b/verilog/dv/caravel/user_proj_example/sw/test.c
@@ -0,0 +1,138 @@
+#include "n5_drv.h"
+#include "n5_int.h"
+
+unsigned int A[100];
+
+void IRQ() {
+ gpio_write(0x0099);
+}
+
+int fact(int n){
+ int f = 1;
+ for(int i=2; i<=n; i++)
+ f = f * i;
+ return f;
+}
+
+int strlen(char *s){
+ int i=0;
+ while (*s){
+ i++;
+ }
+ return i;
+}
+
+void M23LC_write_byte(int n, unsigned int addr, unsigned int data){
+ spi_start(n);
+ spi_write(n, 0x2);
+ spi_write(n, addr >> 8); // Address high byte
+ spi_write(n, addr & 0xFF); // Address low byte
+ spi_write(n, data);
+ spi_end(n);
+}
+
+unsigned char M23LC_read_byte(int n, unsigned short addr){
+ spi_start(n);
+ spi_write(n, 0x3);
+ spi_write(n, addr >> 8); // Address high byte
+ spi_write(n, addr & 0xFF); // Address low byte
+ spi_write(n, 0); // just write a dummy data to get the data out
+ spi_end(n);
+ return spi_read(n);
+}
+
+#define DELAY(n) for(int i=0; i<n; i++)
+
+int main(){
+ // Initialization
+ uart_init (0, 0);
+ gpio_set_dir(0x00FF);
+
+ spi_init(0, 0,0,40);
+
+ // Start the test
+ uart_puts (0, "Hello World!\n", 13);
+
+ // I2C testing
+ uart_puts (0, "I2C Test: ", 10);
+ i2c_init(0, 16000);
+ i2c_start(0, 0xA0); // slave address = 1010_000, R/W_b=0 (write)
+ i2c_sendByte(0x0);
+ i2c_sendByte(0x0);
+ i2c_sendByte(0x55);
+ i2c_stop();
+ DELAY(20);
+ i2c_start(0, 0xA0); // slave address = 1010_000, R/W_b=0 (write)
+ i2c_sendByte(0x0);
+ i2c_sendByte(0x0);
+ i2c_start(0, 0xA1); // slave address = 1010_000, R/W_b=1 (read)
+ int i2c_data = i2c_readByte();
+ gpio_write(i2c_data);
+ if(i2c_data == 0x55)
+ uart_puts(0,"Passed!\n", 8);
+ else
+ uart_puts(0,"Failed!\n", 8);
+ i2c_stop();
+
+ // GPIO
+ uart_puts (0, "GPIO Test: ", 11);
+
+ int gpio_val = 0x55;
+ if (SIM_SOC == 0){
+ gpio_val = 0x15; // Wrapper has a lower number of GPIOs
+ }
+
+ gpio_write(gpio_val);
+ DELAY(50);
+ int gpio_data = gpio_read();
+ if((gpio_data >> 8) == gpio_val)
+ uart_puts(0,"Passed!\n", 8);
+ else
+ uart_puts(0,"Failed!\n", 8);
+
+ // SPI
+ uart_puts (0, "SPI Test: ", 10);
+ M23LC_write_byte(0, 0, 0xA5);
+ unsigned int spi_data = M23LC_read_byte(0, 0);
+ DELAY(10);
+ if(spi_data==0xA5)
+ uart_puts(0,"Passed!\n", 8);
+ else
+ uart_puts(0,"Failed!\n", 8);
+
+ // Timer
+ uart_puts (0, "TMR Test: ", 10);
+ tmr_init(0, 800, 10);
+ tmr_enable(0);
+ tmr_wait(0);
+ tmr_disable(0);
+ if(tmr_read(0) == 0)
+ uart_puts(0,"Passed!\n", 8);
+ else
+ uart_puts(0,"Failed!\n", 8);
+
+ // WDT
+ uart_puts (0, "WDT Test: ", 10);
+ wdt_init(0);
+ wdt_enable(0);
+ wdt_load(0, 50);
+ while(wdt_read(0) != 0);
+ wdt_disable(0);
+ if (wdt_read(0) == 0)
+ uart_puts(0,"Passed!\n", 8);
+ else
+ uart_puts(0,"Failed!\n", 8);
+
+ // PWM
+ pwm_init(0, 250, 99, 5);
+ pwm_enable(0);
+ DELAY(30);
+ pwm_disable(0);
+
+ // Some Delay
+ DELAY(50);
+
+ // Done!
+ uart_puts(0, "Done!\n\n", 7);
+ return 0;
+}