1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683 |
- /******************************************************************************
- Winbond Electronics Corporation
- Verilog Simulation for W25Q128JV series Serial Flash Memory
- V0.2
- Copyright (c) 2001-2016 Winbond Electronics Corporation
- All Rights Reserved.
- Notes:
- Versions:
- 09/19/2016 Initial Version
- 08/23/2017 V0.2 Modified Protection Area & Updated specs
- ******************************************************************************/
- `timescale 1ns / 1ns
- module W25Q128JV (CSn, CLK, DIO, DO, WPn, HOLDn);
- input CSn, CLK;
- inout DIO;
- inout WPn;
- inout HOLDn;
- inout DO;
- parameter NUM_PAGES = 65536;
- parameter NUM_SEC_PAGES = 3;
- parameter PAGESIZE = 256;
- parameter SECTORSIZE = 4096;
- parameter HALFBLOCKSIZE = 32768;
- parameter BLOCKSIZE = 65536;
- parameter NUM_BLOCKS = NUM_PAGES * PAGESIZE / BLOCKSIZE;
- parameter NUM_LOCKBITS = NUM_BLOCKS - 2 + 32;
- parameter MANUFACTURER = 8'hEF;
- parameter DEVICE_ID = 8'h17;
- parameter JEDEC_ID_HI = 8'h40;
- parameter JEDEC_ID_HI_QPI = 8'h70;
- parameter JEDEC_ID_LO = 8'h18;
- parameter UNIQUE_ID = 64'h0102030405060708;
- parameter ADDRESS_MASK = (NUM_PAGES * PAGESIZE) - 1; // Note that NUM_PAGES must be a power of 2 for this simulation to work properly.
- `define MEM_FILENAME "/home/bart/Documents/FPGA/FPGC6/Verilog/memory/spi.txt" //todo relative path // Memory contents file(s)
- `define SECSI_FILENAME "SECSI.TXT"
- `define SFDP_FILENAME "SFDP.TXT"
- `define SREG_FILENAME "SREG.TXT"
- // The following registers define the main memory spaces of the
- // device.
- //
- reg [7:0] memory [0:(NUM_PAGES * PAGESIZE) - 1]; // Main Memory Array
- reg [7:0] page_latch [0:PAGESIZE-1]; // Page Latch for Program Sector commands.
- reg [7:0] secsi[0:(NUM_SEC_PAGES * (SECTORSIZE/PAGESIZE) * PAGESIZE) - 1]; // Security Sector Array
- reg [7:0] sfdp[0:PAGESIZE]; // Serial Flash Discoverable Parameter
- reg lock_array[0:NUM_LOCKBITS]; // 510 blocks + 32 sectors
- reg [23:0] status_reg; // Status Register
- reg [23:0] status_reg_shadow; // Status Register Shadow Register
- reg status_reg_otp [23:0]; // Status Register OTP Bits
- reg [23:0] byte_address; // Page address used for reading pages.
- reg [23:0] prog_byte_address; // Page address used for writing pages.
- reg [8:0] prog_byte_number;
- reg [7:0] mode_reg; // Mode Register
- reg [7:0] wrap_reg; // burst-wrap register
- reg [7:0] read_param_reg; // Read parameters register
- reg [7:0] read_param_reg_shadow; // Shadow register
- reg flag_prog_page; // Flag used to start the program process for sram 0
- reg flag_prog_secsi_page; // Flag used to program a SECSI page
- reg flag_erase_sector; // Flag used to erase a sector (4KB)
- reg flag_erase_secsi_sector;
- reg flag_erase_half_block; // Flag to erase half a block (32KB)
- reg flag_erase_block; // Flag used to erase a block (64KB)
- reg flag_erase_bulk; // Flag used to erase the chip
- reg flag_power_up_exec;
- reg flag_power_down;
- reg flag_power_up_sig_read;
- reg flag_write_status_reg;
- reg flag_suspend; // Flag used to start an erase suspend process.
- reg flag_resume; // Flag used to resume from and erase suspend
- reg flag_suspend_enabled; // Flag used to stop the erase process.
- reg flag_slow_read_reg;
- reg flag_volatile_sr_write; // flag for volatile status register write.
- wire flag_slow_read = flag_slow_read_reg;
- reg flag_read_op_reg;
- wire #1 flag_read_op = flag_read_op_reg; // Delay avoids race condition
- reg flag_qpi_mode; // flag used for QPI Mode.
- reg flag_enable_reset; // flag used to enable the software reset command.
- reg flag_reset; // flag to execute the chip reset routine
- reg flag_reset_condition; // Flag to stop delay loops
- reg flag_set_read_param; // Flag to set read parameters
- reg timing_error; // Register for identifying timing errors when they occur
- reg [7:0] in_byte; // These two variables are used for debug purposes.
- reg [7:0] out_byte;
- // Logic output for WPn pin.
- //
- reg WPn_Reg, WPn_Output_Enable_reg;
- wire WPn_Output_Enable = WPn_Output_Enable_reg;
- // Logic output for HOLDn pin.
- //
- reg HOLDn_Reg, HOLDn_Output_Enable;
- // Logic output for DO pin.
- //
- reg DO_Reg, DO_Output_Enable, temp_DO_Output_Enable;
- // Logic output for DIO pin.
- //
- reg DIO_Reg, DIO_Output_Enable_reg, temp_DIO_Output_Enable_reg;
- wire DIO_Output_Enable = DIO_Output_Enable_reg;
- // Flag to signal that HOLDn goes active while CSn is low
- reg HOLDn_Active;
- // The following are working variables for the simulation program
- //
- reg [7:0] cmd_byte;
- reg [7:0] null_reg;
- reg [7:0] temp;
- integer x;
- integer fileno;
- reg [15:0] file_sector;
- reg [15:0] file_length;
- // The following macro's define the supported commands in this
- // Simulation
- //
- `define CMD_WRITE_DISABLE 8'h04
- `define CMD_WRITE_ENABLE 8'h06
- `define CMD_READ_STATUS 8'h05
- `define CMD_WRITE_STATUS 8'h01
- `define CMD_READ_STATUS2 8'h35
- `define CMD_WRITE_STATUS2 8'h31
- `define CMD_READ_STATUS3 8'h15
- `define CMD_WRITE_STATUS3 8'h11
- `define CMD_READ_DATA 8'h03
- `define CMD_READ_DATA_FAST 8'h0b
- `define CMD_READ_DATA_FAST_WRAP 8'h0c
- `define CMD_READ_DATA_FAST_DUAL 8'h3b
- `define CMD_READ_DATA_FAST_DUAL_IO 8'hbb
- `define CMD_READ_DATA_FAST_QUAD 8'h6b
- `define CMD_READ_DATA_FAST_QUAD_IO 8'heb
- `define CMD_READ_OCTAL_FAST_QUAD_IO 8'he3
- `define CMD_READ_WORD_FAST_QUAD_IO 8'he7
- `define CMD_PAGE_PROGRAM 8'h02
- `define CMD_PAGE_PROGRAM_QUAD 8'h32
- `define CMD_BLOCK_ERASE 8'hD8
- `define CMD_HALF_BLOCK_ERASE 8'h52
- `define CMD_SECTOR_ERASE 8'h20
- `define CMD_BULK_ERASE 8'hC7
- `define CMD_BULK_ERASE2 8'h60
- `define CMD_DEEP_POWERDOWN 8'hB9
- `define CMD_READ_SIGNATURE 8'hAB
- `define CMD_READ_ID 8'h90
- `define CMD_READ_ID_DUAL 8'h92
- `define CMD_READ_ID_QUAD 8'h94
- `define CMD_READ_JEDEC_ID 8'h9f
- `define CMD_READ_UNIQUE_ID 8'h4b
- `define CMD_SUSPEND 8'h75
- `define CMD_RESUME 8'h7A
- `define CMD_SET_BURST_WRAP 8'h77
- `define CMD_MODE_RESET 8'hff
- `define CMD_DISABLE_QPI 8'hff
- `define CMD_ENABLE_QPI 8'h38
- `define CMD_ENABLE_RESET 8'h66
- `define CMD_CHIP_RESET 8'h99
- `define CMD_SET_READ_PARAM 8'hC0
- `define CMD_SREG_PROGRAM 8'h42
- `define CMD_SREG_ERASE 8'h44
- `define CMD_SREG_READ 8'h48
- `define CMD_WRITE_ENABLE_VSR 8'h50
- `define CMD_READ_SFDP 8'h5A
- `define CMD_INDIVIDUAL_LOCK 8'h36
- `define CMD_INDIVIDUAL_UNLOCK 8'h39
- `define CMD_READ_BLOCK_LOCK 8'h3D
- `define CMD_GLOBAL_BLOCK_LOCK 8'h7E
- `define CMD_GLOBAL_BLOCK_UNLOCK 8'h98
- // Status register definitions
- //
- `define STATUS_HLD_RST 24'h800000
- `define STATUS_DRV1 24'h400000
- `define STATUS_DRV0 24'h200000
- `define STATUS_WPS 24'h040000
- `define STATUS_SUS 24'h008000
- `define STATUS_CMP 24'h004000
- `define STATUS_LB3 24'h002000
- `define STATUS_LB2 24'h001000
- `define STATUS_LB1 24'h000800
- `define STATUS_QE 24'h000200
- `define STATUS_SRP1 24'h000100
- `define STATUS_SRP0 24'h000080
- `define STATUS_SEC 24'h000040
- `define STATUS_TB 24'h000020
- `define STATUS_BP2 24'h000010
- `define STATUS_BP1 24'h000008
- `define STATUS_BP0 24'h000004
- `define STATUS_WEL 24'h000002
- `define STATUS_WIP 24'h000001
- `define HLD_RST 23
- `define DRV1 22
- `define DRV0 21
- `define WPS 18
- `define SUS 15
- `define CMP 14
- `define LB3 13
- `define LB2 12
- `define LB1 11
- `define QE 9
- `define SRP1 8
- `define SRP0 7
- `define SEC 6
- `define TB 5
- `define BP2 4
- `define BP1 3
- `define BP0 2
- `define WEL 1
- `define WIP 0
-
- // Required for specify block
- wire flag_quad_mode = status_reg[`QE];
- wire flag_quad_mode_cs = !flag_quad_mode & !CSn;
- specify
- specparam tReset_Suspend_Max = 1000; // Reset / Suspend Granularity. Controls maximum amount of time for model to recognize a Suspend command.
- // Also controls amount of time it takes to recognize a reset command
- // CSn timing checks
- specparam tSLCH = 5;
- $setup(negedge CSn, posedge CLK, tSLCH, timing_error);
- specparam tCHSL = 5;
- $setup(posedge CLK, negedge CSn, tCHSL, timing_error);
- specparam tSHSL_R = 10;
- specparam tSHSL_W = 50;
- $width(posedge CSn &&& flag_read_op, tSHSL_R, 0, timing_error);
- $width(posedge CSn &&& (~flag_read_op), tSHSL_W, 0, timing_error);
- specparam tCHSH = 3;
- $setup(posedge CLK, posedge CSn, tCHSH, timing_error);
- specparam tSHCH = 3;
- $setup(posedge CSn, posedge CLK, tSHCH, timing_error);
- // CLK timing checks
- specparam tCYC = 9; // Minimum CLK period for all instructions but READ_PAGE
- specparam tCLH = 4; // Minimum CLK high time for all instructions but READ_PAGE
- specparam tCLL = 4; // Minimum CLK low time for all instructions but READ_PAGE
- $period(posedge CLK &&& (~flag_slow_read), tCYC, timing_error);
- $width(posedge CLK &&& (~flag_slow_read), tCLH, 0, timing_error);
- $width(negedge CLK &&& (~flag_slow_read), tCLL, 0, timing_error);
- specparam tCYCR = 20; // Minimum CLK period READ_PAGE
- specparam tCRLH = 8; // Minimum CLK high time READ_PAGE
- specparam tCRLL = 8; // Minimum CLK low time READ_PAGE
- $period(posedge CLK &&& (flag_slow_read), tCYCR, timing_error);
- $width(posedge CLK &&& (flag_slow_read), tCRLH, 0, timing_error);
- $width(negedge CLK &&& (flag_slow_read), tCRLL, 0, timing_error);
- // DIO timing checks
- specparam tDVCH = 2; // DIO Data setup time
- specparam tCHDX = 3; // DIO Data hold time
- // Make sure to turn off DIO input timing checks when outputing data in dual / quad output mode.
- $setup(DIO, posedge CLK &&& (~DIO_Output_Enable), tDVCH, timing_error);
- $hold(posedge CLK, DIO &&& (~DIO_Output_Enable), tCHDX, timing_error);
- // WPn timing checks
- specparam tWHSL = 20;
- specparam tSHWL = 100;
- // Make sure to turn off WPn timing checks when outputing data in quad output mode
- // As well, there is no way to detect setup time of CSn and WPn relative to the Write Status Register
- // command. Disable timing checks
- //$setup(posedge WPn, negedge CSn &&& (~flag_quad_mode), tWHSL, timing_error);
- //$setup(posedge CSn, negedge WPn &&& (~flag_quad_mode), tSHWL, timing_error);
- // HOLDn timing checks
- specparam tHLQZ = 12;
- specparam tHHQX = 7;
- specparam tSUS = 20000;
- specparam tCHHL = 5;
- $setup(posedge CLK, negedge HOLDn &&& (flag_quad_mode_cs),tCHHL, timing_error);
- specparam tHLCH = 5; // Need to verify from datasheet
- $hold(posedge CLK, negedge HOLDn &&& (flag_quad_mode_cs),tHLCH, timing_error);
- specparam tCHHH = 5;
- $setup(posedge CLK, posedge HOLDn &&& (flag_quad_mode_cs),tCHHH, timing_error);
- specparam tHHCH = 5;
- $hold(posedge CLK, posedge HOLDn &&& (flag_quad_mode_cs), tHHCH, timing_error);
- endspecify
- parameter tCLQV = 6; // Time to DO output valid.
- parameter tSHQZ = 7; // Data output disable time.
- parameter tW = 10000000; // Write Status Register Write Time
- parameter tRES1 = 3000; // Release from power down time 1
- parameter tRES2 = 1800; // Release from power down time 2
- parameter tDP = 3000; // Time for device to enter deep power down.
- parameter tPP = 700000; // Page Program Time
- parameter tBP1 = 30000;
- parameter tSE = 45000000; // Sector Erase Time.
- parameter tBE1 = 120000000; // Block Erase Time. 32KB
- parameter tBE2 = 150000000; // Block Erase Time. 64KB
- parameter tCE_40 = 1000000000; // Chip Erase Time. This constant should be repeated 40 times.
- //parameter tSE = 100000; // Sector Erase Time.
- //parameter tBE1 = 1200000; // Block Erase Time. 32KB
- //parameter tBE2 = 1500000; // Block Erase Time. 64KB
- //parameter tCE_40 = 10000000; // Chip Erase Time. This constant should be repeated 40 times.
- /******************************************************************************
- The following code is the initialization code run at the beginning of the
- simulation.
- ******************************************************************************/
- initial
- begin :initialization
-
- // Erase memory array to FFh state.
- //for(x = 0; x < (NUM_PAGES * PAGESIZE); x=x+1)
- // memory[x] = 8'hff;
-
- //dump_mem();
-
- $readmemh(`MEM_FILENAME,memory);
- // $readmemh(`SECSI_FILENAME,secsi);
- // $readmemh(`SFDP_FILENAME,sfdp);
- // $readmemh(`SREG_FILENAME,status_reg_otp);
-
- chip_reset();
- end
- /******************************************************************************
- The following continuous assignment statement assigns the DIO_Reg register to the
- DIO inout wire and so on for the rest of the quad outputs.
- ******************************************************************************/
- assign DIO = DIO_Output_Enable_reg ? DIO_Reg : 1'bz;
- assign DO = DO_Output_Enable ? DO_Reg : 1'bz;
- assign WPn = WPn_Output_Enable_reg ? WPn_Reg : 1'bz;
- assign HOLDn = HOLDn_Output_Enable ? HOLDn_Reg : 1'bz;
- /******************************************************************************
- The following routine occurs when CSn goes low.
- The following routine reads the opcode in from the SPI port and starts command
- execution. All commands execute the following flow:
- Command Dispatch ==> Command Protocol Handler ==> Command State Machine (if necessary)
- Whenever CSn goes high, the Command Dispatch and Command Protocol Handler functions
- stop execution. The Individual Command State Machines continue to run until
- completion, regardless of the state of CSn.
- ******************************************************************************/
- always @(negedge CSn) // When CSn goes low, device becomes active
- begin :read_opcode
- flag_read_op_reg = 1'b1; // Assume a read command first. If write, update variable in case statement.
- mode_reg = mode_reg & 8'hf0;
- if((mode_reg & 8'h30) != 8'h20) // If we are in mode 0x20, skip inputing command byte, execute last command
- input_byte(cmd_byte); // Read Opcode from SPI Port
-
- if(!is_qpi(cmd_byte))
- begin
- $display("WARNING: Non-QPI command was executed in QPI mode");
- $stop;
- end
-
- if(cmd_byte != `CMD_CHIP_RESET)
- flag_enable_reset = 0; // Ensure that ENABLE_RESET immediately precedes CHIP_RESET
- case (cmd_byte) // Now dispatch the correct function
-
- // Mode and Reset commands.
- `CMD_SET_READ_PARAM :
- begin
- if(!status_reg[`WIP] && !flag_power_down && flag_qpi_mode)
- begin
- input_byte(read_param_reg_shadow);
- flag_set_read_param = 1;
- get_posclk_holdn;
- flag_set_read_param = 0;
- end
- end
- `CMD_ENABLE_QPI :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- if(status_reg[`QE] == 1)
- flag_qpi_mode = 1;
- end
- end
- `CMD_MODE_RESET :
- begin
- if(!flag_power_down)
- flag_qpi_mode = 0;
- end
-
- `CMD_ENABLE_RESET : // Reset can happen at any time.
- begin
- flag_enable_reset = 1;
- end
-
- `CMD_CHIP_RESET :
- begin
- if(flag_enable_reset == 1)
- begin
- flag_reset = 1;
- @(posedge CLK);
- flag_reset = 0;
- end
- end
- // Power, ID and Extended Address commands
- `CMD_DEEP_POWERDOWN :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- flag_power_down = 1;
- @(posedge CLK);
- flag_power_down = 0;
- end
- end
-
-
- `CMD_READ_SIGNATURE :
- begin
- if(!status_reg[`WIP])
- begin
- flag_power_up_exec = 1;
- input_byte(null_reg);
- input_byte(null_reg);
- input_byte(null_reg);
- forever
- begin
- output_byte(DEVICE_ID);
- flag_power_up_sig_read = 1;
- end
- end
- end
- `CMD_READ_JEDEC_ID :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- output_byte(MANUFACTURER);
- if(flag_qpi_mode)
- output_byte(JEDEC_ID_HI_QPI);
- else
- output_byte(JEDEC_ID_HI);
- output_byte(JEDEC_ID_LO);
- end
- end
- `CMD_READ_ID :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- byte_address = 0;
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
- forever
- begin
- if(byte_address[0])
- begin
- output_byte(DEVICE_ID);
- output_byte(MANUFACTURER);
- end
- else
- begin
- output_byte(MANUFACTURER);
- output_byte(DEVICE_ID);
- end
- end
- end
- end
- `CMD_READ_ID_DUAL :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- byte_address = 0;
- input_byte_dual(byte_address[23:16]);
- input_byte_dual(byte_address[15:8]);
- input_byte_dual(byte_address[7:0]);
- input_byte_dual(mode_reg[7:0]);
- forever
- begin
- if(byte_address[0])
- begin
- output_byte_dual(DEVICE_ID);
- output_byte_dual(MANUFACTURER);
- end
- else
- begin
- output_byte_dual(MANUFACTURER);
- output_byte_dual(DEVICE_ID);
- end
- end
- end
- end
- `CMD_READ_ID_QUAD :
- begin
- if(!status_reg[`WIP] && !flag_power_down && status_reg[`QE])
- begin
- byte_address = 0;
- input_byte_quad(byte_address[23:16]);
- input_byte_quad(byte_address[15:8]);
- input_byte_quad(byte_address[7:0]);
- input_byte_quad(mode_reg[7:0]);
- input_byte_quad(temp[7:0]);
- input_byte_quad(temp[7:0]);
- forever
- begin
- if(byte_address[0])
- begin
- output_byte_quad(DEVICE_ID);
- output_byte_quad(MANUFACTURER);
- end
- else
- begin
- output_byte_quad(MANUFACTURER);
- output_byte_quad(DEVICE_ID);
- end
- end
- end
- end
-
- `CMD_READ_UNIQUE_ID :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- input_byte(null_reg);
- input_byte(null_reg);
- input_byte(null_reg);
- input_byte(null_reg);
- output_byte(UNIQUE_ID[63:56]);
- output_byte(UNIQUE_ID[55:48]);
- output_byte(UNIQUE_ID[47:40]);
- output_byte(UNIQUE_ID[39:32]);
- output_byte(UNIQUE_ID[31:24]);
- output_byte(UNIQUE_ID[23:16]);
- output_byte(UNIQUE_ID[15:8]);
- output_byte(UNIQUE_ID[7:0]);
- end
- end
-
- // Status Register commands
- `CMD_WRITE_ENABLE :
- begin
- if((!flag_power_down) && (WPn || status_reg[`QE]))
- status_reg[`WEL] = 1;
- end
-
- `CMD_WRITE_ENABLE_VSR :
- begin
- if(!flag_power_down)
- flag_volatile_sr_write = 1;
- end
-
- `CMD_WRITE_DISABLE :
- begin
- if(!flag_power_down)
- status_reg[`WEL] = 0;
- end
- `CMD_READ_STATUS :
- begin
- if(!flag_power_down)
- begin
- forever
- begin
- output_byte(status_reg[7:0]);
- end
- end
- end
- `CMD_READ_STATUS2 :
- begin
- if(!flag_power_down)
- begin
- forever
- begin
- output_byte(status_reg[15:8]);
- end
- end
- end
- `CMD_READ_STATUS3 :
- begin
- if(!flag_power_down)
- begin
- forever
- begin
- output_byte(status_reg[23:16]);
- end
- end
- end
- `CMD_WRITE_STATUS :
- begin
- if(!status_reg[`WIP] && (status_reg[`WEL] || flag_volatile_sr_write) && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- case ({status_reg[`SRP1],status_reg[`SRP0]})
- 2'b00, 2'b01 :
- begin
- if((status_reg[`SRP0] && WPn) || !status_reg[`SRP0] || status_reg[`QE])
- begin
- // Zero out high order byte of status register
- status_reg_shadow[23:8] = status_reg[23:8];
- input_byte(status_reg_shadow[7:0]);
- // flag write now that we have 8 bits....2nd 8 bits is optional
- // command must bail if /CS does not go high at 8th or 16th clock
- flag_write_status_reg = 1;
- // 2nd byte is optional
- if(flag_qpi_mode == 1)
- @(posedge CLK);
- else
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command read 2nd byte.
- flag_write_status_reg = 0;
- input_byte_no1stclock(temp);
- flag_write_status_reg = 1;
- status_reg_shadow[15:8] = temp;
- if(flag_qpi_mode == 1)
- @(posedge CLK);
- else
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command read 2nd byte.
- flag_write_status_reg = 0;
- end
- end
- endcase
- end
- end
-
- `CMD_WRITE_STATUS2 :
- begin
- if(!status_reg[`WIP] && (status_reg[`WEL] || flag_volatile_sr_write) && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- case ({status_reg[`SRP1],status_reg[`SRP0]})
- 2'b00, 2'b01 :
- begin
- if((status_reg[`SRP0] && WPn) || !status_reg[`SRP0] || status_reg[`QE])
- begin
- status_reg_shadow[23:16] = status_reg[23:16];
- status_reg_shadow[7:0] = status_reg[7:0];
- input_byte(status_reg_shadow[15:8]);
- // flag write now that we have 8 bits....
- // command must bail if /CS does not go high at 8th clock
- flag_write_status_reg = 1;
- // 2nd byte is optional
- if(flag_qpi_mode == 1)
- @(posedge CLK);
- else
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command read 2nd byte.
- flag_write_status_reg = 0;
- end
- end
- endcase
- end
- end
- `CMD_WRITE_STATUS3 :
- begin
- if(!status_reg[`WIP] && (status_reg[`WEL] || flag_volatile_sr_write) && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- case ({status_reg[`SRP1],status_reg[`SRP0]})
- 2'b00, 2'b01 :
- begin
- if((status_reg[`SRP0] && WPn) || !status_reg[`SRP0] || status_reg[`QE])
- begin
- status_reg_shadow[15:0] = status_reg[15:0];
- input_byte(status_reg_shadow[23:16]);
- // flag write now that we have 8 bits....
- // command must bail if /CS does not go high at 8th clock
- flag_write_status_reg = 1;
- // 2nd byte is optional
- if(flag_qpi_mode == 1)
- @(posedge CLK);
- else
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command read 2nd byte.
- flag_write_status_reg = 0;
- end
- end
- endcase
- end
- end
- // Write Page Commands
- `CMD_PAGE_PROGRAM :
- begin
- if(status_reg[`WEL] && !status_reg[`SUS] && !flag_power_down)
- begin
- flag_read_op_reg = 1'b0;
- write_page(0);
- end
- end
- `CMD_PAGE_PROGRAM_QUAD :
- begin
- if(status_reg[`WEL]&& !status_reg[`SUS] && status_reg[`QE] && !flag_power_down)
- begin
- flag_read_op_reg = 1'b0;
- write_page(1);
- end
- end
- // Suspend / Resume Commands
- `CMD_SUSPEND :
- begin
- if(!flag_power_down && !flag_erase_bulk)
- begin
- if((!flag_suspend) && (flag_erase_sector || flag_erase_secsi_sector || flag_erase_half_block || flag_erase_block || flag_prog_page || flag_prog_secsi_page))
- begin
- flag_suspend = 1'b1;
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command.
- flag_suspend = 1'b0;
- end
- end
- end
-
- `CMD_RESUME :
- begin
- if(!flag_power_down)
- begin
- if(flag_suspend)
- begin
- flag_resume = 1'b1;
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command.
- flag_resume = 1'b0;
- end
- end
- end
-
- // Erase Commands
-
- `CMD_SECTOR_ERASE :
- begin
- if(status_reg[`WEL] && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
- if(!write_protected(byte_address))
- begin
- flag_erase_sector = 1;
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command.
- flag_erase_sector = 0;
- end
- end
- end
- `CMD_HALF_BLOCK_ERASE :
- begin
- if(status_reg[`WEL] && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
- if(!write_protected(byte_address))
- begin
- flag_erase_half_block = 1;
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command.
- flag_erase_half_block = 0;
- end
- end
- end
- `CMD_BLOCK_ERASE :
- begin
- if(status_reg[`WEL] && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
- if(!write_protected(byte_address))
- begin
- flag_erase_block = 1;
- get_posclk_holdn; // If an extra clock comes before CSn goes high, kill command.
- flag_erase_block = 0;
- end
- end
- end
- `CMD_BULK_ERASE, `CMD_BULK_ERASE2 :
- begin
- if(status_reg[`WEL] && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- case ({status_reg[`BP0],status_reg[`BP1]})
- 2'b00 :
- begin
- flag_erase_bulk = 1;
- get_posclk_holdn;
- flag_erase_bulk = 0;
- end
- endcase
- end
- end
- // Read Page Commands
- `CMD_READ_DATA :
- begin
- if(!flag_power_down)
- begin
- flag_slow_read_reg = 1'b1;
- read_page(0,0);
- end
- end
-
- `CMD_READ_DATA_FAST :
- begin
- if(!flag_power_down)
- read_page(1,0);
- end
-
- `CMD_READ_DATA_FAST_WRAP :
- begin
- if(!flag_power_down)
- begin
- if(flag_qpi_mode)
- read_page_quadio(cmd_byte);
- else
- read_page(1,0);
- end
- end
-
- `CMD_READ_DATA_FAST_DUAL :
- begin
- if(!flag_power_down)
- read_page(2,0);
- end
-
- `CMD_READ_DATA_FAST_QUAD :
- begin
- if(!flag_power_down && status_reg[`QE])
- read_page(3,0);
- end
-
- `CMD_READ_DATA_FAST_DUAL_IO :
- begin
- if(!flag_power_down)
- read_page_dualio;
- end
-
- `CMD_READ_DATA_FAST_QUAD_IO :
- begin
- if(!flag_power_down && status_reg[`QE])
- read_page_quadio(cmd_byte);
- end
- `CMD_READ_OCTAL_FAST_QUAD_IO :
- begin
- if(!flag_power_down && status_reg[`QE])
- read_page_quadio(cmd_byte);
- end
-
- `CMD_READ_WORD_FAST_QUAD_IO :
- begin
- if(!flag_power_down && status_reg[`QE])
- read_page_quadio(cmd_byte);
- end
-
- `CMD_SET_BURST_WRAP :
- begin
- if(!flag_power_down && status_reg[`QE])
- begin
- input_byte_quad(temp[7:0]);
- input_byte_quad(temp[7:0]);
- input_byte_quad(temp[7:0]);
- input_byte_quad(wrap_reg[7:0]);
- end
- end
-
- `CMD_READ_SFDP :
- begin
- if(!flag_power_down)
- begin
- flag_slow_read_reg = 1'b1;
- read_page(0,2);
- end
- end
-
-
- // Security Register Opcodes
- `CMD_SREG_READ :
- begin
- if(!flag_power_down)
- begin
- read_page(0,1);
- end
- end
-
- `CMD_SREG_ERASE :
- begin
- if(status_reg[`WEL] && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
-
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
- case (byte_address[23:8])
- 16'h10 :
- begin
- if(!status_reg[`LB1])
- begin
- flag_erase_secsi_sector = 1;
- get_posclk_holdn;
- flag_erase_secsi_sector = 0;
- end
- end
- 16'h20 :
- begin
- if(!status_reg[`LB2])
- begin
- flag_erase_secsi_sector = 1;
- get_posclk_holdn;
- flag_erase_secsi_sector = 0;
- end
- end
- 16'h30 :
- begin
- if(!status_reg[`LB3])
- begin
- flag_erase_secsi_sector = 1;
- get_posclk_holdn;
- flag_erase_secsi_sector = 0;
- end
- end
-
- endcase
- end
- end
-
- `CMD_SREG_PROGRAM :
- begin
- if(status_reg[`WEL] && !flag_power_down && !status_reg[`SUS])
- begin
- flag_read_op_reg = 1'b0;
- begin
- if(!status_reg[`WIP])
- begin
- input_byte(prog_byte_address[23:16]);
- input_byte(prog_byte_address[15:8]);
- input_byte(prog_byte_address[7:0]);
-
- case (byte_address[23:8])
- 16'h10 :
- if(!status_reg[`LB1])
- fill_page_latch(0,prog_byte_address,1);
- 16'h20 :
- if(!status_reg[`LB2])
- fill_page_latch(0,prog_byte_address,1);
- 16'h30 :
- if(!status_reg[`LB3])
- fill_page_latch(0,prog_byte_address,1);
- endcase
- end
- end
- end
- end
- // Lock Bit commands
-
- `CMD_GLOBAL_BLOCK_LOCK :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- for(x = 0; x < NUM_LOCKBITS; x=x+1)
- lock_array[x] = 1;
- end
- end
-
- `CMD_GLOBAL_BLOCK_UNLOCK :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- for(x = 0; x < NUM_LOCKBITS; x=x+1)
- lock_array[x] = 0;
- end
- end
-
- `CMD_INDIVIDUAL_LOCK :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
-
- lock_array[lockbit_index(byte_address)] = 1;
- end
- end
-
- `CMD_INDIVIDUAL_UNLOCK :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
-
- lock_array[lockbit_index(byte_address)] = 0;
- end
- end
-
- `CMD_READ_BLOCK_LOCK :
- begin
- if(!status_reg[`WIP] && !flag_power_down)
- begin
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
-
- null_reg[7:1] = 0;
- null_reg[0] = lock_array[lockbit_index(byte_address)];
- output_byte(null_reg);
- end
- end
-
- default :
- begin
- $display("Invalid Opcode. (%0h)",cmd_byte);
- $stop;
- end
- endcase
- end
- /******************************************************************************
- The following routine occurs when CSn goes high. In the case, all communications
- activities inside the chip must halt. Transfer and Program/Erase conditions
- will continue.
- ******************************************************************************/
- always @(posedge CSn) // When CSn goes high, device becomes in-active
- begin :disable_interface
- #tSHQZ; // Data-output disable time
- HOLDn_Active = 1'b0; // Disable HOLDn from mucking with output registers.
- DO_Output_Enable = 1'b0; // Tri-state DO output.
- DIO_Output_Enable_reg = 1'b0; // Tri-state DIO output.
- WPn_Output_Enable_reg = 1'b0; // Tri-state WPn output
- HOLDn_Output_Enable = 1'b0; // Tri-state HOLDn output
- flag_slow_read_reg = 1'b0; // Initiate normal timing checks
- disable input_byte;
- disable input_byte_dual;
- disable input_mode_dual;
- disable input_byte_quad;
- disable output_byte;
- disable output_byte_dual;
- disable output_byte_quad;
- disable read_opcode;
- disable write_page;
- disable fill_page_latch;
- disable read_page;
- disable read_page_dualio;
- disable read_page_quadio;
- disable get_posclk_holdn;
- disable get_negclk_holdn;
- end
- /******************************************************************************
- The following routine occurs when HOLDn goes low.
- ******************************************************************************/
- always @(negedge (HOLDn & !status_reg[`QE] & !CSn))
- begin
- if(!HOLDn)
- begin
- #tHLQZ;
- temp_DIO_Output_Enable_reg = DIO_Output_Enable_reg;
- temp_DO_Output_Enable = DO_Output_Enable;
- DIO_Output_Enable_reg = 1'b0; // Set DIO and DO to an input state
- DO_Output_Enable = 1'b0;
- HOLDn_Active = 1'b1;
- end
-
-
- end
- /******************************************************************************
- The following routine occurs when HOLDn goes high.
- ******************************************************************************/
- always @(posedge HOLDn)
- begin
- if(HOLDn_Active == 1'b1)
- begin
- #tHHQX;
- DIO_Output_Enable_reg = temp_DIO_Output_Enable_reg;
- DO_Output_Enable = temp_DO_Output_Enable;
- HOLDn_Active = 1'b0;
- end
-
- end
- /******************************************************************************
- GENERAL PURPOSE SUBROUTINES
- ******************************************************************************/
- task chip_reset;
- integer x;
- begin
- // Tri-state all outputs
- temp_DIO_Output_Enable_reg = 1'b0;
- DIO_Output_Enable_reg = 1'b0; // Tri-state DIO Output
- temp_DO_Output_Enable = 1'b0;
- DO_Output_Enable = 1'b0; // Tri-state DO Output.
- WPn_Output_Enable_reg = 1'b0; // Tri-state WPn Output
- HOLDn_Output_Enable = 1'b0; // Tri-state HOLDn Output
- HOLDn_Active = 1'b0;
- // Set all output registers to default to 0
-
- DIO_Reg = 1'b0;
- DO_Reg = 1'b0;
- WPn_Reg = 1'b0;
- HOLDn_Reg = 1'b0;
-
- mode_reg = 8'h00; // Setup null mode register
- wrap_reg = 8'b00010000; // Setup Bit 4 of wrap register to 1 as default
- read_param_reg = 8'h00; // Reset defaults for read parameter register
-
- status_reg = 0; // Status register default OTP values.
- // status_reg[`QE] = status_reg_otp[`QE];
- status_reg[`QE] = 1;
- status_reg[`SRP1] = 0;//status_reg_otp[`SRP1];
- status_reg[`SRP0] = 0;//status_reg_otp[`SRP0];
- status_reg[`BP0] = 0;//status_reg_otp[`BP0];
- status_reg[`BP1] = 0;//status_reg_otp[`BP1];
- status_reg[`BP2] = 0;//status_reg_otp[`BP2];
- status_reg[`TB] = 0;//status_reg_otp[`TB];
- status_reg[`SEC] = 0;//status_reg_otp[`SEC];
- status_reg[`CMP] = 0;//status_reg_otp[`CMP];
- status_reg[`WPS] = 0;//status_reg_otp[`WPS];
- status_reg[`DRV0] = 0;//status_reg_otp[`DRV0];
- status_reg[`DRV1] = 0;//status_reg_otp[`DRV1];
- status_reg[`HLD_RST] = 0;//status_reg_otp[`HLD_RST];
- status_reg[`LB1] = 0;//status_reg_otp[`LB1];
- status_reg[`LB2] = 0;//status_reg_otp[`LB2];
- status_reg[`LB3] = 0;//status_reg_otp[`LB3];
-
- flag_prog_page = 0;
- flag_prog_secsi_page = 0;
- flag_erase_sector = 0;
- flag_erase_half_block = 0;
- flag_erase_block = 0;
- flag_erase_secsi_sector = 0;
- flag_erase_bulk = 0;
- flag_power_down = 0;
- flag_power_up_exec = 0;
- flag_power_up_sig_read = 0;
- flag_write_status_reg = 0;
- flag_slow_read_reg = 1'b0; // Flag for standard read command....i.e. different timings
- flag_read_op_reg = 1'b0; // Flag for any read command....i.e. different timings.
- flag_suspend = 1'b0; // clear erase suspend status
- flag_suspend_enabled = 1'b0;
- flag_volatile_sr_write = 1'b0;
- flag_qpi_mode = 0;
- flag_enable_reset = 0;
- flag_reset = 0;
- flag_reset_condition = 0;
- flag_set_read_param = 0;
- timing_error = 0;
- cmd_byte = 0;
- null_reg = 0;
- in_byte = 0;
- out_byte = 0;
-
- // Reset the Lock Array to full write protect
-
- for(x = 0; x < NUM_LOCKBITS; x=x+1)
- lock_array[x] = 1;
-
- end
- endtask
- /******************************************************************************
- The following routine will input 1 byte from the SPI DIO pin and place
- the results in the input_data register.
- ******************************************************************************/
- task input_byte;
- output [7:0] input_data;
- integer x;
- begin
- if(flag_qpi_mode == 1)
- input_byte_quad(input_data);
- else
- begin
- // Set the DIO output register high-Z
- if(DIO_Output_Enable_reg != 1'b0)
- DIO_Output_Enable_reg = 1'b0;
-
- for(x = 7; x >= 0; x=x-1)
- begin
- get_posclk_holdn;
- input_data[x] = DIO;
- end
- in_byte = input_data;
- end
- end
- endtask
- /******************************************************************************
- The following routine will input 1 byte from the SPI DIO pin and place
- the results in the input_data register.
- ******************************************************************************/
- task input_byte_no1stclock;
- output [7:0] input_data;
- integer x;
- begin
- if(flag_qpi_mode == 1)
- input_byte_quad_no1stclock(input_data);
- else
- begin
- // Set the DIO output register high-Z
- if(DIO_Output_Enable_reg != 1'b0)
- DIO_Output_Enable_reg = 1'b0;
-
- for(x = 7; x >= 0; x=x-1)
- begin
- if(x != 7)
- get_posclk_holdn;
- input_data[x] = DIO;
- end
- in_byte = input_data;
- end
- end
- endtask
- /******************************************************************************
- The following routine will input 1 byte from the SPI DIO pin and DO pin and place
- the results in the input_data register.
- ******************************************************************************/
- task input_byte_dual;
- output [7:0] input_data;
- integer x;
- begin
-
- // Set the DIO output register high-Z
- if(DIO_Output_Enable_reg != 1'b0)
- DIO_Output_Enable_reg = 1'b0;
-
- // Set the DO output register high-Z
- if(DO_Output_Enable != 1'b0)
- DO_Output_Enable = 1'b0;
-
- for(x = 7; x >= 0; x=x-2)
- begin
- get_posclk_holdn;
-
- input_data[x-1] = DIO;
- input_data[x] = DO;
- end
- in_byte = input_data;
- end
- endtask
- /******************************************************************************
- The following routine will input 1 nibble from the SPI DIO pin and DO pin and place
- the results in the input_data register.
- ******************************************************************************/
- task input_mode_dual;
- output [5:0] input_data;
- integer x;
- begin
-
- // Set the DIO output register high-Z
- if(DIO_Output_Enable_reg != 1'b0)
- DIO_Output_Enable_reg = 1'b0;
-
- // Set the DO output register high-Z
- if(DO_Output_Enable != 1'b0)
- DO_Output_Enable = 1'b0;
-
- for(x = 5; x >= 0; x=x-2)
- begin
- get_posclk_holdn;
-
- input_data[x-1] = DIO;
- input_data[x] = DO;
- end
- end
- endtask
- /******************************************************************************
- The following routine will input 1 byte from the SPI DIO and DO and WPn and HOLDn pins
- and place the results in the input_data register.
- ******************************************************************************/
- task input_byte_quad;
- output [7:0] input_data;
- integer x;
- begin
- // Set the DIO output register high-Z
- if(DIO_Output_Enable_reg != 1'b0)
- DIO_Output_Enable_reg = 1'b0;
-
- // Set the DO output register high-Z
- if(DO_Output_Enable != 1'b0)
- DO_Output_Enable = 1'b0;
- // Set the WPn output register high-Z
- if(WPn_Output_Enable_reg != 1'b0)
- WPn_Output_Enable_reg = 1'b0;
- // Set the HOLDn output register high-Z
- if(HOLDn_Output_Enable != 1'b0)
- DO_Output_Enable = 1'b0;
- for(x = 7; x >= 0; x=x-4)
- begin
- @(posedge CLK);
- input_data[x-3] = DIO;
- input_data[x-2] = DO;
- input_data[x-1] = WPn;
- input_data[x] = HOLDn;
- end
- in_byte = input_data;
- end
- endtask
- /******************************************************************************
- The following routine will input 1 byte from the SPI DIO and DO and WPn and HOLDn pins
- and place the results in the input_data register.
- ******************************************************************************/
- task input_byte_quad_no1stclock;
- output [7:0] input_data;
- integer x;
- begin
- // Set the DIO output register high-Z
- if(DIO_Output_Enable_reg != 1'b0)
- DIO_Output_Enable_reg = 1'b0;
-
- // Set the DO output register high-Z
- if(DO_Output_Enable != 1'b0)
- DO_Output_Enable = 1'b0;
- // Set the WPn output register high-Z
- if(WPn_Output_Enable_reg != 1'b0)
- WPn_Output_Enable_reg = 1'b0;
- // Set the HOLDn output register high-Z
- if(HOLDn_Output_Enable != 1'b0)
- DO_Output_Enable = 1'b0;
- for(x = 7; x >= 0; x=x-4)
- begin
- if(x != 7)
- @(posedge CLK);
- input_data[x-3] = DIO;
- input_data[x-2] = DO;
- input_data[x-1] = WPn;
- input_data[x] = HOLDn;
- end
- in_byte = input_data;
- end
- endtask
- /******************************************************************************
- The following routine will output 1 byte to the DO pin.
- ******************************************************************************/
- task output_byte;
- input [7:0] output_data;
- integer x;
- begin
-
- if(flag_qpi_mode == 1)
- output_byte_quad(output_data);
- else
- begin
- out_byte = output_data;
- for(x = 7; x >= 0; x=x-1)
- begin
- get_negclk_holdn;
-
- if(DO_Output_Enable == 1'b0) // If the bus is not enabled, enable it now.
- DO_Output_Enable = 1'b1;
- #tCLQV DO_Reg = output_data[x];
- end
- end
- end
- endtask
- /******************************************************************************
- The following routine will output 1 byte to the DO and DIO pin.
- ******************************************************************************/
- task output_byte_dual;
- input [7:0] output_data;
- integer x;
- begin
- out_byte = output_data;
- for(x = 7; x >= 0; x=x-2)
- begin
- get_negclk_holdn;
-
- if(DO_Output_Enable == 1'b0) // If the bus is not enabled, enable it now.
- DO_Output_Enable = 1'b1;
- if(DIO_Output_Enable_reg == 1'b0)
- DIO_Output_Enable_reg = 1'b1;
-
- #tCLQV ;
- DIO_Reg = output_data[x-1];
- DO_Reg = output_data[x];
- end
- end
- endtask
- /******************************************************************************
- The following routine will output 1 byte to the DO and DIO and WPn and HOLDn pin.
- ******************************************************************************/
- task output_byte_quad;
- input [7:0] output_data;
- integer x;
- begin
- out_byte = output_data;
- for(x = 7; x >= 0; x=x-4)
- begin
- @(negedge CLK);
- if(DO_Output_Enable == 1'b0) // If the bus is not enabled, enable it now.
- DO_Output_Enable = 1'b1;
- if(DIO_Output_Enable_reg == 1'b0)
- DIO_Output_Enable_reg = 1'b1;
- if(WPn_Output_Enable_reg == 1'b0)
- WPn_Output_Enable_reg = 1'b1;
- if(HOLDn_Output_Enable == 1'b0)
- HOLDn_Output_Enable = 1'b1;
-
- #tCLQV;
- DIO_Reg = output_data[x-3];
- DO_Reg = output_data[x-2];
- WPn_Reg = output_data[x-1];
- HOLDn_Reg = output_data[x];
- end
- end
- endtask
- /******************************************************************************
- The following routine will return when a negative edge happens on CLK with respect
- to the HOLDn signal.
- ******************************************************************************/
- task get_negclk_holdn;
- begin
- if(status_reg[`QE]) // Quad bus is enabled, HOLD condition does not exist
- @(negedge CLK); // Therefore return negedge CLK
- else
- @(negedge (CLK & HOLDn)); // If Quad bus is disabled, return CLK only when HOLDn is high.
- end
- endtask
- /******************************************************************************
- The following routine will return when a positive edge happens on CLK with respect
- to the HOLDn signal.
- ******************************************************************************/
- task get_posclk_holdn;
- begin
- if(status_reg[`QE]) // Quad bus is enabled, HOLD condition does not exist
- @(posedge CLK); // Therefore return negedge CLK
- else
- @(posedge (CLK & HOLDn)); // If Quad bus is disabled, return CLK only when HOLDn is high.
- end
- endtask
- /******************************************************************************
- The following routine will delay the specified amount of time while waiting for the
- flag_suspend_enabled signal or the flag_reset_condition signal. If the flag_suspend_enable asserts, the delay routine will wait indefinetly
- until flag_suspend_enable deasserts; if flag_reset_condition asserts, the routine exits immediately
- ******************************************************************************/
- task wait_reset_suspend;
- input [31:0] delay;
- integer waitx;
- integer num_iterations;
- begin
-
- // Warning, this routine is not recursive and cannot be called while suspend is enabled!
- // This function delays while optionally waiting for the suspend signal. To reduce CPU simulation resources,
- // This routine will count in tReset_Suspend_Max increments down to a value less than tReset_Suspend_Max wait and then
- // look every nanosecond to finish. It exists under any circumstance if the chip is reset.
- waitx = 0;
-
- if(delay >= tReset_Suspend_Max)
- begin
- num_iterations = delay / tReset_Suspend_Max;
- for(waitx = 0; waitx < num_iterations; waitx=waitx+1) // check for erase suspend while part is programming
- begin
- if(flag_reset_condition) // If chip is reset, exit loop
- waitx = num_iterations; // Break the loop
- else
- begin
- wait(!flag_suspend_enabled || flag_reset_condition);
- #tReset_Suspend_Max;
- end
- end
- end
- num_iterations = delay % tReset_Suspend_Max;
- for(waitx = 0; waitx < num_iterations; waitx=waitx+1)
- begin
- if(flag_reset_condition) // check for chip reset while part is programming
- waitx = num_iterations;
- else
- begin
- wait(!flag_suspend_enabled || flag_reset_condition); // check for erase suspend while waiting
- #1;
- end
- end
- end
- endtask
- /******************************************************************************
- The following routine will delay the specified amount of time while waiting for the
- flag_reset_condition signal. If flag_reset_condition is asserted, the routine aborts because the chip has been reset
- ******************************************************************************/
- task wait_reset;
- input [31:0] delay;
- integer waitx;
- integer num_iterations;
- begin
- // This task delays while waiting for the reset signal. To reduce CPU simulation resources,
- // This routine will count in tReset_Suspend_Max increments down to a value less than tReset_Suspend_Max wait and then
- // look every nanosecond to finish. It exists under any circumstance if the chip is reset.
- waitx = 0;
-
- if(delay >= tReset_Suspend_Max)
- begin
- num_iterations = delay / tReset_Suspend_Max;
- for(waitx = 0; waitx < num_iterations; waitx=waitx+1) // check for erase suspend while part is programming
- begin
- if(flag_reset_condition) // If chip is reset, exit loop
- waitx = num_iterations; // Break the loop
- else
- #tReset_Suspend_Max; // else delay
- end
- end
- num_iterations = delay % tReset_Suspend_Max;
- for(waitx = 0; waitx < num_iterations; waitx=waitx+1) // check for erase suspend while part is programming
- begin
- if(flag_reset_condition) // check for chip reset while part is programming
- waitx = num_iterations;
- else
- #1;
- end
- end
- endtask
- /******************************************************************************
- The following function returns whether or not the current page is write
- protected based upon the status register protect bits.
- ******************************************************************************/
- function write_protected;
- input [23:0] byte_address;
- begin
- if(status_reg[`WPS])
- write_protected = lock_array[lockbit_index(byte_address)];
- else
- begin
- casez ({status_reg[`SEC], status_reg[`TB],status_reg[`BP2],status_reg[`BP1],status_reg[`BP0]})
- 5'b??000 :
- write_protected = 1'b0 ^ status_reg[`CMP];
- 5'b00001 :
- begin
- if(byte_address >= (NUM_PAGES * 63 / 64 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b00010 :
- begin
- if(byte_address >= (NUM_PAGES * 31 / 32 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b00011 :
- begin
- if(byte_address >= (NUM_PAGES * 15 / 16 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b00100 :
- begin
- if(byte_address >= (NUM_PAGES * 7 / 8 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b00101 :
- begin
- if(byte_address >= (NUM_PAGES * 3 / 4 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b00110 :
- begin
- if(byte_address >= (NUM_PAGES * 1 / 2 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b01001 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 64 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b01010 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 32 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b01011 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 16 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b01100:
- begin
- if(byte_address < (NUM_PAGES * 1 / 8 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b01101 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 4 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b01110 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 2 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b10001 :
- begin
- if(byte_address >= (NUM_PAGES * 4095 / 4096 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b10010 :
- begin
- if(byte_address >= (NUM_PAGES * 2047 / 2048 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b10011 :
- begin
- if(byte_address >= (NUM_PAGES * 1023 / 1024 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b1010? :
- begin
- if(byte_address >= (NUM_PAGES * 511 / 512 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b11001 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 4096 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b11010 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 2048 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
- 5'b11011 :
- begin
- if(byte_address < (NUM_PAGES * 1 / 1024 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b1110? :
- begin
- if(byte_address < (NUM_PAGES * 1 / 512 * PAGESIZE))
- write_protected = 1'b1 ^ status_reg[`CMP];
- else
- write_protected = 1'b0 ^ status_reg[`CMP];
- end
-
- 5'b??111 :
- begin
- write_protected = 1'b1 ^ status_reg[`CMP];
- end
- endcase
- end
- end
- endfunction
- /******************************************************************************
- The following function returns whether passed command is valid in QPI mode.
- ******************************************************************************/
- function is_qpi;
- input [7:0] cmd_byte;
- begin
- if(flag_qpi_mode == 1)
- begin
- case (cmd_byte) // check command byte for being valid in QPI mode.
- `CMD_WRITE_ENABLE, `CMD_WRITE_ENABLE_VSR, `CMD_WRITE_DISABLE, `CMD_READ_STATUS,
- `CMD_READ_STATUS2, `CMD_READ_STATUS3, `CMD_WRITE_STATUS, `CMD_WRITE_STATUS2, `CMD_WRITE_STATUS3, `CMD_PAGE_PROGRAM,
- `CMD_INDIVIDUAL_LOCK, `CMD_INDIVIDUAL_UNLOCK, `CMD_READ_BLOCK_LOCK, `CMD_GLOBAL_BLOCK_LOCK, `CMD_GLOBAL_BLOCK_UNLOCK,
- `CMD_SECTOR_ERASE,`CMD_HALF_BLOCK_ERASE, `CMD_BLOCK_ERASE, `CMD_BULK_ERASE, `CMD_BULK_ERASE2,
- `CMD_SUSPEND, `CMD_RESUME, `CMD_DEEP_POWERDOWN, `CMD_SET_READ_PARAM, `CMD_READ_DATA_FAST,
- `CMD_READ_DATA_FAST_WRAP, `CMD_READ_DATA_FAST_QUAD_IO, `CMD_READ_SIGNATURE, `CMD_READ_ID, `CMD_READ_JEDEC_ID,
- `CMD_READ_UNIQUE_ID, `CMD_DISABLE_QPI, `CMD_ENABLE_RESET, `CMD_CHIP_RESET :
- begin
- is_qpi = 1;
- end
-
- default :
- begin
- is_qpi = 0;
- $display("Invalid Opcode for QPI mode. (%0h)",cmd_byte);
- end
- endcase
- end
- else
- is_qpi = 1;
- end
- endfunction
- /******************************************************************************
- The following function returns the lockbit index based on the passed byte address
- The array is indexed with BLOCK 0 sectors, then last Block sectors,
- then block 1 - 510
- ******************************************************************************/
- function integer lockbit_index;
- input [23:0] byte_address;
- begin
-
- if((byte_address[23:16] == 0) || (byte_address[23:16] == (NUM_BLOCKS-1)))
- begin
- if(byte_address[23:16] == 0)
- lockbit_index = byte_address[15:0] / SECTORSIZE;
- else
- lockbit_index = (byte_address[15:0] / SECTORSIZE) + 16;
- end
- else
- lockbit_index = byte_address[23:16] - 1 + 32;
- end
- endfunction
-
-
- /******************************************************************************
- ******************************************************************************
- ******************************************************************************
- COMMAND PROTOCOL HANDLERS
- The following functions execute the command protocol for the selected function
- before enabling the internal state machine to handle the function
- ******************************************************************************
- ******************************************************************************
- ******************************************************************************/
- /******************************************************************************
- READ/WRITE PAGE PROTOCOL HANDLERS
- ******************************************************************************/
- /******************************************************************************
- The following routine will execute the Read Page command 03h,
- Read Page Fast command 0bh, Read Page Fast Dual 3bh and Read Page Fast Quad 6b.
- and Read Security Registers 48h and SFDP Read 5Ah
- ******************************************************************************/
- task read_page;
- input [1:0] fast_read; // 0 = normal, 2 = dual, 3 = quad
- input [1:0] mem_read; // 0 = main array, 1 = Security Pages, 2 = SFDP
- integer x;
- begin
- if(!status_reg[`WIP])
- begin
-
- input_byte(byte_address[23:16]);
- input_byte(byte_address[15:8]);
- input_byte(byte_address[7:0]);
- if(fast_read)
- begin
- if(flag_qpi_mode == 1)
- begin
- for(x = 0; x <= read_param_reg[5:4];x = x + 1)
- input_byte(null_reg);
- end
- else
- input_byte(null_reg);
- end
-
- if(mem_read) // SFDP Read and Security Register Read, input 8 dummy bytes.
- input_byte(null_reg);
-
- forever
- begin
- if(mem_read == 1) // If we're reading a security sector, process output here.
- begin
- case(byte_address[23:8])
- 16'h10 :
- output_byte(secsi[byte_address[7:0]]);
- 16'h20 :
- output_byte(secsi[byte_address[7:0]+PAGESIZE]);
- 16'h30 :
- output_byte(secsi[byte_address[7:0]]+(2*PAGESIZE));
- default :
- begin
- $display("Invalid Security Page Address (%x)",byte_address);
- $stop;
- end
- endcase
- end
- else if(mem_read == 2) //If we're reading SFDP, process output here.
- begin
- if(byte_address[23:8] == 0)
- output_byte(sfdp[byte_address[7:0]]);
- else
- begin
- $display("Invalid SFDP Page Address (%x)", byte_address);
- $stop;
- end
- end
- else // Main Array Reads
- begin
- byte_address = byte_address & ADDRESS_MASK;
- if(fast_read == 2)
- output_byte_dual(memory[byte_address]);
- else if(fast_read == 3)
- output_byte_quad(memory[byte_address]);
- else
- output_byte(memory[byte_address]);
- end
- // If security register or SFDP, wrap at 256 byte boundry. Only allow to read page.
- if(mem_read)
- byte_address[7:0] = byte_address[7:0] + 1;
- else
- byte_address = byte_address + 1;
- end
- end
- end
- endtask
- /******************************************************************************
- The following routine will execute the Read Page Fast Dual IO command bbh
- ******************************************************************************/
- task read_page_dualio;
- begin
- if(!status_reg[`WIP])
- begin
-
- input_byte_dual(byte_address[23:16]);
- input_byte_dual(byte_address[15:8]);
- input_byte_dual(byte_address[7:0]);
- input_mode_dual(mode_reg[7:2]); // Ensure that mode_reg is setup on posedge clock 22.
- get_posclk_holdn; // Get dummy last clock.
-
- forever
- begin
- byte_address = byte_address & ADDRESS_MASK;
- output_byte_dual(memory[byte_address]);
- byte_address = byte_address + 1;
- end
- end
- end
- endtask
- /******************************************************************************
- The following routine will execute the Read Page Fast Quad IO command ebh and e3h and e7h and 0ch
- For the following commands, fast_read == the command being sent.
- `define CMD_READ_DATA_FAST_QUAD_IO 8'heb
- `define CMD_READ_OCTAL_FAST_QUAD_IO 8'he3 A3:0 = 0
- `define CMD_READ_WORD_FAST_QUAD_IO 8'he7 A0 = 0
- ******************************************************************************/
- task read_page_quadio;
- input [7:0] cmd;
- integer x;
- begin
- input_byte_quad(byte_address[23:16]);
- input_byte_quad(byte_address[15:8]);
- input_byte_quad(byte_address[7:0]);
-
- if(!status_reg[`WIP])
- begin
- case (cmd)
- `CMD_READ_OCTAL_FAST_QUAD_IO :
- begin
- input_byte_quad(mode_reg[7:0]);
- if(byte_address[3:0] != 0)
- begin
- $display("WARNING: Error in Octal Word Read Quad I/O address input. A3-0 are non-zero!");
- $display("WARNING: The actual device still accepts the command, but the output data may be wrong!");
- $display("WARNING: It is OK if this is a Continuous Read Mode Reset (FFh).");
- end
- end
- `CMD_READ_DATA_FAST_QUAD_IO :
- begin
- input_byte_quad(mode_reg[7:0]);
- input_byte_quad(null_reg);
- input_byte_quad(null_reg);
- end
- `CMD_READ_WORD_FAST_QUAD_IO :
- begin
- input_byte_quad(mode_reg[7:0]);
- input_byte_quad(null_reg);
- if(byte_address[0] != 0)
- begin
- $display("WARNING: Error in Word Read Quad I/O address input. A0 is non-zero!");
- $display("WARNING: The actual device still accepts the command, but the output data may be wrong!");
- $display("WARNING: It is OK if this is a Continuous Read Mode Reset (FFh).");
- end
- end
- `CMD_READ_DATA_FAST_WRAP :
- begin
- for(x = 0; x <= read_param_reg[5:4];x = x + 1)
- input_byte_quad(null_reg);
- end
-
- endcase
- forever
- begin
- byte_address = byte_address & ADDRESS_MASK;
- output_byte_quad(memory[byte_address]);
- if(cmd == `CMD_READ_DATA_FAST_WRAP)
- begin
- case ({read_param_reg[1],read_param_reg[0]})
- 2'b00 :
- byte_address[2:0] = byte_address[2:0] + 1;
- 2'b01 :
- byte_address[3:0] = byte_address[3:0] + 1;
- 2'b10 :
- byte_address[4:0] = byte_address[4:0] + 1;
- 2'b11 :
- byte_address[5:0] = byte_address[5:0] + 1;
- endcase
- end
- else
- if(!wrap_reg[4] && ((cmd == `CMD_READ_WORD_FAST_QUAD_IO) || (cmd == `CMD_READ_DATA_FAST_QUAD_IO))) // wrap only a feature on non-fast read commands.
- begin
- case ({wrap_reg[6],wrap_reg[5]})
- 2'b00 :
- byte_address[2:0] = byte_address[2:0] + 1;
- 2'b01 :
- byte_address[3:0] = byte_address[3:0] + 1;
- 2'b10 :
- byte_address[4:0] = byte_address[4:0] + 1;
- 2'b11 :
- byte_address[5:0] = byte_address[5:0] + 1;
- endcase
- end
- else
- byte_address = byte_address + 1;
-
- end
- end
- end
- endtask
- /******************************************************************************
- The following routine will execute the Write to Page command 02h.
- ******************************************************************************/
- task write_page;
- input quadio;
- integer x;
- integer address;
- begin
- if(!status_reg[`WIP])
- begin
- input_byte(prog_byte_address[23:16]);
- input_byte(prog_byte_address[15:8]);
- input_byte(prog_byte_address[7:0]);
- if(!write_protected(prog_byte_address))
- fill_page_latch(quadio,prog_byte_address,0);
- end
- end
- endtask
- /******************************************************************************
- The following routine will fill the page_latch with input data in either regular or quad io.
- ******************************************************************************/
- task fill_page_latch;
- input quadio;
- input [31:0] prog_address;
- input flag_secsi;
- integer x;
- integer address;
- begin
- prog_byte_number = 0;
- // Move memory page into page latch
- if(flag_secsi)
- begin
- address = (prog_address >> 4) - 31'h100;
- address[7:0] = 0;
- end
- else
- begin
- address = prog_address;
- address[7:0] = 0;
- end
-
- for(x = 0; x < PAGESIZE; x=x+1)
- page_latch[x] = flag_secsi ? secsi[address+x] : memory[address+x];
-
- // Now update page latch with input data and signal a page_program operation
- forever
- begin
- if(quadio)
- input_byte_quad(temp);
- else
- input_byte(temp);
- page_latch[prog_address[7:0]] = temp;
- prog_byte_number = prog_byte_number + 1;
- if(flag_secsi)
- flag_prog_secsi_page = 1;
- else
- flag_prog_page = 1;
- prog_address[7:0] = prog_address[7:0] + 1;
- end
- end
- endtask
- ////////////////////////////////////////////////////////////////////////////////
- // This routine dumps the main memory array to the MEM_FILENAME file.
- //
- task dump_mem;
- integer x;
- integer file;
- begin
-
- file = $fopen(`MEM_FILENAME);
- $fwrite(file,"/* Contents of Memory Array starting from address 0. This is a standard Verilog readmemh format. */");
-
- // Erase memory array to FFh state.
- for(x = 0; x < (NUM_PAGES * PAGESIZE); x=x+1)
- begin
- if(x % 16)
- $fwrite(file,"%h ", memory[x]);
- else
- $fwrite(file,"\n%h ", memory[x]);
- end
- $fclose(file);
-
- end
- endtask
- /******************************************************************************
- ******************************************************************************
- ******************************************************************************
- COMMAND STATE MACHINES
- ******************************************************************************
- ******************************************************************************/
- /******************************************************************************
- The following routine occurs when flag_set_read_param goes high.
- This starts the main process for the set read param process.
- ******************************************************************************/
- always @(posedge flag_set_read_param)
- begin :set_read_param
- @(posedge CSn);
- if(flag_set_read_param == 1)
- begin
- read_param_reg = read_param_reg_shadow;
- end
- flag_set_read_param = 0;
- end
-
-
-
- /******************************************************************************
- The following routine occurs when flag_reset goes high.
- This starts the main process for the reset process.
- ******************************************************************************/
- always @(posedge flag_reset)
- begin :reset
- @(posedge CSn);
- if((flag_reset == 1) && (flag_write_status_reg == 0)) // Execute command, except if within a write status register command.
- begin
- flag_reset_condition = 1;
- #tRES1;
- chip_reset();
- end
- flag_reset = 0;
- end
- /******************************************************************************
- POWER UP/DOWN STATE MACHINES
- ******************************************************************************/
- /******************************************************************************
- The following routine occurs when flag_power_up_exec goes high.
- This starts the main process for the power up process.
- ******************************************************************************/
- always @(posedge flag_power_up_exec)
- begin :power_up
- @(posedge CSn);
- if(flag_power_up_exec == 1)
- begin
- if(flag_power_up_sig_read == 1)
- #tRES2;
- else
- #tRES1;
- flag_power_down = 0;
- flag_power_up_exec = 0;
- flag_power_up_sig_read = 0;
- flag_suspend = 0;
- end
- end
- /******************************************************************************
- The following routine occurs when flag_power_down_exec goes high.
- This starts the main process for the power down process.
- ******************************************************************************/
- always @(posedge flag_power_down)
- begin :power_down
- @(posedge CSn);
- if(flag_power_down == 1)
- begin
- #tDP;
- end
- end
- /******************************************************************************
- ERASE PAGE/BLOCK COMMAND STATE MACHINES
- ******************************************************************************/
- /******************************************************************************
- The following routine occurs when flag_suspend goes high.
- This starts the main erase process for the handling erase suspend.
- ******************************************************************************/
- always @(posedge flag_suspend)
- begin :erase_suspend
- @(posedge CSn); // Wait for CSn to go high
- if(flag_suspend == 1)
- begin
- status_reg[`SUS] = 1;
- wait_reset(tSUS);
- flag_suspend_enabled = 1'b1;
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
-
- end
- end
- /******************************************************************************
- The following routine occurs when flag_resume goes high.
- This starts the main erase process for the handling erase resume.
- ******************************************************************************/
- always @(posedge flag_resume)
- begin :erase_resume
- @(posedge CSn); // Wait for CSn to go high
- if(flag_resume == 1)
- begin
- status_reg[`SUS] = 0;
- flag_suspend_enabled = 1'b0;
- flag_suspend = 1'b0;
- flag_resume = 1'b0;
- status_reg[`WEL] = 1;
- status_reg[`WIP] = 1;
-
- end
- end
- /******************************************************************************
- The following routine occurs when flag_erase_sector goes high.
- This starts the main erase process for the defined sector.
- ******************************************************************************/
- always @(posedge flag_erase_sector) // When flag_erase_sector goes high, device becomes active
- // and starts erasing the sector defined by byte_address
- begin :erase_sector
- integer x;
- @(posedge CSn); // Wait for CSn to go high
- if(flag_erase_sector == 1)
- begin
- status_reg[`WIP] = 1;
- wait_reset_suspend(tSE);
-
- for(x = 0; x < SECTORSIZE; x=x+1)
- memory[(byte_address[23:12] * SECTORSIZE) + x] = 8'hff;
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_erase_sector = 0;
- end
- /******************************************************************************
- The following routine occurs when flag_erase_secsi_sector goes high.
- This starts the main erase process for the defined secsi sector.
- ******************************************************************************/
- always @(posedge flag_erase_secsi_sector) // When flag_erase_secsi_sector goes high, device becomes active
- // and starts erasing the sector defined by byte_address
- begin :erase_secsi_sector
- integer x;
- @(posedge CSn); // Wait for CSn to go high
- if(flag_erase_secsi_sector == 1)
- begin
- status_reg[`WIP] = 1;
- case(byte_address[23:8])
- 16'h10 :
- begin
- wait_reset_suspend(tSE);
- for(x = 0; x < PAGESIZE; x=x+1)
- secsi[x] = 8'hff;
- end
- 16'h20 :
- begin
- wait_reset_suspend(tSE);
- for(x = 0; x < PAGESIZE; x=x+1)
- secsi[x+PAGESIZE] = 8'hff;
- end
- 16'h30 :
- begin
- wait_reset_suspend(tSE);
- for(x = 0; x < PAGESIZE; x=x+1)
- secsi[x+(PAGESIZE * 2)] = 8'hff;
- end
- default :
- begin
- $display("Invalid Security Page Erase Address (%x)",byte_address);
- $stop;
- end
- endcase
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_erase_secsi_sector = 0;
- end
- /******************************************************************************
- The following routine occurs when flag_erase_block goes high.
- This starts the main erase process for the defined block.
- ******************************************************************************/
- always @(posedge flag_erase_block) // When flag_erase_block goes high, device becomes active
- // and starts erasing the block defined by byte_address
- begin :erase_block
- integer x;
- @(posedge CSn); // Wait for CSn to go high
- if(flag_erase_block == 1)
- begin
- status_reg[`WIP] = 1;
-
- wait_reset_suspend(tBE2);
- for(x = 0; x < BLOCKSIZE; x=x+1)
- memory[(byte_address[23:16] * BLOCKSIZE) + x] = 8'hff;
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_erase_block = 0;
- end
- /******************************************************************************
- The following routine occurs when flag_erase_half_block goes high.
- This starts the main erase process for the defined block.
- ******************************************************************************/
- always @(posedge flag_erase_half_block) // When flag_erase_block goes high, device becomes active
- // and starts erasing the block defined by byte_address
- begin :erase_half_block
- integer x;
- @(posedge CSn); // Wait for CSn to go high
- if(flag_erase_half_block == 1)
- begin
- status_reg[`WIP] = 1;
- wait_reset_suspend(tBE1);
- for(x = 0; x < HALFBLOCKSIZE; x=x+1)
- memory[(byte_address[23:15] * HALFBLOCKSIZE) + x] = 8'hff;
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_erase_half_block = 0;
- end
- /******************************************************************************
- The following routine occurs when flag_erase_bulk goes high.
- This starts the main erase process for the entire chip.
- ******************************************************************************/
- always @(posedge flag_erase_bulk) // When flag_erase_block goes high, device becomes active
- // and starts erasing the block defined by page_address
- begin :erase_bulk
- integer x;
- @(posedge CSn); // Wait for CSn to go high
- if(flag_erase_bulk == 1)
- begin
- status_reg[`WIP] = 1;
- for(x = 0; x < 40; x=x+1)
- wait_reset(tCE_40);
- for(x = 0; x < PAGESIZE * NUM_PAGES; x=x+1)
- memory[x] = 8'hff;
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_erase_bulk = 0;
- end
- /******************************************************************************
- PROGRAMMING PAGE COMMAND STATE MACHINES
- ******************************************************************************/
- /******************************************************************************
- The following routine occurs when flag_prog_page goes high.
- This starts the program page process.
- ******************************************************************************/
- always @(posedge flag_prog_page) // When flag_prog_page goes high, device becomes active
- // and starts programming the page defined by page_address
- begin :program_to_page
- reg [31:0] x; // Local loop variable only to be used here.
- @(posedge CSn); // Wait for CSn to go high
- begin
- status_reg[`WIP] = 1;
- if((prog_byte_address[7:0]+prog_byte_number[8:0]) > PAGESIZE)
- begin
- prog_byte_address[7:0] = 0;
- prog_byte_number = 256;
- end
-
- for(x = prog_byte_address; x < (prog_byte_address+prog_byte_number[8:0]); x=x+1)
- begin
- memory[x] = page_latch[x[7:0]] & memory[x];
-
- if(x == prog_byte_address)
- wait_reset_suspend(tBP1);
- else
- wait_reset_suspend(tPP / PAGESIZE);
- end
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_prog_page = 0;
- end
- /******************************************************************************
- The following routine occurs when flag_prog_secsi_page goes high.
- This starts the program secsi page process.
- ******************************************************************************/
- always @(posedge flag_prog_secsi_page) // When flag_prog_page goes high, device becomes active
- // and starts programming the page defined by page_address
- begin :program_to_secsi_page
- integer x; // Local loop variable only to be used here.
- @(posedge CSn); // Wait for CSn to go high
- begin
- status_reg[`WIP] = 1;
- prog_byte_address[7:0] = 0;
-
- case(prog_byte_address[23:8])
- 16'h10 :
- begin
- for(x = 0; x < PAGESIZE; x=x+1)
- begin
- secsi[x] = page_latch[x] & secsi[x];
- wait_reset_suspend(tPP / PAGESIZE);
- end
- end
- 16'h20 :
- begin
- for(x = 0; x < PAGESIZE; x=x+1)
- begin
- secsi[x+PAGESIZE] = page_latch[x] & secsi[x+PAGESIZE];
- wait_reset_suspend(tPP / PAGESIZE);
- end
- end
- 16'h30 :
- begin
- for(x = 0; x < PAGESIZE; x=x+1)
- begin
- secsi[x+(PAGESIZE*2)] = page_latch[x] & secsi[x+(PAGESIZE*2)];
- wait_reset_suspend(tPP / PAGESIZE);
- end
- end
- default :
- begin
- $display("Invalid Security Page Program Address (%x)",prog_byte_address);
- $stop;
- end
- endcase
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- end
- flag_prog_secsi_page = 0;
- end
- /******************************************************************************
- CONFIGURATION REGISTER COMMAND STATE MACHINES
- ******************************************************************************/
- /******************************************************************************
- The following routine occurs when flag_write_status_reg goes high.
- This starts the main write status register process.
- ******************************************************************************/
- always @(posedge flag_write_status_reg) // When flag_write_status_reg goes high, device becomes active
- // and starts writing the status_reg_shadow register into the
- begin :write_status_reg
- @(posedge CSn); // Wait for CSn to go high
- if(flag_write_status_reg == 1)
- begin
- status_reg[`WIP] = 1;
- status_reg[`QE] = status_reg_shadow[`QE];
- status_reg[`SRP1] = status_reg_shadow[`SRP1];
- status_reg[`SRP0] = status_reg_shadow[`SRP0];
- status_reg[`BP0] = status_reg_shadow[`BP0];
- status_reg[`BP1] = status_reg_shadow[`BP1];
- status_reg[`BP2] = status_reg_shadow[`BP2];
- status_reg[`TB] = status_reg_shadow[`TB];
- status_reg[`SEC] = status_reg_shadow[`SEC];
- status_reg[`CMP] = status_reg_shadow[`CMP];
- status_reg[`WPS] = status_reg_shadow[`WPS];
- status_reg[`DRV0] = status_reg_shadow[`DRV0];
- status_reg[`DRV1] = status_reg_shadow[`DRV1];
- status_reg[`HLD_RST] = status_reg_shadow[`HLD_RST];
-
- // One time program OTP bits to 1.
- status_reg[`LB1] = status_reg[`LB1] | status_reg_shadow[`LB1];
- status_reg[`LB2] = status_reg[`LB2] | status_reg_shadow[`LB2];
- status_reg[`LB3] = status_reg[`LB3] | status_reg_shadow[`LB3];
- if(!flag_volatile_sr_write)
- begin
-
- // Now set OTP bits
- status_reg_otp[`QE] = status_reg_shadow[`QE];
- status_reg_otp[`SRP1] = status_reg_shadow[`SRP1];
- status_reg_otp[`SRP0] = status_reg_shadow[`SRP0];
- status_reg_otp[`BP0] = status_reg_shadow[`BP0];
- status_reg_otp[`BP1] = status_reg_shadow[`BP1];
- status_reg_otp[`BP2] = status_reg_shadow[`BP2];
- status_reg_otp[`TB] = status_reg_shadow[`TB];
- status_reg_otp[`SEC] = status_reg_shadow[`SEC];
- status_reg_otp[`CMP] = status_reg_shadow[`CMP];
- status_reg_otp[`WPS] = status_reg_shadow[`WPS];
- status_reg_otp[`DRV0] = status_reg_shadow[`DRV0];
- status_reg_otp[`DRV1] = status_reg_shadow[`DRV1];
- status_reg_otp[`HLD_RST] = status_reg_shadow[`HLD_RST];
- // One time program OTP bits to 1.
- status_reg_otp[`LB1] = status_reg[`LB1] | status_reg_shadow[`LB1];
- status_reg_otp[`LB2] = status_reg[`LB2] | status_reg_shadow[`LB2];
- status_reg_otp[`LB3] = status_reg[`LB3] | status_reg_shadow[`LB3];
-
- end
-
- // If QE bit got reset, make sure QPI mode is disabled.
- if(status_reg[`QE] == 0)
- flag_qpi_mode = 0;
-
-
- if(status_reg[`WEL])
- wait_reset(tW);
- status_reg[`WIP] = 0;
- status_reg[`WEL] = 0;
- flag_volatile_sr_write = 0;
- flag_write_status_reg = 0;
- end
- end
- endmodule // W25Q128JV
|