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; +}