From 2edaa4d7cb28c6fa8fc65cf22b76aca38fe227dc Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Wed, 10 Jun 2015 19:27:35 +0000 Subject: [PATCH] - added models git-svn-id: http://moon:8086/svn/vhdl/trunk@1290 cc03376c-175c-47c8-b038-4cd826a8556b --- .../serial/S25fl064a/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl064a/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../flash/serial/S25fl064a/model/s25fl064a.v | 1217 ++ .../serial/S25fl064a/model/s25fl064a.vhd | 1256 ++ .../S25fl064a/model/s25fl064a_verilog.ftm | 52 + .../serial/S25fl064a/model/s25fl064a_vhd.ftm | 65 + .../S25fl064a/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl064a/utilities/conversions.vhd | 1035 ++ .../serial/S25fl064a/utilities/gen_utils.vhd | 144 + .../serial/S25fl064k/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl064k/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl064k/model/model_release_history.txt | 89 + .../flash/serial/S25fl064k/model/s25fl064k.v | 4219 +++++ .../serial/S25fl064k/model/s25fl064k.vhd | 3768 +++++ .../serial/S25fl064k/model/s25fl064k_ver.ftm | 61 + .../serial/S25fl064k/model/s25fl064k_vhd.ftm | 81 + .../S25fl064k/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl064k/utilities/conversions.vhd | 1035 ++ .../serial/S25fl064k/utilities/gen_utils.vhd | 144 + .../serial/S25fl064p/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl064p/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl064p/model/model_release_history.txt | 196 + .../flash/serial/S25fl064p/model/s25fl064p.v | 2603 +++ .../serial/S25fl064p/model/s25fl064p.vhd | 2562 +++ .../serial/S25fl064p/model/s25fl064p_ver.ftm | 230 + .../serial/S25fl064p/model/s25fl064p_vhd.ftm | 242 + .../S25fl064p/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl064p/utilities/conversions.vhd | 1035 ++ .../serial/S25fl064p/utilities/gen_utils.vhd | 144 + .../serial/S25fl128k/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl128k/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl128k/model/model_release_history.txt | 21 + .../flash/serial/S25fl128k/model/s25fl128k.v | 4276 +++++ .../serial/S25fl128k/model/s25fl128k.vhd | 3787 +++++ .../serial/S25fl128k/model/s25fl128k_ver.ftm | 65 + .../serial/S25fl128k/model/s25fl128k_vhd.ftm | 81 + .../S25fl128k/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl128k/utilities/conversions.vhd | 1035 ++ .../serial/S25fl128k/utilities/gen_utils.vhd | 144 + .../serial/S25fl128s/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl128s/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl128s/model/model_release_history.txt | 438 + .../flash/serial/S25fl128s/model/s25fl128s.v | 7978 +++++++++ .../serial/S25fl128s/model/s25fl128s.vhd | 7180 ++++++++ .../serial/S25fl128s/model/s25fl128s_ver.ftm | 726 + .../serial/S25fl128s/model/s25fl128s_vhd.ftm | 783 + .../S25fl128s/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl128s/utilities/conversions.vhd | 1035 ++ .../serial/S25fl128s/utilities/gen_utils.vhd | 144 + .../serial/S25fl256s/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl256s/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl256s/model/model_release_history.txt | 350 + .../flash/serial/S25fl256s/model/s25fl256s.v | 8062 +++++++++ .../serial/S25fl256s/model/s25fl256s.vhd | 7222 ++++++++ .../serial/S25fl256s/model/s25fl256s_ver.ftm | 725 + .../serial/S25fl256s/model/s25fl256s_vhd.ftm | 781 + .../S25fl256s/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl256s/utilities/conversions.vhd | 1035 ++ .../serial/S25fl256s/utilities/gen_utils.vhd | 144 + .../serial/S25fl512s/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl512s/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl512s/model/model_release_history.txt | 380 + .../flash/serial/S25fl512s/model/s25fl512s.sv | 8080 +++++++++ .../flash/serial/S25fl512s/model/s25fl512s.v | 7523 +++++++++ .../serial/S25fl512s/model/s25fl512s.vhd | 13905 ++++++++++++++++ .../serial/S25fl512s/model/s25fl512s_ver.ftm | 511 + .../serial/S25fl512s/model/s25fl512s_vhd.ftm | 547 + .../S25fl512s/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 + .../utilities/CreateSDF/my_mem_vhd.ftm | 205 + .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++ .../S25fl512s/utilities/conversions.vhd | 1035 ++ .../serial/S25fl512s/utilities/gen_utils.vhd | 144 + .../memory/sdram/mt48lc16m16a2/dumpdata.txt | 47 + .../memory/sdram/mt48lc16m16a2/ed_comnd.vhd | 349 + .../memory/sdram/mt48lc16m16a2/loaddata.txt | 50 + .../sdram/mt48lc16m16a2/mt48lc16m16a2.vhd | 1319 ++ .../memory/sdram/mt48lc16m16a2/mti_pkg.vhd | 139 + lib/models/memory/sdram/mt48lc16m16a2/test.do | 57 + .../memory/sdram/mt48lc16m16a2/test.txt | 101 + .../memory/sdram/mt48lc16m16a2/test.vhd | 164 + .../memory/sdram/mt48lc16m16a2/vec_gen.vhd | 353 + lib/models/memory/sdram/mt48lc16m16a2/wave.do | 33 + .../sdram/mt48lc16m8a2/mt48lc16m8a2.vhd | 1069 ++ lib/models/memory/sdram/mt48lc16m8a2/test.do | 5 + lib/models/memory/sdram/mt48lc16m8a2/test.vhd | 313 + lib/models/memory/sdram/mt48lc16m8a2/wave.do | 39 + .../memory/sdram/mt48lc1m16a1/ed_comnd.vhd | 242 + .../memory/sdram/mt48lc1m16a1/io_utils.vhd | 266 + .../sdram/mt48lc1m16a1/mt48lc1m16a1.vhd | 907 + .../memory/sdram/mt48lc1m16a1/mti_pkg.vhd | 143 + .../memory/sdram/mt48lc1m16a1/readme.txt | 14 + .../memory/sdram/mt48lc1m16a1/stdlogar.vhd | 2247 +++ lib/models/memory/sdram/mt48lc1m16a1/test.txt | 69 + lib/models/memory/sdram/mt48lc1m16a1/test.vhd | 168 + .../memory/sdram/mt48lc1m16a1/util1164.vhd | 124 + .../memory/sdram/mt48lc1m16a1/vec_gen.vhd | 369 + lib/models/memory/sdram/mt48lc32m4a2/base.do | 5 + .../memory/sdram/mt48lc32m4a2/ed_comnd.vhd | 345 + .../memory/sdram/mt48lc32m4a2/io_utils.vhd | 266 + .../sdram/mt48lc32m4a2/mt48lc32m4a2.vhd | 1140 ++ .../memory/sdram/mt48lc32m4a2/mti_pkg.vhd | 129 + .../memory/sdram/mt48lc32m4a2/readme.txt | 14 + .../memory/sdram/mt48lc32m4a2/stdlogar.vhd | 2247 +++ lib/models/memory/sdram/mt48lc32m4a2/test.do | 5 + lib/models/memory/sdram/mt48lc32m4a2/test.txt | 98 + lib/models/memory/sdram/mt48lc32m4a2/test.vhd | 169 + .../memory/sdram/mt48lc32m4a2/util1164.vhd | 124 + .../memory/sdram/mt48lc32m4a2/vec_gen.vhd | 372 + .../memory/sdram/mt48lc32m4a2/vector.do | 4 + lib/models/memory/sdram/mt48lc32m4a2/wave.do | 31 + lib/models/memory/sdram/mt48lc4m16a2/base.do | 5 + .../memory/sdram/mt48lc4m16a2/ed_comnd.vhd | 357 + .../memory/sdram/mt48lc4m16a2/io_utils.vhd | 266 + .../memory/sdram/mt48lc4m16a2/loaddata.txt | 40 + .../sdram/mt48lc4m16a2/mt48lc4m16a2.vhd | 1356 ++ .../memory/sdram/mt48lc4m16a2/mti_pkg.vhd | 128 + .../memory/sdram/mt48lc4m16a2/outdata0.txt | 0 .../memory/sdram/mt48lc4m16a2/outdata1.txt | 0 .../memory/sdram/mt48lc4m16a2/outdata2.txt | 0 .../memory/sdram/mt48lc4m16a2/outdata3.txt | 0 .../memory/sdram/mt48lc4m16a2/readme.txt | 14 + .../memory/sdram/mt48lc4m16a2/runall.do | 42 + .../memory/sdram/mt48lc4m16a2/stdlogar.vhd | 2247 +++ lib/models/memory/sdram/mt48lc4m16a2/test.do | 5 + lib/models/memory/sdram/mt48lc4m16a2/test.txt | 99 + lib/models/memory/sdram/mt48lc4m16a2/test.vhd | 196 + .../memory/sdram/mt48lc4m16a2/util1164.vhd | 124 + .../memory/sdram/mt48lc4m16a2/vec_gen.vhd | 373 + .../memory/sdram/mt48lc4m16a2/vector.do | 4 + lib/models/memory/sdram/mt48lc4m16a2/wave.do | 34 + .../sdram/mt48lc4m32b2/mt48lc4m32b2.vhd | 1148 ++ lib/models/memory/sdram/mt48lc4m32b2/test.do | 5 + lib/models/memory/sdram/mt48lc4m32b2/test.vhd | 309 + lib/models/memory/sdram/mt48lc4m32b2/wave.do | 26 + lib/models/memory/sdram/mt48lc64m4a2/base.do | 5 + .../memory/sdram/mt48lc64m4a2/ed_comnd.vhd | 345 + .../memory/sdram/mt48lc64m4a2/io_utils.vhd | 266 + .../sdram/mt48lc64m4a2/mt48lc64m4a2.vhd | 1055 ++ .../memory/sdram/mt48lc64m4a2/mti_pkg.vhd | 129 + .../memory/sdram/mt48lc64m4a2/readme.txt | 14 + .../memory/sdram/mt48lc64m4a2/stdlogar.vhd | 2247 +++ lib/models/memory/sdram/mt48lc64m4a2/test.do | 5 + lib/models/memory/sdram/mt48lc64m4a2/test.txt | 98 + lib/models/memory/sdram/mt48lc64m4a2/test.vhd | 168 + .../memory/sdram/mt48lc64m4a2/util1164.vhd | 124 + .../memory/sdram/mt48lc64m4a2/vec_gen.vhd | 372 + .../memory/sdram/mt48lc64m4a2/vector.do | 4 + lib/models/memory/sdram/mt48lc64m4a2/wave.do | 31 + lib/models/memory/sdram/mt48lc8m16a2/base.do | 5 + .../memory/sdram/mt48lc8m16a2/ed_comnd.vhd | 349 + .../memory/sdram/mt48lc8m16a2/io_utils.vhd | 266 + .../memory/sdram/mt48lc8m16a2/loaddata.txt | 40 + .../sdram/mt48lc8m16a2/mt48lc8m16a2.vhd | 1426 ++ .../memory/sdram/mt48lc8m16a2/mti_pkg.vhd | 129 + .../memory/sdram/mt48lc8m16a2/outdata0.txt | 33 + .../memory/sdram/mt48lc8m16a2/outdata1.txt | 0 .../memory/sdram/mt48lc8m16a2/outdata2.txt | 0 .../memory/sdram/mt48lc8m16a2/outdata3.txt | 0 .../memory/sdram/mt48lc8m16a2/readme.txt | 14 + .../memory/sdram/mt48lc8m16a2/runall.do | 49 + .../memory/sdram/mt48lc8m16a2/stdlogar.vhd | 2247 +++ lib/models/memory/sdram/mt48lc8m16a2/test.do | 5 + lib/models/memory/sdram/mt48lc8m16a2/test.txt | 115 + lib/models/memory/sdram/mt48lc8m16a2/test.vhd | 197 + .../memory/sdram/mt48lc8m16a2/util1164.vhd | 124 + .../memory/sdram/mt48lc8m16a2/vec_gen.vhd | 364 + .../memory/sdram/mt48lc8m16a2/vector.do | 4 + lib/models/memory/sdram/mt48lc8m16a2/wave.do | 33 + lib/models/memory/sdram/mt48lc8m8a2/base.do | 5 + .../memory/sdram/mt48lc8m8a2/ed_comnd.vhd | 370 + .../memory/sdram/mt48lc8m8a2/io_utils.vhd | 266 + .../memory/sdram/mt48lc8m8a2/loaddata.txt | 41 + .../memory/sdram/mt48lc8m8a2/mt48lc8m8a2.vhd | 1351 ++ .../memory/sdram/mt48lc8m8a2/mti_pkg.vhd | 129 + .../memory/sdram/mt48lc8m8a2/outdata0.txt | 35 + .../memory/sdram/mt48lc8m8a2/outdata1.txt | 35 + .../memory/sdram/mt48lc8m8a2/outdata2.txt | 35 + .../memory/sdram/mt48lc8m8a2/outdata3.txt | 35 + .../memory/sdram/mt48lc8m8a2/readme.txt | 14 + .../memory/sdram/mt48lc8m8a2/stdlogar.vhd | 2247 +++ lib/models/memory/sdram/mt48lc8m8a2/test.do | 5 + lib/models/memory/sdram/mt48lc8m8a2/test.txt | 103 + lib/models/memory/sdram/mt48lc8m8a2/test.vhd | 196 + .../memory/sdram/mt48lc8m8a2/util1164.vhd | 124 + .../memory/sdram/mt48lc8m8a2/vec_gen.vhd | 319 + lib/models/memory/sdram/mt48lc8m8a2/vector.do | 4 + lib/models/memory/sdram/mt48lc8m8a2/wave.do | 31 + .../sdram/mt48v2m32lffc/mt48v2m32lffc.vhd | 1163 ++ lib/models/memory/sdram/mt48v2m32lffc/test.do | 5 + .../memory/sdram/mt48v2m32lffc/test.vhd | 309 + lib/models/memory/sdram/mt48v2m32lffc/wave.do | 26 + 217 files changed, 152127 insertions(+) create mode 100644 lib/models/memory/flash/serial/S25fl064a/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl064a/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl064a/model/s25fl064a.v create mode 100644 lib/models/memory/flash/serial/S25fl064a/model/s25fl064a.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_verilog.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064a/utilities/gen_utils.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064k/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl064k/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl064k/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.v create mode 100644 lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064k/utilities/gen_utils.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064p/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl064p/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl064p/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.v create mode 100644 lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl064p/utilities/gen_utils.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128k/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl128k/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl128k/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.v create mode 100644 lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128k/utilities/gen_utils.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128s/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl128s/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl128s/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.v create mode 100644 lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl128s/utilities/gen_utils.vhd create mode 100644 lib/models/memory/flash/serial/S25fl256s/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl256s/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl256s/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.v create mode 100644 lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.vhd create mode 100644 lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl256s/utilities/gen_utils.vhd create mode 100644 lib/models/memory/flash/serial/S25fl512s/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl512s/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl512s/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.sv create mode 100644 lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.v create mode 100644 lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.vhd create mode 100644 lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl512s/utilities/gen_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/dumpdata.txt create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/loaddata.txt create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/mt48lc16m16a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/test.txt create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m16a2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc16m8a2/mt48lc16m8a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m8a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc16m8a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc16m8a2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/io_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/mt48lc1m16a1.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/readme.txt create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/stdlogar.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/test.txt create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/util1164.vhd create mode 100644 lib/models/memory/sdram/mt48lc1m16a1/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/base.do create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/io_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/mt48lc32m4a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/readme.txt create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/stdlogar.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/test.txt create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/util1164.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/vector.do create mode 100644 lib/models/memory/sdram/mt48lc32m4a2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/base.do create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/io_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/loaddata.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/mt48lc4m16a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/outdata0.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/outdata1.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/outdata2.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/outdata3.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/readme.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/runall.do create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/stdlogar.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/test.txt create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/util1164.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/vector.do create mode 100644 lib/models/memory/sdram/mt48lc4m16a2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc4m32b2/mt48lc4m32b2.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m32b2/test.do create mode 100644 lib/models/memory/sdram/mt48lc4m32b2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc4m32b2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/base.do create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/io_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/mt48lc64m4a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/readme.txt create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/stdlogar.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/test.txt create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/util1164.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/vector.do create mode 100644 lib/models/memory/sdram/mt48lc64m4a2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/base.do create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/io_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/loaddata.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/mt48lc8m16a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/outdata0.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/outdata1.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/outdata2.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/outdata3.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/readme.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/runall.do create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/stdlogar.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/test.txt create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/util1164.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/vector.do create mode 100644 lib/models/memory/sdram/mt48lc8m16a2/wave.do create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/base.do create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/ed_comnd.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/io_utils.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/loaddata.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/mt48lc8m8a2.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/mti_pkg.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/outdata0.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/outdata1.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/outdata2.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/outdata3.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/readme.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/stdlogar.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/test.do create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/test.txt create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/test.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/util1164.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/vec_gen.vhd create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/vector.do create mode 100644 lib/models/memory/sdram/mt48lc8m8a2/wave.do create mode 100644 lib/models/memory/sdram/mt48v2m32lffc/mt48v2m32lffc.vhd create mode 100644 lib/models/memory/sdram/mt48v2m32lffc/test.do create mode 100644 lib/models/memory/sdram/mt48v2m32lffc/test.vhd create mode 100644 lib/models/memory/sdram/mt48v2m32lffc/wave.do diff --git a/lib/models/memory/flash/serial/S25fl064a/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl064a/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl064a/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl064a/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 SO) = tpd_SCK_SO; + (CSNeg => SO) = tpd_CSNeg_SO; + (HOLDNeg => SO) = tpd_HOLDNeg_SO; + +//////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +//////////////////////////////////////////////////////////////////////////////// + $setup ( WNeg , negedge CSNeg, tsetup_WNeg_CSNeg, Viol); + $setup ( negedge HOLDNeg, posedge SCK, tsetup_HOLDNeg_SCK, Viol); + $setup ( posedge SCK, posedge HOLDNeg, tsetup_SCK_HOLDNeg, Viol); + + $hold ( posedge CSNeg, WNeg, thold_WNeg_CSNeg, Viol); + $hold ( posedge SCK, negedge HOLDNeg, thold_HOLDNeg_SCK, Viol); + $hold ( posedge HOLDNeg, posedge SCK, thold_SCK_HOLDNeg, Viol); + + $setuphold ( posedge SCK, SI, tsetup_SI_SCK, thold_SI_SCK, Viol); + $setuphold ( posedge SCK, CSNeg, tsetup_CSNeg_SCK, + thold_CSNeg_SCK, Viol); + + $width (posedge SCK, tpw_SCK_posedge); + $width (negedge SCK, tpw_SCK_negedge); + + $width (posedge CSNeg, tpw_CSNeg_posedge); + + $period (posedge SCK &&& rd, tperiod_SCK_rd); + $period (posedge SCK &&& fast_rd, tperiod_SCK_fast_rd); + + endspecify + +//////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +//////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE =4'd0; + parameter WRITE_SR =4'd1; + parameter DP_DOWN =4'd2; + parameter SECTOR_ER =4'd3; + parameter BULK_ER =4'd4; + parameter PAGE_PG =4'd5; + + reg [3:0] current_state; + reg [3:0] next_state; + +// Instructions + parameter NONE =5'd0; + parameter WREN =5'd1; + parameter WRDI =5'd2; + parameter WRSR =5'd3; + parameter RDSR =5'd4; + parameter READ =5'd5; + parameter FAST_READ =5'd6; + parameter SE =5'd8; + parameter BE =5'd9; + parameter PP =5'd10; + parameter DP =5'd11; + parameter RDID =5'd12; + parameter RES_READ_ES =5'd13; + + reg [4:0] Instruct; + +//Bus cycle states + parameter STAND_BY =3'd0; + parameter CODE_BYTE =3'd1; + parameter ADDRESS_BYTES =3'd2; + parameter DUMMY_BYTES =3'd3; + parameter DATA_BYTES =3'd4; + + reg [2:0] bus_cycle_state; + + initial + begin : Init + + write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + + PDONE = 1'b1; + PSTART = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + DP_in = 1'b0; + DP_out = 1'b0; + RES_in = 1'b0; + RES_out = 1'b0; + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + Sec_Prot = 0; + end + + // initialize memory + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl016a.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + end + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + always @(posedge DP_in) + begin:TDPr + #tdevice_DP DP_out = DP_in; + end + always @(negedge DP_in) + begin:TDPf + #1 DP_out = DP_in; + end + + always @(posedge RES_in) + begin:TRESr + #tdevice_RES RES_out = RES_in; + end + always @(negedge RES_in) + begin:TRESf + #1 RES_out = RES_in; + end + + always @(next_state or PoweredUp) + begin: StateTransition + if (PoweredUp) + begin + current_state = next_state; + end + end + + always @(PoweredUp) + begin:CheckCEOnPowerUP + if ((~PoweredUp) && (~CSNeg_ipd)) + $display ("Device is selected during Power Up"); + end + +// /////////////////////////////////////////////////////////////////////////// +// // Instruction cycle decode +// /////////////////////////////////////////////////////////////////////////// + integer data_cnt = 0; + integer addr_cnt = 0; + integer code_cnt = 0; + integer dummy_cnt = 0; + integer bit_cnt = 0; + reg[2047:0] Data_in = 2048'b0; + reg[7:0] code = 8'b0; + reg[7:0] code_in = 8'b0; + reg[7:0] Byte_slv = 8'b0; + reg[HiAddrBit:0] addr_bytes; + reg[23:0] Address_in = 8'b0; + + always @(negedge CSNeg_ipd) + begin: Buscycle1 + if (bus_cycle_state==STAND_BY) + begin + bus_cycle_state = CODE_BYTE; + Instruct = NONE; + write = 1'b1; + code_cnt = 0; + addr_cnt = 0; + data_cnt = 0; + dummy_cnt = 0; + end + end + + always @(posedge SCK_ipd) + begin: Buscycle2 + integer i; + if ( HOLDNeg_ipd) + begin + case (bus_cycle_state) + CODE_BYTE : + begin + code_in[code_cnt] = SI_ipd; + code_cnt = code_cnt + 1; + if (code_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + code[i] = code_in[7-i]; + end + case(code) + 8'b00000110 : + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : + begin + Instruct = WRSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000101 : + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00001011 : + begin + Instruct = FAST_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10101011 : + begin + Instruct = RES_READ_ES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b11011000 : + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11000111 : + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b00000010 : + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10111001 : + begin + Instruct = DP; + bus_cycle_state = DATA_BYTES; + end + 8'b10011111 : + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + endcase + end + end + + ADDRESS_BYTES : + begin + Address_in[addr_cnt] = SI_ipd; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct == FAST_READ) + bus_cycle_state = DUMMY_BYTES; + else + bus_cycle_state = DATA_BYTES; + end + end + + DUMMY_BYTES : + begin + dummy_cnt = dummy_cnt + 1; + if ((dummy_cnt == BYTE && Instruct == FAST_READ) || + (dummy_cnt == 3*BYTE && Instruct == RES_READ_ES)) + bus_cycle_state = DATA_BYTES; + end + + DATA_BYTES : + begin + if (data_cnt > 2047) + //In case of PP, if more than 256 bytes are + //sent to the device + begin + if (bit_cnt == 0) + begin + for (i=0;i<=(255*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[2040 + bit_cnt] = SI_ipd; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_ipd; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + endcase + end + end + + always @(negedge SCK_ipd) + begin: Buscycle3 + if (bus_cycle_state==DATA_BYTES && (~CSNeg_ipd) && (HOLDNeg_ipd)) + if (Instruct == READ || Instruct == RES_READ_ES || + Instruct == FAST_READ || Instruct == RDSR || + Instruct == RDID) + read_out = 1'b1; + #1 read_out = 1'b0; + end + + always @(posedge CSNeg_ipd) + begin: Buscycle4 + integer i; + integer j; + if (bus_cycle_state == DATA_BYTES) + begin + bus_cycle_state = STAND_BY; + if (HOLDNeg_ipd) + begin + case (Instruct) + WREN, + WRDI, + DP, + BE, + SE : + begin + if (data_cnt == 0) + write = 1'b0; + end + + RES_READ_ES, + RDID : + begin + write = 1'b0; + end + + WRSR : + begin + if (data_cnt == BYTE) + write = 1'b0; + Status_reg_in = Data_in[7:0]; + end + + PP : + begin + if ((data_cnt > 0) && ((data_cnt % 8) == 0)) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = Data_in[(i*8) + (7-j)]; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE) + Byte_number = 255; + else + Byte_number = ((data_cnt/8) - 1); + end + end + endcase + end + end + + if (bus_cycle_state == DUMMY_BYTES) + begin + bus_cycle_state = STAND_BY; + if (HOLDNeg_ipd && Instruct == RES_READ_ES) + write = 1'b0; + end + + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Program Operations +// // start +// ///////////////////////////////////////////////////////////////////////// + + event pdone_event; + + always @(PSTART) + begin + if (PSTART && PDONE) + begin + PDONE = 1'b0; + ->pdone_event; + end + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #tdevice_PP PDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Write Status Register Operation +// // start +// ///////////////////////////////////////////////////////////////////////// + + event wdone_event; + + always @(WSTART) + begin + if (WSTART && WDONE) + begin + WDONE = 1'b0; + ->wdone_event; + end + end + + always @(wdone_event) + begin:wdone_process + WDONE = 1'b0; + #tdevice_WR WDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Erase Operations +// ///////////////////////////////////////////////////////////////////////// + integer cnt_erase = 0; + time duration_erase; + + event edone_event; + + always @(ESTART) + begin: erase + if (ESTART && EDONE) + begin + + if (Instruct == BE) + begin + duration_erase = tdevice_BE; + end + else //if (Instruct == SE) + begin + duration_erase = tdevice_SE; + end + + EDONE = 1'b0; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_erase EDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + integer sect; + + always @(negedge write) + begin: StateGen1 + + case (current_state) + IDLE : + begin + if (~write) + begin + if (Instruct == WRSR && Status_reg[1]) + begin + if (~(Status_reg[7] && (~WNeg_ipd))) + next_state = WRITE_SR; + end + else if (Instruct == PP && Status_reg[1]) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + next_state = PAGE_PG; + end + else if (Instruct == SE && Status_reg[1]) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + next_state = SECTOR_ER; + end + else if (Instruct == BE && Status_reg[1]) + begin + if (Status_reg[2] == 1'b0 && Status_reg[3] == 1'b0 && + Status_reg[4] == 1'b0) + next_state = BULK_ER; + end + else if (Instruct == DP) + next_state = DP_DOWN; + else + next_state = IDLE; + end + end + + DP_DOWN: + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + next_state = IDLE; + end + end + + endcase + end + + always @(posedge PDONE) + begin: StateGen2 + if (current_state==PAGE_PG) + begin + next_state = IDLE; + end + end + + always @(posedge WDONE) + begin: StateGen3 + if (current_state==WRITE_SR) + begin + next_state = IDLE; + end + end + + always @(posedge EDONE) + begin: StateGen4 + if (current_state==SECTOR_ER || current_state==BULK_ER) + begin + next_state = IDLE; + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general funcionality + /////////////////////////////////////////////////////////////////////////// + + always @(posedge read_out) + begin + if (PoweredUp == 1'b1) + ->oe_event; + end + + always @(oe_event) + begin + oe = 1'b1; + #1 oe = 1'b0; + end + + always @(Instruct) + begin + read_cnt = 0; + end + + always @(change_addr) + begin + if (change_addr) + read_addr = Address; + end + + always @(Instruct) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + end + + always @(oe or current_state) + begin + case (current_state) + IDLE : + begin + if (oe && RES_in == 1'b0) + begin + if (Instruct == RDSR) + begin + //Read Status Register + SO_zd = Status_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + //Read Memory array + if (Instruct == READ) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + end + data_out[7:0] = Mem[read_addr]; + SO_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == RDID) + begin + // Read ID + ident_out[23:0] = DeviceID; + SO_zd = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RES_READ_ES) + begin + // Read ID + data_out[7:0] = ES; + SO_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe && RES_in == 1'b1) + begin + $display ("Command results can be corrupted"); + SO_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + WRITE_SR, + SECTOR_ER, + BULK_ER, + PAGE_PG : + begin + if (oe && Instruct == RDSR) + begin + //Read Status Register + SO_zd = Status_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + DP_DOWN : + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + RES_in = 1'b1; + end + else if (oe && Instruct == RES_READ_ES) + begin + // Read ES + data_out[7:0] = ES; + SO_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + endcase + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + + integer sector; + integer WData [0:255]; + integer Addr; + + always @(negedge write) + begin : Output_generation + integer i; + + case (current_state) + IDLE : + begin + if (~write) + begin + if (RES_in == 1'b1) + begin + $display ("Command results can be corrupted"); + end + if (Instruct == WREN) + Status_reg[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg[1] = 1'b0; + else if (Instruct == WRSR && Status_reg[1] && + (~(Status_reg[7] == 1'b1 && WNeg_ipd == 1'b0))) + begin + WSTART = 1'b1; + WSTART <= #1 1'b0; + Status_reg[0] = 1'b1; + end + else if (Instruct == PP && Status_reg[1] == 1'b1) + begin + sector = Address / 20'h10000; + if (Sec_Prot[sector] == 1'b0) + begin + PSTART = 1'b1; + PSTART <= #1 1'b0; + Status_reg[0] = 1'b1; + Addr = Address; + SA = sector; + wr_cnt = Byte_number; + for (i=0;i<=wr_cnt;i=i+1) + begin + if (Viol!=1'b0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + end + else if (Instruct == SE && Status_reg[1] == 1'b1) + begin + sector = Address / 20'h10000; + if (Sec_Prot[sector] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + Status_reg[0] = 1'b1; + Addr = Address; + end + end + else if (Instruct == BE && Status_reg[1] == 1'b1 && + Status_reg[2] == 1'b0 && Status_reg[3] == 1'b0 && + Status_reg[4] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + Status_reg[0] = 1'b1; + end + else if (Instruct == DP && RES_in == 1'b0) + DP_in = 1'b1; + end + + end + + DP_DOWN : + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + RES_in = 1'b1; + end + end + + endcase + end + + always @(RES_out) + begin : DPDOWN1 + if (RES_out) + begin + RES_in = 1'b0; + end + end + + always @(current_state or EDONE) + begin: ERASE1 + integer i; + case (current_state) + + SECTOR_ER : + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + + BULK_ER : + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = -1; + end + + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + endcase + end + + always @(current_state or WDONE) + begin: WRSR1 + if (current_state == WRITE_SR) + begin + if (WDONE) + begin + Status_reg[0] = 1'b0;//WIP + Status_reg[1] = 1'b0;//WEL + Status_reg[7] = Status_reg_in[0];//MSB first, SRWD + Status_reg[4] = Status_reg_in[3];//MSB first, BP2 + Status_reg[3] = Status_reg_in[4];//MSB first, BP1 + Status_reg[2] = Status_reg_in[5];//MSB first, BP0 + case (Status_reg[4:2]) + + 3'b000 : + begin + Sec_Prot = 128'h00000000000000000000000000000000; + end + + 3'b001 : + begin + Sec_Prot = 128'hC0000000000000000000000000000000; + end + + 3'b010 : + begin + Sec_Prot = 128'hF0000000000000000000000000000000; + end + + 3'b011 : + begin + Sec_Prot = 128'hFF000000000000000000000000000000; + end + + 3'b100 : + begin + Sec_Prot = 128'hFFFF0000000000000000000000000000; + end + + 3'b101 : + begin + Sec_Prot = 128'hFFFFFFFF000000000000000000000000; + end + + 3'b110 : + begin + Sec_Prot = 128'hFFFFFFFFFFFFFFFF0000000000000000; + end + + 3'b111 : + begin + Sec_Prot = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + end + + endcase + end + end + end + + always @(current_state or PDONE) + begin: PPPG1 + integer i, j; + if (current_state == PAGE_PG) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + if ((Addr + wr_cnt) > AddrHi) + wr_cnt = AddrHi - Addr; + for (i=Addr;i<=Addr+wr_cnt;i=i+1) + begin + new_int = WData[i-Addr]; + old_int = Mem[i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + if (~old_bit[j]) + new_bit[j]=1'b0; + new_int=new_bit; + end + + WData[i-Addr]= new_int; + end + else + begin + WData[i-Addr] = -1; + end + end + + for (i=Addr;i<=Addr+wr_cnt;i=i+1) + begin + Mem[i] = -1; + end + + if (PDONE) + begin + Status_reg[0] = 1'b0;//wip + Status_reg[1] = 1'b0;// wel + for (i=Addr;i<=Addr+wr_cnt;i=i+1) + begin + Mem[i] = WData[i-Addr]; + end + end + end + end + +// Output Control + always @(CSNeg_ipd or HOLDNeg_ipd or SCK_ipd) + begin + //Output Disable Control + if (CSNeg_ipd ) + SO_zd = 1'bZ; + end + + always @(SO_zd or HOLDNeg_ipd) + begin + if (HOLDNeg_ipd == 1) + SO_z = SO_zd; + else + SO_z = 1'bZ; + end + +// Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + + sector = Addr / 20'h10000; + AddrLOW = sector * 20'h10000; + AddrHIGH = sector * 20'h10000 + 16'hFFFF; + + end + endtask + +// Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + + page = Addr / 16'h100; + AddrLOW = page * 16'h100; + AddrHIGH = page * 16'h100 + 8'hFF; + + end + endtask + +endmodule diff --git a/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a.vhd b/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a.vhd new file mode 100644 index 0000000..445d593 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a.vhd @@ -0,0 +1,1256 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl064a.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2006-2007 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 G.Gojanovic 05 May 11 Inital Release +-- V1.1 D.Randjelovic 06 Apr 11 MSB of latched address is ignored +-- V1.2 D.Randjelovic 06 May 04 Page Program Command used with the +-- single byte data corrected. +-- Release from Deep Power Down when +-- Electronic Signature is not read +-- fixed +-- V1.3 D.Stanojkovic 07 Jul 02 Correction to enable testing in NCSim +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: Flash Memory +-- Part: S25FL064A +-- +-- Description: 64 Megabit Serial Flash Memory with 50MHz SPI Bus Interface +-- +------------------------------------------------------------------------------- +-- Comments : +-- When testing with NCSim default value for TimingModel in +-- generic list should be removed, otherwise backannotation of this value +-- will not be done properly +------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Known Bugs: +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl064a IS + GENERIC ( + -- tipd delays: interconnect path delays + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_SCK_SO : VitalDelayType01Z := UnitDelay01Z;--tV + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tDIS + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tLZ,tHZ + + --tsetup values + tsetup_SI_SCK : VitalDelayType := UnitDelay; --tsuDAT / + tsetup_CSNeg_SCK : VitalDelayType := UnitDelay; --tCSS / + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; --tHD / + tsetup_WNeg_CSNeg : VitalDelayType := UnitDelay; --tWPS \ + + --thold values + thold_SI_SCK : VitalDelayType := UnitDelay; --thdDAT / + thold_CSNeg_SCK : VitalDelayType := UnitDelay; --tCSH / + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; --tCD / + thold_WNeg_CSNeg : VitalDelayType := UnitDelay; --tWPH \ + + --tpw values: pulse width + tpw_SCK_posedge : VitalDelayType := UnitDelay; --tWH + tpw_SCK_negedge : VitalDelayType := UnitDelay; --tWL + tpw_CSNeg_posedge : VitalDelayType := UnitDelay; --tCS + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_rd : VitalDelayType := UnitDelay; -- fSCK=33MHz + tperiod_SCK_fast_rd : VitalDelayType := UnitDelay; -- fSCK=50MHz + + -- tdevice values: values for internal delays + -- Page Program Operation + tdevice_PP : VitalDelayType := 3 ms; --tPP + --Sector Erase Operation + tdevice_SE : VitalDelayType := 3 sec; --tSE + --Bulk Erase Operation + tdevice_BE : VitalDelayType := 384 sec; --tBE + --Write Status Register Operation + tdevice_WR : VitalDelayType := 60 ms; --tW + --Deep Power Down + tdevice_DP : VitalDelayType := 3 us; --tDP + --Release from Software Protect Mode + tdevice_RES : VitalDelayType := 30 us; --tRES + --VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 10 ms; + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING := "s25fl064a.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= DefaultTimingModel + ); + PORT ( + SCK : IN std_ulogic := 'U'; --serial clock input + SI : IN std_ulogic := 'U'; --serial data input + CSNeg : IN std_ulogic := 'U'; -- chip select input + HOLDNeg : IN std_ulogic := 'U'; -- hold input + WNeg : IN std_ulogic := 'U'; -- write protect input + SO : OUT std_ulogic := 'U' --serial data output + ); + ATTRIBUTE VITAL_LEVEL0 of s25fl064a : ENTITY IS TRUE; +END s25fl064a; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of s25fl064a IS + ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; + + CONSTANT PartID : STRING := "s25fl064a"; + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 22; + CONSTANT AddrRANGE : NATURAL := 16#7FFFFF#; + CONSTANT BYTE : NATURAL := 8; + --Electronic Signature + CONSTANT ES : NATURAL := 16#16#; + --Device ID + --Manufacturer Identification && Memory Type && Memory Capacity + CONSTANT DeviceID : NATURAL := 16#010216#; + +-- interconnect path delay signals + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL WNeg_ipd : std_ulogic := 'U'; + + --- internal delays + SIGNAL PP_in : std_ulogic := '0'; + SIGNAL PP_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL SE_in : std_ulogic := '0'; + SIGNAL SE_out : std_ulogic := '0'; + SIGNAL BE_in : std_ulogic := '0'; + SIGNAL BE_out : std_ulogic := '0'; + SIGNAL WR_in : std_ulogic := '0'; + SIGNAL WR_out : std_ulogic := '0'; + SIGNAL DP_in : std_ulogic := '0'; + SIGNAL DP_out : std_ulogic := '0'; + SIGNAL RES_in : std_ulogic := '0'; + SIGNAL RES_out : std_ulogic := '0'; + +BEGIN + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); + BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); + WR :VitalBuf(WR_out, WR_in, (tdevice_WR ,UnitDelay)); + DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay)); + RES :VitalBuf(RES_out, RES_in, (tdevice_RES ,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_2 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_3 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_4 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + w_5 : VitalWireDelay (WNeg_ipd, WNeg, tipd_WNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + DP_DOWN, + WRITE_SR, + SECTOR_ER, + BULK_ER, + PAGE_PG + ); + + -- Instruction Type + TYPE instruction_type IS (NONE, + WREN, + WRDI, + WRSR, + RDSR, + READ, + RDID, + FAST_READ, + SE, + BE, + PP, + DP, + RES_READ_ES + ); + + TYPE WByteType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; + --Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL WByte : WByteType := (others => 0); + SIGNAL Instruct : instruction_type; + --zero delay signal + SIGNAL SO_zd : std_logic :='Z'; + --HOLD delay on output data + SIGNAL SO_z : std_logic :='Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + SHARED VARIABLE Status_reg : std_logic_vector(7 downto 0) + := (others => '0'); + + SIGNAL Status_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + ALIAS WEL :std_logic IS Status_reg(1); + ALIAS WIP :std_logic IS Status_reg(0); + ALIAS BP0 :std_logic IS Status_reg(2); + ALIAS BP1 :std_logic IS Status_reg(3); + ALIAS BP2 :std_logic IS Status_reg(4); + ALIAS SRWD :std_logic IS Status_reg(7); + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL fast_rd : boolean := true; + SIGNAL rd : boolean := false; + + SIGNAL change_addr : std_logic := '0'; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; -- Page Prog. Done + SIGNAL PSTART : std_logic := '0'; --Start Page Programming + + SIGNAL WDONE : std_logic := '1'; -- Write. Done + SIGNAL WSTART : std_logic := '0'; --Start Write + + SIGNAL ESTART : std_logic := '0'; --Start Erase + SIGNAL EDONE : std_logic := '1'; --Erase Done + + SIGNAL SA : NATURAL RANGE 0 TO SecNum := 0; + SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0; + + SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum downto 0) := + (OTHERS => '0'); + + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO SecNum; + BEGIN + sector := Addr/16#10000#; + AddrLOW := sector*16#10000#; + AddrHIGH := sector*16#10000# + 16#0FFFF#; + END AddrHILO_SEC; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO 65535; + BEGIN + page := Addr/16#100#; + AddrLOW := Page*16#100#; + AddrHIGH := Page*16#100# + 16#FF#; + END AddrHILO_PG; + + BEGIN + ---------------------------------------------------------------------------- + --Power Up time; + --------------------------------------------------------------------------- + + PoweredUp <= '1' AFTER tdevice_PU; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SI_ipd, SCK_ipd, CSNeg_ipd, HOLDNeg_ipd, + WNeg_ipd) + -- Timing Check Variables + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_HOLD_SCK : X01 := '0'; + VARIABLE TD_HOLD_SCK : VitalTimingDataType; + + VARIABLE Tviol_CS_SCK : X01 := '0'; + VARIABLE TD_CS_SCK : VitalTimingDataType; + + VARIABLE Tviol_WS_CS : X01 := '0'; + VARIABLE TD_WS_CS : VitalTimingDataType; + + VARIABLE Tviol_WH_CS : X01 := '0'; + VARIABLE TD_WH_CS : VitalTimingDataType; + + VARIABLE Pviol_CS : X01 := '0'; + VARIABLE PD_CS : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK : X01 := '0'; + VARIABLE PD_SCK : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_rd : X01 := '0'; + VARIABLE PD_SCK_rd : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_rd: X01 := '0'; + VARIABLE PD_SCK_fast_rd : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between SI and SCK + VitalSetupHoldCheck ( + TestSignal => SI_ipd, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK, + SetupLow => tsetup_SI_SCK, + HoldHigh => thold_SI_SCK, + HoldLow => thold_SI_SCK, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNeg_ipd, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupLow => tsetup_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLD_SCK, + Violation => Tviol_HOLD_SCK + ); + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK, + SetupLow => tsetup_CSNeg_SCK, + HoldHigh => thold_CSNeg_SCK, + HoldLow => thold_CSNeg_SCK, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CS_SCK, + Violation => Tviol_CS_SCK + ); + + -- Setup Check between W# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WNeg_ipd, + TestSignalName => "W#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WNeg_CSNeg, + CheckEnabled => true, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WS_CS, + Violation => Tviol_WS_CS + ); + + -- Hold Check between W# and CS# / + VitalSetupHoldCheck ( + TestSignal => WNeg_ipd, + TestSignalName => "W#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WNeg_CSNeg, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WH_CS, + Violation => Tviol_WH_CS + ); + + -- Period Check CS# m + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_posedge, + PeriodData => PD_CS, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CS, + HeaderMsg => InstancePath & PartID, + CheckEnabled => true ); + + -- Period Check SCK for everything but READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_negedge, + PulseWidthHigh => tpw_SCK_posedge, + PeriodData => PD_SCK, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK, + HeaderMsg => InstancePath & PartID, + CheckEnabled => true ); + + -- Period Check SCK for READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_rd, + PeriodData => PD_SCK_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for other than READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast_rd, + PeriodData => PD_SCK_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + Violation := Tviol_SI_SCK OR + Tviol_HOLD_SCK OR + Tviol_CS_SCK OR + Tviol_WS_CS OR + Tviol_WH_CS OR + Pviol_SCK OR + Pviol_SCK_rd OR + Pviol_SCK_fast_rd OR + Pviol_CS; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; +END PROCESS VITALTimingCheck; + + ---------------------------------------------------------------------------- + -- sequential process for FSM state transition + ---------------------------------------------------------------------------- + StateTransition : PROCESS(next_state, PoweredUp) + + BEGIN + IF PoweredUp = '1' THEN + current_state <= next_state; + END IF; +END PROCESS StateTransition; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_ipd, SI_ipd, RES_in) + + TYPE bus_cycle_type IS (STAND_BY, + CODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + DATA_BYTES + ); + + VARIABLE bus_cycle_state : bus_cycle_type; + + VARIABLE data_cnt : NATURAL := 0; + VARIABLE addr_cnt : NATURAL := 0; + VARIABLE code_cnt : NATURAL := 0; + VARIABLE dummy_cnt : NATURAL := 0; + VARIABLE bit_cnt : NATURAL := 0; + VARIABLE Data_in : std_logic_vector(2047 downto 0) + := (others => '0'); + VARIABLE code : std_logic_vector(7 downto 0); + VARIABLE code_in : std_logic_vector(7 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + VARIABLE addr_bytes : std_logic_vector(HiAddrBit downto 0); + VARIABLE Address_in : std_logic_vector(23 downto 0); + BEGIN + + CASE bus_cycle_state IS + WHEN STAND_BY => + IF falling_edge(CSNeg_ipd) THEN + Instruct <= NONE; + write <= '1'; + code_cnt := 0; + addr_cnt := 0; + data_cnt := 0; + dummy_cnt := 0; + bus_cycle_state := CODE_BYTE; + END IF; + + WHEN CODE_BYTE => + IF rising_edge(SCK_ipd) AND HOLDNeg_ipd = '1' THEN + Code_in(code_cnt) := SI_ipd; + code_cnt := code_cnt + 1; + IF code_cnt = BYTE THEN + --MSB first + FOR I IN 7 DOWNTO 0 LOOP + code(i) := code_in(7-i); + END LOOP; + CASE code IS + WHEN "00000110" => + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => + Instruct <= WRSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000101" => + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00001011" => + Instruct <= FAST_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10011111" => + Instruct <= RDID; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => + Instruct <= RES_READ_ES; + bus_cycle_state := DUMMY_BYTES; + WHEN "11011000" => + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11000111" => + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "00000010" => + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10111001" => + Instruct <= DP; + bus_cycle_state := DATA_BYTES; + WHEN others => + null; + END CASE; + END IF; + END IF; + + WHEN ADDRESS_BYTES => + IF rising_edge(SCK_ipd) AND HOLDNeg_ipd = '1' THEN + Address_in(addr_cnt) := SI_ipd; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 23-HiAddrBit LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF Instruct = FAST_READ THEN + bus_cycle_state := DUMMY_BYTES; + ELSE + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + END IF; + + WHEN DUMMY_BYTES => + IF rising_edge(SCK_ipd) AND HOLDNeg_ipd = '1' THEN + dummy_cnt := dummy_cnt + 1; + IF dummy_cnt = BYTE THEN + IF Instruct = FAST_READ THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF dummy_cnt = 3*BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + bus_cycle_state := STAND_BY; + IF HOLDNeg_ipd = '1' AND Instruct = RES_READ_ES THEN + write <= '0'; + END IF; + END IF; + + WHEN DATA_BYTES => + IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' + AND HOLDNeg_ipd = '1' THEN + IF Instruct = READ OR Instruct = RES_READ_ES + OR Instruct = FAST_READ OR Instruct = RDSR + OR Instruct = RDID THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF rising_edge(SCK_ipd) AND HOLDNeg_ipd = '1' THEN + IF data_cnt > 2047 THEN + --In case of PP, if more than 256 bytes are + --sent to the device + IF bit_cnt = 0 THEN + FOR I IN 0 TO (255*BYTE - 1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in(2040 + bit_cnt) := SI_ipd; + bit_cnt := bit_cnt + 1; + IF bit_cnt = 8 THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SI_ipd; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + bus_cycle_state := STAND_BY; + IF HOLDNeg_ipd = '1' THEN + CASE Instruct IS + WHEN WREN | WRDI | DP | BE | SE => + IF data_cnt = 0 THEN + write <= '0'; + END IF; + WHEN RDID | RES_READ_ES => + write <= '0'; + WHEN WRSR => + IF data_cnt = 8 THEN + write <= '0'; + Status_reg_in <= Data_in(7 downto 0); + --MSB first + END IF; + WHEN PP => + IF ((data_cnt mod 8) = 0 AND + data_cnt > 0) THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 7 DOWNTO 0 LOOP + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + IF data_cnt > 256*BYTE THEN + Byte_number <= 255; + ELSE + Byte_number <= data_cnt/8-1; + END IF; + END IF; + WHEN others => + null; + END CASE; + END IF; + END IF; + + END CASE; + +END PROCESS BusCycleDecode; + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART) + VARIABLE pob : time; + BEGIN + IF LongTimming THEN + pob := tdevice_PP; + ELSE + pob := tdevice_PP / 100; + END IF; + IF rising_edge(PSTART) AND PDONE = '1' THEN + IF NOT Sec_Prot(SA) = '1' THEN + PDONE <= '0', '1' AFTER pob; + END IF; + END IF; +END PROCESS ProgTime; + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WR; + ELSE + wob := tdevice_WR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; +END PROCESS WriteTime; + --------------------------------------------------------------------------- + -- Timing control for the Bulk Erase + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART) + VARIABLE seo : time; + VARIABLE beo : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + seo := tdevice_SE; + beo := tdevice_BE; + ELSE + seo := tdevice_SE / 100; + beo := tdevice_BE / 100; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = BE THEN + duration := beo; + ELSE --Instruct = SE + duration := seo; + END IF; + EDONE <= '0', '1' AFTER duration; + END IF; +END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS + BEGIN + IF CSNeg /= '1' THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + WAIT; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(write, CSNeg, WDONE, PDONE, EDONE) + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + + BEGIN + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + CASE current_state IS + WHEN IDLE => + IF falling_edge(write) THEN + IF Instruct = WRSR AND WEL = '1' + AND not(SRWD = '1' AND WNeg = '0') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + next_state <= WRITE_SR; + ELSIF Instruct = PP AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + next_state <= PAGE_PG; + END IF; + ELSIF Instruct = SE AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + next_state <= SECTOR_ER; + END IF; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0 = '0' AND BP1 = '0' AND BP2 = '0') THEN + next_state <= BULK_ER; + ELSIF Instruct = DP THEN + next_state <= DP_DOWN; + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN BULK_ER | SECTOR_ER => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN DP_DOWN => + IF falling_edge(write) AND Instruct = RES_READ_ES THEN + next_state <= IDLE; + END IF; + + END CASE; + +END PROCESS StateGen; + + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(write,read_out, WDONE, PDONE, EDONE, current_state, + CSNeg_ipd, HOLDNeg_ipd, Instruct, Address, WByte, + RES_out, change_addr, PoweredUp, WNeg_ipd) + + TYPE WDataType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; + + VARIABLE WData : WDataType:= (OTHERS => 0); + + VARIABLE oe : boolean := FALSE; + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + VARIABLE Addr : NATURAL; + + VARIABLE read_cnt : NATURAL; + VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE; + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(23 downto 0); + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + VARIABLE wr_cnt : NATURAL RANGE 0 TO 255; + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + VARIABLE BP : std_logic_vector(2 downto 0) := "000"; + + BEGIN + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + oe := rising_edge(read_out) AND PoweredUp = '1'; + + IF Instruct'EVENT THEN + read_cnt := 0; + fast_rd <= true; + rd <= false; + END IF; + + IF rising_edge(change_addr) THEN + read_addr := Address; + END IF; + + IF RES_out'EVENT AND RES_out = '1' THEN + RES_in <= '0'; + END IF; + + CASE current_state IS + WHEN IDLE => + IF falling_edge(write) THEN + read_cnt := 0; + IF RES_in = '1' THEN + ASSERT false + REPORT InstancePath & partID & "Command results" & + " can be corrupted, a delay of tRES" & + " currently in progress." + SEVERITY WARNING; + END IF; + IF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = WRDI THEN + WEL := '0'; + ELSIF Instruct = WRSR AND WEL = '1' + AND not(SRWD = '1' AND WNeg_ipd = '0') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + WSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + ELSIF Instruct = PP AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + PSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + SA <= sect; + Addr := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' AND Sec_Prot(SA) /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + END IF; + ELSIF Instruct = SE AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + ESTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + Addr := Address; + END IF; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0 = '0' AND BP1 = '0' AND BP2 = '0') THEN + ESTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + END IF; + + ELSIF oe AND RES_in = '0' THEN + IF Instruct = RDSR THEN + --Read Status Register + SO_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ OR Instruct = FAST_READ THEN + --Read Memory array + IF Instruct = READ THEN + fast_rd <= false; + rd <= true; + END IF; + data_out := to_slv(Mem(read_addr),8); + SO_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF Instruct = RDID THEN + --Read Device ID + --can be terminated by driving CSNeg high + --at any time + ident_out := to_slv(DeviceID,24); + SO_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 24 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RES_READ_ES THEN + --Read Electronic Signature + data_out := to_slv(ES,8); + SO_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe AND RES_in = '1' THEN + SO_zd <= 'X'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ASSERT false + REPORT InstancePath & partID & "Command results" & + " can be corrupted, a delay of tRES" & + " currently in progress." + SEVERITY WARNING; + + END IF; + + WHEN WRITE_SR => + + IF oe AND Instruct = RDSR THEN + SO_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + IF WDONE = '1' THEN + WIP := '0'; + WEL := '0'; + SRWD := Status_reg_in(0);--MSB first + BP2 := Status_reg_in(3); + BP1 := Status_reg_in(4); + BP0 := Status_reg_in(5); + BP := BP2 & BP1 & BP0; + CASE BP IS + WHEN "000" => + Sec_Prot := (others => '0'); + WHEN "001" => + Sec_Prot(127) := '1'; + Sec_Prot(126) := '1'; + Sec_Prot(125 downto 0) := (others => '0'); + WHEN "010" => + Sec_Prot(127 downto 124):= (others => '1'); + Sec_Prot(123 downto 0) := (others => '0'); + WHEN "011" => + Sec_Prot(127 downto 120):= to_slv(16#FF#,8); + Sec_Prot(119 downto 0) := (others => '0'); + WHEN "100" => + Sec_Prot(127 downto 112):= to_slv(16#FFFF#,16); + Sec_Prot(111 downto 0) := (others => '0'); + WHEN "101" => + Sec_Prot(127 downto 112):= to_slv(16#FFFF#,16); + Sec_Prot(111 downto 96):= to_slv(16#FFFF#,16); + Sec_Prot(95 downto 0) := (others => '0'); + WHEN "110" => + Sec_Prot(127 downto 112):= to_slv(16#FFFF#,16); + Sec_Prot(111 downto 96):= to_slv(16#FFFF#,16); + Sec_Prot(95 downto 80):= to_slv(16#FFFF#,16); + Sec_Prot(79 downto 64):= to_slv(16#FFFF#,16); + Sec_Prot(63 downto 0) := (others => '0'); + WHEN others => + Sec_Prot := (others => '1'); + END CASE; + END IF; + + WHEN PAGE_PG => + + IF oe AND Instruct = RDSR THEN + SO_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + IF (Addr + wr_cnt) > AddrHi THEN + wr_cnt := AddrHi - Addr; + END IF; + + FOR I IN Addr TO Addr + wr_cnt LOOP + new_int := WData(i-Addr); + old_int := Mem(i); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i-Addr) := new_int; + ELSE + WData(i-Addr) := -1; + END IF; + END LOOP; + + FOR I IN Addr TO Addr + wr_cnt LOOP + Mem (i) := -1; + END LOOP; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN Addr TO Addr + wr_cnt LOOP + Mem(i) := WData(i-Addr); + END LOOP; + END IF; + + WHEN SECTOR_ER => + + IF oe AND Instruct = RDSR THEN + SO_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + + WHEN BULK_ER => + + IF oe AND Instruct = RDSR THEN + SO_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + FOR i IN 0 TO AddrRANGE LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO AddrRANGE LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + + WHEN DP_DOWN => + IF falling_edge(write) THEN + IF Instruct = RES_READ_ES THEN + RES_in <= '1'; + END IF; + ELSIF oe AND Instruct = RES_READ_ES THEN + --Read Electronic Signature + data_out := to_slv(ES,8); + SO_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SO_zd <= 'Z'; + END IF; + +END PROCESS Functional; + + HOLD_FRAME_ON_SO_ZD : PROCESS( SO_zd, HOLDNeg_ipd) + BEGIN + IF (HOLDNeg_ipd = '0') THEN + SO_z <= 'Z'; + ELSE + SO_z <= SO_zd; + END IF; + END PROCESS HOLD_FRAME_ON_SO_ZD; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + MemPreload : PROCESS + + -- text file input variables + FILE mem_file : text is mem_file_name; + VARIABLE ind : NATURAL := 0; + VARIABLE buf : line; + + BEGIN + --------------------------------------------------------------------------- + --s25fl016a memory preload file format ----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaaaaa - stands for address + -- dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=SCREG_LoAddr;i<=SCREG_HiAddr;i=i+1) + begin + Security_Reg[i] = MaxData; + end + + if (UserPreload && !(screg_file_name == "none")) + begin + //s25fl064kSCREG memory file + // / - comment + // @aaa - stands for address of specific Security register + // dd -
is byte to be written at SCREG(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(screg_file_name,Security_Reg); + end + for (i=0;i<=255;i=i+1) + begin + Security_Reg1[i] = Security_Reg[i]; + Security_Reg2[i] = Security_Reg[256+i]; + Security_Reg3[i] = Security_Reg[512+i]; + end + end + + /////////////////////////////////////////////////////////////////////////// + // SFDP - Serial Flash Discoverable Parameter register + initial + begin: InitSFDP + integer i; + integer j; + SFDP_array[8'h00] = 8'h53; + SFDP_array[8'h01] = 8'h46; + SFDP_array[8'h02] = 8'h44; + SFDP_array[8'h03] = 8'h50; + SFDP_array[8'h04] = 8'h01; + SFDP_array[8'h05] = 8'h01; + SFDP_array[8'h06] = 8'h00; + SFDP_array[8'h07] = 8'hFF; + SFDP_array[8'h08] = 8'hEF; + SFDP_array[8'h09] = 8'h00; + SFDP_array[8'h0A] = 8'h01; + SFDP_array[8'h0B] = 8'h04; + SFDP_array[8'h0C] = 8'h80; + SFDP_array[8'h0D] = 8'h00; + SFDP_array[8'h0E] = 8'h00; + SFDP_array[8'h0F] = 8'hFF; + SFDP_array[8'h10] = 8'hEF; + SFDP_array[8'h11] = 8'h00; + SFDP_array[8'h12] = 8'h01; + SFDP_array[8'h13] = 8'h00; + SFDP_array[8'h14] = 8'h90; + SFDP_array[8'h15] = 8'h00; + SFDP_array[8'h16] = 8'h00; + SFDP_array[8'h17] = 8'hFF; + + for (i=24;i<=127;i=i+1) + begin + SFDP_array[i] = MaxData; + end + + SFDP_array[8'h80] = 8'hE5; + SFDP_array[8'h81] = 8'h20; + SFDP_array[8'h82] = 8'hF1; + SFDP_array[8'h83] = 8'hFF; + SFDP_array[8'h84] = 8'hFF; + SFDP_array[8'h85] = 8'hFF; + SFDP_array[8'h86] = 8'hFF; + SFDP_array[8'h87] = 8'h03; + SFDP_array[8'h88] = 8'h44; + SFDP_array[8'h89] = 8'hEB; + SFDP_array[8'h8A] = 8'h08; + SFDP_array[8'h8B] = 8'h6B; + SFDP_array[8'h8C] = 8'h08; + SFDP_array[8'h8D] = 8'h3B; + SFDP_array[8'h8E] = 8'h80; + SFDP_array[8'h8F] = 8'hBB; + + for (i=144;i<=255;i=i+1) + begin + SFDP_array[i] = MaxData; + end +// SFDP_array[8'h90:8'hFF] = {112{8'hFF}}; + + end + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + always @(posedge DP_in) + begin:TDPr + #tdevice_DP DP_out = DP_in; + end + always @(negedge DP_in) + begin:TDPf + #1 DP_out = DP_in; + end + + always @(posedge RES_in) + begin:TRESr + if (res_flag) // res_flag is '1' when read ID after resume DP + // res_flag will be set to '1' in DUMMY_BYTES if read ID + #tdevice_RES2 RES_out = RES_in; + else + #tdevice_RES1 RES_out = RES_in; + end + always @(negedge RES_in) + begin:TRESf + #1 RES_out = RES_in; + end + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_SUS PRGSUSP_out = 1'b1; + end + + always @(posedge PRGRES_in) + begin:ProgSuspend + PRGRES_out = 1'b0; + #tdevice_PRGSUSP PRGRES_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_SUS ERSSUSP_out = 1'b1; + end + + always @(posedge ERSRES_in) + begin:ERSresume + ERSRES_out = 1'b0; + #tdevice_PRGSUSP ERSRES_out = 1'b1; + end + + always @(posedge ERSRES_in or posedge PRGRES_in) + begin + susp_flag = 1'b1; + #tdevice_SUS susp_flag = 1'b0; + end + + always @(next_state or PoweredUp) + begin: StateTransition + if (PoweredUp) + begin + current_state = next_state; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer wrap_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [15:0] opcode_double; + reg [7:0] opcode_in; + reg [15:0] opcode_double_in; + reg [23:0] addr_bytes; + reg [23:0] Address_in; + reg [7:0] mode_byte; + reg [7:0] mode_in; + reg [7:0] wrap_in; + reg [7:0] wrap_byte; + + integer quad_data_in [0:511]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle + integer i; + integer j; + integer k; + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + bus_cycle_state = OPCODE_BYTE; + Instruct = NONE; + write = 1'b1; + opcode_cnt = 0; + addr_cnt = 0; + data_cnt = 0; + mode_cnt = 0; + wrap_cnt = 0; + dummy_cnt = 0; + end + else if (bus_cycle_state==DATA_BYTES && (mode_byte[5:4]==2'b10)) + begin + bus_cycle_state = ADDRESS_BYTES; + dummy_cnt = 0; + opcode_cnt = 0; + end + end + if (rising_edge_SCK_ipd && PoweredUp) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE : + begin + if ((HOLDNeg_in && ~QE) || QE) + begin + opcode_in[opcode_cnt] = SI_in; +// opcode_double_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + if (opcode_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + opcode[i] = opcode_in[7-i]; + end + case(opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b01010000 : // 50h + begin + Instruct = WRENV; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 05h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FAST_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00111011 : // 3Bh + begin + Instruct = FAST_DREAD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01101011 : // 6Bh + begin + Instruct = FAST_QREAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b10111011 : // BBh + begin + Instruct = FAST_DREAD_2; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11101011 : // EBh + begin + Instruct = FAST_QREAD_4; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b11100111 : // E7h + begin + Instruct = W_QREAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b11100011 : // E3h + begin + Instruct = WOCT_QREAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b01110111 : // 77h + begin + Instruct = SET_BURST_WRAP; + if (QE) + bus_cycle_state = DUMMY_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b11111111 : // FFh + begin + Instruct = CONT_RD_RST; + bus_cycle_state = MODE_BYTE; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010 : // 32h + begin + Instruct = QPP; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b00100000 : // 20h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01010010 : // 52h + begin + Instruct = BE_32; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = BE_64; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11000111, 8'b01100000 : // C7h or 60h + begin + Instruct = CE; + bus_cycle_state = DATA_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERS_PG_SUSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERS_PG_RES; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = DP; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011: // ABh + begin + Instruct = RES_RD_ID; + bus_cycle_state = DUMMY_BYTES; + end + 8'b10010000: // 90h + begin + Instruct = RDID; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10010010: // 92h + begin + Instruct = RDID_DUAL; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10010100: // 94h + begin + Instruct = RDID_QUAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b01001011: // 4Bh + begin + Instruct = RD_UNIQ_ID; + bus_cycle_state = DUMMY_BYTES; + end + 8'b10011111: // 9Fh + begin + Instruct = RDIDJ; + bus_cycle_state = DATA_BYTES; + end + 8'b01011010: // 5Ah + begin + Instruct = RD_SFDP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000100: // 44h + begin + Instruct = ERS_SCREG; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000010: // 42h + begin + Instruct = PG_SCREG; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001000: // 48h + begin + Instruct = RD_SCREG; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + else + $display("Device is in HOLD mode, opcode"); + end // end of OPCODE_BYTE + + ADDRESS_BYTES : + begin + if ((HOLDNeg_in && ~QE) || QE) + begin + if (Instruct == READ || Instruct == FAST_READ || + Instruct == FAST_DREAD || Instruct == RDID || + Instruct == SE || Instruct == PP || + Instruct == RD_SCREG || Instruct == PG_SCREG || + Instruct == RD_SFDP || Instruct == BE_32 || + Instruct == BE_64 || Instruct == ERS_SCREG || + ((Instruct == QPP || Instruct == FAST_QREAD) + && QE)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes ; + change_addr = 1'b1; + #1000 change_addr = 1'b0; + if (Instruct == PP || Instruct == QPP + || Instruct == READ || Instruct == SE + || Instruct == BE_32 || Instruct == BE_64 + || Instruct == RDID || Instruct == PG_SCREG + || Instruct == ERS_SCREG) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct == RDID_DUAL || + Instruct == FAST_DREAD_2) + begin + if (SO_in !== 1'bX) + begin + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for (i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes ; + change_addr = 1'b1; + #1000 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + begin + if (mode_byte[5:4] == 2'b10) + begin + opcode_double_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + + if (opcode_cnt == 2*BYTE) + begin + for (i=0;i<=15;i=i+1) + begin + opcode_double[i] = + opcode_double_in[15-i]; + end + if (opcode_double == 16'hFFFF) + begin + Instruct = CONT_RD_RST; + bus_cycle_state = MODE_BYTE; + end + end + end + end + end + else if (QE && (Instruct == FAST_QREAD_4 || + Instruct == W_QREAD || + Instruct == WOCT_QREAD || + Instruct == RDID_QUAD)) + begin + if (SO_in !== 1'bX) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes ; + change_addr = 1'b1; + #1000 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + begin + if (mode_byte[5:4] == 2'b10) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + if (opcode_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + opcode[i] = opcode_in[7-i]; + end + if (opcode == 8'hFF) + begin + Instruct = CONT_RD_RST; + bus_cycle_state = MODE_BYTE; + end + end + end + end + end + end + else + $display("Device is in HOLD mode, addr"); + end // end of ADDRESS_BYTES + + MODE_BYTE: + begin + if (QE || (HOLDNeg_in && ~QE)) + begin + if (Instruct == SET_BURST_WRAP && QE) + begin + wrap_in[4*wrap_cnt] = HOLDNeg_in; + wrap_in[4*wrap_cnt+1] = WPNeg_in; + wrap_in[4*wrap_cnt+2] = SO_in; + wrap_in[4*wrap_cnt+3] = SI_in; + wrap_cnt = wrap_cnt + 1; + if (wrap_cnt == BYTE/4) + begin + wrap_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + wrap_byte[i] = wrap_in[7-i]; + end + bus_cycle_state = DATA_BYTES; + end + case (wrap_byte[6:5]) + 2'b00: + w_size = 8; + 2'b01: + w_size = 16; + 2'b10: + w_size = 32; + 2'b11: + w_size = 64; + endcase + end + else if ((Instruct == FAST_QREAD_4 || + Instruct == WOCT_QREAD || + Instruct == W_QREAD || + Instruct == RDID_QUAD ) && QE) + // FAST_QREAD_4,WOCT_QREAD,W_QREAD,RDID_QUAD + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_byte[i] = mode_in[7-i]; + end + if (Instruct == WOCT_QREAD) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct == RDID_DUAL || + Instruct == FAST_DREAD_2) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_byte[i] = mode_in[7-i]; + end + bus_cycle_state = DATA_BYTES; + end + end + end + else + $display("Device is in HOLD mode, mode"); + + end // end of MODE_BYTE + + DUMMY_BYTES: + begin + if (QE || (HOLDNeg_in && ~QE)) + begin + if ((Instruct == FAST_QREAD_4 || + Instruct == RDID_QUAD) && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE/2) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct == W_QREAD && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE/4) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct == SET_BURST_WRAP && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE/4) + bus_cycle_state = MODE_BYTE; + end + else if (Instruct == FAST_QREAD && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct==FAST_READ || Instruct==RD_SFDP + || Instruct == FAST_DREAD || Instruct == RD_SCREG) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct == RD_UNIQ_ID) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 4*BYTE) + bus_cycle_state = DATA_BYTES; + end + else // for RES_RD_ID + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + end + else + $display("Device is in HOLD mode, dummy"); + end // end of DUMMY_BYTES + + DATA_BYTES: + begin + if (Instruct == PP || Instruct == WRR || + Instruct == PG_SCREG) + begin + if ((HOLDNeg_in && ~QE) || QE) + begin + if (data_cnt > 2047) + //In case of serial mode and PP,if more than + //256 bytes are sent to the device + begin + if (bit_cnt == 0) + begin + for (i=0;i<=(255*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[2040 + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + else + $display("Device is in HOLD mode, data"); + end + else if (Instruct == QPP && QE) + begin + pp_quad = 1'b1; + quad_nybble = {HOLDNeg_in, WPNeg_in, + SO_in, SI_in}; + if (data_cnt > 511) + begin + //In case of quad mode and QPP,if more than + // 256 bytes are sent to the device + for(i=0;i<=510;i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[511] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + end // end of DATA_BYTES + endcase // end of case bus_cycle_state + end // end of ~CSNeg + end // end of rising_edge_SCK + + if (falling_edge_SCK_ipd) + begin + if ((bus_cycle_state == DATA_BYTES) && (~CSNeg_ipd)) + begin + if (((Instruct == RDSR || Instruct == RDSR2 || + Instruct == FAST_READ || Instruct == FAST_DREAD || + Instruct == FAST_DREAD_2 || Instruct == RES_RD_ID || + Instruct == RDID || Instruct == RDID_DUAL || + Instruct == RD_UNIQ_ID || Instruct == RDIDJ || + Instruct == RD_SFDP || Instruct == RD_SCREG || + Instruct == READ) && ((HOLDNeg_in && ~QE) || QE)) || + ((Instruct == FAST_QREAD || Instruct == FAST_QREAD_4 || + Instruct == W_QREAD || Instruct == RDID_QUAD || + Instruct == WOCT_QREAD) && QE)) + begin + read_out = 1'b1; + #1 read_out = 1'b0; + end + end // end of ~CSNeg_ipd + end // end of falling_edge_SCK_ipd + + if (rising_edge_CSNeg_ipd) + begin + if (bus_cycle_state==MODE_BYTE && Instruct == CONT_RD_RST) + begin + mode_byte[5:4] = 2'b11; + mode_byte[7:6] = 2'b00; + mode_byte[3:0] = 4'b0000; + bus_cycle_state = STAND_BY; + end + else if (bus_cycle_state==DATA_BYTES && ~(mode_byte[5:4]==2'b10)) + begin + bus_cycle_state = STAND_BY; + case (Instruct) + WREN, +// WRENV, + WRDI, + SET_BURST_WRAP, + SE, + BE_32, + BE_64, + CE, + ERS_PG_RES, + DP, + ERS_SCREG: + begin + if (data_cnt == 0) + write = 1'b0; + end + + WRENV: + begin + write = 1'b0; + wren_vlt_flag = 1'b1; + end + + RES_RD_ID: + begin + write = 1'b0; + res_flag = 1'b1; + end + + WRR: + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Status_reg2_in[i]= + Data_in[15-i]; + end + end + end + + PP, + PG_SCREG: + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = + Data_in[(i*8) + (7-j)]; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE) + Byte_number = 255; + else + Byte_number = ((data_cnt/8) - 1); + end + end + end + + QPP: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else // if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE/4) + Byte_number = 255; + else + Byte_number = ((data_cnt/2) - 1); + end + end + end + + endcase + end + else if (bus_cycle_state==DATA_BYTES && (mode_byte[5:4]==2'b10)) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = STAND_BY; + if (HOLDNeg_in && (Instruct == RES_RD_ID) && + (dummy_cnt == 0)) + begin + write = 1'b0; + res_flag = 1'b0; + end + end + end // end of rising_edge_CSNeg_ipd + + end // end of Buscycle + + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Page Program + /////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed; + time start; + time duration; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == QPP) || (Instruct == PG_SCREG)) + pob = tdevice_PP; + else + pob = tdevice_BP1; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed = 0; + PDONE = 1'b0; + ->pdone_event; + start = $time; + end + end + + always @(PGSUSP_event) + begin + if ((PGSUSP_event) && PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed = $time - start; + duration = pob - elapsed; + PDONE = 1'b0; + end + end + + always @(PGRES_event) + begin + if ((PGRES_event) && PGRES && (~PDONE)) + begin + start = $time; + ->pdone_event; + end + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #pob PDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Write Status Register Operation + // start + /////////////////////////////////////////////////////////////////////////// + time wob; + always @(WSTART) + begin + wob = tdevice_WRR; + if ((rising_edge_WSTART) && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Volatile Write Status Register Operation + // start + /////////////////////////////////////////////////////////////////////////// + time vob; + always @(VLTSTART) + begin + vob = tdevice_VRR; + if (rising_edge_VLTSTART && VLTDONE) + begin + VLTDONE = 1'b0; + #vob VLTDONE = 1'b1; + end + end + + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Erase Operations + /////////////////////////////////////////////////////////////////////////// + time seo; + time beo32; + time beo64; + time ceo; + event edone_event; + + always @(rising_edge_ESTART) + begin + seo = tdevice_SE; + beo32 = tdevice_BE1; + beo64 = tdevice_BE2; + ceo = tdevice_CE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == CE) + begin + duration = ceo; + end + else if (Instruct == BE_64) + begin + duration = beo64; + end + else if (Instruct == BE_32) + begin + duration = beo32; + end + else + begin + duration = seo; + end + elapsed = 0; + EDONE = 1'b0; + ->edone_event; + start = $time; + end + end + + always @(ESUSP_event) + begin + if ((ESUSP_event) && ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed = $time - start; + duration = duration - elapsed; + EDONE = 1'b0; + end + end + + always @(ERES_event) + begin + if ((ERES_event) && ERES && (~EDONE)) + begin + start = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////////////// + // Main Behavior Process + // combinational process for next state generation + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg rising_edge_VLTDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or rising_edge_DP_out + or rising_edge_PDONE or rising_edge_WDONE or rising_edge_EDONE or + ERSSUSP_out_event or ERSRES_out_event or RES_out or + PRGSUSP_out_event or PRGRES_out_event or rising_edge_VLTDONE) + begin: StateGen1 + + if (rising_edge_PoweredUp) + next_state = IDLE; + else + begin + case (current_state) + IDLE : + begin + if (falling_edge_write) + begin + if (Instruct == WRR && (~SRP1 && + (~SRP0 || (SRP0 && WPNeg)))) + begin + if (WEL && ~wren_vlt_flag) + next_state = WRITE_SR; + else if (~WEL && wren_vlt_flag) + next_state = WRITE_SR_V; + end + else if (Instruct == PP && WEL) + begin + sect = Address / 16'h1000; + sect_tmp_pg = sect; + if (Sec_Prot[sect] == 0) + next_state = PAGE_PG; + end + else if (Instruct == QPP && WEL && QE) + begin + sect = Address / 16'h1000; + sect_tmp_pg = sect; + if (Sec_Prot[sect] == 0) + next_state = PAGE_PG; + end + else if (Instruct == PG_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect < 4 && sect > 0) && LB[sect-1]==0) + next_state = PAGE_PG; + end + else if (Instruct == ERS_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect <= 3) && LB[sect-1]==0) + next_state = SECTOR_ERS; + end + else if ((Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) && WEL) + begin + sect = Address / 16'h1000; + sect_tmp_ers = sect; + if (Sec_Prot[sect] == 0) + next_state = SECTOR_ERS; + end + else if (Instruct == CE && WEL && + ((~CMP && ~BP2 && ~BP1 && ~BP0) || + (CMP && BP2 && BP1 && BP0))) + next_state = BULK_ERS; + else + next_state = IDLE; + end + else if (rising_edge_DP_out) + next_state = DP_DOWN; + end // end of IDLE + + WRITE_SR: + begin + if (rising_edge_WDONE) + next_state = IDLE; + end // end of WRITE_SR + + WRITE_SR_V: + begin + if (rising_edge_VLTDONE) + next_state = IDLE; + end + + PAGE_PG: + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end // end of PAGE_PG + + PG_SUSP: + begin + if (PRGRES_out_event && PRGRES_out == 1) + next_state = PAGE_PG; + else if (falling_edge_write) + begin + if (Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) + begin + sect = Address / 16'h1000; + if ((Sec_Prot[sect] == 0) && (sect != sect_tmp_pg)) + next_state = PG_SUSP_ERS; + end + end + end // end of PG_SUSP + + PG_SUSP_ERS: + begin + if (rising_edge_EDONE) + next_state = PG_SUSP; + else + next_state = PG_SUSP_ERS; + end + + BULK_ERS: + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS: + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP: + begin + if (ERSRES_out_event && ERSRES_out == 1) + next_state = SECTOR_ERS; + else if (falling_edge_write) + begin + if (Instruct == PP || (Instruct == QPP && QE)) + begin + sect = Address / 16'h1000; + if ((Sec_Prot[sect] == 0)&&(sect != sect_tmp_ers)) + next_state = ERS_SUSP_PG; + end + else if (Instruct == PG_SCREG) + begin + sect = Address / 16'h1000; + if ((sect < 4 && sect > 0) && LB[sect-1]==0) + next_state = ERS_SUSP_PG; + end + end + end + + ERS_SUSP_PG: + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else + next_state = ERS_SUSP_PG; + end + + DP_DOWN: + begin + if (rising_edge_RES_out) + next_state = IDLE; + end + + endcase // end case of current_state + end // + end // end of StateGen1 + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + + integer WData [0:255]; + integer Addr; + integer Addr_ers; + integer Addr_tmp; + integer Addr_tmp_2; + integer Addr_tmp_3; + integer Addr_screg; + + always @(oe_event) + begin + oe = 1'b1; + #1000 oe = 1'b0; + end + + always @(rising_edge_read_out or Instruct or rising_edge_SCK_ipd or + change_addr_event or oe or current_state_event or Address or + falling_edge_write or PDONE or rising_edge_WDONE or Instruct_event + or rising_edge_EDONE or ERSSUSP_out or rising_edge_PoweredUp or + rising_edge_CSNeg_ipd or rising_edge_RES_out or ERSRES_out or + PRGSUSP_out or PRGRES_out_event or rising_edge_VLTDONE or + rising_edge_DP_out) + + begin: Functionality + integer i,j; + + if (rising_edge_read_out) + begin + if (PoweredUp == 1'b1) + ->oe_event; + end + + if (Instruct_event) + begin + read_cnt = 0; + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + read_id = 1'b0; + pp_quad = 1'b0; + if (current_state == IDLE) + begin + if (DP_in == 1'b1) + begin + $display ("Command results can be corrupted "); + end + end + end + + if (rising_edge_PoweredUp) + begin + Status_reg1[1] = 1'b0; // WEL bit + Status_reg1[0] = 1'b0; // BUSY bit + + Status_reg2[7] = 1'b0; // SUS bit + end + + if (change_addr_event) + begin + read_addr = Address; + end + + if (rising_edge_RES_out) + begin + if(RES_out) + begin + RES_in = 1'b0; + end + end + + case (current_state) + IDLE : + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + res_flag = 1'b0; + pg_screg_flag = 1'b0; + ers_screg_flag = 1'b0; + if (falling_edge_write && ~DP_in) + begin + read_cnt = 0; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 1'b0; + else if (Instruct == WRR) + begin + if(~SRP1 && (~SRP0 || (SRP0 && WPNeg))) + begin + if (WEL && ~wren_vlt_flag) + begin + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (~WEL && wren_vlt_flag) + begin + VLTSTART = 1'b1; + VLTSTART <= #5 1'b0; + end + end + else + Status_reg1[1] = 1'b0; + end + else if ((Instruct == PP || (Instruct == QPP && QE)) + && WEL && PDONE) + begin + sect = Address / 16'h1000; + if (Sec_Prot[sect] == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == PG_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect <= 3) && LB[sect-1]==0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + wr_cnt = Byte_number; + Addr_screg = Address % 16'h1000; + pg_screg_flag = 1'b1; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + end + end + else if ((Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) && WEL) + begin + sect = Address / 16'h1000; + if (Sec_Prot[sect] == 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + Addr_ers = Address; + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == CE && WEL) + begin +// if ((~CMP && ~BP2 && ~BP1 && ~BP0) || +// (CMP && BP2 && BP1 && BP0)) + if (Sec_Prot == 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == ERS_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect <= 3) && LB[sect-1]==0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + ers_screg_flag = 1'b1; + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == DP) + begin + RES_in <= 1'b0; + DP_in <= 1'b1; + end + end // end of falling_edge_write + else if (oe && ~DP_in) + begin + if (Instruct == RDSR) + begin //Read Status Register + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + sr_read = 1'b1; + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + if (Instruct == READ) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b1; + quad_read = 1'b0; + sr_read = 1'b0; + end + else + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct==FAST_DREAD || Instruct==FAST_DREAD_2) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if ((Instruct==FAST_QREAD || Instruct==FAST_QREAD_4 || + Instruct==W_QREAD || Instruct==WOCT_QREAD) + && QE) + begin + if ((Instruct==W_QREAD && Address[0]) || + (Instruct==WOCT_QREAD && ~(Address[3:0] == 4'h0))) + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + $display("Word Read could not execute"); + $display("Wrong Read Address"); + end + end + else + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (wrap_byte[4]==1'b0 && + (Instruct==FAST_QREAD_4 || Instruct==W_QREAD)) + begin + ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap, + Address,w_size); + if (read_addr == AddrHi_wrap) + read_addr = AddrLo_wrap; + else + read_addr = read_addr + 1; + end + else + begin + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (Instruct==RDID || Instruct==RDID_DUAL || + Instruct==RDID_QUAD) + begin + if (read_addr % 2 == 0) + begin + ident_out2 = {Manuf_ID,Device_ID1}; + end + else + begin + ident_out2 = {Device_ID1,Manuf_ID}; + end + read_id = 1'b1; + if (Instruct == RDID) + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + SOut_zd = ident_out2[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == RDID_DUAL) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + SOut_zd = ident_out2[15-2*read_cnt]; + SIOut_zd = ident_out2[14-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else // (Instruct == RDID_QUAD) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + HOLDNegOut_zd = ident_out2[15-4*read_cnt]; + WPNegOut_zd = ident_out2[14-4*read_cnt]; + SOut_zd = ident_out2[13-4*read_cnt]; + SIOut_zd = ident_out2[12-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + read_cnt = 0; + end + end + else if (Instruct == RD_UNIQ_ID) + begin + // unique ID number is not in data sheet + read_id = 1'b1; + SOut_zd = unique_id[63-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 64) + read_cnt = 0; + end + else if (Instruct == RDIDJ) + begin + read_id = 1'b1; + ident_out = {Manuf_ID,Device_ID2,Device_ID3}; + SOut_zd = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RD_SFDP) + begin + sfdp_addr = read_addr / 12'h100; + if (sfdp_addr == 0) + begin + Addr_tmp_2 = (read_addr % 12'h100); + data_out[7:0] = SFDP_array[Addr_tmp_2]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == SFDP_HiAddr) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given SFDP address is out of range"); + end + end + end + else if (Instruct == RD_SCREG) + begin + Addr_tmp_2 = read_addr / 12'h100; + Addr_tmp_3 = read_addr % 12'h100; + if (Addr_tmp_2 == 16) + begin + // Security Register No.1 + data_out[7:0] = Security_Reg1[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 32) + begin + // Security Register No.2 + data_out[7:0] = Security_Reg2[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 48) + // Security Register No.2 + begin + data_out[7:0] = Security_Reg3[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given Security Register Read "); + $display("address is out of range "); + end + end + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr % 256 == SecReg_HiAddr) + read_addr = (read_addr/256)*(SecReg_HiAddr+1); + else + read_addr = read_addr + 1; + end + end + else if (Instruct == RES_RD_ID) + begin + read_id = 1'b1; + data_out[7:0] = Device_ID1; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end // end of oe + else if (rising_edge_DP_out) + DP_in = 1'b0; + end // end of IDLE state + + WRITE_SR: + begin + if (WDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + + Status_reg1[7:2] = Status_reg1_in[7:2]; + Status_reg2[6] = Status_reg2_in[6]; + Status_reg2[1] = Status_reg2_in[1]; + // SRP1 bit will only change value from '0' to '1' + // if SRP1 is '1' than Status Register is protected + //and is not possible to write it + Status_reg2[0] = Status_reg2_in[0]; + for(i=5;i>=3;i=i-1) + begin + if (Status_reg2[i] == 1'b0) + Status_reg2[i] = Status_reg2_in[i]; + else + begin + $display("LB bit is set to '1'"); + $display("No change allowed"); + end + end + change_prot_bits = 1'b1; + #1000 change_prot_bits = 1'b0; + end // end of WDONE + + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end // end of oe + end // end of WRITE_SR + + WRITE_SR_V: + begin + if (VLTDONE) + begin + Status_reg1[7:2] = Status_reg1_in[7:2]; + Status_reg2[6] = Status_reg2_in[6]; + Status_reg2[1] = Status_reg2_in[1]; + // SRP1 bit will only change value from '0' to '1' + // if SRP1 is '1' than Status Register is protected + //and is not possible to write it + Status_reg2[0] = Status_reg2_in[0]; + for(i=5;i>=3;i=i-1) + begin + if (Status_reg2[i] == 1'b0) + Status_reg2[i] = Status_reg2_in[i]; + else + begin + $display("LB bit is set to '1'"); + $display("No change allowed"); + end + end + change_prot_bits = 1'b1; + #1000 change_prot_bits = 1'b0; + wren_vlt_flag = 1'b0; + end + end + + PAGE_PG, + ERS_SUSP_PG: + begin + if (current_state_event && ~PDONE) + begin + if (Instruct !== PG_SCREG) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + end + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + if (Instruct == PG_SCREG) + begin + if (sect == 1) + old_int = Security_Reg1[Addr_screg + i - cnt]; + else if (sect == 2) + old_int = Security_Reg2[Addr_screg + i - cnt]; + else + old_int = Security_Reg3[Addr_screg + i - cnt]; + end + else + begin + old_int = Mem[Addr + i - cnt]; + end + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + if (Instruct == PG_SCREG) + begin + if (sect == 1) + Security_Reg1[Addr_screg + i - cnt] = - 1; + else if (sect == 2) + Security_Reg2[Addr_screg + i - cnt] = - 1; + else + Security_Reg3[Addr_screg + i - cnt] = - 1; + end + else + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + + Addr = AddrLo; + cnt = i + 1; + end + end + cnt = 0; + end // end of current_state_event + + if (PDONE) + begin + if (current_state !== ERS_SUSP_PG) + begin + Status_reg1[0] = 1'b0; + end + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + if (pg_screg_flag ) + begin + if (sect == 1) + Security_Reg1[Addr_screg + i - cnt] = WData[i]; + else if (sect == 2) + Security_Reg2[Addr_screg + i - cnt] = WData[i]; + else + Security_Reg3[Addr_screg + i - cnt] = WData[i]; + + if ((Addr_screg + i) == SecReg_HiAddr) + begin + Addr_screg = SecReg_LoAddr; + cnt = i + 1; + end + end + else + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + end // end of PDONE + + if (Instruct == ERS_PG_SUSP && current_state == PAGE_PG && ~susp_flag) + begin + PGSUSP = 1'b1; + PGSUSP <= #1000 1'b0; + PRGSUSP_in = 1'b1; + end + + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end // end of PAGE_PG + + PG_SUSP: + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (PRGSUSP_out == 1 && ~(Instruct == ERS_PG_RES)) + begin + PRGSUSP_in = 1'b0; + //The BUSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Suspend (SUS) bit in the Status Register2 will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[7] = 1'b1; + end + if (PRGRES_out_event && PRGRES_out == 1) + begin + PRGRES_in = 1'b0; + Status_reg1[0] = 1'b1; + end + if (SUS) + begin + if (falling_edge_write) + begin + if (Instruct == ERS_PG_RES) + begin + Status_reg2[7] = 1'b0; + PRGRES_in = 1'b1; + PGRES = 1'b1; + PGRES <= #1000 1'b0; + end + else if ((Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) && WEL) + begin + sect = Address / 16'h1000; + if (sect !== sect_tmp_pg && Sec_Prot[sect] == 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + Addr_ers = Address; + end + else + begin + Status_reg1[0] = 1'b0; + $display("Can't erase sector/block"); + $display("Block is protected or suspended"); + end + end + end + else if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + sr_read = 1'b1; + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + if (sect_tmp_pg !== read_addr / 16'h1000) + begin + if (Instruct == READ) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b1; + quad_read = 1'b0; + sr_read = 1'b0; + end + else + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==FAST_DREAD || + Instruct==FAST_DREAD_2) + begin + if (sect_tmp_pg !== read_addr / 16'h1000) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if ((Instruct==FAST_QREAD || Instruct==W_QREAD + || Instruct==FAST_QREAD_4 || Instruct==WOCT_QREAD) + && QE) + begin + if (sect_tmp_pg !== read_addr / 16'h1000) + begin + if ((Instruct==W_QREAD && Address[0]) || + (Instruct==WOCT_QREAD && + ~(Address[3:0] == 4'h0))) + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + $display("Word Read can't execute"); + $display("Wrong Read Address"); + end + end + else + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (wrap_byte[4]==0 && + (Instruct==FAST_QREAD_4 || + Instruct==W_QREAD)) + begin + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap, Address,w_size); + if (read_addr == AddrHi_wrap) + read_addr = AddrLo_wrap; + else + read_addr = read_addr + 1; + end + else + begin + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==RDID || Instruct==RDID_DUAL || + Instruct==RDID_QUAD) + begin + if (read_addr % 2 == 0) + begin + ident_out2 = {Manuf_ID,Device_ID1}; + end + else + begin + ident_out2 = {Device_ID1,Manuf_ID}; + end + read_id = 1'b1; + if (Instruct == RDID) + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + SOut_zd = ident_out2[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == RDID_DUAL) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + SOut_zd = ident_out2[15-2*read_cnt]; + SIOut_zd = ident_out2[14-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else // (Instruct == RDID_QUAD) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + HOLDNegOut_zd = ident_out2[15-4*read_cnt]; + WPNegOut_zd = ident_out2[14-4*read_cnt]; + SOut_zd = ident_out2[13-4*read_cnt]; + SIOut_zd = ident_out2[12-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + read_cnt = 0; + end + end + else if (Instruct == RD_UNIQ_ID) + begin + // unique ID number is not in data sheet + read_id = 1'b1; + SOut_zd = unique_id[63-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 64) + read_cnt = 0; + end + else if (Instruct == RDIDJ) + begin + read_id = 1'b1; + ident_out = {Manuf_ID,Device_ID2,Device_ID3}; + SOut_zd = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RD_SFDP) + begin + sfdp_addr = read_addr / 12'h100; + if (sfdp_addr == 0) + begin + Addr_tmp_2 = (read_addr % 12'h100); + data_out[7:0] = SFDP_array[Addr_tmp_2]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == SFDP_HiAddr) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("SFDP address is out of range"); + end + end + end + else if (Instruct == RD_SCREG) + begin + Addr_tmp_2 = read_addr / 12'h100; + Addr_tmp_3 = read_addr % 12'h100; + if (Addr_tmp_2 == 16) + begin + // Security Register No.1 + data_out[7:0] = Security_Reg1[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 32) + begin + // Security Register No.2 + data_out[7:0] = Security_Reg2[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 48) + // Security Register No.2 + begin + data_out[7:0] = Security_Reg3[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given Security Register Read "); + $display("address is out of range "); + end + end +// SOut_zd = data_out[7-read_cnt]; +// read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr % 256 == SecReg_HiAddr) + read_addr=(read_addr/256)* + (SecReg_HiAddr+1); + else + read_addr = read_addr + 1; + end + end + end // end of 'oe' + end + end // end of PG_SUSP + + SECTOR_ERS, + PG_SUSP_ERS: + begin + if (current_state_event && ~EDONE) + begin + if (Instruct == SE) + ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers); + else if (Instruct == BE_32) + ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers); + else if (Instruct == BE_64) + begin + ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers); + end + if (Instruct !== ERS_SCREG) + begin + for (i=AddrLo_ers;i<=AddrHi_ers;i=i+1) + begin + Mem[i] = -1; + end + end + else + begin + if (sect == 1) + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg1[i] = -1; + end + end + else if (sect == 2) + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg2[i] = -1; + end + end + else + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg3[i] = -1; + end + end + end + end + + if (EDONE == 1) + begin + if (current_state !== PG_SUSP_ERS) + begin + Status_reg1[0] = 1'b0; + end + Status_reg1[1] = 1'b0; + if (ers_screg_flag ) + begin + if (sect == 1) + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg1[i] = MaxData; + end + end + else if (sect == 2) + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg2[i] = MaxData; + end + else + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg3[i] = MaxData; + end + + end + else + begin + for (i=AddrLo_ers;i<=AddrHi_ers;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + + if (Instruct == ERS_PG_SUSP && current_state == SECTOR_ERS) + begin + ESUSP = 1'b1; + ESUSP <= #1000 1'b0; + ERSSUSP_in = 1'b1; + end + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end // end of SECTOR_ERS + + BULK_ERS: + begin + if (current_state_event && ~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = -1; + end + end + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + end + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end // end of BULK_ERS + + ERS_SUSP: + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (ERSSUSP_out == 1 && ~(Instruct == ERS_PG_RES)) + begin + ERSSUSP_in = 1'b0; + //The BUSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Suspend (SUS) bit in the Status Register2 will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[7] = 1'b1; + end + if (ERSRES_out_event && ERSRES_out == 1) + begin + ERSRES_in = 1'b0; + Status_reg1[0] = 1'b1; + end + if (SUS) + begin + if (falling_edge_write) + begin + if (Instruct == ERS_PG_RES) + begin + Status_reg2[7] = 1'b0; + ERSRES_in = 1'b1; + ERES = 1'b1; + ERES <= #1000 1'b0; + end + else if ((Instruct == PP || (Instruct==QPP && QE)) + && WEL) + begin + sect = Address / 16'h1000; + if (sect !== sect_tmp_ers && Sec_Prot[sect]==0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[0] = 1'b0; + $display("Can't program sector/block"); + $display("Block is protected or suspended"); + end + end + else if (Instruct == PG_SCREG) + begin + sect = Address / 16'h1000; + if ((sect <= 3 && sect >=1) && LB[sect-1]==0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + wr_cnt = Byte_number; + Addr_screg = Address % 16'h1000; + pg_screg_flag = 1'b1; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + Status_reg1[1] = 1'b0; + end + end + else if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + sr_read = 1'b1; + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + if (sect !== read_addr / 16'h1000) + begin + if (Instruct == READ) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b1; + quad_read = 1'b0; + sr_read = 1'b0; + end + else + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==FAST_DREAD || Instruct==FAST_DREAD_2) + begin + if (sect !== read_addr / 16'h1000) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if ((Instruct==FAST_QREAD || Instruct==W_QREAD + || Instruct==FAST_QREAD_4 || Instruct==WOCT_QREAD) + && QE) + begin + if (sect_tmp_ers !== read_addr / 16'h1000) + begin + if ((Instruct==W_QREAD && Address[0]) || + (Instruct==WOCT_QREAD && + ~(Address[3:0]==4'h0))) + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + $display("Word Read can't execute"); + $display("Wrong Read Address"); + end + end + else + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (wrap_byte[4]==0 && + (Instruct==FAST_QREAD_4 + || Instruct==W_QREAD)) + begin + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap,Address,w_size); + if (read_addr == AddrHi_wrap) + read_addr = AddrLo_wrap; + else + read_addr = read_addr + 1; + end + else + begin + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==RDID || Instruct==RDID_DUAL || + Instruct==RDID_QUAD) + begin + if (read_addr % 2 == 0) + begin + ident_out2 = {Manuf_ID,Device_ID1}; + end + else + begin + ident_out2 = {Device_ID1,Manuf_ID}; + end + read_id = 1'b1; + if (Instruct == RDID) + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + SOut_zd = ident_out2[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == RDID_DUAL) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + SOut_zd = ident_out2[15-2*read_cnt]; + SIOut_zd = ident_out2[14-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else // (Instruct == RDID_QUAD) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + HOLDNegOut_zd = ident_out2[15-4*read_cnt]; + WPNegOut_zd = ident_out2[14-4*read_cnt]; + SOut_zd = ident_out2[13-4*read_cnt]; + SIOut_zd = ident_out2[12-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + read_cnt = 0; + end + end + else if (Instruct == RD_UNIQ_ID) + begin + // unique ID number is not in data sheet + read_id = 1'b1; + SOut_zd = unique_id[63-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 64) + read_cnt = 0; + end + else if (Instruct == RDIDJ) + begin + read_id = 1'b1; + ident_out = {Manuf_ID,Device_ID2,Device_ID3}; + SOut_zd = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RD_SFDP) + begin + sfdp_addr = read_addr / 12'h100; + if (sfdp_addr == 0) + begin + Addr_tmp_2 = (read_addr % 12'h100); + data_out[7:0] = SFDP_array[Addr_tmp_2]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == SFDP_HiAddr) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("SFDP address is out of range"); + end + end + end + else if (Instruct == RD_SCREG) + begin + Addr_tmp_2 = read_addr / 12'h100; + Addr_tmp_3 = read_addr % 12'h100; + if (Addr_tmp_2 == 16) + begin + // Security Register No.1 + data_out[7:0] = Security_Reg1[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 32) + begin + // Security Register No.2 + data_out[7:0] = Security_Reg2[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 48) + // Security Register No.2 + begin + data_out[7:0] = Security_Reg3[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given Security Register Read "); + $display("address is out of range "); + end + end + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr % 256 == SecReg_HiAddr) + read_addr = (read_addr/256)* + (SecReg_HiAddr+1); + else + read_addr = read_addr + 1; + end + end + end // end of 'oe' + end // end of SUS + end // end of ERS_SUSP + + DP_DOWN: + begin + if (oe) + begin + if (Instruct == RES_RD_ID) + begin + read_id = 1'b1; + data_out[7:0] = Device_ID1; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + if (falling_edge_write) + begin + if (Instruct == RES_RD_ID) + begin + RES_in = 1'b1; + end + else + begin + $display("Device is in Deep Power Down Mode"); + $display("No instructions allowed"); + end + end + end + + endcase + //Output Disable Control + if (CSNeg_ipd ) + begin + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + end + end // end of Functionality + + /////////////////////////////////////////////////////////////////////////// + always @(posedge change_prot_bits) + begin +// if (rising_edge_prot_bits) +// begin + case (Status_reg1[4:2]) + 3'b000: + begin + if (Status_reg2[6] == 1'b0) + Sec_Prot[2047:0] = {2048{1'b0}}; + else + Sec_Prot[2047:0] = {2048{1'b1}}; + end + + 3'b001: + begin + if (Status_reg2[6] ==1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:2016] = {32{1'b1}}; + Sec_Prot[2015:0] = {2016{1'b0}}; + end + 2'b01: + begin + Sec_Prot[2047:32] = {2016{1'b0}}; + Sec_Prot[31:0] = {32{1'b1}}; + end + 2'b10: + begin + Sec_Prot[2047] = 1'b1; + Sec_Prot[2046:0] = {2047{1'b0}}; + end + 2'b11: + begin + Sec_Prot[2047:1] = {2047{1'b0}}; + Sec_Prot[0] = 1'b1; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:2016] = {32{1'b0}}; + Sec_Prot[2015:0] = {2016{1'b1}}; + end + 2'b01: + begin + Sec_Prot[2047:32] = {2016{1'b1}}; + Sec_Prot[31:0] = {32{1'b0}}; + end + 2'b10: + begin + Sec_Prot[2047] = 1'b0; + Sec_Prot[2046:0] = {2047{1'b1}}; + end + 2'b11: + begin + Sec_Prot[2047:1] = {2047{1'b1}}; + Sec_Prot[0] = 1'b0; + end + endcase + end + end + + 3'b010: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1984] = {64{1'b1}} ; + Sec_Prot[1983:0] = {1984{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[2047:64] = {1984{1'b0}} ; + Sec_Prot[63:0] = {64{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[2047:2046] = 2'b11; + Sec_Prot[2045:0] = {2046{1'b0}}; + end + 2'b11: + begin + Sec_Prot[2047:2] = {2046{1'b0}}; + Sec_Prot[1:0] = 2'b11; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1984] = {64{1'b0}} ; + Sec_Prot[1983:0] = {1984{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[2047:64] = {1984{1'b1}} ; + Sec_Prot[63:0] = {64{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[2047:2046] = 2'b00; + Sec_Prot[2045:0] = {2046{1'b1}}; + end + 2'b11: + begin + Sec_Prot[2047:2] = {2046{1'b1}}; + Sec_Prot[1:0] = 2'b00; + end + endcase + end + end + + 3'b011: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1920] = {128{1'b1}} ; + Sec_Prot[1919:0] = {1920{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[2047:128] = {1920{1'b0}} ; + Sec_Prot[127:0] = {128{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[2047:2044] = 4'b1111; + Sec_Prot[2043:0] = {2044{1'b0}}; + end + 2'b11: + begin + Sec_Prot[2047:4] = {2044{1'b0}}; + Sec_Prot[3:0] = 4'b1111; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1920] = {128{1'b0}} ; + Sec_Prot[1919:0] = {1920{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[2047:128] = {1920{1'b1}} ; + Sec_Prot[127:0] = {128{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[2047:2044] = {4{1'b0}}; + Sec_Prot[2043:0] = {2044{1'b1}}; + end + 2'b11: + begin + Sec_Prot[2047:4] = {2044{1'b1}}; + Sec_Prot[3:0] = {4{1'b0}}; + end + endcase + end + end + + 3'b100: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1792] = {256{1'b1}} ; + Sec_Prot[1791:0] = {1792{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[2047:256] = {1792{1'b0}} ; + Sec_Prot[255:0] = {256{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[2047:2040] = 8'hFF; + Sec_Prot[2039:0] = {2040{1'b0}}; + end + 2'b11: + begin + Sec_Prot[2047:8] = {2040{1'b0}}; + Sec_Prot[7:0] = 8'hFF; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1792] = {256{1'b0}}; + Sec_Prot[1791:0] = {1792{1'b1}}; + end + 2'b01: + begin + Sec_Prot[2047:256] = {1792{1'b1}}; + Sec_Prot[255:0] = {256{1'b0}}; + end + 2'b10: + begin + Sec_Prot[2047:2040] = {8{1'b0}}; + Sec_Prot[2039:0] = {2040{1'b1}}; + end + 2'b11: + begin + Sec_Prot[2047:8] = {2040{1'b1}}; + Sec_Prot[7:0] = {8{1'b0}}; + end + endcase + end + end + + 3'b101: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1536] = {512{1'b1}} ; + Sec_Prot[1535:0] = {1536{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[2047:512] = {1536{1'b0}} ; + Sec_Prot[511:0] = {512{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[2047:2040] = 8'hFF; + Sec_Prot[2039:0] = {2040{1'b0}} ; + end + 2'b11: + begin + Sec_Prot[2047:8] = {2040{1'b0}} ; + Sec_Prot[7:0] = 8'hFF; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1536] = {512{1'b0}} ; + Sec_Prot[1535:0] = {1536{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[2047:512] = {1536{1'b1}} ; + Sec_Prot[511:0] = {512{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[2047:2040] = {8{1'b0}}; + Sec_Prot[2039:0] = {2040{1'b1}}; + end + 2'b11: + begin + Sec_Prot[2047:8] = {2040{1'b1}}; + Sec_Prot[7:0] = {8{1'b0}}; + end + endcase + end + end + + 3'b110: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1024] = {1024{1'b1}} ; + Sec_Prot[1023:0] = {1024{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[2047:1024] = {1024{1'b0}} ; + Sec_Prot[1023:0] = {1024{1'b1}} ; + end + 2'b10, 2'b11: + begin + $display("This combination of bits "); + $display("is not deffined"); + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[2047:1024] = {1024{1'b0}} ; + Sec_Prot[1023:0] = {1024{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[2047:1024] = {1024{1'b1}} ; + Sec_Prot[1023:0] = {1024{1'b0}} ; + end + 2'b10, 2'b11: + begin + $display("This combination of bits "); + $display("is not deffined"); + end + endcase + end + end + + 3'b111: + begin + if (Status_reg2[6]== 1'b0) + Sec_Prot[2047:0] = {2048{1'b1}}; + else + Sec_Prot[2047:0] = {2048{1'b0}}; + end + endcase +// end + end // end of rising_edge_prot_bits + //////////////////////////////////////////////////////////////////////// + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QE) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure ADDRHILO_SEC 4KB, 32KB, 64KB + task ADDRHILO_SEC64; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + AddrLOW = sector * 20'h10000; + AddrHIGH = sector * 20'h10000 + 20'h0FFFF; + end + endtask + + task ADDRHILO_SEC32; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 16'h8000; + AddrLOW = sector * 16'h8000; + AddrHIGH = sector * 16'h8000 + 16'h7FFF; + end + endtask + + task ADDRHILO_SEC4; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 16'h1000; + AddrLOW = sector * 16'h1000; + AddrHIGH = sector * 16'h1000 + 16'h0FFF; + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / 16'h0100; + AddrLOW = page * 16'h0100; + AddrHIGH = page * 16'h0100 + 16'h00FF; + end + endtask + + // Procedure ADDRHILO_WRAP + task ADDRHILO_WRAP; + inout Addr_low_wrap; + inout Addr_hi_wrap; + input Address; + input w_size; + integer Addr_low_wrap; + integer Addr_hi_wrap; + integer Address; + integer w_size; + integer sect_wrap; + begin + sect_wrap = Address / w_size; + Addr_low_wrap = sect_wrap * w_size; + Addr_hi_wrap = sect_wrap * w_size + w_size - 1; + end + endtask + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1'b1; + #1000 falling_edge_write = 1'b0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge VLTDONE) + begin + rising_edge_VLTDONE = 1'b1; + #1000 rising_edge_VLTDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge VLTSTART) + begin + rising_edge_VLTSTART = 1'b1; + #1000 rising_edge_VLTSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge DP_out) + begin + rising_edge_DP_out = 1'b1; + #1 rising_edge_DP_out = 1'b0; + end + + always @(posedge RES_out) + begin + rising_edge_RES_out = 1'b1; + #1000 rising_edge_RES_out = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge PRGRES_out) + begin + PRGRES_out_event = 1; + #1000 PRGRES_out_event = 0; + end + + always @(posedge ESUSP) + begin + ESUSP_event = 1'b1; + #1000 ESUSP_event = 1'b0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge ERSRES_out) + begin + ERSRES_out_event = 1; + #1000 ERSRES_out_event = 0; + end + + always @(posedge PGSUSP) + begin + PGSUSP_event = 1'b1; + #1000 PGSUSP_event = 1'b0; + end + + always @(posedge PGRES) + begin + PGRES_event = 1'b1; + #1000 PGRES_event = 1'b0; + end + + always @(posedge ERES) + begin + ERES_event = 1'b1; + #1000 ERES_event = 1'b0; + end + + always @(posedge change_prot_bits) + begin + rising_edge_prot_bits = 1'b1; + #1000 rising_edge_prot_bits = 1'b0; + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.vhd b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.vhd new file mode 100644 index 0000000..f767cd6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.vhd @@ -0,0 +1,3768 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl064k.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2012 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Prokopovic 10 Sep 08 Inital Release +-- V1.0 S. Petrovic 12 Sep 12 Corrected functionality for sector +-- and block erase and page program +-- operation +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: FLASH MEMORY +-- Part: S25FL064K +-- +-- Description: 64 Megabit Serial Flash Memory +-- +------------------------------------------------------------------------------- +-- Known Bugs: +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl064k IS + GENERIC ( + --------------------------------------------------------------------------- + -- TIMING GENERICS: + --------------------------------------------------------------------------- + -- tipd delays: interconnect path delays (delay between components) + -- There should be one for each IN or INOUT pin in the port list + -- They are given default values of zero delay. + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_SO : VitalDelayType01 := VitalZeroDelay01; + + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays: propagation delays (pin-to-pin delay within a component) + tpd_SCK_SO_RDID_EQ_0 : VitalDelayType01Z := UnitDelay01Z;--tCLQV1 + tpd_SCK_SO_RDID_EQ_1 : VitalDelayType01Z := UnitDelay01Z;--tCLQV2 + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tSHQZ + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tHLQZ + + -- tsetup values: setup times + tsetup_CSNeg_SCK : VitalDelayType := UnitDelay;--tSLCH,tSHCH + tsetup_SI_SCK_normal_noedge_posedge : VitalDelayType + := UnitDelay;--tDVCH + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay;--tHLCH,tHHCH + tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay;--tWHSL + + -- thold values: hold times + thold_CSNeg_SCK : VitalDelayType := UnitDelay;--tSLCH,tSHCH + thold_SI_SCK_normal_noedge_posedge : VitalDelayType + := UnitDelay;--tCHDX + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay;--tCHHL,tCHHH + thold_WPNeg_CSNeg : VitalDelayType := UnitDelay;--tSHWL + + --tpw values: pulse width + tpw_SCK_slow_posedge : VitalDelayType := UnitDelay; -- tCH + tpw_SCK_slow_negedge : VitalDelayType := UnitDelay; -- tCL + tpw_SCK_fast_posedge : VitalDelayType := UnitDelay; -- tCH + tpw_SCK_fast_negedge : VitalDelayType := UnitDelay; -- tCL + tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tSHSL1 + tpw_CSNeg_pger_posedge : VitalDelayType := UnitDelay; -- tSHSL2 + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_slow : VitalDelayType := UnitDelay;-- + tperiod_SCK_fast : VitalDelayType := UnitDelay;-- + + -- tdevice values: values for internal delays + -- VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 10 us; + -- CS# High to Power Down Mode -- tDP + tdevice_DP : VitalDelayType := 3 us; + -- CS# High to StandBy mode without Electronic Signature read + tdevice_RES1 : VitalDelayType := 3 us; + -- CS# High to StandBy mode with Electronic Signature read + tdevice_RES2 : VitalDelayType := 1.8 us; + -- CS# High to next Instruction after Suspend + tdevice_PRGSUSP : VitalDelayType := 20 us; + -- CS# High to next Instruction after Suspend + tdevice_ERSSUSP : VitalDelayType := 20 us; + -- CS# High to next Instruction after Suspend + tdevice_SUSP_DLY : VitalDelayType := 20 us; + -- Resume Suspend to Program/Erase time + tdevice_PRGRES : VitalDelayType := 200 ns; + -- Resume Suspend to Program/Erase time + tdevice_ERSRES : VitalDelayType := 200 ns; + -- Page Program Time + tdevice_PP : VitalDelayType := 3 ms; + -- Byte Program Time (First Byte) + tdevice_BP1 : VitalDelayType := 50 us; + -- Additional Byte Program Time (After First Byte) + tdevice_BP2 : VitalDelayType := 12 us; + -- Sector Erase Time (4KB) + tdevice_SE : VitalDelayType := 400 ms; + -- Block Erase Time (32KB) + tdevice_BE1 : VitalDelayType := 800 ms; + -- Block Erase Time (64KB) + tdevice_BE2 : VitalDelayType := 1000 ms; + -- Chip Erase Time + tdevice_CE : VitalDelayType := 30 sec; + -- Write Status Register Time + tdevice_WRR : VitalDelayType := 15 ms; + -- Write Volatile Status Register Time + tdevice_VRR : VitalDelayType := 50 ns; + + --------------------------------------------------------------------------- + -- CONTROL GENERICS: + --------------------------------------------------------------------------- + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + + -- memory file to be loaded + mem_file_name : STRING := "s25fl064k.mem"; + screg_file_name : STRING := "s25fl064kscreg.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := FALSE; + + -- For FMF SDF technology file usage + TimingModel : STRING := DefaultTimingModel + ); + PORT ( + -- Data Inputs/Outputs + SI : INOUT std_ulogic := 'U'; -- serial data input/IO0 + SO : INOUT std_ulogic := 'U'; -- serial data output/IO1 + -- Controls + SCK : IN std_ulogic := 'U'; -- serial clock input + CSNeg : IN std_ulogic := 'U'; -- chip select input + WPNeg : INOUT std_ulogic := 'U'; -- write protect input/IO2 + HOLDNeg : INOUT std_ulogic := 'U' -- hold input/IO3 + ); + + ATTRIBUTE VITAL_LEVEL0 of s25fl064k : ENTITY IS TRUE; +END s25fl064k; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of s25fl064k IS + ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; + + --------------------------------------------------------------------------- + -- CONSTANT AND SIGNAL DECLARATION + --------------------------------------------------------------------------- + --Declaration of constants - memory characteristics + -- The constant declared here are used to enable the creation of models + -- of memories within a family with a minimum amount of editing + + CONSTANT PartID : STRING := "s25fl064k"; + CONSTANT MaxData : NATURAL := 16#FF#; + CONSTANT AddrRANGE : NATURAL := 16#7FFFFF#; + CONSTANT PageNum : NATURAL := 16#7FFF#; + CONSTANT SecSize_4 : NATURAL := 16#FFF#; + CONSTANT SecSize_32 : NATURAL := 16#7FFF#; + CONSTANT SecSize_64 : NATURAL := 16#FFFF#; + CONSTANT Blk_4_Num : NATURAL := 2047; + CONSTANT Blk_64_Num : NATURAL := 127; + CONSTANT Blk_32_Num : NATURAL := 255; + CONSTANT SFDP_HiAddr : NATURAL := 16#FF#; + CONSTANT SFDP_LoAddr : NATURAL := 16#00#; + CONSTANT SecReg_HiAddr : NATURAL := 16#FF#; + CONSTANT SecReg_LoAddr : NATURAL := 16#00#; + CONSTANT SCREG_LoAddr : NATURAL := 16#000#; + CONSTANT SCREG_HiAddr : NATURAL := 16#2FF#; + CONSTANT BYTE : NATURAL := 8; + + -- Manufacturer Identification and Device Identification + CONSTANT Manuf_ID : NATURAL := 16#EF#; + CONSTANT Device_ID1 : NATURAL := 16#16#; + CONSTANT Device_ID2 : NATURAL := 16#40#; + CONSTANT Device_ID3 : NATURAL := 16#17#; + CONSTANT Unique_id_1 : NATURAL := 16#ABAB#;--this is 64bit ID number + CONSTANT Unique_id_2 : NATURAL := 16#00#;--this is 64bit ID number + + -- Declaration of signals that will hold the delayed values of ports + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + + -- internal delays + SIGNAL PP_in : std_ulogic := '0'; + SIGNAL PP_out : std_ulogic := '0'; + SIGNAL BP1_in : std_ulogic := '0'; + SIGNAL BP1_out : std_ulogic := '0'; + SIGNAL BP2_in : std_ulogic := '0'; + SIGNAL BP2_out : std_ulogic := '0'; + SIGNAL SE_in : std_ulogic := '0'; + SIGNAL SE_out : std_ulogic := '0'; + SIGNAL BE1_in : std_ulogic := '0'; + SIGNAL BE1_out : std_ulogic := '0'; + SIGNAL BE2_in : std_ulogic := '0'; + SIGNAL BE2_out : std_ulogic := '0'; + SIGNAL CE_in : std_ulogic := '0'; + SIGNAL CE_out : std_ulogic := '0'; + SIGNAL WRR_in : std_ulogic := '0'; + SIGNAL WRR_out : std_ulogic := '0'; + SIGNAL ERSSUSP_in : std_ulogic := '0'; + SIGNAL ERSSUSP_out : std_ulogic := '0'; + SIGNAL ERSRES_in : std_ulogic := '0'; + SIGNAL ERSRES_out : std_ulogic := '0'; + SIGNAL PRGSUSP_in : std_ulogic := '0'; + SIGNAL PRGSUSP_out : std_ulogic := '0'; + SIGNAL PRGRES_in : std_ulogic := '0'; + SIGNAL PRGRES_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL RES1_in : std_ulogic := '0'; + SIGNAL RES1_out : std_ulogic := '0'; + SIGNAL RES2_in : std_ulogic := '0'; + SIGNAL RES2_out : std_ulogic := '0'; + SIGNAL DP_in : std_ulogic := '0'; + SIGNAL DP_out : std_ulogic := '0'; + SIGNAL SUSP_FL_IN : std_ulogic := '0'; + SIGNAL SUSP_FL_OUT : std_ulogic := '0'; + +BEGIN + + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + -- Because a tdevice generics is used, there must be a VITAL_primitives + -- assotiated with them + PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); + BP1 :VitalBuf(BP1_out, BP1_in, (tdevice_BP1 ,UnitDelay)); + BP2 :VitalBuf(BP2_out, BP2_in, (tdevice_BP2 ,UnitDelay)); + SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); + BE1 :VitalBuf(BE1_out, BE1_in, (tdevice_BE1 ,UnitDelay)); + BE2 :VitalBuf(BE2_out, BE2_in, (tdevice_BE2 ,UnitDelay)); + WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay)); + ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay)); + ERSRES :VitalBuf(ERSRES_out, ERSRES_in, (tdevice_ERSRES ,UnitDelay)); + PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay)); + PRGRES :VitalBuf(PRGRES_out, PRGRES_in, (tdevice_PRGRES ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + RES1 :VitalBuf(RES1_out, RES1_in, (tdevice_RES1 ,UnitDelay)); + CE :VitalBuf(CE_out, CE_in, (tdevice_CE ,UnitDelay)); + DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay)); + RES2 :VitalBuf(RES2_out, RES2_in, (tdevice_RES2 ,UnitDelay)); + SUSP_DLY :VitalBuf(SUSP_FL_OUT, SUSP_FL_IN, (tdevice_SUSP_DLY,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO); + w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + SCK : IN std_ulogic := 'U'; + CSNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + + PORT MAP ( + SIIn => SI_ipd, + SIOut => SI, + SOIn => SO_ipd, + SOut => SO, + SCK => SCK_ipd, + CSNeg => CSNeg_ipd, + HOLDNegIn => HOLDNeg_ipd, + HOLDNegOut => HOLDNeg, + WPNegIn => WPNeg_ipd, + WPNegOut => WPNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + WRITE_SR, + PAGE_PG, + PG_SUSP, + SECTOR_ERS, + BULK_ERS, + ERS_SUSP, + ERS_SUSP_PG, + PG_SUSP_ERS, + DP_DOWN, + WRITE_SR_V + ); + + -- Instruction Type + TYPE instruction_type IS ( NONE, + WREN , -- 06h + WRENV , -- 50h + WRDI , -- 04h + RDSR , -- 05h + RDSR2 , -- 35h + WRR , -- 01h + READ , -- 03h + FAST_READ , -- 0Bh + FAST_DREAD , -- 3Bh + FAST_QREAD , -- 6Bh + FAST_DREAD_2 , -- BBh + FAST_QREAD_4 , -- EBh + W_QREAD , -- E7h + WOCT_QREAD , -- E3h + SET_BURST_WRAP , -- 77h + CONT_RD_RST , -- FFh or FFFFH + PP , -- 02h + QPP , -- 32h + SE , -- 20h + BE_32 , -- 52h + BE_64 , -- D8h + CE , -- C7h or 60h + ERS_PG_SUSP , -- 75h + ERS_PG_RES , -- 7Ah + DP , -- B9h + RES_RD_ID , -- ABh + RDID , -- 90h + RDID_DUAL , -- 92h + RDID_QUAD , -- 94h + RD_UNIQ_ID , -- 4Bh + RDIDJ , -- 9Fh + RD_SFDP , -- 5Ah + ERS_SCREG , -- 44h + PG_SCREG , -- 42h + RD_SCREG -- 48h + ); + + TYPE WByteType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; + -- Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; + -- SFDP Memory Array + TYPE SFDPArray IS ARRAY (SFDP_LoAddr TO SFDP_HiAddr) OF INTEGER + RANGE -1 TO MaxData; + -- Security Register Array + TYPE SCREGArray IS ARRAY (SecReg_LoAddr TO SecReg_HiAddr) OF INTEGER + RANGE -1 TO MaxData; + ----------------------------------------------------------------------- + -- memory declaration + ----------------------------------------------------------------------- + -- Memory + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + -- Security Register 1 + SHARED VARIABLE Security_Reg1 : SCREGArray := (OTHERS => MaxData); + -- Security Register 2 + SHARED VARIABLE Security_Reg2 : SCREGArray := (OTHERS => MaxData); + -- Security Register 3 + SHARED VARIABLE Security_Reg3 : SCREGArray := (OTHERS => MaxData); + --SFDP Array + SHARED VARIABLE SFDP_array : SFDPArray := (OTHERS => 0); + -- Programming Buffer + SIGNAL WByte : WByteType := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + ----------------------------------------------------------------------- + -- Registers + ----------------------------------------------------------------------- + -- Status register 1 + SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Protect Bit 0 + ALIAS SRP0 :std_logic IS Status_reg1(7); + -- Sector/Block protect bit + ALIAS SEC :std_logic IS Status_reg1(6); + -- Top Bottom Bit + ALIAS TB :std_logic IS Status_reg1(5); + -- Status Register Block Protection Bits + ALIAS BP2 :std_logic IS Status_reg1(4); + ALIAS BP1 :std_logic IS Status_reg1(3); + ALIAS BP0 :std_logic IS Status_reg1(2); + -- Status Register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg1(1); + -- Status Register Busy Bit + ALIAS BUSY :std_logic IS Status_reg1(0); + + -- Status register 2 + SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg2_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Suspend status bit + ALIAS SUS :std_logic IS Status_reg2(7); + -- Complement protect bit + ALIAS CMP :std_logic IS Status_reg2(6); + -- Security Register Lock bits + ALIAS LB3 :std_logic IS Status_reg2(5); + ALIAS LB2 :std_logic IS Status_reg2(4); + ALIAS LB1 :std_logic IS Status_reg2(3); + -- Quad enable bit + ALIAS QE :std_logic IS Status_reg2(1); + -- Status register protect bit + ALIAS SRP1 :std_logic IS Status_reg2(0); + + -- Sector is protect if Sec_Prot(Blk_4_Num) = '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(Blk_4_Num downto 0) := + (OTHERS => '0'); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL pg_screg_flag : boolean := false; + SIGNAL ers_screg_flag : boolean := false; + SIGNAL slow_read : boolean := false; + SIGNAL dual_read : boolean := false; + SIGNAL fast_rd : boolean := true; + SIGNAL quad_read : boolean := false; + SIGNAL read_id : boolean := false; + SIGNAL sr_read : boolean := false; + + SHARED VARIABLE pp_quad : boolean := false; + SHARED VARIABLE hold_mode : boolean := false; + SHARED VARIABLE res_flag : boolean := false; + SHARED VARIABLE wren_vlt_flag : boolean := false; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; + SIGNAL PSTART : std_logic := '0'; + SIGNAL PGSUSP : std_logic := '0'; + SIGNAL PGRES : std_logic := '0'; + + SIGNAL WDONE : std_logic := '1'; + SIGNAL WSTART : std_logic := '0'; + SIGNAL VLTSTART : std_logic := '0'; + SIGNAL VLTDONE : std_logic := '1'; + + SIGNAL EDONE : std_logic := '1'; + SIGNAL ESTART : std_logic := '0'; + SIGNAL ESUSP : std_logic := '0'; + SIGNAL ERES : std_logic := '0'; + + SHARED VARIABLE read_cnt : NATURAL := 0; + SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ; + SHARED VARIABLE wrap_byte : std_logic_vector(7 downto 0); + SIGNAL change_addr : std_logic := '0'; + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + + SIGNAL change_prot_bits : std_logic := '0'; + SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000"; + SHARED VARIABLE LB_bits : std_logic_vector(2 downto 0) := "000"; + + SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0; + + -- Sector and subsector addresses + SIGNAL SA : NATURAL RANGE 0 TO Blk_4_Num := 0; + SHARED VARIABLE sect : NATURAL RANGE 0 TO Blk_4_Num; + SHARED VARIABLE sect_tmp_pg : NATURAL RANGE 0 TO Blk_4_Num; + SHARED VARIABLE sect_tmp_ers: NATURAL RANGE 0 TO Blk_4_Num; + + SHARED VARIABLE w_size : NATURAL RANGE 0 TO 64; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC64 ( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO Blk_64_Num; + BEGIN + sector := Addr/16#10000#; + AddrLOW := sector*16#10000#; + AddrHIGH := sector*16#10000# + 16#0FFFF#; + END ADDRHILO_SEC64; + + PROCEDURE ADDRHILO_SEC32 ( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO Blk_32_Num; + BEGIN + sector := Addr/16#8000#; + AddrLOW := sector*16#8000#; + AddrHIGH := sector*16#8000# + 16#7FFF#; + END ADDRHILO_SEC32; + + PROCEDURE ADDRHILO_SEC4 ( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO Blk_4_Num; + BEGIN + sector := Addr/16#1000#; + AddrLOW := sector*16#1000#; + AddrHIGH := sector*16#1000# + 16#0FFF#; + END ADDRHILO_SEC4; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + BEGIN + page := Addr/16#100#; + AddrLOW := Page*16#100#; + AddrHIGH := Page*16#100# + 16#FF#; + END AddrHILO_PG; + +-- PROCEDURE ADDRHILO_WRAP( +-- VARIABLE AddrLOW_w : INOUT NATURAL RANGE 0 to AddrRANGE; +-- VARIABLE AddrHIGH_w : INOUT NATURAL RANGE 0 to AddrRANGE; +-- VARIABLE Addr : NATURAL; +-- VARIABLE w_size : NATURAL) IS +-- VARIABLE sect_wrap : NATURAL ; +-- BEGIN +-- sect_wrap := Addr/w_size; +-- AddrLOW_w := sect_wrap*w_size; +-- AddrHIGH_w := sect_wrap*w_size + (w_size - 1); +-- END ADDRHILO_WRAP; + + PROCEDURE ADDRHILO_WRAP( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Address : NATURAL; + VARIABLE Wrap_size: NATURAL) IS + VARIABLE Addr_tmp : NATURAL; + VARIABLE Sect_wrap: NATURAL; + BEGIN + Addr_tmp := Address; + Sect_wrap := Addr_tmp/Wrap_size; + + AddrLOW := Sect_wrap*Wrap_size; + AddrHIGH := Sect_wrap*Wrap_size + (Wrap_size - 1); + END ADDRHILO_WRAP; + + BEGIN + --------------------------------------------------------------------------- + --Power Up time + --------------------------------------------------------------------------- + PoweredUp <= '1' AFTER tdevice_PU; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn,SOIn,SCK_ipd,CSNeg_ipd,HOLDNegIn,WPNegIn) + + -- Timing Check Variables + -- Setup/Hold Checks variables + VARIABLE Tviol_CSNeg_SCK : X01 := '0'; + VARIABLE TD_CSNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_SOIn_SCK : X01 := '0'; + VARIABLE TD_SOIn_SCK : VitalTimingDataType; + + VARIABLE Tviol_HOLDNeg_SCK : X01 := '0'; + VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_HOLDNegIn_SCK : X01 := '0'; + VARIABLE TD_HOLDNegIn_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNegIn_SCK : X01 := '0'; + VARIABLE TD_WPNegIn_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType; + + --Pulse Width and Period Check Variables + VARIABLE Pviol_SCK_slow : X01 := '0'; + VARIABLE PD_SCK_slow : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast : X01 := '0'; + VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_read : X01 := '0'; + VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_pgers : X01 := '0'; + VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_slow_p : X01 := '0'; + VARIABLE PD_SCK_slow_p : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_p : X01 := '0'; + VARIABLE PD_SCK_fast_p : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK, + SetupLow => tsetup_CSNeg_SCK, + HoldHigh => thold_CSNeg_SCK, + HoldLow => thold_CSNeg_SCK, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK, + Violation => Tviol_CSNeg_SCK + ); + -- Setup/Hold Check between SI and SCK / + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + VitalSetupHoldCheck ( + TestSignal => SOIn, + TestSignalName => "SO", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => SOut_z /= SOIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SOIn_SCK, + Violation => Tviol_SOIn_SCK + ); + + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNegIn_SCK, + Violation => Tviol_HOLDNegIn_SCK + ); + + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => WPNegOut_zd /= WPNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNegIn_SCK, + Violation => Tviol_WPNegIn_SCK + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_HOLDNeg_SCK, + SetupLow => tsetup_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + CheckEnabled => QE = '0', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNeg_SCK, + Violation => Tviol_HOLDNeg_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => QE = '0', + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_setup, + Violation => Tviol_WPNeg_CSNeg_setup + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => QE = '0', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_hold, + Violation => Tviol_WPNeg_CSNeg_hold + ); + + --Pulse Width and Period Check Variables + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_slow_negedge, + PulseWidthHigh => tpw_SCK_slow_posedge, + PeriodData => PD_SCK_slow, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_slow, + HeaderMsg => InstancePath & PartID, + CheckEnabled => slow_read + ); + + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_fast_negedge, + PulseWidthHigh => tpw_SCK_fast_posedge, + PeriodData => PD_SCK_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd + ); + + -- Pulse Width Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CSNeg_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => slow_read OR fast_rd OR dual_read OR + quad_read + ); + + -- Pulse Width Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pger_posedge, + PeriodData => PD_CSNeg_pgers, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_pgers, + HeaderMsg => InstancePath & PartID, + CheckEnabled => true); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_slow, + PeriodData => PD_SCK_slow_p, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_slow_p, + HeaderMsg => InstancePath & PartID, + CheckEnabled => slow_read + ); + + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast, + PeriodData => PD_SCK_fast_p, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_p, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd OR dual_read OR quad_read + ); + + Violation := Tviol_CSNeg_SCK OR + Tviol_SI_SCK OR + Tviol_HOLDNeg_SCK OR + Tviol_WPNeg_CSNeg_setup OR + Tviol_WPNeg_CSNeg_hold OR + Tviol_HOLDNegIn_SCK OR + Tviol_WPNegIn_SCK OR + Tviol_SOIn_SCK OR + Pviol_SCK_slow OR + Pviol_SCK_fast OR + Pviol_CSNeg_read OR + Pviol_CSNeg_pgers OR + Pviol_SCK_slow_p OR + Pviol_SCK_fast_p; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + + --------------------------------------------------------------------------- + -- sequential process for FSM state transition + --------------------------------------------------------------------------- + StateTransition : PROCESS(next_state,PoweredUp) + + BEGIN + IF PoweredUp = '1' THEN + IF next_state'EVENT THEN + current_state <= next_state; + END IF; + END IF; + END PROCESS StateTransition; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd) + + TYPE bus_cycle_type IS (STAND_BY, + OPCODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + + TYPE quad_data_type IS ARRAY (0 TO 511) OF INTEGER RANGE 0 TO 15; + + VARIABLE bus_cycle_state : bus_cycle_type; + + VARIABLE opcode_cnt : NATURAL := 0; + VARIABLE addr_cnt : NATURAL := 0; + VARIABLE mode_cnt : NATURAL := 0; + VARIABLE wrap_cnt : NATURAL := 0; + VARIABLE dummy_cnt : NATURAL := 0; + VARIABLE data_cnt : NATURAL := 0; + VARIABLE bit_cnt : NATURAL := 0; + + VARIABLE Data_in : std_logic_vector(2047 downto 0) + := (others => '0'); + VARIABLE opcode : std_logic_vector(7 downto 0); + VARIABLE opcode_in : std_logic_vector(7 downto 0); + VARIABLE opcode_double : std_logic_vector(15 downto 0); + VARIABLE opcode_double_in : std_logic_vector(15 downto 0); + VARIABLE addr_bytes : std_logic_vector(23 downto 0); + VARIABLE Address_in : std_logic_vector(23 downto 0); + VARIABLE mode_bits : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); +-- VARIABLE wrap_byte : std_logic_vector(7 downto 0); + VARIABLE wrap_in : std_logic_vector(7 downto 0); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + + BEGIN + + IF falling_edge(CSNeg_ipd) THEN + IF (bus_cycle_state = STAND_BY) THEN + bus_cycle_state := OPCODE_BYTE; + Instruct <= NONE; + write <= '1'; + opcode_cnt := 0; + addr_cnt := 0; + data_cnt := 0; + mode_cnt := 0; + wrap_cnt := 0; + dummy_cnt := 0; + ELSIF (bus_cycle_state = DATA_BYTES AND + mode_bits(5 DOWNTO 4) = "10") THEN + bus_cycle_state := ADDRESS_BYTES; + dummy_cnt := 0; + opcode_cnt := 0; + END IF; + END IF; + + IF rising_edge(SCK_ipd) AND (PoweredUp = '1') THEN + IF (CSNeg_ipd = '0') THEN + CASE (bus_cycle_state) IS + WHEN OPCODE_BYTE => + IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF opcode_cnt = BYTE THEN + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := opcode_in(7-i); + END LOOP; + + CASE opcode IS + WHEN "00000110" => -- 06H + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "01010000" => + Instruct <= WRENV; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000101" => -- 05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => -- 35h + Instruct <= RDSR2; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => -- 01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => -- 03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00001011" => -- 0Bh + Instruct <= FAST_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111011" => -- 3Bh + Instruct <= FAST_DREAD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01101011" => -- 6Bh + Instruct <= FAST_QREAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "10111011" => -- BBh + Instruct <= FAST_DREAD_2; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11101011" => -- EBh + Instruct <= FAST_QREAD_4; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "11100111" => --E7h + Instruct <= W_QREAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "11100011" => -- E3h + Instruct <= WOCT_QREAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "01110111" => -- 77h + Instruct <= SET_BURST_WRAP; + IF (QE = '1') THEN + bus_cycle_state := DUMMY_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "11111111" => -- FFh + Instruct <= CONT_RD_RST; + bus_cycle_state := MODE_BYTE; + WHEN "00000010" => -- 02H + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => -- 32h + Instruct <= QPP; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "00100000" => -- 20h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01010010" => -- 52h + Instruct <= BE_32; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11011000" => -- D8h + Instruct <= BE_64; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11000111" | "01100000" => -- C7 or 60h + Instruct <= CE; + bus_cycle_state := DATA_BYTES; + WHEN "01110101" => -- 75h + Instruct <= ERS_PG_SUSP; + bus_cycle_state := DATA_BYTES; + WHEN "01111010" => -- 7Ah + Instruct <= ERS_PG_RES; + bus_cycle_state := DATA_BYTES; + WHEN "10111001" => -- B9h + Instruct <= DP; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => -- ABh + Instruct <= RES_RD_ID; + bus_cycle_state := DUMMY_BYTES; + WHEN "10010000" => -- 90h + Instruct <= RDID; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10010010" => -- 92h + Instruct <= RDID_DUAL; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10010100" => -- 94h + Instruct <= RDID_QUAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "01001011" => -- 4Bh + Instruct <= RD_UNIQ_ID; + bus_cycle_state := DUMMY_BYTES; + WHEN "10011111" => -- 9Fh + Instruct <= RDIDJ; + bus_cycle_state := DATA_BYTES; + WHEN "01011010" => -- 5Ah + Instruct <= RD_SFDP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01000100" => -- 44h + Instruct <= ERS_SCREG; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01000010" => -- 42h + Instruct <= PG_SCREG; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001000" => -- 48h + Instruct <= RD_SCREG; + bus_cycle_state := ADDRESS_BYTES; + + WHEN OTHERS => + NULL; + + END CASE; + END IF; + ELSE + REPORT "Device is in HOLD mode, opcode" + SEVERITY NOTE; + END IF; + + WHEN ADDRESS_BYTES => + IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN + IF (Instruct = READ OR Instruct = FAST_READ OR + Instruct = FAST_DREAD OR Instruct = RDID OR + Instruct = SE OR Instruct = PP OR + Instruct = RD_SCREG OR Instruct = PG_SCREG OR + Instruct = RD_SFDP OR Instruct = BE_32 OR + Instruct = BE_64 OR Instruct = ERS_SCREG OR + ((Instruct = QPP OR Instruct = FAST_QREAD) + AND QE = '1')) THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + + IF (Instruct = PP OR Instruct = QPP + OR Instruct = READ OR Instruct = SE + OR Instruct = BE_32 OR Instruct = BE_64 + OR Instruct = RDID OR Instruct = PG_SCREG + OR Instruct = ERS_SCREG) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct = RDID_DUAL OR + Instruct = FAST_DREAD_2) THEN + IF (SOIn /= 'Z') THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt + 1):= SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF (addr_cnt = (3*BYTE)/2) THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF (mode_bits(5 downto 4) = "10") THEN + opcode_double_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF (opcode_cnt = 2*BYTE) THEN + FOR I IN 15 DOWNTO 0 LOOP + opcode_double(i) := + opcode_double_in(15-i); + END LOOP; + IF (opcode_double="1111111111111111") THEN + Instruct <= CONT_RD_RST; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + ELSIF (QE = '1' AND (Instruct = FAST_QREAD_4 OR + Instruct = W_QREAD OR Instruct = WOCT_QREAD OR + Instruct = RDID_QUAD)) THEN + IF (SOIn /= 'Z') THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF (addr_cnt = (3*BYTE)/4) THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF (mode_bits(5 downto 4) = "10") THEN + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF (opcode_cnt = BYTE) THEN + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := + opcode_in(7-i); + END LOOP; + IF (opcode = "11111111") THEN + Instruct <= CONT_RD_RST; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + END IF; + ELSE + REPORT "Device is in HOLD mode, addr" + SEVERITY NOTE; + END IF; + + WHEN MODE_BYTE => + IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN + IF (Instruct = SET_BURST_WRAP AND QE = '1') THEN + wrap_in(4*wrap_cnt) := HOLDNegIn; + wrap_in(4*wrap_cnt+1) := WPNegIn; + wrap_in(4*wrap_cnt+2) := SOIn; + wrap_in(4*wrap_cnt+3) := SIIn; + wrap_cnt := wrap_cnt + 1; + IF (wrap_cnt = BYTE/4) THEN + wrap_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + wrap_byte(i) := wrap_in(7-i); + END LOOP; + bus_cycle_state := DATA_BYTES; + END IF; + CASE (wrap_byte(6 DOWNTO 5)) IS + WHEN "00" => + w_size := 8; + WHEN "01" => + w_size := 16; + WHEN "10" => + w_size := 32; + WHEN "11" => + w_size := 64; + WHEN OTHERS => + NULL; + END CASE; + ELSIF ((Instruct = FAST_QREAD_4 OR + Instruct = WOCT_QREAD OR Instruct = W_QREAD OR + Instruct = RDID_QUAD ) AND QE = '1') THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF (mode_cnt = BYTE/4) THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bits(i) := mode_in(7-i); + END LOOP; + IF (Instruct = WOCT_QREAD) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct = RDID_DUAL OR + Instruct = FAST_DREAD_2) THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF (mode_cnt = BYTE/2) THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bits(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSE + REPORT "Device is in HOLD mode, mode" + SEVERITY NOTE; + END IF; + + WHEN DUMMY_BYTES => + IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN + IF ((Instruct = FAST_QREAD_4 OR + Instruct = RDID_QUAD) AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE/2) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = W_QREAD AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE/4) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = SET_BURST_WRAP AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = 3*BYTE/4) THEN + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF (Instruct = FAST_QREAD AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct=FAST_READ OR Instruct=RD_SFDP + OR Instruct = FAST_DREAD OR Instruct=RD_SCREG) THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = 4*BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSE -- for RES_RD_ID + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = 3*BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSE + REPORT "Device is in HOLD mode, dummy" + SEVERITY NOTE; + END IF; -- end of DUMMY_BYTES + + WHEN DATA_BYTES => + IF (Instruct = PP OR Instruct = WRR OR + Instruct = PG_SCREG) THEN + IF ((HOLDNeg_pullup = '1' AND QE='0') OR QE='1') THEN + IF (data_cnt > 2047) THEN + --In case of serial mode and PP,IF more than + --256 bytes are sent to the device + IF (bit_cnt = 0) THEN + FOR I IN 0 TO (255*BYTE-1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in(2040 + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF (bit_cnt = 8) THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + ELSE + REPORT "Device is in HOLD mode, data" + SEVERITY NOTE; + END IF; + ELSIF (Instruct = QPP AND QE ='1') THEN + pp_quad := TRUE; + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF (data_cnt > 511) THEN + --In case of quad mode and QPP,IF more than + -- 256 bytes are sent to the device + FOR I IN 0 TO 510 LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in(511) := to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF (quad_nybble /= "ZZZZ") THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + END IF; + + WHEN OTHERS => NULL; + END CASE; + END IF; + END IF; + + IF falling_edge(SCK_ipd) AND (bus_cycle_state = DATA_BYTES AND + CSNeg_ipd ='0') THEN + IF (((Instruct = RDSR OR Instruct = RDSR2 OR + Instruct = FAST_READ OR Instruct = FAST_DREAD OR + Instruct = FAST_DREAD_2 OR Instruct = RES_RD_ID OR + Instruct = RDID OR Instruct = RDID_DUAL OR + Instruct = RD_UNIQ_ID OR Instruct = RDIDJ OR + Instruct = RD_SFDP OR Instruct = RD_SCREG OR + Instruct = READ) AND ((HOLDNeg_pullup ='1' AND QE='0') OR QE='1')) + OR ((Instruct = FAST_QREAD OR Instruct = FAST_QREAD_4 OR + Instruct = W_QREAD OR Instruct = RDID_QUAD OR + Instruct = WOCT_QREAD) AND QE='1')) THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + IF (bus_cycle_state=MODE_BYTE AND Instruct = CONT_RD_RST) THEN + mode_bits(5 downto 4) := "11"; + mode_bits(7 downto 6) := "00"; + mode_bits(3 downto 0) := "0000"; + bus_cycle_state := STAND_BY; + ELSIF (bus_cycle_state=DATA_BYTES AND + NOT (mode_bits(5 downto 4)="10")) THEN + bus_cycle_state := STAND_BY; + CASE (Instruct) IS + WHEN WREN | WRDI | SET_BURST_WRAP | SE | BE_32 | BE_64 | + CE | ERS_PG_RES | DP | ERS_SCREG => + + IF (data_cnt = 0) THEN + write <= '0'; + END IF; + WHEN WRENV => + write <= '0'; + wren_vlt_flag := TRUE; + + WHEN RES_RD_ID => + write <= '0'; + res_flag := TRUE; + + WHEN WRR => + IF (data_cnt = 8) THEN + --If CS# is driven high after eight + --cycle,only the Status Register is + --written to. + write <= '0'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= Data_in(7-i); + END LOOP; + ELSIF (data_cnt = 16) THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= Data_in(7-i); + END LOOP; + + FOR j IN 0 TO 7 LOOP + Status_reg2_in(j) <= Data_in(15-j); + END LOOP; +-- FOR I IN 0 TO 15 LOOP +-- Status_reg1_in(i) <= Data_in(7-i); +-- Status_reg2_in(i) <= Data_in(15-i); +-- END LOOP; + END IF; + + WHEN PP | PG_SCREG => + IF (data_cnt > 0) THEN + IF ((data_cnt mod 8) = 0) THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 7 DOWNTO 0 LOOP + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + + IF (data_cnt > 256*BYTE) THEN + Byte_number <= 255; + ELSE + Byte_number <= ((data_cnt/8) - 1); + END IF; + END IF; + END IF; + + WHEN QPP => + IF (data_cnt >0) THEN + IF ((data_cnt mod 2) = 0) THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + + IF (data_cnt > 256*BYTE/4) THEN + Byte_number <= 255; + ELSE + Byte_number <= ((data_cnt/2) - 1); + END IF; + END IF; + END IF; + + WHEN others => + null; + + END CASE; + + ELSIF (bus_cycle_state=DATA_BYTES AND + (mode_bits(5 DOWNTO 4)="10")) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := STAND_BY; + IF (HOLDNeg_pullup ='1' AND (Instruct = RES_RD_ID) AND + (dummy_cnt = 0)) THEN + write <= '0'; + res_flag := FALSE; + END IF; + END IF; + END IF; -- end of rising_edge_CSNeg_ipd + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART, PGSUSP, PGRES) + VARIABLE pob : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF Instruct = PP OR Instruct = QPP OR Instruct = PG_SCREG THEN + IF LongTimming THEN + pob := tdevice_PP; + ELSE + pob := tdevice_PP / 10; + END IF; + END IF; + IF rising_edge(PSTART) AND PDONE = '1' THEN + elapsed := 0 ns; + PDONE <= '0', '1' AFTER pob; + start := NOW; + ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN + elapsed := NOW - start; + duration := pob - elapsed; + PDONE <= '0'; + ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN + start := NOW; + PDONE <= '0', '1' AFTER duration; + END IF; + + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WRR; + ELSE + wob := tdevice_WRR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register when Write Enable for + -- Volatile Status Register was issued + --------------------------------------------------------------------------- + + WriteTimeVlt : PROCESS(VLTSTART) + VARIABLE wvob : time; + BEGIN + wvob := tdevice_VRR; + IF rising_edge(VLTSTART) AND VLTDONE = '1' THEN + VLTDONE <= '0' , '1' AFTER wvob; + END IF; + END PROCESS WriteTimeVlt; + + --------------------------------------------------------------------------- + -- Timing control for the Erase Operation + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART, ESUSP, ERES) + VARIABLE seo : time; + VARIABLE beo32 : time; + VARIABLE beo64 : time; + VARIABLE ceo : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + seo := tdevice_SE; + beo32 := tdevice_BE1; + beo64 := tdevice_BE2; + ceo := tdevice_CE; + ELSE + seo := tdevice_SE / 100; + beo32 := tdevice_BE1 / 100; + beo64 := tdevice_BE2 / 100; + ceo := tdevice_CE / 100; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = CE THEN + duration := ceo; + ELSIF Instruct = BE_64 THEN + duration := beo64; + ELSIF Instruct = BE_32 THEN + duration := beo32; + ELSE -- sector erase 4KB, instruct SE + duration := seo; + END IF; + elapsed := 0 ns; + EDONE <= '0', '1' AFTER duration; + start := NOW; + ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN + elapsed := NOW - start; + duration := duration - elapsed; + EDONE <= '0'; + ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN + start := NOW; + EDONE <= '0', '1' AFTER duration; + END IF; + + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS(CSNeg_ipd) + BEGIN + IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, WDONE, ERSSUSP_out, RES1_out, + ERSRES_out, PRGSUSP_out, EDONE,PRGRES_out, DP_out, PDONE, + VLTDONE,RES2_out) + + BEGIN + + IF rising_edge(PoweredUp) THEN + next_state <= IDLE; + ELSE + CASE current_state IS + WHEN IDLE => + IF falling_edge(write) THEN + IF (Instruct = WRR AND (SRP1='0' AND + (SRP0='0' OR (SRP0='1' AND WPNeg ='1')))) THEN + IF (WEL='1' AND NOT (wren_vlt_flag)) THEN + next_state <= WRITE_SR; + ELSIF (WEL='0' AND wren_vlt_flag) THEN + next_state <= WRITE_SR_V; + END IF; + ELSIF (Instruct = PP AND WEL='1') THEN + sect := Address / 16#1000#; + sect_tmp_pg := sect; + IF (Sec_Prot(sect) = '0') THEN + next_state <= PAGE_PG; + END IF; + ELSIF (Instruct = QPP AND WEL='1' AND QE='1') THEN + sect := Address / 16#1000#; + sect_tmp_pg := sect; + IF (Sec_Prot(sect) = '0') THEN + next_state <= PAGE_PG; + END IF; + ELSIF (Instruct = PG_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect < 4 AND sect > 0) AND + LB_bits(sect-1)='0') THEN + next_state <= PAGE_PG; + END IF; + ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF ((Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) AND WEL='1') THEN + sect := Address / 16#1000#; + sect_tmp_ers := sect; + IF (Sec_Prot(sect) = '0') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF (Instruct = CE AND WEL='1' AND + ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR + (CMP='1' AND BP2='1' AND BP1='1' AND BP0='1'))) THEN + next_state <= BULK_ERS; + ELSE + next_state <= IDLE; + END IF; + ELSIF rising_edge(DP_out) THEN + next_state <= DP_DOWN; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; -- end of WRITE_SR + + WHEN WRITE_SR_V => + IF rising_edge(VLTDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF (PRGSUSP_out'event AND PRGSUSP_out = '1') THEN + next_state <= PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; -- end of PAGE_PG + + WHEN PG_SUSP => + IF (PRGRES_out'event AND PRGRES_out = '1') THEN + next_state <= PAGE_PG; + ELSIF falling_edge(write) THEN + IF (Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) THEN + sect := Address / 16#1000#; + IF ((Sec_Prot(sect) = '0') AND + (sect /= sect_tmp_pg)) THEN + next_state <= PG_SUSP_ERS; + END IF; + END IF; + END IF; -- end of PG_SUSP + + WHEN PG_SUSP_ERS => + IF rising_edge(EDONE) THEN + next_state <= PG_SUSP; + ELSE + next_state <= PG_SUSP_ERS; + END IF; + + WHEN BULK_ERS => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN SECTOR_ERS => + IF (ERSSUSP_out'event AND ERSSUSP_out = '1') THEN + next_state <= ERS_SUSP; + ELSIF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN ERS_SUSP => + IF (ERSRES_out'event AND ERSRES_out = '1') THEN + next_state <= SECTOR_ERS; + ELSIF falling_edge(write) THEN + IF (Instruct = PP OR (Instruct = QPP AND QE='1')) THEN + sect := Address / 16#1000#; + IF ((Sec_Prot(sect) = '0') AND + (sect /= sect_tmp_ers)) THEN + next_state <= ERS_SUSP_PG; + END IF; + ELSIF (Instruct = PG_SCREG) THEN + sect := Address / 16#1000#; + IF ((sect < 4 AND sect > 0) AND + LB_bits(sect-1)='0') THEN + next_state <= ERS_SUSP_PG; + END IF; + END IF; + END IF; + + WHEN ERS_SUSP_PG => + IF rising_edge(PDONE) THEN + next_state <= ERS_SUSP; + ELSE + next_state <= ERS_SUSP_PG; + END IF; + + WHEN DP_DOWN => + IF rising_edge(RES1_out) OR rising_edge(RES2_out) THEN + next_state <= IDLE; + END IF; + + END CASE; + END IF; + END PROCESS StateGen; + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(read_out, Instruct, SCK_ipd, change_addr, write, + Address, PDONE, WDONE, EDONE, ERSSUSP_out, PoweredUp, + CSNeg_ipd, RES1_out, ERSRES_out, PRGSUSP_out,PRGRES_out, + VLTDONE, current_state, DP_out, RES2_out,SUSP_FL_OUT) + + VARIABLE WData : WByteType:= (OTHERS => MaxData); + + VARIABLE oe : boolean := FALSE; + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + + VARIABLE AddrLo_ers : NATURAL; + VARIABLE AddrHi_ers : NATURAL; + VARIABLE AddrLo_wrap : NATURAL; + VARIABLE AddrHi_wrap : NATURAL; + + VARIABLE Addr : NATURAL; + VARIABLE Addr_w : NATURAL; + VARIABLE Addr_ers : NATURAL; + VARIABLE Addr_tmp : NATURAL; + VARIABLE Addr_tmp_2 : NATURAL; + VARIABLE Addr_tmp_3 : NATURAL; + VARIABLE Addr_screg : NATURAL; + VARIABLE Addr_screg_tmp : NATURAL; + + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(23 downto 0); + VARIABLE ident_out2 : std_logic_vector(15 downto 0); + VARIABLE uniq_id : std_logic_vector(63 downto 0); + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + + VARIABLE wr_cnt : NATURAL RANGE 0 TO 255; +-- VARIABLE sect : NATURAL RANGE 0 TO Blk_4_Num; + VARIABLE cnt : NATURAL RANGE 0 TO 256 := 0; + + BEGIN + + oe := rising_edge(read_out) AND PoweredUp = '1'; + + IF Instruct'EVENT THEN + read_cnt := 0; + + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + read_id <= false; + pp_quad := FALSE; + + IF (current_state = IDLE AND DP_in = '1') THEN + REPORT "Command results can be corrupted " + SEVERITY WARNING; + END IF; + END IF; + + IF rising_edge(PoweredUp) THEN + WEL := '0'; + BUSY := '0'; + SUS := '0'; + change_prot_bits <= '1', '0' AFTER 1 ns; + END IF; + + IF change_addr'EVENT THEN + read_addr := Address; + END IF; + + IF RES1_out'EVENT AND RES1_out = '1' THEN + RES1_in <= '0'; + END IF; + + IF RES2_out'EVENT AND RES2_out = '1' THEN + RES2_in <= '0'; + END IF; + + IF SUSP_FL_OUT'EVENT AND SUSP_FL_OUT = '1' THEN + SUSP_FL_IN <= '0'; + END IF; + + CASE current_state IS + + WHEN IDLE => + + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + read_id <= false; + sr_read <= false; + res_flag := FALSE; + pg_screg_flag <= false; + ers_screg_flag <= false; + + IF falling_edge(write) AND DP_in ='0' THEN + read_cnt := 0; + IF (Instruct = WREN) THEN + WEL := '1'; + ELSIF (Instruct = WRDI) THEN + WEL := '0'; + ELSIF (Instruct = WRR) THEN + IF(SRP1='0' AND (SRP0='0' OR + (SRP0='1' AND WPNeg='1'))) THEN + IF WEL='1' AND NOT (wren_vlt_flag) THEN + WSTART <= '1', '0' AFTER 5 ns; + BUSY := '1'; + ELSIF (WEL='0' AND wren_vlt_flag) THEN + VLTSTART <= '1', '0' AFTER 5 ns; + END IF; + ELSE + WEL := '0'; + END IF; + ELSIF ((Instruct = PP OR (Instruct = QPP AND QE='1')) + AND WEL='1' AND PDONE='1') THEN + sect := Address / 16#1000#; + IF (Sec_Prot(sect) = '0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + Addr := Address; + Addr_tmp:= Address; + wr_cnt := Byte_number; + + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PG_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + wr_cnt := Byte_number; + Addr_screg := Address mod 16#1000#; + Addr_screg_tmp := Address mod 16#1000#; + pg_screg_flag <= true; + + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + + ELSE + WEL := '0'; + END IF; + ELSIF ((Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) AND WEL='1') THEN + sect := Address / 16#1000#; + IF (Sec_Prot(sect) = '0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + Addr_ers := Address; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = CE AND WEL='1') THEN + IF ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR + (CMP='1' AND BP2='1' AND BP1='1' AND BP0='1')) THEN +-- IF (Sec_Prot = 0) + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + SA <= sect; + ers_screg_flag <= true; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = DP) THEN + RES2_in <= '0'; + RES1_in <= '0'; + DP_in <= '1'; + END IF; + -- end of falling_edge_write + ELSIF (oe AND DP_in='0') THEN + IF (Instruct = RDSR) THEN + --Read Status Register + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDSR2) THEN + sr_read <= true; + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN + IF (Instruct = READ) THEN + fast_rd <= false; + dual_read <= false; + slow_read <= true; + quad_read <= false; + sr_read <= false; + ELSE + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + END IF; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF (Instruct=FAST_DREAD OR Instruct=FAST_DREAD_2) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF ((Instruct=FAST_QREAD OR Instruct=FAST_QREAD_4 OR + Instruct=W_QREAD OR Instruct=WOCT_QREAD) + AND QE='1') THEN + IF ((Instruct=W_QREAD AND (Address mod 2 /= 0) ) OR + (Instruct=WOCT_QREAD AND + (Address mod 16 /= 0))) THEN + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + REPORT "Word Read can't execute Wrong Address" + SEVERITY NOTE; + END IF; + ELSE + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + Addr_w := Address; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + IF (wrap_byte(4)='0' AND (Instruct=FAST_QREAD_4 + OR Instruct=W_QREAD)) THEN + ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap, + Addr_w,w_size); + IF (read_addr = AddrHi_wrap) THEN + read_addr := AddrLo_wrap; + ELSE + read_addr := read_addr + 1; + END IF; + ELSE + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR + Instruct=RDID_QUAD) THEN + IF (read_addr mod 2 = 0) THEN + ident_out2 := to_slv(Manuf_ID,8) & + to_slv(Device_ID1,8); + ELSE + ident_out2 := to_slv(Device_ID1,8) & + to_slv(Manuf_ID,8); + END IF; + read_id <= true; + IF (Instruct = RDID) THEN + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 16) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDID_DUAL) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-2*read_cnt); + SIOut_zd <= ident_out2(14-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSE -- (Instruct = RDID_QUAD) + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + HOLDNegOut_zd <= ident_out2(15-4*read_cnt); + WPNegOut_zd <= ident_out2(14-4*read_cnt); + SOut_zd <= ident_out2(13-4*read_cnt); + SIOut_zd <= ident_out2(12-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + -- unique ID number is not in data sheet + read_id <= true; + uniq_id := to_slv(Unique_id_2,32)& + to_slv(Unique_id_1,32); + SOut_zd <= uniq_id(63-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 64) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDIDJ) THEN + read_id <= true; + ident_out := to_slv(Manuf_ID,8) & + to_slv(Device_ID2,8) & to_slv(Device_ID3,8); + SOut_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 24) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RD_SFDP) THEN +-- sfdp_addr := read_addr / 16#100#; + IF (read_addr / 16#100# = 0) THEN + Addr_tmp_2 := (read_addr mod 16#100#); + data_out := to_slv(SFDP_array(Addr_tmp_2),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = SFDP_HiAddr) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Given SFDP address is out of range" + SEVERITY NOTE; + END IF; + END IF; + ELSIF (Instruct = RD_SCREG) THEN + Addr_tmp_2 := read_addr / 16#100#; + Addr_tmp_3 := read_addr mod 16#100#; + IF (Addr_tmp_2 = 16) THEN + -- Security Register No.1 + data_out := to_slv(Security_Reg1(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 32) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg2(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 48) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg3(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Security Reg address is out of range " + SEVERITY NOTE; + END IF; + END IF; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr mod 256 = SecReg_HiAddr) THEN + read_addr := (read_addr/256)*(SecReg_HiAddr+1); + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF Instruct = RES_RD_ID THEN + read_id <= true; + data_out := to_slv(Device_ID1,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; -- end of oe + ELSIF rising_edge(DP_out) THEN + DP_in <= '0'; + END IF; -- end of IDLE state + + WHEN WRITE_SR => + + IF (WDONE ='1') THEN + BUSY := '0'; + WEL := '0'; + + SRP0 := Status_reg1_in(7); + SEC := Status_reg1_in(6); + TB := Status_reg1_in(5); + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + BP_bits := BP2 & BP1 & BP0; + CMP := Status_reg2_in(6); + QE := Status_reg2_in(1); + -- SRP1 bit will only change value from '0' to '1' + -- if SRP1 is '1' than Status Register is protected + --and is not possible to write it + SRP1 := Status_reg2_in(0); + + IF LB3 = '0' THEN + LB3 := Status_reg2_in(5); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + + IF LB2 = '0' THEN + LB2 := Status_reg2_in(4); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + IF LB1 = '0' THEN + LB1 := Status_reg2_in(3); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + LB_bits := LB3 & LB2 & LB1; + change_prot_bits <= '1' , '0' AFTER 2 ns; + END IF; -- end of WDONE + + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; -- end of WRITE_SR + + WHEN WRITE_SR_V => + + IF (VLTDONE = '1') THEN + SRP0 := Status_reg1_in(7); + SEC := Status_reg1_in(6); + TB := Status_reg1_in(5); + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + BP_bits := BP2 & BP1 & BP0; + CMP := Status_reg2_in(6); + QE := Status_reg2_in(1); + -- SRP1 bit will only change value from '0' to '1' + -- if SRP1 is '1' than Status Register is protected + --and is not possible to write it + SRP1 := Status_reg2_in(0); + IF LB3 = '0' THEN + LB3 := Status_reg2_in(5); + ELSIF LB2 = '0' THEN + LB2 := Status_reg2_in(4); + ELSIF LB1 = '0' THEN + LB1 := Status_reg2_in(3); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + + change_prot_bits <= '1' , '0' AFTER 2 ns; + + wren_vlt_flag := FALSE; + END IF; + + WHEN PAGE_PG | ERS_SUSP_PG => + + IF falling_edge(PDONE) THEN + + IF (Instruct /= PG_SCREG) THEN + ADDRHILO_PG(AddrLo, AddrHi, Addr); + END IF; + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + IF (Instruct = PG_SCREG) THEN + IF (sect = 1) THEN + old_int := Security_Reg1(Addr_screg + i - cnt); + ELSIF (sect = 2) THEN + old_int := Security_Reg2(Addr_screg + i - cnt); + ELSE + old_int := Security_Reg3(Addr_screg + i - cnt); + END IF; + ELSE + old_int := Mem(Addr + i - cnt); + END IF; + IF (new_int > -1) THEN + new_bit := to_slv(new_int,8); + IF (old_int > -1) THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + IF (Instruct = PG_SCREG) THEN + IF (sect = 1) THEN + Security_Reg1(Addr_screg + i - cnt) := - 1; + ELSIF (sect = 2) THEN + Security_Reg2(Addr_screg + i - cnt) := - 1; + ELSE + Security_Reg3(Addr_screg + i - cnt) := - 1; + END IF; + ELSE + Mem(Addr + i - cnt) := - 1; + END IF; + IF (Instruct /= PG_SCREG) THEN + IF ((Addr + i) = AddrHi) THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + ELSE + IF Addr_screg + i = SecReg_HiAddr THEN + Addr_screg := SecReg_LoAddr; + cnt := i + 1; + END IF; + END IF; + END LOOP; + cnt := 0; + + END IF; + + IF (PDONE = '1') THEN + IF (current_state /= ERS_SUSP_PG) THEN + BUSY := '0'; + END IF; + WEL := '0'; + + FOR I IN 0 TO wr_cnt LOOP + IF pg_screg_flag THEN + IF (sect = 1) THEN + Security_Reg1(Addr_screg_tmp + i - cnt) :=WData(i); + ELSIF (sect = 2) THEN + Security_Reg2(Addr_screg_tmp + i - cnt) :=WData(i); + ELSE + Security_Reg3(Addr_screg_tmp + i - cnt) :=WData(i); + END IF; + IF ((Addr_screg_tmp + i) = SecReg_HiAddr) THEN + Addr_screg_tmp := SecReg_LoAddr; + cnt := i + 1; + END IF; + ELSE + Mem(Addr_tmp + i - cnt) := WData(i); + IF ((Addr_tmp + i) = AddrHi) THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END IF; + END LOOP; + END IF; -- end of PDONE + + IF (Instruct = ERS_PG_SUSP AND current_state = PAGE_PG AND + SUSP_FL_IN = '0') THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + END IF; + + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + + WHEN PG_SUSP => + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + BUSY := '0'; + IF (PRGSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN + PRGSUSP_in <= '0'; + --The BUSY bit in the Status Register will indicate that + --the device is ready for another operation. +-- BUSY := '0'; + --The SuspEND (SUS) bit in the Status Register2 will + --be set to the logical “1” state to indicate that the + --program operation has been suspENDed. + SUS := '1'; + END IF; + IF (PRGRES_out'event AND PRGRES_out = '1') THEN + PRGRES_in <= '0'; + BUSY := '1'; + END IF; + IF (SUS = '1') THEN + IF falling_edge(write) THEN + IF (Instruct = ERS_PG_RES) THEN + SUS := '0'; + PRGRES_in <= '1'; + SUSP_FL_IN <= '1'; + PGRES <= '1', '0' AFTER 5 ns; + ELSIF ((Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) AND WEL='1') THEN + sect := Address / 16#1000#; + IF (sect /= sect_tmp_pg AND + Sec_Prot(sect) = '0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + Addr_ers := Address; + ELSE + BUSY := '0'; + REPORT "Can't erase sector,protected or susp." + SEVERITY NOTE; + END IF; + END IF; + ELSIF (oe) THEN + IF (Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDSR2) THEN + --Read Status Register 2 + sr_read <= true; + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN + IF (sect_tmp_pg /= read_addr / 16#1000#) THEN + IF (Instruct = READ) THEN + fast_rd <= false; + dual_read <= false; + slow_read <= true; + quad_read <= false; + sr_read <= false; + ELSE + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + END IF; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct=FAST_DREAD OR + Instruct=FAST_DREAD_2) THEN + IF sect_tmp_pg /= (read_addr / 16#1000#) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + END if; + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD + OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD) + AND QE = '1') THEN + IF sect_tmp_pg /= (read_addr / 16#1000#) THEN + IF ((Instruct=W_QREAD AND + Address mod 2 /= 0) OR + (Instruct=WOCT_QREAD AND + Address mod 16 /= 0)) THEN + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + REPORT "Word Read - Wrong Read Address" + SEVERITY NOTE; + END IF; + ELSE + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + Addr_w := Address; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + IF (wrap_byte(4)= '0' AND + (Instruct=FAST_QREAD_4 OR + Instruct=W_QREAD)) THEN + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap, Addr_w,w_size); + IF (read_addr = AddrHi_wrap) THEN + read_addr := AddrLo_wrap; + ELSE + read_addr := read_addr + 1; + END IF; + ELSE + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR + Instruct=RDID_QUAD) THEN + IF (read_addr mod 2 = 0) THEN + ident_out2 := to_slv(Manuf_ID,8) & + to_slv(Device_ID1,8); + ELSE + ident_out2 := to_slv(Device_ID1,8)& + to_slv(Manuf_ID,8); + END IF; + read_id <= true; + IF (Instruct = RDID) THEN + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 16) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDID_DUAL) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-2*read_cnt); + SIOut_zd <= ident_out2(14-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSE -- (Instruct = RDID_QUAD) + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + HOLDNegOut_zd <= ident_out2(15-4*read_cnt); + WPNegOut_zd <= ident_out2(14-4*read_cnt); + SOut_zd <= ident_out2(13-4*read_cnt); + SIOut_zd <= ident_out2(12-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + -- unique ID number is not in data sheet + read_id <= true; + uniq_id := to_slv(Unique_id_2,32)& + to_slv(Unique_id_1,32); + SOut_zd <= uniq_id(63-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 64) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDIDJ) THEN + read_id <= true; + ident_out := to_slv(Manuf_ID,8) & + to_slv(Device_ID2,8) & to_slv(Device_ID3,8); + SOut_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 24) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RD_SFDP) THEN + IF (read_addr / 16#100# = 0) THEN + Addr_tmp_2 := (read_addr mod 16#100#); + data_out := to_slv(SFDP_array(Addr_tmp_2),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = SFDP_HiAddr) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "SFDP address is out of range" + SEVERITY NOTE; + END IF; + END IF; + ELSIF (Instruct = RD_SCREG) THEN + Addr_tmp_2 := read_addr / 16#100#; + Addr_tmp_3 := read_addr mod 16#100#; + IF (Addr_tmp_2 = 16) THEN + -- Security Register No.1 + data_out := to_slv(Security_Reg1(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 32) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg2(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 48) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg3(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Security Reg addr is out of range " + SEVERITY NOTE; + END if; + END IF; + + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr mod 256) = SecReg_HiAddr THEN + read_addr:=(read_addr/256)* + (SecReg_HiAddr+1); + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + END IF; + + WHEN SECTOR_ERS | PG_SUSP_ERS => + IF falling_edge(EDONE) THEN + IF (Instruct = SE) THEN + ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers); + ELSIF (Instruct = BE_32) THEN + ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers); + ELSIF (Instruct = BE_64) THEN + ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers); + END IF; + IF (Instruct /= ERS_SCREG) THEN + + FOR I IN AddrLo_ers TO AddrHi_ers LOOP + Mem(i) := -1; + END LOOP; + ELSE + IF (sect = 1) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg1(i) := -1; + END LOOP; + ELSIF (sect = 2) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg2(i) := -1; + END LOOP; + ELSE + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg3(i) := -1; + END LOOP; + END IF; + END IF; + END IF; + IF (EDONE = '1') THEN + IF (current_state /= PG_SUSP_ERS) THEN + BUSY := '0'; + END IF; + WEL := '0'; + IF (ers_screg_flag) THEN + IF (sect = 1) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg1(i) := MaxData; + END LOOP; + ELSIF (sect = 2) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg2(i) := MaxData; + END LOOP; + ELSE + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg3(i) := MaxData; + END LOOP; + END IF; + ELSE + FOR I IN AddrLo_ers TO AddrHi_ers LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + END IF; + + IF (Instruct = ERS_PG_SUSP AND current_state = SECTOR_ERS AND + SUSP_FL_IN = '0') THEN + ESUSP <= '1', '0' AFTER 1 ns; + ERSSUSP_in <= '1'; + END IF; + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + + WHEN BULK_ERS => + IF (current_state'event AND EDONE = '0') THEN + FOR I IN 0 TO AddrRANGE LOOP + Mem(i) := -1; + END LOOP; + END IF; + IF (EDONE = '1') THEN + BUSY := '0'; + WEL := '0'; + FOR I IN 0 TO AddrRANGE LOOP + Mem(i) := MaxData; + END LOOP; + + END IF; + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + + WHEN ERS_SUSP => + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + pg_screg_flag <= false; + BUSY := '0'; + IF (ERSSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN + ERSSUSP_in <= '0'; + --The BUSY bit in the Status Register will indicate that + --the device is ready for another operation. +-- BUSY := '0'; + --The SuspEND (SUS) bit in the Status Register2 will + --be set to the logical “1” state to indicate that the + --program operation has been suspENDed. + SUS := '1'; + END IF; + IF (ERSRES_out'event AND ERSRES_out = '1') THEN + ERSRES_in <= '0'; + BUSY := '1'; + END IF; + IF (SUS = '1') THEN + IF falling_edge(write) THEN + IF (Instruct = ERS_PG_RES) THEN + SUS := '0'; + ERSRES_in <= '1'; + SUSP_FL_IN <= '1'; + ERES <= '1', '0' AFTER 5 ns; + ELSIF ((Instruct = PP OR (Instruct=QPP AND QE='1')) + AND WEL ='1') THEN + sect := Address / 16#1000#; + IF (sect /= sect_tmp_ers AND + Sec_Prot(sect)='0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + Addr := Address; + Addr_tmp:= Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + BUSY := '0'; + REPORT "Can't program sector,protected or susp" + SEVERITY NOTE; + END IF; + ELSIF (Instruct = PG_SCREG) THEN + sect := Address / 16#1000#; + IF ((sect <= 3 AND sect >=1) AND + LB_bits(sect-1)='0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + wr_cnt := Byte_number; + Addr_screg := Address mod 16#1000#; + Addr_screg_tmp := Address mod 16#1000#; + pg_screg_flag <= true; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + END IF; + END IF; + ELSIF (oe) THEN + IF (Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDSR2) THEN + --Read Status Register 2 + sr_read <= true; + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN + IF sect /= (read_addr / 16#1000#) THEN + IF (Instruct = READ) THEN + fast_rd <= false; + dual_read <= false; + slow_read <= true; + quad_read <= false; + sr_read <= true; + ELSE + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + END IF; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = FAST_DREAD OR + Instruct = FAST_DREAD_2) THEN + IF sect_tmp_ers /= (read_addr / 16#1000#) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD + OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD) + AND QE = '1') THEN + IF sect_tmp_ers /= (read_addr / 16#1000#) THEN + IF ((Instruct=W_QREAD AND + Address mod 2 /= 0) OR + (Instruct=WOCT_QREAD AND + Address mod 16 /=0)) THEN + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + REPORT "Bad Word Read- Wrong Address" + SEVERITY NOTE; + END IF; + ELSE + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + data_out := to_slv(Mem(read_addr),8); + Addr_w := Address; + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + IF (wrap_byte(4)='0' AND + (Instruct=FAST_QREAD_4 + OR Instruct=W_QREAD)) THEN + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap,Addr_w,w_size); + IF (read_addr = AddrHi_wrap) THEN + read_addr := AddrLo_wrap; + ELSE + read_addr := read_addr + 1; + END IF; + ELSE + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR + Instruct=RDID_QUAD) THEN + IF (read_addr mod 2 = 0) THEN + ident_out2 := to_slv(Manuf_ID,8) & + to_slv(Device_ID1,8); + ELSE + ident_out2 := to_slv(Device_ID1,8) & + to_slv(Manuf_ID,8); + END IF; + read_id <= true; + IF (Instruct = RDID) THEN + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 16) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDID_DUAL) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-2*read_cnt); + SIOut_zd <= ident_out2(14-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSE -- (Instruct = RDID_QUAD) + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + HOLDNegOut_zd <= ident_out2(15-4*read_cnt); + WPNegOut_zd <= ident_out2(14-4*read_cnt); + SOut_zd <= ident_out2(13-4*read_cnt); + SIOut_zd <= ident_out2(12-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + -- unique ID number is not in data sheet + read_id <= true; + uniq_id := to_slv(Unique_id_2,32)& + to_slv(Unique_id_1,32); + SOut_zd <= uniq_id(63-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 64) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDIDJ) THEN + read_id <= true; + ident_out := to_slv(Manuf_ID,8) & + to_slv(Device_ID2,8) & to_slv(Device_ID3,8); + SOut_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 24) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RD_SFDP) THEN +-- sfdp_addr := read_addr / 16#100#; + IF (read_addr / 16#100# = 0) THEN + Addr_tmp_2 := (read_addr mod 16#100#); + data_out := to_slv(SFDP_array(Addr_tmp_2),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = SFDP_HiAddr) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Given SFDP address is out of range" + SEVERITY NOTE; + END IF; + END IF; + ELSIF (Instruct = RD_SCREG) THEN + Addr_tmp_2 := read_addr / 16#100#; + Addr_tmp_3 := read_addr mod 16#100#; + IF (Addr_tmp_2 = 16) THEN + -- Security Register No.1 + data_out :=to_slv(Security_Reg1(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 32) THEN + -- Security Register No.2 + data_out :=to_slv(Security_Reg2(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 48) THEN + -- Security Register No.2 + data_out :=to_slv(Security_Reg3(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; +-- END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Security Reg addr is out of range" + SEVERITY NOTE; + END IF; + END IF; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr mod 256 = SecReg_HiAddr) THEN + read_addr := (read_addr/256)* + (SecReg_HiAddr+1); + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + END IF; + + WHEN DP_DOWN => + IF (oe AND Instruct = RES_RD_ID) THEN + read_id <= true; + data_out := to_slv(Device_ID1,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + IF falling_edge(write) THEN + IF (Instruct = RES_RD_ID) THEN + IF res_flag = true THEN + RES2_in <= '1'; + ELSE + RES1_in <= '1'; + END IF; + ELSE + REPORT "Device is in DPD Mode No instructions allowed" + SEVERITY NOTE; + END IF; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + END PROCESS Functional; + + --------------------------------------------------------------------------- + -- SFDP Process + --------------------------------------------------------------------------- + SFDPPreload: PROCESS + + BEGIN + ----------------------------------------------------------------------- + --SFDP array data + ----------------------------------------------------------------------- + + SFDP_array(16#00#) := 16#53#; + SFDP_array(16#01#) := 16#46#; + SFDP_array(16#02#) := 16#44#; + SFDP_array(16#03#) := 16#50#; + SFDP_array(16#04#) := 16#01#; + SFDP_array(16#05#) := 16#01#; + SFDP_array(16#06#) := 16#00#; + SFDP_array(16#07#) := 16#FF#; + SFDP_array(16#08#) := 16#EF#; + SFDP_array(16#09#) := 16#00#; + SFDP_array(16#0A#) := 16#01#; + SFDP_array(16#0B#) := 16#04#; + SFDP_array(16#0C#) := 16#80#; + SFDP_array(16#0D#) := 16#00#; + SFDP_array(16#0E#) := 16#00#; + SFDP_array(16#0F#) := 16#FF#; + SFDP_array(16#10#) := 16#EF#; + SFDP_array(16#11#) := 16#00#; + SFDP_array(16#12#) := 16#01#; + SFDP_array(16#13#) := 16#00#; + SFDP_array(16#14#) := 16#90#; + SFDP_array(16#15#) := 16#00#; + SFDP_array(16#16#) := 16#00#; + SFDP_array(16#17#) := 16#FF#; + + FOR I IN 24 TO 127 LOOP + SFDP_array(i) := MaxData; + END LOOP; + + SFDP_array(16#80#) := 16#E5#; + SFDP_array(16#81#) := 16#20#; + SFDP_array(16#82#) := 16#F1#; + SFDP_array(16#83#) := 16#FF#; + SFDP_array(16#84#) := 16#FF#; + SFDP_array(16#85#) := 16#FF#; + SFDP_array(16#86#) := 16#FF#; + SFDP_array(16#87#) := 16#03#; + SFDP_array(16#88#) := 16#44#; + SFDP_array(16#89#) := 16#EB#; + SFDP_array(16#8A#) := 16#08#; + SFDP_array(16#8B#) := 16#6B#; + SFDP_array(16#8C#) := 16#08#; + SFDP_array(16#8D#) := 16#3B#; + SFDP_array(16#8E#) := 16#80#; + SFDP_array(16#8F#) := 16#BB#; + + FOR I IN 144 TO 255 LOOP + SFDP_array(i) := MaxData; + END LOOP; + + WAIT; + + END PROCESS SFDPPreload; + + --------------------------------------------------------------------------- + -- Sector Protection Bits + --------------------------------------------------------------------------- + Protect : PROCESS(change_prot_bits) + BEGIN + IF rising_edge(change_prot_bits) THEN + + CASE BP_bits IS + WHEN "000" => + IF (CMP = '0') THEN + Sec_Prot := (others => '0'); + ELSE + Sec_Prot := (others => '1'); + END IF; + WHEN "001" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(2047 downto 2016) := + (others => '1'); + Sec_Prot(2015 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(31 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 32) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2047) := '1'; + Sec_Prot(2046 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(0) := '1'; + Sec_Prot(2047 downto 1) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(2015 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 2016) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(2047 downto 32) := + (others => '1'); + Sec_Prot(31 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2046 downto 0) := + (others => '1'); + Sec_Prot(2047) := '0'; + + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(2047 downto 1) := + (others => '1'); + Sec_Prot(0) := '0'; + END IF; + END IF; + WHEN "010" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(2047 downto 1984) := + (others => '1'); + Sec_Prot(1983 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(63 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 64) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2047 downto 2046) := + (others => '1'); + Sec_Prot(2045 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(1 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 2) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(1983 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 1984) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(2047 downto 64) := + (others => '1'); + Sec_Prot(63 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2045 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 2046) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(2047 downto 2) := + (others => '1'); + Sec_Prot(1 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "011" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(2047 downto 1920) := + (others => '1'); + Sec_Prot(1919 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(127 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 128) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2047 downto 2044) := + (others => '1'); + Sec_Prot(2043 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(3 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 4) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(1919 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 1920) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(2047 downto 128) := + (others => '1'); + Sec_Prot(127 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2043 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 2044) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(2047 downto 4) := + (others => '1'); + Sec_Prot(3 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "100" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(2047 downto 1792) := + (others => '1'); + Sec_Prot(1791 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(255 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 256) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2047 downto 2040) := + (others => '1'); + Sec_Prot(2041 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(7 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 8) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(1791 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 1792) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(2047 downto 256) := + (others => '1'); + Sec_Prot(255 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2039 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 2040) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(2047 downto 8) := + (others => '1'); + Sec_Prot(7 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "101" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(2047 downto 1536) := + (others => '1'); + Sec_Prot(1535 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(511 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 512) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2047 downto 2040) := + (others => '1'); + Sec_Prot(2039 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(7 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 8) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(1535 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 1536) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(2047 downto 512) := + (others => '1'); + Sec_Prot(511 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(2039 downto 0) := + (others => '1'); + Sec_Prot(2047 downto 2040) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(2047 downto 8) := + (others => '1'); + Sec_Prot(7 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "110" => + IF (CMP = '0') THEN + IF (SEC = '0' AND TB = '0') THEN + Sec_Prot(2047 downto 1024) := (others => '1'); + Sec_Prot(1023 downto 0) := (others => '0'); + ELSIF (SEC = '0' AND TB = '1') THEN + Sec_Prot(1023 downto 0) := (others => '1'); + Sec_Prot(2047 downto 1024) := (others => '0'); + END IF; + ELSE + IF (SEC = '0' AND TB = '0') THEN + Sec_Prot(2047 downto 1024) := (others => '0'); + Sec_Prot(1023 downto 0) := (others => '1'); + ELSIF (SEC = '0' AND TB = '1') THEN + Sec_Prot(2047 downto 1024) := (others => '1'); + Sec_Prot(1023 downto 0) := (others => '0'); + END IF; + END IF; + + WHEN "111" => + IF (CMP = '0') THEN + Sec_Prot(2047 downto 0) := (others => '1'); + ELSE + Sec_Prot(2047 downto 0) := (others => '0'); + END IF; + WHEN OTHERS => + Sec_Prot := (OTHERS => '1'); + END CASE; -- end of CASE BP_bits + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNegIn) + BEGIN + IF (HOLDNegIn = '0' AND QE /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QE = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QE = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + + MemPreload: PROCESS + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE screg_file : text is screg_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE:= 0; + VARIABLE screg_ind: NATURAL RANGE 16#00# TO 16#2FF#:= 16#00#; + VARIABLE buf : line; + + BEGIN + -- memory preload + IF (mem_file_name (1 to 4)/= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 7)); --address + ELSE + IF ind <= AddrRANGE THEN + Mem(ind) := h(buf(1 to 2)); + END IF; + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + ----------------------------------------------------------------------- + -- Security Register Preload + ----------------------------------------------------------------------- + + IF (screg_file_name(1 to 4) /= "none" AND UserPreload) THEN + ind := 0; + Security_Reg1 := (OTHERS => MaxData); + Security_Reg2 := (OTHERS => MaxData); + Security_Reg3 := (OTHERS => MaxData); + WHILE (not ENDFILE (screg_file)) LOOP + READLINE (screg_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + screg_ind := h(buf(2 to 4)); --address + ELSE + IF screg_ind <= 16#0FF# THEN + Security_Reg1(screg_ind) := h(buf(1 to 2)); + ELSIF screg_ind>=16#100# AND screg_ind<=16#1FF# THEN + Security_Reg2(screg_ind-16#100#) := h(buf(1 to 2)); + ELSIF screg_ind>=16#200# AND screg_ind<=16#2FF# THEN + Security_Reg3(screg_ind-16#200#) := h(buf(1 to 2)); + END IF; + IF (screg_ind mod 16#100#) < 16#FF# THEN + screg_ind := screg_ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + WAIT; + END PROCESS MemPreload; + + --------------------------------------------------------------------------- + -- Path Delay Section + --------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "SO", + OutTemp => SOut_z, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => SOut_z /= 'Z' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => SOut_z /= 'Z' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => QE = '0') + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => SIOut_z /= 'Z' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => SIOut_z /= 'Z' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND SIOut_zd = 'Z'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => SIOut_z /= 'Z' AND QE = '0') + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => HOLDNegOut_zd /= 'Z' --AND quad_read + AND QE = '1' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => HOLDNegOut_zd /= 'Z' --AND quad_read + AND QE = '1' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND --quad_read AND + HOLDNegOut_zd = 'Z' AND QE = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => WPNegOut_zd /= 'Z' --AND quad_read + AND QE = '1' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => WPNegOut_zd /= 'Z' -- AND quad_read + AND QE = '1' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND --quad_read AND + WPNegOut_zd = 'Z' AND QE = '1') + ) + ); + END PROCESS; + + END BLOCK behavior; +END vhdl_behavioral; \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_ver.ftm b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_ver.ftm new file mode 100644 index 0000000..8f3facd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_ver.ftm @@ -0,0 +1,61 @@ + +FMF Timing for s25fl064k Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 10 Aug 25 Initial release + +1ns +s25fl064k + +S25FL064KOSMFI000 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI001 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI003 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI010 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI011 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI013 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +The values listed are for VCC=2.7V to 3.6V, +Industrial Ta=-40 to +85 Celsius + +(DELAY(ABSOLUTE + (COND ~read_id (IOPATH SCK SO (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND read_id (IOPATH SCK SO (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (COND CSNeg (IOPATH CSNeg SO () () (5:6:7) () (5:6:7) ())) + (COND ~quad_read (IOPATH HOLDNeg SO () () (8:10:12) (5:6:7) (8:10:12) (5:6:7))) + (COND dual_read || quad_read (IOPATH SCK SI (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND CSNeg && ~deg_sin (IOPATH CSNeg SI () () (5:6:7) () (5:6:7) ())) + (COND ~quad_read && dual_read (IOPATH HOLDNeg SI () () (8:10:12) (5:6:7) (8:10:12) (5:6:7))) + (COND quad_read (IOPATH SCK WPNeg (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND quad_read (IOPATH SCK HOLDNeg (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND CSNeg && QE (IOPATH CSNeg SI () () (5:6:7) () (5:6:7) ())) + (COND CSNeg && QE (IOPATH CSNeg WPNeg () () (5:6:7) () (5:6:7) ())) + (COND CSNeg && QE (IOPATH CSNeg HOLDNeg () () (5:6:7) () (5:6:7) ())) +)) +(TIMINGCHECK + (SETUP CSNeg (posedge SCK) (5)) + (SETUP SI (COND deg_sin(posedge SCK)) (2)) + (SETUP SO (COND quad_pg(posedge SCK)) (2)) + (SETUP WPNeg (COND quad_pg(posedge SCK)) (2)) + (SETUP HOLDNeg (COND quad_pg(posedge SCK)) (2)) + (SETUP HOLDNeg (COND hold_cond(posedge SCK)) (5)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (5)) + (HOLD SI (COND deg_sin (posedge SCK)) (5)) + (HOLD SO (COND quad_pg (posedge SCK)) (5)) + (HOLD WPNeg (COND quad_pg (posedge SCK)) (5)) + (HOLD HOLDNeg (COND quad_pg (posedge SCK)) (5)) + (HOLD HOLDNeg (COND hold_cond(posedge SCK)) (5)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + + (WIDTH (COND rd_slow (posedge SCK)) (15.2)) + (WIDTH (COND rd_slow (negedge SCK)) (15.2)) + (WIDTH (COND rd_fast (posedge SCK)) (6.25)) + (WIDTH (COND rd_fast (negedge SCK)) (6.25)) + (WIDTH (COND any_read (posedge CSNeg)) (10)) + (WIDTH (COND pg_ers (posedge CSNeg)) (50)) + (PERIOD (COND rd_slow SCK) (30.4)) + (PERIOD (COND rd_fast SCK) (12.5)) +) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_vhd.ftm b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_vhd.ftm new file mode 100644 index 0000000..e6be6b6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k_vhd.ftm @@ -0,0 +1,81 @@ + +FMF Timing for s25fl064k Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 10 Sep 11 Initial release + +1ns +s25fl064k + +S25FL064KOSMFI000 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI001 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI003 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI010 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI011 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +S25FL064KOSMFI013 Spansion, S25FL064K, Rev. 01,JUN.29,2010 +The values listed are for VCC=2.7V to 3.6V, +Industrial Ta=-40 to +85 Celsius + +(DELAY(ABSOLUTE + (COND RDID == 0 (IOPATH SCK SO (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND RDID == 1 (IOPATH SCK SO (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (IOPATH CSNeg SO () () (5:6:7) () (5:6:7) ()) + (IOPATH HOLDNeg SO () () (8:10:12) (5:6:7) (8:10:12) (5:6:7)) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (5)) + (SETUP (COND normal SI) (posedge SCK) (2)) + (SETUP HOLDNeg SCK (5)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (5)) + (HOLD (COND normal SI) (posedge SCK) (5)) + (HOLD HOLDNeg SCK (5)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND slow (posedge SCK)) (15.2)) + (WIDTH (COND slow (negedge SCK)) (15.2)) + (WIDTH (COND fast (posedge SCK)) (6.25)) + (WIDTH (COND fast (negedge SCK)) (6.25)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pger (posedge CSNeg)) (50)) + (PERIOD (COND slow SCK) (30.4)) + (PERIOD (COND fast SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(400000:700000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP1) (DELAY (ABSOLUTE (DEVICE(15000:30000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP2) (DELAY (ABSOLUTE (DEVICE(1000:2500:12000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(10000000:30000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE1) (DELAY (ABSOLUTE (DEVICE(5e7:12e7:8e8) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE2) (DELAY (ABSOLUTE (DEVICE(5e7:15e7:1e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/CE) (DELAY (ABSOLUTE (DEVICE(5e9:15e9:30e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(3000:3000:3000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES1) (DELAY (ABSOLUTE (DEVICE(3000:3000:3000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES2) (DELAY (ABSOLUTE (DEVICE(1800:1800:1800) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGRES) (DELAY (ABSOLUTE (DEVICE(200:200:200) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSRES) (DELAY (ABSOLUTE (DEVICE(200:200:200) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(15000000:15000000:15000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SUSP_DLY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl064k/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl064k/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl064k/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/flash/serial/S25fl064p/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl064p/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl064p/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl064p/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 vital-amd-REL-s25fl064p-2008-01-22-1.tar.gz +# Release Date (DD/MM/YYYY) => 22/01/2008 +# Release Version => 1.0 + +########################################## +RELEASE 1.1 + +# Release Label => vital-amd-REL-s25fl064p-2008-02-20-2.tar.gz +# Release Date (DD/MM/YYYY) => 20/02/2008 +# Release Version => 1.1 + +# Bugs fixed (from previous release) +- Quad functionality issue + +# Files modified (from previous release) +- s25fl064p.vhd +- s25fl064p.v +- testbench_s25fl064p_vhdl.vhd +- testbench_s25fl064p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +########################################## +Publication ID - SPANSION, S25FL064 032P DRS Rev.19, 2008 + +VITAL model author - Dragisa Stanojkovic + d-stanojkovic@hdl-dh.com +########################################## +########################################## +RELEASE 1.2 + +# Release Label => vital-amd-REL-s25fl064p-2008-03-05-1.tar.gz +# Release Date (DD/MM/YYYY) => 05/03/2008 +# Release Version => 1.2 + +# Bugs fixed (from previous release) +- MPM mode for Dual/Quad High Performance changed + +# Files modified (from previous release) +- s25fl064p.ftm +- s25fl064p.ftmv +- s25fl064p_vhdl.sdf +- s25fl064p_verilog.sdf +- s25fl064p.vhd +- s25fl064p.v +- testbench_s25fl064p_vhdl.vhd +- testbench_s25fl064p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +########################################## +RELEASE 1.3 + +# Release Label => vital-amd-REL-s25fl064p-2008-03-20-1.tar.gz +# Release Date (DD/MM/YYYY) => 20/03/2008 +# Release Version => 1.3 + +# Bugs fixed (from previous release) +- MPM mode removed + +# Files modified (from previous release) +- s25fl064p.vhd +- s25fl064p.v +- testbench_s25fl064p_vhdl.vhd +- testbench_s25fl064p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +########################################## + +VITAL model author - Jadranka Stoickov + j-stoickov@hdl-dh.com +########################################## +########################################## +RELEASE 1.4 + +# Release Label => vital-amd-REL-s25fl064p-2008-08-07-1.tar.gz +# Release Date (DD/MM/YYYY) => 07/08/2008 +# Release Version => 1.4 + +# Bugs fixed (from previous release) +- WEL bit fixed + +# Files modified (from previous release) +- s25fl064p.v +- model_release_history.txt +########################################## +########################################## +Publication ID - SPANSION, S25FL129_064_032P_DRS Rev.23.2, Oct 13, 2008 + +VITAL model author - Jadranka Stoickov + j-stoickov@hdl-dh.com +########################################## +########################################## +RELEASE 1.5 + +# Release Label => vital-amd-REL-s25fl064p-2008-15-10-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/12/2008 +# Release Version => 1.5 + +# Changes made (from previous release) +- alignment to new datasheet + +# Files modified (from previous release) +- s25fl064p.ftm +- s25fl064p.ftmv +- s25fl064p_vhdl.sdf +- s25fl064p_verilog.sdf +- s25fl064p.vhd +- s25fl064p.v +- testbench_s25fl064p_vhdl.vhd +- testbench_s25fl064p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +########################################## +RELEASE 1.6 + +# Release Label => vital-amd-REL-s25fl064p-2009-05-29-1.tar.gz +# Release Date (DD/MM/YYYY) => 29/05/2009 +# Release Version => 1.6 + +# Changes made (from previous release) +- Timing ranges in timing files corrected + +# Files modified (from previous release) +- s25fl064p.ftm +- s25fl064p.ftmv +- s25fl064p_vhdl.sdf +- s25fl064p_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +########################################## +RELEASE 1.7 + +# Release Label => vital-amd-REL-s25fl064p-2010-09-29-1.tar.gz +# Release Date (DD/MM/YYYY) => 29/09/2010 +# Release Version => 1.7 + +# Changes made (from previous release) +# 1. During the QUAD mode HOLD# input is not monitored for its normal function +# 2. Internal pull-up resistors for HOLD# and WP# inputs are implemented + +# Files modified (from previous release) +- s25fl064p.vhd +- s25fl064p.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +########################################## +RELEASE 1.8 + +# Release Label => vital-amd-REL-s25fl064p-2012-01-13-1.tar.gz +# Release Date (DD/MM/YYYY) => 13/01/2012 +# Release Version => 1.8 + +# Changes made (from previous release) +- alignment to new datasheet (S25FL064P_00_05, November 18, 2011) + +# Files modified (from previous release) +- s25fl064p.ftm +- s25fl064p.ftmv +- s25fl064p_vhdl.sdf +- s25fl064p_verilog.sdf +- s25fl064p.vhd +- s25fl064p.v +- testbench_s25fl064p_vhdl.vhd +- testbench_s25fl064p_verilog.vhd +- spansion_tc_pkg.vhd +- spansion_flash_testbench_struct.pdf +- spansion_flash_test_cases_list.pdf +- model_release_history.txt +########################################## \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.v b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.v new file mode 100644 index 0000000..ec40177 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.v @@ -0,0 +1,2603 @@ +////////////////////////////////////////////////////////////////////////////// +// File name : s25fl064p.v +////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 D.Stanojkovic 08 Jan 22 Inital Release +// V1.1 D.Stanojkovic 08 Feb 20 BP bits setting corrected +// V1.2 D.Stanojkovic 08 Mar 04 MPM mode corrected +// V1.3 D.Stanojkovic 08 Mar 20 MPM mode removed +// v1.4 J.Stoickov 08 Aug 07 WEL bit corrected +// V1.5 J.Stoickov 08 Dec 10 Latest datasheet aligned +// (S25FL129 064 032P) +// Program Error bit will not be +// set after programming in +// protect memory region +// V1.6 V.Mancev 10 Sep 29 Implementation of internal pull-up +// for HOLDNeg and WPNeg pins +// V1.7 V.Mancev 12 Jan 13 Latest datasheet aligned +// (S25FL064P_00_05) +////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL064P +// +// Description:64 Megabit Serial Flash Memory with 104 MHz SPI Bus Interface +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps +module s25fl064p +( + SCK , + SI , + + CSNeg , + HOLDNeg , + WPNeg , + SO +); +//////////////////////////////////////////////////////////////////////// +// Port / Part SOIn Declarations +//////////////////////////////////////////////////////////////////////// + input SCK ; + inout SI ; + + input CSNeg ; + inout HOLDNeg ; + inout WPNeg ; + inout SO ; + +// interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire SO_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire SOIn ; + assign SOIn = SO_ipd ; + + wire SOut ; + assign SOut = SO ; + +// internal delays + reg PP_in ; + reg PP_out ; + reg PU_in ; + reg PU_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg PE_in ; + reg PE_out ; + reg WR_in ; + reg WR_out ; + reg DP_in ; + reg DP_out ; + reg EP_in ; + reg EP_out ; + reg RES_in ; + reg RES_out ; + + reg SOut_zd = 1'bZ; + reg SOut_z = 1'bZ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl064p.mem"; + parameter otp_file_name = "none";//"s25fl064p_secsi.mem"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl064p"; + parameter MaxData = 255; + parameter SecSize = 16'hFFFF; + parameter SecSize_4 = 4095; + parameter SecSize_8 = 8191; + parameter SecNum = 127; + parameter PageNum = 16'h7FFF; + parameter OTPSize = 511; + parameter OTPLoAddr = 9'h100; + parameter OTPHiAddr = 10'h2FF; + parameter HiAddrBit = 23; + parameter AddrRANGE = 24'h7FFFFF; + parameter BYTE = 8; + parameter Manuf_ID = 8'h01; + parameter ES = 8'h16; + parameter Jedec_ID = 8'h20; // first byte of Device ID + parameter DeviceID = 16'h0216; + parameter ExtendedBytes = 8'h4D; + parameter ReservedBytes = 8'h00; + + // If speed simulation is needed uncomment following line + + //`define SPEEDSIM; + + // powerup + reg PoweredUp; + + //FSM control signals + reg PDONE ; ////Prog. Done + reg PSTART ; ////Start Programming + + reg EDONE ; ////Era. Done + reg ESTART ; ////Start Erasing + + reg WDONE ; //// Writing Done + reg WSTART ; ////Start writing + + //Command Register + reg write; + reg cfg_write; + reg read_out; + + //Status reg. + reg[7:0] Status_reg = 8'b0; + reg[7:0] Status_reg_in = 8'b0; + reg[7:0] Sec_conf_reg = 8'b0; + reg[7:0] Sec_conf_reg_in = 8'b0; + + wire FREEZE; + wire QUAD; + wire TBPARM; + wire BPNV; + wire TBPROT; + assign FREEZE = Sec_conf_reg[0]; + assign QUAD = Sec_conf_reg[1]; + assign TBPARM = Sec_conf_reg[2]; + assign BPNV = Sec_conf_reg[3]; + assign TBPROT = Sec_conf_reg[5]; + + wire WIP; + wire WEL; + wire [2:0]BP; + wire E_ERR; + wire P_ERR; + wire SRWD; + assign WIP = Status_reg[0]; + assign WEL = Status_reg[1]; + assign BP = Status_reg[4:2]; + assign E_ERR = Status_reg[5]; + assign P_ERR = Status_reg[6]; + assign SRWD = Status_reg[7]; + + integer SA = 0; // 0 TO SecNum+1 + integer Byte_number = 0; + integer sect; + + //Address + integer Address = 0; // 0 - AddrRANGE + reg change_addr; + reg rd_fast; // = 1'b1; + reg rd_slow; + reg rd_jedec; + reg change_BP = 0; + reg rd_dual; + reg dual; + wire fast_rd; + wire rd; + wire rd_jid; + + wire RD_EQU_1; + assign RD_EQU_1 = rd_slow; + + wire RD_EQU_0; + assign RD_EQU_0 = ~rd_slow; + + reg hold_mode; + reg mpm_mode = 0; + reg initial_config = 0; + wire hold; + + //Sector Protection Status + reg [SecNum:0] Sec_Prot = 127'b0; //= SecNum'b0; + + // timing check violation + reg Viol = 1'b0; + + integer Mem[0:AddrRANGE]; + integer OTPMem[OTPLoAddr: OTPHiAddr]; + + integer WByte[0:255]; + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer read_addr = 0; + reg[7:0] data_out; + reg[647:0] ident_out; + + reg oe = 1'b0; + event oe_event; + + integer CFI_array[8'h07:8'h50]; + reg [591:0] CFI_array_tmp; + reg [7:0] CFI_tmp; + + reg[15:0] PR_LOCK1; + reg[15:0] PR_LOCK2; + reg[15:0] PR_LOCK3; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (SO_ipd, SO); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SO, SO_z , 1); + + nmos (SI, SI_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + //VHDL VITAL CheckEnable equivalents + wire dual_wr; + assign dual_wr = deg_holdin && QUAD; + wire quad_wr; + assign quad_wr = SRWD && WEL ; + wire dual_rd; + assign dual_rd = dual; + wire power; + assign power = PoweredUp; + + specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO =1; + specparam tpd_SCK_SI =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + + specparam tsetup_SI_SCK =1; //tsuDAT / + specparam tsetup_CSNeg_SCK =1; // tCSS / + specparam tsetup_HOLDNeg_SCK =1; //tHD / + specparam tsetup_SCK_HOLDNeg =1; //tCH \ + specparam tsetup_WPNeg_CSNeg =1; //tWPS \ + + // thold values: hold times + specparam thold_SI_SCK =1; //thdDAT / + specparam thold_CSNeg_SCK =1; //tCSH / + specparam thold_HOLDNeg_SCK =1; //tCHHH / + specparam thold_SCK_HOLDNeg =1; //tHC \ + specparam thold_WPNeg_CSNeg =1; //tWPH \ + + // tpw values: pulse width + specparam tpw_SCK_fast_posedge =1; //tWH + specparam tpw_SCK_posedge =1; //tWH + specparam tpw_SCK_dual_posedge =1; //tWH + specparam tpw_SCK_rdid_posedge =1; //tWH + specparam tpw_SCK_fast_negedge =1; //tWL + specparam tpw_SCK_negedge =1; //tWL + specparam tpw_SCK_dual_negedge =1; //tWL + specparam tpw_SCK_rdid_negedge =1; //tWL + specparam tpw_CSNeg_read_posedge =1; //tCS + specparam tpw_CSNeg_pgm_posedge =1; //tCS + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_rd =1; // fSCK = 40MHz + specparam tperiod_SCK_fast_rd =1; // fSCK = 104MHz + specparam tperiod_SCK_dual_fast_rd =1; // fSCK = 80MHz + specparam tperiod_SCK_rdid =1; // fSCK = 50MHz + + // tdevice values: values for internal delays + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP = 3e7; //30 us; + //Page Program Operation (ACC=9V)) + specparam tdevice_EP = 2.4e9; //2.4 ms; + //Sector Erase Operation + specparam tdevice_SE = 2e9; //2 ms; + //Bulk Erase Operation + specparam tdevice_BE = 128e9; //128 ms; + //Write Status Register Operation + specparam tdevice_WR = 1e9; // 1 ms; + //Software Protect Mode + specparam tdevice_DP = 10000000; // 10 us; + //Release from Software Protect Mode + specparam tdevice_RES = 30000000; // 30 us; + //Parameter block erase + specparam tdevice_PE = 800e6; //800 us; + //VCC (min) to CS# Low + specparam tdevice_PU = 300000000; //300 us; + `else + // Page Program Operation + specparam tdevice_PP = 3e9; //3 ms; + //Page Program Operation (ACC=9V)) + specparam tdevice_EP = 2.4e9; //2.4 ms; + //Sector Erase Operation + specparam tdevice_SE = 2e12; //2 s; + //Bulk Erase Operation + specparam tdevice_BE = 128e12; //128 sec; + //Write Status Register Operation + specparam tdevice_WR = 100e9; // 100 ms; + //Software Protect Mode + specparam tdevice_DP = 10000000; // 10 us; + //Release from Software Protect Mode + specparam tdevice_RES = 30000000; // 30 us; + //Parameter block erase + specparam tdevice_PE = 800e9; //800 ms; + //VCC (min) to CS# Low + specparam tdevice_PU = 300000000; //300 us; + `endif//SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~dual) (SCK => SO) = tpd_SCK_SO; + if (dual) (SCK => SO) = tpd_SCK_SI; + if (CSNeg)(CSNeg => SO) = tpd_CSNeg_SO; + if (~dual) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (dual) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + + if (dual)(SCK => SI) = tpd_SCK_SI; + if (dual && CSNeg)(CSNeg => SI) = tpd_CSNeg_SO; + if (dual)(HOLDNeg => SI) = tpd_HOLDNeg_SO; + + if (dual && QUAD)(SCK => HOLDNeg) = tpd_SCK_SI; + if (dual && CSNeg && QUAD)(CSNeg => HOLDNeg) = tpd_CSNeg_SO; + + if (dual && QUAD)(SCK => WPNeg) = tpd_SCK_SI; + if (dual && CSNeg && QUAD)(CSNeg => WPNeg) = tpd_CSNeg_SO; +//////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +//////////////////////////////////////////////////////////////////////////////// + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK, Viol); + $setup ( negedge HOLDNeg, posedge SCK &&& dual_wr, + tsetup_HOLDNeg_SCK, Viol); + $setup ( posedge SCK , posedge HOLDNeg &&& dual_wr, + tsetup_SCK_HOLDNeg, Viol); + $setup ( CSNeg , posedge SCK &&& power, + tsetup_CSNeg_SCK, Viol); + $setup ( WPNeg , negedge CSNeg &&& WPNeg, + tsetup_WPNeg_CSNeg, Viol); + + $hold ( posedge SCK , SI &&& deg_sin, + thold_SI_SCK, Viol); + $hold ( posedge HOLDNeg , posedge SCK &&& dual_wr, + thold_SCK_HOLDNeg, Viol); + $hold ( posedge SCK , CSNeg &&& power, + thold_CSNeg_SCK, Viol); + $hold ( posedge CSNeg , WPNeg &&& quad_wr, + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK , negedge HOLDNeg &&& dual_wr, + thold_HOLDNeg_SCK, Viol); + + $width (posedge SCK &&& rd , tpw_SCK_posedge); + $width (posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width (posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width (posedge SCK &&& rd_jid , tpw_SCK_rdid_posedge); + $width (negedge SCK &&& rd , tpw_SCK_negedge); + $width (negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width (negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width (negedge SCK &&& rd_jid , tpw_SCK_rdid_negedge); + + $width (posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgm_posedge); + $width (posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + + $period (posedge SCK &&& rd, tperiod_SCK_rd); + $period (posedge SCK &&& fast_rd, tperiod_SCK_fast_rd); + $period (posedge SCK &&& dual_rd, tperiod_SCK_dual_fast_rd); + $period (posedge SCK &&& rd_jid, tperiod_SCK_rdid); + + endspecify + +//////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +//////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE =4'd0; + parameter WRITE_SR =4'd1; + parameter DP_DOWN_WAIT =4'd2; + parameter DP_DOWN =4'd3; + parameter SECTOR_ER =4'd4; + parameter BULK_ER =4'd5; + parameter PAGE_PG =4'd6; + parameter OTP_PG =4'd7; + parameter P4_ER =4'd8; + parameter P8_ER =4'd9; + + reg [3:0] current_state; + reg [3:0] next_state; + +// Instructions + parameter NONE =5'd0; + parameter WREN =5'd1; + parameter WRDI =5'd2; + parameter WRR =5'd3; + parameter RDSR =5'd4; + parameter READ =5'd5; + parameter READ_ID =5'd6; + parameter RDID =5'd7; + parameter FAST_READ =5'd8; + parameter DUAL_READ =5'd9; + parameter QUAD_READ =5'd10; + parameter DH_READ =5'd11; + parameter QH_READ =5'd12; + parameter SE =5'd13; + parameter BE =5'd14; + parameter PP =5'd15; + parameter QPP =5'd16; + parameter DP =5'd17; + parameter RES_READ_ES =5'd18; + parameter CLSR =5'd19; + parameter RCR =5'd20; + parameter P4E =5'd21; + parameter P8E =5'd22; + parameter OTPP =5'd23; + parameter OTPR =5'd24; + reg [4:0] Instruct; + +//Bus cycle states + parameter STAND_BY =3'd0; + parameter CODE_BYTE =3'd1; + parameter ADDRESS_BYTES =3'd2; + parameter DUMMY_BYTES =3'd3; + parameter MODE_BYTE =3'd4; + parameter DATA_BYTES =3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SOIn, SO_z) + begin + if (SOIn==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // chech when data is generated from model to avoid setuphold check in + // those occasion + assign deg_pin=deq_pin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // chech when data is generated from model to avoid setuphold check in + // those occasion + assign deg_sin=deq_sin; + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + initial + begin : Init + + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + + PDONE = 1'b1; + PSTART = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + DP_in = 1'b0; + DP_out = 1'b0; + RES_in = 1'b0; + RES_out = 1'b0; + Instruct = NONE; + + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + + CFI_array[8'h07] = 8'hFF; + CFI_array[8'h08] = 8'hFF; + CFI_array[8'h09] = 8'hFF; + CFI_array[8'h0A] = 8'hFF; + CFI_array[8'h0B] = 8'hFF; + CFI_array[8'h0C] = 8'hFF; + CFI_array[8'h0D] = 8'hFF; + CFI_array[8'h0E] = 8'hFF; + CFI_array[8'h0F] = 8'hFF; + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h00; + CFI_array[8'h18] = 8'h00; + CFI_array[8'h19] = 8'h00; + CFI_array[8'h1A] = 8'h00; + //System interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h0B; + CFI_array[8'h20] = 8'h0B; + CFI_array[8'h21] = 8'h09; + CFI_array[8'h22] = 8'h10; + CFI_array[8'h23] = 8'h01; + CFI_array[8'h24] = 8'h01; + CFI_array[8'h25] = 8'h02; + CFI_array[8'h26] = 8'h01; + //device geometry definition + CFI_array[8'h27] = 8'h17; + CFI_array[8'h28] = 8'h05; + CFI_array[8'h29] = 8'h05; + CFI_array[8'h2A] = 8'h08; + CFI_array[8'h2B] = 8'h00; + CFI_array[8'h2C] = 8'h02; + CFI_array[8'h2D] = 8'h1F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h10; + CFI_array[8'h30] = 8'h00; + CFI_array[8'h31] = 8'h7D; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h00; + CFI_array[8'h34] = 8'h01; + CFI_array[8'h35] = 8'h00; + CFI_array[8'h36] = 8'h00; + CFI_array[8'h37] = 8'h00; + CFI_array[8'h38] = 8'h00; + CFI_array[8'h39] = 8'h00; + CFI_array[8'h3A] = 8'h00; + CFI_array[8'h3B] = 8'h00; + CFI_array[8'h3C] = 8'h00; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + //primary vendor-specific extended query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h15; + CFI_array[8'h46] = 8'h00; + CFI_array[8'h47] = 8'h02; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h05; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h03; + CFI_array[8'h4D] = 8'h85; + CFI_array[8'h4E] = 8'h95; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h00; + + for(i=73;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h07-i+73]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + + // initialize memory + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl064p.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl064p_secsi memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at SecSi(aaaaaa++) + // (aa is incremented at every load) + // only first 1-5 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + PR_LOCK1[15:8] = 16'h0; + PR_LOCK1[7:0] = OTPMem[256]; + + PR_LOCK2[15:8] = OTPMem[275]; + PR_LOCK2[7:0] = OTPMem[274]; + + PR_LOCK3[15:8] = OTPMem[533]; + PR_LOCK3[7:0] = OTPMem[532]; + end + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + always @(posedge DP_in) + begin:TDPr + #tdevice_DP DP_out = DP_in; + end + always @(negedge DP_in) + begin:TDPf + #1 DP_out = DP_in; + end + + always @(posedge RES_in) + begin:TRESr + #tdevice_RES RES_out = RES_in; + end + always @(negedge RES_in) + begin:TRESf + #1 RES_out = RES_in; + end + + always @(next_state or PoweredUp) + begin: StateTransition + if (PoweredUp) + begin + current_state = next_state; + end + end + + always @(negedge CSNeg_ipd) + begin:CheckCSOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + +// /////////////////////////////////////////////////////////////////////////// +// // Instruction cycle decode +// /////////////////////////////////////////////////////////////////////////// + integer data_cnt = 0; + integer addr_cnt = 0; + integer code_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer bit_cnt = 0; + + reg[2047:0] Data_in = 2048'b0; + integer quad_data_in [0:511]; + reg[3:0] quad_nybble = 4'b0; + reg[3:0] Quad_slv = 4'b0; + reg[7:0] code = 8'b0; + reg[7:0] code_in = 8'b0; + reg[7:0] Byte_slv = 8'b0; + reg[HiAddrBit:0] addr_bytes; + reg[23:0] Address_in = 8'b0; + reg[7:0] mode_bytes; + reg[7:0] mode_in; + + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + always @(falling_edge_CSNeg_ipd or rising_edge_CSNeg_ipd + or rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle1 + integer i; + integer j; + integer k; + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + bus_cycle_state = CODE_BYTE; + Instruct = NONE; + write = 1'b1; + code_cnt = 0; + addr_cnt = 0; + data_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + end + end + + if (rising_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + CODE_BYTE : + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + code_in[code_cnt] = SI_in; + code_cnt = code_cnt + 1; + if (code_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + code[i] = code_in[7-i]; + end + case(code) + 8'b00000110 : + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000101 : + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00001011 : + begin + Instruct = FAST_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : + begin + Instruct = READ_ID; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10101011 : + begin + Instruct = RES_READ_ES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b11011000 : + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11000111 , 8'b01100000: + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b00000010 : + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010 : + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10111001 : + begin + Instruct = DP; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : + begin + Instruct = RCR; + bus_cycle_state = DATA_BYTES; + end + 8'b00100000 : + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000000 : + begin + Instruct = P8E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000010 : + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00111011 : + begin + Instruct = DUAL_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01101011 : + begin + Instruct = QUAD_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10111011 : + begin + Instruct = DH_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11101011 : + begin + Instruct = QH_READ; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + end + + ADDRESS_BYTES : + begin + if (((Instruct == FAST_READ || Instruct == OTPR || + Instruct == DUAL_READ) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QUAD_READ) && QUAD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct == DH_READ && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (SOIn !== 1'b0 && SOIn !== 1'b1) + begin + mpm_mode = 0; + bus_cycle_state = STAND_BY; + end + else + begin + Address_in[2*addr_cnt] = SOIn; + Address_in[2*addr_cnt+1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 12) + begin + addr_cnt = 0; + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + else if (Instruct == QH_READ) + begin + if(QUAD) + begin + if (SOIn !== 1'b0 && SOIn !== 1'b1) + begin + mpm_mode = 0; + bus_cycle_state = STAND_BY; + end + else + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SOIn; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 6) + begin + addr_cnt = 0; + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + else + begin + bus_cycle_state = STAND_BY; + end + end + else if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + + MODE_BYTE : + begin + if((Instruct == DH_READ) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SOIn; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for (i=7;i>=7-BYTE;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DATA_BYTES; + end + end + else if((Instruct == QH_READ) && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SOIn; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for (i=7;i>=7-BYTE;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + if(QUAD && (Instruct == QUAD_READ || + Instruct == QH_READ)) + begin + dummy_cnt = dummy_cnt + 1; + if ((dummy_cnt == BYTE) && Instruct == QUAD_READ) + bus_cycle_state = DATA_BYTES; + else if ((dummy_cnt == BYTE/2) && + Instruct == QH_READ) + bus_cycle_state = DATA_BYTES; + end + else if((HOLDNeg_in && ~QUAD) || QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE && (Instruct == FAST_READ || + Instruct == OTPR || Instruct == DUAL_READ)) + bus_cycle_state = DATA_BYTES; + else if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + end + + DATA_BYTES : + begin + if(QUAD && Instruct == QPP) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SOIn, SI_in}; + if (data_cnt > 511) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for (i=0;i<=510;i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[511] = quad_nybble; + data_cnt = data_cnt + 1; + end + else + begin + if( quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt + 1; + end + end + else if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 2047) + //In case of serial mode and PP, if more than 256 + //bytes are sent to the device + begin + if (bit_cnt == 0) + begin + for (i=0;i<=(255*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[2040 + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + if (falling_edge_SCK_ipd) + begin + if ((bus_cycle_state == DATA_BYTES) && (~CSNeg_ipd)) + begin + if (((Instruct == READ || Instruct == FAST_READ || + Instruct == DUAL_READ || Instruct == DH_READ || + Instruct == RES_READ_ES || Instruct == RDID || + Instruct == RDSR || Instruct == READ_ID || + Instruct == RCR || Instruct == OTPR) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QUAD_READ || Instruct == QH_READ) && QUAD)) + begin + read_out = 1'b1; + #1 read_out = 1'b0; + end + end + end + if (rising_edge_CSNeg_ipd) + begin + if ((bus_cycle_state != DATA_BYTES) && + (bus_cycle_state != DUMMY_BYTES)) + bus_cycle_state = STAND_BY; + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (mpm_mode && (mode_bytes[7:4] == 4'b1010) && + (Instruct == DH_READ || Instruct == QH_READ)) + bus_cycle_state = ADDRESS_BYTES; + else + begin + mpm_mode = 0; + bus_cycle_state = STAND_BY; + end + if (Instruct == QPP) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 2) == 0) + begin + write = 0; + for(i=0;i<=255;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = quad_data_in[(i*2)+(1-j)]; + for(k=3;k>=0;k=k-1) + begin + Byte_slv[4*j+k] = Quad_slv[k]; + end + end + WByte[i] = Byte_slv; + end + if (data_cnt > 512) + Byte_number = 255; + else + Byte_number = data_cnt/2 -1; + end + end + end + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + case (Instruct) + WRDI, + WREN, + DP, + BE, + SE, + P4E, + P8E, + CLSR: + begin + if (data_cnt == 0) + write = 1'b0; + end + + RES_READ_ES: + begin + write = 1'b0; + end + + WRR : + begin + if((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 0; + cfg_write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + begin + write = 0; + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg_in[i]= + Data_in[7-i]; + Sec_conf_reg_in[i]= + Data_in[15-i]; + end + end + end + end + + PP : + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = + Data_in[(i*8) + (7-j)]; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE) + Byte_number = 255; + else + Byte_number = ((data_cnt/8) - 1); + end + end + end + + OTPP : + begin + if (data_cnt == 8) + begin + write = 1'b0; + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = Data_in[7-j]; + end + WOTPByte = Byte_slv; + end + end + endcase + end + end + else + if (bus_cycle_state == DUMMY_BYTES) + begin + bus_cycle_state = STAND_BY; + if (((HOLDNeg_in && ~QUAD) || QUAD) && + (Instruct == RES_READ_ES) && (dummy_cnt == 0)) + write = 1'b0; + end + end + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Program Operations +// // start +// ///////////////////////////////////////////////////////////////////////// + + event pdone_event; + + always @(PSTART) + begin + if (PSTART && PDONE) + if (Sec_Prot[SA] == 1'b0) + begin + PDONE = 1'b0; + ->pdone_event; + end + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #tdevice_PP PDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Write Status Register Operation +// // start +// ///////////////////////////////////////////////////////////////////////// + + event wdone_event; + + always @(WSTART) + begin + if (WSTART && WDONE) + begin + WDONE = 1'b0; + ->wdone_event; + end + end + + always @(wdone_event) + begin:wdone_process + WDONE = 1'b0; + #tdevice_WR WDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Erase Operations +// ///////////////////////////////////////////////////////////////////////// + time duration_erase; + + event edone_event; + + always @(ESTART) + begin: erase + if (ESTART && EDONE) + begin + if (Instruct == BE) + begin + duration_erase = tdevice_BE; + end + else if (Instruct == P4E || Instruct == P8E) + begin + duration_erase = tdevice_PE; + end + else + begin + duration_erase = tdevice_SE; + end + + EDONE = 1'b0; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_erase EDONE = 1'b1; + end +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg rising_edge_DP_out = 1'b0; + reg falling_edge_write = 1'b0; + integer i; + integer j; + + always @(falling_edge_write or rising_edge_PDONE or rising_edge_WDONE + or rising_edge_EDONE or rising_edge_DP_out) + begin: StateGen1 + if (falling_edge_write) + begin + case (current_state) + IDLE : + begin + if (~write) + begin + if ((Instruct == WRR) && WEL) + begin + if (~(Status_reg[7] && ~WPNeg_in && ~QUAD)) + //HPM is disabled when the Quad I/O Mode is enabled + //(Quad bit = 1 in the Configuration Register) + next_state = WRITE_SR; + end + + else if ((Instruct == PP || Instruct == QPP) && + WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + next_state = PAGE_PG; + end + + else if (Instruct == OTPP && WEL) + begin + if(Address == 256 || Address == 257 || + ((Address >= 258 && Address <= 273) && + PR_LOCK1[(Address-258)/8] == 1'b1) + || Address == 274 + || Address == 275 || ((Address >= 276 && + Address <= 531) && PR_LOCK2[(Address-276)/16] + ==1'b1) || Address == 532 || Address == 533 || + ((Address >= 534 && Address <= 767) + && PR_LOCK3[(Address-534)/16] == 1'b1)) + next_state = OTP_PG; + end + + else if (Instruct == SE && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + next_state = SECTOR_ER; + end + + else if (Instruct == P4E && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0 && (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM))) + next_state = P4_ER; + end + + else if (Instruct == P8E && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0 && (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM))) + next_state = P8_ER; + end + + else if (Instruct == BE && WEL) + begin + if (Status_reg[2]==1'b0 && Status_reg[3]==1'b0 && + Status_reg[4]==1'b0) + next_state = BULK_ER; + end + else if (Instruct == DP) + next_state = DP_DOWN_WAIT; + else + next_state = IDLE; + end + end + + DP_DOWN : + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + next_state = IDLE; + end + end + + endcase + end + + if (rising_edge_PDONE) + begin + if (current_state==PAGE_PG || current_state==OTP_PG) + begin + next_state = IDLE; + end + end + + if (rising_edge_WDONE) + begin + if (current_state==WRITE_SR) + begin + next_state = IDLE; + end + end + + if (rising_edge_EDONE) + begin + if (current_state==SECTOR_ER || current_state==BULK_ER + || current_state==P4_ER || current_state==P8_ER) + begin + next_state = IDLE; + end + end + + if (rising_edge_DP_out) + begin + if (current_state==DP_DOWN_WAIT) + next_state = DP_DOWN; + end + + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg rising_edge_RES_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg rising_edge_powered = 1'b0; + reg current_state_event = 1'b0; + + integer WData [0:255]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(oe_event) + begin + oe = 1'b1; + #1 oe = 1'b0; + end + + always @(rising_edge_read_out or Instruct_event or + change_addr_event or oe or current_state_event or + falling_edge_write or EDONE or WDONE or PDONE or + CSNeg_ipd or rising_edge_RES_out or rising_edge_powered or + rising_edge_DP_out) + begin: Functionality + integer i,j; + + if (rising_edge_read_out) + begin + if (PoweredUp == 1'b1) + ->oe_event; + end + + if (Instruct_event) + begin + read_cnt = 0; + rd_fast = 1'b1; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b0; + if (current_state == DP_DOWN_WAIT) + begin + if (DP_in == 1'b1) + begin + $display ("Command results can be corrupted"); + end + end + if (Instruct == DH_READ || Instruct == QH_READ) + begin + mpm_mode = 1; + end + end + + if (rising_edge_powered) + begin + //The Configuration Register FREEZE bit is cleared. + Sec_conf_reg[0] = 1'b0; + + //The WEL bit resets (disables writes) on power-up + Status_reg[1] = 1'b0; + + if (BPNV == 1) + begin + //When BPNV is set to ‘1’,the BP2-0 bits in the Status Register + //are volatile and will be reset to binary 111 after power on reset. + Status_reg[4] = 1'b1;// BP2 + Status_reg[3] = 1'b1;// BP1 + Status_reg[2] = 1'b1;// BP0 + change_BP = 1'b1; + #1 change_BP = 1'b0; + end + end + + if (change_addr_event) + begin + read_addr = Address; + end + + if (oe || current_state_event) + begin + case (current_state) + IDLE : + begin + if (oe && ~RES_in) + begin + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + if (Instruct == RCR) + begin + //Read Security Conf. Register + SOut_zd = Sec_conf_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + //Read Memory array + if (Instruct == READ) + begin + rd_fast = 1'b0; + rd_jedec = 1'b0; + rd_slow = 1'b1; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == DUAL_READ || Instruct == DH_READ) + begin + //Read Memory array + rd_fast = 1'b0; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b1; + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == QUAD_READ || Instruct == QH_READ) + begin + //Read Memory array + rd_fast = 1'b0; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b1; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b0; + data_out = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum; + //instead, the data will be indeterminate. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == RDID) + begin + // Read ID + rd_fast = 1'b0; + rd_slow = 1'b0; + rd_jedec = 1'b1; + dual = 1'b0; + ident_out = {Manuf_ID,DeviceID,ExtendedBytes, + ReservedBytes,ReservedBytes, + ReservedBytes,CFI_array_tmp}; + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 648) + read_cnt = 0; + end + else if (Instruct == READ_ID) + begin + // --Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if (read_addr % 2 == 1) + begin + data_out[7:0] = ES; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + end + else if (oe && RES_in) + begin + $display ("Command results can be corrupted"); + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + WRITE_SR, + SECTOR_ER, + BULK_ER, + P4_ER, + P8_ER, + OTP_PG, + PAGE_PG : + begin + if (oe && Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + if (oe && Instruct == RCR) + begin + //Read Security Conf. Register + SOut_zd = Sec_conf_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + DP_DOWN : + begin + if (oe && Instruct == RES_READ_ES) + begin + // Read ID + data_out[7:0] = ES; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + endcase + end + + if (falling_edge_write) + begin + case (current_state) + IDLE : + begin + if (~write) + begin + if (RES_in == 1'b1 && Instruct != DP) + begin + $display ("Command results can be corrupted"); + end + if (Instruct == WREN) + Status_reg[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg[1] = 1'b0; + else if (Instruct == WRR && WEL) + begin + if (~(Status_reg[7] && ~WPNeg_in && ~QUAD)) + begin + WSTART = 1'b1; + WSTART <= #1 1'b0; + Status_reg[0] = 1'b1; + end + else + begin + Status_reg[1] = 0; + end + end + else if ((Instruct == PP || Instruct == QPP) && + WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + begin + PSTART = 1'b1; + PSTART <= #1 1'b0; + initial_config = 1; + Status_reg[0] = 1'b1; //WIP + Addr = Address; + Addr_tmp = Address; + SA = sect; + wr_cnt = Byte_number; + for (i=0;i<=wr_cnt;i=i+1) + begin + if (Viol != 1'b0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == OTPP && WEL) + begin + if(Address == 256 || Address == 257 || + ((Address >= 258 && Address <= 273) && + PR_LOCK1[(Address-258)/8] == 1'b1) + || Address == 274 + || Address == 275 || ((Address >= 276 && + Address <= 531) && PR_LOCK2[(Address-276)/16] + ==1'b1) || Address == 532 || Address == 533 || + ((Address >= 534 && Address <= 767) + && PR_LOCK3[(Address-534)/16] == 1'b1)) + begin + PSTART = 1'b1; + PSTART <= #1 1'b0; + Status_reg[0] = 1'b1; //WIP + Addr = Address; + if (Viol != 1'b0 ) + WOTPData = -1; + else + WOTPData = WOTPByte; + end + else if (Address < 100 || Address > 767 ) + begin + Status_reg[6] = 1'b1; + Status_reg[1] = 1'b0; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == SE && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + initial_config = 1; + Status_reg[0] = 1'b1; + Addr = Address; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == BE && WEL) + begin + if(Status_reg[2]==1'b0 && Status_reg[3]==1'b0 && + Status_reg[4]==1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + initial_config = 1; + Status_reg[0] = 1'b1; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == P4E && WEL) + begin + sect = Address / 24'h10000; + if (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM)) + begin + if (Sec_Prot[sect] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + initial_config = 1; + Status_reg[0] = 1'b1; + Addr = Address; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else + begin + Status_reg[5] = 1'b1; + Status_reg[1] = 1'b0; + end + end + else if (Instruct == P8E && WEL) + begin + sect = Address / 24'h10000; + if (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM)) + begin + if (Sec_Prot[sect] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + initial_config = 1; + Status_reg[0] = 1'b1; + Addr = Address; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else + begin + Status_reg[5] = 1'b1; + Status_reg[1] = 1'b0; + end + end + else if (Instruct == CLSR) + begin + Status_reg[5] = 1'b0; + Status_reg[6] = 1'b0; + end + else if (Instruct == DP) + begin + RES_in <= 1'b0; + DP_in = 1'b1; + end + else if (Instruct == RES_READ_ES) + begin + RES_in <= 1'b1; + end + end + + end + + DP_DOWN : + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + RES_in = #1 1'b1; + end + end + + endcase + end + + if(current_state_event || EDONE) + begin + case (current_state) + + SECTOR_ER : + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + BULK_ER : + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = -1; + end + + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + P4_ER : + begin + ADDRHILO_PB4(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + P8_ER : + begin + ADDRHILO_PB8(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + endcase + end + + if(current_state_event || WDONE) + begin + if (current_state == WRITE_SR) + begin + if (WDONE) + begin + Status_reg[0] = 1'b0;//WIP + Status_reg[1] = 1'b0;//WEL + //SRWD bit + Status_reg[7] = Status_reg_in[7];//MSB first + + if (FREEZE == 0) + begin + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT and TBPARM bits in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + Status_reg[4] = Status_reg_in[4];// BP2 + Status_reg[3] = Status_reg_in[3];// BP1 + Status_reg[2] = Status_reg_in[2];// BP0 + + if (cfg_write) + begin + Sec_conf_reg[0] = Sec_conf_reg_in[0];// FREEZE + + if (TBPARM == 1'b0 && initial_config == 1'b0) + begin + Sec_conf_reg[2] = Sec_conf_reg_in[2];//TBPARM + end + + if (TBPROT == 1'b0 && initial_config == 1'b0) + begin + Sec_conf_reg[5] = Sec_conf_reg_in[5];//TBPROT + end + end + + change_BP = 1'b1; + #1 change_BP = 1'b0; + end + + if (cfg_write) + begin + Sec_conf_reg[1] = Sec_conf_reg_in[1];// QUAD + + if (BPNV == 1'b0) + begin + Sec_conf_reg[3] = Sec_conf_reg_in[3];//BPNV + end + end + + end + end + end + + if(current_state_event || PDONE) + begin + if (current_state == PAGE_PG) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + if (~old_bit[j]) + new_bit[j]=1'b0; + new_int=new_bit; + end + + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i -cnt] = - 1; + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + + cnt = 0; + + if (PDONE) + begin + Status_reg[0] = 1'b0;//wip + Status_reg[1] = 1'b0;// wel + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + end + end + + if(current_state_event || PDONE) + begin + if (current_state == OTP_PG) + begin + new_int = WOTPData; + old_int = OTPMem[Addr]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WOTPData = new_int; + end + else + begin + WOTPData = -1; + end + OTPMem[Addr] = -1; + if (PDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + OTPMem[Addr] = WOTPData; + PR_LOCK1 = {OTPMem[257],OTPMem[256]}; + + PR_LOCK1[15:8] = OTPMem[257]; + PR_LOCK1[7:0] = OTPMem[256]; + PR_LOCK2[15:8] = OTPMem[275]; + PR_LOCK2[7:0] = OTPMem[274]; + PR_LOCK3[15:8] = OTPMem[533]; + PR_LOCK3[7:0] = OTPMem[532]; + end + end + end + + //Output Disable Control + if (CSNeg_ipd ) + begin + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + end + + if (rising_edge_RES_out) + begin + if(RES_out) + begin + RES_in = 1'b0; + end + end + + if (rising_edge_DP_out) + begin + if (current_state == DP_DOWN_WAIT) + begin + DP_in = 1'b0; + end + end + + end + + always @(change_BP) + begin + if (change_BP) + begin + case (Status_reg[4:2]) + 3'b000 : + begin + Sec_Prot = 256'h0; + end + + 3'b001 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*63/64] = 2'b11; + Sec_Prot[(SecNum+1)*63/64 - 1 : 0] = 126'h0; + end + else + begin + Sec_Prot[(SecNum+1)/64 - 1 : 0] = 2'b11; + Sec_Prot[SecNum : (SecNum+1)/64] = 126'h0; + end + end + + 3'b010 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*31/32] = 4'hF; + Sec_Prot[(SecNum+1)*31/32 - 1 : 0] = 124'h0; + end + else + begin + Sec_Prot[(SecNum+1)/32 - 1 : 0] = 4'hF; + Sec_Prot[SecNum : (SecNum+1)/32] = 124'h0; + end + end + + 3'b011 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*15/16] = 8'hFF; + Sec_Prot[(SecNum+1)*15/16 - 1 : 0] = 120'h0; + end + else + begin + Sec_Prot[(SecNum+1)/16 - 1 : 0] = 8'hFF; + Sec_Prot[SecNum : (SecNum+1)/16] = 120'h0; + end + end + + 3'b100 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*7/8] = 16'hFFFF; + Sec_Prot[(SecNum+1)*7/8 - 1 : 0] = 112'h0; + end + else + begin + Sec_Prot[(SecNum+1)/8 - 1 : 0] = 16'hFFFF; + Sec_Prot[SecNum : (SecNum+1)/8] = 112'h0; + end + end + + 3'b101 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*3/4] + = 32'hFFFFFFFF; + Sec_Prot[(SecNum+1)*3/4 - 1 : 0] = 96'h0; + end + else + begin + Sec_Prot[(SecNum+1)/4 - 1 : 0] + = 32'hFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/4] = 96'h0; + end + end + + 3'b110 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)/2] + = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[(SecNum+1)/2 - 1 : 0] = 64'h0; + end + else + begin + Sec_Prot[(SecNum+1)/2 - 1 : 0] + = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/2] = 64'h0; + end + end + + 3'b111 : + begin + Sec_Prot = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + end + + endcase + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign rd_jid = rd_jedec; + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (~HOLDNeg_in && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + +// Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + AddrLOW = sector * 20'h10000; + AddrHIGH = sector * 20'h10000 + 16'hFFFF; + end + endtask + +// Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + + page = Addr / 16'h100; + AddrLOW = page * 16'h100; + AddrHIGH = page * 16'h100 + 8'hFF; + + end + endtask + +// Procedure ADDRHILO_PB4 + task ADDRHILO_PB4; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + if (sector == 0 || sector == 1 || + sector == SecNum || sector == SecNum-1) + begin + AddrLOW = (Address/(SecSize_4+1))*(SecSize_4+1); + AddrHIGH = (Address/(SecSize_4+1))*(SecSize_4+1) + SecSize_4; + end + end + endtask + +// Procedure ADDRHILO_PB8 + task ADDRHILO_PB8; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + if (sector == 0 || sector == SecNum-1) + begin + AddrLOW = (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + end + if (sector == 1) + begin + AddrLOW = (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + if (AddrHIGH > 20'h1FFFF) + AddrHIGH = 20'h1FFFF; + end + if (sector == SecNum) + begin + AddrLOW = (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + if (AddrHIGH > 24'h7FFFFF) + AddrHIGH = 24'h7FFFFF; + end + end + endtask + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1'b1; + #1 falling_edge_write = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1 rising_edge_WDONE = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1 rising_edge_EDONE = 1'b0; + end + + always @(posedge DP_out) + begin + rising_edge_DP_out = 1'b1; + #1 rising_edge_DP_out = 1'b0; + end + + always @(posedge RES_out) + begin + rising_edge_RES_out = 1'b1; + #1 rising_edge_RES_out = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1 rising_edge_read_out = 1'b0; + end + + always @(posedge PoweredUp) + begin + rising_edge_powered = 1'b1; + #1 rising_edge_powered = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1 change_addr_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1 current_state_event = 1'b0; + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.vhd b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.vhd new file mode 100644 index 0000000..d63c5d0 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p.vhd @@ -0,0 +1,2562 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl064p.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2012 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 D.Stanojkovic 08 Jan 22 Inital Release +-- V1.1 D.Stanojkovic 08 Feb 20 BP bits setting corrected +-- V1.2 D.Stanojkovic 08 Mar 04 MPM mode corrected +-- V1.3 D.Stanojkovic 08 Mar 20 MPM mode removed +-- V1.4 J.Stoickov 08 Dec 10 Latest datasheet aligned +-- (S25FL129 064 032P) +-- Program Error bit will not be +-- set after programming +-- in protect memory region +-- V1.5 V.Mancev 10 Sep 29 Implementation of internal pull-up +-- for HOLDNeg and WPNeg pins +-- V1.6 V.Mancev 12 Jan 13 Latest datasheet aligned +-- (S25FL064P_00_05) +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: FLASH MEMORY +-- Part: S25FL064P +-- +-- Description: 64 Megabit Serial Flash Memory with 104 MHz SPI Bus Interface +-- +------------------------------------------------------------------------------- +-- Known Bugs: +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl064p IS + GENERIC ( + -- tipd delays: interconnect path delays + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_SO : VitalDelayType01 := VitalZeroDelay01; + + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_SCK_SO : VitalDelayType01Z := UnitDelay01Z; -- tV + tpd_SCK_SI : VitalDelayType01Z := UnitDelay01Z; -- tV + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tDIS + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tLZ,tHZ + + --tsetup values + tsetup_CSNeg_SCK : VitalDelayType := UnitDelay; -- tCSS / + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- tHC / + tsetup_SI_SCK : VitalDelayType := UnitDelay; -- tsuDAT / + tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPS \ + + --thold values + thold_CSNeg_SCK : VitalDelayType := UnitDelay; -- tCSH / + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- tCHHH / + thold_SI_SCK : VitalDelayType := UnitDelay; -- thdDAT / + thold_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPH \ + + --tpw values: pulse width + tpw_SCK_serial_fast_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_serial_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_dual_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_rd_jid_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_serial_fast_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_serial_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_dual_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_rd_jid_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_CSNeg_pgm_posedge : VitalDelayType := UnitDelay; -- tCS + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_serial_rd : VitalDelayType := UnitDelay;--fSCK=40MHz + tperiod_SCK_serial_fast_rd : VitalDelayType := UnitDelay;--fSCK=104MHz + tperiod_SCK_dual_fast_rd : VitalDelayType := UnitDelay;--fSCK=80MHz + tperiod_SCK_serial_rd_jid : VitalDelayType := UnitDelay;--fSCK=50MHz + + -- tdevice values: values for internal delays + -- Page Program Operation + tdevice_PP : VitalDelayType := 3 ms; + -- Page Program Operation (ACC=9V)) + tdevice_EP : VitalDelayType := 2.4 ms; --tPP + -- Sector Erase Operation + tdevice_SE : VitalDelayType := 2 sec; --tSE + -- Bulk Erase Operation + tdevice_BE : VitalDelayType := 128 sec; --tBE + -- Write Status Register Operation + tdevice_WR : VitalDelayType := 100 ms; --tW + -- Deep Power Down + tdevice_DP : VitalDelayType := 10 us; --tDP + -- Release from Software Protect Mode + tdevice_RES : VitalDelayType := 30 us; --tRES + -- Parameter block erase + tdevice_PE : VitalDelayType := 800 ms; --tPE + -- VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 300 us; --tPU + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING := "s25fl064p.mem"; + otp_file_name : STRING := "s25fl064pOTP.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING := DefaultTimingModel + ); + PORT ( + SCK : IN std_ulogic := 'U'; -- serial clock input + SI : INOUT std_ulogic := 'U'; -- serial data input + CSNeg : IN std_ulogic := 'U'; -- chip select input + HOLDNeg : INOUT std_ulogic := 'U'; -- hold input + WPNeg : INOUT std_ulogic := 'U'; -- write protect input + SO : INOUT std_ulogic := 'U' -- SO + ); + ATTRIBUTE VITAL_LEVEL0 of s25fl064p : ENTITY IS TRUE; +END s25fl064p; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of s25fl064p IS + ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; + + CONSTANT PartID : STRING := "s25fl064p"; + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSize_4 : NATURAL := 16#FFF#; --4095 + CONSTANT SecSize_8 : NATURAL := 16#1FFF#; --8191 + CONSTANT OTPSize : NATURAL := 511; + CONSTANT OTPLoAddr : NATURAL := 16#100#; + CONSTANT OTPHiAddr : NATURAL := 16#2FF#; + CONSTANT SecNum : NATURAL := 127; + CONSTANT PageNum : NATURAL := 16#7FFF#; + CONSTANT HiAddrBit : NATURAL := 23; + CONSTANT AddrRANGE : NATURAL := 16#7FFFFF#; + CONSTANT BYTE : NATURAL := 8; + --Manufacturer Identification + CONSTANT Manuf_ID : NATURAL := 16#01#; + --Electronic Signature + CONSTANT ES : NATURAL := 16#16#; + --Device ID + --Manufacturer Identification && Memory Type && Memory Capacity + CONSTANT Jedec_ID : NATURAL := 16#20#; -- first byte of Device ID + CONSTANT DeviceID : NATURAL := 16#0216#; + CONSTANT ExtendedBytes : NATURAL := 16#4D#; + CONSTANT ReservedBytes : NATURAL := 16#00#; + +-- interconnect path delay signals + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + + --- internal delays + SIGNAL PP_in : std_ulogic := '0'; + SIGNAL PP_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL SE_in : std_ulogic := '0'; + SIGNAL SE_out : std_ulogic := '0'; + SIGNAL BE_in : std_ulogic := '0'; + SIGNAL BE_out : std_ulogic := '0'; + SIGNAL EP_in : std_ulogic := '0'; + SIGNAL EP_out : std_ulogic := '0'; + SIGNAL WR_in : std_ulogic := '0'; + SIGNAL WR_out : std_ulogic := '0'; + SIGNAL DP_in : std_ulogic := '0'; + SIGNAL DP_out : std_ulogic := '0'; + SIGNAL PE_in : std_ulogic := '0'; + SIGNAL PE_out : std_ulogic := '0'; + SIGNAL RES_in : std_ulogic := '0'; + SIGNAL RES_out : std_ulogic := '0'; + +BEGIN + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); + BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); + EP :VitalBuf(EP_out, EP_in, (tdevice_EP ,UnitDelay)); + WR :VitalBuf(WR_out, WR_in, (tdevice_WR ,UnitDelay)); + DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay)); + PE :VitalBuf(PE_out, PE_in, (tdevice_PE ,UnitDelay)); + RES :VitalBuf(RES_out, RES_in, (tdevice_RES ,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_2 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_3 : VitalWireDelay (SO_ipd, SO, tipd_SO); + + w_4: VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_5: VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + w_6: VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SCK : IN std_ulogic := 'U'; + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + CSNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + PORT MAP ( + SCK => SCK_ipd, + SIIn => SI_ipd, + + SOIn => SO_ipd, + + SOut => SO, + + CSNeg => CSNeg_ipd, + + HOLDNegIn => HOLDNeg_ipd, + WPNegIn => WPNeg_ipd, + + SIOut => SI, + WPNegOut => WPNeg, + HOLDNegOut => HOLDNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + WRITE_SR, + PAGE_PG, + OTP_PG, + SECTOR_ER, + BULK_ER, + P4_ER, + P8_ER, + DP_DOWN_WAIT, + DP_DOWN + ); + + -- Instruction Type + TYPE instruction_type IS (NONE, + WREN, + WRDI, + WRR, + RDSR, + READ, + READ_ID, + RDID, + FAST_READ, + DUAL_READ, + QUAD_READ, + DH_READ, + QH_READ, + SE, + BE, + PP, + QPP, + DP, + RES_READ_ES, + ENTER_PRL, + EXIT_PRL, + CLSR, + RCR, + P4E, + P8E, + OTPR, + OTPP + ); + + TYPE WByteType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; + --Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER + RANGE -1 TO MaxData; + --OTP Memory Array + TYPE OTPArr IS ARRAY (OTPLoAddr TO OTPHiAddr) OF INTEGER + RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + -- OTP Sector + SHARED VARIABLE OTPMem : OTPArr := (OTHERS => MaxData); + + SIGNAL WByte : WByteType := (OTHERS => 0); + SIGNAL WOTPByte : INTEGER RANGE -1 TO MaxData; + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + SHARED VARIABLE Status_reg : std_logic_vector(7 downto 0) + := (others => '0'); + + SIGNAL Status_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status register Write In Progress Bit + ALIAS WIP :std_logic IS Status_reg(0); + -- Status register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg(1); + -- Status register block protect Bits + ALIAS BP0 :std_logic IS Status_reg(2); + ALIAS BP1 :std_logic IS Status_reg(3); + ALIAS BP2 :std_logic IS Status_reg(4); + -- status register Erase Error bit + ALIAS E_ERR :std_logic IS Status_reg(5); + -- status register Program Error bit + ALIAS P_ERR :std_logic IS Status_reg(6); + -- status register write disable + ALIAS SRWD :std_logic IS Status_reg(7); + + SHARED VARIABLE Sec_conf_reg : std_logic_vector(7 downto 0) + := (others => '0'); + + SIGNAL Sec_conf_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Configuration Register FREEZE bit + ALIAS FREEZE :std_logic IS Sec_conf_reg(0); + -- Configuration Register QUAD bit + ALIAS QUAD :std_logic IS Sec_conf_reg(1); + -- Configuration Register TBPARM bit + ALIAS TBPARM :std_logic IS Sec_conf_reg(2); + -- Configuration Register BPNV bit + ALIAS BPNV :std_logic IS Sec_conf_reg(3); + -- Security Configuration Register the TBPROT bit + ALIAS TBPROT :std_logic IS Sec_conf_reg(5); + + -- The Lock Protection Registers for OTP Memory space + SHARED VARIABLE PR_LOCK1 :std_logic_vector(15 downto 0); + SHARED VARIABLE PR_LOCK2 :std_logic_vector(15 downto 0); + SHARED VARIABLE PR_LOCK3 :std_logic_vector(15 downto 0); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL cfg_write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL fast_rd : boolean := true; + SIGNAL rd : boolean := false; + SIGNAL dual : boolean := false; + SIGNAL rd_jid : boolean := false; + + SHARED VARIABLE hold_mode : boolean := false; + SHARED VARIABLE mpm_mode : boolean := false; + + SHARED VARIABLE read_cnt : NATURAL := 0; + + SIGNAL change_addr : std_logic := '0'; + + SIGNAL change_BP : std_logic := '0'; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; -- Page Prog. Done + SIGNAL PSTART : std_logic := '0'; --Start Page Programming + + SIGNAL WDONE : std_logic := '1'; -- Write. Done + SIGNAL WSTART : std_logic := '0'; --Start Write + + SIGNAL ESTART : std_logic := '0'; --Start Erase + SIGNAL EDONE : std_logic := '1'; --Erase Done + + SIGNAL INITIAL_CONFIG : std_logic := '0'; + + -- Sector and subsector addresses + SIGNAL SA : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE sect : NATURAL RANGE 0 TO SecNum; + + SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0; + + -- Sector is protect if '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum downto 0) := + (OTHERS => '0'); + + SHARED VARIABLE BP : std_logic_vector(2 downto 0) := "000"; + + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO SecNum; + BEGIN + sector := Addr/16#10000#; + AddrLOW := sector*16#10000#; + AddrHIGH := sector*16#10000# + 16#0FFFF#; + END ADDRHILO_SEC; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + BEGIN + page := Addr/16#100#; + AddrLOW := Page*16#100#; + AddrHIGH := Page*16#100# + 16#FF#; + END AddrHILO_PG; + + PROCEDURE ADDRHILO_PB4( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE Sec : NATURAL RANGE 0 TO SecNum; + BEGIN + Sec := Addr/16#10000#; + IF Sec = 0 OR Sec = 1 OR Sec = SecNum OR Sec = SecNum - 1 THEN + AddrLOW := (Address/(SecSize_4+1))*(SecSize_4+1); + AddrHIGH := (Address/(SecSize_4+1))*(SecSize_4+1) + SecSize_4; + END IF; + END ADDRHILO_PB4; + + PROCEDURE ADDRHILO_PB8( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE Sec : NATURAL RANGE 0 TO SecNum; + BEGIN + Sec := Addr/16#10000#; + IF Sec = 0 OR Sec = SecNum - 1 THEN + AddrLOW := (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH := (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + ELSIF Sec = 1 THEN + AddrLOW := (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH := (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + IF AddrHIGH > 16#1FFFF# THEN + AddrHIGH := 16#1FFFF#; + END IF; + ELSIF Sec = SecNum THEN + AddrLOW := (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH := (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + IF AddrHIGH > 16#7FFFFF# THEN + AddrHIGH := 16#7FFFFF#; + END IF; + END IF; + END ADDRHILO_PB8; + + BEGIN + + ---------------------------------------------------------------------------- + --Power Up time; + --------------------------------------------------------------------------- + PoweredUp <= '1' AFTER tdevice_PU; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn, SOIn, SCK_ipd, CSNeg_ipd, HOLDNegIn, + WPNegIn) + -- Timing Check Variables + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_HOLD_SCK : X01 := '0'; + VARIABLE TD_HOLD_SCK : VitalTimingDataType; + + VARIABLE Tviol_CS_SCK : X01 := '0'; + VARIABLE TD_CS_SCK : VitalTimingDataType; + + VARIABLE Tviol_WS_CS : X01 := '0'; + VARIABLE TD_WS_CS : VitalTimingDataType; + + VARIABLE Tviol_WH_CS : X01 := '0'; + VARIABLE TD_WH_CS : VitalTimingDataType; + + VARIABLE Pviol_CS_read : X01 := '0'; + VARIABLE PD_CS_read : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_CS_pgm : X01 := '0'; + VARIABLE PD_CS_pgm : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_fast : X01 := '0'; + VARIABLE PD_SCK_serial_fast : VitalPeriodDataType := + VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual : X01 := '0'; + VARIABLE PD_SCK_dual : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_rdid : X01 := '0'; + VARIABLE PD_SCK_rdid : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial : X01 := '0'; + VARIABLE PD_SCK_serial : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_fast_rd: X01 := '0'; + VARIABLE PD_SCK_serial_fast_rd : VitalPeriodDataType := + VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_rd : X01 := '0'; + VARIABLE PD_SCK_serial_rd : VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_rdid : X01 := '0'; + VARIABLE PD_SCK_serial_rdid: VitalPeriodDataType := VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual_fast_rd: X01 := '0'; + VARIABLE PD_SCK_dual_fast_rd : VitalPeriodDataType := + VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between SI and SCK, serial mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK, + SetupLow => tsetup_SI_SCK, + HoldHigh => thold_SI_SCK, + HoldLow => thold_SI_SCK, + CheckEnabled => SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupLow => tsetup_HOLDNeg_SCK, + SetupHigh => tsetup_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + CheckEnabled => QUAD = '1' + AND HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLD_SCK, + Violation => Tviol_HOLD_SCK + ); + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK, + SetupLow => tsetup_CSNeg_SCK, + HoldHigh => thold_CSNeg_SCK, + HoldLow => thold_CSNeg_SCK, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CS_SCK, + Violation => Tviol_CS_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => true, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WS_CS, + Violation => Tviol_WS_CS + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => SRWD = '1' AND WEL = '1' AND QUAD = '0', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WH_CS, + Violation => Tviol_WH_CS + ); + + -- Period Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pgm_posedge, + PeriodData => PD_CS_pgm, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CS_pgm, + HeaderMsg => InstancePath & PartID, + CheckEnabled => TRUE ); + + -- Period Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CS_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CS_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_serial_negedge, + PulseWidthHigh => tpw_SCK_serial_posedge, + PeriodData => PD_SCK_serial, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd); + + -- Period Check SCK for RDID, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_rd_jid_negedge, + PulseWidthHigh => tpw_SCK_rd_jid_posedge, + PeriodData => PD_SCK_rdid, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_rdid, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd_jid); + + -- Period Check SCK for FAST_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_serial_fast_negedge, + PulseWidthHigh => tpw_SCK_serial_fast_posedge, + PeriodData => PD_SCK_serial_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Period Check SCK for DUAL_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_dual_negedge, + PulseWidthHigh => tpw_SCK_dual_posedge, + PeriodData => PD_SCK_dual, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_rd, + PeriodData => PD_SCK_serial_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for RDID, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_rd_jid, + PeriodData => PD_SCK_serial_rdid, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_rdid, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd_jid ); + + -- Period Check SCK for other than READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_fast_rd, + PeriodData => PD_SCK_serial_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Period Check SCK for other than READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_dual_fast_rd, + PeriodData => PD_SCK_dual_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual ); + + Violation := Tviol_SI_SCK OR + Tviol_HOLD_SCK OR + Tviol_CS_SCK OR + Tviol_WS_CS OR + Tviol_WH_CS OR + Pviol_CS_read OR + Pviol_CS_pgm OR + Pviol_SCK_serial_fast OR + Pviol_SCK_dual OR + Pviol_SCK_rdid OR + Pviol_SCK_serial OR + Pviol_SCK_serial_rd OR + Pviol_SCK_serial_rdid OR + Pviol_SCK_serial_fast_rd OR + Pviol_SCK_dual_fast_rd; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + +---------------------------------------------------------------------------- +-- sequential process for FSM state transition +---------------------------------------------------------------------------- + StateTransition : PROCESS(next_state, PoweredUp) + + BEGIN + IF PoweredUp = '1' THEN + current_state <= next_state; + END IF; + END PROCESS StateTransition; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_pullup, SIIn, RES_in) + + TYPE bus_cycle_type IS (STAND_BY, + CODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + TYPE quad_data_type IS ARRAY (0 TO 511) OF INTEGER RANGE 0 TO 15; + + VARIABLE bus_cycle_state : bus_cycle_type; + + VARIABLE data_cnt : NATURAL := 0; + VARIABLE addr_cnt : NATURAL := 0; + VARIABLE code_cnt : NATURAL := 0; + VARIABLE mode_cnt : NATURAL := 0; + VARIABLE dummy_cnt : NATURAL := 0; + VARIABLE bit_cnt : NATURAL := 0; + VARIABLE Data_in : std_logic_vector(2047 downto 0) + := (others => '0'); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE code : std_logic_vector(7 downto 0); + VARIABLE code_in : std_logic_vector(7 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + VARIABLE addr_bytes : std_logic_vector(HiAddrBit downto 0); + VARIABLE Address_in : std_logic_vector(23 downto 0); + VARIABLE mode_bytes : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); + BEGIN + + IF rising_edge(CSNeg_ipd) AND NOT(bus_cycle_state = DATA_BYTES) + AND NOT(bus_cycle_state = DUMMY_BYTES) THEN + bus_cycle_state := STAND_BY; + ELSE + CASE bus_cycle_state IS + WHEN STAND_BY => + IF falling_edge(CSNeg_ipd) THEN + Instruct <= NONE; + write <= '1'; + code_cnt := 0; + addr_cnt := 0; + data_cnt := 0; + mode_cnt := 0; + dummy_cnt := 0; + bus_cycle_state := CODE_BYTE; + END IF; + + WHEN CODE_BYTE => + IF rising_edge(SCK_ipd) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') THEN + Code_in(code_cnt) := SIIn; + code_cnt := code_cnt + 1; + IF code_cnt = BYTE THEN + --MSB first + FOR I IN 7 DOWNTO 0 LOOP + code(i) := code_in(7-i); + END LOOP; + + CASE code IS + WHEN "00000110" => --06h + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => --01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000101" => --05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => --03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00001011" => --0Bh + Instruct <= FAST_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10011111" => --9Fh + Instruct <= RDID; + bus_cycle_state := DATA_BYTES; + WHEN "10010000" => + Instruct <= READ_ID; --90h + bus_cycle_state := ADDRESS_BYTES; + WHEN "10101011" => + Instruct <= RES_READ_ES; --ABh + bus_cycle_state := DUMMY_BYTES; + WHEN "11011000" => --D8h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11000111" | "01100000" => --C7h or 60h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "00000010" => --02h + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => --32h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10111001" => --B9h + Instruct <= DP; + bus_cycle_state := DATA_BYTES; + WHEN "00110000" => --30h + Instruct <= CLSR; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => --35h + Instruct <= RCR; + bus_cycle_state := DATA_BYTES; + WHEN "00100000" => --20h + Instruct <= P4E; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01000000" =>--40h + Instruct <= P8E; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01000010" => --42h + Instruct <= OTPP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001011" => --4Bh + Instruct <= OTPR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111011" => --3Bh + Instruct <= DUAL_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01101011" => --6Bh + Instruct <= QUAD_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10111011" => --BBh + Instruct <= DH_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11101011" => --EBh + Instruct <= QH_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN others => + null; + END CASE; + END IF; + END IF; + + WHEN ADDRESS_BYTES => + IF rising_edge(SCK_ipd) THEN + IF ((Instruct=FAST_READ OR Instruct=OTPR + OR Instruct=DUAL_READ) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1')) + OR (Instruct=QUAD_READ AND QUAD = '1') THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 23-HiAddrBit LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSIF Instruct = DH_READ AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') THEN + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 12 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 23-HiAddrBit LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSE + mpm_mode := FALSE; + bus_cycle_state := STAND_BY; + END IF; + ELSIF Instruct = QH_READ THEN + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 6 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 23-HiAddrBit LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSE + mpm_mode := FALSE; + bus_cycle_state := STAND_BY; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 23-HiAddrBit LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + END IF; + + WHEN MODE_BYTE => + IF rising_edge(SCK_ipd) THEN + IF Instruct=DH_READ AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF Instruct=QH_READ AND QUAD = '1' THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + dummy_cnt := 0; + END IF; + + WHEN DUMMY_BYTES => + IF rising_edge(SCK_ipd) THEN + IF QUAD = '1' AND (Instruct=QUAD_READ + OR Instruct=QH_READ) THEN + dummy_cnt := dummy_cnt + 1; + IF dummy_cnt = BYTE AND Instruct=QUAD_READ THEN + bus_cycle_state := DATA_BYTES; + ELSIF dummy_cnt = BYTE/2 AND Instruct=QH_READ THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + dummy_cnt := dummy_cnt + 1; + IF dummy_cnt = BYTE THEN + IF Instruct=FAST_READ OR Instruct=OTPR OR + Instruct=DUAL_READ THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF dummy_cnt = 3*BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + IF (((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') + AND dummy_cnt = 0 AND Instruct = RES_READ_ES) THEN + write <= '0'; + END IF; + bus_cycle_state := STAND_BY; + END IF; + + WHEN DATA_BYTES => + IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' THEN + IF ((Instruct = READ OR Instruct = FAST_READ + OR Instruct = DUAL_READ OR Instruct = DH_READ + OR Instruct = RES_READ_ES OR Instruct = RDID + OR Instruct = READ_ID OR Instruct = RDSR + OR Instruct = RCR OR Instruct = OTPR) + AND ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1')) + OR ((Instruct=QUAD_READ OR Instruct=QH_READ) + AND QUAD = '1') THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + IF rising_edge(SCK_ipd) THEN + IF QUAD = '1' AND Instruct=QPP THEN + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF data_cnt > 511 THEN + --In case of quad mode and QPP, + --if more than 512 bytes are sent to the device + FOR I IN 0 TO 510 LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in(511) := to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF quad_nybble /= "ZZZZ" THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + IF data_cnt > 2047 THEN + --In case of serial mode and PP, + --if more than 256 bytes are sent to the device + IF bit_cnt = 0 THEN + FOR I IN 0 TO (255*BYTE - 1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in(2040 + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF bit_cnt = 8 THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + IF mpm_mode AND mode_bytes(7 downto 4) = "1010" + AND (Instruct = DH_READ OR Instruct = QH_READ) THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + mpm_mode := FALSE; + bus_cycle_state := STAND_BY; + END IF; + CASE Instruct IS + WHEN WREN | WRDI | DP | BE | SE | P4E | P8E + | CLSR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + IF data_cnt = 0 THEN + write <= '0'; + END IF; + END IF; + WHEN RES_READ_ES => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + write <= '0'; + END IF; + WHEN WRR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + IF ((data_cnt mod 8) = 0 AND + data_cnt > 0) THEN + IF data_cnt = 8 THEN + write <= '0'; + cfg_write <= '0'; + FOR i IN 0 TO 7 LOOP + Status_reg_in(i) <= + Data_in(7-i); + END LOOP; + ELSIF data_cnt = 16 THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + cfg_write <= '1'; + FOR i IN 0 TO 7 LOOP + Status_reg_in(i) <= + Data_in(7-i); + Sec_conf_reg_in(i) <= + Data_in(15-i); + END LOOP; + END IF; + END IF; + END IF; + + WHEN PP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + IF data_cnt > 0 THEN + IF data_cnt mod 8 = 0 THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 7 DOWNTO 0 LOOP + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + IF data_cnt > 256*BYTE THEN + Byte_number <= 255; + ELSE + Byte_number <= data_cnt/8-1; + END IF; + END IF; + END IF; + END IF; + + WHEN QPP => + IF data_cnt > 0 THEN + IF data_cnt mod 2 = 0 THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + IF data_cnt > 512 THEN + Byte_number <= 255; + ELSE + Byte_number <= data_cnt/2-1; + END IF; + END IF; + END IF; + + WHEN OTPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD ='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 7 DOWNTO 0 LOOP + Byte_slv(j) := Data_in(7-j); + END LOOP; + WOTPByte <= to_nat(Byte_slv); + END IF; + END IF; + + WHEN others => + null; + END CASE; + END IF; + + END CASE; + END IF; + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART) + VARIABLE pob : time; + BEGIN + IF LongTimming THEN + pob := tdevice_PP; + ELSE + pob := tdevice_PP / 100; + END IF; + IF rising_edge(PSTART) AND PDONE = '1' THEN + IF Sec_Prot(SA) = '0' THEN + PDONE <= '0', '1' AFTER pob; + END IF; + END IF; + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WR; + ELSE + wob := tdevice_WR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Bulk Erase + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART) + VARIABLE seo : time; + VARIABLE beo : time; + VARIABLE peo : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + seo := tdevice_SE; + beo := tdevice_BE; + peo := tdevice_PE; + ELSE + seo := tdevice_SE / 1000; + beo := tdevice_BE / 1000; + peo := tdevice_PE / 1000; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = BE THEN + duration := beo; + ELSIF Instruct = P4E OR Instruct = P8E THEN + duration := peo; + ELSE --Instruct = SE + duration := seo; + END IF; + EDONE <= '0', '1' AFTER duration; + END IF; + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS + BEGIN + IF CSNeg /= '1' THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + WAIT; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(write, CSNeg, WDONE, PDONE, EDONE, DP_out) + + BEGIN + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + CASE current_state IS + WHEN IDLE => + IF falling_edge(write) THEN + IF Instruct = WRR AND WEL = '1' + AND not(SRWD='1' AND WPNeg_pullup='0' AND QUAD='0') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + next_state <= WRITE_SR; + ELSIF (Instruct = PP OR Instruct = QPP) AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + next_state <= PAGE_PG; + END IF; + ELSIF Instruct = OTPP AND WEL = '1' THEN + IF Address = 256 OR Address = 257 OR + ((Address >= 258 AND Address <= 273) AND + PR_LOCK1((Address-258)/8) = '1') OR Address = 274 OR + Address = 275 OR((Address >= 276 AND Address <= 531) + AND PR_LOCK2((Address-276)/16) = '1') OR Address = 532 + OR Address = 533 OR((Address >= 534 AND Address <= 767) + AND PR_LOCK3((Address-534)/16) = '1') THEN + next_state <= OTP_PG; + END IF; + ELSIF Instruct = SE AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + next_state <= SECTOR_ER; + END IF; + ELSIF Instruct = P4E AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' AND (((sect=0 OR sect=1) + AND TBPARM='0') OR ((sect=SecNum OR sect=SecNum-1) + AND TBPARM='1')) THEN + next_state <= P4_ER; + END IF; + ELSIF Instruct = P8E AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' AND (((sect=0 OR sect=1) + AND TBPARM='0') OR ((sect=SecNum OR sect=SecNum-1) + AND TBPARM='1')) THEN + next_state <= P8_ER; + END IF; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0='0' AND BP1='0' AND BP2='0') THEN + next_state <= BULK_ER; + ELSIF Instruct = DP THEN + next_state <= DP_DOWN_WAIT; + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN OTP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN BULK_ER | SECTOR_ER | P4_ER | P8_ER => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN DP_DOWN_WAIT => + IF rising_edge(DP_out) THEN + next_state <= DP_DOWN; + END IF; + + WHEN DP_DOWN => + IF falling_edge(write) AND Instruct = RES_READ_ES THEN + next_state <= IDLE; + END IF; + + END CASE; + + END PROCESS StateGen; + + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(write,read_out, WDONE, PDONE, EDONE, current_state, + CSNeg_ipd, HOLDNeg_pullup, Instruct, Address, WByte, + DP_out, RES_out, change_addr, PoweredUp, WPNeg_pullup) + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#07# TO 16#50#) OF + INTEGER RANGE -1 TO 16#FF#; + TYPE WDataType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; + + VARIABLE CFI_array : CFItype := (OTHERS => -1); + VARIABLE WData : WDataType := (OTHERS => 0); + VARIABLE WOTPData : INTEGER RANGE -1 to MaxData; + VARIABLE oe : boolean := FALSE; + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + VARIABLE Addr : NATURAL; + VARIABLE Addr_tmp : NATURAL; + + VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE; + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(647 downto 0); + VARIABLE CFI_array_tmp : std_logic_vector(591 downto 0); + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + VARIABLE wr_cnt : NATURAL RANGE 0 TO 255; + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + VARIABLE cnt : NATURAL RANGE 0 TO 256 := 0; + + BEGIN + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + oe := rising_edge(read_out) AND PoweredUp = '1'; + + IF Instruct'EVENT THEN + read_cnt := 0; + fast_rd <= true; + rd_jid <= false; + dual <= false; + rd <= false; + IF Instruct = DH_READ OR Instruct = QH_READ THEN + mpm_mode := TRUE; + END IF; + END IF; + + IF rising_edge(PoweredUp) THEN + + FREEZE := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status Register are + --volatile and will be reset binary 111 after power-on reset + IF BPNV = '1' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF rising_edge(change_addr) THEN + read_addr := Address; + END IF; + + IF RES_out'EVENT AND RES_out = '1' THEN + RES_in <= '0'; + END IF; + + CASE current_state IS + WHEN IDLE => + IF falling_edge(write) THEN + read_cnt := 0; + IF RES_in = '1' AND Instruct /= DP THEN + ASSERT false + REPORT InstancePath & partID & "Command results" & + " can be corrupted, a delay of tRES" & + " currently in progress." + SEVERITY WARNING; + END IF; + IF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = WRDI THEN + WEL := '0'; + ELSIF Instruct = WRR AND WEL = '1' THEN + IF not(SRWD='1' AND WPNeg_pullup='0' AND QUAD='0') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + WSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PP OR Instruct = QPP) AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + PSTART <= '1', '0' AFTER 1 ns; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + END IF; + ELSIF Instruct = OTPP AND WEL = '1' THEN + IF Address = 256 OR Address = 257 OR + ((Address >= 258 AND Address <= 273) AND + PR_LOCK1((Address-258)/8)='1') OR Address=274 OR + Address=275 OR ((Address>=276 AND Address<=531) + AND PR_LOCK2((Address-276)/16)='1') OR Address=532 + OR Address=533 OR ((Address>=534 AND Address<=767) + AND PR_LOCK3((Address-534)/16) = '1') THEN + PSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + Addr := Address; + IF Viol /= '0' THEN + WOTPData := -1; + ELSE + WOTPData := WOTPByte; + END IF; + ELSIF (Address < 100 OR Address > 767 ) THEN + P_ERR := '1'; + WEL := '0'; + ELSE + WEL := '0'; + END IF; + ELSIF Instruct = SE AND WEL = '1' THEN + sect := Address / 16#10000#; + IF Sec_Prot(sect) = '0' THEN + ESTART <= '1', '0' AFTER 1 ns; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + WEL := '0'; + END IF; + ELSIF Instruct = BE AND WEL = '1' THEN + IF (BP0='0' AND BP1='0' AND BP2='0') THEN + ESTART <= '1', '0' AFTER 1 ns; + INITIAL_CONFIG <= '1'; + WIP := '1'; + ELSE + WEL := '0'; + END IF; + ELSIF Instruct = P4E AND WEL = '1' THEN + sect := Address / 16#10000#; + IF ((sect=0 OR sect=1) AND TBPARM='0') + OR ((sect=SecNum OR sect=SecNum-1) + AND TBPARM='1') THEN + IF Sec_Prot(sect) = '0' THEN + ESTART <= '1', '0' AFTER 1 ns; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + WEL := '0'; + END IF; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + ELSIF Instruct = P8E AND WEL = '1' THEN + sect := Address / 16#10000#; + IF ((sect=0 OR sect=1) AND TBPARM='0') + OR ((sect=SecNum OR sect=SecNum-1) + AND TBPARM='1') THEN + IF Sec_Prot(sect) = '0' THEN + ESTART <= '1', '0' AFTER 1 ns; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + WEL := '0'; + END IF; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + ELSIF Instruct = CLSR THEN + E_ERR := '0'; + P_ERR := '0'; + ELSIF Instruct = DP THEN + RES_in <= '0'; + DP_in <= '1'; + ELSIF Instruct = RES_READ_ES THEN + RES_in <= '1'; + END IF; + + ELSIF oe AND RES_in = '0' THEN + IF Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RCR THEN + --Read Security Conf. Register + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ OR Instruct = FAST_READ THEN + --Read Memory array + IF Instruct = READ THEN + fast_rd <= false; + rd_jid <= false; + rd <= true; + END IF; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF Instruct = DUAL_READ OR Instruct = DH_READ THEN + --Read Memory array + fast_rd <= false; + rd <= false; + rd_jid <= false; + dual <= true; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF (Instruct = QUAD_READ OR Instruct = QH_READ) + AND QUAD = '1' THEN + --Read Memory array + fast_rd <= false; + rd <= false; + rd_jid <= false; + dual <= true; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF Instruct = OTPR THEN + IF (read_addr>=OTPLoAddr) AND (read_addr<=OTPHiAddr) + THEN + --Read OTP Memory array + fast_rd <= true; + rd_jid <= false; + rd <= false; + data_out := to_slv(OTPMem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSIF (read_addr > OTPHiAddr) THEN + --OTP Read operation will not wrap to the + --starting address after the OTP address is at + --its maximum or Read Password Protection Mode + --is selected; instead, the data beyond the + --maximum OTP address will be undefined. + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF Instruct = RDID THEN + --Read Device ID + --can be terminated by driving CSNeg high + --at any time + fast_rd <= false; + rd_jid <= true; + rd <= false; + ident_out := to_slv(Manuf_ID,8) & to_slv(DeviceID,16) & + to_slv(ExtendedBytes,8) & to_slv(ReservedBytes,8) & + to_slv(ReservedBytes,8) & to_slv(ReservedBytes,8) & + CFI_array_tmp; + SOut_zd <= ident_out(647-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 648 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ_ID THEN + --Read Manufacturer and Device ID + IF read_addr MOD 2 = 0 THEN + data_out := to_slv(Manuf_ID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + data_out := to_slv(ES,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := 0; + END IF; + END IF; + END IF; + ELSIF oe AND RES_in = '1' THEN + SOut_zd <= 'X'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ASSERT false + REPORT InstancePath & partID & "Command results" & + " can be corrupted, a delay of tRES" & + " currently in progress." + SEVERITY WARNING; + END IF; + + WHEN WRITE_SR => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + IF WDONE = '1' THEN + WIP := '0'; + WEL := '0'; + SRWD := Status_reg_in(7);--MSB first + + IF FREEZE='0' THEN + --The Freeze Bit, when set to 1, locks the current + --state of the BP2-0 bits in Status Register, + --the TBPROT and TBPARM bits in the Config Register + --As long as the FREEZE bit remains cleared to logic + --'0', the other bits of the Configuration register + --including FREEZE are writeable. + + BP2 := Status_reg_in(4); + BP1 := Status_reg_in(3); + BP0 := Status_reg_in(2); + + BP := BP2 & BP1 & BP0; + + IF cfg_write = '1' THEN + + FREEZE := Sec_conf_reg_in(0);--MSB first + + IF TBPARM = '0' AND INITIAL_CONFIG = '0' THEN + TBPARM := Sec_conf_reg_in(2); + END IF; + + IF TBPROT = '0' AND INITIAL_CONFIG = '0' THEN + TBPROT := Sec_conf_reg_in(5); + END IF; + + END IF; + + change_BP <= '1', '0' AFTER 1 ns; + END IF; + + IF cfg_write = '1' THEN + QUAD := Sec_conf_reg_in(1); + + IF BPNV = '0' THEN + BPNV := Sec_conf_reg_in(3); + END IF; + END IF; + END IF; + + WHEN PAGE_PG => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + Mem(Addr + i - cnt) := -1; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + END IF; + + WHEN OTP_PG => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + new_int := WOTPData; + old_int := OTPMem(Addr); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WOTPData := new_int; + ELSE + WOTPData := -1; + END IF; + OTPMem(Addr) := -1; + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + OTPMem(Addr) := WOTPData; + PR_LOCK1 := to_slv(OTPMem(257),8) & to_slv(OTPMem(256),8); + PR_LOCK2 := to_slv(OTPMem(275),8) & to_slv(OTPMem(274),8); + PR_LOCK3 := to_slv(OTPMem(533),8) & to_slv(OTPMem(532),8); + END IF; + + WHEN SECTOR_ER => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + + WHEN BULK_ER => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + FOR i IN 0 TO AddrRANGE LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO AddrRANGE LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + + WHEN P4_ER => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ADDRHILO_PB4(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + + WHEN P8_ER => + IF oe AND Instruct = RDSR THEN + --Read Status Register + SOut_zd <= Status_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + IF oe AND Instruct = RCR THEN + SOut_zd <= Sec_conf_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ADDRHILO_PB8(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + + WHEN DP_DOWN_WAIT => + IF rising_edge(DP_out) THEN + DP_in <= '0'; + ELSIF DP_in = '1' AND Instruct'EVENT THEN + ASSERT false + REPORT InstancePath & partID & "Command results" & + " can be corrupted, a delay of tPD" & + " currently in progress." + SEVERITY WARNING; + END IF; + + WHEN DP_DOWN => + IF falling_edge(write) THEN + IF Instruct = RES_READ_ES THEN + RES_in <= '1'; + END IF; + ELSIF oe AND Instruct = RES_READ_ES THEN + --Read Electronic Signature + data_out := to_slv(ES,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + IF NOW = 0 ns THEN + CFI_array(16#07#) := 16#FF#; + CFI_array(16#08#) := 16#FF#; + CFI_array(16#09#) := 16#FF#; + CFI_array(16#0A#) := 16#FF#; + CFI_array(16#0B#) := 16#FF#; + CFI_array(16#0C#) := 16#FF#; + CFI_array(16#0D#) := 16#FF#; + CFI_array(16#0E#) := 16#FF#; + CFI_array(16#0F#) := 16#FF#; + --Product Group CFI Query Identification String + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --Product Group CFI system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#0B#; + CFI_array(16#20#) := 16#0B#; + CFI_array(16#21#) := 16#09#; + CFI_array(16#22#) := 16#10#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#01#; + CFI_array(16#25#) := 16#02#; + CFI_array(16#26#) := 16#01#; + --Product Group CFI Device Geometry Definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#05#; + CFI_array(16#29#) := 16#05#; + CFI_array(16#2A#) := 16#08#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#02#; + CFI_array(16#2D#) := 16#1F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#10#; + CFI_array(16#30#) := 16#00#; + CFI_array(16#31#) := 16#7D#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#01#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + CFI_array(16#3D#) := 16#FF#; + CFI_array(16#3E#) := 16#FF#; + CFI_array(16#3F#) := 16#FF#; + --Product Group CFI Primary Vendor-Specific Extended Query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#15#; + CFI_array(16#46#) := 16#00#; + CFI_array(16#47#) := 16#02#; + CFI_array(16#48#) := 16#00#; + CFI_array(16#49#) := 16#05#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#01#; + CFI_array(16#4C#) := 16#03#; + CFI_array(16#4D#) := 16#85#; + CFI_array(16#4E#) := 16#95#; + CFI_array(16#4F#) := 16#07#; + CFI_array(16#50#) := 16#00#; + END IF; + + CFI_array_tmp :=to_slv(CFI_array(16#07#), 8) & + to_slv(CFI_array(16#08#), 8) & + to_slv(CFI_array(16#09#), 8) & + to_slv(CFI_array(16#0A#), 8) & + to_slv(CFI_array(16#0B#), 8) & + to_slv(CFI_array(16#0C#), 8) & + to_slv(CFI_array(16#0D#), 8) & + to_slv(CFI_array(16#0E#), 8) & + to_slv(CFI_array(16#0F#), 8) & + to_slv(CFI_array(16#10#), 8) & + to_slv(CFI_array(16#11#), 8) & + to_slv(CFI_array(16#12#), 8) & + to_slv(CFI_array(16#13#), 8) & + to_slv(CFI_array(16#14#), 8) & + to_slv(CFI_array(16#15#), 8) & + to_slv(CFI_array(16#16#), 8) & + to_slv(CFI_array(16#17#), 8) & + to_slv(CFI_array(16#18#), 8) & + to_slv(CFI_array(16#19#), 8) & + to_slv(CFI_array(16#1A#), 8) & + to_slv(CFI_array(16#1B#), 8) & + to_slv(CFI_array(16#1C#), 8) & + to_slv(CFI_array(16#1D#), 8) & + to_slv(CFI_array(16#1E#), 8) & + to_slv(CFI_array(16#1F#), 8) & + to_slv(CFI_array(16#20#), 8) & + to_slv(CFI_array(16#21#), 8) & + to_slv(CFI_array(16#22#), 8) & + to_slv(CFI_array(16#23#), 8) & + to_slv(CFI_array(16#24#), 8) & + to_slv(CFI_array(16#25#), 8) & + to_slv(CFI_array(16#26#), 8) & + to_slv(CFI_array(16#27#), 8) & + to_slv(CFI_array(16#28#), 8) & + to_slv(CFI_array(16#29#), 8) & + to_slv(CFI_array(16#2A#), 8) & + to_slv(CFI_array(16#2B#), 8) & + to_slv(CFI_array(16#2C#), 8) & + to_slv(CFI_array(16#2D#), 8) & + to_slv(CFI_array(16#2E#), 8) & + to_slv(CFI_array(16#2F#), 8) & + to_slv(CFI_array(16#30#), 8) & + to_slv(CFI_array(16#31#), 8) & + to_slv(CFI_array(16#32#), 8) & + to_slv(CFI_array(16#33#), 8) & + to_slv(CFI_array(16#34#), 8) & + to_slv(CFI_array(16#35#), 8) & + to_slv(CFI_array(16#36#), 8) & + to_slv(CFI_array(16#37#), 8) & + to_slv(CFI_array(16#38#), 8) & + to_slv(CFI_array(16#39#), 8) & + to_slv(CFI_array(16#3A#), 8) & + to_slv(CFI_array(16#3B#), 8) & + to_slv(CFI_array(16#3C#), 8) & + to_slv(CFI_array(16#3D#), 8) & + to_slv(CFI_array(16#3E#), 8) & + to_slv(CFI_array(16#3F#), 8) & + to_slv(CFI_array(16#40#), 8) & + to_slv(CFI_array(16#41#), 8) & + to_slv(CFI_array(16#42#), 8) & + to_slv(CFI_array(16#43#), 8) & + to_slv(CFI_array(16#44#), 8) & + to_slv(CFI_array(16#45#), 8) & + to_slv(CFI_array(16#46#), 8) & + to_slv(CFI_array(16#47#), 8) & + to_slv(CFI_array(16#48#), 8) & + to_slv(CFI_array(16#49#), 8) & + to_slv(CFI_array(16#4A#), 8) & + to_slv(CFI_array(16#4B#), 8) & + to_slv(CFI_array(16#4C#), 8) & + to_slv(CFI_array(16#4D#), 8) & + to_slv(CFI_array(16#4E#), 8) & + to_slv(CFI_array(16#4F#), 8) & + to_slv(CFI_array(16#50#), 8); + + END PROCESS Functional; + + Protect : PROCESS(change_BP) + BEGIN + IF rising_edge(change_BP) THEN + + CASE BP IS + WHEN "000" => + Sec_Prot := (others => '0'); + WHEN "001" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*63/64) + := (others => '1'); + Sec_Prot((SecNum+1)*63/64 - 1 downto 0) + := (others => '0'); + ELSE + Sec_Prot((SecNum+1)/64 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/64) + := (others => '0'); + END IF; + WHEN "010" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*31/32) + := (others => '1'); + Sec_Prot((SecNum+1)*31/32 - 1 downto 0) + := (others => '0'); + ELSE + Sec_Prot((SecNum+1)/32 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/32) + := (others => '0'); + END IF; + WHEN "011" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*15/16) + := (others => '1'); + Sec_Prot((SecNum+1)*15/16 - 1 downto 0) + := (others => '0'); + ELSE + Sec_Prot((SecNum+1)/16 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/16) + := (others => '0'); + END IF; + WHEN "100" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*7/8) + := (others => '1'); + Sec_Prot((SecNum+1)*7/8 - 1 downto 0) + := (others => '0'); + ELSE + Sec_Prot((SecNum+1)/8 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/8) + := (others => '0'); + END IF; + WHEN "101" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*3/4) + := (others => '1'); + Sec_Prot((SecNum+1)*3/4 - 1 downto 0) + := (others => '0'); + ELSE + Sec_Prot((SecNum+1)/4 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/4) + := (others => '0'); + END IF; + WHEN "110" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)/2) + := (others => '1'); + Sec_Prot((SecNum+1)/2 - 1 downto 0) + := (others => '0'); + ELSE + Sec_Prot((SecNum+1)/2 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/2) + := (others => '0'); + END IF; + WHEN OTHERS => + Sec_Prot := (others => '1'); + END CASE; + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNeg_pullup) + BEGIN + IF (HOLDNeg_pullup = '0' AND QUAD /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + MemPreload : PROCESS + + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE otp_file : text is otp_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0; + VARIABLE secsi_ind : NATURAL RANGE 16#100# TO 16#2FF# := 16#100#; + VARIABLE buf : line; + + BEGIN + --------------------------------------------------------------------------- + --s25fl064p memory preload file format +----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaaaaa - stands for address + -- dd -
is byte to be written at Mem(aaaaaa++) + -- (aaaaaa is incremented at every load) + -- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (mem_file_name /= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF ind > AddrRANGE THEN + ASSERT false + REPORT "Given preload address is out of" & + "memory address range" + SEVERITY warning; + ELSE + ind := h(buf(2 to 7)); --address + END IF; + ELSE + Mem(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END LOOP; + END IF; + + --------------------------------------------------------------------------- + --s25fl064p_otp memory preload file format +----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaa - stands for address + -- dd -
is byte to be written at OTPMem(aaa++) + -- (aaa is incremented at every load) + -- only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (otp_file_name /= "none" AND UserPreload) THEN + secsi_ind := 16#100#; + OTPMem := (OTHERS => MaxData); + WHILE (not ENDFILE (otp_file)) LOOP + READLINE (otp_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF secsi_ind > 16#2FF# OR secsi_ind < 16#100# THEN + ASSERT false + REPORT "Given preload address is out of" & + "OTP address range" + SEVERITY warning; + ELSE + secsi_ind := h(buf(2 to 4)); --address + END IF; + ELSE + OTPMem(secsi_ind) := h(buf(1 to 2)); + PR_LOCK1 := to_slv(OTPMem(257),8) & to_slv(OTPMem(256),8); + PR_LOCK2 := to_slv(OTPMem(275),8) & to_slv(OTPMem(274),8); + PR_LOCK3 := to_slv(OTPMem(533),8) & to_slv(OTPMem(532),8); + secsi_ind := secsi_ind + 1; + END IF; + END LOOP; + END IF; + + WAIT; + END PROCESS MemPreload; + + ---------------------------------------------------------------------------- + -- Path Delay Section + ---------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "PO", + OutTemp => SOut_z, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO), + PathCondition => SOut_z /= 'Z' + AND (NOT dual)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SI), + PathCondition => SOut_z /= 'Z' + AND dual), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => TRUE) + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SI), + PathCondition => SIOut_z /= 'Z' AND dual), + 1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND dual), + 2 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => dual) + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SI), + PathCondition => HOLDNegOut_zd /= 'Z' AND dual + AND QUAD = '1'), + 1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND dual + AND QUAD = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SI), + PathCondition => HOLDNegOut_zd /= 'Z'AND dual + AND QUAD = '1'), + 1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND dual + AND QUAD = '1') + ) + ); + END PROCESS; + END BLOCK behavior; +END vhdl_behavioral; diff --git a/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_ver.ftm b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_ver.ftm new file mode 100644 index 0000000..b448a6c --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_ver.ftm @@ -0,0 +1,230 @@ + +FMF Timing for s25fl064p Parts + + +version: | author: | mod date: | changes made: + V1.0 D.Stanojkovic 08 Jan 11 Initial release + V1.1 D.Stanojkovic 08 Mar 04 New timmings added and changed + timming model labeling + V1.2 J.Stoickov 08 Dec 10 Changed timming model labeling + V1.3 S.Petrovic 09 May 29 Timing ranges corrected + V1.4 V.Mancev 12 Jan 10 Latest datasheet update + +1ns +s25fl064p + +S25FL064P0XMFI000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI020_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI023_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI030_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI033_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV020_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV023_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV030_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV033_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + + (DELAY (ABSOLUTE + (COND ~dual (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual (IOPATH SCK SO (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (COND dual (IOPATH SCK SI (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + (COND dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual && CSNeg (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK HOLDNeg (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK WPNeg (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) +)) +(TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND fast_rd (negedge SCK)) (4.5)) + (WIDTH (COND fast_rd (posedge SCK)) (4.5)) + (WIDTH (COND dual_rd (negedge SCK)) (4.5)) + (WIDTH (COND dual_rd (posedge SCK)) (4.5)) + (WIDTH (COND rd (negedge SCK)) (4.5)) + (WIDTH (COND rd (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (PERIOD (COND fast_rd SCK) (9.6)) + (PERIOD (COND rd SCK) (25.0)) + (PERIOD (COND rd_jid SCK) (20.0)) + (PERIOD (COND dual_rd SCK) (12.5)) +) + + + + +S25FL064P0XMFI000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI020_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI023_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI030_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI033_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV020_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV023_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV030_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV033_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + + (DELAY (ABSOLUTE + (COND ~dual (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5))) + (COND dual (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (COND dual (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual && CSNeg (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK HOLDNeg (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK WPNeg (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) +)) +(TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND fast_rd (negedge SCK)) (4.5)) + (WIDTH (COND fast_rd (posedge SCK)) (4.5)) + (WIDTH (COND dual_rd (negedge SCK)) (4.5)) + (WIDTH (COND dual_rd (posedge SCK)) (4.5)) + (WIDTH (COND rd (negedge SCK)) (4.5)) + (WIDTH (COND rd (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (PERIOD (COND fast_rd SCK) (9.6)) + (PERIOD (COND rd SCK) (25.0)) + (PERIOD (COND rd_jid SCK) (20.0)) + (PERIOD (COND dual_rd SCK) (12.5)) +) + + + + +S25FL064P0XMFI000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI020_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI023_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI030_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI033_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV020_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV023_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV030_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV033_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + + (DELAY (ABSOLUTE + (COND ~dual (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5))) + (COND dual (IOPATH SCK SO (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (COND dual (IOPATH SCK SI (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + (COND dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual && CSNeg (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK HOLDNeg (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK WPNeg (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) +)) +(TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND fast_rd (negedge SCK)) (4.5)) + (WIDTH (COND fast_rd (posedge SCK)) (4.5)) + (WIDTH (COND dual_rd (negedge SCK)) (4.5)) + (WIDTH (COND dual_rd (posedge SCK)) (4.5)) + (WIDTH (COND rd (negedge SCK)) (4.5)) + (WIDTH (COND rd (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (PERIOD (COND fast_rd SCK) (9.6)) + (PERIOD (COND rd SCK) (25.0)) + (PERIOD (COND rd_jid SCK) (20.0)) + (PERIOD (COND dual_rd SCK) (12.5)) +) + + + diff --git a/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_vhd.ftm b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_vhd.ftm new file mode 100644 index 0000000..dde01da --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/model/s25fl064p_vhd.ftm @@ -0,0 +1,242 @@ + +FMF Timing for s25fl064p Parts + + +version: | author: | mod date: | changes made: + V1.0 D.Stanojkovic 08 Jan 22 Initial release + V1.1 D.Stanojkovic 08 Mar 04 New timmings added and changed + timming model labeling + V1.2 J.Stoickov 08 Dec 10 Changed timming model labeling + V1.3 S.Petrovic 09 May 29 Timing ranges corrected + V1.4 V.Mancev 12 Jan 12 Latest datasheet update + +1ns +s25fl064p + +S25FL064P0XMFI000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV000_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV001_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV003_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI020_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI023_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI030_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI033_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV020_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV023_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV030_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV033_F_30pF Spansion, S25FL064P_00_05, November 18, 2011 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8)) + (IOPATH SCK SI (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5)) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND serial_fast (negedge SCK)) (4.5)) + (WIDTH (COND serial_fast (posedge SCK)) (4.5)) + (WIDTH (COND dual (negedge SCK)) (4.5)) + (WIDTH (COND dual (posedge SCK)) (4.5)) + (WIDTH (COND serial (negedge SCK)) (4.5)) + (WIDTH (COND serial (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgm (posedge CSNeg)) (50)) + (PERIOD (COND serial_fast_rd SCK) (9.6)) + (PERIOD (COND serial_rd SCK) (25.0)) + (PERIOD (COND serial_rd_jid SCK) (20.0)) + (PERIOD (COND dual_fast_rd SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1200000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/EP) (DELAY (ABSOLUTE (DEVICE(1000000:1200000:2400000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(40e7:50e7:2e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(50e9:64e9:128e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE(DEVICE(100000000:100000000:100000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300000:300000:300000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PE) (DELAY (ABSOLUTE (DEVICE(20e7:20e7:80e7) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + + +S25FL064P0XMFI000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV000_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV001_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV003_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI020_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI023_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI030_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI033_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV020_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV023_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV030_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV033_R_30pF Spansion, S25FL064P_00_05, November 18, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5)) + (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8)) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND serial_fast (negedge SCK)) (4.5)) + (WIDTH (COND serial_fast (posedge SCK)) (4.5)) + (WIDTH (COND dual (negedge SCK)) (4.5)) + (WIDTH (COND dual (posedge SCK)) (4.5)) + (WIDTH (COND serial (negedge SCK)) (4.5)) + (WIDTH (COND serial (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgm (posedge CSNeg)) (50)) + (PERIOD (COND serial_fast_rd SCK) (9.6)) + (PERIOD (COND serial_rd SCK) (25.0)) + (PERIOD (COND serial_rd_jid SCK) (20.0)) + (PERIOD (COND dual_fast_rd SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1200000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/EP) (DELAY (ABSOLUTE (DEVICE(1000000:1200000:2400000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(40e7:50e7:2e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(50e9:64e9:128e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE(DEVICE(100000000:100000000:100000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300000:300000:300000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PE) (DELAY (ABSOLUTE (DEVICE(20e7:20e7:80e7) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + + +S25FL064P0XMFI000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFI003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFI003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XMFV003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV000_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV001_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XNFV003_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI020_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI023_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI030_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHI033_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV020_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV023_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV030_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +S25FL064P0XBHV033_R_15pF Spansion, S25FL064P_00_05, November 18, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5)) + (IOPATH SCK SI (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7)) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND serial_fast (negedge SCK)) (4.5)) + (WIDTH (COND serial_fast (posedge SCK)) (4.5)) + (WIDTH (COND dual (negedge SCK)) (4.5)) + (WIDTH (COND dual (posedge SCK)) (4.5)) + (WIDTH (COND serial (negedge SCK)) (4.5)) + (WIDTH (COND serial (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgm (posedge CSNeg)) (50)) + (PERIOD (COND serial_fast_rd SCK) (9.6)) + (PERIOD (COND serial_rd SCK) (25.0)) + (PERIOD (COND serial_rd_jid SCK) (20.0)) + (PERIOD (COND dual_fast_rd SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1200000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/EP) (DELAY (ABSOLUTE (DEVICE(1000000:1200000:2400000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(40e7:50e7:2e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(50e9:64e9:128e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE(DEVICE(100000000:100000000:100000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300000:300000:300000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PE) (DELAY (ABSOLUTE (DEVICE(20e7:20e7:80e7) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl064p/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl064p/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl064p/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064p/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/flash/serial/S25fl128k/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl128k/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl128k/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl128k/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 vital-amd-serial-s25fl-REL-s25fl128k-2010-10-08-1.tar.gz +# Release Date (DD/MM/YYYY) => 08/10/2010 +# Release Version => 1.0 + +########################################## diff --git a/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.v b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.v new file mode 100644 index 0000000..50cdf02 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.v @@ -0,0 +1,4276 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl128k.v +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2010 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 R.Prokopovic 10 Oct 08 Initial +// +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL128K +// +// Description: 128 Megabit Serial Flash Memory +// +/////////////////////////////////////////////////////////////////////////////// +// Comments : +// +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl128k + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + HOLDNeg, + WPNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + inout SI ; + inout SO ; + input SCK ; + input CSNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + // ***** internal delays ********************* + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGRES_out ; + reg ERSRES_out ; + reg PRGRES_in ; + reg ERSRES_in ; + reg WRR_in ; + reg WRR_out ; + reg DP_in ; + reg DP_out ; + reg RES_in ; + reg RES_out ; + // ******* event control registers ************ + reg PRGSUSP_out_event; + reg PRGRES_out_event; + reg ERSSUSP_out_event; + reg ERSRES_out_event; + reg PGSUSP_event; + reg PGRES_event; + reg ESUSP_event; + reg ERES_event; + reg next_state_event; + + reg rising_edge_PoweredUp; + reg rising_edge_RES_out; + reg rising_edge_PRGRES_out; + reg rising_edge_PSTART; + reg rising_edge_WSTART; + reg rising_edge_VLTSTART; + reg rising_edge_ESTART; + reg rising_edge_prot_bits; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + reg DataDriveOut_SO = 1'bZ ; + reg DataDriveOut_SI = 1'bZ ; + reg DataDriveOut_HOLD = 1'bZ ; + reg DataDriveOut_WP = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl128k.mem"; + parameter screg_file_name = "s25fl128kscreg.mem";//"none"; + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl128k"; + parameter MaxData = 255; + parameter AddrRANGE = 24'hFFFFFF; + parameter PageNum = 16'hFFFF; + parameter SecSize_4 = 12'hFFF; + parameter SecSize_32 = 16'h7FFF; + parameter SecSize_64 = 16'hFFFF; + parameter Blk_4_Num = 4095; + parameter Blk_64_Num = 255; + parameter Blk_32_Num = 511; + parameter SFDP_HiAddr = 8'hFF; + parameter SFDP_LoAddr = 8'h00; + parameter SecReg_HiAddr = 8'hFF; + parameter SecReg_LoAddr = 8'h00; + parameter SCREG_LoAddr = 12'h000; + parameter SCREG_HiAddr = 12'h2FF; + parameter BYTE = 8; + + // Manufacturer Identification and Device Identification + parameter Manuf_ID = 8'hEF; + parameter Device_ID1 = 8'h17; + parameter Device_ID2 = 8'h40; + parameter Device_ID3 = 8'h18; + parameter unique_id = 64'h000000000000ABAB; + + // If speedsimulation is needed uncomment following line + +// `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; +// reg ERSRES ; + + reg WDONE ; + reg WSTART ; + reg VLTSTART ; + reg VLTDONE ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + + // Programming buffer + integer WByte[0:255]; + + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRP0; + wire SEC; + wire TB; + wire BP2; + wire BP1; + wire BP0; + wire WEL; + wire BUSY; + assign SRP0 = Status_reg1[7]; + assign SEC = Status_reg1[6]; + assign TB = Status_reg1[5]; + assign BP2 = Status_reg1[4]; + assign BP1 = Status_reg1[3]; + assign BP0 = Status_reg1[2]; + assign WEL = Status_reg1[1]; + assign BUSY = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire SUS; + wire CMP; + + wire [2:0]LB; + wire QE; + wire SRP1; + assign SUS = Status_reg2[7]; + assign CMP = Status_reg2[6]; + assign LB = Status_reg2[5:3]; + assign QE = Status_reg2[1]; + assign SRP1 = Status_reg2[0]; + + reg[15:0] Status_reg; // Status_reg2 & Status_reg1 + reg[15:0] Status_reg_in; // Status_reg2 & Status_reg1 + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [Blk_4_Num:0] Sec_Prot = {4095{1'b0}}; + + // Security registers array + integer Security_Reg[SCREG_LoAddr:SCREG_HiAddr]; + integer Security_Reg1[SecReg_LoAddr:SecReg_HiAddr]; + integer Security_Reg2[SecReg_LoAddr:SecReg_HiAddr]; + integer Security_Reg3[SecReg_LoAddr:SecReg_HiAddr]; + + // SFDP register array + integer SFDP_array[SFDP_LoAddr:SFDP_HiAddr]; + + /////////////////////////////////////////////////////////////////////////// + // Command Register + reg write; + reg read_out; + reg slow_read; + reg dual_read; + reg fast_read; + reg quad_read; + reg pp_quad; + reg oe = 1'b0; + event oe_event; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + integer wr_cnt; + integer cnt; + integer Byte_number = 0; + integer read_cnt = 0; + integer read_addr = 0; + reg[7:0] data_out; + reg[23:0] ident_out; + reg[15:0] ident_out2; + integer AddrLo; + integer AddrHi; + integer AddrLo_ers; + integer AddrHi_ers; + integer AddrLo_wrap; + integer AddrHi_wrap; + + reg change_prot_bits = 0; + + //Address + integer Address = 0; // 0 - AddrRANGE + reg change_addr; + + //Sector and subsector addresses + integer SA = 0; + integer sect; + integer sect_tmp_pg; + integer sect_tmp_ers; + integer sfdp_addr; + integer w_size; + + reg hold_mode = 1'b0; + + time SCK_cycle = 0; + time prev_SCK; + + // Flag for release from deep power down, read ID or not + reg res_flag; + reg pg_screg_flag = 1'b0; + reg ers_screg_flag = 1'b0; + reg wren_vlt_flag = 1'b0; + reg susp_flag = 1'b0; + // timing check violation + reg Viol = 1'b0; + reg sr_read = 1'b0; + reg read_id = 1'b0; + + reg glitch = 1'b0; + time SCK_SO_2; + time start_rdid; + time out_time; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + //VHDL VITAL CheckEnable equivalents + wire rd_slow; + assign rd_slow = slow_read; + wire rd_fast; + assign rd_fast = fast_read && ~quad_read; + wire quad_spi; + assign quad_spi = pp_quad || quad_read; + wire quad_rd; + assign quad_rd = deg_holdin && QE && ~dual_read && (SIOut_z != 1'bz); + wire quad_pg; + assign quad_pg = QE && WEL && pp_quad; + wire wr_prot; + assign wr_prot = SRP0 && WEL; + wire dual_rd; + assign dual_rd = dual_read ; + wire power; + assign power = PoweredUp; + wire hold_cond; + assign hold_cond = PoweredUp && ~QE && HOLDNeg_in != 1'bX; + wire any_read; + assign any_read = (dual_read || quad_read || slow_read || fast_read) + && ~WEL && ~sr_read; + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in !== 1'bZ) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + assign deg_sin = deq_sin && ~read_out; /*&& (~any_read);*/ + + wire pg_ers; + assign pg_ers = PSTART || ESTART || sr_read; + +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_1 =1; // tCLQV1 + specparam tpd_SCK_SO_2 =1; // tCLQV2 -for read ID instructions + specparam tpd_CSNeg_SO =1; // tSHQZ (tDIS) + specparam tpd_HOLDNeg_SO =1; // tHLQZ, tHHQX + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; // tSLCH, tSHCH + specparam tsetup_SI_SCK =1; // tDVCH + specparam tsetup_HOLDNeg_SCK =1; // tHLCH, tHHCH + specparam tsetup_WPNeg_CSNeg =1; // tWHSL + + //thold values: hold times + specparam thold_CSNeg_SCK =1; // tCHSL, tCHSH + specparam thold_SI_SCK =1; // tCHDX + specparam thold_HOLDNeg_SCK =1; // tCHHL, tCHHH + specparam thold_WPNeg_CSNeg =1; // tSHWL + + // tpw values: pulse width + specparam tpw_SCK_slow_posedge =1; // tCH + specparam tpw_SCK_slow_negedge =1; // tCL + specparam tpw_SCK_fast_posedge =1; // tCH + specparam tpw_SCK_fast_negedge =1; // tCL + specparam tpw_SCK_quad_posedge =1; // tCH + specparam tpw_SCK_quad_negedge =1; // tCL + specparam tpw_CSNeg_read_posedge =1; // tSHSL1 + specparam tpw_CSNeg_pger_posedge =1; // tSHSL2 + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_slow =1; + specparam tperiod_SCK_fast =1; + specparam tperiod_SCK_quad =1; + + // tdevice values: values for internal delays + + // VCC (min) to CS# Low + specparam tdevice_PU = 1e7; // 10 us + // CS# High to Power Down Mode -- tDP + specparam tdevice_DP = 3e6; // 3 us + // CS# High to StandBy mode without Electronic Signature read + specparam tdevice_RES1 = 3e6; // 3 us + // CS# High to StandBy mode with Electronic Signature read + specparam tdevice_RES2 = 18e5; // 1.8 us + // CS# High to next Instruction after Suspend + specparam tdevice_SUS = 2e7; // 20 us + // Resume Suspend to Program/Erase time + specparam tdevice_PRGSUSP = 2e5; // 200 ns + + `ifdef SPEEDSIM + // Page Program Time + specparam tdevice_PP = 3e8; // 30 us + // Byte Program Time (First Byte) + specparam tdevice_BP1 = 5e5; // 0.5 us + // Additional Byte Program Time (After First Byte) + specparam tdevice_BP2 = 12e4; // 120 ns + // Sector Erase Time (4KB) + specparam tdevice_SE = 4e9; // 4 ms + // Block Erase Time (32KB) + specparam tdevice_BE1 = 8e9; // 8 ms + // Block Erase Time (64KB) + specparam tdevice_BE2 = 1e10; // 10 ms + // Chip Erase Time + specparam tdevice_CE = 40e10; // 400 ms + // Write Status Register Time + specparam tdevice_WRR = 15e7; // 150 us + // Write Volatile Status Register Time + specparam tdevice_VRR = 5e4; // 50 ns + `else + // Page Program Time + specparam tdevice_PP = 3e9; // 3 ms + // Byte Program Time (First Byte) + specparam tdevice_BP1 = 5e7; // 50 us + // Additional Byte Program Time (After First Byte) + specparam tdevice_BP2 = 12e6; // 12 us + // Sector Erase Time (4KB) + specparam tdevice_SE = 4e11; // 400 ms + // Block Erase Time (32KB) + specparam tdevice_BE1 = 8e11; // 800 ms + // Block Erase Time (64KB) + specparam tdevice_BE2 = 1e12; // 1000 ms + // Chip Erase Time + specparam tdevice_CE = 40e12; // 40 s + // Write Status Register Time + specparam tdevice_WRR = 15e9; // 15 ms + // Write Volatile Status Register Time + specparam tdevice_VRR = 5e4; // 50 ns + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~read_id) (SCK => SO) = tpd_SCK_SO_1; + if ((~glitch || quad_read) && read_id) (SCK => SO) = tpd_SCK_SO_2; + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (~quad_read) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if ((dual_read || quad_read) && ~read_id) (SCK => SI) = tpd_SCK_SO_1; + if (dual_read && read_id && ~glitch) (SCK => SI) = tpd_SCK_SO_2; + if (quad_read && read_id) (SCK => SI) = tpd_SCK_SO_2; + if (CSNeg && ~deg_sin) (CSNeg => SI) = tpd_CSNeg_SO; + if (~quad_read && dual_read) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + if (quad_read && ~read_id) (SCK => WPNeg) = tpd_SCK_SO_1; + if (quad_read && read_id) (SCK => WPNeg) = tpd_SCK_SO_2; + if (quad_read && ~read_id) (SCK => HOLDNeg) = tpd_SCK_SO_1; + if (quad_read && read_id) (SCK => HOLDNeg) = tpd_SCK_SO_2; + if (CSNeg && QE) (CSNeg => SI) = tpd_CSNeg_SO; + if (CSNeg && QE) (CSNeg => WPNeg) = tpd_CSNeg_SO; + if (CSNeg && QE) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& power, + tsetup_CSNeg_SCK , Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK , Viol); + $setup ( SO , posedge SCK &&& quad_pg, + tsetup_SI_SCK , Viol); + $setup ( WPNeg , posedge SCK &&& quad_pg, + tsetup_SI_SCK , Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_pg, + tsetup_SI_SCK , Viol); + $setup ( HOLDNeg , posedge SCK &&& hold_cond, + tsetup_HOLDNeg_SCK , Viol); + $setup ( WPNeg , negedge CSNeg &&& WPNeg, + tsetup_WPNeg_CSNeg , Viol); + + $hold ( posedge SCK &&& power, CSNeg, + thold_CSNeg_SCK , Viol); + $hold ( posedge SCK &&& deg_sin, SI , + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& quad_pg, SO , + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& quad_pg, WPNeg, + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& quad_pg, HOLDNeg, + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& hold_cond, HOLDNeg, + thold_HOLDNeg_SCK, Viol); + $hold ( posedge CSNeg &&& wr_prot, WPNeg, + thold_WPNeg_CSNeg, Viol); + + $width ( posedge SCK &&& rd_slow , tpw_SCK_slow_posedge); + $width ( negedge SCK &&& rd_slow , tpw_SCK_slow_negedge); + $width ( posedge SCK &&& rd_fast , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& rd_fast , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& quad_spi , tpw_SCK_quad_posedge); + $width ( negedge SCK &&& quad_spi , tpw_SCK_quad_negedge); + $width ( posedge CSNeg &&& any_read , tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& pg_ers , tpw_CSNeg_pger_posedge); + + $period ( posedge SCK &&& rd_slow , tperiod_SCK_slow); + $period ( posedge SCK &&& rd_fast , tperiod_SCK_fast); + $period ( posedge SCK &&& quad_spi , tperiod_SCK_quad); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 4'd0; + parameter WRITE_SR = 4'd1; + parameter PAGE_PG = 4'd2; + parameter PG_SUSP = 4'd3; + parameter SECTOR_ERS = 4'd4; + parameter BULK_ERS = 4'd5; + parameter ERS_SUSP = 4'd6; + parameter ERS_SUSP_PG = 4'd7; + parameter PG_SUSP_ERS = 4'd8; + parameter DP_DOWN = 4'd9; + parameter WRITE_SR_V = 4'd10; + + reg [3:0] current_state; + reg [3:0] next_state; + +// Instruction type + parameter NONE = 6'd0; + parameter WREN = 6'd1; // 06h + parameter WRENV = 6'd2; // 50h + parameter WRDI = 6'd3; // 04h + parameter RDSR = 6'd4; // 05h + parameter RDSR2 = 6'd5; // 35h + parameter WRR = 6'd6; // 01h + parameter READ = 6'd7; // 03h + parameter FAST_READ = 6'd8; // 0Bh + parameter FAST_DREAD = 6'd9; // 3Bh + parameter FAST_QREAD = 6'd10; // 6Bh + parameter FAST_DREAD_2 = 6'd11; // BBh + parameter FAST_QREAD_4 = 6'd12; // EBh + parameter W_QREAD = 6'd13; // E7h + parameter WOCT_QREAD = 6'd14; // E3h + parameter SET_BURST_WRAP = 6'd15; // 77h + parameter CONT_RD_RST = 6'd16; // FFh or FFFFH + parameter PP = 6'd17; // 02h + parameter QPP = 6'd18; // 32h + parameter SE = 6'd19; // 20h + parameter BE_32 = 6'd20; // 52h + parameter BE_64 = 6'd21; // D8h + parameter CE = 6'd22; // C7h or 60h + parameter ERS_PG_SUSP = 6'd23; // 75h + parameter ERS_PG_RES = 6'd24; // 7Ah + parameter DP = 6'd25; // B9h + parameter RES_RD_ID = 6'd26; // ABh + parameter RDID = 6'd27; // 90h + parameter RDID_DUAL = 6'd28; // 92h + parameter RDID_QUAD = 6'd29; // 94h + parameter RD_UNIQ_ID = 6'd30; // 4Bh + parameter RDIDJ = 6'd31; // 9Fh + parameter RD_SFDP = 6'd32; // 5Ah + parameter ERS_SCREG = 6'd33; // 44h + parameter PG_SCREG = 6'd34; // 42h + parameter RD_SCREG = 6'd35; // 48h + + reg [5:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + always @(PoweredUp or falling_edge_CSNeg_ipd) + begin:CheckCEOnPowerUP + if ((~PoweredUp) && falling_edge_CSNeg_ipd) + $display ("Device is selected during Power Up"); + end + + initial + begin : Init + write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; +// cnt = 0; + PGSUSP = 1'b0; + PGRES = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + PDONE = 1'b1; + PSTART = 1'b0; + EDONE = 1'b1; + ESTART = 1'b0; + WDONE = 1'b1; + WSTART = 1'b0; + VLTDONE = 1'b1; + VLTSTART = 1'b0; + + DP_in = 1'b0; + DP_out = 1'b0; + RES_in = 1'b0; + RES_out = 1'b0; + PRGRES_in = 1'b0; + ERSRES_in = 1'b0; + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl128k.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=SCREG_LoAddr;i<=SCREG_HiAddr;i=i+1) + begin + Security_Reg[i] = MaxData; + end + + if (UserPreload && !(screg_file_name == "none")) + begin + //s25fl128kSCREG memory file + // / - comment + // @aaa - stands for address of specific Security register + // dd -
is byte to be written at SCREG(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(screg_file_name,Security_Reg); + end + for (i=0;i<=255;i=i+1) + begin + Security_Reg1[i] = Security_Reg[i]; + Security_Reg2[i] = Security_Reg[256+i]; + Security_Reg3[i] = Security_Reg[512+i]; + end + end + + /////////////////////////////////////////////////////////////////////////// + // SFDP - Serial Flash Discoverable Parameter register + initial + begin: InitSFDP + integer i; + integer j; + SFDP_array[8'h00] = 8'h53; + SFDP_array[8'h01] = 8'h46; + SFDP_array[8'h02] = 8'h44; + SFDP_array[8'h03] = 8'h50; + SFDP_array[8'h04] = 8'h01; + SFDP_array[8'h05] = 8'h01; + SFDP_array[8'h06] = 8'h00; + SFDP_array[8'h07] = 8'hFF; + SFDP_array[8'h08] = 8'hEF; + SFDP_array[8'h09] = 8'h00; + SFDP_array[8'h0A] = 8'h01; + SFDP_array[8'h0B] = 8'h04; + SFDP_array[8'h0C] = 8'h80; + SFDP_array[8'h0D] = 8'h00; + SFDP_array[8'h0E] = 8'h00; + SFDP_array[8'h0F] = 8'hFF; + SFDP_array[8'h10] = 8'hEF; + SFDP_array[8'h11] = 8'h00; + SFDP_array[8'h12] = 8'h01; + SFDP_array[8'h13] = 8'h00; + SFDP_array[8'h14] = 8'h90; + SFDP_array[8'h15] = 8'h00; + SFDP_array[8'h16] = 8'h00; + SFDP_array[8'h17] = 8'hFF; + + for (i=24;i<=127;i=i+1) + begin + SFDP_array[i] = MaxData; + end + + SFDP_array[8'h80] = 8'hE5; + SFDP_array[8'h81] = 8'h20; + SFDP_array[8'h82] = 8'hF1; + SFDP_array[8'h83] = 8'hFF; + SFDP_array[8'h84] = 8'hFF; + SFDP_array[8'h85] = 8'hFF; + SFDP_array[8'h86] = 8'hFF; + SFDP_array[8'h87] = 8'h07; + SFDP_array[8'h88] = 8'h44; + SFDP_array[8'h89] = 8'hEB; + SFDP_array[8'h8A] = 8'h08; + SFDP_array[8'h8B] = 8'h6B; + SFDP_array[8'h8C] = 8'h08; + SFDP_array[8'h8D] = 8'h3B; + SFDP_array[8'h8E] = 8'h80; + SFDP_array[8'h8F] = 8'hBB; + + for (i=144;i<=255;i=i+1) + begin + SFDP_array[i] = MaxData; + end + + end + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + always @(posedge DP_in) + begin:TDPr + #tdevice_DP DP_out = DP_in; + end + always @(negedge DP_in) + begin:TDPf + #1 DP_out = DP_in; + end + + always @(posedge RES_in) + begin:TRESr + if (res_flag) // res_flag is '1' when read ID after resume DP + // res_flag will be set to '1' in DUMMY_BYTES if read ID + #tdevice_RES2 RES_out = RES_in; + else + #tdevice_RES1 RES_out = RES_in; + end + always @(negedge RES_in) + begin:TRESf + #1 RES_out = RES_in; + end + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_SUS PRGSUSP_out = 1'b1; + end + + always @(posedge PRGRES_in) + begin:ProgSuspend + PRGRES_out = 1'b0; + #tdevice_PRGSUSP PRGRES_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_SUS ERSSUSP_out = 1'b1; + end + + always @(posedge ERSRES_in) + begin:ERSresume + ERSRES_out = 1'b0; + #tdevice_PRGSUSP ERSRES_out = 1'b1; + end + + always @(posedge ERSRES_in or posedge PRGRES_in) + begin + susp_flag = 1'b1; + #tdevice_SUS susp_flag = 1'b0; + end + + always @(next_state or PoweredUp) + begin: StateTransition + if (PoweredUp) + begin + current_state = next_state; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer wrap_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [15:0] opcode_double; + reg [7:0] opcode_in; + reg [15:0] opcode_double_in; + reg [23:0] addr_bytes; + reg [23:0] Address_in; + reg [7:0] mode_byte; + reg [7:0] mode_in; + reg [7:0] wrap_in; + reg [7:0] wrap_byte; + + integer quad_data_in [0:511]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle + integer i; + integer j; + integer k; + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + bus_cycle_state = OPCODE_BYTE; + Instruct = NONE; + write = 1'b1; + opcode_cnt = 0; + addr_cnt = 0; + data_cnt = 0; + mode_cnt = 0; + wrap_cnt = 0; + dummy_cnt = 0; + end + else if (bus_cycle_state==DATA_BYTES && (mode_byte[5:4]==2'b10)) + begin + bus_cycle_state = ADDRESS_BYTES; + dummy_cnt = 0; + opcode_cnt = 0; + end + end + if (rising_edge_SCK_ipd && PoweredUp) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE : + begin + if ((HOLDNeg_in && ~QE) || QE) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + if (opcode_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + opcode[i] = opcode_in[7-i]; + end + case(opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b01010000 : // 50h + begin + Instruct = WRENV; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 05h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FAST_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00111011 : // 3Bh + begin + Instruct = FAST_DREAD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01101011 : // 6Bh + begin + Instruct = FAST_QREAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b10111011 : // BBh + begin + Instruct = FAST_DREAD_2; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11101011 : // EBh + begin + Instruct = FAST_QREAD_4; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b11100111 : // E7h + begin + Instruct = W_QREAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b11100011 : // E3h + begin + Instruct = WOCT_QREAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b01110111 : // 77h + begin + Instruct = SET_BURST_WRAP; + if (QE) + bus_cycle_state = DUMMY_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b11111111 : // FFh + begin + Instruct = CONT_RD_RST; + bus_cycle_state = MODE_BYTE; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010 : // 32h + begin + Instruct = QPP; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b00100000 : // 20h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01010010 : // 52h + begin + Instruct = BE_32; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = BE_64; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11000111, 8'b01100000 : // C7h or 60h + begin + Instruct = CE; + bus_cycle_state = DATA_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERS_PG_SUSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERS_PG_RES; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = DP; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011: // ABh + begin + Instruct = RES_RD_ID; + bus_cycle_state = DUMMY_BYTES; + end + 8'b10010000: // 90h + begin + Instruct = RDID; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10010010: // 92h + begin + Instruct = RDID_DUAL; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10010100: // 94h + begin + Instruct = RDID_QUAD; + if (QE) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + end + 8'b01001011: // 4Bh + begin + Instruct = RD_UNIQ_ID; + bus_cycle_state = DUMMY_BYTES; + end + 8'b10011111: // 9Fh + begin + Instruct = RDIDJ; + bus_cycle_state = DATA_BYTES; + end + 8'b01011010: // 5Ah + begin + Instruct = RD_SFDP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000100: // 44h + begin + Instruct = ERS_SCREG; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000010: // 42h + begin + Instruct = PG_SCREG; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001000: // 48h + begin + Instruct = RD_SCREG; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + else + $display("Device is in HOLD mode, opcode"); + end // end of OPCODE_BYTE + + ADDRESS_BYTES : + begin + if ((HOLDNeg_in && ~QE) || QE) + begin + if (Instruct == READ || Instruct == FAST_READ || + Instruct == FAST_DREAD || Instruct == RDID || + Instruct == SE || Instruct == PP || + Instruct == RD_SCREG || Instruct == PG_SCREG || + Instruct == RD_SFDP || Instruct == BE_32 || + Instruct == BE_64 || Instruct == ERS_SCREG || + ((Instruct == QPP || Instruct == FAST_QREAD) + && QE)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes ; + change_addr = 1'b1; + #1000 change_addr = 1'b0; + if (Instruct == PP || Instruct == QPP + || Instruct == READ || Instruct == SE + || Instruct == BE_32 || Instruct == BE_64 + || Instruct == RDID || Instruct == PG_SCREG + || Instruct == ERS_SCREG) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct == RDID_DUAL || + Instruct == FAST_DREAD_2) + begin + if (SO_in !== 1'bX) + begin + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for (i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes ; + change_addr = 1'b1; + #1000 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + begin + if (mode_byte[5:4] == 2'b10) + begin + opcode_double_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + + if (opcode_cnt == 2*BYTE) + begin + for (i=0;i<=15;i=i+1) + begin + opcode_double[i] = + opcode_double_in[15-i]; + end + if (opcode_double == 16'hFFFF) + begin + Instruct = CONT_RD_RST; + bus_cycle_state = MODE_BYTE; + end + end + end + end + end + else if (QE && (Instruct == FAST_QREAD_4 || + Instruct == W_QREAD || + Instruct == WOCT_QREAD || + Instruct == RDID_QUAD)) + begin + if (SO_in !== 1'bX) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes ; + change_addr = 1'b1; + #1000 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + begin + if (mode_byte[5:4] == 2'b10) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + if (opcode_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + opcode[i] = opcode_in[7-i]; + end + if (opcode == 8'hFF) + begin + Instruct = CONT_RD_RST; + bus_cycle_state = MODE_BYTE; + end + end + end + end + end + end + else + $display("Device is in HOLD mode, addr"); + end // end of ADDRESS_BYTES + + MODE_BYTE: + begin + if (QE || (HOLDNeg_in && ~QE)) + begin + if (Instruct == SET_BURST_WRAP && QE) + begin + wrap_in[4*wrap_cnt] = HOLDNeg_in; + wrap_in[4*wrap_cnt+1] = WPNeg_in; + wrap_in[4*wrap_cnt+2] = SO_in; + wrap_in[4*wrap_cnt+3] = SI_in; + wrap_cnt = wrap_cnt + 1; + if (wrap_cnt == BYTE/4) + begin + wrap_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + wrap_byte[i] = wrap_in[7-i]; + end + bus_cycle_state = DATA_BYTES; + end + case (wrap_byte[6:5]) + 2'b00: + w_size = 8; + 2'b01: + w_size = 16; + 2'b10: + w_size = 32; + 2'b11: + w_size = 64; + endcase + end + else if ((Instruct == FAST_QREAD_4 || + Instruct == WOCT_QREAD || + Instruct == W_QREAD || + Instruct == RDID_QUAD ) && QE) + // FAST_QREAD_4,WOCT_QREAD,W_QREAD,RDID_QUAD + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_byte[i] = mode_in[7-i]; + end + if (Instruct == WOCT_QREAD) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct == RDID_DUAL || + Instruct == FAST_DREAD_2) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_byte[i] = mode_in[7-i]; + end + bus_cycle_state = DATA_BYTES; + end + end + end + else + $display("Device is in HOLD mode, mode"); + + end // end of MODE_BYTE + + DUMMY_BYTES: + begin + if (QE || (HOLDNeg_in && ~QE)) + begin + if ((Instruct == FAST_QREAD_4 || + Instruct == RDID_QUAD) && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE/2) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct == W_QREAD && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE/4) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct == SET_BURST_WRAP && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE/4) + bus_cycle_state = MODE_BYTE; + end + else if (Instruct == FAST_QREAD && QE) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct==FAST_READ || Instruct==RD_SFDP + || Instruct == FAST_DREAD || Instruct == RD_SCREG) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct == RD_UNIQ_ID) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 4*BYTE) + bus_cycle_state = DATA_BYTES; + end + else // for RES_RD_ID + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + end + else + $display("Device is in HOLD mode, dummy"); + end // end of DUMMY_BYTES + + DATA_BYTES: + begin + if (Instruct == PP || Instruct == WRR || + Instruct == PG_SCREG) + begin + if ((HOLDNeg_in && ~QE) || QE) + begin + if (data_cnt > 2047) + //In case of serial mode and PP,if more than + //256 bytes are sent to the device + begin + if (bit_cnt == 0) + begin + for (i=0;i<=(255*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[2040 + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + else + $display("Device is in HOLD mode, data"); + end + else if (Instruct == QPP && QE) + begin + pp_quad = 1'b1; + quad_nybble = {HOLDNeg_in, WPNeg_in, + SO_in, SI_in}; + if (data_cnt > 511) + begin + //In case of quad mode and QPP,if more than + // 256 bytes are sent to the device + for(i=0;i<=510;i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[511] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + end // end of DATA_BYTES + endcase // end of case bus_cycle_state + end // end of ~CSNeg + end // end of rising_edge_SCK + + if (falling_edge_SCK_ipd) + begin + if ((bus_cycle_state == DATA_BYTES) && (~CSNeg_ipd)) + begin + if (((Instruct == RDSR || Instruct == RDSR2 || + Instruct == FAST_READ || Instruct == FAST_DREAD || + Instruct == FAST_DREAD_2 || Instruct == RES_RD_ID || + Instruct == RDID || Instruct == RDID_DUAL || + Instruct == RD_UNIQ_ID || Instruct == RDIDJ || + Instruct == RD_SFDP || Instruct == RD_SCREG || + Instruct == READ) && ((HOLDNeg_in && ~QE) || QE)) || + ((Instruct == FAST_QREAD || Instruct == FAST_QREAD_4 || + Instruct == W_QREAD || Instruct == RDID_QUAD || + Instruct == WOCT_QREAD) && QE)) + begin + read_out = 1'b1; + #1 read_out = 1'b0; + end + end // end of ~CSNeg_ipd + end // end of falling_edge_SCK_ipd + + if (rising_edge_CSNeg_ipd) + begin + if (bus_cycle_state==MODE_BYTE && Instruct == CONT_RD_RST) + begin + mode_byte[5:4] = 2'b11; + mode_byte[7:6] = 2'b00; + mode_byte[3:0] = 4'b0000; + bus_cycle_state = STAND_BY; + end + else if (bus_cycle_state==DATA_BYTES && ~(mode_byte[5:4]==2'b10)) + begin + bus_cycle_state = STAND_BY; + case (Instruct) + WREN, + WRDI, + SET_BURST_WRAP, + SE, + BE_32, + BE_64, + CE, + ERS_PG_RES, + DP, + ERS_SCREG: + begin + if (data_cnt == 0) + write = 1'b0; + end + + WRENV: + begin + write = 1'b0; + wren_vlt_flag = 1'b1; + end + + RES_RD_ID: + begin + write = 1'b0; + res_flag = 1'b1; + end + + WRR: + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Status_reg2_in[i]= + Data_in[15-i]; + end + end + end + + PP, + PG_SCREG: + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = + Data_in[(i*8) + (7-j)]; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE) + Byte_number = 255; + else + Byte_number = ((data_cnt/8) - 1); + end + end + end + + QPP: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else // if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE/4) + Byte_number = 255; + else + Byte_number = ((data_cnt/2) - 1); + end + end + end + + endcase + end + else if (bus_cycle_state==DATA_BYTES && (mode_byte[5:4]==2'b10)) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = STAND_BY; + if (HOLDNeg_in && (Instruct == RES_RD_ID) && + (dummy_cnt == 0)) + begin + write = 1'b0; + res_flag = 1'b0; + end + end + end // end of rising_edge_CSNeg_ipd + + end // end of Buscycle + + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Page Program + /////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed; + time start; + time duration; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == QPP) || (Instruct == PG_SCREG)) + pob = tdevice_PP; + else + pob = tdevice_BP1; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed = 0; + PDONE = 1'b0; + ->pdone_event; + start = $time; + end + end + + always @(PGSUSP_event) + begin + if ((PGSUSP_event) && PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed = $time - start; + duration = pob - elapsed; + PDONE = 1'b0; + end + end + + always @(PGRES_event) + begin + if ((PGRES_event) && PGRES && (~PDONE)) + begin + start = $time; + ->pdone_event; + end + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #pob PDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Write Status Register Operation + // start + /////////////////////////////////////////////////////////////////////////// + time wob; + always @(WSTART) + begin + wob = tdevice_WRR; + if ((rising_edge_WSTART) && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Volatile Write Status Register Operation + // start + /////////////////////////////////////////////////////////////////////////// + time vob; + always @(VLTSTART) + begin + vob = tdevice_VRR; + if (rising_edge_VLTSTART && VLTDONE) + begin + VLTDONE = 1'b0; + #vob VLTDONE = 1'b1; + end + end + + /////////////////////////////////////////////////////////////////////////// + // Timing control for the Erase Operations + /////////////////////////////////////////////////////////////////////////// + time seo; + time beo32; + time beo64; + time ceo; + event edone_event; + + always @(rising_edge_ESTART) + begin + seo = tdevice_SE; + beo32 = tdevice_BE1; + beo64 = tdevice_BE2; + ceo = tdevice_CE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == CE) + begin + duration = ceo; + end + else if (Instruct == BE_64) + begin + duration = beo64; + end + else if (Instruct == BE_32) + begin + duration = beo32; + end + else + begin + duration = seo; + end + elapsed = 0; + EDONE = 1'b0; + ->edone_event; + start = $time; + end + end + + always @(ESUSP_event) + begin + if ((ESUSP_event) && ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed = $time - start; + duration = duration - elapsed; + EDONE = 1'b0; + end + end + + always @(ERES_event) + begin + if ((ERES_event) && ERES && (~EDONE)) + begin + start = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + + /////////////////////////////////////////////////////////////////////////// + // Main Behavior Process + // combinational process for next state generation + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg rising_edge_VLTDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or rising_edge_DP_out + or rising_edge_PDONE or rising_edge_WDONE or rising_edge_EDONE or + ERSSUSP_out_event or ERSRES_out_event or RES_out or + PRGSUSP_out_event or PRGRES_out_event or rising_edge_VLTDONE) + begin: StateGen1 + + if (rising_edge_PoweredUp) + next_state = IDLE; + else + begin + case (current_state) + IDLE : + begin + if (falling_edge_write) + begin + if (Instruct == WRR && (~SRP1 && + (~SRP0 || (SRP0 && WPNeg)))) + begin + if (WEL && ~wren_vlt_flag) + next_state = WRITE_SR; + else if (~WEL && wren_vlt_flag) + next_state = WRITE_SR_V; + end + else if (Instruct == PP && WEL) + begin + sect = Address / 16'h1000; + sect_tmp_pg = sect; + if (Sec_Prot[sect] == 0) + next_state = PAGE_PG; + end + else if (Instruct == QPP && WEL && QE) + begin + sect = Address / 16'h1000; + sect_tmp_pg = sect; + if (Sec_Prot[sect] == 0) + next_state = PAGE_PG; + end + else if (Instruct == PG_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect < 4 && sect > 0) && LB[sect-1]==0) + next_state = PAGE_PG; + end + else if (Instruct == ERS_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect <= 3) && LB[sect-1]==0) + next_state = SECTOR_ERS; + end + else if ((Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) && WEL) + begin + sect = Address / 16'h1000; + sect_tmp_ers = sect; + if (Sec_Prot[sect] == 0) + next_state = SECTOR_ERS; + end + else if (Instruct == CE && WEL && + ((~CMP && ~BP2 && ~BP1 && ~BP0) || + (CMP && BP2 && BP1 && BP0))) + next_state = BULK_ERS; + else + next_state = IDLE; + end + else if (rising_edge_DP_out) + next_state = DP_DOWN; + end // end of IDLE + + WRITE_SR: + begin + if (rising_edge_WDONE) + next_state = IDLE; + end // end of WRITE_SR + + WRITE_SR_V: + begin + if (rising_edge_VLTDONE) + next_state = IDLE; + end + + PAGE_PG: + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end // end of PAGE_PG + + PG_SUSP: + begin + if (PRGRES_out_event && PRGRES_out == 1) + next_state = PAGE_PG; + else if (falling_edge_write) + begin + if (Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) + begin + sect = Address / 16'h1000; + if ((Sec_Prot[sect] == 0) && (sect != sect_tmp_pg)) + next_state = PG_SUSP_ERS; + end + end + end // end of PG_SUSP + + PG_SUSP_ERS: + begin + if (rising_edge_EDONE) + next_state = PG_SUSP; + else + next_state = PG_SUSP_ERS; + end + + BULK_ERS: + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS: + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP: + begin + if (ERSRES_out_event && ERSRES_out == 1) + next_state = SECTOR_ERS; + else if (falling_edge_write) + begin + if (Instruct == PP || (Instruct == QPP && QE)) + begin + sect = Address / 16'h1000; + if ((Sec_Prot[sect] == 0)&&(sect != sect_tmp_ers)) + next_state = ERS_SUSP_PG; + end + else if (Instruct == PG_SCREG) + begin + sect = Address / 16'h1000; + if ((sect < 4 && sect > 0) && LB[sect-1]==0) + next_state = ERS_SUSP_PG; + end + end + end + + ERS_SUSP_PG: + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else + next_state = ERS_SUSP_PG; + end + + DP_DOWN: + begin + if (rising_edge_RES_out) + next_state = IDLE; + end + + endcase // end case of current_state + end // + end // end of StateGen1 + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + + integer WData [0:255]; + integer Addr; + integer Addr_ers; + integer Addr_tmp; + integer Addr_tmp_2; + integer Addr_tmp_3; + integer Addr_screg; + + always @(oe_event) + begin + oe = 1'b1; + #1000 oe = 1'b0; + end + + always @(rising_edge_read_out or Instruct or rising_edge_SCK_ipd or + change_addr_event or oe or current_state_event or Address or + falling_edge_write or PDONE or rising_edge_WDONE or Instruct_event + or rising_edge_EDONE or ERSSUSP_out or rising_edge_PoweredUp or + rising_edge_CSNeg_ipd or rising_edge_RES_out or ERSRES_out or + PRGSUSP_out or PRGRES_out_event or rising_edge_VLTDONE or + rising_edge_DP_out) + + begin: Functionality + integer i,j; + + if (rising_edge_read_out) + begin + if (PoweredUp == 1'b1) + ->oe_event; + end + + if (Instruct_event) + begin + read_cnt = 0; + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + read_id = 1'b0; + pp_quad = 1'b0; + if (current_state == IDLE) + begin + if (DP_in == 1'b1) + begin + $display ("Command results can be corrupted "); + end + end + end + + if (rising_edge_PoweredUp) + begin + Status_reg1[1] = 1'b0; // WEL bit + Status_reg1[0] = 1'b0; // BUSY bit + + Status_reg2[7] = 1'b0; // SUS bit + end + + if (change_addr_event) + begin + read_addr = Address; + end + + if (rising_edge_RES_out) + begin + if(RES_out) + begin + RES_in = 1'b0; + end + end + + case (current_state) + IDLE : + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + res_flag = 1'b0; + pg_screg_flag = 1'b0; + ers_screg_flag = 1'b0; + if (falling_edge_write && ~DP_in) + begin + read_cnt = 0; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 1'b0; + else if (Instruct == WRR) + begin + if(~SRP1 && (~SRP0 || (SRP0 && WPNeg))) + begin + if (WEL && ~wren_vlt_flag) + begin + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (~WEL && wren_vlt_flag) + begin + VLTSTART = 1'b1; + VLTSTART <= #5 1'b0; + end + end + else + Status_reg1[1] = 1'b0; + end + else if ((Instruct == PP || (Instruct == QPP && QE)) + && WEL && PDONE) + begin + sect = Address / 16'h1000; + if (Sec_Prot[sect] == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == PG_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect <= 3) && LB[sect-1]==0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + wr_cnt = Byte_number; + Addr_screg = Address % 16'h1000; + pg_screg_flag = 1'b1; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + end + end + else if ((Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) && WEL) + begin + sect = Address / 16'h1000; + if (Sec_Prot[sect] == 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + Addr_ers = Address; + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == CE && WEL) + begin +// if ((~CMP && ~BP2 && ~BP1 && ~BP0) || +// (CMP && BP2 && BP1 && BP0)) + if (Sec_Prot == 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == ERS_SCREG && WEL) + begin + sect = Address / 16'h1000; + if ((sect <= 3) && LB[sect-1]==0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + ers_screg_flag = 1'b1; + end + else + Status_reg1[1] = 1'b0; + end + else if (Instruct == DP) + begin + RES_in <= 1'b0; + DP_in <= 1'b1; + end + end // end of falling_edge_write + else if (oe && ~DP_in) + begin + if (Instruct == RDSR) + begin //Read Status Register + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + sr_read = 1'b1; + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + if (Instruct == READ) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b1; + quad_read = 1'b0; + sr_read = 1'b0; + end + else + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct==FAST_DREAD || Instruct==FAST_DREAD_2) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if ((Instruct==FAST_QREAD || Instruct==FAST_QREAD_4 || + Instruct==W_QREAD || Instruct==WOCT_QREAD) + && QE) + begin + if ((Instruct==W_QREAD && Address[0]) || + (Instruct==WOCT_QREAD && ~(Address[3:0] == 4'h0))) + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + $display("Word Read could not execute"); + $display("Wrong Read Address"); + end + end + else + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (wrap_byte[4]==1'b0 && + (Instruct==FAST_QREAD_4 || Instruct==W_QREAD)) + begin + ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap, + Address,w_size); + if (read_addr == AddrHi_wrap) + read_addr = AddrLo_wrap; + else + read_addr = read_addr + 1; + end + else + begin + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (Instruct==RDID || Instruct==RDID_DUAL || + Instruct==RDID_QUAD) + begin + if (read_addr % 2 == 0) + begin + ident_out2 = {Manuf_ID,Device_ID1}; + end + else + begin + ident_out2 = {Device_ID1,Manuf_ID}; + end + read_id = 1'b1; + if (Instruct == RDID) + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + DataDriveOut_SO = ident_out2[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == RDID_DUAL) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + DataDriveOut_SO = ident_out2[15-2*read_cnt]; + DataDriveOut_SI = ident_out2[14-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else // (Instruct == RDID_QUAD) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + HOLDNegOut_zd = ident_out2[15-4*read_cnt]; + WPNegOut_zd = ident_out2[14-4*read_cnt]; + SOut_zd = ident_out2[13-4*read_cnt]; + SIOut_zd = ident_out2[12-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + read_cnt = 0; + end + end + else if (Instruct == RD_UNIQ_ID) + begin + // unique ID number is not in data sheet + read_id = 1'b1; + DataDriveOut_SO = unique_id[63-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 64) + read_cnt = 0; + end + else if (Instruct == RDIDJ) + begin + read_id = 1'b1; + ident_out = {Manuf_ID,Device_ID2,Device_ID3}; + DataDriveOut_SO = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RD_SFDP) + begin + sfdp_addr = read_addr / 12'h100; + if (sfdp_addr == 0) + begin + Addr_tmp_2 = (read_addr % 12'h100); + data_out[7:0] = SFDP_array[Addr_tmp_2]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == SFDP_HiAddr) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given SFDP address is out of range"); + end + end + end + else if (Instruct == RD_SCREG) + begin + Addr_tmp_2 = read_addr / 12'h100; + Addr_tmp_3 = read_addr % 12'h100; + if (Addr_tmp_2 == 16) + begin + // Security Register No.1 + data_out[7:0] = Security_Reg1[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 32) + begin + // Security Register No.2 + data_out[7:0] = Security_Reg2[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 48) + // Security Register No.2 + begin + data_out[7:0] = Security_Reg3[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given Security Register Read "); + $display("address is out of range "); + end + end + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr % 256 == SecReg_HiAddr) + read_addr = (read_addr/256)*(SecReg_HiAddr+1); + else + read_addr = read_addr + 1; + end + end + else if (Instruct == RES_RD_ID) + begin + read_id = 1'b1; + data_out[7:0] = Device_ID1; + DataDriveOut_SO = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end // end of oe + else if (rising_edge_DP_out) + DP_in = 1'b0; + end // end of IDLE state + + WRITE_SR: + begin + if (WDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + + Status_reg1[7:2] = Status_reg1_in[7:2]; + Status_reg2[6] = Status_reg2_in[6]; + Status_reg2[1] = Status_reg2_in[1]; + // SRP1 bit will only change value from '0' to '1' + // if SRP1 is '1' than Status Register is protected + //and is not possible to write it + Status_reg2[0] = Status_reg2_in[0]; + for(i=5;i>=3;i=i-1) + begin + if (Status_reg2[i] == 1'b0) + Status_reg2[i] = Status_reg2_in[i]; + else + begin + $display("LB bit is set to '1'"); + $display("No change allowed"); + end + end + change_prot_bits = 1'b1; + #1000 change_prot_bits = 1'b0; + end // end of WDONE + + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end // end of oe + end // end of WRITE_SR + + WRITE_SR_V: + begin + if (VLTDONE) + begin + Status_reg1[7:2] = Status_reg1_in[7:2]; + Status_reg2[6] = Status_reg2_in[6]; + Status_reg2[1] = Status_reg2_in[1]; + // SRP1 bit will only change value from '0' to '1' + // if SRP1 is '1' than Status Register is protected + //and is not possible to write it + Status_reg2[0] = Status_reg2_in[0]; + for(i=5;i>=3;i=i-1) + begin + if (Status_reg2[i] == 1'b0) + Status_reg2[i] = Status_reg2_in[i]; + else + begin + $display("LB bit is set to '1'"); + $display("No change allowed"); + end + end + change_prot_bits = 1'b1; + #1000 change_prot_bits = 1'b0; + wren_vlt_flag = 1'b0; + end + end + + PAGE_PG, + ERS_SUSP_PG: + begin + if (current_state_event && ~PDONE) + begin + if (Instruct !== PG_SCREG) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + end + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + if (Instruct == PG_SCREG) + begin + if (sect == 1) + old_int = Security_Reg1[Addr_screg + i - cnt]; + else if (sect == 2) + old_int = Security_Reg2[Addr_screg + i - cnt]; + else + old_int = Security_Reg3[Addr_screg + i - cnt]; + end + else + begin + old_int = Mem[Addr + i - cnt]; + end + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + if (Instruct == PG_SCREG) + begin + if (sect == 1) + Security_Reg1[Addr_screg + i - cnt] = - 1; + else if (sect == 2) + Security_Reg2[Addr_screg + i - cnt] = - 1; + else + Security_Reg3[Addr_screg + i - cnt] = - 1; + end + else + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + + Addr = AddrLo; + cnt = i + 1; + end + end + cnt = 0; + end // end of current_state_event + + if (PDONE) + begin + if (current_state !== ERS_SUSP_PG) + begin + Status_reg1[0] = 1'b0; + end + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + if (pg_screg_flag ) + begin + if (sect == 1) + Security_Reg1[Addr_screg + i - cnt] = WData[i]; + else if (sect == 2) + Security_Reg2[Addr_screg + i - cnt] = WData[i]; + else + Security_Reg3[Addr_screg + i - cnt] = WData[i]; + + if ((Addr_screg + i) == SecReg_HiAddr) + begin + Addr_screg = SecReg_LoAddr; + cnt = i + 1; + end + end + else + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + end // end of PDONE + + if (Instruct == ERS_PG_SUSP && current_state == PAGE_PG && ~susp_flag) + begin + PGSUSP = 1'b1; + PGSUSP <= #1000 1'b0; + PRGSUSP_in = 1'b1; + end + + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end // end of PAGE_PG + + PG_SUSP: + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (PRGSUSP_out == 1 && ~(Instruct == ERS_PG_RES)) + begin + PRGSUSP_in = 1'b0; + //The BUSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Suspend (SUS) bit in the Status Register2 will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[7] = 1'b1; + end + if (PRGRES_out_event && PRGRES_out == 1) + begin + PRGRES_in = 1'b0; + Status_reg1[0] = 1'b1; + end + if (SUS) + begin + if (falling_edge_write) + begin + if (Instruct == ERS_PG_RES) + begin + Status_reg2[7] = 1'b0; + PRGRES_in = 1'b1; + PGRES = 1'b1; + PGRES <= #1000 1'b0; + end + else if ((Instruct == SE || Instruct == BE_32 || + Instruct == BE_64) && WEL) + begin + sect = Address / 16'h1000; + if (sect !== sect_tmp_pg && Sec_Prot[sect] == 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + Status_reg1[0] = 1'b1; + Addr_ers = Address; + end + else + begin + Status_reg1[0] = 1'b0; + $display("Can't erase sector/block"); + $display("Block is protected or suspended"); + end + end + end + else if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + sr_read = 1'b1; + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + if (sect_tmp_pg !== read_addr / 16'h1000) + begin + if (Instruct == READ) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b1; + quad_read = 1'b0; + sr_read = 1'b0; + end + else + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==FAST_DREAD || + Instruct==FAST_DREAD_2) + begin + if (sect_tmp_pg !== read_addr / 16'h1000) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if ((Instruct==FAST_QREAD || Instruct==W_QREAD + || Instruct==FAST_QREAD_4 || Instruct==WOCT_QREAD) + && QE) + begin + if (sect_tmp_pg !== read_addr / 16'h1000) + begin + if ((Instruct==W_QREAD && Address[0]) || + (Instruct==WOCT_QREAD && + ~(Address[3:0] == 4'h0))) + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + $display("Word Read can't execute"); + $display("Wrong Read Address"); + end + end + else + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (wrap_byte[4]==0 && + (Instruct==FAST_QREAD_4 || + Instruct==W_QREAD)) + begin + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap, Address,w_size); + if (read_addr == AddrHi_wrap) + read_addr = AddrLo_wrap; + else + read_addr = read_addr + 1; + end + else + begin + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==RDID || Instruct==RDID_DUAL || + Instruct==RDID_QUAD) + begin + if (read_addr % 2 == 0) + begin + ident_out2 = {Manuf_ID,Device_ID1}; + end + else + begin + ident_out2 = {Device_ID1,Manuf_ID}; + end + read_id = 1'b1; + if (Instruct == RDID) + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + DataDriveOut_SO = ident_out2[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == RDID_DUAL) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + DataDriveOut_SO = ident_out2[15-2*read_cnt]; + DataDriveOut_SI = ident_out2[14-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else // (Instruct == RDID_QUAD) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + HOLDNegOut_zd = ident_out2[15-4*read_cnt]; + WPNegOut_zd = ident_out2[14-4*read_cnt]; + SOut_zd = ident_out2[13-4*read_cnt]; + SIOut_zd = ident_out2[12-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + read_cnt = 0; + end + end + else if (Instruct == RD_UNIQ_ID) + begin + // unique ID number is not in data sheet + read_id = 1'b1; + DataDriveOut_SO = unique_id[63-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 64) + read_cnt = 0; + end + else if (Instruct == RDIDJ) + begin + read_id = 1'b1; + ident_out = {Manuf_ID,Device_ID2,Device_ID3}; + DataDriveOut_SO = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RD_SFDP) + begin + sfdp_addr = read_addr / 12'h100; + if (sfdp_addr == 0) + begin + Addr_tmp_2 = (read_addr % 12'h100); + data_out[7:0] = SFDP_array[Addr_tmp_2]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == SFDP_HiAddr) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("SFDP address is out of range"); + end + end + end + else if (Instruct == RD_SCREG) + begin + Addr_tmp_2 = read_addr / 12'h100; + Addr_tmp_3 = read_addr % 12'h100; + if (Addr_tmp_2 == 16) + begin + // Security Register No.1 + data_out[7:0] = Security_Reg1[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 32) + begin + // Security Register No.2 + data_out[7:0] = Security_Reg2[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 48) + // Security Register No.2 + begin + data_out[7:0] = Security_Reg3[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given Security Register Read "); + $display("address is out of range "); + end + end + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr % 256 == SecReg_HiAddr) + read_addr=(read_addr/256)* + (SecReg_HiAddr+1); + else + read_addr = read_addr + 1; + end + end + end // end of 'oe' + end + end // end of PG_SUSP + + SECTOR_ERS, + PG_SUSP_ERS: + begin + if (current_state_event && ~EDONE) + begin + if (Instruct == SE) + ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers); + else if (Instruct == BE_32) + ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers); + else if (Instruct == BE_64) + begin + ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers); + end + if (Instruct !== ERS_SCREG) + begin + for (i=AddrLo_ers;i<=AddrHi_ers;i=i+1) + begin + Mem[i] = -1; + end + end + else + begin + if (sect == 1) + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg1[i] = -1; + end + end + else if (sect == 2) + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg2[i] = -1; + end + end + else + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg3[i] = -1; + end + end + end + end + + if (EDONE == 1) + begin + if (current_state !== PG_SUSP_ERS) + begin + Status_reg1[0] = 1'b0; + end + Status_reg1[1] = 1'b0; + if (ers_screg_flag ) + begin + if (sect == 1) + begin + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg1[i] = MaxData; + end + end + else if (sect == 2) + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg2[i] = MaxData; + end + else + for(i=SecReg_LoAddr;i<=SecReg_HiAddr;i=i+1) + begin + Security_Reg3[i] = MaxData; + end + + end + else + begin + for (i=AddrLo_ers;i<=AddrHi_ers;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + + if (Instruct == ERS_PG_SUSP && current_state == SECTOR_ERS) + begin + ESUSP = 1'b1; + ESUSP <= #1000 1'b0; + ERSSUSP_in = 1'b1; + end + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end // end of SECTOR_ERS + + BULK_ERS: + begin + if (current_state_event && ~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = -1; + end + end + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + end + if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end // end of BULK_ERS + + ERS_SUSP: + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (ERSSUSP_out == 1 && ~(Instruct == ERS_PG_RES)) + begin + ERSSUSP_in = 1'b0; + //The BUSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Suspend (SUS) bit in the Status Register2 will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[7] = 1'b1; + end + if (ERSRES_out_event && ERSRES_out == 1) + begin + ERSRES_in = 1'b0; + Status_reg1[0] = 1'b1; + end + if (SUS) + begin + if (falling_edge_write) + begin + if (Instruct == ERS_PG_RES) + begin + Status_reg2[7] = 1'b0; + ERSRES_in = 1'b1; + ERES = 1'b1; + ERES <= #1000 1'b0; + end + else if ((Instruct == PP || (Instruct==QPP && QE)) + && WEL) + begin + sect = Address / 16'h1000; + if (sect !== sect_tmp_ers && Sec_Prot[sect]==0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[0] = 1'b0; + $display("Can't program sector/block"); + $display("Block is protected or suspended"); + end + end + else if (Instruct == PG_SCREG) + begin + sect = Address / 16'h1000; + if ((sect <= 3 && sect >=1) && LB[sect-1]==0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + Status_reg1[0] = 1'b1; + SA = sect; + wr_cnt = Byte_number; + Addr_screg = Address % 16'h1000; + pg_screg_flag = 1'b1; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + Status_reg1[1] = 1'b0; + end + end + else if (oe) + begin + if (Instruct == RDSR) + begin + //Read Status Register 1 + sr_read = 1'b1; + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + sr_read = 1'b1; + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + if (sect !== read_addr / 16'h1000) + begin + if (Instruct == READ) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b1; + quad_read = 1'b0; + sr_read = 1'b0; + end + else + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==FAST_DREAD || Instruct==FAST_DREAD_2) + begin + if (sect !== read_addr / 16'h1000) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if ((Instruct==FAST_QREAD || Instruct==W_QREAD + || Instruct==FAST_QREAD_4 || Instruct==WOCT_QREAD) + && QE) + begin + if (sect_tmp_ers !== read_addr / 16'h1000) + begin + if ((Instruct==W_QREAD && Address[0]) || + (Instruct==WOCT_QREAD && + ~(Address[3:0]==4'h0))) + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + $display("Word Read can't execute"); + $display("Wrong Read Address"); + end + end + else + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (wrap_byte[4]==0 && + (Instruct==FAST_QREAD_4 + || Instruct==W_QREAD)) + begin + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap,Address,w_size); + if (read_addr == AddrHi_wrap) + read_addr = AddrLo_wrap; + else + read_addr = read_addr + 1; + end + else + begin + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + $display("Can't read suspended sector"); + read_cnt = 0; + end + end + end + else if (Instruct==RDID || Instruct==RDID_DUAL || + Instruct==RDID_QUAD) + begin + if (read_addr % 2 == 0) + begin + ident_out2 = {Manuf_ID,Device_ID1}; + end + else + begin + ident_out2 = {Device_ID1,Manuf_ID}; + end + read_id = 1'b1; + if (Instruct == RDID) + begin + fast_read = 1'b1; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + DataDriveOut_SO = ident_out2[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == RDID_DUAL) + begin + fast_read = 1'b0; + dual_read = 1'b1; + slow_read = 1'b0; + quad_read = 1'b0; + sr_read = 1'b0; + DataDriveOut_SO = ident_out2[15-2*read_cnt]; + DataDriveOut_SI = ident_out2[14-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else // (Instruct == RDID_QUAD) + begin + fast_read = 1'b0; + dual_read = 1'b0; + slow_read = 1'b0; + quad_read = 1'b1; + sr_read = 1'b0; + HOLDNegOut_zd = ident_out2[15-4*read_cnt]; + WPNegOut_zd = ident_out2[14-4*read_cnt]; + SOut_zd = ident_out2[13-4*read_cnt]; + SIOut_zd = ident_out2[12-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + read_cnt = 0; + end + end + else if (Instruct == RD_UNIQ_ID) + begin + // unique ID number is not in data sheet + read_id = 1'b1; + DataDriveOut_SO = unique_id[63-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 64) + read_cnt = 0; + end + else if (Instruct == RDIDJ) + begin + read_id = 1'b1; + ident_out = {Manuf_ID,Device_ID2,Device_ID3}; + DataDriveOut_SO = ident_out[23-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 24) + read_cnt = 0; + end + else if (Instruct == RD_SFDP) + begin + sfdp_addr = read_addr / 12'h100; + if (sfdp_addr == 0) + begin + Addr_tmp_2 = (read_addr % 12'h100); + data_out[7:0] = SFDP_array[Addr_tmp_2]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == SFDP_HiAddr) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("SFDP address is out of range"); + end + end + end + else if (Instruct == RD_SCREG) + begin + Addr_tmp_2 = read_addr / 12'h100; + Addr_tmp_3 = read_addr % 12'h100; + if (Addr_tmp_2 == 16) + begin + // Security Register No.1 + data_out[7:0] = Security_Reg1[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 32) + begin + // Security Register No.2 + data_out[7:0] = Security_Reg2[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else if (Addr_tmp_2 == 48) + // Security Register No.2 + begin + data_out[7:0] = Security_Reg3[Addr_tmp_3]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + $display("Given Security Register Read "); + $display("address is out of range "); + end + end + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr % 256 == SecReg_HiAddr) + read_addr = (read_addr/256)* + (SecReg_HiAddr+1); + else + read_addr = read_addr + 1; + end + end + end // end of 'oe' + end // end of SUS + end // end of ERS_SUSP + + DP_DOWN: + begin + if (oe) + begin + if (Instruct == RES_RD_ID) + begin + read_id = 1'b1; + data_out[7:0] = Device_ID1; + DataDriveOut_SO = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + if (falling_edge_write) + begin + if (Instruct == RES_RD_ID) + begin + RES_in = 1'b1; + end + else + begin + $display("Device is in Deep Power Down Mode"); + $display("No instructions allowed"); + end + end + end + + endcase + //Output Disable Control + if (CSNeg_ipd ) + begin + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + DataDriveOut_SO = 1'bZ; + DataDriveOut_SI = 1'bZ; + end + end // end of Functionality + + /////////////////////////////////////////////////////////////////////////// + always @(posedge change_prot_bits) + begin + case (Status_reg1[4:2]) + 3'b000: + begin + if (Status_reg2[6] == 1'b0) + Sec_Prot[4095:0] = {4096{1'b0}}; + else + Sec_Prot[4095:0] = {4096{1'b1}}; + end + + 3'b001: + begin + if (Status_reg2[6] ==1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:4032] = {64{1'b1}}; + Sec_Prot[4031:0] = {4032{1'b0}}; + end + 2'b01: + begin + Sec_Prot[4095:64] = {4032{1'b0}}; + Sec_Prot[63:0] = {64{1'b1}}; + end + 2'b10: + begin + Sec_Prot[4095] = 1'b1; + Sec_Prot[4094:0] = {4095{1'b0}}; + end + 2'b11: + begin + Sec_Prot[4095:1] = {4095{1'b0}}; + Sec_Prot[0] = 1'b1; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:4032] = {64{1'b0}}; + Sec_Prot[4031:0] = {4032{1'b1}}; + end + 2'b01: + begin + Sec_Prot[4095:64] = {4032{1'b1}}; + Sec_Prot[63:0] = {64{1'b0}}; + end + 2'b10: + begin + Sec_Prot[4095] = 1'b0; + Sec_Prot[4094:0] = {4095{1'b1}}; + end + 2'b11: + begin + Sec_Prot[4095:1] = {4095{1'b1}}; + Sec_Prot[0] = 1'b0; + end + endcase + end + end + + 3'b010: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3968] = {128{1'b1}} ; + Sec_Prot[3967:0] = {3968{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[4095:128] = {3968{1'b0}} ; + Sec_Prot[127:0] = {128{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[4095:4094] = 2'b11; + Sec_Prot[4093:0] = {4094{1'b0}}; + end + 2'b11: + begin + Sec_Prot[4095:2] = {4094{1'b0}}; + Sec_Prot[1:0] = 2'b11; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3968] = {128{1'b0}} ; + Sec_Prot[3967:0] = {3968{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[4095:128] = {3968{1'b1}} ; + Sec_Prot[127:0] = {128{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[4095:4094] = 2'b00; + Sec_Prot[4093:0] = {4094{1'b1}}; + end + 2'b11: + begin + Sec_Prot[4095:2] = {4094{1'b1}}; + Sec_Prot[1:0] = 2'b00; + end + endcase + end + end + + 3'b011: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3840] = {256{1'b1}} ; + Sec_Prot[3839:0] = {3840{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[4095:256] = {3840{1'b0}} ; + Sec_Prot[255:0] = {256{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[4095:4092] = 4'b1111; + Sec_Prot[4091:0] = {4092{1'b0}}; + end + 2'b11: + begin + Sec_Prot[4095:4] = {4092{1'b0}}; + Sec_Prot[3:0] = 4'b1111; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3840] = {256{1'b0}} ; + Sec_Prot[3839:0] = {3840{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[4095:256] = {3840{1'b1}} ; + Sec_Prot[255:0] = {256{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[4095:4092] = 4'b0000; + Sec_Prot[4091:0] = {4092{1'b1}}; + end + 2'b11: + begin + Sec_Prot[4095:4] = {4092{1'b1}}; + Sec_Prot[3:0] = 4'b0000; + end + endcase + end + end + + 3'b100: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3584] = {512{1'b1}} ; + Sec_Prot[3583:0] = {3584{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[4095:512] = {3584{1'b0}} ; + Sec_Prot[511:0] = {512{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[4095:4088] = 8'hFF; + Sec_Prot[4087:0] = {4088{1'b0}}; + end + 2'b11: + begin + Sec_Prot[4095:8] = {4088{1'b0}}; + Sec_Prot[7:0] = 8'hFF; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3584] = {512{1'b0}} ; + Sec_Prot[3583:0] = {3584{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[4095:512] = {3584{1'b1}} ; + Sec_Prot[511:0] = {512{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[4095:4088] = 8'h00; + Sec_Prot[4087:0] = {4088{1'b1}}; + end + 2'b11: + begin + Sec_Prot[4095:8] = {4088{1'b1}}; + Sec_Prot[7:0] = 8'h00; + end + endcase + end + end + + 3'b101: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3072] = {1024{1'b1}} ; + Sec_Prot[3071:0] = {3072{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[4095:1024] = {3072{1'b0}} ; + Sec_Prot[1023:0] = {1024{1'b1}} ; + end + 2'b10: + begin + Sec_Prot[4095:4088] = 8'hFF; + Sec_Prot[4087:0] = {4088{1'b0}}; + end + 2'b11: + begin + Sec_Prot[4095:8] = {4088{1'b0}}; + Sec_Prot[7:0] = 8'hFF; + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:3072] = {1024{1'b0}} ; + Sec_Prot[3071:0] = {3072{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[4095:1024] = {3072{1'b1}} ; + Sec_Prot[1023:0] = {1024{1'b0}} ; + end + 2'b10: + begin + Sec_Prot[4095:4088] = 8'h00; + Sec_Prot[4087:0] = {4088{1'b1}}; + end + 2'b11: + begin + Sec_Prot[4095:8] = {4088{1'b1}}; + Sec_Prot[7:0] = 8'h00; + end + endcase + end + end + + 3'b110: + begin + if (Status_reg2[6] == 1'b0) + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:2048] = {2048{1'b1}} ; + Sec_Prot[2047:0] = {2048{1'b0}} ; + end + 2'b01: + begin + Sec_Prot[4095:2048] = {2048{1'b0}} ; + Sec_Prot[2047:0] = {2048{1'b1}} ; + end + 2'b10, 2'b11: + begin + $display("This combination of bits "); + $display("is not deffined"); + end + endcase + end + else + begin + case (Status_reg1[6:5]) + 2'b00: + begin + Sec_Prot[4095:2048] = {2048{1'b0}} ; + Sec_Prot[2047:0] = {2048{1'b1}} ; + end + 2'b01: + begin + Sec_Prot[4095:2048] = {2048{1'b1}} ; + Sec_Prot[2047:0] = {2048{1'b0}} ; + end + 2'b10, 2'b11: + begin + $display("This combination of bits "); + $display("is not deffined"); + end + endcase + end + end + + 3'b111: + begin + if (Status_reg2[6]== 1'b0) + Sec_Prot[4095:0] = {4096{1'b1}}; + else + Sec_Prot[4095:0] = {4096{1'b0}}; + end + endcase + end // end of rising_edge_prot_bits + //////////////////////////////////////////////////////////////////////// + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QE) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure ADDRHILO_SEC 4KB, 32KB, 64KB + task ADDRHILO_SEC64; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + AddrLOW = sector * 20'h10000; + AddrHIGH = sector * 20'h10000 + 20'h0FFFF; + end + endtask + + task ADDRHILO_SEC32; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 16'h8000; + AddrLOW = sector * 16'h8000; + AddrHIGH = sector * 16'h8000 + 16'h7FFF; + end + endtask + + task ADDRHILO_SEC4; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 16'h1000; + AddrLOW = sector * 16'h1000; + AddrHIGH = sector * 16'h1000 + 16'h0FFF; + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / 16'h0100; + AddrLOW = page * 16'h0100; + AddrHIGH = page * 16'h0100 + 16'h00FF; + end + endtask + + // Procedure ADDRHILO_WRAP + task ADDRHILO_WRAP; + inout Addr_low_wrap; + inout Addr_hi_wrap; + input Address; + input w_size; + integer Addr_low_wrap; + integer Addr_hi_wrap; + integer Address; + integer w_size; + integer sect_wrap; + begin + sect_wrap = Address / w_size; + Addr_low_wrap = sect_wrap * w_size; + Addr_hi_wrap = sect_wrap * w_size + w_size - 1; + end + endtask + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1'b1; + #1000 falling_edge_write = 1'b0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge VLTDONE) + begin + rising_edge_VLTDONE = 1'b1; + #1000 rising_edge_VLTDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge VLTSTART) + begin + rising_edge_VLTSTART = 1'b1; + #1000 rising_edge_VLTSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge DP_out) + begin + rising_edge_DP_out = 1'b1; + #1 rising_edge_DP_out = 1'b0; + end + + always @(posedge RES_out) + begin + rising_edge_RES_out = 1'b1; + #1000 rising_edge_RES_out = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge PRGRES_out) + begin + PRGRES_out_event = 1; + #1000 PRGRES_out_event = 0; + end + + always @(posedge ESUSP) + begin + ESUSP_event = 1'b1; + #1000 ESUSP_event = 1'b0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge ERSRES_out) + begin + ERSRES_out_event = 1; + #1000 ERSRES_out_event = 0; + end + + always @(posedge PGSUSP) + begin + PGSUSP_event = 1'b1; + #1000 PGSUSP_event = 1'b0; + end + + always @(posedge PGRES) + begin + PGRES_event = 1'b1; + #1000 PGRES_event = 1'b0; + end + + always @(posedge ERES) + begin + ERES_event = 1'b1; + #1000 ERES_event = 1'b0; + end + + always @(posedge change_prot_bits) + begin + rising_edge_prot_bits = 1'b1; + #1000 rising_edge_prot_bits = 1'b0; + end + + reg update_time = 1'b0; + always @(posedge read_id) + begin + start_rdid = $time; + update_time = 1'b1; + end + + always @(SO_out) + begin + if (read_id && update_time) + out_time = $time; + SCK_SO_2 = out_time - start_rdid; + update_time = 1'b0; + end + + always @(DataDriveOut_SO,DataDriveOut_SI) + begin + if (SCK_SO_2 > SCK_cycle) + begin + glitch = 1; + SOut_zd <= #SCK_SO_2 DataDriveOut_SO; + SIOut_zd <= #SCK_SO_2 DataDriveOut_SI; + end + else + begin + glitch = 0; + SOut_zd <= DataDriveOut_SO; + SIOut_zd <= DataDriveOut_SI; + end + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.vhd b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.vhd new file mode 100644 index 0000000..ad7fc72 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.vhd @@ -0,0 +1,3787 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl128k.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2010 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Prokopovic 10 Oct 08 Inital Release +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: FLASH MEMORY +-- Part: S25FL128K +-- +-- Description: 128 Megabit Serial Flash Memory +-- +------------------------------------------------------------------------------- +-- Known Bugs: +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl128k IS + GENERIC ( + --------------------------------------------------------------------------- + -- TIMING GENERICS: + --------------------------------------------------------------------------- + -- tipd delays: interconnect path delays (delay between components) + -- There should be one for each IN or INOUT pin in the port list + -- They are given default values of zero delay. + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_SO : VitalDelayType01 := VitalZeroDelay01; + + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays: propagation delays (pin-to-pin delay within a component) + tpd_SCK_SO_RDID_EQ_0 : VitalDelayType01Z := UnitDelay01Z;--tCLQV1 + tpd_SCK_SO_RDID_EQ_1 : VitalDelayType01Z := UnitDelay01Z;--tCLQV2 + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tSHQZ + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tHLQZ + + -- tsetup values: setup times + tsetup_CSNeg_SCK : VitalDelayType := UnitDelay;--tSLCH,tSHCH + tsetup_SI_SCK_normal_noedge_posedge : VitalDelayType + := UnitDelay;--tDVCH + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay;--tHLCH,tHHCH + tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay;--tWHSL + + -- thold values: hold times + thold_CSNeg_SCK : VitalDelayType := UnitDelay;--tSLCH,tSHCH + thold_SI_SCK_normal_noedge_posedge : VitalDelayType + := UnitDelay;--tCHDX + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay;--tCHHL,tCHHH + thold_WPNeg_CSNeg : VitalDelayType := UnitDelay;--tSHWL + + --tpw values: pulse width + tpw_SCK_slow_posedge : VitalDelayType := UnitDelay; -- tCH + tpw_SCK_slow_negedge : VitalDelayType := UnitDelay; -- tCL + tpw_SCK_fast_posedge : VitalDelayType := UnitDelay; -- tCH + tpw_SCK_fast_negedge : VitalDelayType := UnitDelay; -- tCL + tpw_SCK_quad_posedge : VitalDelayType := UnitDelay; -- tCH + tpw_SCK_quad_negedge : VitalDelayType := UnitDelay; -- tCL + tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tSHSL1 + tpw_CSNeg_pger_posedge : VitalDelayType := UnitDelay; -- tSHSL2 + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_slow : VitalDelayType := UnitDelay;-- + tperiod_SCK_fast : VitalDelayType := UnitDelay;-- + tperiod_SCK_quad : VitalDelayType := UnitDelay;-- + + -- tdevice values: values for internal delays + -- VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 10 us; + -- CS# High to Power Down Mode -- tDP + tdevice_DP : VitalDelayType := 3 us; + -- CS# High to StandBy mode without Electronic Signature read + tdevice_RES1 : VitalDelayType := 3 us; + -- CS# High to StandBy mode with Electronic Signature read + tdevice_RES2 : VitalDelayType := 1.8 us; + -- CS# High to next Instruction after Suspend + tdevice_PRGSUSP : VitalDelayType := 20 us; + -- CS# High to next Instruction after Suspend + tdevice_ERSSUSP : VitalDelayType := 20 us; + -- CS# High to next Instruction after Suspend + tdevice_SUSP_DLY : VitalDelayType := 20 us; + -- Resume Suspend to Program/Erase time + tdevice_PRGRES : VitalDelayType := 200 ns; + -- Resume Suspend to Program/Erase time + tdevice_ERSRES : VitalDelayType := 200 ns; + -- Page Program Time + tdevice_PP : VitalDelayType := 3 ms; + -- Byte Program Time (First Byte) + tdevice_BP1 : VitalDelayType := 50 us; + -- Additional Byte Program Time (After First Byte) + tdevice_BP2 : VitalDelayType := 12 us; + -- Sector Erase Time (4KB) + tdevice_SE : VitalDelayType := 400 ms; + -- Block Erase Time (32KB) + tdevice_BE1 : VitalDelayType := 800 ms; + -- Block Erase Time (64KB) + tdevice_BE2 : VitalDelayType := 1000 ms; + -- Chip Erase Time + tdevice_CE : VitalDelayType := 40 sec; + -- Write Status Register Time + tdevice_WRR : VitalDelayType := 15 ms; + -- Write Volatile Status Register Time + tdevice_VRR : VitalDelayType := 50 ns; + + --------------------------------------------------------------------------- + -- CONTROL GENERICS: + --------------------------------------------------------------------------- + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + + -- memory file to be loaded + mem_file_name : STRING := "s25fl128k.mem"; + screg_file_name : STRING := "s25fl128kscreg.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING := DefaultTimingModel + ); + PORT ( + -- Data Inputs/Outputs + SI : INOUT std_ulogic := 'U'; -- serial data input/IO0 + SO : INOUT std_ulogic := 'U'; -- serial data output/IO1 + -- Controls + SCK : IN std_ulogic := 'U'; -- serial clock input + CSNeg : IN std_ulogic := 'U'; -- chip select input + WPNeg : INOUT std_ulogic := 'U'; -- write protect input/IO2 + HOLDNeg : INOUT std_ulogic := 'U' -- hold input/IO3 + ); + + ATTRIBUTE VITAL_LEVEL0 of s25fl128k : ENTITY IS TRUE; +END s25fl128k; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of s25fl128k IS + ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; + + --------------------------------------------------------------------------- + -- CONSTANT AND SIGNAL DECLARATION + --------------------------------------------------------------------------- + --Declaration of constants - memory characteristics + -- The constant declared here are used to enable the creation of models + -- of memories within a family with a minimum amount of editing + + CONSTANT PartID : STRING := "s25fl128k"; + CONSTANT MaxData : NATURAL := 16#FF#; + CONSTANT AddrRANGE : NATURAL := 16#FFFFFF#; + CONSTANT PageNum : NATURAL := 16#FFFF#; + CONSTANT SecSize_4 : NATURAL := 16#FFF#; + CONSTANT SecSize_32 : NATURAL := 16#7FFF#; + CONSTANT SecSize_64 : NATURAL := 16#FFFF#; + CONSTANT Blk_4_Num : NATURAL := 4095; + CONSTANT Blk_64_Num : NATURAL := 255; + CONSTANT Blk_32_Num : NATURAL := 511; + CONSTANT SFDP_HiAddr : NATURAL := 16#FF#; + CONSTANT SFDP_LoAddr : NATURAL := 16#00#; + CONSTANT SecReg_HiAddr : NATURAL := 16#FF#; + CONSTANT SecReg_LoAddr : NATURAL := 16#00#; + CONSTANT SCREG_LoAddr : NATURAL := 16#000#; + CONSTANT SCREG_HiAddr : NATURAL := 16#2FF#; + CONSTANT BYTE : NATURAL := 8; + + -- Manufacturer Identification and Device Identification + CONSTANT Manuf_ID : NATURAL := 16#EF#; + CONSTANT Device_ID1 : NATURAL := 16#17#; + CONSTANT Device_ID2 : NATURAL := 16#40#; + CONSTANT Device_ID3 : NATURAL := 16#18#; + CONSTANT Unique_id_1 : NATURAL := 16#ABAB#;--this is 64bit ID number + CONSTANT Unique_id_2 : NATURAL := 16#00#;--this is 64bit ID number + + -- Declaration of signals that will hold the delayed values of ports + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + + -- internal delays + SIGNAL PP_in : std_ulogic := '0'; + SIGNAL PP_out : std_ulogic := '0'; + SIGNAL BP1_in : std_ulogic := '0'; + SIGNAL BP1_out : std_ulogic := '0'; + SIGNAL BP2_in : std_ulogic := '0'; + SIGNAL BP2_out : std_ulogic := '0'; + SIGNAL SE_in : std_ulogic := '0'; + SIGNAL SE_out : std_ulogic := '0'; + SIGNAL BE1_in : std_ulogic := '0'; + SIGNAL BE1_out : std_ulogic := '0'; + SIGNAL BE2_in : std_ulogic := '0'; + SIGNAL BE2_out : std_ulogic := '0'; + SIGNAL CE_in : std_ulogic := '0'; + SIGNAL CE_out : std_ulogic := '0'; + SIGNAL WRR_in : std_ulogic := '0'; + SIGNAL WRR_out : std_ulogic := '0'; + SIGNAL ERSSUSP_in : std_ulogic := '0'; + SIGNAL ERSSUSP_out : std_ulogic := '0'; + SIGNAL ERSRES_in : std_ulogic := '0'; + SIGNAL ERSRES_out : std_ulogic := '0'; + SIGNAL PRGSUSP_in : std_ulogic := '0'; + SIGNAL PRGSUSP_out : std_ulogic := '0'; + SIGNAL PRGRES_in : std_ulogic := '0'; + SIGNAL PRGRES_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL RES1_in : std_ulogic := '0'; + SIGNAL RES1_out : std_ulogic := '0'; + SIGNAL RES2_in : std_ulogic := '0'; + SIGNAL RES2_out : std_ulogic := '0'; + SIGNAL DP_in : std_ulogic := '0'; + SIGNAL DP_out : std_ulogic := '0'; + SIGNAL SUSP_FL_IN : std_ulogic := '0'; + SIGNAL SUSP_FL_OUT : std_ulogic := '0'; + +BEGIN + + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + -- Because a tdevice generics is used, there must be a VITAL_primitives + -- assotiated with them + PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); + BP1 :VitalBuf(BP1_out, BP1_in, (tdevice_BP1 ,UnitDelay)); + BP2 :VitalBuf(BP2_out, BP2_in, (tdevice_BP2 ,UnitDelay)); + SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); + BE1 :VitalBuf(BE1_out, BE1_in, (tdevice_BE1 ,UnitDelay)); + BE2 :VitalBuf(BE2_out, BE2_in, (tdevice_BE2 ,UnitDelay)); + WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay)); + ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay)); + ERSRES :VitalBuf(ERSRES_out, ERSRES_in, (tdevice_ERSRES ,UnitDelay)); + PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay)); + PRGRES :VitalBuf(PRGRES_out, PRGRES_in, (tdevice_PRGRES ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + RES1 :VitalBuf(RES1_out, RES1_in, (tdevice_RES1 ,UnitDelay)); + CE :VitalBuf(CE_out, CE_in, (tdevice_CE ,UnitDelay)); + DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay)); + RES2 :VitalBuf(RES2_out, RES2_in, (tdevice_RES2 ,UnitDelay)); + SUSP_DLY :VitalBuf(SUSP_FL_OUT, SUSP_FL_IN, (tdevice_SUSP_DLY,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO); + w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + SCK : IN std_ulogic := 'U'; + CSNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + + PORT MAP ( + SIIn => SI_ipd, + SIOut => SI, + SOIn => SO_ipd, + SOut => SO, + SCK => SCK_ipd, + CSNeg => CSNeg_ipd, + HOLDNegIn => HOLDNeg_ipd, + HOLDNegOut => HOLDNeg, + WPNegIn => WPNeg_ipd, + WPNegOut => WPNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + WRITE_SR, + PAGE_PG, + PG_SUSP, + SECTOR_ERS, + BULK_ERS, + ERS_SUSP, + ERS_SUSP_PG, + PG_SUSP_ERS, + DP_DOWN, + WRITE_SR_V + ); + + -- Instruction Type + TYPE instruction_type IS ( NONE, + WREN , -- 06h + WRENV , -- 50h + WRDI , -- 04h + RDSR , -- 05h + RDSR2 , -- 35h + WRR , -- 01h + READ , -- 03h + FAST_READ , -- 0Bh + FAST_DREAD , -- 3Bh + FAST_QREAD , -- 6Bh + FAST_DREAD_2 , -- BBh + FAST_QREAD_4 , -- EBh + W_QREAD , -- E7h + WOCT_QREAD , -- E3h + SET_BURST_WRAP , -- 77h + CONT_RD_RST , -- FFh or FFFFH + PP , -- 02h + QPP , -- 32h + SE , -- 20h + BE_32 , -- 52h + BE_64 , -- D8h + CE , -- C7h or 60h + ERS_PG_SUSP , -- 75h + ERS_PG_RES , -- 7Ah + DP , -- B9h + RES_RD_ID , -- ABh + RDID , -- 90h + RDID_DUAL , -- 92h + RDID_QUAD , -- 94h + RD_UNIQ_ID , -- 4Bh + RDIDJ , -- 9Fh + RD_SFDP , -- 5Ah + ERS_SCREG , -- 44h + PG_SCREG , -- 42h + RD_SCREG -- 48h + ); + + TYPE WByteType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; + -- Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; + -- SFDP Memory Array + TYPE SFDPArray IS ARRAY (SFDP_LoAddr TO SFDP_HiAddr) OF INTEGER + RANGE -1 TO MaxData; + -- Security Register Array + TYPE SCREGArray IS ARRAY (SecReg_LoAddr TO SecReg_HiAddr) OF INTEGER + RANGE -1 TO MaxData; + ----------------------------------------------------------------------- + -- memory declaration + ----------------------------------------------------------------------- + -- Memory + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + -- Security Register 1 + SHARED VARIABLE Security_Reg1 : SCREGArray := (OTHERS => MaxData); + -- Security Register 2 + SHARED VARIABLE Security_Reg2 : SCREGArray := (OTHERS => MaxData); + -- Security Register 3 + SHARED VARIABLE Security_Reg3 : SCREGArray := (OTHERS => MaxData); + --SFDP Array + SHARED VARIABLE SFDP_array : SFDPArray := (OTHERS => 0); + -- Programming Buffer + SIGNAL WByte : WByteType := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + ----------------------------------------------------------------------- + -- Registers + ----------------------------------------------------------------------- + -- Status register 1 + SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Protect Bit 0 + ALIAS SRP0 :std_logic IS Status_reg1(7); + -- Sector/Block protect bit + ALIAS SEC :std_logic IS Status_reg1(6); + -- Top Bottom Bit + ALIAS TB :std_logic IS Status_reg1(5); + -- Status Register Block Protection Bits + ALIAS BP2 :std_logic IS Status_reg1(4); + ALIAS BP1 :std_logic IS Status_reg1(3); + ALIAS BP0 :std_logic IS Status_reg1(2); + -- Status Register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg1(1); + -- Status Register Busy Bit + ALIAS BUSY :std_logic IS Status_reg1(0); + + -- Status register 2 + SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg2_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Suspend status bit + ALIAS SUS :std_logic IS Status_reg2(7); + -- Complement protect bit + ALIAS CMP :std_logic IS Status_reg2(6); + -- Security Register Lock bits + ALIAS LB3 :std_logic IS Status_reg2(5); + ALIAS LB2 :std_logic IS Status_reg2(4); + ALIAS LB1 :std_logic IS Status_reg2(3); + -- Quad enable bit + ALIAS QE :std_logic IS Status_reg2(1); + -- Status register protect bit + ALIAS SRP1 :std_logic IS Status_reg2(0); + + -- Sector is protect if Sec_Prot(Blk_4_Num) = '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(Blk_4_Num downto 0) := + (OTHERS => '0'); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL pg_screg_flag : boolean := false; + SIGNAL ers_screg_flag : boolean := false; + SIGNAL slow_read : boolean := false; + SIGNAL dual_read : boolean := false; + SIGNAL fast_rd : boolean := true; + SIGNAL quad_read : boolean := false; + SIGNAL read_id : boolean := false; + SIGNAL sr_read : boolean := false; + + SHARED VARIABLE pp_quad : boolean := false; + SHARED VARIABLE hold_mode : boolean := false; + SHARED VARIABLE res_flag : boolean := false; + SHARED VARIABLE wren_vlt_flag : boolean := false; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; + SIGNAL PSTART : std_logic := '0'; + SIGNAL PGSUSP : std_logic := '0'; + SIGNAL PGRES : std_logic := '0'; + + SIGNAL WDONE : std_logic := '1'; + SIGNAL WSTART : std_logic := '0'; + SIGNAL VLTSTART : std_logic := '0'; + SIGNAL VLTDONE : std_logic := '1'; + + SIGNAL EDONE : std_logic := '1'; + SIGNAL ESTART : std_logic := '0'; + SIGNAL ESUSP : std_logic := '0'; + SIGNAL ERES : std_logic := '0'; + + SHARED VARIABLE read_cnt : NATURAL := 0; + SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ; + SHARED VARIABLE wrap_byte : std_logic_vector(7 downto 0); + SIGNAL change_addr : std_logic := '0'; + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + + SIGNAL change_prot_bits : std_logic := '0'; + SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000"; + SHARED VARIABLE LB_bits : std_logic_vector(2 downto 0) := "000"; + + SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0; + + -- Sector and subsector addresses + SIGNAL SA : NATURAL RANGE 0 TO Blk_4_Num := 0; + SHARED VARIABLE sect : NATURAL RANGE 0 TO Blk_4_Num; + SHARED VARIABLE sect_tmp_pg : NATURAL RANGE 0 TO Blk_4_Num; + SHARED VARIABLE sect_tmp_ers: NATURAL RANGE 0 TO Blk_4_Num; + + SHARED VARIABLE w_size : NATURAL RANGE 0 TO 64; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC64 ( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO Blk_64_Num; + BEGIN + sector := Addr/16#10000#; + AddrLOW := sector*16#10000#; + AddrHIGH := sector*16#10000# + 16#0FFFF#; + END ADDRHILO_SEC64; + + PROCEDURE ADDRHILO_SEC32 ( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO Blk_32_Num; + BEGIN + sector := Addr/16#8000#; + AddrLOW := sector*16#8000#; + AddrHIGH := sector*16#8000# + 16#7FFF#; + END ADDRHILO_SEC32; + + PROCEDURE ADDRHILO_SEC4 ( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO Blk_4_Num; + BEGIN + sector := Addr/16#1000#; + AddrLOW := sector*16#1000#; + AddrHIGH := sector*16#1000# + 16#0FFF#; + END ADDRHILO_SEC4; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + BEGIN + page := Addr/16#100#; + AddrLOW := Page*16#100#; + AddrHIGH := Page*16#100# + 16#FF#; + END AddrHILO_PG; + + PROCEDURE ADDRHILO_WRAP( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Address : NATURAL; + VARIABLE Wrap_size: NATURAL) IS + VARIABLE Addr_tmp : NATURAL; + VARIABLE Sect_wrap: NATURAL; + BEGIN + Addr_tmp := Address; + Sect_wrap := Addr_tmp/Wrap_size; + + AddrLOW := Sect_wrap*Wrap_size; + AddrHIGH := Sect_wrap*Wrap_size + (Wrap_size - 1); + END ADDRHILO_WRAP; + + BEGIN + --------------------------------------------------------------------------- + --Power Up time + --------------------------------------------------------------------------- + PoweredUp <= '1' AFTER tdevice_PU; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn,SOIn,SCK_ipd,CSNeg_ipd,HOLDNegIn,WPNegIn) + + -- Timing Check Variables + -- Setup/Hold Checks variables + VARIABLE Tviol_CSNeg_SCK : X01 := '0'; + VARIABLE TD_CSNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_SOIn_SCK : X01 := '0'; + VARIABLE TD_SOIn_SCK : VitalTimingDataType; + + VARIABLE Tviol_HOLDNeg_SCK : X01 := '0'; + VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_HOLDNegIn_SCK : X01 := '0'; + VARIABLE TD_HOLDNegIn_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNegIn_SCK : X01 := '0'; + VARIABLE TD_WPNegIn_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType; + + --Pulse Width and Period Check Variables + VARIABLE Pviol_SCK_slow : X01 := '0'; + VARIABLE PD_SCK_slow : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast : X01 := '0'; + VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quad : X01 := '0'; + VARIABLE PD_SCK_quad : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_read : X01 := '0'; + VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_pgers : X01 := '0'; + VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_slow_p : X01 := '0'; + VARIABLE PD_SCK_slow_p : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_p : X01 := '0'; + VARIABLE PD_SCK_fast_p : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quad_p : X01 := '0'; + VARIABLE PD_SCK_quad_p : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK, + SetupLow => tsetup_CSNeg_SCK, + HoldHigh => thold_CSNeg_SCK, + HoldLow => thold_CSNeg_SCK, + CheckEnabled => true, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK, + Violation => Tviol_CSNeg_SCK + ); + -- Setup/Hold Check between SI and SCK / + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => SIOut_z /= SIIn AND (NOT dual_read) + AND (NOT quad_read), + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + VitalSetupHoldCheck ( + TestSignal => SOIn, + TestSignalName => "SO", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => SOut_z /= SOIn AND QE = '1' + AND (read_out = '0'), + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SOIn_SCK, + Violation => Tviol_SOIn_SCK + ); + + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNegIn_SCK, + Violation => Tviol_HOLDNegIn_SCK + ); + + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => WPNegOut_zd /= WPNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNegIn_SCK, + Violation => Tviol_WPNegIn_SCK + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_HOLDNeg_SCK, + SetupLow => tsetup_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + CheckEnabled => QE = '0' AND HOLDNegIn /= 'X', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNeg_SCK, + Violation => Tviol_HOLDNeg_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => QE = '0', + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_setup, + Violation => Tviol_WPNeg_CSNeg_setup + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => QE = '0', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_hold, + Violation => Tviol_WPNeg_CSNeg_hold + ); + + --Pulse Width and Period Check Variables + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_slow_negedge, + PulseWidthHigh => tpw_SCK_slow_posedge, + PeriodData => PD_SCK_slow, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_slow, + HeaderMsg => InstancePath & PartID, + CheckEnabled => slow_read + ); + + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_fast_negedge, + PulseWidthHigh => tpw_SCK_fast_posedge, + PeriodData => PD_SCK_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd + ); + + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_quad_negedge, + PulseWidthHigh => tpw_SCK_quad_posedge, + PeriodData => PD_SCK_quad, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quad, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quad_read OR pp_quad + ); + + -- Pulse Width Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CSNeg_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => slow_read OR fast_rd OR dual_read OR + quad_read + ); + + -- Pulse Width Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pger_posedge, + PeriodData => PD_CSNeg_pgers, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_pgers, + HeaderMsg => InstancePath & PartID, + CheckEnabled => true); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_slow, + PeriodData => PD_SCK_slow_p, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_slow_p, + HeaderMsg => InstancePath & PartID, + CheckEnabled => slow_read + ); + + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast, + PeriodData => PD_SCK_fast_p, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_p, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd OR dual_read + ); + + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_quad, + PeriodData => PD_SCK_quad_p, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quad_p, + HeaderMsg => InstancePath & PartID, + CheckEnabled => pp_quad OR quad_read + ); + + Violation := Tviol_CSNeg_SCK OR + Tviol_SI_SCK OR + Tviol_HOLDNeg_SCK OR + Tviol_WPNeg_CSNeg_setup OR + Tviol_WPNeg_CSNeg_hold OR + Tviol_HOLDNegIn_SCK OR + Tviol_WPNegIn_SCK OR + Tviol_SOIn_SCK OR + Pviol_SCK_slow OR + Pviol_SCK_fast OR + Pviol_CSNeg_read OR + Pviol_CSNeg_pgers OR + Pviol_SCK_slow_p OR + Pviol_SCK_fast_p OR + Pviol_SCK_quad_p OR + Pviol_SCK_quad; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + + --------------------------------------------------------------------------- + -- sequential process for FSM state transition + --------------------------------------------------------------------------- + StateTransition : PROCESS(next_state,PoweredUp) + + BEGIN + IF PoweredUp = '1' THEN + IF next_state'EVENT THEN + current_state <= next_state; + END IF; + END IF; + END PROCESS StateTransition; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd) + + TYPE bus_cycle_type IS (STAND_BY, + OPCODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + + TYPE quad_data_type IS ARRAY (0 TO 511) OF INTEGER RANGE 0 TO 15; + + VARIABLE bus_cycle_state : bus_cycle_type; + + VARIABLE opcode_cnt : NATURAL := 0; + VARIABLE addr_cnt : NATURAL := 0; + VARIABLE mode_cnt : NATURAL := 0; + VARIABLE wrap_cnt : NATURAL := 0; + VARIABLE dummy_cnt : NATURAL := 0; + VARIABLE data_cnt : NATURAL := 0; + VARIABLE bit_cnt : NATURAL := 0; + + VARIABLE Data_in : std_logic_vector(2047 downto 0) + := (others => '0'); + VARIABLE opcode : std_logic_vector(7 downto 0); + VARIABLE opcode_in : std_logic_vector(7 downto 0); + VARIABLE opcode_double : std_logic_vector(15 downto 0); + VARIABLE opcode_double_in : std_logic_vector(15 downto 0); + VARIABLE addr_bytes : std_logic_vector(23 downto 0); + VARIABLE Address_in : std_logic_vector(23 downto 0); + VARIABLE mode_bits : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); +-- VARIABLE wrap_byte : std_logic_vector(7 downto 0); + VARIABLE wrap_in : std_logic_vector(7 downto 0); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + + BEGIN + + IF falling_edge(CSNeg_ipd) THEN + IF (bus_cycle_state = STAND_BY) THEN + bus_cycle_state := OPCODE_BYTE; + Instruct <= NONE; + write <= '1'; + opcode_cnt := 0; + addr_cnt := 0; + data_cnt := 0; + mode_cnt := 0; + wrap_cnt := 0; + dummy_cnt := 0; + ELSIF (bus_cycle_state = DATA_BYTES AND + mode_bits(5 DOWNTO 4) = "10") THEN + bus_cycle_state := ADDRESS_BYTES; + dummy_cnt := 0; + opcode_cnt := 0; + END IF; + END IF; + + IF rising_edge(SCK_ipd) AND (PoweredUp = '1') THEN + IF (CSNeg_ipd = '0') THEN + CASE (bus_cycle_state) IS + WHEN OPCODE_BYTE => + IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF opcode_cnt = BYTE THEN + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := opcode_in(7-i); + END LOOP; + + CASE opcode IS + WHEN "00000110" => -- 06H + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "01010000" => + Instruct <= WRENV; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000101" => -- 05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => -- 35h + Instruct <= RDSR2; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => -- 01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => -- 03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00001011" => -- 0Bh + Instruct <= FAST_READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111011" => -- 3Bh + Instruct <= FAST_DREAD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01101011" => -- 6Bh + Instruct <= FAST_QREAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "10111011" => -- BBh + Instruct <= FAST_DREAD_2; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11101011" => -- EBh + Instruct <= FAST_QREAD_4; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "11100111" => --E7h + Instruct <= W_QREAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "11100011" => -- E3h + Instruct <= WOCT_QREAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "01110111" => -- 77h + Instruct <= SET_BURST_WRAP; + IF (QE = '1') THEN + bus_cycle_state := DUMMY_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "11111111" => -- FFh + Instruct <= CONT_RD_RST; + bus_cycle_state := MODE_BYTE; + WHEN "00000010" => -- 02H + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => -- 32h + Instruct <= QPP; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "00100000" => -- 20h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01010010" => -- 52h + Instruct <= BE_32; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11011000" => -- D8h + Instruct <= BE_64; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11000111" | "01100000" => -- C7 or 60h + Instruct <= CE; + bus_cycle_state := DATA_BYTES; + WHEN "01110101" => -- 75h + Instruct <= ERS_PG_SUSP; + bus_cycle_state := DATA_BYTES; + WHEN "01111010" => -- 7Ah + Instruct <= ERS_PG_RES; + bus_cycle_state := DATA_BYTES; + WHEN "10111001" => -- B9h + Instruct <= DP; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => -- ABh + Instruct <= RES_RD_ID; + bus_cycle_state := DUMMY_BYTES; + WHEN "10010000" => -- 90h + Instruct <= RDID; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10010010" => -- 92h + Instruct <= RDID_DUAL; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10010100" => -- 94h + Instruct <= RDID_QUAD; + IF (QE = '1') THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + WHEN "01001011" => -- 4Bh + Instruct <= RD_UNIQ_ID; + bus_cycle_state := DUMMY_BYTES; + WHEN "10011111" => -- 9Fh + Instruct <= RDIDJ; + bus_cycle_state := DATA_BYTES; + WHEN "01011010" => -- 5Ah + Instruct <= RD_SFDP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01000100" => -- 44h + Instruct <= ERS_SCREG; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01000010" => -- 42h + Instruct <= PG_SCREG; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001000" => -- 48h + Instruct <= RD_SCREG; + bus_cycle_state := ADDRESS_BYTES; + + WHEN OTHERS => + NULL; + + END CASE; + END IF; + ELSE + REPORT "Device is in HOLD mode, opcode" + SEVERITY NOTE; + END IF; + + WHEN ADDRESS_BYTES => + IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN + IF (Instruct = READ OR Instruct = FAST_READ OR + Instruct = FAST_DREAD OR Instruct = RDID OR + Instruct = SE OR Instruct = PP OR + Instruct = RD_SCREG OR Instruct = PG_SCREG OR + Instruct = RD_SFDP OR Instruct = BE_32 OR + Instruct = BE_64 OR Instruct = ERS_SCREG OR + ((Instruct = QPP OR Instruct = FAST_QREAD) + AND QE = '1')) THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + + IF (Instruct = PP OR Instruct = QPP + OR Instruct = READ OR Instruct = SE + OR Instruct = BE_32 OR Instruct = BE_64 + OR Instruct = RDID OR Instruct = PG_SCREG + OR Instruct = ERS_SCREG) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct = RDID_DUAL OR + Instruct = FAST_DREAD_2) THEN + IF (SOIn /= 'Z') THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt + 1):= SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF (addr_cnt = (3*BYTE)/2) THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF (mode_bits(5 downto 4) = "10") THEN + opcode_double_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF (opcode_cnt = 2*BYTE) THEN + FOR I IN 15 DOWNTO 0 LOOP + opcode_double(i) := + opcode_double_in(15-i); + END LOOP; + IF (opcode_double="1111111111111111") THEN + Instruct <= CONT_RD_RST; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + ELSIF (QE = '1' AND (Instruct = FAST_QREAD_4 OR + Instruct = W_QREAD OR Instruct = WOCT_QREAD OR + Instruct = RDID_QUAD)) THEN + IF (SOIn /= 'Z') THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF (addr_cnt = (3*BYTE)/4) THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF (mode_bits(5 downto 4) = "10") THEN + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF (opcode_cnt = BYTE) THEN + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := + opcode_in(7-i); + END LOOP; + IF (opcode = "11111111") THEN + Instruct <= CONT_RD_RST; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + END IF; + ELSE + REPORT "Device is in HOLD mode, addr" + SEVERITY NOTE; + END IF; + + WHEN MODE_BYTE => + IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN + IF (Instruct = SET_BURST_WRAP AND QE = '1') THEN + wrap_in(4*wrap_cnt) := HOLDNegIn; + wrap_in(4*wrap_cnt+1) := WPNegIn; + wrap_in(4*wrap_cnt+2) := SOIn; + wrap_in(4*wrap_cnt+3) := SIIn; + wrap_cnt := wrap_cnt + 1; + IF (wrap_cnt = BYTE/4) THEN + wrap_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + wrap_byte(i) := wrap_in(7-i); + END LOOP; + bus_cycle_state := DATA_BYTES; + END IF; + CASE (wrap_byte(6 DOWNTO 5)) IS + WHEN "00" => + w_size := 8; + WHEN "01" => + w_size := 16; + WHEN "10" => + w_size := 32; + WHEN "11" => + w_size := 64; + WHEN OTHERS => + NULL; + END CASE; + ELSIF ((Instruct = FAST_QREAD_4 OR + Instruct = WOCT_QREAD OR Instruct = W_QREAD OR + Instruct = RDID_QUAD ) AND QE = '1') THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF (mode_cnt = BYTE/4) THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bits(i) := mode_in(7-i); + END LOOP; + IF (Instruct = WOCT_QREAD) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct = RDID_DUAL OR + Instruct = FAST_DREAD_2) THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF (mode_cnt = BYTE/2) THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bits(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSE + REPORT "Device is in HOLD mode, mode" + SEVERITY NOTE; + END IF; + + WHEN DUMMY_BYTES => + IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN + IF ((Instruct = FAST_QREAD_4 OR + Instruct = RDID_QUAD) AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE/2) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = W_QREAD AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE/4) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = SET_BURST_WRAP AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = 3*BYTE/4) THEN + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF (Instruct = FAST_QREAD AND QE = '1') THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct=FAST_READ OR Instruct=RD_SFDP + OR Instruct = FAST_DREAD OR Instruct=RD_SCREG) THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = 4*BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSE -- for RES_RD_ID + dummy_cnt := dummy_cnt + 1; + IF (dummy_cnt = 3*BYTE) THEN + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSE + REPORT "Device is in HOLD mode, dummy" + SEVERITY NOTE; + END IF; -- end of DUMMY_BYTES + + WHEN DATA_BYTES => + IF (Instruct = PP OR Instruct = WRR OR + Instruct = PG_SCREG) THEN + IF ((HOLDNeg_pullup = '1' AND QE='0') OR QE='1') THEN + IF (data_cnt > 2047) THEN + --In case of serial mode and PP,IF more than + --256 bytes are sent to the device + IF (bit_cnt = 0) THEN + FOR I IN 0 TO (255*BYTE-1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in(2040 + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF (bit_cnt = 8) THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + ELSE + REPORT "Device is in HOLD mode, data" + SEVERITY NOTE; + END IF; + ELSIF (Instruct = QPP AND QE ='1') THEN + pp_quad := TRUE; + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF (data_cnt > 511) THEN + --In case of quad mode and QPP,IF more than + -- 256 bytes are sent to the device + FOR I IN 0 TO 510 LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in(511) := to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF (quad_nybble /= "ZZZZ") THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + END IF; + + WHEN OTHERS => NULL; + END CASE; + END IF; + END IF; + + IF falling_edge(SCK_ipd) AND (bus_cycle_state = DATA_BYTES AND + CSNeg_ipd ='0') THEN + IF (((Instruct = RDSR OR Instruct = RDSR2 OR + Instruct = FAST_READ OR Instruct = FAST_DREAD OR + Instruct = FAST_DREAD_2 OR Instruct = RES_RD_ID OR + Instruct = RDID OR Instruct = RDID_DUAL OR + Instruct = RD_UNIQ_ID OR Instruct = RDIDJ OR + Instruct = RD_SFDP OR Instruct = RD_SCREG OR + Instruct = READ) AND ((HOLDNeg_pullup ='1' AND QE='0') OR QE='1')) + OR ((Instruct = FAST_QREAD OR Instruct = FAST_QREAD_4 OR + Instruct = W_QREAD OR Instruct = RDID_QUAD OR + Instruct = WOCT_QREAD) AND QE='1')) THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + IF (bus_cycle_state=MODE_BYTE AND Instruct = CONT_RD_RST) THEN + mode_bits(5 downto 4) := "11"; + mode_bits(7 downto 6) := "00"; + mode_bits(3 downto 0) := "0000"; + bus_cycle_state := STAND_BY; + ELSIF (bus_cycle_state=DATA_BYTES AND + NOT (mode_bits(5 downto 4)="10")) THEN + bus_cycle_state := STAND_BY; + CASE (Instruct) IS + WHEN WREN | WRDI | SET_BURST_WRAP | SE | BE_32 | BE_64 | + CE | ERS_PG_RES | DP | ERS_SCREG => + + IF (data_cnt = 0) THEN + write <= '0'; + END IF; + WHEN WRENV => + write <= '0'; + wren_vlt_flag := TRUE; + + WHEN RES_RD_ID => + write <= '0'; + res_flag := TRUE; + + WHEN WRR => + IF (data_cnt = 8) THEN + --If CS# is driven high after eight + --cycle,only the Status Register is + --written to. + write <= '0'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= Data_in(7-i); + END LOOP; + ELSIF (data_cnt = 16) THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= Data_in(7-i); + END LOOP; + + FOR j IN 0 TO 7 LOOP + Status_reg2_in(j) <= Data_in(15-j); + END LOOP; + END IF; + + WHEN PP | PG_SCREG => + IF (data_cnt > 0) THEN + IF ((data_cnt mod 8) = 0) THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 7 DOWNTO 0 LOOP + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + + IF (data_cnt > 256*BYTE) THEN + Byte_number <= 255; + ELSE + Byte_number <= ((data_cnt/8) - 1); + END IF; + END IF; + END IF; + + WHEN QPP => + IF (data_cnt >0) THEN + IF ((data_cnt mod 2) = 0) THEN + write <= '0'; + FOR I IN 0 TO 255 LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + + IF (data_cnt > 256*BYTE/4) THEN + Byte_number <= 255; + ELSE + Byte_number <= ((data_cnt/2) - 1); + END IF; + END IF; + END IF; + + WHEN others => + null; + + END CASE; + + ELSIF (bus_cycle_state=DATA_BYTES AND + (mode_bits(5 DOWNTO 4)="10")) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := STAND_BY; + IF (HOLDNeg_pullup ='1' AND (Instruct = RES_RD_ID) AND + (dummy_cnt = 0)) THEN + write <= '0'; + res_flag := FALSE; + END IF; + END IF; + END IF; -- end of rising_edge_CSNeg_ipd + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART, PGSUSP, PGRES) + VARIABLE pob : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF Instruct = PP OR Instruct = QPP OR Instruct = PG_SCREG THEN + IF LongTimming THEN + pob := tdevice_PP; + ELSE + pob := tdevice_PP / 10; + END IF; + END IF; + IF rising_edge(PSTART) AND PDONE = '1' THEN + elapsed := 0 ns; + PDONE <= '0', '1' AFTER pob; + start := NOW; + ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN + elapsed := NOW - start; + duration := pob - elapsed; + PDONE <= '0'; + ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN + start := NOW; + PDONE <= '0', '1' AFTER duration; + END IF; + + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WRR; + ELSE + wob := tdevice_WRR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register when Write Enable for + -- Volatile Status Register was issued + --------------------------------------------------------------------------- + + WriteTimeVlt : PROCESS(VLTSTART) + VARIABLE wvob : time; + BEGIN + wvob := tdevice_VRR; + IF rising_edge(VLTSTART) AND VLTDONE = '1' THEN + VLTDONE <= '0' , '1' AFTER wvob; + END IF; + END PROCESS WriteTimeVlt; + + --------------------------------------------------------------------------- + -- Timing control for the Erase Operation + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART, ESUSP, ERES) + VARIABLE seo : time; + VARIABLE beo32 : time; + VARIABLE beo64 : time; + VARIABLE ceo : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + seo := tdevice_SE; + beo32 := tdevice_BE1; + beo64 := tdevice_BE2; + ceo := tdevice_CE; + ELSE + seo := tdevice_SE / 100; + beo32 := tdevice_BE1 / 100; + beo64 := tdevice_BE2 / 100; + ceo := tdevice_CE / 100; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = CE THEN + duration := ceo; + ELSIF Instruct = BE_64 THEN + duration := beo64; + ELSIF Instruct = BE_32 THEN + duration := beo32; + ELSIF Instruct = BE_64 THEN + duration := beo64; + ELSE -- sector erase 4KB, instruct SE + duration := seo; + END IF; + elapsed := 0 ns; + EDONE <= '0', '1' AFTER duration; + start := NOW; + ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN + elapsed := NOW - start; + duration := duration - elapsed; + EDONE <= '0'; + ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN + start := NOW; + EDONE <= '0', '1' AFTER duration; + END IF; + + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS(CSNeg_ipd) + BEGIN + IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, WDONE, ERSSUSP_out, RES1_out, + ERSRES_out, PRGSUSP_out, EDONE,PRGRES_out, DP_out, PDONE, + VLTDONE,RES2_out) + + BEGIN + + IF rising_edge(PoweredUp) THEN + next_state <= IDLE; + ELSE + CASE current_state IS + WHEN IDLE => + IF falling_edge(write) THEN + IF (Instruct = WRR AND (SRP1='0' AND + (SRP0='0' OR (SRP0='1' AND WPNeg ='1')))) THEN + IF (WEL='1' AND NOT (wren_vlt_flag)) THEN + next_state <= WRITE_SR; + ELSIF (WEL='0' AND wren_vlt_flag) THEN + next_state <= WRITE_SR_V; + END IF; + ELSIF (Instruct = PP AND WEL='1') THEN + sect := Address / 16#1000#; + sect_tmp_pg := sect; + IF (Sec_Prot(sect) = '0') THEN + next_state <= PAGE_PG; + END IF; + ELSIF (Instruct = QPP AND WEL='1' AND QE='1') THEN + sect := Address / 16#1000#; + sect_tmp_pg := sect; + IF (Sec_Prot(sect) = '0') THEN + next_state <= PAGE_PG; + END IF; + ELSIF (Instruct = PG_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect < 4 AND sect > 0) AND + LB_bits(sect-1)='0') THEN + next_state <= PAGE_PG; + END IF; + ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF ((Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) AND WEL='1') THEN + sect := Address / 16#1000#; + sect_tmp_ers := sect; + IF (Sec_Prot(sect) = '0') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF (Instruct = CE AND WEL='1' AND + ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR + (CMP='1' AND BP2='1' AND BP1='1' AND BP0='1'))) THEN + next_state <= BULK_ERS; + ELSE + next_state <= IDLE; + END IF; + ELSIF rising_edge(DP_out) THEN + next_state <= DP_DOWN; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; -- end of WRITE_SR + + WHEN WRITE_SR_V => + IF rising_edge(VLTDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF (PRGSUSP_out'event AND PRGSUSP_out = '1') THEN + next_state <= PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; -- end of PAGE_PG + + WHEN PG_SUSP => + IF (PRGRES_out'event AND PRGRES_out = '1') THEN + next_state <= PAGE_PG; + ELSIF falling_edge(write) THEN + IF (Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) THEN + sect := Address / 16#1000#; + IF ((Sec_Prot(sect) = '0') AND + (sect /= sect_tmp_pg)) THEN + next_state <= PG_SUSP_ERS; + END IF; + END IF; + END IF; -- end of PG_SUSP + + WHEN PG_SUSP_ERS => + IF rising_edge(EDONE) THEN + next_state <= PG_SUSP; + ELSE + next_state <= PG_SUSP_ERS; + END IF; + + WHEN BULK_ERS => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN SECTOR_ERS => + IF (ERSSUSP_out'event AND ERSSUSP_out = '1') THEN + next_state <= ERS_SUSP; + ELSIF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN ERS_SUSP => + IF (ERSRES_out'event AND ERSRES_out = '1') THEN + next_state <= SECTOR_ERS; + ELSIF falling_edge(write) THEN + IF (Instruct = PP OR (Instruct = QPP AND QE='1')) THEN + sect := Address / 16#1000#; + IF ((Sec_Prot(sect) = '0') AND + (sect /= sect_tmp_ers)) THEN + next_state <= ERS_SUSP_PG; + END IF; + ELSIF (Instruct = PG_SCREG) THEN + sect := Address / 16#1000#; + IF ((sect < 4 AND sect > 0) AND + LB_bits(sect-1)='0') THEN + next_state <= ERS_SUSP_PG; + END IF; + END IF; + END IF; + + WHEN ERS_SUSP_PG => + IF rising_edge(PDONE) THEN + next_state <= ERS_SUSP; + ELSE + next_state <= ERS_SUSP_PG; + END IF; + + WHEN DP_DOWN => + IF rising_edge(RES1_out) OR rising_edge(RES2_out) THEN + next_state <= IDLE; + END IF; + + END CASE; + END IF; + END PROCESS StateGen; + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(read_out, Instruct, SCK_ipd, change_addr, write, + Address, PDONE, WDONE, EDONE, ERSSUSP_out, PoweredUp, + CSNeg_ipd, RES1_out, ERSRES_out, PRGSUSP_out,PRGRES_out, + VLTDONE, current_state, DP_out, RES2_out,SUSP_FL_OUT) + + VARIABLE WData : WByteType:= (OTHERS => MaxData); + + VARIABLE oe : boolean := FALSE; + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + + VARIABLE AddrLo_ers : NATURAL; + VARIABLE AddrHi_ers : NATURAL; + VARIABLE AddrLo_wrap : NATURAL; + VARIABLE AddrHi_wrap : NATURAL; + + VARIABLE Addr : NATURAL; + VARIABLE Addr_w : NATURAL; + VARIABLE Addr_ers : NATURAL; + VARIABLE Addr_tmp : NATURAL; + VARIABLE Addr_tmp_2 : NATURAL; + VARIABLE Addr_tmp_3 : NATURAL; + VARIABLE Addr_screg : NATURAL; + VARIABLE Addr_screg_tmp : NATURAL; + + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(23 downto 0); + VARIABLE ident_out2 : std_logic_vector(15 downto 0); + VARIABLE uniq_id : std_logic_vector(63 downto 0); + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + + VARIABLE wr_cnt : NATURAL RANGE 0 TO 255; + VARIABLE cnt : NATURAL RANGE 0 TO 256 := 0; + + BEGIN + + oe := rising_edge(read_out) AND PoweredUp = '1'; + + IF Instruct'EVENT THEN + read_cnt := 0; + + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + read_id <= false; + pp_quad := FALSE; + + IF (current_state = IDLE AND DP_in = '1') THEN + REPORT "Command results can be corrupted " + SEVERITY WARNING; + END IF; + END IF; + + IF rising_edge(PoweredUp) THEN + WEL := '0'; + BUSY := '0'; + SUS := '0'; + change_prot_bits <= '1', '0' AFTER 1 ns; + END IF; + + IF change_addr'EVENT THEN + read_addr := Address; + END IF; + + IF RES1_out'EVENT AND RES1_out = '1' THEN + RES1_in <= '0'; + END IF; + + IF RES2_out'EVENT AND RES2_out = '1' THEN + RES2_in <= '0'; + END IF; + + IF SUSP_FL_OUT'EVENT AND SUSP_FL_OUT = '1' THEN + SUSP_FL_IN <= '0'; + END IF; + + CASE current_state IS + + WHEN IDLE => + + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + read_id <= false; + sr_read <= false; + res_flag := FALSE; + pg_screg_flag <= false; + ers_screg_flag <= false; + + IF falling_edge(write) AND DP_in ='0' THEN + read_cnt := 0; + IF (Instruct = WREN) THEN + WEL := '1'; + ELSIF (Instruct = WRDI) THEN + WEL := '0'; + ELSIF (Instruct = WRR) THEN + IF(SRP1='0' AND (SRP0='0' OR + (SRP0='1' AND WPNeg='1'))) THEN + IF WEL='1' AND NOT (wren_vlt_flag) THEN + WSTART <= '1', '0' AFTER 5 ns; + BUSY := '1'; + ELSIF (WEL='0' AND wren_vlt_flag) THEN + VLTSTART <= '1', '0' AFTER 5 ns; + END IF; + ELSE + WEL := '0'; + END IF; + ELSIF ((Instruct = PP OR (Instruct = QPP AND QE='1')) + AND WEL='1' AND PDONE='1') THEN + sect := Address / 16#1000#; + IF (Sec_Prot(sect) = '0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + Addr := Address; + Addr_tmp:= Address; + wr_cnt := Byte_number; + + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PG_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + wr_cnt := Byte_number; + Addr_screg := Address mod 16#1000#; + Addr_screg_tmp := Address mod 16#1000#; + pg_screg_flag <= true; + + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + + ELSE + WEL := '0'; + END IF; + ELSIF ((Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) AND WEL='1') THEN + sect := Address / 16#1000#; + IF (Sec_Prot(sect) = '0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + Addr_ers := Address; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = CE AND WEL='1') THEN + IF ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR + (CMP='1' AND BP2='1' AND BP1='1' AND BP0='1')) THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN + sect := Address / 16#1000#; + IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + SA <= sect; + ers_screg_flag <= true; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = DP) THEN + RES2_in <= '0'; + RES1_in <= '0'; + DP_in <= '1'; + END IF; + -- end of falling_edge_write + ELSIF (oe AND DP_in='0') THEN + IF (Instruct = RDSR) THEN + --Read Status Register + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDSR2) THEN + sr_read <= true; + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN + IF (Instruct = READ) THEN + fast_rd <= false; + dual_read <= false; + slow_read <= true; + quad_read <= false; + sr_read <= false; + ELSE + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + END IF; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF (Instruct=FAST_DREAD OR Instruct=FAST_DREAD_2) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF ((Instruct=FAST_QREAD OR Instruct=FAST_QREAD_4 OR + Instruct=W_QREAD OR Instruct=WOCT_QREAD) + AND QE='1') THEN + IF ((Instruct=W_QREAD AND (Address mod 2 /= 0) ) OR + (Instruct=WOCT_QREAD AND + (Address mod 16 /= 0))) THEN + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + REPORT "Word Read can't execute Wrong Address" + SEVERITY NOTE; + END IF; + ELSE + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + Addr_w := Address; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + IF (wrap_byte(4)='0' AND (Instruct=FAST_QREAD_4 + OR Instruct=W_QREAD)) THEN + ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap, + Addr_w,w_size); + IF (read_addr = AddrHi_wrap) THEN + read_addr := AddrLo_wrap; + ELSE + read_addr := read_addr + 1; + END IF; + ELSE + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR + Instruct=RDID_QUAD) THEN + IF (read_addr mod 2 = 0) THEN + ident_out2 := to_slv(Manuf_ID,8) & + to_slv(Device_ID1,8); + ELSE + ident_out2 := to_slv(Device_ID1,8) & + to_slv(Manuf_ID,8); + END IF; + read_id <= true; + IF (Instruct = RDID) THEN + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 16) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDID_DUAL) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-2*read_cnt); + SIOut_zd <= ident_out2(14-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSE -- (Instruct = RDID_QUAD) + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + HOLDNegOut_zd <= ident_out2(15-4*read_cnt); + WPNegOut_zd <= ident_out2(14-4*read_cnt); + SOut_zd <= ident_out2(13-4*read_cnt); + SIOut_zd <= ident_out2(12-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + -- unique ID number is not in data sheet + read_id <= true; + uniq_id := to_slv(Unique_id_2,32)& + to_slv(Unique_id_1,32); + SOut_zd <= uniq_id(63-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 64) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDIDJ) THEN + read_id <= true; + ident_out := to_slv(Manuf_ID,8) & + to_slv(Device_ID2,8) & to_slv(Device_ID3,8); + SOut_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 24) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RD_SFDP) THEN + IF (read_addr / 16#100# = 0) THEN + Addr_tmp_2 := (read_addr mod 16#100#); + data_out := to_slv(SFDP_array(Addr_tmp_2),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = SFDP_HiAddr) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Given SFDP address is out of range" + SEVERITY NOTE; + END IF; + END IF; + ELSIF (Instruct = RD_SCREG) THEN + Addr_tmp_2 := read_addr / 16#100#; + Addr_tmp_3 := read_addr mod 16#100#; + IF (Addr_tmp_2 = 16) THEN + -- Security Register No.1 + data_out := to_slv(Security_Reg1(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 32) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg2(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 48) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg3(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Security Reg address is out of range " + SEVERITY NOTE; + END IF; + END IF; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr mod 256 = SecReg_HiAddr) THEN + read_addr := (read_addr/256)*(SecReg_HiAddr+1); + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF Instruct = RES_RD_ID THEN + read_id <= true; + data_out := to_slv(Device_ID1,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; -- end of oe + ELSIF rising_edge(DP_out) THEN + DP_in <= '0'; + END IF; -- end of IDLE state + + WHEN WRITE_SR => + + IF (WDONE ='1') THEN + BUSY := '0'; + WEL := '0'; + + SRP0 := Status_reg1_in(7); + SEC := Status_reg1_in(6); + TB := Status_reg1_in(5); + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + BP_bits := BP2 & BP1 & BP0; + CMP := Status_reg2_in(6); + QE := Status_reg2_in(1); + -- SRP1 bit will only change value from '0' to '1' + -- if SRP1 is '1' than Status Register is protected + --and is not possible to write it + SRP1 := Status_reg2_in(0); + + IF LB3 = '0' THEN + LB3 := Status_reg2_in(5); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + + IF LB2 = '0' THEN + LB2 := Status_reg2_in(4); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + IF LB1 = '0' THEN + LB1 := Status_reg2_in(3); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + LB_bits := LB3 & LB2 & LB1; + change_prot_bits <= '1' , '0' AFTER 2 ns; + END IF; -- end of WDONE + + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; -- end of WRITE_SR + + WHEN WRITE_SR_V => + + IF (VLTDONE = '1') THEN + SRP0 := Status_reg1_in(7); + SEC := Status_reg1_in(6); + TB := Status_reg1_in(5); + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + BP_bits := BP2 & BP1 & BP0; + CMP := Status_reg2_in(6); + QE := Status_reg2_in(1); + -- SRP1 bit will only change value from '0' to '1' + -- if SRP1 is '1' than Status Register is protected + --and is not possible to write it + SRP1 := Status_reg2_in(0); + IF LB3 = '0' THEN + LB3 := Status_reg2_in(5); + ELSIF LB2 = '0' THEN + LB2 := Status_reg2_in(4); + ELSIF LB1 = '0' THEN + LB1 := Status_reg2_in(3); + ELSE + REPORT "LB bit is set to '1', no change allowed" + SEVERITY NOTE; + END IF; + + change_prot_bits <= '1' , '0' AFTER 2 ns; + + wren_vlt_flag := FALSE; + END IF; + + WHEN PAGE_PG | ERS_SUSP_PG => + + IF current_state'event AND PDONE = '0' THEN + + IF (Instruct /= PG_SCREG) THEN + ADDRHILO_PG(AddrLo, AddrHi, Addr); + END IF; + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + IF (Instruct = PG_SCREG) THEN + IF (sect = 1) THEN + old_int := Security_Reg1(Addr_screg + i - cnt); + ELSIF (sect = 2) THEN + old_int := Security_Reg2(Addr_screg + i - cnt); + ELSE + old_int := Security_Reg3(Addr_screg + i - cnt); + END IF; + ELSE + old_int := Mem(Addr + i - cnt); + END IF; + IF (new_int > -1) THEN + new_bit := to_slv(new_int,8); + IF (old_int > -1) THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + IF (Instruct = PG_SCREG) THEN + IF (sect = 1) THEN + Security_Reg1(Addr_screg + i - cnt) := - 1; + ELSIF (sect = 2) THEN + Security_Reg2(Addr_screg + i - cnt) := - 1; + ELSE + Security_Reg3(Addr_screg + i - cnt) := - 1; + END IF; + ELSE + Mem(Addr + i - cnt) := - 1; + END IF; + IF (Instruct /= PG_SCREG) THEN + IF ((Addr + i) = AddrHi) THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + ELSE + IF Addr_screg + i = SecReg_HiAddr THEN + Addr_screg := SecReg_LoAddr; + cnt := i + 1; + END IF; + END IF; + END LOOP; + cnt := 0; + + END IF; + + IF (PDONE = '1') THEN + IF (current_state /= ERS_SUSP_PG) THEN + BUSY := '0'; + END IF; + WEL := '0'; + + FOR I IN 0 TO wr_cnt LOOP + IF pg_screg_flag THEN + IF (sect = 1) THEN + Security_Reg1(Addr_screg_tmp + i - cnt) :=WData(i); + ELSIF (sect = 2) THEN + Security_Reg2(Addr_screg_tmp + i - cnt) :=WData(i); + ELSE + Security_Reg3(Addr_screg_tmp + i - cnt) :=WData(i); + END IF; + IF ((Addr_screg_tmp + i) = SecReg_HiAddr) THEN + Addr_screg_tmp := SecReg_LoAddr; + cnt := i + 1; + END IF; + ELSE + Mem(Addr_tmp + i - cnt) := WData(i); + IF ((Addr_tmp + i) = AddrHi) THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END IF; + END LOOP; + END IF; -- end of PDONE + + IF (Instruct = ERS_PG_SUSP AND current_state = PAGE_PG AND + SUSP_FL_IN = '0') THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + END IF; + + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + + WHEN PG_SUSP => + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + BUSY := '0'; + IF (PRGSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN + PRGSUSP_in <= '0'; + --The BUSY bit in the Status Register will indicate that + --the device is ready for another operation. +-- BUSY := '0'; + --The SuspEND (SUS) bit in the Status Register2 will + --be set to the logical “1” state to indicate that the + --program operation has been suspENDed. + SUS := '1'; + END IF; + IF (PRGRES_out'event AND PRGRES_out = '1') THEN + PRGRES_in <= '0'; + BUSY := '1'; + END IF; + IF (SUS = '1') THEN + IF falling_edge(write) THEN + IF (Instruct = ERS_PG_RES) THEN + SUS := '0'; + PRGRES_in <= '1'; + SUSP_FL_IN <= '1'; + PGRES <= '1', '0' AFTER 5 ns; + ELSIF ((Instruct = SE OR Instruct = BE_32 OR + Instruct = BE_64) AND WEL='1') THEN + sect := Address / 16#1000#; + IF (sect /= sect_tmp_pg AND + Sec_Prot(sect) = '0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + BUSY := '1'; + Addr_ers := Address; + ELSE + BUSY := '0'; + REPORT "Can't erase sector,protected or susp." + SEVERITY NOTE; + END IF; + END IF; + ELSIF (oe) THEN + IF (Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDSR2) THEN + --Read Status Register 2 + sr_read <= true; + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN + IF (sect_tmp_pg /= read_addr / 16#1000#) THEN + IF (Instruct = READ) THEN + fast_rd <= false; + dual_read <= false; + slow_read <= true; + quad_read <= false; + sr_read <= false; + ELSE + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + END IF; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct=FAST_DREAD OR + Instruct=FAST_DREAD_2) THEN + IF sect_tmp_pg /= (read_addr / 16#1000#) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + END if; + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD + OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD) + AND QE = '1') THEN + IF sect_tmp_pg /= (read_addr / 16#1000#) THEN + IF ((Instruct=W_QREAD AND + Address mod 2 /= 0) OR + (Instruct=WOCT_QREAD AND + Address mod 16 /= 0)) THEN + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + REPORT "Word Read - Wrong Read Address" + SEVERITY NOTE; + END IF; + ELSE + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + Addr_w := Address; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + IF (wrap_byte(4)= '0' AND + (Instruct=FAST_QREAD_4 OR + Instruct=W_QREAD)) THEN + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap, Addr_w,w_size); + IF (read_addr = AddrHi_wrap) THEN + read_addr := AddrLo_wrap; + ELSE + read_addr := read_addr + 1; + END IF; + ELSE + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR + Instruct=RDID_QUAD) THEN + IF (read_addr mod 2 = 0) THEN + ident_out2 := to_slv(Manuf_ID,8) & + to_slv(Device_ID1,8); + ELSE + ident_out2 := to_slv(Device_ID1,8)& + to_slv(Manuf_ID,8); + END IF; + read_id <= true; + IF (Instruct = RDID) THEN + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 16) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDID_DUAL) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-2*read_cnt); + SIOut_zd <= ident_out2(14-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSE -- (Instruct = RDID_QUAD) + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + HOLDNegOut_zd <= ident_out2(15-4*read_cnt); + WPNegOut_zd <= ident_out2(14-4*read_cnt); + SOut_zd <= ident_out2(13-4*read_cnt); + SIOut_zd <= ident_out2(12-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + -- unique ID number is not in data sheet + read_id <= true; + uniq_id := to_slv(Unique_id_2,32)& + to_slv(Unique_id_1,32); + SOut_zd <= uniq_id(63-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 64) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDIDJ) THEN + read_id <= true; + ident_out := to_slv(Manuf_ID,8) & + to_slv(Device_ID2,8) & to_slv(Device_ID3,8); + SOut_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 24) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RD_SFDP) THEN + IF (read_addr / 16#100# = 0) THEN + Addr_tmp_2 := (read_addr mod 16#100#); + data_out := to_slv(SFDP_array(Addr_tmp_2),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = SFDP_HiAddr) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "SFDP address is out of range" + SEVERITY NOTE; + END IF; + END IF; + ELSIF (Instruct = RD_SCREG) THEN + Addr_tmp_2 := read_addr / 16#100#; + Addr_tmp_3 := read_addr mod 16#100#; + IF (Addr_tmp_2 = 16) THEN + -- Security Register No.1 + data_out := to_slv(Security_Reg1(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 32) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg2(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 48) THEN + -- Security Register No.2 + data_out := to_slv(Security_Reg3(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Security Reg addr is out of range " + SEVERITY NOTE; + END if; + END IF; + + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr mod 256) = SecReg_HiAddr THEN + read_addr:=(read_addr/256)* + (SecReg_HiAddr+1); + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + END IF; + + WHEN SECTOR_ERS | PG_SUSP_ERS => + IF (current_state'event AND EDONE = '0') THEN + IF (Instruct = SE) THEN + ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers); + ELSIF (Instruct = BE_32) THEN + ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers); + ELSIF (Instruct = BE_64) THEN + ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers); + END IF; + IF (Instruct /= ERS_SCREG) THEN + + FOR I IN AddrLo_ers TO AddrHi_ers LOOP + Mem(i) := -1; + END LOOP; + ELSE + IF (sect = 1) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg1(i) := -1; + END LOOP; + ELSIF (sect = 2) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg2(i) := -1; + END LOOP; + ELSE + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg3(i) := -1; + END LOOP; + END IF; + END IF; + END IF; + IF (EDONE = '1') THEN + IF (current_state /= PG_SUSP_ERS) THEN + BUSY := '0'; + END IF; + WEL := '0'; + IF (ers_screg_flag) THEN + IF (sect = 1) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg1(i) := MaxData; + END LOOP; + ELSIF (sect = 2) THEN + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg2(i) := MaxData; + END LOOP; + ELSE + FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP + Security_Reg3(i) := MaxData; + END LOOP; + END IF; + ELSE + FOR I IN AddrLo_ers TO AddrHi_ers LOOP + Mem(i) := MaxData; + END LOOP; + END IF; + END IF; + + IF (Instruct = ERS_PG_SUSP AND current_state = SECTOR_ERS AND + SUSP_FL_IN = '0') THEN + ESUSP <= '1', '0' AFTER 1 ns; + ERSSUSP_in <= '1'; + END IF; + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + + WHEN BULK_ERS => + IF (current_state'event AND EDONE = '0') THEN + FOR I IN 0 TO AddrRANGE LOOP + Mem(i) := -1; + END LOOP; + END IF; + IF (EDONE = '1') THEN + BUSY := '0'; + WEL := '0'; + FOR I IN 0 TO AddrRANGE LOOP + Mem(i) := MaxData; + END LOOP; + + END IF; + IF (oe AND Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + + WHEN ERS_SUSP => + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + pg_screg_flag <= false; + BUSY := '0'; + IF (ERSSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN + ERSSUSP_in <= '0'; + --The BUSY bit in the Status Register will indicate that + --the device is ready for another operation. +-- BUSY := '0'; + --The SuspEND (SUS) bit in the Status Register2 will + --be set to the logical “1” state to indicate that the + --program operation has been suspENDed. + SUS := '1'; + END IF; + IF (ERSRES_out'event AND ERSRES_out = '1') THEN + ERSRES_in <= '0'; + BUSY := '1'; + END IF; + IF (SUS = '1') THEN + IF falling_edge(write) THEN + IF (Instruct = ERS_PG_RES) THEN + SUS := '0'; + ERSRES_in <= '1'; + SUSP_FL_IN <= '1'; + ERES <= '1', '0' AFTER 5 ns; + ELSIF ((Instruct = PP OR (Instruct=QPP AND QE='1')) + AND WEL ='1') THEN + sect := Address / 16#1000#; + IF (sect /= sect_tmp_ers AND + Sec_Prot(sect)='0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + Addr := Address; + Addr_tmp:= Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + BUSY := '0'; + REPORT "Can't program sector,protected or susp" + SEVERITY NOTE; + END IF; + ELSIF (Instruct = PG_SCREG) THEN + sect := Address / 16#1000#; + IF ((sect <= 3 AND sect >=1) AND + LB_bits(sect-1)='0') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + BUSY := '1'; + SA <= sect; + wr_cnt := Byte_number; + Addr_screg := Address mod 16#1000#; + Addr_screg_tmp := Address mod 16#1000#; + pg_screg_flag <= true; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + END IF; + END IF; + ELSIF (oe) THEN + IF (Instruct = RDSR) THEN + --Read Status Register 1 + sr_read <= true; + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDSR2) THEN + --Read Status Register 2 + sr_read <= true; + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN + IF sect /= (read_addr / 16#1000#) THEN + IF (Instruct = READ) THEN + fast_rd <= false; + dual_read <= false; + slow_read <= true; + quad_read <= false; + sr_read <= true; + ELSE + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + END IF; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = FAST_DREAD OR + Instruct = FAST_DREAD_2) THEN + IF sect_tmp_ers /= (read_addr / 16#1000#) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + IF (Mem(read_addr) /= -1) THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD + OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD) + AND QE = '1') THEN + IF sect_tmp_ers /= (read_addr / 16#1000#) THEN + IF ((Instruct=W_QREAD AND + Address mod 2 /= 0) OR + (Instruct=WOCT_QREAD AND + Address mod 16 /=0)) THEN + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + REPORT "Bad Word Read- Wrong Address" + SEVERITY NOTE; + END IF; + ELSE + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + data_out := to_slv(Mem(read_addr),8); + Addr_w := Address; + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + read_cnt := 0; + IF (wrap_byte(4)='0' AND + (Instruct=FAST_QREAD_4 + OR Instruct=W_QREAD)) THEN + ADDRHILO_WRAP(AddrLo_wrap, + AddrHi_wrap,Addr_w,w_size); + IF (read_addr = AddrHi_wrap) THEN + read_addr := AddrLo_wrap; + ELSE + read_addr := read_addr + 1; + END IF; + ELSE + IF (read_addr = AddrRANGE) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 2) THEN + REPORT "Can't read suspended sector" + SEVERITY NOTE; + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR + Instruct=RDID_QUAD) THEN + IF (read_addr mod 2 = 0) THEN + ident_out2 := to_slv(Manuf_ID,8) & + to_slv(Device_ID1,8); + ELSE + ident_out2 := to_slv(Device_ID1,8) & + to_slv(Manuf_ID,8); + END IF; + read_id <= true; + IF (Instruct = RDID) THEN + fast_rd <= true; + dual_read <= false; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 16) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDID_DUAL) THEN + fast_rd <= false; + dual_read <= true; + slow_read <= false; + quad_read <= false; + sr_read <= false; + SOut_zd <= ident_out2(15-2*read_cnt); + SIOut_zd <= ident_out2(14-2*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + ELSE -- (Instruct = RDID_QUAD) + fast_rd <= false; + dual_read <= false; + slow_read <= false; + quad_read <= true; + sr_read <= false; + HOLDNegOut_zd <= ident_out2(15-4*read_cnt); + WPNegOut_zd <= ident_out2(14-4*read_cnt); + SOut_zd <= ident_out2(13-4*read_cnt); + SIOut_zd <= ident_out2(12-4*read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 4) THEN + read_cnt := 0; + END IF; + END IF; + ELSIF (Instruct = RD_UNIQ_ID) THEN + -- unique ID number is not in data sheet + read_id <= true; + uniq_id := to_slv(Unique_id_2,32)& + to_slv(Unique_id_1,32); + SOut_zd <= uniq_id(63-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 64) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RDIDJ) THEN + read_id <= true; + ident_out := to_slv(Manuf_ID,8) & + to_slv(Device_ID2,8) & to_slv(Device_ID3,8); + SOut_zd <= ident_out(23-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 24) THEN + read_cnt := 0; + END IF; + ELSIF (Instruct = RD_SFDP) THEN + IF (read_addr / 16#100# = 0) THEN + Addr_tmp_2 := (read_addr mod 16#100#); + data_out := to_slv(SFDP_array(Addr_tmp_2),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr = SFDP_HiAddr) THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Given SFDP address is out of range" + SEVERITY NOTE; + END IF; + END IF; + ELSIF (Instruct = RD_SCREG) THEN + Addr_tmp_2 := read_addr / 16#100#; + Addr_tmp_3 := read_addr mod 16#100#; + IF (Addr_tmp_2 = 16) THEN + -- Security Register No.1 + data_out :=to_slv(Security_Reg1(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 32) THEN + -- Security Register No.2 + data_out :=to_slv(Security_Reg2(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + ELSIF (Addr_tmp_2 = 48) THEN + -- Security Register No.2 + data_out :=to_slv(Security_Reg3(Addr_tmp_3),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; +-- END IF; + ELSE + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + REPORT "Security Reg addr is out of range" + SEVERITY NOTE; + END IF; + END IF; + IF (read_cnt = 8) THEN + read_cnt := 0; + IF (read_addr mod 256 = SecReg_HiAddr) THEN + read_addr := (read_addr/256)* + (SecReg_HiAddr+1); + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + END IF; + + WHEN DP_DOWN => + IF (oe AND Instruct = RES_RD_ID) THEN + read_id <= true; + data_out := to_slv(Device_ID1,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF (read_cnt = 8) THEN + read_cnt := 0; + END IF; + END IF; + IF falling_edge(write) THEN + IF (Instruct = RES_RD_ID) THEN + IF res_flag = true THEN + RES2_in <= '1'; + ELSE + RES1_in <= '1'; + END IF; + ELSE + REPORT "Device is in DPD Mode No instructions allowed" + SEVERITY NOTE; + END IF; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + END PROCESS Functional; + + --------------------------------------------------------------------------- + -- SFDP Process + --------------------------------------------------------------------------- + SFDPPreload: PROCESS + + BEGIN + ----------------------------------------------------------------------- + --SFDP array data + ----------------------------------------------------------------------- + + SFDP_array(16#00#) := 16#53#; + SFDP_array(16#01#) := 16#46#; + SFDP_array(16#02#) := 16#44#; + SFDP_array(16#03#) := 16#50#; + SFDP_array(16#04#) := 16#01#; + SFDP_array(16#05#) := 16#01#; + SFDP_array(16#06#) := 16#00#; + SFDP_array(16#07#) := 16#FF#; + SFDP_array(16#08#) := 16#EF#; + SFDP_array(16#09#) := 16#00#; + SFDP_array(16#0A#) := 16#01#; + SFDP_array(16#0B#) := 16#04#; + SFDP_array(16#0C#) := 16#80#; + SFDP_array(16#0D#) := 16#00#; + SFDP_array(16#0E#) := 16#00#; + SFDP_array(16#0F#) := 16#FF#; + SFDP_array(16#10#) := 16#EF#; + SFDP_array(16#11#) := 16#00#; + SFDP_array(16#12#) := 16#01#; + SFDP_array(16#13#) := 16#00#; + SFDP_array(16#14#) := 16#90#; + SFDP_array(16#15#) := 16#00#; + SFDP_array(16#16#) := 16#00#; + SFDP_array(16#17#) := 16#FF#; + + FOR I IN 24 TO 127 LOOP + SFDP_array(i) := MaxData; + END LOOP; + + SFDP_array(16#80#) := 16#E5#; + SFDP_array(16#81#) := 16#20#; + SFDP_array(16#82#) := 16#F1#; + SFDP_array(16#83#) := 16#FF#; + SFDP_array(16#84#) := 16#FF#; + SFDP_array(16#85#) := 16#FF#; + SFDP_array(16#86#) := 16#FF#; + SFDP_array(16#87#) := 16#07#; + SFDP_array(16#88#) := 16#44#; + SFDP_array(16#89#) := 16#EB#; + SFDP_array(16#8A#) := 16#08#; + SFDP_array(16#8B#) := 16#6B#; + SFDP_array(16#8C#) := 16#08#; + SFDP_array(16#8D#) := 16#3B#; + SFDP_array(16#8E#) := 16#80#; + SFDP_array(16#8F#) := 16#BB#; + + FOR I IN 144 TO 255 LOOP + SFDP_array(i) := MaxData; + END LOOP; + + WAIT; + + END PROCESS SFDPPreload; + + --------------------------------------------------------------------------- + -- Sector Protection Bits + --------------------------------------------------------------------------- + Protect : PROCESS(change_prot_bits) + BEGIN + IF rising_edge(change_prot_bits) THEN + + CASE BP_bits IS + WHEN "000" => + IF (CMP = '0') THEN + Sec_Prot := (others => '0'); + ELSE + Sec_Prot := (others => '1'); + END IF; + WHEN "001" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(4095 downto 4032) := + (others => '1'); + Sec_Prot(4031 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(63 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 64) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4095) := '1'; + Sec_Prot(4094 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(0) := '1'; + Sec_Prot(4095 downto 1) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(4031 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 4032) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(4095 downto 64) := + (others => '1'); + Sec_Prot(63 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4094 downto 0) := + (others => '1'); + Sec_Prot(4095) := '0'; + + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(4095 downto 1) := + (others => '1'); + Sec_Prot(0) := '0'; + END IF; + END IF; + WHEN "010" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(4095 downto 3968) := + (others => '1'); + Sec_Prot(3967 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(127 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 128) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4095 downto 4094) := + (others => '1'); + Sec_Prot(4093 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(1 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 2) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(3967 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 3968) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(4095 downto 128) := + (others => '1'); + Sec_Prot(127 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4093 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 4094) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(4095 downto 2) := + (others => '1'); + Sec_Prot(1 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "011" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(4095 downto 3840) := + (others => '1'); + Sec_Prot(3839 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(255 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 256) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4095 downto 4092) := + (others => '1'); + Sec_Prot(4091 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(3 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 4) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(3839 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 3840) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(4095 downto 256) := + (others => '1'); + Sec_Prot(255 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4091 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 4092) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(4095 downto 4) := + (others => '1'); + Sec_Prot(3 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "100" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(4095 downto 3584) := + (others => '1'); + Sec_Prot(3583 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(511 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 512) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4095 downto 4088) := + (others => '1'); + Sec_Prot(4087 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(7 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 8) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(3583 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 3584) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(4095 downto 512) := + (others => '1'); + Sec_Prot(511 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4087 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 4088) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(4095 downto 8) := + (others => '1'); + Sec_Prot(7 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "101" => + IF (CMP = '0') THEN + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(4095 downto 3072) := + (others => '1'); + Sec_Prot(3071 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(1023 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 1024) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4095 downto 4088) := + (others => '1'); + Sec_Prot(4087 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(7 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 8) := + (others => '0'); + END IF; + ELSE + IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN + Sec_Prot(3071 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 3072) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN + Sec_Prot(4095 downto 1024) := + (others => '1'); + Sec_Prot(1023 downto 0) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN + Sec_Prot(4087 downto 0) := + (others => '1'); + Sec_Prot(4095 downto 4088) := + (others => '0'); + ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN + Sec_Prot(4095 downto 8) := + (others => '1'); + Sec_Prot(7 downto 0) := + (others => '0'); + END IF; + END IF; + + WHEN "110" => + IF (CMP = '0') THEN + IF (SEC = '0' AND TB = '0') THEN + Sec_Prot(4095 downto 2048) := (others => '1'); + Sec_Prot(2047 downto 0) := (others => '0'); + ELSIF (SEC = '0' AND TB = '1') THEN + Sec_Prot(2047 downto 0) := (others => '1'); + Sec_Prot(4095 downto 2048) := (others => '0'); + END IF; + ELSE + IF (SEC = '0' AND TB = '0') THEN + Sec_Prot(4095 downto 2048) := (others => '0'); + Sec_Prot(2047 downto 0) := (others => '1'); + ELSIF (SEC = '0' AND TB = '1') THEN + Sec_Prot(4095 downto 2048) := (others => '1'); + Sec_Prot(2047 downto 0) := (others => '0'); + END IF; + END IF; + + WHEN "111" => + IF (CMP = '0') THEN + Sec_Prot(4095 downto 0) := (others => '1'); + ELSE + Sec_Prot(4095 downto 0) := (others => '0'); + END IF; + WHEN OTHERS => + Sec_Prot := (OTHERS => '1'); + END CASE; -- end of CASE BP_bits + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNegIn) + BEGIN + IF (HOLDNegIn = '0' AND QE /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QE = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QE = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + + MemPreload: PROCESS + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE screg_file : text is screg_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE:= 0; + VARIABLE screg_ind: NATURAL RANGE 16#00# TO 16#2FF#:= 16#00#; + VARIABLE buf : line; + + BEGIN + -- memory preload + IF (mem_file_name (1 to 4)/= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 7)); --address + ELSE + IF ind <= AddrRANGE THEN + Mem(ind) := h(buf(1 to 2)); + END IF; + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + ----------------------------------------------------------------------- + -- Security Register Preload + ----------------------------------------------------------------------- + + IF (screg_file_name(1 to 4) /= "none" AND UserPreload) THEN + ind := 0; + Security_Reg1 := (OTHERS => MaxData); + Security_Reg2 := (OTHERS => MaxData); + Security_Reg3 := (OTHERS => MaxData); + WHILE (not ENDFILE (screg_file)) LOOP + READLINE (screg_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + screg_ind := h(buf(2 to 4)); --address + ELSE + IF screg_ind <= 16#0FF# THEN + Security_Reg1(screg_ind) := h(buf(1 to 2)); + ELSIF screg_ind>=16#100# AND screg_ind<=16#1FF# THEN + Security_Reg2(screg_ind-16#100#) := h(buf(1 to 2)); + ELSIF screg_ind>=16#200# AND screg_ind<=16#2FF# THEN + Security_Reg3(screg_ind-16#200#) := h(buf(1 to 2)); + END IF; + IF (screg_ind mod 16#100#) < 16#FF# THEN + screg_ind := screg_ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + WAIT; + END PROCESS MemPreload; + + --------------------------------------------------------------------------- + -- Path Delay Section + --------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "SO", + OutTemp => SOut_z, + Mode => VitalTransport, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => SOut_z /= 'Z' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => SOut_z /= 'Z' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => QE = '0') + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + Mode => VitalTransport, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => SIOut_z /= 'Z' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => SIOut_z /= 'Z' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND SIOut_zd = 'Z'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => SIOut_z /= 'Z' AND QE = '0') + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => HOLDNegOut_zd /= 'Z' --AND quad_read + AND QE = '1' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => HOLDNegOut_zd /= 'Z' --AND quad_read + AND QE = '1' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND --quad_read AND + HOLDNegOut_zd = 'Z' AND QE = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0), + PathCondition => WPNegOut_zd /= 'Z' --AND quad_read + AND QE = '1' AND NOT(read_id)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1), + PathCondition => WPNegOut_zd /= 'Z' -- AND quad_read + AND QE = '1' AND read_id), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND --quad_read AND + WPNegOut_zd = 'Z' AND QE = '1') + ) + ); + END PROCESS; + + END BLOCK behavior; +END vhdl_behavioral; \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_ver.ftm b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_ver.ftm new file mode 100644 index 0000000..581567c --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_ver.ftm @@ -0,0 +1,65 @@ + +FMF Timing for s25fl128k Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 10 Oct 08 Initial release + +1ns +s25fl128k + +S25FL128KOXMFI000 Spansion, S25FL128K, JULY 22,2010 +S25FL128KOXMFI001 Spansion, S25FL128K, JULY 22,2010 +S25FL128KOXMFI003 Spansion, S25FL128K, JULY 22,2010 +The values listed are for VCC=2.7V to 3.6V, +Industrial Ta=-40 to +85 Celsius + +(DELAY(ABSOLUTE + (COND ~read_id (IOPATH SCK SO (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND (~glitch || quad_read) && read_id (IOPATH SCK SO (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (COND CSNeg (IOPATH CSNeg SO () () (5:6:7) () (5:6:7) ())) + (COND ~quad_read (IOPATH HOLDNeg SO () () (8:10:12) (5:6:7) (8:10:12) (5:6:7))) + (COND (dual_read || quad_read) && ~read_id (IOPATH SCK SI (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND dual_read && read_id && ~glitch (IOPATH SCK SI (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (COND quad_read && read_id (IOPATH SCK SI (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (COND CSNeg && ~deg_sin (IOPATH CSNeg SI () () (5:6:7) () (5:6:7) ())) + (COND ~quad_read && dual_read (IOPATH HOLDNeg SI () () (8:10:12) (5:6:7) (8:10:12) (5:6:7))) + (COND quad_read && ~read_id (IOPATH SCK WPNeg (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND quad_read && read_id (IOPATH SCK WPNeg (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (COND quad_read && ~read_id (IOPATH SCK HOLDNeg (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND quad_read && read_id (IOPATH SCK HOLDNeg (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (COND CSNeg && QE (IOPATH CSNeg SI () () (5:6:7) () (5:6:7) ())) + (COND CSNeg && QE (IOPATH CSNeg WPNeg () () (5:6:7) () (5:6:7) ())) + (COND CSNeg && QE (IOPATH CSNeg HOLDNeg () () (5:6:7) () (5:6:7) ())) +)) +(TIMINGCHECK + (SETUP CSNeg (posedge SCK) (5)) + (SETUP SI (COND deg_sin(posedge SCK)) (2)) + (SETUP SO (COND quad_pg(posedge SCK)) (2)) + (SETUP WPNeg (COND quad_pg(posedge SCK)) (2)) + (SETUP HOLDNeg (COND quad_pg(posedge SCK)) (2)) + (SETUP HOLDNeg (COND hold_cond(posedge SCK)) (5)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (5)) + (HOLD SI (COND deg_sin (posedge SCK)) (5)) + (HOLD SO (COND quad_pg (posedge SCK)) (5)) + (HOLD WPNeg (COND quad_pg (posedge SCK)) (5)) + (HOLD HOLDNeg (COND quad_pg (posedge SCK)) (5)) + (HOLD HOLDNeg (COND hold_cond(posedge SCK)) (5)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + + (WIDTH (COND rd_slow (posedge SCK)) (8)) + (WIDTH (COND rd_slow (negedge SCK)) (8)) + (WIDTH (COND rd_fast (posedge SCK)) (4)) + (WIDTH (COND rd_fast (negedge SCK)) (4)) + (WIDTH (COND quad_spi (posedge SCK)) (6)) + (WIDTH (COND quad_spi (negedge SCK)) (6)) + (WIDTH (COND any_read (posedge CSNeg)) (10)) + (WIDTH (COND pg_ers (posedge CSNeg)) (50)) + (PERIOD (COND rd_slow SCK) (16)) + (PERIOD (COND rd_fast SCK) (8)) + (PERIOD (COND quad_spi SCK) (12)) +) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_vhd.ftm b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_vhd.ftm new file mode 100644 index 0000000..14c4dec --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k_vhd.ftm @@ -0,0 +1,81 @@ + +FMF Timing for s25fl128k Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 10 Oct 05 Initial release + +1ns +s25fl128k + +S25FL128KOXMFI000 Spansion, S25FL128K, JULY 22,2010 +S25FL128KOXMFI001 Spansion, S25FL128K, JULY 22,2010 +S25FL128KOXMFI003 Spansion, S25FL128K, JULY 22,2010 +The values listed are for VCC=2.7V to 3.6V, +Industrial Ta=-40 to +85 Celsius + +(DELAY(ABSOLUTE + (COND RDID == 0 (IOPATH SCK SO (5:6:7) (5:6:7) () (5:6:7) () (5:6:7))) + (COND RDID == 1 (IOPATH SCK SO (5.5:7:8.5) (5.5:7:8.5) () (5.5:7:8.5) () (5.5:7:8.5))) + (IOPATH CSNeg SO () () (5:6:7) () (5:6:7) ()) + (IOPATH HOLDNeg SO () () (8:10:12) (5:6:7) (8:10:12) (5:6:7)) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (5)) + (SETUP (COND normal SI) (posedge SCK) (2)) + (SETUP HOLDNeg SCK (5)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (5)) + (HOLD (COND normal SI) (posedge SCK) (5)) + (HOLD HOLDNeg SCK (5)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND slow (posedge SCK)) (8)) + (WIDTH (COND slow (negedge SCK)) (8)) + (WIDTH (COND fast (posedge SCK)) (4)) + (WIDTH (COND fast (negedge SCK)) (4)) + (WIDTH (COND quad (posedge SCK)) (6)) + (WIDTH (COND quad (negedge SCK)) (6)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pger (posedge CSNeg)) (50)) + (PERIOD (COND slow SCK) (16)) + (PERIOD (COND fast SCK) (8)) + (PERIOD (COND quad SCK) (12)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(400000:700000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP1) (DELAY (ABSOLUTE (DEVICE(15000:30000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP2) (DELAY (ABSOLUTE (DEVICE(1000:2500:12000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(10000000:30000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE1) (DELAY (ABSOLUTE (DEVICE(5e7:12e7:8e8) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE2) (DELAY (ABSOLUTE (DEVICE(5e7:15e7:1e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/CE) (DELAY (ABSOLUTE (DEVICE(15e9:25e9:40e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(3000:3000:3000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES1) (DELAY (ABSOLUTE (DEVICE(3000:3000:3000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES2) (DELAY (ABSOLUTE (DEVICE(1800:1800:1800) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGRES) (DELAY (ABSOLUTE (DEVICE(200:200:200) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSRES) (DELAY (ABSOLUTE (DEVICE(200:200:200) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(15000000:15000000:15000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SUSP_DLY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl128k/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl128k/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl128k/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128k/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/flash/serial/S25fl128s/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl128s/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl128s/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl128s/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 vital-amd-serial-s25fl-REL-s25fl128s-2009-11-11-3.tar.gz +# Release Date (DD/MM/YYYY) => 11/11/2009 +# Release Version => 1.0 + +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com + Hana Dimitrijevic + h-dimitrijevic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2009-11-12-1.tar.gz +# Release Date (DD/MM/YYYY) => 12/11/2009 +# Release Version => 1.1 + +# Correction of s25fl128s.v file : +# State transition from Program Suspend to Autoboot state when +# RESET command is initiated, is delayed with additional 500 ps. +# (For compatibility with Modelsim 6.4b Version) + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2009-11-20-1.tar.gz +# Release Date (DD/MM/YYYY) => 20/11/2009 +# Release Version => 1.2 + +# Corrections: +# 1.Negative tests which show how model behaves when reset pulse +# width is less than specified and when write and erase operations are interrupted . +# with reset signal are interrupted with reset signal are added. +# 2.Implementation of Continuous Read Mode +# 3.After 8 clock cycles for instruction, first address bit is latched on the next +# rising edge of clock. + +# Files modified +-s25fl128s.vhd +-testbench_s25fl128s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl128s.ftm +-s25fl128s_vhdl.sdf +-s25fl128s.v +-testbench_s25fl128s_verilog.vhd +-s25fl128s.ftmv +-s25fl128s_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2009-11-23-1.tar.gz +# Release Date (DD/MM/YYYY) => 23/11/2009 +# Release Version => 1.3 + +# Corrections: +# 1.Correction of Bulk Erase Time +# + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-02-24-1.tar.gz +# Release Date (DD/MM/YYYY) => 24/02/2010 +# Release Version => 1.4 + +# Corrections: +# 1.Array variable WByte in sensitivity list is replaced with signal WB_flag to enable +# compilation in NCSim +# 2.addr_cnt for second read in high performance read continuous mode can change its +# value only when CSNeg = '0' + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-04-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/04/2010 +# Release Version => 1.5 + +# Corrections: +# 1.HOLD mode corrected +# 2.Condition for PP operation corrected + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-05-19-1.tar.gz +# Release Date (DD/MM/YYYY) => 19/05/2010 +# Release Version => 1.6 + +# Corrections: +# 1.SRWD bit assignment is corrected +# 2.Condition for WRR command in write_cycle_decode section is corrected +# 3.Blocking assignments for signals WSTART and PSTART are replaced with +# nonblocking assignments +# 4.Conditions in Page Program section are fixed +# + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-05-26-1.tar.gz +# Release Date (DD/MM/YYYY) => 26/05/2010 +# Release Version => 1.7 + +# Corrections: +# 1. Timing control sections for Program and Erase operation are changed +# 2. Conditions in Page Program section are fixed +# + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-06-03-2.tar.gz +# Release Date (DD/MM/YYYY) => 03/06/2010 +# Release Version => 1.8 + +# Corrections: +# 1. bus_cycle_state section for PGSP command is fixed +# + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-07-29-1.tar.gz +# Release Date (DD/MM/YYYY) => 29/07/2010 +# Release Version => 1.9 + +# Corrections: +# 1. During the QUAD mode HOLD# input is not monitored for its normal function +# 2. Internal pull-up resistors for HOLD# and WP# inputs are implemented + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-08-24-1.tar.gz +# Release Date (DD/MM/YYYY) => 24/08/2010 +# Release Version => 2.0 + +# Corrections: +# 1. All redundant signals are removed from BusCycle process + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-10-19-2.tar.gz +# Release Date (DD/MM/YYYY) => 19/10/2010 +# Release Version => 2.1 + +# Corrections: +# 1. Path delay correction: path delay is longer than clock cycle. +# 2. Write bank register: WIP bit of status register 1 is not affected by this +# instruction. +# 3. All other functionality is updated according to new datasheet version 1.5 + +# Files modified +-s25fl128s.v +-testbench_s25fl128s_verilog.vhd +-s25fl128s.ftmv +-s25fl128s_verilog.sdf +-spansion_tc_pkg.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-10-21-1.tar.gz +# Release Date (DD/MM/YYYY) => 21/10/2010 +# Release Version => 2.2 + +# Corrections: +# 1. VHDL model, which is alligned with datasheet version 1.5, added to the release +# 2. Names of documentation files are updated + +# Files modified +-s25fl128s.vhd +-testbench_s25fl128s_vhdl.vhd +-s25fl128s.ftm +-s25fl128s_vhdl.sdf +-spansion_flash_testbench_struct.pdf +-spansion_flash_test_cases_list.pdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-11-05-1.tar.gz +# Release Date (DD/MM/YYYY) => 05/11/2010 +# Release Version => 2.3 + +# Corrections: +# 1. Hybrid configuration added + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +-testbench_s25fl128s_verilog.vhd +-testbench_s25fl128s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl128s.ftmv +-s25fl128s.ftm +-s25fl128s_verilog.sdf +-s25fl128s_vhdl.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2010-11-12-1.tar.gz +# Release Date (DD/MM/YYYY) => 12/11/2010 +# Release Version => 2.4 + +# Corrections: +# 1. QUAD Program operation during Erase Suspend is added +# 2. Warning for Resume to Suspend time is added +# 3. During Erase Suspend, after Program operation is completed, WEL bit is cleared +# 4. Implemetation of Software Reset is Changed + +# Files modified +-spansion_tc_pkg.vhd +-s25fl128s.v +-s25fl128s.vhd +########################################## +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2011-04-08-2.tar.gz +# Release Date (DD/MM/YYYY) => 08/04/2011 +# Release Version => 2.5 + +# Corrections: +- corrected timing for internal signal rising_edge_CSNeg_ipd + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2011-05-11-1.tar.gz +# Release Date (DD/MM/YYYY) => 11/05/2011 +# Release Version => 2.6 + +# Corrections: +- Condition for CS# High Time(Program/Erase) is fixed + +# Files modified +-s25fl128s.vhd +-testbench_s25fl128s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl128s.v +-testbench_s25fl128s_verilog.vhd +-s25fl128s.ftmv +-s25fl128s_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2011-07-01-1.tar.gz +# Release Date (DD/MM/YYYY) => 01/07/2011 +# Release Version => 2.7 + +# Corrections: +- Latest Datasheet Aligned + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +-testbench_s25fl128s_verilog.vhd +-testbench_s25fl128s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl128s.ftmv +-s25fl128s.ftm +-s25fl128s_verilog.sdf +-s25fl128s_vhdl.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2011-07-14-2.tar.gz +# Release Date (DD/MM/YYYY) => 14/07/2011 +# Release Version => 2.8 + +# Corrections: +- Optimization issue is fixed + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2011-07-22-1.tar.gz +# Release Date (DD/MM/YYYY) => 22/07/2011 +# Release Version => 2.9 + +# Corrections: +- Timing check issue is fixed + +# Files modified +-s25fl128s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2011-11-16-1.tar.gz +# Release Date (DD/MM/YYYY) => 16/11/2011 +# Release Version => 3.0 + +# Corrections: +- Time tHO is changed to 1 ns (customer's request) +- Setting of Device protection mode is modified (customer's request) +- BRWR instruction is corrected + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +-testbench_s25fl128s_verilog.vhd +-testbench_s25fl128s_vhdl.vhd +-s25fl128s.ftmv +-s25fl128s.ftm +-s25fl128s_verilog.sdf +-s25fl128s_vhdl.sdf +########################################## +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2012-08-28-1.tar.gz +# Release Date (DD/MM/YYYY) => 28/08/2012 +# Release Version => 3.1 + +# Corrections: +- QPP instruction is allowed on previously programmed page + +# Files modified +-s25fl128s.v +-s25fl128s.vhd +-testbench_s25fl128s_verilog.vhd +-testbench_s25fl128s_vhdl.vhd +-spansion_tc_pkg.vhd +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl128s-2012-08-30-1.tar.gz +# Release Date (DD/MM/YYYY) => 30/08/2012 +# Release Version => 3.2 + +# Corrections: +- Wrong code corrected + +# Files modified +-s25fl128s.v +########################################## \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.v b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.v new file mode 100644 index 0000000..e11b4a4 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.v @@ -0,0 +1,7978 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl128s.v +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 V.Mancev 23 Nov 09 Initial +// R.Prokopovic +// V1.1 V.Mancev 24 Feb 10 addr_cnt for second read in +// high performance read continuous +// mode can change its value only +// when CSNeg = '0' +// V1.2 V.Mancev 23 Mar 10 During read operations read_out +// signal changes its value in +// shorter interval +// V1.3 V.Mancev 13 Apr 10 HOLD mode corrected +// Condition for PP operation +// corrected +// V1.4 V.Mancev 19 May 10 SRWD bit assignment is corrected +// Condition for WRR command in +// write_cycle _decode section is +// corrected +// Blocking assignments for signals +// WSTART and PSTART are replaced +// with nonblocking assignments +// Conditions in Page Program +// section are fixed +// V1.5 V.Mancev 26 May 10 Conditions in programming +// sections are fixed +// Timing control sections for +// Program and Erase operation are +// changed +// V1.6 V.Mancev 03 June 10 bus_cycle_state section for +// PGSP command is fixed +// V1.7 V.Mancev 29 July 10 During the QUAD mode HOLD# input +// is not monitored for its normal +// function +// V1.8 B.Colakovic 24 Aug 10 All redundant signals are removed +// from BusCycle process +// V1.9 V. Mancev 08 Oct 10 Latest datasheet aligned +// B.Colakovic +// R. Prokopovic +// V1.10 V. Mancev 01 Nov 10 Read Configuration register added +// B.Colakovic for any state. Hybrid configuration +// R. Prokopovic added +// V1.11 S.Petrovic 08 Apr 11 Corrected timing in always block +// that generates +// rising_edge_CSNeg_ipd +// V1.12 V. Mancev 11 May 11 Condition for CS# High Time +// (Program/Erase) is fixed +// V1.13 V. Mancev 01 July 11 Latest datasheet aligned +// V1.14 B.Colakovic 14 July 11 Optimization issue is fixed +// V1.15 V.Mancev 22 July 11 Timing check issue is fixed +// V1.16 V. Mancev 16 Nov 11 Time tHO is changed to 1 ns +// (customer's request) +// BRWR instruction is corrected +// V1.17 S.Petrovic 28 Aug 12 QPP Instruction is allowed on +// previously programmed page +// V1.18 S.Petrovic 30 Aug 12 Wrong code corrected +// +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL128S +// +// Description: 128 Megabit Serial Flash Memory +// +////////////////////////////////////////////////////////////////////////////// +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// A device ordering (trim) option determines whether a feature is enabled +// or not, or provide relevant parameters: +// -15th character in TimingModel determines if enhanced high +// performance option is available +// (0,2,3,R,A,B,C,D) EHPLC +// (Y,Z,S,T,K,L) Security EHPLC +// (4,6,7,8,9,Q) HPLC +// -15th character in TimingModel determines if RESET# input +// is available +// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +// state,inside the package. +// -16th character in TimingModel determines Sector and Page Size: +// (0) Sector Size = 64 kB; Page Size = 256 bytes +// Hybrid Top/Bottom sector size architecture +// (1) Sector Size = 256 kB; Page Size = 512 bytes +// Uniform sector size architecture +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl128s + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + RSTNeg , + WPNeg , + HOLDNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + + inout SI ; + inout SO ; + + input SCK ; + input CSNeg ; + input RSTNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire RSTNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire RSTNeg_in ; + //Internal pull-up + assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd; + + // internal delays + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg WRR_in ; + reg WRR_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg PU_in ; + reg PU_out ; + reg RST_in ; + reg RST_out ; + reg PPBERASE_in ; + reg PPBERASE_out; + reg PASSULCK_in ; + reg PASSULCK_out; + reg PASSACC_in ; + reg PASSACC_out; + + // event control registers + reg PRGSUSP_out_event; + reg ERSSUSP_out_event; + reg Reseted_event; + reg SCK_ipd_event; + reg next_state_event; + + reg rising_edge_PoweredUp; + reg rising_edge_Reseted; + reg rising_edge_PASSULCK_in; + reg rising_edge_RES_out; + reg rising_edge_PSTART; + reg rising_edge_WSTART; + reg rising_edge_ESTART; + reg rising_edge_RSTNeg; + reg rising_edge_RST; + reg falling_edge_RSTNeg; + reg falling_edge_RST; + reg rising_edge_RST_out; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg RST ; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl128s.mem"; + parameter otp_file_name = "s25fl128sOTP.mem";//"none"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl128s"; + parameter MaxData = 255; + parameter MemSize = 24'hFFFFFF; + parameter SecSize256 = 20'h3FFFF; + parameter SecSize64 = 16'hFFFF; + parameter SecSize4 = 12'hFFF; + parameter SecNum64 = 285; + parameter SecNum256 = 63; + parameter PageNum64 = 20'h1FFFF; + parameter PageNum256 = 16'h7FFF; + parameter AddrRANGE = 24'hFFFFFF; + parameter HiAddrBit = 31; + parameter OTPSize = 1023; + parameter OTPLoAddr = 12'h000; + parameter OTPHiAddr = 12'h3FF; + parameter BYTE = 8; + + // Manufacturer Identification + parameter Manuf_ID = 8'h01; + parameter DeviceID = 8'h17; + // Electronic Signature + parameter ESignature = 8'h17; + // Device ID + //Manufacturer Identification && Memory Type && Memory Capacity + parameter Jedec_ID = 8'h01; + parameter DeviceID1 = 8'h20; + parameter DeviceID2 = 8'h18; + parameter ExtendedBytes = 8'h4D; + parameter ExtendedID64 = 8'h01; + parameter ExtendedID256 = 8'h00; + parameter DieRev = 8'h03; + parameter MaskRev = 8'h00; + + integer PageSize; + integer PageNum; + integer SecSize; + integer b_act = 0; + + integer ASP_ProtSE = 0; + integer Sec_ProtSE = 0; + + integer EHP; //Enhanced High Performance Mode active + + integer BAR_ACC = 0; //Bank Register Access active + + //varaibles to resolve architecture used + reg [24*8-1:0] tmp_timing;//stores copy of TimingModel + reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode + reg [7:0] tmp_char2;//stores "0" or "1" character defining sector/page size + integer found = 1'b0; + + // If speedsimulation is needed uncomment following line + + `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // Memory Array Configuration + reg BottomBoot = 1'b0; + reg TopBoot = 1'b0; + reg UniformSec = 1'b0; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; + + reg RES_TO_SUSP_MIN_TIME; + reg RES_TO_SUSP_TYP_TIME; + + reg WDONE ; + reg WSTART ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + reg ERS_SUSP_PG_SUSP_ACT; + + reg Reseted ; + + reg PARAM_REGION = 1'b0; + + // Lock Bit is enabled for customer programming + reg WRLOCKENABLE = 1'b1; + // Flag that mark if ASP Register is allready programmed + reg ASPOTPFLAG = 1'b0; + + //Flag for Password unlock command + reg PASS_UNLOCKED = 1'b0; + reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF; + + reg QUADRD = 1'b0; + reg INITIAL_CONFIG = 1'b0; + reg CHECK_FREQ = 1'b0; + + // Programming buffer + integer WByte[0:511]; + // CFI array + integer CFI_array[8'h00:8'h50]; + // OTP Memory Array + integer OTPMem[OTPLoAddr:OTPHiAddr]; + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // VDLR Register + reg[7:0] VDLR_reg = 8'h00; + reg[7:0] VDLR_reg_in = 8'h00; + // NVDLR Register + reg[7:0] NVDLR_reg = 8'h00; + reg[7:0] NVDLR_reg_in = 8'h00; + reg dlp_act = 1'b0; + + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRWD ; + wire P_ERR; + wire E_ERR; + wire [2:0]BP; + wire WEL; + wire WIP; + assign SRWD = Status_reg1[7]; + assign P_ERR = Status_reg1[6]; + assign E_ERR = Status_reg1[5]; + assign BP = Status_reg1[4:2]; + assign WEL = Status_reg1[1]; + assign WIP = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire ES ; + wire PS ; + assign ES = Status_reg2[1]; + assign PS = Status_reg2[0]; + + // Configuration Register 1 + reg[7:0] Config_reg1 = 8'h00; + reg[7:0] Config_reg1_in = 8'h00; + + wire LC1 ; + wire LC0 ; + wire TBPROT ; + wire LOCK ; + wire BPNV ; + wire TBPARM ; + wire QUAD ; + wire FREEZE ; + assign LC1 = Config_reg1[7]; + assign LC0 = Config_reg1[6]; + assign TBPROT = Config_reg1[5]; + assign LOCK = Config_reg1[4]; + assign BPNV = Config_reg1[3]; + assign TBPARM = Config_reg1[2]; + assign QUAD = Config_reg1[1]; + assign FREEZE = Config_reg1[0]; + + // Autoboot Register + reg[31:0] AutoBoot_reg = 32'h00000000; + reg[31:0] AutoBoot_reg_in = 32'h00000000; + + wire ABE; + assign ABE = AutoBoot_reg[0]; + + // Bank Address Register + reg [7:0] Bank_Addr_reg = 8'h00; + reg [7:0] Bank_Addr_reg_in = 8'h00; + + wire EXTADD; + assign EXTADD = Bank_Addr_reg[7]; + + // ASP Register + reg[15:0] ASP_reg ; + reg[15:0] ASP_reg_in; + + wire RPME ; + wire PPBOTP ; + wire PWDMLB ; + wire PSTMLB ; + assign RPME = ASP_reg[5]; + assign PPBOTP = ASP_reg[3]; + assign PWDMLB = ASP_reg[2]; + assign PSTMLB = ASP_reg[1]; + + // Password register + reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF; + reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF; + + // PPB Lock Register + reg[7:0] PPBL = 8'h00; + reg[7:0] PPBL_in = 8'h00; + + wire PPB_LOCK ; + assign PPB_LOCK = PPBL[0]; + + // PPB Access Register + reg[7:0] PPBAR = 8'hFF; + reg[7:0] PPBAR_in = 8'hFF; + + reg[SecNum64:0] PPB_bits = {286{1'b1}}; + + // DYB Access Register + reg[7:0] DYBAR = 8'hFF; + reg[7:0] DYBAR_in = 8'hFF; + + reg[SecNum64:0] DYB_bits = {286{1'b1}}; + + //The Lock Protection Registers for OTP Memory space + reg[7:0] LOCK_BYTE1; + reg[7:0] LOCK_BYTE2; + reg[7:0] LOCK_BYTE3; + reg[7:0] LOCK_BYTE4; + + // Command Register + reg write; + reg cfg_write; + reg read_out; + reg dual = 1'b0; + reg rd_fast = 1'b1; + reg rd_slow = 1'b0; + reg ddr = 1'b0; + reg ddr_fast = 1'b0; + reg hold_mode = 1'b0; + reg any_read = 1'b0; + reg quad_pg = 1'b0; + + wire rd ; + wire fast_rd ; + wire ddrd ; + wire fast_ddr ; + + wire quadpg ; + assign quadpg = quad_pg; + + wire RD_EQU_1; + assign RD_EQU_1 = any_read; + + wire RD_EQU_0; + assign RD_EQU_0 = ~any_read; + + reg change_TBPARM = 0; + + reg change_BP = 0; + reg [2:0] BP_bits = 3'b0; + + reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag + + reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag + reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag + + integer Byte_number = 0; + + reg oe = 1'b0; + reg oe_z = 1'b0; + + reg [647:0] CFI_array_tmp ; + reg [7:0] CFI_tmp; + + integer start_delay; + reg start_autoboot; + integer ABSD; + + reg change_addr ; + integer Address = 0; + integer SectorSuspend = 0; + + //Sector and subsector addresses + integer SA = 0; + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [SecNum64:0] Sec_Prot = {286{1'b0}}; + + // timing check violation + reg Viol = 1'b0; + + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + reg[63:0] old_pass; + reg[63:0] new_pass; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer byte_cnt = 1; + integer read_addr = 0; + integer read_addr_tmp = 0; + integer Sec_addr = 0; + integer SecAddr = 0; + integer Page_addr = 0; + integer pgm_page = 0; + + reg[7:0] data_out; + reg[647:0] ident_out; + + time SCK_cycle = 0; + time prev_SCK; + time start_ddr; + time out_time; + time SCK_SO_DDR; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (RSTNeg_ipd, RSTNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + //VHDL VITAL CheckEnable equivalents + wire quad_rd; + assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz); + wire wr_prot; + assign wr_prot = SRWD && WEL && ~QUAD; + wire dual_rd; + assign dual_rd = dual ; + wire ddro; + assign ddro = ddr && ~dual ; + wire ddr_rd; + assign ddr_rd = PoweredUp && ddr; + wire sdr_rd; + assign sdr_rd = PoweredUp && ~ddr; + +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_normal =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + specparam tpd_RSTNeg_SO =1; + //DDR operation values + specparam tpd_SCK_SO_DDR =1; + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; + specparam tsetup_SI_SCK_normal =1; + specparam tsetup_WPNeg_CSNeg =1; + specparam tsetup_HOLDNeg_SCK =1; + specparam tsetup_RSTNeg_CSNeg =1; + // DDR operation values + specparam tsetup_SI_SCK_DDR =1; + specparam tsetup_SI_SCK_DDR_fast =1; + specparam tsetup_CSNeg_SCK_DDR =1; + + //thold values: hold times + specparam thold_CSNeg_SCK =1; + specparam thold_SI_SCK_normal =1; + specparam thold_WPNeg_CSNeg =1; + specparam thold_HOLDNeg_SCK =1; + specparam thold_CSNeg_RSTNeg =1; + // DDR operation values + specparam thold_SI_SCK_DDR =1; + specparam thold_SI_SCK_DDR_fast =1; + specparam thold_CSNeg_SCK_DDR =1; + + // tpw values: pulse width + specparam tpw_SCK_serial_posedge =1; + specparam tpw_SCK_dual_posedge =1; + specparam tpw_SCK_fast_posedge =1; + specparam tpw_SCK_quadpg_posedge =1; + specparam tpw_SCK_serial_negedge =1; + specparam tpw_SCK_dual_negedge =1; + specparam tpw_SCK_fast_negedge =1; + specparam tpw_SCK_quadpg_negedge =1; + specparam tpw_CSNeg_read_posedge =1; + specparam tpw_CSNeg_pgers_posedge =1; + specparam tpw_RSTNeg_negedge =1; + specparam tpw_RSTNeg_posedge =1; + // DDR operation values + specparam tpw_SCK_DDR_posedge =1; + specparam tpw_SCK_DDR_negedge =1; + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_serial_rd =1;// 50 MHz + specparam tperiod_SCK_fast_rd =1;//133 MHz + specparam tperiod_SCK_dual_rd =1;//104 MHz + specparam tperiod_SCK_quadpg =1;// 80 MHz + // DDR operation values + specparam tperiod_SCK_DDR_rd =1;// 66 MHz + + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e7;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e7;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 165e9;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e9;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `else + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e9;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e9;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 165e12;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e11;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~ddr) (SCK => SO) = tpd_SCK_SO_normal; + if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR; + + if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal; + if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR; + + if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR; + if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR; + + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO; + + if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; + if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO; + + if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + (RSTNeg => SO) = tpd_RSTNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& sdr_rd, + tsetup_CSNeg_SCK, Viol); + $setup ( CSNeg , posedge SCK &&& ddr_rd, + tsetup_CSNeg_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK_normal, Viol); + $setup ( WPNeg , negedge CSNeg &&& wr_prot, + tsetup_WPNeg_CSNeg, Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_rd, + tsetup_HOLDNeg_SCK, Viol); + $setup ( SI , posedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + + $setup ( RSTNeg , negedge CSNeg, + tsetup_RSTNeg_CSNeg, Viol); + + $hold ( posedge SCK &&& sdr_rd , CSNeg, + thold_CSNeg_SCK, Viol); + $hold ( posedge SCK &&& ddr_rd , CSNeg, + thold_CSNeg_SCK_DDR, Viol); + $hold ( posedge SCK &&& deg_sin , SI , + thold_SI_SCK_normal, Viol); + $hold ( posedge CSNeg &&& wr_prot , WPNeg , + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK &&& quad_rd , HOLDNeg , + thold_HOLDNeg_SCK, Viol); + $hold ( posedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + + $hold ( negedge RSTNeg , CSNeg, + thold_CSNeg_RSTNeg, Viol); + + $width ( posedge SCK &&& rd , tpw_SCK_serial_posedge); + $width ( negedge SCK &&& rd , tpw_SCK_serial_negedge); + $width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge); + $width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge); + $width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge); + $width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge); + + $width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge); + $width ( negedge RSTNeg , tpw_RSTNeg_negedge); + $width ( posedge RSTNeg , tpw_RSTNeg_posedge); + + $period ( posedge SCK &&& rd , tperiod_SCK_serial_rd); + $period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); + $period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); + $period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg); + $period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 5'd0; + parameter RESET_STATE = 5'd1; + parameter AUTOBOOT = 5'd2; + parameter WRITE_SR = 5'd3; + parameter PAGE_PG = 5'd4; + parameter OTP_PG = 5'd5; + parameter PG_SUSP = 5'd6; + parameter SECTOR_ERS = 5'd7; + parameter BULK_ERS = 5'd8; + parameter ERS_SUSP = 5'd9; + parameter ERS_SUSP_PG = 5'd10; + parameter ERS_SUSP_PG_SUSP= 5'd11; + parameter PASS_PG = 5'd12; + parameter PASS_UNLOCK = 5'd13; + parameter PPB_PG = 5'd14; + parameter PPB_ERS = 5'd15; + parameter AUTOBOOT_PG = 5'd16; + parameter ASP_PG = 5'd17; + parameter PLB_PG = 5'd18; + parameter DYB_PG = 5'd19; + parameter NVDLR_PG = 5'd20; + + reg [4:0] current_state; + reg [4:0] next_state; + +// Instruction type + parameter NONE = 7'd0; + parameter WRR = 7'd1; + parameter PP = 7'd2; + parameter READ = 7'd3; + parameter WRDI = 7'd4; + parameter RDSR = 7'd5; + parameter WREN = 7'd6; + parameter RDSR2 = 7'd7; + parameter FSTRD = 7'd8; + parameter FSTRD4 = 7'd9; + parameter DDRFR = 7'd10; + parameter DDRFR4 = 7'd11; + parameter PP4 = 7'd12; + parameter RD4 = 7'd13; + parameter ABRD = 7'd14; + parameter ABWR = 7'd15; + parameter BRRD = 7'd16; + parameter BRWR = 7'd17; + parameter P4E = 7'd19; + parameter P4E4 = 7'd20; + parameter ASPRD = 7'd21; + parameter ASPP = 7'd22; + parameter CLSR = 7'd23; + parameter QPP = 7'd24; + parameter QPP4 = 7'd25; + parameter RDCR = 7'd26; + parameter DOR = 7'd27; + parameter DOR4 = 7'd28; + parameter DLPRD = 7'd29; + parameter OTPP = 7'd30; + parameter PNVDLR = 7'd31; + parameter OTPR = 7'd32; + parameter WVDLR = 7'd33; + parameter BE = 7'd34; + parameter QOR = 7'd35; + parameter QOR4 = 7'd36; + parameter ERSP = 7'd37; + parameter ERRS = 7'd38; + parameter PGSP = 7'd39; + parameter PGRS = 7'd40; + parameter REMS = 7'd41; + parameter RDID = 7'd42; + parameter MPM = 7'd43; + parameter PLBWR = 7'd44; + parameter PLBRD = 7'd45; + parameter RES = 7'd46; + parameter DIOR = 7'd47; + parameter DIOR4 = 7'd48; + parameter DDRDIOR = 7'd49; + parameter DDRDIOR4 = 7'd50; + parameter SE = 7'd51; + parameter SE4 = 7'd52; + parameter DYBRD = 7'd53; + parameter DYBWR = 7'd54; + parameter PPBRD = 7'd55; + parameter PPBP = 7'd56; + parameter PPBERS = 7'd57; + parameter PASSRD = 7'd58; + parameter PASSP = 7'd59; + parameter PASSU = 7'd60; + parameter QIOR = 7'd61; + parameter QIOR4 = 7'd62; + parameter DDRQIOR = 7'd63; + parameter DDRQIOR4 = 7'd64; + parameter RESET = 7'd65; + parameter MBR = 7'd66; + parameter BRAC = 7'd67; + + reg [6:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SO_in, SO_z) + begin + if (SO_in==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_pin=deq_pin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_sin=deq_sin + && (ddr == 1'b0) && (Instruct !== DDRFR) + && (Instruct !== DDRFR4) && (Instruct !== DDRDIOR) + && (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR) + && (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz); + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + initial + begin : Init + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + cnt = 0; + RST = 1'b0; + RST_in = 1'b0; + RST_out = 1'b1; + PDONE = 1'b1; + PSTART = 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + PRGSUSP_in = 1'b0; + ERSSUSP_in = 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + Reseted = 1'b0; + + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl128s.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl128s_otp memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at OTPMem(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + + LOCK_BYTE1[7:0] = OTPMem[16]; + LOCK_BYTE2[7:0] = OTPMem[17]; + LOCK_BYTE3[7:0] = OTPMem[18]; + LOCK_BYTE4[7:0] = OTPMem[19]; + end + + // initialize memory and load preload files if any + initial + begin: InitTimingModel + integer i; + integer j; + //UNIFORM OR HYBRID arch model is used + //assumptions: + //1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF + //it is important that 16-th character from first one is "0" or "1" + //2. TimingModel does not have more then 24 characters + tmp_timing = TimingModel;//copy of TimingModel + + i = 23; + while ((i >= 0) && (found != 1'b1))//search for first non null character + begin //i keeps position of first non null character + j = 7; + while ((j >= 0) && (found != 1'b1)) + begin + if (tmp_timing[i*8+j] != 1'd0) + found = 1'b1; + else + j = j-1; + end + i = i - 1; + end + i = i +1; + if (found)//if non null character is found + begin + for (j=0;j<=7;j=j+1) + begin + //EHPLC/HPLC character is 15 + tmp_char1[j] = TimingModel[(i-14)*8+j]; + //256B/512B Page character is 16 + tmp_char2[j] = TimingModel[(i-15)*8+j]; + end + end + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" || + tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L") + begin + EHP = 1; + if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y") + begin + RdPswdProtEnable = 1; + end + end + else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" || + tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q") + begin + EHP = 0; + end + + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" || + tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" || + tmp_char1 == "9" || tmp_char1 == "Q") + begin + ASP_reg = 16'hFE7F; + ASP_reg_in = 16'hFE7F; + end + else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" || + tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L") + begin + ASP_reg = 16'hFE4F; + ASP_reg_in = 16'hFE4F; + end + + if (tmp_char2 == "0") + begin + PageSize = 255; + PageNum = PageNum64; + SecSize = SecSize64; + end + else if (tmp_char2 == "1") + begin + PageSize = 511; + PageNum = PageNum256; + SecSize = SecSize256; + end + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + /////////////////////////////////////////////////////////////////////// + // ID-CFI array data + /////////////////////////////////////////////////////////////////////// + // Manufacturer and Device ID + CFI_array[8'h00] = Jedec_ID; + CFI_array[8'h01] = DeviceID1; + CFI_array[8'h02] = DeviceID2; + CFI_array[8'h03] = 8'h00; + if (tmp_char2 == "0") + // Uniform 64kB sectors + CFI_array[8'h04] = ExtendedID64; + else if (tmp_char2 == "1") + // Uniform 256kB sectors + CFI_array[8'h04] = ExtendedID256; + CFI_array[8'h05] = 8'h80; + CFI_array[8'h06] = 8'h00; + CFI_array[8'h07] = 8'h00; + CFI_array[8'h08] = 8'h00; + CFI_array[8'h09] = 8'h00; + CFI_array[8'h0A] = 8'h00; + CFI_array[8'h0B] = 8'h00; + CFI_array[8'h0C] = 8'h00; + CFI_array[8'h0D] = 8'h00; + CFI_array[8'h0E] = 8'h00; + CFI_array[8'h0F] = 8'h00; + // CFI Query Identification String + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h53; + CFI_array[8'h18] = 8'h46; + CFI_array[8'h19] = 8'h51; + CFI_array[8'h1A] = 8'h00; + //CFI system interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h06; + if (tmp_char2 == "0") + begin + // 64kB sector and 256B page + CFI_array[8'h20] = 8'h08; + CFI_array[8'h21] = 8'h08; + end + else if (tmp_char2 == "1") + begin + // 256kB sector and 512B page + CFI_array[8'h20] = 8'h09; + CFI_array[8'h21] = 8'h09; + end + CFI_array[8'h22] = 8'h0F; + CFI_array[8'h23] = 8'h02; + CFI_array[8'h24] = 8'h02; + CFI_array[8'h25] = 8'h03; + CFI_array[8'h26] = 8'h03; + // Device Geometry Definition(Uniform Sector Devices) + CFI_array[8'h27] = 8'h18; + CFI_array[8'h28] = 8'h02; + CFI_array[8'h29] = 8'h01; + + if (tmp_char2 == "0") + // 64kB sectors + CFI_array[8'h2A] = 8'h08; + else if (tmp_char2 == "1") + CFI_array[8'h2A] = 8'h09; + + CFI_array[8'h2B] = 8'h00; + if (tmp_char2 == "1") + begin + CFI_array[8'h2C] = 8'h01; + CFI_array[8'h2D] = 8'h3F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h04; + CFI_array[8'h31] = 8'hFF; + CFI_array[8'h32] = 8'hFF; + CFI_array[8'h33] = 8'hFF; + CFI_array[8'h34] = 8'hFF; + end + else + begin + CFI_array[8'h2C] = 8'h02; + if (TBPARM) + begin + // 4KB physical sectors at top + CFI_array[8'h2D] = 8'hFD; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h01; + CFI_array[8'h31] = 8'h1F; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h10; + CFI_array[8'h34] = 8'h00; + end + else + begin + // 4KB physical sectors at bottom + CFI_array[8'h2D] = 8'h1F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h10; + CFI_array[8'h30] = 8'h00; + CFI_array[8'h31] = 8'hFD; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h00; + CFI_array[8'h34] = 8'h01; + end + end + CFI_array[8'h35] = 8'hFF; + CFI_array[8'h36] = 8'hFF; + CFI_array[8'h37] = 8'hFF; + CFI_array[8'h38] = 8'hFF; + CFI_array[8'h39] = 8'hFF; + CFI_array[8'h3A] = 8'hFF; + CFI_array[8'h3B] = 8'hFF; + CFI_array[8'h3C] = 8'hFF; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + // CFI Primary Vendor-Specific Extended Query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h21; + CFI_array[8'h46] = 8'h02; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h08; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h00; + CFI_array[8'h4D] = 8'h00; + CFI_array[8'h4E] = 8'h00; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h01; + + begin + for(i=80;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h00-i+80]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + + end + + always @(next_state_event or PoweredUp or RST or RST_out) + begin: StateTransition + if (PoweredUp) + begin + if ((RSTNeg_in) && RST_out == 1'b1) + current_state = #(1000) next_state; + else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST) + begin + // no state transition while RESET# low + current_state = RESET_STATE; + RST_in = 1'b1; + #1000 RST_in = 1'b0; + end + end + end + + always @(posedge RST_in) + begin:Threset + RST_out = 1'b0; + #(35000000-200000) RST_out = 1'b1; + end + + always @(negedge CSNeg_ipd) + begin:CheckCEOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_PRGSUSP PRGSUSP_out = 1'b1; + end + + always @(posedge PPBERASE_in) + begin:PPBErs + PPBERASE_out = 1'b0; + #tdevice_PPBERASE PPBERASE_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_ERSSUSP ERSSUSP_out = 1'b1; + end + + always @(posedge PASSULCK_in) + begin:PASSULock + PASSULCK_out = 1'b0; + #tdevice_PASSULCK PASSULCK_out = 1'b1; + end + + always @(posedge PASSACC_in) + begin:PASSAcc + PASSACC_out = 1'b0; + #tdevice_PASSACC PASSACC_out = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [7:0] opcode_in; + reg [7:0] opcode_tmp; + reg [31:0] addr_bytes; + reg [31:0] hiaddr_bytes; + reg [31:0] Address_in; + reg [7:0] mode_bytes; + reg [7:0] mode_in; + integer Latency_code; + integer quad_data_in [0:1023]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle + integer i; + integer j; + integer k; + time CLK_PER; + time LAST_CLK; + + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + Instruct = NONE; + write = 1'b1; + cfg_write = 0; + opcode_cnt = 0; + addr_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + data_cnt = 0; + opcode_tmp = 0; + DOUBLE = 1'b0; + QUADRD = 1'b0; + CLK_PER = 1'b0; + LAST_CLK = 1'b0; + if (current_state == AUTOBOOT) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = OPCODE_BYTE; + end + end + end + + if (rising_edge_SCK_ipd) // Instructions, addresses or data present + begin // at SI are latched on the rising edge of SCK + + CLK_PER = $time - LAST_CLK; + LAST_CLK = $time; + if (CHECK_FREQ) + begin + if ((CLK_PER < 20000 && Latency_code == 3) || + (CLK_PER < 12500 && Latency_code == 0) || + (CLK_PER < 11100 && Latency_code == 1) || + (CLK_PER < 9600 && Latency_code == 2)) + begin + $display ("More wait states are required for"); + $display ("this clock frequency value"); + end + CHECK_FREQ = 0; + end + + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + Latency_code = Config_reg1[7:6]; + if (opcode_cnt == BYTE) + begin + for(i=7;i>=0;i=i-1) + begin + opcode[i] = opcode_in[7-i]; + end + case (opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010011 : // 13h + begin + Instruct = RD4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : // 4Bh + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000111 : // 07h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 35h + begin + Instruct = RDCR; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : // 90h + begin + Instruct = REMS; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : // 9Fh + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011 : // ABh + begin + Instruct = RES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FSTRD; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001100 : // 0Ch + begin + Instruct = FSTRD4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001101 : // 0Dh + begin + Instruct = DDRFR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001110 : // 0Eh + begin + Instruct = DDRFR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111011 : // 3Bh + begin + Instruct = DOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111100 : // 3Ch + begin + Instruct = DOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111011 : // BBh + begin + Instruct = DIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111100 : // BCh + begin + Instruct = DIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111101 : // BDh + begin + Instruct = DDRDIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111110 : // BEh + begin + Instruct = DDRDIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101011 : // 6Bh + begin + Instruct = QOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101100 : // 6Ch + begin + Instruct = QOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101011 : // EBh + begin + Instruct = QIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101100 : // ECh + begin + Instruct = QIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101101 : // EDh + begin + Instruct = DDRQIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101110 : // EEh + begin + Instruct = DDRQIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010010 : // 12h + begin + Instruct = PP4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010: // 32h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00111000: // 38h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00110100 : // 34h + begin + Instruct = QPP4; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b01000010 : // 42h + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10000101 : // 85h + begin + Instruct = PGSP; + bus_cycle_state = DATA_BYTES; + end + 8'b10001010 : // 8Ah + begin + Instruct = PGRS; + bus_cycle_state = DATA_BYTES; + end + 8'b11000111 : // C7h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b01100000 : // 60h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011100 : // DCh + begin + Instruct = SE4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERRS; + bus_cycle_state = DATA_BYTES; + end + 8'b00010100 : // 14h + begin + Instruct = ABRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010101 : // 15h + begin + Instruct = ABWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00010110 : // 16h + begin + Instruct = BRRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010111 : // 17h + begin + Instruct = BRWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00101011 : // 2Bh + begin + Instruct = ASPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00101111 : // 2Fh + begin + Instruct = ASPP; + bus_cycle_state = DATA_BYTES; + end + 8'b11100000 : // E0h + begin + Instruct = DYBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100001 : // E1h + begin + Instruct = DYBWR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100010 : // E2h + begin + Instruct = PPBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100011 : // E3h + begin + Instruct = PPBP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100100 : // E4h + begin + Instruct = PPBERS; + bus_cycle_state = DATA_BYTES; + end + 8'b10100110 : // A6h + begin + Instruct = PLBWR; + bus_cycle_state = DATA_BYTES; + end + 8'b10100111 : // A7h + begin + Instruct = PLBRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11100111 : // E7h + begin + Instruct = PASSRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11101000 : // E8h + begin + Instruct = PASSP; + bus_cycle_state = DATA_BYTES; + end + 8'b11101001 : // E9h + begin + Instruct = PASSU; + bus_cycle_state = DATA_BYTES; + end + 8'b11110000 : // F0h + begin + Instruct = RESET; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : // 30h + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00100000 : // 20h + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00100001 : // 21h + begin + Instruct = P4E4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000001 : // 41h + begin + Instruct = DLPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b01000011 : // 43h + begin + Instruct = PNVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b01001010 : // 4Ah + begin + Instruct = WVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = BRAC; + bus_cycle_state = DATA_BYTES; + end + 8'b11111111 : // FFh + begin + Instruct = MBR; + bus_cycle_state = MODE_BYTE; + end + endcase + end + end + end //end of OPCODE BYTE + + ADDRESS_BYTES : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4) || + (Instruct == DDRDIOR) || (Instruct == DDRDIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + DOUBLE = 1'b1; + else + DOUBLE = 1'b0; + if ((Instruct == QOR) || (Instruct == QOR4) || + (Instruct == QIOR) || (Instruct == QIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + QUADRD = 1'b1; + else + QUADRD = 1'b0; + if (DOUBLE == 1'b0) + begin + if (((((Instruct == FSTRD) && (~EXTADD)) || + ((Instruct == DOR) && (~EXTADD)) || + (Instruct == OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QOR) && QUAD && (~EXTADD))) + begin + //Instruction + 3 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes ; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct==FSTRD || Instruct==DOR || + Instruct == QOR) + begin + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((((Instruct==FSTRD4) || + (Instruct==DOR4) || + ((Instruct==FSTRD) && EXTADD) || + ((Instruct==DOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct==QOR4) && QUAD) || + ((Instruct==QOR) && QUAD && EXTADD)) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + end + end + end + else if ((Instruct==DIOR) && (~EXTADD) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + //DUAL I/O High Performance Read(3 Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i]=Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==DIOR4) || + ((Instruct==DIOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin //DUAL I/O High Performance Read(4Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == QIOR) && (~EXTADD)) + begin + //QUAD I/O High Performance Read (3Bytes Address) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((Instruct==QIOR4) || ((Instruct==QIOR) + && EXTADD)) + begin + //QUAD I/O High Performance Read (4Bytes Addr) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt +1; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt =0; + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((((Instruct==RD4) || (Instruct==PP4) || + (Instruct==SE4) ||(Instruct==PPBRD) || + (Instruct==DYBRD) ||(Instruct==DYBWR) || + (Instruct==PPBP) || (Instruct==P4E4) || + ((Instruct==READ) && EXTADD) || + ((Instruct==PP) && EXTADD) || + ((Instruct==P4E) && EXTADD) || + ((Instruct==SE) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (QUAD && (Instruct==QPP4 || + ((Instruct==QPP) && EXTADD)))) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + else if (((HOLDNeg_in && ~QUAD) || QUAD) && + (~EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + else + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + end + end + + MODE_BYTE : + begin + if (((Instruct==DIOR) || (Instruct == DIOR4)) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + if (Latency_code == 0 || Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + mode_in[2*mode_cnt] = SI_in; + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt] = SO_in; + mode_in[4*mode_cnt+1] = SI_in; + end + else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4)) + && QUAD) + begin + mode_in[0] = HOLDNeg_in; + mode_in[1] = WPNeg_in; + mode_in[2] = SO_in; + mode_in[3] = SI_in; + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + if ((((Instruct==FSTRD) || (Instruct==FSTRD4) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (((Instruct==QOR)||(Instruct==QOR4)) && QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + begin + bus_cycle_state = DATA_BYTES; + end + end + + else if ((Instruct==DDRFR) || (Instruct==DDRFR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==2)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==5)) || + ((Latency_code == 1) && (dummy_cnt==6)) || + ((Latency_code == 2) && (dummy_cnt==7))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (Instruct==RES) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + else if ((Instruct == DIOR) || (Instruct == DIOR4) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 1) && (dummy_cnt==1)) || + ((Latency_code == 2) && (dummy_cnt==2))) + bus_cycle_state = DATA_BYTES; + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + bus_cycle_state = DATA_BYTES; + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==2)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (((Instruct == QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + + if (((Latency_code == 3) && (dummy_cnt==3)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + + DATA_BYTES : + begin + + if (DOUBLE == 1'b1 && (hold_mode==0)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + + if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4))) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in}; + if (data_cnt > ((PageSize+1)*2-1)) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for(i=0;i<=(PageSize*2-1);i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[(PageSize+1)*2-1] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + else if ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (data_cnt > ((PageSize+1)*8-1)) + begin + //In case of serial mode and PP, + //if more than PageSize are sent to the device + //previously latched data are discarded and last + //256/512 data bytes are guaranteed to be programmed + //correctly within the same page. + if (bit_cnt == 0) + begin + for(i=0;i<=(PageSize*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[PageSize*BYTE + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + + if (falling_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + ADDRESS_BYTES : + begin + if (DOUBLE == 1'b1) + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[23:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + end + + MODE_BYTE : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + begin + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + begin + mode_in[4] = HOLDNeg_in; + mode_in[5] = WPNeg_in; + mode_in[6] = SO_in; + mode_in[7] = SI_in; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + DATA_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 ) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + else + begin + if ((Instruct==READ) || (Instruct==RD4) || + (Instruct==FSTRD)|| (Instruct==FSTRD4)|| + (Instruct==RDSR) || (Instruct==RDSR2) || + (Instruct==RDCR) || (Instruct==OTPR) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==DIOR)|| (Instruct==DIOR4)|| + (Instruct==ABRD) || (Instruct==BRRD) || + (Instruct==ASPRD)|| (Instruct==DYBRD) || + (Instruct==PPBRD)|| + (Instruct==PASSRD)|| (Instruct==RDID)|| + (Instruct==RES) || (Instruct==REMS) || + (Instruct==PLBRD)|| (Instruct==DLPRD) || + (current_state == AUTOBOOT && + start_delay == 0) || + (((Instruct==QOR) || (Instruct==QIOR) || + (Instruct==QOR4) || + (Instruct==QIOR4)) && QUAD)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + + DUMMY_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + endcase + end + end + + if (rising_edge_CSNeg_ipd) + begin + if ((bus_cycle_state != DATA_BYTES) && + (bus_cycle_state != DUMMY_BYTES)) + begin + if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF) + begin + Instruct = MBR; + end + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (((mode_bytes[7:4] == 4'b1010) && + (Instruct==DIOR || Instruct==DIOR4 || + Instruct==QIOR || Instruct==QIOR4)) || + ((mode_bytes[7:4] == ~mode_bytes[3:0]) && + (Instruct == DDRFR || Instruct == DDRFR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4))) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + + case (Instruct) + WREN, + WRDI, + BE, + SE, + SE4, + P4E, + P4E4, + CLSR, + BRAC, + RESET, + PPBERS, + PPBP, + PLBWR, + PGSP, + PGRS, + ERSP, + ERRS: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 0) + write = 1'b0; + end + end + + WRR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Config_reg1_in[i]= + Data_in[15-i]; + end + end + end + end + + PP, + PP4, + OTPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=7;j>=0;j=j-1) + begin + if ((Data_in[(i*8)+(7-j)]) + !== 1'bX) + begin + Byte_slv[j] = + Data_in[(i*8)+(7-j)]; + end + end + WByte[i] = Byte_slv; + end + + if (data_cnt > (PageSize+1)*BYTE) + Byte_number = PageSize; + else + Byte_number = + ((data_cnt/8) - 1); + end + end + end + end + + QPP, + QPP4: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + quad_pg = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > (PageSize+1)*2) + Byte_number = PageSize; + else + Byte_number = ((data_cnt/2)-1); + end + end + end + + ABWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 32) + begin + write = 1'b0; + for(j=0;j<=31;j=j+1) + begin + AutoBoot_reg_in[j] = Data_in[31-j]; + end + end + end + end + + BRWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + Bank_Addr_reg_in[j] = Data_in[7-j]; + end + end + end + end + + ASPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 16) + begin + write = 1'b0; + for(j=0;j<=15;j=j+1) + begin + ASP_reg_in[j] = Data_in[15-j]; + end + end + end + end + + DYBWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + DYBAR_in[j] = Data_in[7-j]; + end + end + end + end + + PNVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + NVDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + WVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + VDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + PASSP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + Password_reg_in[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + + PASSU: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + PASS_TEMP[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + endcase + end + end + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Page Program +/////////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed_pgm; + time start_pgm; + time duration_pgm; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) || + (Instruct == QPP) || (Instruct == QPP4)) + if (PageSize == 255) + begin + pob = tdevice_PP_256; + end + else + begin + pob = tdevice_PP_512; + end + else + pob = tdevice_BP; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed_pgm = 0; + duration_pgm = pob; + PDONE = 1'b0; + ->pdone_event; + start_pgm = $time; + end + end + + always @(posedge PGSUSP) + begin + if (PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed_pgm = $time - start_pgm; + duration_pgm = pob - elapsed_pgm; + PDONE = 1'b0; + end + end + + always @(posedge PGRES) + begin + start_pgm = $time; + ->pdone_event; + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #duration_pgm PDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Write Status Register +/////////////////////////////////////////////////////////////////////////////// + time wob; + always @(posedge WSTART) + begin:wdone_process + wob = tdevice_WRR; + if (WSTART && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Reset Timing +/////////////////////////////////////////////////////////////////////////////// + + time startlo; + time starthi; + time durationlo; + time durationhi; + + always @(negedge RSTNeg_in or Instruct) + begin + if (~RSTNeg_in) + begin + RST = 1'b1; + #200000 RST = 1'b0; // 200 ns + end + else if (Instruct == RESET) + begin + Reseted = 1'b0; + #10000 Reseted = 1'b1; // 10 ns + end + end + + always @(RST_in or rising_edge_Reseted) // Reset done,program terminated + begin + if ((RST_in && ~RST) || (rising_edge_Reseted)) + disable pdone_process; + disable edone_process; + disable wdone_process; + PDONE = 1'b1; + EDONE = 1'b1; + WDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Bulk Erase +/////////////////////////////////////////////////////////////////////////////// + time seo; + time beo; + event edone_event; + time elapsed_ers; + time start_ers; + time duration_ers; + + always @(rising_edge_ESTART) + begin + if (UniformSec) + begin + seo = tdevice_SE256; + end + else + begin + seo = tdevice_SE64; + end + beo = tdevice_BE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == BE) + begin + duration_ers = beo; + end + else + begin + duration_ers = seo; + end + elapsed_ers = 0; + EDONE = 1'b0; + ->edone_event; + start_ers = $time; + end + end + + always @(posedge ESUSP) + begin + if (ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed_ers = $time - start_ers; + duration_ers = seo - elapsed_ers; + EDONE = 1'b0; + end + end + + always @(posedge ERES) + begin + if (ERES && (~EDONE)) + begin + start_ers = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_ers EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg falling_edge_PPBERASE_in = 1'b0; + reg falling_edge_PASSULCK_in = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or + falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or + rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or + PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out + or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in) + begin: StateGen1 + + integer sect; + + if (rising_edge_PoweredUp) + begin + if (ABE == 1 && RPME !== 0 ) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + else + begin + if (RST_out == 1'b0) + next_state = current_state; + else if (falling_edge_write && Instruct == RESET) + begin + if (ABE == 1 && RPME !== 0) + begin + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + ABSD = AutoBoot_reg[8:1]; + start_autoboot = 0; + next_state = AUTOBOOT; + end + else + next_state = IDLE; + end + else + begin + case (current_state) + RESET_STATE : + begin + if (rising_edge_RST_out) + begin + if (ABE == 1 && RPME!== 0) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9],9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + end + + IDLE : + begin + if (falling_edge_write && RdPswdProtMode == 0) + begin + if (Instruct == WRR && WEL == 1 && BAR_ACC == 0 + && (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)) + // can not execute if HPM is entered or + // if WEL bit is zero + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + $display ("WARNING: Changing value of "); + $display ("Configuration Register OTP "); + $display ("bit from 1 to 0 is not"); + $display ("allowed!!!"); + end + else + begin + next_state = WRITE_SR; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = PAGE_PG; + end + end + else if (Instruct==OTPP && WEL==1 && FREEZE==0) + begin + if (((((Address>=16'h0010 && Address<=16'h0013) + ||(Address>=16'h0020 && Address<=16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address>=16'h0100 && Address<=16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32]==1) || + ((Address>=16'h0200 && Address<=16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32]==1) || + ((Address>=16'h0300 && Address<=16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) + && (Address + Byte_number <= OTPHiAddr)) + next_state = OTP_PG; + end + else if ((Instruct == SE || Instruct == SE4) + && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 + && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + else if ((TopBoot && sect >= 254) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a + //64 KB range that includes 4 KB sectors. + next_state = SECTOR_ERS; + end + end + else if ((Instruct == P4E || Instruct == P4E4) + && WEL == 1) + begin + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + $display("The instruction is applied to"); + $display("a sector that is larger than"); + $display("4 KB."); + $display("Instruction is ignored!!!"); + end + else + begin + if (Sec_Prot[sect]== 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + end + else if (Instruct == BE && WEL == 1 && + (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0)) + next_state = BULK_ERS; + else if (Instruct == ABWR && WEL == 1) + //Autoboot Register Write Command + next_state = AUTOBOOT_PG; + else if (Instruct == BRWR) + //Bank Register Write Command + next_state = IDLE; + else if (Instruct == ASPP && WEL == 1) + begin + //ASP Register Program Command + if (~(ASPOTPFLAG)) + next_state = ASP_PG; + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + next_state = PLB_PG; + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + next_state = PASS_PG; + end + else if (Instruct == PASSU && WEL && ~WIP) + next_state = PASS_UNLOCK; + else if (Instruct == PPBP && WEL == 1) + next_state <= PPB_PG; + else if (Instruct == PPBERS && WEL && PPBOTP) + next_state <= PPB_ERS; + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == PNVDLR && WEL == 1) + next_state = NVDLR_PG; + else + next_state = IDLE; + end + if (falling_edge_write && RdPswdProtMode == 1 && ~WIP) + begin + if (Instruct == PASSU) + next_state = PASS_UNLOCK; + end + end + + AUTOBOOT : + begin + if (rising_edge_CSNeg_ipd) + next_state = IDLE; + end + + WRITE_SR : + begin + if (rising_edge_WDONE) + next_state = IDLE; + end + + PAGE_PG : + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end + + PG_SUSP : + begin + if (falling_edge_write) + begin + if (Instruct == BRWR) + //Bank Register Write Command + next_state = PG_SUSP; + else if (Instruct == PGRS) + next_state = PAGE_PG; + end + end + + OTP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + BULK_ERS : + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS : + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP : + begin + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && SectorSuspend != + Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = ERS_SUSP_PG; + end + end + end + else if (Instruct == BRWR) + begin + //Bank Register Write Command + next_state = ERS_SUSP; + end + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == ERRS) + next_state = SECTOR_ERS; + end + end + + ERS_SUSP_PG : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = ERS_SUSP_PG_SUSP; + end + + ERS_SUSP_PG_SUSP : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + next_state = ERS_SUSP_PG_SUSP; + end + else if (Instruct == PGRS) + begin + next_state = ERS_SUSP_PG; + end + end + end + + PASS_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PASS_UNLOCK : + begin + if (falling_edge_PASSULCK_in) + next_state = IDLE; + end + + PPB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PPB_ERS : + begin + if (falling_edge_PPBERASE_in) + next_state = IDLE; + end + + AUTOBOOT_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PLB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + DYB_PG : + begin + if (rising_edge_PDONE) + if (ES) + next_state = ERS_SUSP; + else + next_state = IDLE; + end + + ASP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + NVDLR_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + endcase + end + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer WData [0:511]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(Instruct_event) + begin + read_cnt = 0; + byte_cnt = 1; + rd_fast = 1'b1; + dual = 1'b0; + rd_slow = 1'b0; + any_read = 1'b0; + end + + always @(rising_edge_read_out) + begin + if (rising_edge_read_out == 1'b1) + begin + if (PoweredUp == 1'b1) + begin + oe_z = 1'b1; + #1000 oe_z = 1'b0; + oe = 1'b1; + #1000 oe = 1'b0; + end + end + end + + always @(change_addr_event) + begin + if (change_addr_event) + begin + read_addr = Address; + end + end + + always @(posedge PASSACC_out) + begin + Status_reg1[0] = 1'b0; //WIP + PASSACC_in = 1'b0; + end + + always @(Instruct or posedge start_autoboot or oe or current_state_event or + falling_edge_write or posedge PDONE or posedge WDONE or oe_z or + posedge EDONE or ERSSUSP_out or rising_edge_Reseted or + rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or + Address) + begin: Functionality + integer i,j; + integer sect; + + if (rising_edge_PoweredUp) + begin + //the default condition after power-up + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + //The Configuration Register FREEZE bit is cleared. + Config_reg1[0] = 0; + //The WEL bit is cleared. + Status_reg1[1] = 0; + //When BPNV is set to '1'. the BP2-0 bits in Status Register are + //volatile and will be reset binary 111 after power-on reset + if (BPNV == 1 && LOCK == 0 && FREEZE == 0 ) + begin + Status_reg1[4] = 1'b0;// BP2 + Status_reg1[3] = 1'b0;// BP1 + Status_reg1[2] = 1'b0;// BP0 + BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + + //As shipped from the factory, all devices default ASP to the + //Persistent Protection mode, with all sectors unprotected, + //when power is applied. The device programmer or host system must + //then choose which sector protection method to use. + //For Persistent Protection mode, PPBLOCK defaults to "1" + PPBL[0] = 1'b1; + + //All the DYB power-up in the unprotected state + DYB_bits = {286{1'b1}}; + end + + if (Instruct == RESET) + begin + //EXTADD is cleared to “0” + Bank_Addr_reg[7] = 1'b0; + //P_ERR bit is cleared + Status_reg1[6] = 1'b0; + //E_ERR bit is cleared + Status_reg1[5] = 1'b0; + //The WEL bit is cleared. + Status_reg1[1] = 1'b0; + //The WIP bit is cleared. + Status_reg1[0] = 1'b0; + //The ES bit is cleared. + Status_reg2[1] = 1'b0; + //The PS bit is cleared. + Status_reg2[0] = 1'b0; + //When BPNV is set to '1'. the BP2-0 bits in Status + //Register are volatile and will be reseted after + //reset command + if (BPNV == 1 && LOCK== 0 && FREEZE == 0) + begin + Status_reg1[4] = 1'b1; + Status_reg1[3] = 1'b1; + Status_reg1[2] = 1'b1; + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + case (current_state) + IDLE : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + ASP_ProtSE = 0; + Sec_ProtSE = 0; + + if (BottomBoot) + begin + for (j=31;j>=0;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + else if (TopBoot) + begin + for (j=285;j>=254;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + + if (falling_edge_write && RdPswdProtMode == 1) + begin + if(Instruct == PASSU) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + end + + if (falling_edge_write && RdPswdProtMode == 0) + begin + read_cnt = 0; + byte_cnt = 1; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 0; + else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 && + BAR_ACC == 0) + begin + if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD) + begin + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + // P_ERR bit is set to 1 + Status_reg1[6] = 1'b1; + end + else + begin + // can not execute if Hardware Protection Mode + // is entered or if WEL bit is zero + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + end + else + Status_reg1[1] = 0; + end + else if ((Instruct == PP || Instruct == PP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if (Instruct == OTPP && WEL == 1) + begin + // As long as the FREEZE bit remains cleared to a logic + // '0' the OTP address space is programmable. + if (FREEZE == 0) + begin + if (((((Address>= 16'h0010 && Address<= 16'h0013) || + (Address >= 16'h0020 && Address <= 16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address >= 16'h0100 && Address <= 16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32] == 1) || + ((Address >= 16'h0200 && Address <= 16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32] == 1) || + ((Address >= 16'h0300 && Address <= 16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) && + (Address + Byte_number <= OTPHiAddr)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else if ((Address < 8'h10 || (Address > 8'h13 && + Address < 8'h20) || Address > 12'h3FF )) + begin + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + if (Address < 8'h20) + begin + $display ("Given address is "); + $display ("in reserved address range"); + end + else if (Address > 12'h3FF) + begin + $display ("Given address is "); + $display ("out of OTP address range"); + end + end + else + begin + //P_ERR bit will be set when the user attempts to + // to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == SE || Instruct == SE4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + SectorSuspend = sect; + PARAM_REGION = 0; + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((TopBoot && sect >= 254) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a 64 KB range + //that includes 4 KB sectors + begin + if (TopBoot) + begin + SectorSuspend = 254 + (285 - sect)/16; + end + else + begin + SectorSuspend = sect/16; + end + PARAM_REGION = 1; + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if ((Instruct == P4E || Instruct == P4E4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + Status_reg1[1] = 1'b0;//WEL + end + else + begin + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + //A P4E instruction applied to a sector + //that has been Write Protected through the + //Block Protect Bits or ASP will not be + //executed and will set the E_ERR status + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if (Instruct == BE && WEL == 1) + begin + if (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + end + else + begin + //The Bulk Erase command will not set E_ERR if a + //protected sector is found during the command + //execution. + Status_reg1[1] = 1'b0;//WEL + end + end + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + $display ("Password programming is not allowed"); + $display (" in Password Protection Mode."); + end + end + else if (Instruct == PASSU && WEL) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == ASPP && WEL == 1) + begin + if (~(ASPOTPFLAG)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + $display ("Once the Protection Mode is selected,"); + $display ("no further changes to the ASP "); + $display ("register is allowed."); + end + end + else if (Instruct == ABWR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBP && WEL == 1) + begin + ReturnSectorID(sect,Address); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBERS && WEL == 1) + begin + if (PPBOTP) + begin + PPBERASE_in = 1'b1; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[5] = 1'b1; + end + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PNVDLR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == WVDLR && WEL == 1) + begin + VDLR_reg = VDLR_reg_in; + Status_reg1[1] = 1'b0; + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4 || + Instruct == RES || + (Instruct == DLPRD && RdPswdProtMode == 0)) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4 || + ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + else if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES + && VDLR_reg != 8'b00000000) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + && QUAD) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd = data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr + && RdPswdProtMode == 0) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + data_out[7:0] = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if ((read_addr > OTPHiAddr)||(RdPswdProtMode==1)) + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum or Read Password Protection Mode + //is selected instead, the data beyond the + //maximum OTP address will be undefined. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == REMS) + begin + //Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + data_out[7:0] = DeviceID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + else if (Instruct == RDID) + begin + ident_out = CFI_array_tmp; + if(read_cnt < 648) + begin + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + //Continued shifting of output beyond the end of + //the defined ID-CFI address space will + //provide undefined data. + SOut_zd = 1'bX; + end + end + else if (Instruct == RES) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + data_out = ESignature; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DLPRD && RdPswdProtMode == 0) + begin + //Read DLP + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = VDLR_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ABRD && RdPswdProtMode == 0) + begin + //Read AutoBoot register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = AutoBoot_reg[31-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 32) + read_cnt = 0; + end + else if (Instruct == BRRD && RdPswdProtMode == 0) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ASPRD && RdPswdProtMode == 0) + begin + //Read ASP Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = ASP_reg[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == PASSRD && RdPswdProtMode == 0) + begin + //Read Password Register + if (~(PWDMLB == 0 && PSTMLB == 1)) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = + Password_reg[(8*byte_cnt-1)-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + byte_cnt = byte_cnt + 1; + if (byte_cnt == 9) + byte_cnt = 1; + end + end + end + else if (Instruct == PLBRD) + begin + //Read PPB Lock Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = PPBL[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + DYBAR[7:0] = 8'bXXXXXXXX; + + if (RdPswdProtMode == 0) + begin + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end + + AUTOBOOT: + begin + if (start_autoboot == 1) + begin + if (oe) + begin + any_read = 1'b1; + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + end + else if (oe_z) + begin + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + end + end + + WRITE_SR: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (WDONE == 1) + begin + Status_reg1[0] = 1'b0; //WIP + Status_reg1[1] = 1'b0; //WEL + //SRWD bit + Status_reg1[7] = Status_reg1_in[7]; //MSB first + + if (LOCK == 0) + begin + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT and TBPARM bits in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg1[4] = Status_reg1_in[4];//BP2 + Status_reg1[3] = Status_reg1_in[3];//BP1 + Status_reg1[2] = Status_reg1_in[2];//BP0 + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + if (TBPROT == 1'b0 && INITIAL_CONFIG == 1'b0) + begin + Config_reg1[5] = Config_reg1_in[5];//TBPROT + end + if (TBPARM == 1'b0 && INITIAL_CONFIG == 1'b0 && + tmp_char2 == "0") + begin + Config_reg1[2] = Config_reg1_in[2];//TBPARM + change_TBPARM = 1'b1; + #1000 change_TBPARM = 1'b0; + end + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + Config_reg1[7] = Config_reg1_in[7];//LC1 + Config_reg1[6] = Config_reg1_in[6];//LC0 + Config_reg1[1] = Config_reg1_in[1];//QUAD + + if (FREEZE == 1'b0) + begin + Config_reg1[0] = Config_reg1_in[0];//FREEZE + end + + if (WRLOCKENABLE== 1'b1 && LOCK == 1'b0) + begin + Config_reg1[4] = Config_reg1_in[4];//LOCK + WRLOCKENABLE = 1'b0; + end + if (BPNV == 1'b0) + begin + Config_reg1[3] = Config_reg1_in[3];//BPNV + end + end + end + + PAGE_PG : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == PAGE_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt = 0; + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + quad_pg = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + PDONE = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd =data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + OTP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == OTP_PG) + begin + if (~PDONE) + begin + if (Address + wr_cnt <= OTPHiAddr) + begin + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = OTPMem[Addr + i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + OTPMem[Addr + i] = -1; + end + end + else + begin + $display ("Programming will reach over "); + $display ("address limit of OTP array"); + end + end + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + OTPMem[Addr + i] = WData[i]; + end + LOCK_BYTE1 = OTPMem[16]; + LOCK_BYTE2 = OTPMem[17]; + LOCK_BYTE3 = OTPMem[18]; + LOCK_BYTE4 = OTPMem[19]; + end + end + + SECTOR_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == SECTOR_ERS) + begin + if (~EDONE) + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + else if (Instruct == ERSP && ~ERSSUSP_in) + begin + ESUSP = 1'b1; + ESUSP <= #5 1'b0; + ERSSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + end + + BULK_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == BULK_ERS) + begin + if (~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = -1; + end + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = MaxData; + end + end + end + end + + ERS_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (ERSSUSP_out == 1) + begin + ERSSUSP_in = 0; + //The Erase Suspend (ES) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //erase operation has been suspended. + Status_reg2[1] = 1'b1; + //The WIP bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == PP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + + if (Sec_Prot[sect] == 0 + && PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == ERRS) + begin + Status_reg2[1] = 1'b0; + Status_reg1[0] = 1'b1; + if (BottomBoot) + begin + if (PARAM_REGION) + begin + Addr = SectorSuspend*(SecSize+1); + end + else + begin + Addr = (SectorSuspend-30)*(SecSize+1); + end + end + else + begin + Addr = SectorSuspend*(SecSize+1); + end + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + ERES = 1'b1; + ERES <= #5 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == ERS_SUSP_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt =0; + end + + if(PDONE == 1) + begin + Status_reg1[0] = 1'b0;//WIP + Status_reg1[1] = 1'b0;//WEL + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi ) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PASS_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + new_pass = Password_reg_in; + old_pass = Password_reg; + for (i=0;i<=63;i=i+1) + begin + if (old_pass[j] == 0) + new_pass[j] = 0; + end + + if (PDONE == 1) + begin + Password_reg = new_pass; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PASS_UNLOCK: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PASS_TEMP == Password_reg) + begin + PASS_UNLOCKED = 1'b1; + end + else + begin + PASS_UNLOCKED = 1'b0; + end + if (PASSULCK_out == 1'b1) + begin + if ((PASS_UNLOCKED == 1'b1) && (~PWDMLB)) + begin + PPBL[0] = 1'b1; + Status_reg1[0] = 1'b0; //WIP + end + else + begin + Status_reg1[6] = 1'b1; + $display ("Incorrect Password"); + PASSACC_in = 1'b1; + end + Status_reg1[1] = 1'b0; + PASSULCK_in = 1'b0; + end + end + + PPB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (PPB_LOCK !== 0) + begin + PPB_bits[sect]= 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[5] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + end + + PPB_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PPBERASE_out == 1'b1) + begin + if ((PPB_LOCK !== 0) && PPBOTP) + begin + PPB_bits = {286{1'b1}}; + end + else + begin + Status_reg1[5] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + PPBERASE_in = 1'b0; + end + end + + AUTOBOOT_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + AutoBoot_reg = AutoBoot_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PLB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + PPBL[0] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + DYB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + DYBAR = DYBAR_in; + if (DYBAR == 8'hFF) + begin + DYB_bits[sect]= 1'b1; + end + else if (DYBAR == 8'h00) + begin + DYB_bits[sect]= 1'b0; + end + else + begin + Status_reg1[6] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + ASP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + + if (RPME == 1'b0 && ASP_reg_in[5] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("RPME bit is allready programmed"); + end + else + begin + ASP_reg[5] = ASP_reg_in[5];//RPME + end + + if (PPBOTP == 1'b0 && ASP_reg_in[3] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("PPBOTP bit is allready programmed"); + end + else + begin + ASP_reg[3] = ASP_reg_in[3];//PPBOTP + end + + if (PWDMLB == 1'b1 && PSTMLB == 1'b1) + begin + if (ASP_reg_in[2] == 1'b0 && ASP_reg_in[1] == 1'b0) + begin + $display("ASPR[2:1] = 00 Illegal condition"); + Status_reg1[6] = 1'b1; //P_ERR + end + else + begin + if (ASP_reg_in[2]!==1'b1 || ASP_reg_in[1]!==1'b1) + begin + ASPOTPFLAG = 1'b1; + end + ASP_reg[2] = ASP_reg_in[2];//PWDMLB + ASP_reg[1] = ASP_reg_in[1];//PSTMLB + end + end + + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + NVDLR_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (NVDLR_reg == 0) + begin + NVDLR_reg = NVDLR_reg_in; + VDLR_reg = NVDLR_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; //P_ERR + $display("NVDLR bits allready programmed"); + end + end + end + + RESET_STATE: + begin + //the default condition hardware reset + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + if (BPNV && ~LOCK && ~FREEZE) + begin + Status_reg1[2] = 1'b1;// BP0 + Status_reg1[3] = 1'b1;// BP1 + Status_reg1[4] = 1'b1;// BP2 + BP_bits = 3'b111; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + //Resets the volatile bits in the Status register 1 + Status_reg1[6] = 1'b0; + Status_reg1[5] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[0] = 1'b0; + //Resets the volatile bits in the Status register 2 + Status_reg2[1] = 1'b0; + Status_reg2[0] = 1'b0; + //Resets the volatile bits in the Configuration register 1 + Config_reg1[0] = 1'b0; + //On reset cycles the data pattern reverts back + //to what is in the NVDLR + VDLR_reg = NVDLR_reg; + dlp_act = 1'b0; + //Loads the Program Buffer with all ones + for(i=0;i<=511;i=i+1) + begin + WData[i] = MaxData; + end + if (~PWDMLB) + PPBL[0] = 1'b0; + else + PPBL[0] = 1'b1; + end + + endcase + + //Output Disable Control + if (CSNeg_ipd ) + begin + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign ddrd = ddr; + assign fast_ddr = ddr_fast; + + always @(change_TBPARM, posedge PoweredUp) + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + BottomBoot = 1; + b_act = 1; + end + else + begin + TopBoot = 1; + BottomBoot = 0; + b_act = 0; + end + end + else if (tmp_char2 == "1") + begin + UniformSec = 1; + end + end + + always @(posedge change_BP) + begin + case (Status_reg1[4:2]) + + 3'b000: + Sec_Prot[285:0] = {286{1'b0}}; + + 3'b001: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256:(SecNum256+1)*63/64] = 1'b1; + Sec_Prot[(SecNum256+1)*63/64-1 : 0] = {63{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/64-1 : 0] = 1'b1; + Sec_Prot[SecNum256 : (SecNum256+1)/64] = {63{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64] = {34{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64-1 : 0] = {252{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/64-1 : 0] = {4{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64] = {282{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64+30] = {4{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64+29 : 0] = {282{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/64+29 : 0] = {34{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64+30] = {252{1'b0}}; + end + end + end + + 3'b010: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*31/32] = {2{1'b1}}; + Sec_Prot[(SecNum256+1)*31/32-1 : 0] = {62{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/32-1 : 0] = {2{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/32] = {62{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*31/32] = {38{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32-1 : 0] = {248{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/32-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32] = {278{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*31/32+30] = {8{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32+29 : 0] = {278{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/32+29 : 0] = {38{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32+30] = {248{1'b0}}; + end + end + end + + 3'b011: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*15/16] = 4'b1111; + Sec_Prot[(SecNum256+1)*15/16-1 : 0] = {60{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/16-1 : 0] = 4'b1111; + Sec_Prot[SecNum256 : (SecNum256+1)/16] = {60{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16] = {46{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16-1 : 0] = {240{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/16-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16] = {270{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16+30] ={16{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16+29 : 0] = {270{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/16+29 : 0] ={46{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16+30] = {240{1'b0}}; + end + end + end + + 3'b100: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*7/8] = {8{1'b1}}; + Sec_Prot[(SecNum256+1)*7/8-1 : 0] = {278{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/8-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/8] = {278{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8] = {62{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8-1 : 0] = {224{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/8-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8] = {254{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8+30] ={32{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8+29 : 0] = {254{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/8+29 : 0] = {62{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8+30] = {224{1'b0}}; + end + end + end + + 3'b101: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*3/4] = {16{1'b1}}; + Sec_Prot[(SecNum256+1)*3/4-1 : 0] = {270{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/4-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/4] = {270{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4] = {94{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4-1 : 0] = {192{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/4-1 : 0] = {64{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4] = {222{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4+30] = {64{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4+29 : 0] = {222{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/4+29 : 0] = {94{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4+30] = {192{1'b0}}; + end + end + end + + 3'b110: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {32{1'b1}}; + Sec_Prot[(SecNum256+1)/2-1 : 0] = {32{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/2-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {32{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {158{1'b1}}; + Sec_Prot[(SecNum64-29)/2-1 : 0] = {128{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/2-1 : 0] = {128{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {158{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {128{1'b1}}; + Sec_Prot[(SecNum64-29)/2+29 : 0] = {158{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/2+29 : 0] = {158{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {128{1'b0}}; + end + end + end + + 3'b111: + begin + Sec_Prot[SecNum64:0] = {286{1'b1}}; + end + endcase + end + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // autoboot control logic + //////////////////////////////////////////////////////////////////////// + always @(rising_edge_SCK_ipd or current_state_event) + begin + if(current_state == AUTOBOOT) + begin + if (rising_edge_SCK_ipd) + begin + if (start_delay > 0) + start_delay = start_delay - 1; + end + + if (start_delay == 0) + begin + start_autoboot = 1; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure FDDR_DPL + task Return_DLP; + input integer Instruct; + input integer EHP; + input integer Latency_code; + input integer dummy_cnt; + inout dlp_act; + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + if (EHP) + begin + if (Latency_code == 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b1; + else if (Latency_code == 0 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 1 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 3) + dlp_act = 1'b1; + end + end + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + if (EHP) + begin + if (Latency_code == 1 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if( Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b0; + else if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + end + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && QUAD) + begin + if (EHP) + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + end + end + endtask + + function integer ReturnSectorIDRdPswdMd; + input reg TBPROT; + begin + if(TBPROT == 0) + begin + ReturnSectorIDRdPswdMd = 0; + end + else + begin + if (UniformSec) + begin + ReturnSectorIDRdPswdMd = SecNum256; + end + else + begin + ReturnSectorIDRdPswdMd = 255; + end + end + end + endfunction + + // Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + if (Addr/(SecSize64+1) <= 1 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = Addr/(SecSize4+1); + AddrLOW = sector*(SecSize4+1); + AddrHIGH = sector*(SecSize4+1) + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + else + begin + if (Addr/(SecSize64+1) >= 254 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = 254 + (Addr-(SecSize64+1)*254)/(SecSize4+1); + AddrLOW = 254*(SecSize64+1)+(sector-254)*(SecSize4+1); + AddrHIGH = 254*(SecSize64+1)+(sector-254)*(SecSize4+1) + + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + end + else if (tmp_char2 == "1") + begin + sector = Addr/(SecSize256+1); + AddrLOW = sector*(SecSize256+1); + AddrHIGH = sector*(SecSize256+1) + SecSize256; + end + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / (PageSize + 1); + AddrLOW = page * (PageSize + 1); + AddrHIGH = page * (PageSize + 1) + PageSize ; + end + endtask + + // Procedure ReturnSectorID + task ReturnSectorID; + inout sect; + input Address; + integer sect; + integer Address; + integer conv; + begin + if (tmp_char2 == "0") + begin + conv = Address / (SecSize64+1); + if (BottomBoot) + begin + if (conv <= 1) //4KB Sectors + begin + sect = Address/(SecSize4+1); + end + else + begin + sect = conv + 30; + end + end + else if (TopBoot) + begin + if (conv >= 254) //4KB Sectors + begin + sect = 254 + (Address-(SecSize64+1)*254)/(SecSize4+1); + end + else + begin + sect = conv; + end + end + end + else + begin + sect = Address/(SecSize256+1); + end + end + endtask + + always @(PPBL[0], ASP_reg) + begin + if (PPBL[0] == 0 && PWDMLB == 0 && RPME == 0 && RdPswdProtEnable) + begin + RdPswdProtMode = 1; + AutoBoot_reg[0] = 0;//AUTOBOOT is disabled when Read Password + end //Protection is enabled + else + begin + RdPswdProtMode = 0; + end + end + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1; + #1000 falling_edge_write = 0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge RSTNeg_in) + begin + falling_edge_RSTNeg = 1'b1; + #50000 falling_edge_RSTNeg = 1'b0; + end + + always @(posedge RSTNeg_in) + begin + rising_edge_RSTNeg = 1'b1; + #10000 rising_edge_RSTNeg = 1'b0; + end + + always @(negedge RST) + begin + falling_edge_RST = 1'b1; + #10000 falling_edge_RST = 1'b0; + end + + always @(posedge RST) + begin + rising_edge_RST = 1'b1; + #1000 rising_edge_RST = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge Reseted) + begin + rising_edge_Reseted = 1'b1; + #1000 rising_edge_Reseted = 1'b0; + end + + always @(negedge PASSULCK_in) + begin + falling_edge_PASSULCK_in = 1'b1; + #1000 falling_edge_PASSULCK_in = 1'b0; + end + + always @(negedge PPBERASE_in) + begin + falling_edge_PPBERASE_in = 1'b1; + #1000 falling_edge_PPBERASE_in = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge RST_out) + begin + rising_edge_RST_out = 1'b1; + #1000 rising_edge_RST_out = 1'b0; + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.vhd b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.vhd new file mode 100644 index 0000000..2657e30 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s.vhd @@ -0,0 +1,7180 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl128s.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2012 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 V.Mancev 09 Nov 25 Inital Release +-- V1.1 V.Mancev 10 Feb 24 addr_cnt for second read in +-- high performance read continuous +-- mode can change its value only +-- when CSNeg = '0' +-- V1.2 V.Mancev 10 July 29 During the QUAD mode HOLD# input +-- is not monitored for its normal +-- function +-- V1.3 B.Colakovic 10 Aug 24 All redundant signals are removed from +-- BusCycle process +-- V1.4 R.Prokopovic 10 Oct 21 Latest datasheet aligned +-- V.Mancev +-- V1.5 R.Prokopovic 10 Oct 22 Read Configuration register added for any +-- V.Mancev state. Hybrid configuration added +-- V1.6 R.Prokopovic 10 Nov 12 QUAD Program operation during Erase +-- V.Mancev Suspend is added. Warning for Resume to +-- Suspend time is added. During Erase +-- Suspend, after Program operation is +-- completed, WEL bit is cleared. +-- Implemetation of Software Reset is +-- changed. +-- V1.7 V. Mancev 11 May 11 Condition for CS# High Time +-- (Program/Erase) is fixed +-- V1.8 V. Mancev 11 July 01 Latest datasheet aligned +-- V1.9 V. Mancev 11 Nov 16 Time tHO is changed to 1 ns +-- (customer's request) +-- BRWR instruction is corrected +-- V1.10 S.Petrovic 12 Aug 28 QPP Instruction is allowed on +-- previously programmed page +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: FLASH MEMORY +-- Part: S25FL128S +-- +-- Description: 128 Megabit Serial Flash Memory +-- +------------------------------------------------------------------------------- +-- Comments : +-- For correct simulation, simulator resolution should be set to 1 ps +-- A device ordering (trim) option determines whether a feature is enabled +-- or not, or provide relevant parameters: +-- -15th character in TimingModel determines if enhanced high +-- performance option is available +-- (0,2,3,R,A,B,C,D) EHPLC +-- (Y,Z,S,T,K,L) Security EHPLC +-- (4,6,7,8,9,Q) HPLC +-- -15th character in TimingModel determines if RESET# input +-- is available +-- (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +-- (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +-- state,inside the package. +-- -16th character in TimingModel determines Sector and Page Size: +-- (0) Sector Size = 64 kB; Page Size = 256 bytes +-- Hybrid Top/Bottom sector size architecture +-- (1) Sector Size = 256 kB; Page Size = 512 bytes +-- Uniform sector size architecture +-- +------------------------------------------------------------------------------- +-- Known Bugs: +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl128s IS + GENERIC ( + --------------------------------------------------------------------------- + -- TIMING GENERICS: + --------------------------------------------------------------------------- + -- tipd delays: interconnect path delays (delay between components) + -- There should be one for each IN or INOUT pin in the port list + -- They are given default values of zero delay. + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_SO : VitalDelayType01 := VitalZeroDelay01; + + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RSTNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays: propagation delays (pin-to-pin delay within a component) + tpd_SCK_SO_normal : VitalDelayType01Z := UnitDelay01Z; -- tV, tHO + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tDIS + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;-- + tpd_RSTNeg_SO : VitalDelayType01Z := UnitDelay01Z;-- + -- DDR operation values + tpd_SCK_SO_DDR : VitalDelayType01Z := UnitDelay01Z;--tV(66MHz) + + -- tsetup values: setup times + -- setup time is minimum time before the referent signal edge the + -- input should be stable + tsetup_CSNeg_SCK_normal_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSS / + tsetup_CSNeg_SCK_DDR_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSS / + tsetup_SI_SCK_normal_noedge_posedge: VitalDelayType + := UnitDelay; -- tSU:DAT / + tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPS \ + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; + tsetup_RSTNeg_CSNeg : VitalDelayType := UnitDelay; -- tRP + -- DDR operation values + tsetup_SI_SCK_DDR_noedge_posedge: VitalDelayType + := UnitDelay; -- tSU / + tsetup_SI_SCK_DDR_noedge_negedge: VitalDelayType + := UnitDelay; -- tSU \ + + -- thold values: hold times + -- hold time is minimum time the input should be present stable + -- after the referent signal edge + thold_CSNeg_SCK_normal_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSH / + thold_CSNeg_SCK_DDR_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSH / + thold_SI_SCK_normal_noedge_posedge: VitalDelayType + := UnitDelay; -- tHD:DAT / + thold_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPH / + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- + thold_CSNeg_RSTNeg : VitalDelayType := UnitDelay; -- tRPH + -- DDR operation values + thold_SI_SCK_DDR_noedge_posedge: VitalDelayType + := UnitDelay; -- tHD / + thold_SI_SCK_DDR_noedge_negedge: VitalDelayType + := UnitDelay; -- tHD \ + + --tpw values: pulse width + tpw_SCK_serial_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_dual_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_fast_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_quadpg_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_serial_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_dual_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_fast_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_quadpg_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_CSNeg_pgers_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_RSTNeg_negedge : VitalDelayType := UnitDelay; -- tRP + tpw_RSTNeg_posedge : VitalDelayType := UnitDelay; -- tRS + -- DDR operation values + tpw_SCK_DDR_posedge : VitalDelayType := UnitDelay; -- tWH(66MHz) + tpw_SCK_DDR_negedge : VitalDelayType := UnitDelay; -- tWL(66Hz) + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_serial_rd : VitalDelayType := UnitDelay; --fSCK=50MHz + tperiod_SCK_fast_rd : VitalDelayType := UnitDelay; --fSCK=133MHz + tperiod_SCK_dual_rd : VitalDelayType := UnitDelay; --fSCK=104MHz + tperiod_SCK_quadpg : VitalDelayType := UnitDelay; --fSCK=80MHz + -- DDR operation values + tperiod_SCK_DDR_rd : VitalDelayType := UnitDelay; --fSCK=66MHz + + -- tdevice values: values for internal delays + --timing values that are internal to the model and not associated + --with any port. + -- Page Program Operation (Page Size 256) + tdevice_PP256 : VitalDelayType := 550 us; --tPP + -- Page Program Operation (Page Size 512) + tdevice_PP512 : VitalDelayType := 750 us; --tPP + -- Typical Byte Programming Time + tdevice_BP : VitalDelayType := 400 us; --tBP + -- Sector Erase Operation(256KB Sectors) + tdevice_SE256 : VitalDelayType := 1875 ms; --tSE + -- Sector Erase Operation(64KB Sectors) + tdevice_SE64 : VitalDelayType := 650 ms; --tSE + -- Bulk Erase Operation + tdevice_BE : VitalDelayType := 165 sec; --tBE + -- WRR Cycle Time + tdevice_WRR : VitalDelayType := 200 ms; --tW + -- Erase Suspend/Erase Resume Time + tdevice_ERSSUSP : VitalDelayType := 40 us; --tESL + -- Program Suspend/Program Resume Time + tdevice_PRGSUSP : VitalDelayType := 40 us; -- + -- VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 300 us; --tPU + -- PPB Erase Time + tdevice_PPBERASE :VitalDelayType := 15 ms; -- + -- Password Unlock Time + tdevice_PASSULCK :VitalDelayType := 1 us; -- + -- Password Unlock Time + tdevice_PASSACC :VitalDelayType := 100 us; + + --------------------------------------------------------------------------- + -- CONTROL GENERICS: + --------------------------------------------------------------------------- + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING := "s25fl128s.mem"; + otp_file_name : STRING := "s25fl128sOTP.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING + ); + PORT ( + -- Data Inputs/Outputs + SI : INOUT std_ulogic := 'U'; -- serial data input/IO0 + SO : INOUT std_ulogic := 'U'; -- serial data output/IO1 + -- Controls + SCK : IN std_ulogic := 'U'; -- serial clock input + CSNeg : IN std_ulogic := 'U'; -- chip select input + RSTNeg : IN std_ulogic := 'U'; -- hardware reset pin + WPNeg : INOUT std_ulogic := 'U'; -- write protect input/IO2 + HOLDNeg : INOUT std_ulogic := 'U' -- hold input/IO3 + + ); + + ATTRIBUTE VITAL_LEVEL0 of s25fl128s : ENTITY IS TRUE; +END s25fl128s; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of s25fl128s IS + ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; + + --------------------------------------------------------------------------- + -- CONSTANT AND SIGNAL DECLARATION + --------------------------------------------------------------------------- + --Declaration of constants - memory characteristics + -- The constant declared here are used to enable the creation of models + -- of memories within a family with a minimum amount of editing + + CONSTANT PartID : STRING := "s25fl128s"; + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT MemSize : NATURAL := 16#FFFFFF#; + CONSTANT SecSize256 : NATURAL := 16#3FFFF#; --256KB + CONSTANT SecSize64 : NATURAL := 16#FFFF#; --64KB + CONSTANT SecSize4 : NATURAL := 16#FFF#; --4KB + CONSTANT SecNum64 : NATURAL := 285; + CONSTANT SecNum256 : NATURAL := 63; + CONSTANT PageNum64 : NATURAL := 16#1FFFF#; + CONSTANT PageNum256 : NATURAL := 16#7FFF#; + CONSTANT AddrRANGE : NATURAL := 16#0FFFFFF#; + CONSTANT HiAddrBit : NATURAL := 31; + CONSTANT OTPSize : NATURAL := 1023; + CONSTANT OTPLoAddr : NATURAL := 16#000#; + CONSTANT OTPHiAddr : NATURAL := 16#3FF#; + CONSTANT BYTE : NATURAL := 8; + + --Manufacturer Identification + CONSTANT Manuf_ID : NATURAL := 16#01#; + CONSTANT DeviceID : NATURAL := 16#17#; + --Electronic Signature + CONSTANT ESignature : NATURAL := 16#17#; + --Device ID + --Manufacturer Identification && Memory Type && Memory Capacity + CONSTANT Jedec_ID : NATURAL := 16#01#; -- first byte of Device ID + CONSTANT DeviceID1 : NATURAL := 16#20#; + CONSTANT DeviceID2 : NATURAL := 16#18#; + CONSTANT ExtendedBytes : NATURAL := 16#4D#; + CONSTANT ExtendedID64 : NATURAL := 16#01#; + CONSTANT ExtendedID256 : NATURAL := 16#00#; + CONSTANT DieRev : NATURAL := 16#03#; + CONSTANT MaskRev : NATURAL := 16#00#; + + -- Declaration of signals that will hold the delayed values of ports + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL RSTNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + SIGNAL RSTNeg_pullup : std_ulogic := 'U'; + + -- internal delays + SIGNAL PP256_in : std_ulogic := '0'; + SIGNAL PP256_out : std_ulogic := '0'; + SIGNAL PP512_in : std_ulogic := '0'; + SIGNAL PP512_out : std_ulogic := '0'; + SIGNAL BP_in : std_ulogic := '0'; + SIGNAL BP_out : std_ulogic := '0'; + SIGNAL SE64_in : std_ulogic := '0'; + SIGNAL SE64_out : std_ulogic := '0'; + SIGNAL SE256_in : std_ulogic := '0'; + SIGNAL SE256_out : std_ulogic := '0'; + SIGNAL BE_in : std_ulogic := '0'; + SIGNAL BE_out : std_ulogic := '0'; + SIGNAL WRR_in : std_ulogic := '0'; + SIGNAL WRR_out : std_ulogic := '0'; + SIGNAL ERSSUSP_in : std_ulogic := '0'; + SIGNAL ERSSUSP_out : std_ulogic := '0'; + SIGNAL PRGSUSP_in : std_ulogic := '0'; + SIGNAL PRGSUSP_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL RST_in : std_ulogic := '0';-- Hardware Reset Timeout + SIGNAL RST_out : std_ulogic := '1';-- + SIGNAL PPBERASE_in : std_ulogic := '0'; + SIGNAL PPBERASE_out : std_ulogic := '0'; + SIGNAL PASSULCK_in : std_ulogic := '0'; + SIGNAL PASSULCK_out : std_ulogic := '0'; + SIGNAL PASSACC_in : std_ulogic := '0'; + SIGNAL PASSACC_out : std_ulogic := '0'; + + FUNCTION ReturnSectorIDRdPswdMd(TBPROT : std_logic) RETURN NATURAL IS + VARIABLE result : NATURAL; + BEGIN + IF TBPROT = '0' THEN + result := 0; + ELSE + IF (TimingModel(16) = '1') THEN + result := SecNum256; + ELSE + result := 255; + END IF; + END IF; + RETURN result; + END ReturnSectorIDRdPswdMd; + +BEGIN + + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + -- Because a tdevice generics is used, there must be a VITAL_primitives + -- assotiated with them + PP256 :VitalBuf(PP256_out, PP256_in, (tdevice_PP256 ,UnitDelay)); + PP512 :VitalBuf(PP512_out, PP512_in, (tdevice_PP512 ,UnitDelay)); + BP :VitalBuf(BP_out, BP_in, (tdevice_BP ,UnitDelay)); + SE64 :VitalBuf(SE64_out, SE64_in, (tdevice_SE64 ,UnitDelay)); + SE256 :VitalBuf(SE256_out, SE256_in, (tdevice_SE256 ,UnitDelay)); + BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); + WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay)); + ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay)); + PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + PPBERASE :VitalBuf(PPBERASE_out,PPBERASE_in,(tdevice_PPBERASE,UnitDelay)); + PASSULCK :VitalBuf(PASSULCK_out,PASSULCK_in,(tdevice_PASSULCK,UnitDelay)); + PASSACC :VitalBuf(PASSACC_out, PASSACC_in, (tdevice_PASSACC ,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO); + w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_5 : VitalWireDelay (RSTNeg_ipd, RSTNeg, tipd_RSTNeg); + w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + SCK : IN std_ulogic := 'U'; + CSNeg : IN std_ulogic := 'U'; + RSTNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + + PORT MAP ( + SIIn => SI_ipd, + SIOut => SI, + SOIn => SO_ipd, + SOut => SO, + SCK => SCK_ipd, + CSNeg => CSNeg_ipd, + RSTNeg => RSTNeg_ipd, + HOLDNegIn => HOLDNeg_ipd, + HOLDNegOut => HOLDNeg, + WPNegIn => WPNeg_ipd, + WPNegOut => WPNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + RESET_STATE, + AUTOBOOT, + WRITE_SR, + PAGE_PG, + OTP_PG, + PG_SUSP, + SECTOR_ERS, + BULK_ERS, + ERS_SUSP, + ERS_SUSP_PG, + ERS_SUSP_PG_SUSP, + PASS_PG, + PASS_UNLOCK, + PPB_PG, + PPB_ERS, + AUTOBOOT_PG, + ASP_PG, + PLB_PG, + DYB_PG, + NVDLR_PG + ); + + -- Instruction Type + TYPE instruction_type IS ( NONE, + WREN, -- Write Enable + WRDI, -- Write Disable + WRR, -- Write Register + READ, -- Read Normal (3Byte Address) + RD4, -- Read Normal (4Byte +) + OTPR, -- OTP Read + RDSR, -- Read Status Register 1 + RDSR2, -- Read Status Register 2 + RDCR, -- Read Configuration Register 1 + REMS, -- Read ID (SST) + RDID, -- Read ID JEDEC + RES, -- Read ID + FSTRD, -- Fast Read (3Byte Address) + FSTRD4, -- Fast Read (4Byte +) + DDRFR, -- Fast Read DDR (3Byte Address) + DDRFR4, -- Fast Read DDR (4Byte +) + DOR, -- Read Dual Out (3Byte Address) + DOR4, -- Read Dual Out (4Byte +) + DIOR, -- Read Dual I/O (3Byte Address) + DIOR4, -- Read Dual I/O (4Byte +) + DDRDIOR, -- Read DDR Dual I/O (3Byte) + DDRDIOR4, -- Read DDR Dual I/O (4Byte +) + QOR, -- Read Quad Out (3Byte Address) + QOR4, -- Read Quad Out (4Byte +) + QIOR, -- Read Quad I/O (3Byte Address) + QIOR4, -- Read Quad I/O (4Byte +) + DDRQIOR, -- Read DDR Quad I/O (3Byte) + DDRQIOR4, -- Read DDR Quad I/O (4Byte +) + PP, -- Program Page (3Byte Address) + PP4, -- Program Page (4Byte +) + QPP, -- Quad Page Program (3Byte) + QPP4, -- Quad Page Program (4Byte +) + OTPP, -- OTP Program + PGSP, -- Program Suspend + PGRS, -- Program Resume + BE, -- Bulk Erase + SE, -- Erase 128/256KB (3Byte) + SE4, -- Erase 128/256KB (4Byte +) + P4E, -- 4KB-sector Erase (3Byte Addr) + P4E4, -- 4KB-sector Erase (4Byte Addr) + ERSP, -- Erase Suspend + ERRS, -- Erase Resume + ABRD, -- AutoBoot Register Read + ABWR, -- AutoBoot Register Write + BRRD, -- Bank Register Read + BRWR, -- Bank Register Write + BRAC, -- Bank Register Access + DLPRD, -- Read Data Learning Pattern + PNVDLR, -- Program NVDLP Reg + WVDLR, -- Write Volatile DLP Reg + ASPRD, -- ASP Read + ASPP, -- ASP Program + DYBRD, -- DYB Read + DYBWR, -- DYB Write + PPBRD, -- PPB Read + PPBP, -- PPB Program + PPBERS, -- PPB Erase + PLBWR, -- PPB Lock Bit Write + PLBRD, -- PPB Lock Bit Read + PASSRD, -- Password Read + PASSP, -- Password Program + PASSU, -- Password Unlock + RESET, -- Reset + MBR, -- Mode Bit Reset + MPM, -- Multi-I/O-High Perf Mode + CLSR -- Clear Status Register + ); + + TYPE WByteType IS ARRAY (0 TO 511) OF INTEGER RANGE -1 TO MaxData; + -- Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; + -- OTP Memory Array + TYPE OTPArray IS ARRAY (OTPLoAddr TO OTPHiAddr) OF INTEGER + RANGE -1 TO MaxData; + --CFI Array (Common Flash Interface Query codes) + TYPE CFItype IS ARRAY (16#00# TO 16#55#) OF + INTEGER RANGE -1 TO 16#FF#; + ----------------------------------------------------------------------- + -- memory declaration + ----------------------------------------------------------------------- + -- Memory + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + -- OTP Sector + SHARED VARIABLE OTPMem : OTPArray := (OTHERS => MaxData); + --CFI Array + SHARED VARIABLE CFI_array : CFItype := (OTHERS => 0); + -- Programming Buffer + SIGNAL WByte : WByteType := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + ----------------------------------------------------------------------- + -- Registers + ----------------------------------------------------------------------- + -- *** Status Register 1 *** + SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Disable Bit + ALIAS SRWD :std_logic IS Status_reg1(7); + -- Status Register Programming Error Bit + ALIAS P_ERR :std_logic IS Status_reg1(6); + -- Status Register Erase Error Bit + ALIAS E_ERR :std_logic IS Status_reg1(5); + -- Status Register Block Protection Bits + ALIAS BP2 :std_logic IS Status_reg1(4); + ALIAS BP1 :std_logic IS Status_reg1(3); + ALIAS BP0 :std_logic IS Status_reg1(2); + -- Status Register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg1(1); + -- Status Register Write In Progress Bit + ALIAS WIP :std_logic IS Status_reg1(0); + + -- *** Status Register 2 *** + SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg2_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Enable Latch Bit + ALIAS ES :std_logic IS Status_reg2(1); + -- Status Register Write In Progress Bit + ALIAS PS :std_logic IS Status_reg2(0); + + -- *** Configuration Register 1 *** + SHARED VARIABLE Config_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Config_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Latency code + ALIAS LC1 :std_logic IS Config_reg1(7); + ALIAS LC0 :std_logic IS Config_reg1(6); + -- Configuration Register TBPROT bit + ALIAS TBPROT :std_logic IS Config_reg1(5); + -- Configuration Register LOCK bit + ALIAS LOCK :std_logic IS Config_reg1(4); + -- Configuration Register BPNV bit + ALIAS BPNV :std_logic IS Config_reg1(3); + -- Configuration Register TBPARM bit + ALIAS TBPARM :std_logic IS Config_reg1(2); + -- Configuration Register QUAD bit + ALIAS QUAD :std_logic IS Config_reg1(1); + -- Configuration Register FREEZE bit + ALIAS FREEZE :std_logic IS Config_reg1(0); + + -- *** VDLR Register *** + SHARED VARIABLE VDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL VDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** NVDLR Register *** + SHARED VARIABLE NVDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL NVDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** AutoBoot Register *** + SHARED VARIABLE AutoBoot_reg : std_logic_vector(31 downto 0) + := (others => '0'); + SIGNAL AutoBoot_reg_in : std_logic_vector(31 downto 0) + := (others => '0'); + --AutoBoot Enable Bit + ALIAS ABE :std_logic IS AutoBoot_reg(0); + + -- *** Bank Address Register *** + SHARED VARIABLE Bank_Addr_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Bank_Addr_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Bank Address Register EXTADD bit + ALIAS EXTADD :std_logic IS Bank_Addr_reg(7); + + -- *** ASP Register *** + SHARED VARIABLE ASP_reg : std_logic_vector(15 downto 0); + SIGNAL ASP_reg_in : std_logic_vector(15 downto 0) + := (others => '1'); + --Read Password Mode Enable Bit + ALIAS RPME :std_logic IS ASP_reg(5); + --PPB OTP Bit + ALIAS PPBOTP :std_logic IS ASP_reg(3); + -- Password Protection Mode Lock Bit + ALIAS PWDMLB :std_logic IS ASP_reg(2); + --Persistent Protection Mode Lock Bit + ALIAS PSTMLB :std_logic IS ASP_reg(1); + + -- *** Password Register *** + SHARED VARIABLE Password_reg : std_logic_vector(63 downto 0) + := (others => '1'); + SIGNAL Password_reg_in : std_logic_vector(63 downto 0) + := (others => '1'); + -- *** PPB Lock Register *** + SHARED VARIABLE PPBL : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL PPBL_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Persistent Protection Mode Lock Bit + ALIAS PPB_LOCK : std_logic IS PPBL(0); + SIGNAL PPB_LOCK_temp : std_ulogic := '0'; + + -- *** PPB Access Register *** + SHARED VARIABLE PPBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL PPBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- PPB_bits(Sec) + SHARED VARIABLE PPB_bits : std_logic_vector(SecNum64 downto 0) + := (OTHERS => '1'); + -- *** DYB Access Register *** + SHARED VARIABLE DYBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL DYBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- DYB(Sec) + SHARED VARIABLE DYB_bits : std_logic_vector(SecNum64 downto 0); + + -- The Lock Protection Registers for OTP Memory space + SHARED VARIABLE LOCK_BYTE1 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE2 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE3 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE4 :std_logic_vector(7 downto 0); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL cfg_write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL rd : boolean := false; + SIGNAL dual : boolean := false; + SIGNAL fast_rd : boolean := true; + SIGNAL ddr : boolean := false; + SIGNAL any_read : boolean := false; + + SIGNAL quadpg : boolean := false; + + SIGNAL oe : boolean := false; + SIGNAL oe_z : boolean := false; + + SHARED VARIABLE hold_mode : boolean := false; + + -- Memory Array Configuration + SIGNAL BottomBoot : boolean := false; + SIGNAL TopBoot : boolean := false; + SIGNAL UniformSec : boolean := false; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; --Page Prog. Done + SIGNAL PSTART : std_logic := '0'; --Start Page Programming + SIGNAL PGSUSP : std_logic := '0'; --Suspend Program + SIGNAL PGRES : std_logic := '0'; --Resume Program + + SIGNAL RES_TO_SUSP_MIN_TIME : std_logic := '0';--Resume to Suspend Flag + SIGNAL RES_TO_SUSP_TYP_TIME : std_logic := '0';--Resume to Suspend Flag + + SIGNAL WDONE : std_logic := '1'; --Write operation Done + SIGNAL WSTART : std_logic := '0'; --Start Write operation + + SIGNAL ESTART : std_logic := '0'; --Start Erase operation + SIGNAL EDONE : std_logic := '1'; --Erase operation Done + SIGNAL ESUSP : std_logic := '0'; --Suspend Erase + SIGNAL ERES : std_logic := '0'; --Resume Erase + + SIGNAL ERS_SUSP_PG_SUSP_ACT: std_logic := '0'; --During Erase Suspend + --Program Suspend + --is Active + + --reset timing + SIGNAL RST : std_logic := '0'; + SIGNAL Reseted : std_logic := '0'; --Reset Timing Control + --Lock Bit is enabled for customer programming + SIGNAL WRLOCKENABLE : BOOLEAN := TRUE; + --Flag that mark if ASP Register is allready programmed + SIGNAL ASPOTPFLAG : BOOLEAN := FALSE; + SIGNAL ASP_INIT : NATURAL RANGE 0 TO 1; + SIGNAL INITIAL_CONFIG : std_logic := '0'; + + SHARED VARIABLE PageSize : NATURAL := 0 ; + SHARED VARIABLE PageNum : NATURAL := 0 ; + SHARED VARIABLE SecNum : NATURAL := 0 ; + SHARED VARIABLE SecNumMax : NATURAL := 0 ; + SHARED VARIABLE SecSize : NATURAL := 0 ; + SHARED VARIABLE b_act : NATURAL := 0 ; + + SHARED VARIABLE ASP_ProtSE : NATURAL := 0; + SHARED VARIABLE Sec_ProtSE : NATURAL := 0; + + SHARED VARIABLE SecAddr : NATURAL RANGE 0 TO SecNum64:= 0; + + SHARED VARIABLE Sec_addr : NATURAL := 0; + + SHARED VARIABLE Page_addr : NATURAL; + SHARED VARIABLE pgm_page : NATURAL; + + --Flag for Password unlock command + SIGNAL PASS_UNLOCKED : boolean := FALSE; + SIGNAL PASS_TEMP : std_logic_vector(63 downto 0) + := (others => '1'); + + SHARED VARIABLE DOUBLE : BOOLEAN := FALSE; + SHARED VARIABLE EHP : BOOLEAN := FALSE; + + SHARED VARIABLE read_cnt : NATURAL := 0; + SHARED VARIABLE byte_cnt : NATURAL := 1; + SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ; + SHARED VARIABLE read_addr_tmp : NATURAL RANGE 0 TO AddrRANGE ; + + SHARED VARIABLE start_delay : NATURAL RANGE 0 TO 7; + SHARED VARIABLE ABSD : NATURAL RANGE 0 TO 7; + SIGNAL start_autoboot : std_logic := '0'; + + SIGNAL change_addr : std_logic := '0'; + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + SIGNAL SectorSuspend : NATURAL RANGE 0 TO SecNum64 := 0; + + -- Sector address + SIGNAL SA : NATURAL RANGE 0 TO SecNum64 := 0; + + -- Sector is protect if Sec_Prot(SecNum) = '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum64 downto 0) := + (OTHERS => '0'); + + SIGNAL change_TBPARM : std_logic := '0'; + + SIGNAL change_BP : std_logic := '0'; + SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000"; + + SHARED VARIABLE CFI_array_tmp : std_logic_vector(647 downto 0); + + SIGNAL Byte_number : NATURAL RANGE 0 TO 511 := 0; + + TYPE bus_cycle_type IS (STAND_BY, + OPCODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + SHARED VARIABLE bus_cycle_state : bus_cycle_type; + -- switch between Data bytes and Dummy bytes + SHARED VARIABLE DummyBytes_act : X01 := '0'; + SIGNAL dummy_cnt_act_temp : NATURAL := 0; + SIGNAL dummy_cnt_act : NATURAL := 0; + --Read Password Protection Mode Active flag + SIGNAL RdPswdProtMode : std_ulogic := '0'; + --Read Password Protection Mode Support flag + SIGNAL RdPswdProtEnable : std_ulogic := '0'; + SIGNAL BAR_ACC : std_ulogic := '0'; + + SHARED VARIABLE Latency_code : NATURAL RANGE 0 TO 7; + SHARED VARIABLE opcode_cnt : NATURAL := 0; + SHARED VARIABLE addr_cnt : NATURAL := 0; + SHARED VARIABLE mode_cnt : NATURAL := 0; + SHARED VARIABLE dummy_cnt : NATURAL := 0; + SHARED VARIABLE data_cnt : NATURAL := 0; + + SHARED VARIABLE PARAM_REGION : BOOLEAN := FALSE; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO 285; + BEGIN + + IF (TimingModel(16) = '0') THEN + IF TBPARM = '0' THEN + IF Addr/(SecSize64+1) <= 1 AND + (Instruct = P4E OR Instruct = P4E4) THEN --4KB Sectors + sector := Addr/(SecSize4+1); + AddrLOW := sector*(SecSize4+1); + AddrHIGH := sector*(SecSize4+1) + SecSize4; + ELSE + sector := Addr/(SecSize64+1); + AddrLOW := sector*(SecSize64+1); + AddrHIGH := sector*(SecSize64+1) + SecSize64; + END IF; + ELSE + IF Addr/(SecSize64+1) >= 254 AND + (Instruct = P4E OR Instruct = P4E4) THEN --4KB Sectors + sector := 254 + (Addr-(SecSize64+1)*254)/(SecSize4+1); + AddrLOW := 254*(SecSize64+1)+(sector-254)*(SecSize4+1); + AddrHIGH := 254*(SecSize64+1)+(sector-254)*(SecSize4+1) + + SecSize4; + ELSE + sector := Addr/(SecSize64+1); + AddrLOW := sector*(SecSize64+1); + AddrHIGH := sector*(SecSize64+1) + SecSize64; + END IF; + END IF; + ELSE + sector := Addr/(SecSize256+1); + AddrLOW := sector*(SecSize256+1); + AddrHIGH := sector*(SecSize256+1) + SecSize256; + END IF; + END ADDRHILO_SEC; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + BEGIN + page := Addr/PageSize; + AddrLOW := Page*PageSize; + AddrHIGH := Page*PageSize + (PageSize-1); + END AddrHILO_PG; + + PROCEDURE ReturnSectorID( + VARIABLE result : INOUT NATURAL; + SIGNAL ADDR : NATURAL RANGE 0 TO AddrRANGE) IS + VARIABLE conv : NATURAL; + BEGIN + IF (TimingModel(16) = '0') THEN + conv := ADDR / (SecSize64+1); + IF BottomBoot = TRUE THEN + IF conv <= 1 THEN --4KB Sectors + result := ADDR/(SecSize4+1); + ELSE + result := conv + 30; + END IF; + ELSIF TopBoot = TRUE THEN + IF conv >= 254 THEN --4KB Sectors + result := 254 + (ADDR-(SecSize64+1)*254)/(SecSize4+1); + ELSE + result := conv; + END IF; + END IF; + ELSE + result := ADDR/(SecSize256+1); + END IF; + END ReturnSectorID; + + BEGIN + --------------------------------------------------------------------------- + --Power Up time + --------------------------------------------------------------------------- + + PoweredUp <= '1' AFTER tdevice_PU; + + --------------------------------------------------------------------------- + --sector structure + --------------------------------------------------------------------------- + UniformSec <= TRUE WHEN (TimingModel(16) = '1') + ELSE FALSE; + TimingModelSel: PROCESS + BEGIN + IF TimingModel(16) = '1' THEN + -- Sector Number/Sector Size + SecNumMax:= SecNum256; + SecNum := SecNum256; + SecSize := SecSize256; + -- 256B/512B Page Size + PageSize := 512; + PageNum := 16#FFFF#; + ELSE + -- Sector Number/Sector Size + SecNumMax:= SecNum64; + SecNum := 255; + SecSize := SecSize64; + -- 256B/512B Page Size + PageSize := 256; + PageNum := 16#1FFFF#; + END IF; + --Enhanced High Performance Flag + IF (TimingModel(15) = '0' OR TimingModel(15) = '2' OR + TimingModel(15) = '3' OR TimingModel(15) = 'R' OR + TimingModel(15) = 'A' OR TimingModel(15) = 'B' OR + TimingModel(15) = 'C' OR TimingModel(15) = 'D' OR + TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + EHP := TRUE; + IF (TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + RdPswdProtEnable <= '1'; + END IF; + ELSIF (TimingModel(15) = '4' OR TimingModel(15) = '6' OR + TimingModel(15) = '7' OR TimingModel(15) = '8' OR + TimingModel(15) = '9' OR TimingModel(15) = 'Q') THEN + EHP := FALSE; + END IF; + + IF (TimingModel(15) ='0' OR TimingModel(15) ='2' OR + TimingModel(15) ='3' OR TimingModel(15) ='R' OR + TimingModel(15) ='A' OR TimingModel(15) ='B' OR + TimingModel(15) ='C' OR TimingModel(15) ='D' OR + TimingModel(15) ='4' OR TimingModel(15) ='6' OR + TimingModel(15) ='7' OR TimingModel(15) ='8' OR + TimingModel(15) ='9' OR TimingModel(15) ='Q') THEN + ASP_INIT <= 1; + ELSIF (TimingModel(15) ='Y' OR TimingModel(15) ='Z' OR + TimingModel(15) ='S' OR TimingModel(15) ='T' OR + TimingModel(15) ='K' OR TimingModel(15) ='L') THEN + ASP_INIT <= 0; + END IF; + WAIT; + END PROCESS; + + RSTtiming: PROCESS(RSTNeg_pullup,Instruct) + BEGIN + IF falling_edge(RSTNeg_pullup) THEN + RST <= '1', '0' AFTER 200 ns; + ELSIF Instruct = RESET THEN + Reseted <= '0', '1' AFTER 10 ns; + END IF; + END PROCESS; + + DUMMYcnt: PROCESS(dummy_cnt_act_temp) + BEGIN + dummy_cnt_act <= dummy_cnt_act_temp; + END PROCESS; + + ReadPasswordProtectionMode: PROCESS(PPB_LOCK_temp, + ASP_reg_in(2), ASP_reg_in(5)) + BEGIN + IF (PPB_LOCK = '0' AND PWDMLB = '0' AND RPME = '0' AND + RdPswdProtEnable = '1') THEN + RdPswdProtMode <= '1'; + ABE := '0'; + ELSE + RdPswdProtMode <= '0'; + END IF; + END PROCESS; + --------------------------------------------------------------------------- + -- autoboot control logic + --------------------------------------------------------------------------- + AutoBootControl: PROCESS(SCK_ipd, current_state) + BEGIN + IF (current_state = AUTOBOOT) THEN + IF rising_edge(SCK_ipd) THEN + IF (start_delay > 0) THEN + start_delay := start_delay - 1; + END IF; + END IF; + + IF (start_delay = 0) THEN + start_autoboot <= '1'; + ELSE + start_autoboot <= '0'; + END IF; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn, SOIn, SCK_ipd, CSNeg_ipd, RSTNeg_ipd, + HOLDNegIn, WPNegIn) + + -- Timing Check Variables + -- Setup/Hold Checks variables + VARIABLE Tviol_CSNeg_SCK_normal : X01 := '0'; + VARIABLE TD_CSNeg_SCK_normal : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_SCK_DDR : X01 := '0'; + VARIABLE TD_CSNeg_SCK_DDR : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_RSTNeg : X01 := '0'; + VARIABLE TD_CSNeg_RSTNeg : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType; + + VARIABLE Tviol_HOLDNeg_SCK : X01 := '0'; + VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_R : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_R : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_F : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_F : VitalTimingDataType; + + VARIABLE Tviol_RSTNeg_CSNeg : X01 := '0'; + VARIABLE TD_RSTNeg_CSNeg : VitalTimingDataType; + + --Pulse Width and Period Check Variables + VARIABLE Pviol_SCK_serial : X01 := '0'; + VARIABLE PD_SCK_serial : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual : X01 := '0'; + VARIABLE PD_SCK_dual : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast : X01 := '0'; + VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quadpg : X01 := '0'; + VARIABLE PD_SCK_quadpg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR : X01 := '0'; + VARIABLE PD_SCK_DDR : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_read : X01 := '0'; + VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_pgers : X01 := '0'; + VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_RSTNeg : X01 := '0'; + VARIABLE PD_RSTNeg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_rd : X01 := '0'; + VARIABLE PD_SCK_serial_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_rd : X01 := '0'; + VARIABLE PD_SCK_fast_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual_rd : X01 := '0'; + VARIABLE PD_SCK_dual_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR_rd : X01 := '0'; + VARIABLE PD_SCK_DDR_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quad_pg : X01 := '0'; + VARIABLE PD_SCK_quad_pg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_normal_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_normal_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_normal_noedge_posedge, + HoldLow => thold_CSNeg_SCK_normal_noedge_posedge, + CheckEnabled => ddr = false, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_normal, + Violation => Tviol_CSNeg_SCK_normal + ); + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_DDR_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_DDR_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_DDR_noedge_posedge, + HoldLow => thold_CSNeg_SCK_DDR_noedge_posedge, + CheckEnabled => ddr, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_DDR, + Violation => Tviol_CSNeg_SCK_DDR + ); + + -- Hold Check between CSNeg and RSTNeg + VitalSetupHoldCheck ( + TestSignal => CSNeg, + TestSignalName => "CSNeg", + RefSignal => RSTNeg, + RefSignalName => "RSTNeg", + HoldHigh => thold_CSNeg_RSTNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_RSTNeg, + Violation => Tviol_CSNeg_RSTNeg + ); + + -- Setup/Hold Check between SI and SCK, serial mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => NOT(DOUBLE) AND SIOut_z /= SIIn , + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => true, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_setup, + Violation => Tviol_WPNeg_CSNeg_setup + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => SRWD = '1' AND WEL = '1', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_hold, + Violation => Tviol_WPNeg_CSNeg_hold + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupLow => tsetup_HOLDNeg_SCK, + SetupHigh => tsetup_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + CheckEnabled => QUAD = '0' + AND HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNeg_SCK, + Violation => Tviol_HOLDNeg_SCK + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_posedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_posedge, + HoldHigh => thold_SI_SCK_DDR_noedge_posedge, + HoldLow => thold_SI_SCK_DDR_noedge_posedge, + CheckEnabled => DOUBLE AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_R, + Violation => Tviol_SI_SCK_DDR_R + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_negedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_negedge, + HoldHigh => thold_SI_SCK_DDR_noedge_negedge, + HoldLow => thold_SI_SCK_DDR_noedge_negedge, + CheckEnabled => ddr AND dual = false + AND SIOut_z /= SIIn , + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_F, + Violation => Tviol_SI_SCK_DDR_F + ); + + -- Setup Check between RSTNeg and SCK, DDR fast mode + VitalSetupHoldCheck ( + TestSignal => RSTNeg, + TestSignalName => "RSTNeg", + RefSignal => CSNeg, + RefSignalName => "CSNeg", + SetupHigh => tsetup_RSTNeg_CSNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_RSTNeg_CSNeg, + Violation => Tviol_RSTNeg_CSNeg + ); + + --Pulse Width and Period Check Variables + -- Pulse Width Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_serial_negedge, + PulseWidthHigh => tpw_SCK_serial_posedge, + PeriodData => PD_SCK_serial, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd); + + -- Pulse Width Check SCK for DUAL_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_dual_negedge, + PulseWidthHigh => tpw_SCK_dual_posedge, + PeriodData => PD_SCK_dual, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual); + + -- Pulse Width Check SCK for FAST_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_fast_negedge, + PulseWidthHigh => tpw_SCK_fast_posedge, + PeriodData => PD_SCK_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Pulse Width Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_quadpg_negedge, + PulseWidthHigh => tpw_SCK_quadpg_posedge, + PeriodData => PD_SCK_quadpg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quadpg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg); + + -- Pulse Width Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CSNeg_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => any_read ); + + -- Pulse Width Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pgers_posedge, + PeriodData => PD_CSNeg_pgers, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_pgers, + HeaderMsg => InstancePath & PartID, + CheckEnabled => NOT(any_read)); + + -- Pulse Width Check RSTNeg + VitalPeriodPulseCheck ( + TestSignal => RSTNeg_ipd, + TestSignalName => "RSTNeg", + PulseWidthLow => tpw_RSTNeg_negedge, + PulseWidthHigh => tpw_RSTNeg_posedge, + CheckEnabled => TRUE, + HeaderMsg => InstancePath & PartID, + PeriodData => PD_RSTNeg, + Violation => Pviol_RSTNeg + ); + + -- Pulse Width Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_DDR_negedge, + PulseWidthHigh => tpw_SCK_DDR_posedge, + PeriodData => PD_SCK_DDR, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_rd, + PeriodData => PD_SCK_serial_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for FAST READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast_rd, + PeriodData => PD_SCK_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Period Check SCK for DUAL READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_dual_rd, + PeriodData => PD_SCK_dual_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual ); + + -- Period Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_quadpg, + PeriodData => PD_SCK_quad_pg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quad_pg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg ); + + -- Period Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_DDR_rd, + PeriodData => PD_SCK_DDR_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr ); + + Violation := Tviol_CSNeg_SCK_normal OR + Tviol_CSNeg_SCK_DDR OR + Tviol_CSNeg_RSTNeg OR + Tviol_SI_SCK OR + Tviol_WPNeg_CSNeg_setup OR + Tviol_WPNeg_CSNeg_hold OR + Tviol_HOLDNeg_SCK OR + Tviol_SI_SCK_DDR_R OR + Tviol_SI_SCK_DDR_F OR + Tviol_RSTNeg_CSNeg OR + Pviol_SCK_serial OR + Pviol_SCK_dual OR + Pviol_SCK_fast OR + Pviol_SCK_quadpg OR + Pviol_CSNeg_read OR + Pviol_CSNeg_pgers OR + Pviol_SCK_DDR OR + Pviol_SCK_serial_rd OR + Pviol_SCK_fast_rd OR + Pviol_SCK_dual_rd OR + Pviol_SCK_quad_pg OR + Pviol_SCK_DDR_rd; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + + ---------------------------------------------------------------------------- + -- sequential process for FSM state transition + ---------------------------------------------------------------------------- + StateTransition : PROCESS(next_state, RST, PoweredUp, RST_out) + + BEGIN + IF PoweredUp = '1' THEN + IF RSTNeg_pullup = '1' and RST_out= '1' THEN + IF next_state'EVENT THEN + current_state <= next_state; + END IF; + ELSIF RSTNeg_pullup = '0' AND falling_edge(RST) THEN + --no state transition while RESET# low + current_state <= RESET_STATE; + RST_in <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END PROCESS StateTransition; + + Threset : PROCESS(RST_in) + BEGIN + IF rising_edge(RST_in) THEN + RST_out <= '0', '1' AFTER (thold_CSNeg_RSTNeg-200 ns); + END IF; + END PROCESS Threset; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_pullup, SIIn, RST_out, + WPNeg_pullup) + + TYPE quad_data_type IS ARRAY (0 TO 1023) OF INTEGER RANGE 0 TO 15; + + VARIABLE bit_cnt : NATURAL := 0; + VARIABLE Data_in : std_logic_vector(4095 downto 0) + := (others => '0'); + + VARIABLE opcode : std_logic_vector(7 downto 0); + VARIABLE opcode_in : std_logic_vector(7 downto 0); + VARIABLE addr_bytes : std_logic_vector(31 downto 0); + VARIABLE hiaddr_bytes : std_logic_vector(31 downto 0); + VARIABLE Address_in : std_logic_vector(31 downto 0); + VARIABLE mode_bytes : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + + VARIABLE CLK_PER : time; + VARIABLE LAST_CLK : time; + VARIABLE Check_freq : boolean := FALSE; + + BEGIN + + IF rising_edge(CSNeg_ipd) AND NOT(bus_cycle_state = DATA_BYTES) + AND NOT(bus_cycle_state = DUMMY_BYTES) THEN + bus_cycle_state := STAND_BY; + ELSE + CASE bus_cycle_state IS + WHEN STAND_BY => + IF falling_edge(CSNeg_ipd) THEN + Instruct <= NONE; + write <= '1'; + cfg_write <= '0'; + opcode_cnt:= 0; + addr_cnt := 0; + mode_cnt := 0; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + data_cnt := 0; + DOUBLE := FALSE; + CLK_PER := 0 ns; + LAST_CLK := 0 ns; + IF current_state = AUTOBOOT THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := OPCODE_BYTE; + END IF; + END IF; + + WHEN OPCODE_BYTE => + IF rising_edge(SCK_ipd) THEN + + Latency_code := to_nat(LC1 & LC0); + CLK_PER := NOW - LAST_CLK; + LAST_CLK := NOW; + IF Check_freq THEN + IF (CLK_PER < 20 ns AND Latency_code = 3) OR + (CLK_PER < 12.5 ns AND Latency_code = 0) OR + (CLK_PER < 11.1 ns AND Latency_code = 1) OR + (CLK_PER < 9.6 ns AND Latency_code = 2) THEN + ASSERT FALSE + REPORT "More wait states are required for " & + "this clock frequency value" + SEVERITY warning; + END IF; + END IF; + Check_freq := FALSE; + + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + --One-byte of instruction opcode is shifted into the + --device on the SI serial input pin with the most + --significant bit (MSB) first.Each bit input on the + --SI serial input pin is latched on the rising edge of + --the SCK serial clock signal. + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF opcode_cnt = BYTE THEN + --MSB first + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := opcode_in(7-i); + END LOOP; + + CASE opcode IS + WHEN "00000110" => --06h + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => --01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => --03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010011" => --13h + Instruct <= RD4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001011" => --4Bh + Instruct <= OTPR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00000101" => --05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000111" => --07h + Instruct <= RDSR2; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => --35h + Instruct <= RDCR; + bus_cycle_state := DATA_BYTES; + WHEN "10010000" => --90h + Instruct <= REMS; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10011111" => --9Fh + Instruct <= RDID; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => --ABh + Instruct <= RES; + bus_cycle_state := DUMMY_BYTES; + WHEN "00001011" => --0Bh + Instruct <= FSTRD; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001100" => --0Ch + Instruct <= FSTRD4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001101" => --0Dh + Instruct <= DDRFR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001110" => --0Eh + Instruct <= DDRFR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00111011" => --3Bh + Instruct <= DOR; + Check_freq := TRUE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111100" => --3Ch + Instruct <= DOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111011" => --BBh + Instruct <= DIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111100" => --BCh + Instruct <= DIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111101" => --BDh + Instruct <= DDRDIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111110" => --BEh + Instruct <= DDRDIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101011" => --6Bh + Instruct <= QOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101100" => --6Ch + Instruct <= QOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101011" => --EBh + Instruct <= QIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101100" => --ECh + Instruct <= QIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101101" => --EDh + Instruct <= DDRQIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101110" => --EEh + Instruct <= DDRQIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00000010" => --02h + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010010" => --12h + Instruct <= PP4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => --32h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00111000" => --38h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00110100" => --34h + Instruct <= QPP4; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "01000010" => --42h + Instruct <= OTPP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10000101" => --85h + Instruct <= PGSP; + bus_cycle_state := DATA_BYTES; + WHEN "10001010" => --8Ah + Instruct <= PGRS; + bus_cycle_state := DATA_BYTES; + WHEN "11000111" => --C7h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "01100000" => --60h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "11011000" => --D8h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11011100" => --DCh + Instruct <= SE4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100000" => --20h + Instruct <= P4E; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100001" => --21h + Instruct <= P4E4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01110101" => --75h + Instruct <= ERSP; + bus_cycle_state := DATA_BYTES; + WHEN "01111010" => --7Ah + Instruct <= ERRS; + bus_cycle_state := DATA_BYTES; + WHEN "00010100" => --14h + Instruct <= ABRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010101" => --15h + Instruct <= ABWR; + bus_cycle_state := DATA_BYTES; + WHEN "00010110" => --16h + Instruct <= BRRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010111" => --17h + Instruct <= BRWR; + bus_cycle_state := DATA_BYTES; + WHEN "10111001" => --B9h + Instruct <= BRAC; + bus_cycle_state := DATA_BYTES; + WHEN "00101011" => --2Bh + Instruct <= ASPRD; + bus_cycle_state := DATA_BYTES; + WHEN "00101111" => --2Fh + Instruct <= ASPP; + bus_cycle_state := DATA_BYTES; + WHEN "11100000" => --E0h + Instruct <= DYBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100001" => --E1h + Instruct <= DYBWR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100010" => --E2h + Instruct <= PPBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100011" => --E3h + Instruct <= PPBP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100100" => --E4h + Instruct <= PPBERS; + bus_cycle_state := DATA_BYTES; + WHEN "10100110" => --A6h + Instruct <= PLBWR; + bus_cycle_state := DATA_BYTES; + WHEN "10100111" => --A7h + Instruct <= PLBRD; + bus_cycle_state := DATA_BYTES; + WHEN "11100111" => --E7h + Instruct <= PASSRD; + bus_cycle_state := DATA_BYTES; + WHEN "11101000" => --E8h + Instruct <= PASSP; + bus_cycle_state := DATA_BYTES; + WHEN "11101001" => --E9h + Instruct <= PASSU; + bus_cycle_state := DATA_BYTES; + WHEN "11110000" => --F0h + Instruct <= RESET; + bus_cycle_state := DATA_BYTES; + WHEN "11111111" => --FFh + Instruct <= MBR; + bus_cycle_state := MODE_BYTE; + WHEN "01000001" => -- 41h + Instruct <= DLPRD; + bus_cycle_state := DATA_BYTES; + WHEN "01000011" => -- 43h + Instruct <= PNVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "01001010" => -- 4Ah + Instruct <= WVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "00110000" => --30h + Instruct <= CLSR; + bus_cycle_state := DATA_BYTES; + WHEN others => + null; + + END CASE; + END IF; + END IF; + END IF; + + WHEN ADDRESS_BYTES => + IF Instruct= DDRFR OR Instruct= DDRFR4 OR Instruct= DDRDIOR + OR Instruct = DDRDIOR4 OR Instruct = DDRQIOR OR + Instruct = DDRQIOR4 THEN + DOUBLE := TRUE; + ELSE + DOUBLE := FALSE; + END IF; + + IF (rising_edge(SCK_ipd) AND NOT(DOUBLE) AND + (CSNeg_ipd= '0')) THEN + IF (((Instruct=FSTRD AND EXTADD= '0' ) + OR (Instruct=DOR AND EXTADD= '0') + OR Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (Instruct=QOR AND QUAD= '1' AND EXTADD='0') THEN + --Instruction + 3 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF (Instruct=FSTRD OR Instruct=DOR OR + Instruct=QOR) THEN + IF (Latency_code = 3) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF ((((Instruct=FSTRD4) OR (Instruct=DOR4) OR + ((Instruct=FSTRD) AND EXTADD= '1') OR + ((Instruct=DOR) AND EXTADD= '1')) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct=QOR4) AND QUAD='1') OR + ((Instruct=QOR) AND QUAD='1' AND EXTADD='1')) THEN + --Instruction + 4 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF (DOUBLE AND NOT(hold_mode) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF Instruct = DIOR AND EXTADD= '0' AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + -- DUAL I/O High Performance Read (3Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF ((Instruct = DIOR4 OR + (Instruct = DIOR AND EXTADD= '1')) AND + ((HOLDNeg_pullup = '1' AND QUAD = '0') OR + QUAD = '1')) THEN + -- DUAL I/O High Performance Read (4Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR AND EXTADD= '0') THEN + -- QUAD I/O High Performance Read (3Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR4 OR + (Instruct = QIOR AND EXTADD= '1')) THEN + -- QUAD I/O High Performance Read (4Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) + := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (((Instruct = RD4 OR Instruct = PP4 OR + Instruct = SE4 OR Instruct = PPBRD OR + Instruct = DYBRD OR Instruct = DYBWR OR + Instruct = PPBP OR Instruct = P4E4 OR + (Instruct = READ AND EXTADD= '1' ) OR + (Instruct = PP AND EXTADD= '1' ) OR + (Instruct = SE AND EXTADD= '1' )) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (QUAD ='1' AND (Instruct=QPP4 OR + (Instruct = QPP AND EXTADD= '1' ))))THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') AND EXTADD= '0') THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF (SCK_ipd'EVENT AND DOUBLE AND addr_cnt /= 0 ) OR + (rising_edge(SCK_ipd) AND DOUBLE AND addr_cnt = 0 ) THEN + IF (Instruct=DDRFR AND EXTADD= '0' ) THEN + --Fast DDR Read Mode + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 3*BYTE THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRFR4 OR + (Instruct=DDRFR AND EXTADD= '1' )) THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 4*BYTE THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct= DDRDIOR AND EXTADD= '0' ) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1):= SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRDIOR4 OR + (Instruct=DDRDIOR AND EXTADD= '1' )) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR AND EXTADD= '0' ) AND + QUAD = '1' THEN + --Quad I/O DDR Read Mode + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 24) := "00000000"; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 5 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF QUAD = '1' AND (Instruct=DDRQIOR4 OR + (Instruct=DDRQIOR AND EXTADD= '1' )) THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + + WHEN MODE_BYTE => + IF rising_edge(SCK_ipd) THEN + IF ((Instruct=DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + IF Latency_code = 0 OR Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=QIOR OR Instruct = QIOR4) + AND QUAD = '1' THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSIF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt) := SIIn; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt) := SOIn; + mode_in(4*mode_cnt+1) := SIIn; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(0) := HOLDNegIn; + mode_in(1) := WPNegIn; + mode_in(2) := SOIn; + mode_in(3) := SIIn; + END IF; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + ELSIF falling_edge(SCK_ipd) THEN + IF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(4) := HOLDNegIn; + mode_in(5) := WPNegIn; + mode_in(6) := SOIn; + mode_in(7) := SIIn; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DUMMY_BYTES => + IF rising_edge(SCK_ipd) THEN + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + IF (((Instruct=FSTRD OR Instruct=FSTRD4 OR + Instruct=DOR OR Instruct=DOR4 OR + Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct = QOR OR Instruct = QOR4) AND + QUAD = '1'))THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt=1) OR + (Latency_code = 0 AND dummy_cnt=2) OR + (Latency_code = 1 AND dummy_cnt=4) OR + (Latency_code = 2 AND dummy_cnt=5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 5) OR + (Latency_code = 1 AND dummy_cnt = 6) OR + (Latency_code = 2 AND dummy_cnt = 7)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct=RES THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = 3*BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 1 AND dummy_cnt = 1) OR + (Latency_code = 2 AND dummy_cnt = 2)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt = 2) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF ((Instruct = QIOR OR Instruct = QIOR4) AND + QUAD = '1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 1) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 4) OR + (Latency_code = 2 AND dummy_cnt = 5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 3) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF falling_edge(SCK_ipd) THEN + IF NOT(hold_mode) THEN + IF (DOUBLE AND VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DATA_BYTES => + IF rising_edge(CSNeg_ipd) THEN + IF ((mode_bytes(7 downto 4) = "1010" AND + (Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QIOR OR Instruct = QIOR4)) OR + ((mode_bytes(7 downto 4) = + NOT(mode_bytes(3 downto 0))) AND + (Instruct = DDRFR OR Instruct = DDRFR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 OR + Instruct = DDRQIOR OR Instruct = DDRQIOR4))) THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + END IF; + IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' AND + NOT(DOUBLE) THEN + IF ((Instruct = READ OR Instruct=RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = RDSR OR Instruct = RDSR2 OR + Instruct = RDCR OR Instruct = OTPR OR + Instruct = DOR OR Instruct = DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = ABRD OR Instruct = BRRD OR + Instruct = ASPRD OR Instruct = DYBRD OR + Instruct = PPBRD OR + Instruct = PASSRD OR Instruct = RDID OR + Instruct = RES OR Instruct = REMS OR + Instruct = PLBRD OR Instruct = DLPRD) + AND ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (current_state = AUTOBOOT AND start_delay = 0)OR + ((Instruct=QOR OR Instruct=QIOR OR Instruct=QOR4 + OR Instruct= QIOR4) AND QUAD = '1') THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + ELSIF SCK_ipd'EVENT AND CSNeg_ipd = '0' AND DOUBLE THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + + IF rising_edge(SCK_ipd) THEN + IF QUAD = '1' AND (Instruct=QPP OR Instruct = QPP4)THEN + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF data_cnt > (PageSize*2-1) THEN + --In case of quad mode and QPP, + --if more than 512 bytes are sent to the device + FOR I IN 0 TO (PageSize*2-2) LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in((PageSize*2-1)) := + to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF quad_nybble /= "ZZZZ" THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt > (PageSize*8-1) THEN + --In case of serial mode and PP, + -- if more than 512 bytes are sent to the device + -- previously latched data are discarded and last + -- 512 data bytes are guaranteed to be programmed + -- correctly within the same page. + IF bit_cnt = 0 THEN + FOR I IN 0 TO ((PageSize-1)*BYTE - 1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in((PageSize-1)*BYTE + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF bit_cnt = 8 THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + CASE Instruct IS + WHEN WREN | WRDI | BE | SE | SE4 | CLSR | RESET | + PPBP | PPBERS | PGSP | PGRS | ERSP | BRAC | + ERRS | P4E | P4E4 | PLBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt = 0 THEN + write <= '0'; + END IF; + END IF; + + WHEN WRR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF ((data_cnt mod 8) = 0 AND data_cnt > 0) THEN + IF data_cnt = 8 THEN + --If CS# is driven high after eight + --cycle,only the Status Register is + --written to. + write <= '0'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= Data_in(7-i); + END LOOP; + ELSIF data_cnt = 16 THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + cfg_write <= '1'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= Data_in(7-i); + Config_reg1_in(i) <= Data_in(15-i); + END LOOP; + END IF; + END IF; + END IF; + + WHEN PP | PP4 | OTPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt > 0 THEN + IF (data_cnt mod 8) = 0 THEN + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 7 DOWNTO 0 LOOP + IF Data_in((i*8) + (7-j)) + /= 'X' THEN + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END IF; + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*BYTE THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/8-1; + END IF; + END IF; + END IF; + END IF; + + WHEN QPP | QPP4=> + IF data_cnt > 0 THEN + IF data_cnt mod 2 = 0 THEN + quadpg <= FALSE; + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*2 THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/2-1; + END IF; + END IF; + END IF; + + WHEN ABWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 32 THEN + write <= '0'; + FOR J IN 0 TO 31 LOOP + AutoBoot_reg_in(J) <= + Data_in(31-J); + END LOOP; + END IF; + END IF; + + WHEN BRWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + Bank_Addr_reg_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN ASPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 16 THEN + write <= '0'; + FOR J IN 0 TO 15 LOOP + ASP_reg_in(J) <= + Data_in(15-J); + END LOOP; + END IF; + END IF; + + WHEN DYBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + DYBAR_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PNVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + NVDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN WVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + VDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PASSP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + Password_reg_in(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN PASSU => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + PASS_TEMP(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN others => + null; + + END CASE; + END IF; + END CASE; + END IF; + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART, PGSUSP, PGRES, RST, Reseted) + VARIABLE pob : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF rising_edge(PSTART) AND PDONE = '1' THEN + IF Instruct = PP OR Instruct = PP4 OR Instruct = OTPP OR + Instruct = QPP OR Instruct = QPP4 THEN + IF PageSize = 256 THEN + pob := tdevice_PP256; + ELSE + pob := tdevice_PP512; + END IF; + ELSE + pob := tdevice_BP; + END IF; + elapsed := 0 ns; + start := NOW; + PDONE <= '0', '1' AFTER pob; + ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN + elapsed := NOW - start; + duration := pob - elapsed; + PDONE <= '0'; + ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN + start := NOW; + PDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + PDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + PDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WRR; + ELSE + wob := tdevice_WRR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + WDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + WDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Bulk Erase + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART, ESUSP, ERES, RST, Reseted) + VARIABLE seo : time; + VARIABLE beo : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + IF UniformSec THEN + seo := tdevice_SE256; + ELSE + seo := tdevice_SE64; + END IF; + beo := tdevice_BE; + ELSE + IF UniformSec THEN + seo := tdevice_SE256 / 1000; + ELSE + seo := tdevice_SE64 / 100; + END IF; + beo := tdevice_BE / 1000; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = BE THEN + duration := beo; + ELSE --Instruct = SE OR SE4 OR P4E OR P4E4 + duration := seo; + END IF; + elapsed := 0 ns; + EDONE <= '0', '1' AFTER duration; + start := NOW; + ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN + elapsed := NOW - start; + duration := duration - elapsed; + EDONE <= '0'; + ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN + start := NOW; + EDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + EDONE <= '1'; -- reset done, eras terminated + ELSIF rising_edge(Reseted) THEN + EDONE <= '1'; -- reset done, erase terminated + END IF; + + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS(CSNeg_ipd) + BEGIN + IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, RSTNeg_pullup, WDONE, PDONE, + ERSSUSP_out, PRGSUSP_out, EDONE, RST_out, PPBERASE_in, + PASSULCK_in) + + VARIABLE sect : NATURAL RANGE 0 TO SecNum64; + + BEGIN + + IF rising_edge(PoweredUp) THEN + IF ABE = '1' AND RPME /= '0' THEN + --Autoboot is enabled and The Read Password feature is not enabled + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)&"000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + ELSE + IF RST_out= '0' then + next_state <= current_state; + ELSIF falling_edge(write) AND Instruct = RESET THEN + IF ABE = '1' AND RPME /= '0' THEN + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay:= to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + next_state <= AUTOBOOT; + ELSE + next_state <= IDLE; + END IF; + ELSE + CASE current_state IS + WHEN RESET_STATE => + IF rising_edge(RST_out) THEN + IF ABE = '1' AND RPME /= '0' + AND RdPswdProtMode = '0' THEN + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN IDLE => + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + + IF (Instruct = WRR AND WEL = '1' AND BAR_ACC = '0') THEN + IF ((not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD = '0') OR QUAD = '1') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (TBPARM='1' AND Config_reg1_in(2)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + ASSERT cfg_write = '0' + REPORT "Changing value of Configuration " & + "Register OTP bit from 1 to 0 is " & + "not allowed!!!" + SEVERITY WARNING; + ELSE + next_state <= WRITE_SR; + END IF; + END IF; + ELSIF (Instruct = WRR AND BAR_ACC = '1') THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + REPORT "WARNING: Changing values of " & + "Bank Address Register RFU bits" & + " are not allowed!!!" + SEVERITY WARNING; + END IF; + ELSIF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + ReturnSectorID(sect,Address); + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + next_state <= PAGE_PG; + END IF; + ELSIF Instruct=OTPP AND WEL = '1' AND FREEZE = '0' THEN + IF ((((Address >= 16#10# AND Address <= 16#13#) OR + (Address >= 16#20# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + next_state <= OTP_PG; + END IF; + ELSIF (Instruct= SE OR Instruct= SE4) AND WEL= '1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 254) OR + (BottomBoot = TRUE AND sect > 31) THEN + IF (Sec_Prot(sect) = '0' AND PPB_bits(sect)='1' + AND DYB_bits(sect)='1') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF (TopBoot = TRUE AND sect >= 254) OR + (BottomBoot = TRUE AND sect <= 31) THEN + IF Sec_ProtSE = 32 AND ASP_ProtSE = 32 THEN + --Sector erase command is applied to a 64 KB + --range that includes 4 KB sectors. + next_state <= SECTOR_ERS; + END IF; + END IF; + ELSIF (Instruct=P4E OR Instruct=P4E4) AND WEL='1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 254) OR + (BottomBoot = TRUE AND sect > 31) THEN + --A P4E instruction applied to a sector that + --is larger than 4 KB will not be executed + --and will not set the E_ERR status. + REPORT "The instruction is applied to a "& + "sector that is larger than 4 KB. "& + "Instruction is ignored!!!" + SEVERITY warning; + ELSE + IF Sec_Prot(sect) = '0' AND PPB_bits(sect)='1' + AND DYB_bits(sect)='1' THEN + next_state <= SECTOR_ERS; + END IF; + END IF; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0='0' AND BP1='0' AND BP2='0') THEN + next_state <= BULK_ERS; + ELSIF Instruct = ABWR AND WEL = '1' THEN + --Autoboot Register Write Command + next_state <= AUTOBOOT_PG; + ELSIF Instruct = BRWR THEN + --Bank Register Write Command + next_state <= IDLE; + ELSIF Instruct = ASPP AND WEL = '1' THEN + --ASP Register Program Command + IF not(ASPOTPFLAG) THEN + next_state <= ASP_PG; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + next_state <= PLB_PG; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + next_state <= PASS_PG; + END IF; + ELSIF Instruct = PASSU AND WEL= '1' AND WIP= '0' THEN + next_state <= PASS_UNLOCK; + ELSIF Instruct = PPBP AND WEL = '1' THEN + next_state <= PPB_PG; + ELSIF (Instruct=PPBERS AND WEL='1' AND PPBOTP='1') THEN + next_state <= PPB_ERS; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + next_state <= DYB_PG; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + next_state <= NVDLR_PG; + ELSE + next_state <= IDLE; + END IF; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '1' AND + WIP = '0' THEN + IF Instruct = PASSU THEN + next_state <= PASS_UNLOCK; + END IF; + END IF; + + WHEN AUTOBOOT => + IF rising_edge(CSNeg_ipd) THEN + next_state <= IDLE; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = BRWR THEN + next_state <= PG_SUSP; + ELSIF Instruct = PGRS THEN + next_state <= PAGE_PG; + END IF; + ELSE + next_state <= PG_SUSP; + END IF; + + WHEN OTP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN BULK_ERS => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN SECTOR_ERS => + IF ERSSUSP_out'EVENT AND ERSSUSP_out = '1' THEN + next_state <= ERS_SUSP; + ELSIF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN ERS_SUSP => + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + IF (PARAM_REGION = TRUE AND + SectorSuspend /= Address/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend/=Address/(SecSize+1)+30*b_act) THEN + ReturnSectorID(sect,Address); + pgm_page := Address / (PageSize+1); + IF PPB_bits(sect)='1' AND + DYB_bits(sect)='1' THEN + next_state <= ERS_SUSP_PG; + END IF; + END IF; + ELSIF Instruct = BRWR THEN + next_state <= ERS_SUSP; + ELSIF (Instruct = DYBWR AND WEL = '1') THEN + next_state <= DYB_PG; + ELSIF Instruct = ERRS THEN + next_state <= SECTOR_ERS; + END IF; + ELSE + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= ERS_SUSP_PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = BRWR THEN + next_state <= ERS_SUSP_PG_SUSP; + ELSIF Instruct = PGRS THEN + next_state <= ERS_SUSP_PG; + END IF; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + + WHEN PASS_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PASS_UNLOCK => + IF falling_edge(PASSULCK_in) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_ERS => + IF falling_edge(PPBERASE_in) THEN + next_state <= IDLE; + END IF; + + WHEN AUTOBOOT_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PLB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN DYB_PG => + IF rising_edge(PDONE) THEN + IF ES = '1' THEN + next_state <= ERS_SUSP; + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN ASP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN NVDLR_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + END CASE; + END IF; + END IF; + + END PROCESS StateGen; + + ReadEnable: PROCESS (read_out) + BEGIN + oe_z <= rising_edge(read_out) AND PoweredUp = '1'; + + IF read_out'EVENT AND read_out = '0' AND PoweredUp = '1' THEN + oe <= TRUE, FALSE AFTER 1 ns; + END IF; + END PROCESS ReadEnable; + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(write,current_state,start_autoboot,CSNeg_ipd, + HOLDNeg_pullup, Instruct, Address, WByte,change_addr, + PoweredUp, WPNeg_pullup, WDONE, PDONE, EDONE, + PRGSUSP_out,ERSSUSP_out, PASSACC_out, oe, oe_z) + + VARIABLE WData : WByteType:= (OTHERS => MaxData); + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + VARIABLE Addr : NATURAL; + VARIABLE Addr_tmp : NATURAL; + + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(647 downto 0); + + VARIABLE ExtendedID : NATURAL; + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + VARIABLE old_pass : std_logic_vector(63 downto 0); + VARIABLE new_pass : std_logic_vector(63 downto 0); + VARIABLE wr_cnt : NATURAL RANGE 0 TO 511; + --Data Learning Pattern Enable + VARIABLE dlp_act : BOOLEAN := FALSE; + + VARIABLE sect : NATURAL RANGE 0 TO SecNum64; + VARIABLE cnt : NATURAL RANGE 0 TO 512 := 0; + + VARIABLE sec_tmp : NATURAL RANGE 0 TO SecNum64; + + BEGIN + + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + IF Instruct'EVENT THEN + read_cnt := 0; + byte_cnt := 1; + fast_rd <= true; + dual <= false; + rd <= false; + any_read <= false; + END IF; + + IF PASSACC_out'EVENT AND PASSACC_out = '1' THEN + WIP := '0'; + PASSACC_in <= '0'; + END IF; + + IF rising_edge(PoweredUp) THEN + --the default condition after power-up + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + --The Configuration Register FREEZE bit is cleared. + FREEZE := '0'; + --The WEL bit is cleared. + WEL := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status Register are + --volatile and will be reset binary 111 after power-on reset + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --As shipped from the factory, all devices default ASP to the + --Persistent Protection mode, with all sectors unprotected, + --when power is applied. The device programmer or host system must + --then choose which sector protection method to use. + --For Persistent Protection mode, PPBLOCK defaults to "1" + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + DYB_bits := (OTHERS => '1'); + + END IF; + + IF falling_edge(write) AND Instruct = RESET THEN + --The Configuration Register is set for Address mode + Bank_Addr_reg := (others => '0'); + --P_ERR bit is cleared + P_ERR := '0'; + --E_ERR bit is cleared + E_ERR := '0'; + --The WEL bit is cleared. + WEL := '0'; + --The WIP bit is cleared. + WIP := '0'; + --The ES bit is cleared. + ES := '0'; + --The PS bit is cleared. + PS := '0'; + + DummyBytes_act := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status + --Register are volatile and will be reseted after + --reset command + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF change_addr'EVENT THEN + read_addr := Address; + END IF; + + CASE current_state IS + WHEN IDLE => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + ASP_ProtSE := 0; + Sec_ProtSE := 0; + PARAM_REGION := false; + IF falling_edge(write) AND RdPswdProtMode = '1' THEN + IF Instruct = PASSU THEN + IF WIP = '0' THEN + PASSULCK_in <= '1'; + ELSE + REPORT "The PASSU command cannot be accepted"& + " any faster than once every 100us" + SEVERITY WARNING; + END IF; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + END IF; + IF BottomBoot = TRUE THEN + FOR J IN 31 DOWNTO 0 LOOP + IF (PPB_bits(J)='1' AND DYB_bits(J)='1') THEN + ASP_ProtSE := ASP_ProtSE + 1; + END IF; + IF (Sec_Prot(J)='0') THEN + Sec_ProtSE := Sec_ProtSE + 1; + END IF; + END LOOP; + ELSIF TopBoot = TRUE THEN + FOR J IN 285 DOWNTO 254 LOOP + IF (PPB_bits(J)='1' AND DYB_bits(J)='1') THEN + ASP_ProtSE := ASP_ProtSE + 1; + END IF; + IF (Sec_Prot(J)='0') THEN + Sec_ProtSE := Sec_ProtSE + 1; + END IF; + END LOOP; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + read_cnt := 0; + byte_cnt := 1; + IF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = WRDI THEN + WEL := '0'; + ELSIF Instruct = WRR AND WEL = '1' AND BAR_ACC = '0' THEN + IF (not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD ='0') OR QUAD ='1' THEN + -- can not execute if Hardware Protection Mode + -- is entered or if WEL bit is zero + + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (TBPARM='1' AND Config_reg1_in(2)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + P_ERR := '1'; + ELSE + WSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + END IF; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect)= '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF Instruct = OTPP AND WEL = '1' THEN + -- As long as the FREEZE bit remains cleared to a logic '0' + --the OTP address space is programmable. + IF FREEZE = '0' THEN + IF ((((Address >= 16#0010# AND Address <= 16#13#)OR + (Address >= 16#0020# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + PSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSIF (Address < 16#0010# OR (Address > 16#0013# AND + Address < 16#0020#) OR Address > 16#3FF# ) THEN + P_ERR := '1'; + WEL := '0'; + IF Address < 16#0020# THEN + ASSERT false + REPORT "Given address is in" & + "reserved address range" + SEVERITY warning; + ELSIF Address > 16#3FF# THEN + ASSERT false + REPORT "Given address is out of" & + "OTP address range" + SEVERITY warning; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = SE OR Instruct = SE4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 254) OR + (BottomBoot = TRUE AND sect > 31) THEN + SectorSuspend <= sect; + PARAM_REGION := FALSE; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (TopBoot = TRUE AND sect >= 254) OR + (BottomBoot = TRUE AND sect <= 31) THEN + IF Sec_ProtSE = 32 AND ASP_ProtSE = 32 THEN + --Sector erase command is applied to a 64 KB range + --that includes 4 KB sectors + IF TopBoot = TRUE THEN + SectorSuspend <= 254 + (285 - sect)/16; + ELSE + SectorSuspend <= sect/16; + END IF; + PARAM_REGION := TRUE; + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + END IF; + ELSIF (Instruct = P4E OR Instruct = P4E4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 254) OR + (BottomBoot = TRUE AND sect > 31) THEN + WEL := '0'; + ELSE + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + --A P4E instruction applied to a sector + --that has been Write Protected through the + --Block Protect Bits or ASP will not be + --executed and will set the E_ERR status + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + END IF; + ELSIF Instruct = BE AND WEL = '1' THEN + IF (BP0='0' AND BP1='0' AND BP2='0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + ELSE + --The Bulk Erase command will not set E_ERR if a + --protected sector is found during the command + --execution. + WEL := '0'; + END IF; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + REPORT "Password programming is not allowed" & + " in Password Protection Mode." + SEVERITY warning; + END IF; + ELSIF Instruct = PASSU AND WEL = '1' THEN + PASSULCK_in <= '1'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + ELSIF Instruct = ASPP AND WEL = '1' THEN + IF not(ASPOTPFLAG) THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + WEL := '0'; + P_ERR := '1'; + REPORT "Once the Protection Mode is selected," & + "no further changes to the ASP register" & + "is allowed." + SEVERITY warning; + END IF; + ELSIF Instruct = ABWR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBP AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBERS AND WEL = '1' THEN + IF PPBOTP = '1' THEN + PPBERASE_in <= '1'; + WIP := '1'; + ELSE + E_ERR := '1'; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = WVDLR AND WEL = '1' THEN + VDLR_reg := VDLR_reg_in; + WEL := '0'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 OR + Instruct = RES OR Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES OR + DummyBytes_act='1') AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRFR OR Instruct = DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + dlp_act := FALSE; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := read_addr/(SecSize+1); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + IF Mem(read_addr) /= -1 THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRDIOR OR Instruct = DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := read_addr/(SecSize+1); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF ((Instruct = DDRQIOR OR Instruct = DDRQIOR4) AND + QUAD = '1') THEN + IF EHP THEN + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := read_addr/(SecSize+1); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = OTPR THEN + IF (read_addr>=OTPLoAddr) AND + (read_addr<=OTPHiAddr) AND RdPswdProtMode = '0' THEN + --Read OTP Memory array + fast_rd <= true; + rd <= false; + data_out := to_slv(OTPMem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSIF (read_addr > OTPHiAddr) + OR RdPswdProtMode = '1' THEN + --OTP Read operation will not wrap to the + --starting address after the OTP address is at + --its maximum or Read Password Protection Mode + --is selected; instead, the data beyond the + --maximum OTP address will be undefined. + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF Instruct = REMS THEN + --Read Manufacturer and Device ID + IF read_addr MOD 2 = 0 THEN + data_out := to_slv(Manuf_ID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + data_out := to_slv(DeviceID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := 0; + END IF; + END IF; + ELSIF Instruct = RDID THEN + IF UniformSec THEN + ExtendedID := ExtendedID256; + ELSE + ExtendedID := ExtendedID64; + END IF; + ident_out := CFI_array_tmp; + IF read_cnt < 648 THEN + SOut_zd <= ident_out(647-read_cnt); + read_cnt := read_cnt + 1; + ELSE + --Continued shifting of output beyond the end of + --the defined ID-CFI address space will provide + --undefined data. + SOut_zd <= 'U'; + END IF; + ELSIF Instruct = RES THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + data_out := to_slv(ESignature,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + SOut_zd <= VDLR_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ABRD THEN + --Read AutoBoot register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= AutoBoot_reg(31-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 32 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ASPRD THEN + --Read ASP Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= ASP_reg(15-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 16 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PASSRD THEN + --Read Password Register + IF not (PWDMLB='0' AND PSTMLB='1') THEN + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Password_reg((8*byte_cnt-1)-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + byte_cnt := byte_cnt + 1; + IF byte_cnt = 9 THEN + byte_cnt := 1; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 64 THEN + read_cnt := 0; + END IF; + IF read_cnt = 0 THEN + ASSERT false + REPORT "Verification of password is not " & + " allowed in Password Protection Mode." + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = PLBRD THEN + --Read PPB Lock Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= PPBL(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + DYBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + + WHEN AUTOBOOT => + IF start_autoboot = '1' THEN + IF (oe) THEN + any_read <= true; + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF oe_z THEN + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + END IF; + + WHEN WRITE_SR => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF WDONE = '1' THEN + WIP := '0'; + WEL := '0'; + SRWD := Status_reg1_in(7);--MSB first + + IF LOCK='0' THEN + IF FREEZE='0' THEN + --The Freeze Bit, when set to 1, locks the current + --state of the BP2-0 bits in Status Register, + --the TBPROT and TBPARM bits in the Config Register + --As long as the FREEZE bit remains cleared to logic + --'0', the other bits of the Configuration register + --including FREEZE are writeable. + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + + BP_bits := BP2 & BP1 & BP0; + + IF TBPROT = '0' AND INITIAL_CONFIG = '0' THEN + TBPROT := Config_reg1_in(5); + END IF; + + IF (TBPARM = '0' AND INITIAL_CONFIG = '0' AND + TimingModel(16) = '0') THEN + TBPARM := Config_reg1_in(2); + change_TBPARM <= '1', '0' AFTER 1 ns; + END IF; + + change_BP <= '1', '0' AFTER 1 ns; + + LC1 := Config_reg1_in(7); + LC0 := Config_reg1_in(6); + QUAD := Config_reg1_in(1); + + IF FREEZE = '0' THEN + FREEZE := Config_reg1_in(0); + END IF; + + IF WRLOCKENABLE AND LOCK = '0' THEN + LOCK := Config_reg1_in(4); + WRLOCKENABLE <= false; + END IF; + + IF BPNV = '0' THEN + BPNV := Config_reg1_in(3); + END IF; + END IF; + END IF; + END IF; + + WHEN PAGE_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(PDONE) THEN + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + Mem(Addr + i - cnt) := -1; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + IF RES_TO_SUSP_MIN_TIME = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + ELSE + ASSERT FALSE + REPORT "Minimum for tPRS is not satisfied! " & + "PGSP command is ignored" + SEVERITY warning; + END IF; + END IF; + + WHEN PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + + IF pgm_page /= read_addr/(PageSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF pgm_page /= read_addr/(PageSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + + IF pgm_page /= read_addr/(PageSize+1) THEN + + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + REPORT "WARNING: Changing values of " & + "Bank Address Register RFU bits" & + " are not allowed!!!" + SEVERITY WARNING; + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + + IF (SectorSuspend /= read_addr/(SecSize+1)+30*b_act AND + pgm_page /= read_addr/(PageSize+1)) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1)+30*b_act AND + pgm_page /= read_addr/(PageSize+1)) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1)+30*b_act AND + pgm_page /= read_addr/(PageSize+1)) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + REPORT "WARNING: Changing values of " & + "Bank Address Register RFU bits" & + " are not allowed!!!" + SEVERITY WARNING; + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + + WHEN OTP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF Address + wr_cnt <= OTPHiAddr THEN + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := OTPMem(Addr + i); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + OTPMem(Addr + i) := -1; + END LOOP; + ELSE + ASSERT false + REPORT "Programming will reach over address limit"& + " of OTP array" + SEVERITY warning; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + OTPMem(Addr_tmp + i) := WData(i); + END LOOP; + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + END IF; + + WHEN SECTOR_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + ELSIF Instruct = ERSP AND ERSSUSP_in = '0' THEN + ESUSP <= '1', '0' AFTER 10 ns; + ERSSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + END IF; + + WHEN BULK_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(EDONE) THEN + FOR i IN 0 TO AddrRANGE LOOP + -- Sector ID calculation + IF TimingModel(16) = '0' THEN + sec_tmp := i / (SecSize64+1); + IF BottomBoot THEN + IF sec_tmp <= 1 THEN --4KB Sectors + sect := i/(SecSize4+1); + ELSE + sect := sec_tmp + 30; + END IF; + ELSIF TopBoot THEN + IF sec_tmp >= 254 THEN --4KB Sectors + sect := + 254+(i-(SecSize64+1)*254)/(SecSize4+1); + ELSE + sect := sec_tmp; + END IF; + END IF; + ELSE + sect := i/(SecSize256+1); + END IF; + IF PPB_bits(sect) = '1' AND DYB_bits(sect) = '1' THEN + Mem(i) := -1; + END IF; + END LOOP; + END IF; + + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO AddrRANGE LOOP + -- Sector ID calculation + IF TimingModel(16) = '0' THEN + sec_tmp := i / (SecSize64+1); + IF BottomBoot THEN + IF sec_tmp <= 1 THEN --4KB Sectors + sect := i/(SecSize4+1); + ELSE + sect := sec_tmp + 30; + END IF; + ELSIF TopBoot THEN + IF sec_tmp >= 254 THEN --4KB Sectors + sect := + 254+(i-(SecSize64+1)*254)/(SecSize4+1); + ELSE + sect := sec_tmp; + END IF; + END IF; + ELSE + sect := i/(SecSize256+1); + END IF; + IF PPB_bits(sect) = '1' AND DYB_bits(sect) = '1' THEN + Mem(i) := MaxData; + END IF; + END LOOP; + END IF; + + WHEN ERS_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF ERSSUSP_out = '1' THEN + ERSSUSP_in <= '0'; + --The Erase Suspend (ES) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --erase operation has been suspended. + ES := '1'; + --The WIP bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + + IF (PARAM_REGION = TRUE AND + SectorSuspend /= read_addr/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend /= read_addr/(SecSize+1)+30*b_act) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (PARAM_REGION = TRUE AND + SectorSuspend /= read_addr/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend /= read_addr/(SecSize+1)+30*b_act) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (PARAM_REGION = TRUE AND + SectorSuspend /= read_addr/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend /= read_addr/(SecSize+1)+30*b_act) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + IF (PARAM_REGION = TRUE AND + SectorSuspend /= Address/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend/=Address/(SecSize+1)+30*b_act) THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + IF (PARAM_REGION = TRUE AND + SectorSuspend /= Address/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend/=Address/(SecSize+1)+30*b_act) THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect)='0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + REPORT "WARNING: Changing values of " & + "Bank Address Register RFU bits" & + " are not allowed!!!" + SEVERITY WARNING; + END IF; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + ReturnSectorID(sect,Address); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = ERRS THEN + ERES <= '1', '0' AFTER 5 ns; + ES := '0'; + WIP := '1'; + IF BottomBoot = TRUE THEN + IF PARAM_REGION = TRUE THEN + Addr := SectorSuspend*(SecSize+1); + ELSE + Addr := (SectorSuspend-30)*(SecSize+1); + END IF; + ELSE + Addr := SectorSuspend*(SecSize+1); + END IF; + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + END IF; + + WHEN PASS_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + new_pass := Password_reg_in; + old_pass := Password_reg; + FOR j IN 0 TO 63 LOOP + IF old_pass(j) = '0' THEN + new_pass(j) := '0'; + END IF; + END LOOP; + + IF PDONE = '1' THEN + Password_reg := new_pass; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PASS_UNLOCK => + WIP := '1'; + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PASS_TEMP = Password_reg THEN + PASS_UNLOCKED <= TRUE; + ELSE + PASS_UNLOCKED <= FALSE; + END IF; + + IF PASSULCK_out = '1' THEN + IF PASS_UNLOCKED AND PWDMLB = '0' THEN + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + WIP := '0'; + ELSE + P_ERR := '1'; + REPORT "Incorrect Password!" + SEVERITY warning; + PASSACC_in <= '1'; + END IF; + WEL := '0'; + PASSULCK_in <= '0'; + END IF; + + WHEN PPB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF PPB_LOCK /= '0' THEN + PPB_bits(sect):= '0'; + WIP := '0'; + WEL := '0'; + ELSE + P_ERR := '0'; + WIP := '0'; + WEL := '0'; + END IF; + END IF; + + WHEN PPB_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PPBERASE_out = '1' THEN + IF PPB_LOCK /= '0' AND PPBOTP = '1' THEN + PPB_bits:= (OTHERS => '1'); + ELSE + E_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + PPBERASE_in <= '0'; + END IF; + + WHEN AUTOBOOT_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + AutoBoot_reg := AutoBoot_reg_in; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PLB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN DYB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + DYBAR := DYBAR_in; + IF DYBAR = "11111111" THEN + DYB_bits(sect):= '1'; + ELSIF DYBAR = "00000000" THEN + DYB_bits(sect):= '0'; + ELSE + P_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN ASP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + + IF (RPME = '0' AND ASP_reg_in(5) = '1') THEN + P_ERR := '1'; + REPORT "RPME bit is allready programmed" + SEVERITY warning; + ELSE + RPME := ASP_reg_in(5); + END IF; + + IF (PPBOTP = '0' AND ASP_reg_in(3) ='1') THEN + P_ERR := '1'; + REPORT "PPBOTP bit is allready programmed" + SEVERITY warning; + ELSE + PPBOTP := ASP_reg_in(3); + END IF; + + IF (PWDMLB = '1' AND PSTMLB = '1') THEN + IF (ASP_reg_in(2) = '0' AND ASP_reg_in(1) = '0') THEN + REPORT "ASPR[2:1] = 00 Illegal condition" + SEVERITY warning; + P_ERR := '1'; + ELSE + IF (ASP_reg_in(2) /= '1' OR + ASP_reg_in(1) /= '1') THEN + ASPOTPFLAG <= TRUE; + END IF; + PWDMLB := ASP_reg_in(2); + PSTMLB := ASP_reg_in(1); + END IF; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN NVDLR_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF NVDLR_reg = "00000000" THEN + NVDLR_reg :=NVDLR_reg_in; + VDLR_reg := NVDLR_reg_in; + WIP := '0'; + WEL := '0'; + ELSE + WIP := '0'; + WEL := '0'; + P_ERR := '1'; + REPORT "NVDLR is allready programmed" + SEVERITY warning; + END IF; + END IF; + + WHEN RESET_STATE => + --the default condition hardware reset + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --Resets the Status register 1 + P_ERR := '0'; + E_ERR := '0'; + WEL := '0'; + WIP := '0'; + --Resets the Status register 2 + ES := '0'; + PS := '0'; + --Resets the Configuration register 1 + FREEZE := '0'; + --On reset cycles the data pattern reverts back + --to what is in the NVDLR + VDLR_reg := NVDLR_reg; + dlp_act := FALSE; + --Loads the Program Buffer with all ones + WData := (OTHERS => MaxData); + + IF PWDMLB = '0' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + ELSE + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + END PROCESS Functional; + + --------------------------------------------------------------------------- + -- CFI Process + --------------------------------------------------------------------------- + CFIPreload: PROCESS + + BEGIN + ------------------------------------------------------------------------ + --CFI array data + ------------------------------------------------------------------------ + -- Manufacturer and Device ID + CFI_array(16#00#) := 16#01#; + CFI_array(16#01#) := 16#20#; + CFI_array(16#02#) := 16#18#; + CFI_array(16#03#) := 16#00#; + IF TimingModel(16) = '0' THEN + CFI_array(16#04#) := 16#01#;--256B page + ELSIF TimingModel(16) = '1' THEN + CFI_array(16#04#) := 16#00#;--512B page + END IF; + CFI_array(16#05#) := 16#80#; + + CFI_array(16#06#) := 16#00#; + CFI_array(16#07#) := 16#00#; + CFI_array(16#08#) := 16#00#; + CFI_array(16#09#) := 16#00#; + CFI_array(16#0A#) := 16#00#; + CFI_array(16#0B#) := 16#00#; + CFI_array(16#0C#) := 16#00#; + CFI_array(16#0D#) := 16#00#; + CFI_array(16#0E#) := 16#00#; + CFI_array(16#0F#) := 16#00#; + --CFI Query Identification String + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#53#; + CFI_array(16#18#) := 16#46#; + CFI_array(16#19#) := 16#51#; + CFI_array(16#1A#) := 16#00#; + --CFI system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#06#; + IF TimingModel(16) = '0' THEN + CFI_array(16#20#) := 16#08#;--256B page + CFI_array(16#21#) := 16#08#;--64KB + ELSIF TimingModel(16) = '1' THEN + CFI_array(16#20#) := 16#09#;--512B page + CFI_array(16#21#) := 16#09#;--256KB + END IF; + + CFI_array(16#22#) := 16#0F#; + CFI_array(16#23#) := 16#02#; + CFI_array(16#24#) := 16#02#; + CFI_array(16#25#) := 16#03#; + CFI_array(16#26#) := 16#03#; + --Device Geometry Definition + CFI_array(16#27#) := 16#18#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#01#; + IF TimingModel(16) = '0' THEN + CFI_array(16#2A#) := 16#08#;--256B page + ELSIF TimingModel(16) = '1' THEN + CFI_array(16#2A#) := 16#09#;--512B page + END IF; + CFI_array(16#2B#) := 16#00#; + IF TimingModel(16) = '1' THEN + CFI_array(16#2C#) := 16#01#; --Uniform Device + CFI_array(16#2D#) := 16#3F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#04#; + CFI_array(16#31#) := 16#FF#; + CFI_array(16#32#) := 16#FF#; + CFI_array(16#33#) := 16#FF#; + CFI_array(16#34#) := 16#FF#; + ELSE + CFI_array(16#2C#) := 16#02#; --Boot device + IF TBPARM = '1' THEN + CFI_array(16#2D#) := 16#FD#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#1F#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#10#; + CFI_array(16#34#) := 16#00#; + ELSE + CFI_array(16#2D#) := 16#1F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#10#; + CFI_array(16#30#) := 16#00#; + CFI_array(16#31#) := 16#FD#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#01#; + END IF; + END IF; + CFI_array(16#35#) := 16#FF#; + CFI_array(16#36#) := 16#FF#; + CFI_array(16#37#) := 16#FF#; + CFI_array(16#38#) := 16#FF#; + CFI_array(16#39#) := 16#FF#; + CFI_array(16#3A#) := 16#FF#; + CFI_array(16#3B#) := 16#FF#; + CFI_array(16#3C#) := 16#FF#; + CFI_array(16#3D#) := 16#FF#; + CFI_array(16#3E#) := 16#FF#; + CFI_array(16#3F#) := 16#FF#; + --CFI Primary Vendor-Specific Extended Query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#21#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#00#; + CFI_array(16#49#) := 16#08#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#01#; + CFI_array(16#4C#) := 16#00#; + CFI_array(16#4D#) := 16#00#; + CFI_array(16#4E#) := 16#00#; + CFI_array(16#4F#) := 16#07#; + CFI_array(16#50#) := 16#01#; + CFI_array(16#51#) := 16#41#; + CFI_array(16#52#) := 16#4C#; + CFI_array(16#53#) := 16#54#; + CFI_array(16#54#) := 16#32#; + CFI_array(16#55#) := 16#30#; + + CFI_array_tmp :=to_slv(CFI_array(16#00#), 8) & + to_slv(CFI_array(16#01#), 8) & + to_slv(CFI_array(16#02#), 8) & + to_slv(CFI_array(16#03#), 8) & + to_slv(CFI_array(16#04#), 8) & + to_slv(CFI_array(16#05#), 8) & + to_slv(CFI_array(16#06#), 8) & + to_slv(CFI_array(16#07#), 8) & + to_slv(CFI_array(16#08#), 8) & + to_slv(CFI_array(16#09#), 8) & + to_slv(CFI_array(16#0A#), 8) & + to_slv(CFI_array(16#0B#), 8) & + to_slv(CFI_array(16#0C#), 8) & + to_slv(CFI_array(16#0D#), 8) & + to_slv(CFI_array(16#0E#), 8) & + to_slv(CFI_array(16#0F#), 8) & + to_slv(CFI_array(16#10#), 8) & + to_slv(CFI_array(16#11#), 8) & + to_slv(CFI_array(16#12#), 8) & + to_slv(CFI_array(16#13#), 8) & + to_slv(CFI_array(16#14#), 8) & + to_slv(CFI_array(16#15#), 8) & + to_slv(CFI_array(16#16#), 8) & + to_slv(CFI_array(16#17#), 8) & + to_slv(CFI_array(16#18#), 8) & + to_slv(CFI_array(16#19#), 8) & + to_slv(CFI_array(16#1A#), 8) & + to_slv(CFI_array(16#1B#), 8) & + to_slv(CFI_array(16#1C#), 8) & + to_slv(CFI_array(16#1D#), 8) & + to_slv(CFI_array(16#1E#), 8) & + to_slv(CFI_array(16#1F#), 8) & + to_slv(CFI_array(16#20#), 8) & + to_slv(CFI_array(16#21#), 8) & + to_slv(CFI_array(16#22#), 8) & + to_slv(CFI_array(16#23#), 8) & + to_slv(CFI_array(16#24#), 8) & + to_slv(CFI_array(16#25#), 8) & + to_slv(CFI_array(16#26#), 8) & + to_slv(CFI_array(16#27#), 8) & + to_slv(CFI_array(16#28#), 8) & + to_slv(CFI_array(16#29#), 8) & + to_slv(CFI_array(16#2A#), 8) & + to_slv(CFI_array(16#2B#), 8) & + to_slv(CFI_array(16#2C#), 8) & + to_slv(CFI_array(16#2D#), 8) & + to_slv(CFI_array(16#2E#), 8) & + to_slv(CFI_array(16#2F#), 8) & + to_slv(CFI_array(16#30#), 8) & + to_slv(CFI_array(16#31#), 8) & + to_slv(CFI_array(16#32#), 8) & + to_slv(CFI_array(16#33#), 8) & + to_slv(CFI_array(16#34#), 8) & + to_slv(CFI_array(16#35#), 8) & + to_slv(CFI_array(16#36#), 8) & + to_slv(CFI_array(16#37#), 8) & + to_slv(CFI_array(16#38#), 8) & + to_slv(CFI_array(16#39#), 8) & + to_slv(CFI_array(16#3A#), 8) & + to_slv(CFI_array(16#3B#), 8) & + to_slv(CFI_array(16#3C#), 8) & + to_slv(CFI_array(16#3D#), 8) & + to_slv(CFI_array(16#3E#), 8) & + to_slv(CFI_array(16#3F#), 8) & + to_slv(CFI_array(16#40#), 8) & + to_slv(CFI_array(16#41#), 8) & + to_slv(CFI_array(16#42#), 8) & + to_slv(CFI_array(16#43#), 8) & + to_slv(CFI_array(16#44#), 8) & + to_slv(CFI_array(16#45#), 8) & + to_slv(CFI_array(16#46#), 8) & + to_slv(CFI_array(16#47#), 8) & + to_slv(CFI_array(16#48#), 8) & + to_slv(CFI_array(16#49#), 8) & + to_slv(CFI_array(16#4A#), 8) & + to_slv(CFI_array(16#4B#), 8) & + to_slv(CFI_array(16#4C#), 8) & + to_slv(CFI_array(16#4D#), 8) & + to_slv(CFI_array(16#4E#), 8) & + to_slv(CFI_array(16#4F#), 8) & + to_slv(CFI_array(16#50#), 8); + + WAIT; + + END PROCESS CFIPreload; + + AspRegInit: PROCESS(ASP_INIT) + BEGIN + IF ASP_INIT = 0 THEN + ASP_reg := to_slv(16#FE4F#,16); + ELSE + ASP_reg := to_slv(16#FE7F#,16); + END IF; + END PROCESS AspRegInit; + + TopBottom: PROCESS(change_TBPARM, PoweredUp) + BEGIN + IF (TimingModel(16)= '0') THEN + IF TBPARM = '0' THEN + BottomBoot <= TRUE; + b_act := 1; + ELSE + TopBoot <= TRUE; + BottomBoot <= FALSE; + b_act := 0; + END IF; + END IF; + END PROCESS TopBottom; + + Protect : PROCESS(change_BP) + BEGIN + IF rising_edge(change_BP) THEN + + CASE BP_bits IS + WHEN "000" => + Sec_Prot := (OTHERS => '0'); + WHEN "001" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*63/64+30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*63/64 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/64 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/64 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "010" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*31/32+30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*31/32+30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/32 + 30*b_act - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/32 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "011" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*15/16+30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*15/16 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/16 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/16 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "100" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*7/8 + 30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*7/8 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/8 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/8 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "101" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*3/4 + 30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*3/4 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/4 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/4 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "110" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)/2 + 30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)/2 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/2 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/2 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN OTHERS => + Sec_Prot := (OTHERS => '1'); + END CASE; + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNeg_pullup) + BEGIN + IF (HOLDNeg_pullup = '0' AND QUAD /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + RST_PULL_UP : PROCESS(RSTNeg) + BEGIN + IF (RSTNeg = 'Z') THEN + RSTNeg_pullup <= '1'; + ELSE + RSTNeg_pullup <= RSTNeg; + END IF; + END PROCESS RST_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + MemPreload : PROCESS + + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE otp_file : text is otp_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0; + VARIABLE otp_ind : NATURAL RANGE 16#000# TO 16#3FF# := 16#000#; + VARIABLE buf : line; + + BEGIN + --------------------------------------------------------------------------- + --s25fl128s memory preload file format +----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaaaaa - stands for address + -- dd -
is byte to be written at Mem(aaaaaa++) + -- (aaaaaa is incremented at every load) + -- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (mem_file_name /= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF ind > AddrRANGE THEN + ASSERT false + REPORT "Given preload address is out of" & + "memory address range" + SEVERITY warning; + ELSE + ind := h(buf(2 to 7)); --address + END IF; + ELSE + Mem(ind) := h(buf(1 to 2)); + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --------------------------------------------------------------------------- + --s25fl128s_otp memory preload file format + --------------------------------------------------------------------------- + -- / - comment + -- @aaa - stands for address + -- dd -
is byte to be written at OTPMem(aaa++) + -- (aaa is incremented at every load) + -- only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (otp_file_name /= "none" AND UserPreload) THEN + otp_ind := 16#000#; + OTPMem := (OTHERS => MaxData); + WHILE (not ENDFILE (otp_file)) LOOP + READLINE (otp_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF otp_ind > 16#3FF# OR otp_ind < 16#000# THEN + ASSERT false + REPORT "Given preload address is out of" & + "OTP address range" + SEVERITY warning; + ELSE + otp_ind := h(buf(2 to 4)); --address + END IF; + ELSE + OTPMem(otp_ind) := h(buf(1 to 2)); + otp_ind := otp_ind + 1; + END IF; + END LOOP; + END IF; + + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + + WAIT; + END PROCESS MemPreload; + + ---------------------------------------------------------------------------- + -- Path Delay Section + ---------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "SO", + OutTemp => SOut_z, + Mode => VitalTransport, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => (ddr OR fast_rd)), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => QUAD = '0') + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + Mode => VitalTransport, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => dual AND ddr), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => dual AND QUAD = '0') + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + Mode => VitalTransport, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + HOLDNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + Mode => VitalTransport, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + WPNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + END BLOCK behavior; +END vhdl_behavioral; \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_ver.ftm b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_ver.ftm new file mode 100644 index 0000000..219d3b1 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_ver.ftm @@ -0,0 +1,726 @@ + +FMF Timing for s25fl128s Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 09 Nov 19 Initial release + V1.1 V.Mancev 10 Oct 07 Latest datasheet aligned + V1.2 V.Mancev 11 May 11 CS# High Time modifications + V1.3 V.Mancev 11 June 27 Latest datasheet aligned + V1.4 V.Mancev 11 Nov 16 Time tHO is changed to 1 ns + +1ns +s25fl128s + +S25FL128SAGMFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for VIO=VCC=2.7V to 3.6V, CL=30pF + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL128SAGMFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL128SAGMFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL128SDPMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for Vcc range VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (5)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (4)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (7.5)) + (WIDTH (COND dual_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL128SDPMFIR00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR01_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR11_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI000_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI001_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI003_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI010_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI011_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI013_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI200_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI203_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI210_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI213_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI300_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI303_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI310_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI313_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for Vcc range VCC=2.7V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (5)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (4)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (7.5)) + (WIDTH (COND dual_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND ddrd SCK) (15)) +) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_vhd.ftm b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_vhd.ftm new file mode 100644 index 0000000..7d90f2c --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/model/s25fl128s_vhd.ftm @@ -0,0 +1,783 @@ + +FMF Timing for s25fl128s Parts + + +version: | author: | mod date: | changes made: + V1.0 V.Mancev 09 Nov 26 Initial release + V1.1 V. Mancev 10 Oct 21 New datasheet aligned + R. Prokopovic + V1.2 V.Mancev 11 June 27 Latest datasheet aligned + V1.3 V.Mancev 11 Nov 16 Time tHO is changed to 1 ns + +1ns +s25fl128s + +S25FL128SAGMFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:110e9:165e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL128SAGMFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:110e9:165e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL128SAGMFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFIR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGMFVR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGNFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHI313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHID13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHV313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHVD13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIY13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIZ13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIS13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIT13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIK13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SAGBHIL13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:110e9:165e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL128SDPMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (10:12:14) (10:12:14) (10:12:14) (10:12:14)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (5)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (5)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (4)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (5)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (7.5)) + (WIDTH (COND dual (negedge SCK)) (7.5)) + (WIDTH (COND fast (negedge SCK)) (7.5)) + (WIDTH (COND fast (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:110e9:165e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL128SDPMFIR00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR01_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR11_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPMFIR13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI000_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI001_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI003_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI010_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI011_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPNFI013_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI200_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI203_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI210_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI213_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI300_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI303_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI310_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHI313_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHIC13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL128SDPBHID13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (10:12:14) (10:12:14) (10:12:14) (10:12:14)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (5)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (5)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (4)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (5)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (7.5)) + (WIDTH (COND dual (negedge SCK)) (7.5)) + (WIDTH (COND fast (negedge SCK)) (7.5)) + (WIDTH (COND fast (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:110e9:165e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl128s/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl128s/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl128s/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl128s/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/flash/serial/S25fl256s/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl256s/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl256s/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl256s/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 zcmc$FcU)7;)+mU8qJWA@Z_+IE5_%Bn(m|z3@4bW`0wPLpBGMs95s@a+Tj;%n-XZkR z0|W@27d+?Qd+t5=`+e{C{(0FBd-j?&Yt5QfXD70#Ny~EZaPkwgEG)u@h=~LM4BQNk zCN^SXT=IGVK>!0kA3&c=$=bo(*u~o0+>C*TONK#EfLDm0ONoJpj}O2v#HGT(!_B42 zARx^33Jc=p7vcc|iOn6%uw;lC{`Mgz@^mq`_|1t&n3#zB&kqll@zsaH;U6#_9v
2G+#f5XErgXeE}{6c(xg9!=!4Ud`L99h+a49%gI5G%e310Q3^~3~t0o=T%e0=8E z-4f;(H0Cqq<>eLR2M7xo^O&2N2?50{c!kUb%uIwVc!hCQXctj4X_dPMR8;8XE5PGIYGd zd4D_qw%v2*NX4G;+qWUK`YOaeVP~XPpbk4D{f4-vp8kf0XfX+7^~D07llZlpIj@LP z-zN4Yh?y+e_?3d*_UVuS~rrJlZ!r#Am`E*;&n1J9Xr=%p~gW&vP9yP*41{|HHhRTC$9hm3&Hy+$I3bwQ|>M{1Y zwM1(%-ksk1wk^8Drg`~%Hu}>?;~(G2!1tx_O>vqf1A&3{w{PAa%G!9h?#^eyy}dNk zq}J(_I6(05d)w`B!#+G~R)%td8{9Y}jCO;>L|AYCbHD%e``=dcM;uWzwloJZ2w;5= zYdWvIoXokTj9rcG94)!7MwEAy{+*qP!*2XU!J@v3I#{j?v6+vNMeJ&{% zN2k95HOxVdZZ4+S^#ZPt|FVGJ&wmIcQu=ubt)H-tCW?o3)Y9Yl#KuE^Y939X}X!X zUg_?Yi<|jB$xEAqOkJ#5V zKONw=(*K{e@jod7n{EGBMf?$?|DgzhzbZnI_iA(avCehX0DMI2F9B?b5aQ><+CCQV zYE!wdya<~=u(Pogu=Ri-cIH)I7;7p3p)0Zeb^Wn+05_ICFCT*dmgeufFaVnyu(Pl* z03RO%HX&Vc!qx{@Jz>E=pa56xp}!9o&GtZ%=XKvj31^4ete_FQPISq2+6Q(5 zYcbCZ^zW<2K?Y|j6aj+rt>fBTb3f2#n|15--`vScwG?e#U;Pvoi-?~$@VQlea0b%n{VriYoXU?bLXnc8r z?_m^FbQCY|Q2H9_L5;lfL*GQ;?KYyt@l<{xh~R6?aY+1@mGPJb<7ZQ;49aNZ?1mrm z4behkp;?~cL?o%v4Yx;_)O7;bfb0QQDwt<8w84fw3omoKR2TADOI2`L&HWFhE+f~| zN1vBYo?d==R~Oe1)*>3QJiwAF#+LR=`B`6$atdZ9gqMcrdAsvUYxdTTp^5XfudU$6 zlxq5c!FX#)^6mQ0wLRDRa45c!9S7?v(Tmd5fhXiyMCS#s(rVt&k-g(usukfHvVPeA zuzSNbaM4=sn`SRW?UbsCLG;J<47c2yfRUf-w>Hx#%szB`<1{zB1G(?Z&~n^3x4wX_ zzT!wtr?arZFWs>|*i(w#Mz(}t^U8ZEeLOe^`1r?%L9Wyd!ih)W^|iGk+;0Ky zl?w(i0}?3pM)81YXl~xZgjJAcqx383<5w?t@1%}=ea2!=u`_zSXf=O0d%JE+*99vLv{~2wuHJIxaDUcpEzF*}9u2+t) z9jvd;HQ1zh1^G)9{Z}#kXK3KzyXv*cr-E-6lUk zJDr@rS>HO|t5V26JMj4IbLLWap=Y?h3{h(y8d6)|bxQK>9YgFX(yAmJNgb_il#yH; z#grK;LTXm(X7`psv~*uI_V~q;*pIEh$M0S45*FM?+P7b*!o+=s952^%)yH2#3-Y5$ zV(_<;mJ|Z-DAxVqP%F**v#RgsFY2)l>lLetn@hCTOwK(I)Rx9A zBsVBar8N2NM{i_6@hL$~BVokplyAC57Z<{tiSS>~^?d01K?O^|7yZ%kt)wgF+LIW- zy+`WAXQl5CY(9RI8nIpm_q=^KrYobyPZfK=^L_d4P;r#*vrWca12^5urW-|N>8#TU zMw;&#jm0PCCMr1@Qg8&HM1J+2UgEa6|A>ciZ_>uh{N_%p_olzVR}T9^gXj2pMb6h~ zckF0+;7_!5*v4H;tNQv~%aI*<4?9#k0<=7oTY79y*2vnVpWS(bF_F77isn63+F%fW z33JRQTc1qkJG)JpWD)o!_$h`n+8sB-gNV6Bn zadVkaW-Ee}VOh}-Q)&g%3hN36$ykj8hA3KdnU_C*;ajmzQ+YQ}>{}8(t7#m6oKPW} z&+R=t7-@I%scNPw^GUjQXlJ^w$Yifiy?^TY<;VQ6kH^-HZHmviEyG%WG`7WmFcH@9 z5Vk@LvA;YpB4{)wXL)$vJ6#4GuEQ+px*d6)t$)}Y@2iju6N`T*S>uBTVw|?0en@t| zSbuU87oU*;_m**@WOlr1uqmQa`z_^sICpTn`t6cHWoU8GgpqiZ)P0LA>GwCR+G?E| zRzlk)A9XPuDto+`mn}0n_;5qE&d7kM|30%mU`X@cRKalW+<1!>&zqMR_HW-6{D&3O z?dwkO!5{PHzW1_>xbepHxhF~1f_exN2X51m-cj69{Ncu^bh78*QvZ(k?T(e=#`v3H zD-=^cyC+e^=y> zgHzwWe~?`K-a{KcFQ5J0Xz1&lX3Mg*##&M@kE+OXsyF>m{&n)DsAh(XDPyCW!O4%q zTNSFLmFl6it=kOKOdk%Fj6eR|QTFg0lIpzgaQ~P1li~c~{o(wO7d9vOO#w{-`Y$VQ zc@RxJ{i>_WG-Nsj^ly?k{u<38-!w%233>Q+C2?q%uAG!yBvUf@`{kkWrK?5MhbBk* z@|R3$lUCnDl5=n7T3ZdNfijd8B{&3}O$CYWyBs7IB+fip0$3iJ9lq=5q4jilr7HL# zrO$v(L`aUP^0V2LSnu6W zf@lFd<4?5L)o&==z`gfEejHy?8vnkG^oJi`ct`DBWmRQTISWk-NJb&+gLntr>#IVg z562=?$%W)nRV=>^q3BTjd0(>i5N|XzYK4E_~5=t)=eBd zB8F>sad^E7I5|Wa3Fl(k6o2YY-#iOTGa!t%u6v}^)xf=T8NxBPMvU{EQi$+zY?(`n zsB_^D!BwS0$`r5cFRX#;WE;EJoy+-)ZPMzHJ}bhLEkqG-{7ar#roPDJ-nCBA8l(Io z#FQ)KF_Qb`K*+FlBD?Fm`r_I2{XF$98{Fq>tTmEPxY{R3EvtcSito|aa5`K^MBko} zP{$Gz3}rKqRLj=szIJGsUZzWU%>OE!<;g}~EI|Ob6l+oJ+Jl5F-OSI{)VK-t=oF!E zlO~>@0%X26Hoowq9}xX`Qj}b;_HDLr=yOk1n&jCnM|%mRmN?Nn&xb|5Cl%#`95~@c z*Bka$^pd+zakzJ3w6LQ-$k8{iCxR5N#xU5y!2!@Fd%FEqzu*a!r2aXo7T)eUoxEq{ z+{K$%-1RPTowca&2VlKeH&v;y<%0z6f+6h@+RM}ONq4Mw_QR--<{YJh*YjJWPlpNI z${uRkUTTv0nUAaTON>=knik;}jT8Rl+{4+cxP`Mkh@(+TjPRe`=lBvs$h#wen4dkH zhTlBFXwCzNGT#&=g?%<#Hgd^?Irzf&b*^1Yzs5R;`^<3bdA~zaxF1LSJ0V9pt*bxXPddA6%|@aWcr}f_PItlsq8e}R$T`vZ+${9hGrFe~ z5M)FkhF`>R_fO-H52b6*=Wrn4igX@vcxi1gQ-qw&0%|K4_vwUW$$khC## z2YAHoa}7vp7{E3kw8MVw4poyJ&0WSvvdr=#8o{xQ-dPXUWC=d0n@PCb77lwW$@)pI z<5q02i~8*c8S_^6lES(Ms7fDf$pj7PuNq@(5d72^mi=Sb2^!<(WNt9Y-weC)^o97> zFmCyAg`;4nK&J?9WzUz)_l~7;c|IgavopN8lN?glQqY3eve=^7Qq!VyFT_k{?~zRO zpaO4<|FF#Di%GeYaMwhBWp9;lpJ+QSmae-n>L_kAkj7x5C0Gnu5lrD= zL5IFsajnu+v+2L!%Aj7`Sfw9~8miBbFy^Lk2)B}DY;MqQAMX`vJxbc04!2z~Wfjm& zC`*h;pas;}9VRFkSM!=CC?+cRNUkuh$gD6u{J7i}^V2N<&FGDd#~TE;alPhY<7;-r zHSu*pkVptrYN673L6}H|4T;zHq)(r-$!+CjrOP(aHU;LkN0QvqO-~I2{GuR?-t2Y9 zwiHu3t2E15BcRDe$T2hhe9dn5*;8NoONL94%j}P-GT|QwO(I%-!@3{B+3ndgIljcr z#1XO=>A*^x@)ru8767y(^k#}>3&acf3N{KVbfCq)X3ZrxD?UxRPSKQBS>KxSp0t<% zO!*pt8{J3yW;q8`EGt^KV`rGaFi0unu>BIDZofOYKe}Oi>kqR|-{TRh3q5x>c>cbbe41 zSL5I=zH!o{JQs&5@3NoXf;DI`Jm9~1NaRq%H=Q|cJ1sX;pOvbxY{pj(xgTIputm%{uu|*H>oFrgpp;{Ov7g+y(KzsDfUzGbd7xGx z>SlfY^PkVFjO-d`Zsgq1X^9N(lxP3Nym#KwiM2tUVXI-mfxdyz)zkruiI~Y#lfzcA z$b+zvcHjG_O7~cGScU0=T3FiL+Lc>C3!ufI#d;N|muf7V$_Wa$U)rgNrAf=bRG5r* zm9k;`qUfP$86y=F&jMBXnq!u8JICkqdg2dN@i>AUmK=Mfn!0|sukQ1nBJ%Oy9F^)n zGj@FMJd$GN;bQ_Zqq%f4^5gPLCZ;zRHpM4YK_;LR7l-9)Bo#LOJtR^zh_@nsi@0mVkHPtqyek=)FBzM#m)4%^}__Zq}#7Lnz2BcUJ|Ayl{D?x|- z8SvGM$DLdgntK84`hcg&SQCV4i7>@?2zJvy&3J$pO4xP7ynfF>M_R{k0`mHUP3F3! z*Q;ZrW2Q1`@%)SON4X~8){?IMF4AXy`CUaK>5R57`Q^%J?6VJD%OGx22P~=ag^GeY zWN%7xEo7k?2%TFaoVnsAbMq3Ku&2K@eAsm;;dbP<@8MJb$gj0n zrKWE=)kBN5aC*voG#gc2{M2XUaAeiyU_C?t*S0+0Yo=iJBBQ;?@+UILzzaogD`Oip zdQn+uHzRH6geX5~IhZ^c6O^_eAAxT>uGiP_*e}lG+NFc%PL*4e`-llh91uz~cGF_Q zu_vlHS-5%^36+V=iP4E?NmfZC$uE+NQfN{_QZT7zse@_H(+Z)q&@kvpx^?>aSGlj{ z8LSy`nFN{cnJZauvf8tSvU9&teGB_`p5u@+_g&+AORivU?hl$DQF+($-164)-{$uh zNEcKVauj|odRP?p6X&Pf&-G%X;?ZAj?n%0kO=%e~5XDy%BzDs?Ic zs$Nz#Rf|@a)o|A2)H2p4*FC6kk^78a5j(8yA}lo2Htzn}=J}Tl!iR zTRYlh+nU=Y+v_{TJ8C;cI;*;bx+=N>-Q_(3J!QQDy=8rXzH+!Ays}@ozj{Dy05&Kw z*f=CT)HbXz+&!W)GBEmjbbRdX*xb0;`09k+#O|c~N%=sM|)>^*Jbx|FC0yY&e`YRZ#qyrm_4*VJjH|_Q67Ci7CLS}(K_k3J`9QAn^czO7Qc=`WY zWR}Jsd&Fu{wxdMB7ObD`SrZv=k;VKpZ&G1kd9Ho$hA4;H&+&Wi4<>`v)*``qWikc& zc4Z^g!;qgg>Kg-~{gjJ2(u-BD%Cm9kKIutv{(-o+%h~XR2c0drt*YM~`G_k; z1l`~1GvBn)w=q3mI}XlK4X3@7I_w2;);?i8I8_a6KHcchK`x+|t4{YP(B$!{Cur!B zPM08Qn%CU;c+5(@_|^+_MHjk%qBv}E>cxD#zUN|%2F&wve1goe_H@vl+yIlc?}0k1 zB3mpfmAD8-Pc93e$swy0XU)mK{EA;fR5h25y)Bqpm67_Yt;~F1`2$l?RX<9l9z9#X ztY6nLBV27=LG98S;#X};HpXh}N-B(5M_j(I=mT9&8TPcYfvuuT+gMn7E34n-befkf zwS353K0W8<;Pk7DgRZZL`}^f>&7aGmA`_KWv@Vl7$hd<(}QQ;8f+gWLCU+NV~~i?MERD|RHfTV^fu z^{&N$`@>6n%5m{Ru7%=K?$ znuruE3SzU${Io5c%hU6(b=jof##tsw&&TazP#e8wPOCPGXMW=`^}AnpA1A;2Mfte- zIVEn_!*o0RuE%QSxaOj2?l|UbYVNq^f@+62*zbo!-@CA>ZC~pGrf(8<;igX$#|AtX zz8*`8vrLyxL(oO&@4}_Fjn{QIJsfxWv05bVvXGhz&N8!_3hpw$8W4+!x6Jfh7%x^u zQutQvssA31TATl#dU^_8SNl5`y2s@2_88QFB(Y)7y>2|l;@(XcBZ_T*wUOBb2>s^}9kHyqrII%hYdot-_c(IoLE|iZAuXV-y z?>$HtBaAJ&w(ON&ixW%kzjsd!Mi7gI6RE*SVjXdoU#Hg+#5!JE)_cBoFLum-&pzFU z@G%0v3-fM|Kn+G3OOLZ0^!)g)n(yscD9&=u^Cx)AL~6bSv4Z}4p!BnAkL#~@={>I^ ziZ#St9(#UFtTs!~<%r)ZLB!wRN=^=?PxNkTwbNx7#@LsFfrUauV%nXmrz z3A#kD6l&kgi@LXOtihDw6@z-{_VNO!D|n{$qTiv&Dl(Vc+|ZgYQd6N@Zy7H%!Rvbr zcRn{nr!`z-=&{X8;}3y!Sw7O&F&8z*5si-Wi7=_5@$0A1zICdI9bt!+a|-|nkD6!8 zCRH|409Mf%4#_J%v8OoA&&$V9@sc|jEtZNPCG$XWPG8DsN*`x}9|1oqf3g)3o$}ZjUH}QzxrGAuK{~@sX_aBsu-NfT(>W1mL3<%mCQh?k3ztyW1f5VOl?f8g^cv$3oYfPya$=E51Q= zCfoC5;YeiEFd%_brf!mieC;eLCyfVD zbtCQPrPK-;vDvB+9Q>wCTXvYDM7=RUU+O$me|R^oX?=2+>#%J$G^_7!v5XcZXV}Bh z>w=aDfnYu+mpMoYU~T&f>5Izg*YFCwqxuk$WmxKe6bN>RL<}!JMH&*G7PJFBeBb6{ zHK>Fd>400%@z7i1B-D%>2%gWpin_bqik`3(gdzvDYCoP-``z;wCaPNZD%s#`Qwg6R4T+1$ke#7sxHTtgx!r} z1E-NiQ)GST>usf<#|@QhK;kx8?aeBZMLnA|fiwbB=x9XcdR60WORa3B!9L7p(SSRW z{OvNQY5iE6OE=WaXKm?NboHr6G&g+WBRdq}6}vX-?)*^HPhy-;#gx+o&t&ib;r|w| zQq)XZ+(NA1uiz;1S3RALIO>)*8M?E4^z~uob{ISAdO{FOAA;Q7H)hlCjZtKbg~R(F zf~e2m3ZBki7*D4B>ft|dLh2f=e<%|_f5VG$I=l7lZLe~E9efp~RM!7z( z#qw0Yv390@;5j8Ndall;YnODm?7&|56mqT^0rer9B^8oz$Z{yLaV!C#Qz`>CNWIPi zwY$;g#PHC>)$_Szl?w1%1ZlQoacw5u!w683q*TU;1wsXwNps#21uk57ShLszYO`ts zwb|4z%Ymw2pep{nBEZO9oBr1(@f;p`7l~H(3`LmUN@Go77v0(PbH5MnTl& zxUtV5!nqNBy#3! zstJvP7NlJ!KRjPPn(hQruR7+~8w1;`@p%{ZN!#3BwuiPHDjaF;+8aqCA1UHKBIvmH;u`)v9^((up4VFV75vsIonEuaF&!|d>9dp3_!z=J5Lv!2vN zeu-c3A(u0Cg&*0r+^^&MACOVMdjD**i`Qbg$~q;!F4r|?)nL7+zU(K^&UT4@+M?b- z%U^O$mhaE%=~-9}!;sXt)wl77(*kgOwW^y3`{w-pNYvLmvKuEGESo+yX3zLj$e#uM zLO~`zT&8&OM!AsmO`a=>4bj1uL1#zOVu&vKeOzzJ1>eUf@UnRRXQ}qCMIQ*SZMr=2 zWE>~rygp7gRTr)S7J`c%y#iE5*ADLr3hsQ_e7^aOn0K_Dpy)bc?7a9Z{0Ct`#HK7n zFN8#|zJVK zvAThHC0#Gd;iy->?_mQItJI$7_077N?#poH^;Q*d_v1429Jdu1{LYTfO&8$W4M!#z z-avz6_GKxWvFq&DpxiIf#7*ms+R?aHqPM?#hkU464f zF=ol1wj16`(uMaTb3{ZV4#Qs1*=h#_+$QVJUt#e+7jRuWcuXdB>0y8x|+4B1PbO&=r zXIg{C_p%=6ts(>bJ`WTUedEbe-05gp(b?J5j+OXkLw~mA5}z$ zoGFxoc$VGm5ynntGc=9pN_P>bf%sawN%FLDTM8D{Q#q%%@gc7CZ}uL&oLQsl%WtyH z7$$LXws7AUbF`J?mb?;Y56vF9ki-|YHNM$5b!EEXYO&>@?CI)B zD|w9l4Y9o*sf-`Xn$2@CdbCKRL##mGX=2WF`ZIy8a!v*+`{rE z;TE5qDe6AlE|EFGYf>|4wpbB-j~r-wT35w|&Vy&SZ_i4LvT6sQJg97nip8B0E!Rb}YTaTz8hG@IB_eq% z_}j2Q#SEE>aG&-p+;P~cXwP53<3_63^`@>TEY(Ry&G(>V&azibxK3yf#%!OK=cM%u ze#bTaToQa(6MQsbEzak6=ho`r4SJ{v(}Iy*Z7yDI{7QM7dxYmf4|#3gs?4)R$?b^D zVd`1w;rGU+8`o+BWhJ=j7Kv&}lrr_nz89w@s|1klke_wZ!sm4h+k;UBQF9{#y^z+r zV9OJ)UW|5~eFj7e88j1uIg5HMFpFw=tBGDqyjTV0$1{BPVT2}G!D-7Jy+?o-YxMJo zc>8I`GKV~?4cRl&h3%Qhi4p(t4e8vOqXI|UzG-^M;(W23y;EKCO9yc#p>27J@vwiy+L7H_sNZj;3m2|{cORuf0z~kHXVS^=~ z1|kOO&kBSElM1)_1oRs}UW#?;g}+S*OY^e5V;*Nn$z_8HnMmL||5RNS#!I~u*a{u8 zs>d%LD2%D%@rDxaQtz#<9fgYf2=g2CwSz}QCd*77Q9&8MuZ_Hc59u*zP*Ho*E??-x(l8;k2zo-s84tt-4S6!{K8DTi z%)CBaq?@uj1=F(lwGX60+*fQXj=M$;ELQ?ce)_?2SHbR%N73=;kG*Qb4yW6Ds(7%b z2a9#@(rr)PG%f|(74nfl+wIf1vbsZ#L0>`J@)2#&eZlod9vLg@i_momHy8lAnK{hl zGwCm}8h0oW5hKxp@8$N8r7-sa5a~QB4Nluj zeCItXNCkz6j8vx$RjXSBnxemrxfEprZAqU_`c99O-9CW0*bMI7s zts?iQOAZ_JkhORM<9zo#Ec;Gv_a>y1O;z^D#o=Y%$(DYhqu^b#>IJ>C8V;~NJI}3M zscF}RTY-}gL@+B6X{!T@vgC?N&wIe16l?hidj!t>26h51r^&@bNkMjFU8`W zRwxUA+tO0K**U`W4Uwj$Ku~BL=?*ZIPQRaciV6y4K_GKKF1cq%SREhBcs#mPDJ~rW zQjI2H>Mx%co_{PnI?_0@2RX8z);xeMQ67+rH!h}STAZkOxYtqLqP@(qf>1&az1adA zZVSNjZRt54ZtA(dcQ|=RdX%;8QJiuMwyI*;Nf2N}j?vgAQgJ~beF^I{!$fzPqadW- zq7b}kA?TDm+X9YgnuaA>>`ByCLrWyr z6p84TTN~horJ4P*-b2d1H!vPyAk$$}IGlZQ#D25JM{HCEZ$gdt-JG495yCw(p*tZD^{0Fy-9VS+- z-txzRwsrdb1-~+pcCt*hQmivf?6@lLgx7rTDbAOghYU_YzB0K7YOmk|00mKi?I!d`)MCjj*(}HaCQoosJc?_k<8ipI z&(^tHyHum5Io9{)bbL0_d;_U1)He90Tyvxu+-G>&;#{|~2w_JVQ;ii@S3C;?T7%W| z#*W^ILP}{wM=Wf22?%~*|ND_$m_56_Ho6s)t$JGT9B68*{Ym^jtmTK-7L2ieGWon_ zTLWztF<>M8hA@ zgI3CpK=NSsUr~t0m*eI+NC2XuxCg~~P`z~FHw2WpEcfk%cmkPCeJ?@25_>Siz4N=o zV`3TeuP%B$E;I-Ipq7yBZ;mTza+4RYFSU;rp3p`MPHlkF@KFYC@fB9%q{l&Gn2r+1 zffY5g*_MDhoi@^EC*p(UTrz@7b=fLA^jh0DauEoglz@*(aS^?_b-Np`MBRDMmoq8zxoT31k zl6>`kn5h%fQV{`k@Y!sO3oD;NI(>g~6t;z`4Va18thiTAZHic*VdYbXA`k)szbl!w>|{a?HdtV>z>doo!t@ohL9IHVqDAF(@uH z5bXqAE=e3tx9}RS_(6&2*WLEQQTSoIS6^f8~&u8w76EVIEYv! zLp&_-JoS*ZuAa5dS|6kOv7MR93~>M%9s*&%)$&dml$+x`ZQSd(e|p9yUNneLUvGsd z4b!0YB9oU14G<$8x!WyG=CGF;JL8%X-APX&3Uc(b*Rowy)!gbH(l+7X`UuFw$ zvhA+562juowoNFphpzF0li51x^vz>%c=kp7a9NbOPt7H5=_)vl6xcMex*}2OP+-*NzQTUY~V)gL6q^N{NXiU-(YO#r?3FLXMhVglkT8 z)p~kK*joA0o_(vc-d@<0ngVVoO&WRlc5Ql@-P2teStj0|ib>G#sWB8r6m&Q#dCBUO zyk7dH9~@!N4(ZXS-Iy~(Z|)O2!hH+JcFabT>Lp~F&y$-zi-brV!RwO{BZcMU9%r$t zaHY|(0~THSWb3qQGKjB1R2JWbhcY)S?cVK!uJc3#esp#FY2uyQ>p-*1yD0EX@lKY- z*Qt^-Kb--5x;856U0lJ>mxWUMlsodNwB_DVYedFDYTjAJT|>K#i35QHQ>Z8JIpgex z%=vQR=S_LI`<9yoC-83_3%k~{InrDGV=_$u_uEnEbeOuu|uu{X~R&v z>RO)Bh@&2%88?gB%N(E42eZlA>jQFmjk6woqjbu*sTN%q#vT}qduSe(%M@-r5ZHT? zq>I9w09Lr65oa&LZ_ALJ1=n;fQgj1-A6GXcwfhdt;lI}Dfa7cD-~Hyu)6gd><;kdn z4uLOj1`}u#x~y&Q$lY0k(;81fo zcZ9ieaelGpSIIsVF)!3D#K{tEGI#wa(jMSkSB~o=fPtCZDY=qo)I+l2XJ(@YuF4Yh z=u}GAZ}rO<0o}79INdHRQs}}raungKL|1=S?%U-jffN<#6&Btk4vd-Lzl}>h!oV`ag5~vI>j}`SR4dB5bYF4g5>Fn za;Yz5EFwBXd1|A$!Y4Xgb@4i&3YOoRz{FbAcvNJ&js>Int+k6;Fls|D5nz{C;3R!^7U=2c;Y3+{5OtJ9?H6UP z1g{cm-=&Ek%Stq_Tfx|tCP^wM)uTkf!Ev7vy2E5E%nL(x6r1mh9J~;qQeDqbKzvHZ z2vi@~X}H4$PRVAKhM`&rl`f&R2t8jALjBaydhxhQLF95OY(?f2^TH!6TfC<9G=Gfm zAj83z)3Ppdz-I95oCP7?F3y5P6P^Ldfd=q1_{{cXb4AfdR8oH4nSuRYl4bw0&S9{^ z)Y9E<3TAiI@e(clUBl!vR&wt(r2?327`YASQ7Q#KUlr&6WF9DZH{O|F`vV24RIV3c z<=8LU?MbJ@I9Z&sW}*`XuB#~=MW>Paa2{id>-}yo?v+=4qrx$Mr`mmPkrkSI^Yy5*2Q!z)oF&U0&P<_C zZRg*Zy;iVs!|YptAJOpnCXnu2UM76xR+;1em_&G8f&0^`%e=>hs)&c`4}wq69nL^$!5G!XIp%#3i0pR z6rmgx7`;vOECm9cQhi-Bp^f6%6z}?_nmyWUEXP(1S!_EaW_g}ds1z32(kei(%~#$@ z5#rPAcT5)wSBX&-SKj3z9hV3b1i}G5Yn%C??bHj-y-HJckGa@iFA;>K`lS-<=RZ80 z$S_e)sNPg{79p*K@Dri;GYeoKxd3v^gKecH&hbt$M8?Px+ZqzgwX4Ho8WxC<9mt?Y zHqh45%?n$f#XDdA@Y`w4*`a6!he0Ahgk5f`O5w+a#bdZSnHMELF;D3O9&k?9hdeyr zNd(<^>m30(XJ1(3JH+2@WIH@adgzlrqj5HBB@hP}X@`4zAYh?}Z7Wj0?q2eV>Kh(b znM(V*kkBjd;cH85_^R^uz|q7&&5Xu!u|@CVJsSN3(w;DwFbZ_h9PjI-;9BQ<3!ZG{ zjnVVGdkYy@+|QxQm9;X%g#GoUUR4nL3Gk(dH_)3}w22fk#3h!zw)XjA!eGxenoI06 z@2H8vPeInnCj$@lNQ$Ah)5Z}qeUp|B0saZN`&#WBr<64I^rm{{f*A4B;5sn>Z8In% z^hi9+qYs41RP^a#Gf6#7JRM0%YvGxKjQN?(^Q|Y-fulylwrSIbUlqa7lY<^@c`!tN zaYeKEm$S8z8(!i1UcN6J6L${8yImu7NW+H0SUdNXj7Co#yc9~$_~2rT=XEW!ZxB;r znm-xQ?xaF%wY$}(OG)&ZMLEvGW!B>J;x^jfOINC7zdkug`8pp->xRrzbjN;#9!uvDbYR@Q1X% zMTkOr?=FtX&1;Lkp`&CC4ExiTYn!mw`)5=IE4u;c*raq+G<|#5Sn>5miKONp59EzQ zZt{?!M|EKlK~@mQFu>=ZC}v3Ttz81rU9k?}-sT&OzGxdq`+6Ap8t`>JA6Ej$A#PQt zovZ4%!X1RVh*x1823}l$i@3Og5kWj{8I51gegYwX5T_S%qe35@<+SkBp31$4Z8@B+aTY4--n?(^r@hdQ8g&Y=!L{rcZ1V} zk&!e$JF%{fanm{9qyq}aJ))<5RxogY%>4 zSMeJp$M5jFCf=juo$LOyczcfFFYa~tng5)}-bu1u_fz5tPUy`Z{DvQi2foEdunaQ_ z?0_GN4yR~!zlaw95)X39{lIgB*haLRL0{%$q`iaeg~soWj}cxr33X2MkjX0#J{5D4>jXO z|L|Rpf9##~K5I>#eR6G1>yq9t9e!SS@yocZNB=7Oty@nA^7Rz^es27k?Zhvqv~OBu zFG;5FEwf~j(^*gWj5-f5`ok<6X}&L=r+u@f z|9Mf5o>hM4I~03-qbK!CPGOU6%Y4!4B|hfTBYlmB9W&z+<_5E;`06e8*kX;ne(*B( zaUOYZijO&CZ1^mC@EtnhFURMl?wz#e^i411{>NhP80|jm`z?1vdeu??itRt5VIF8E z@gnwTorV5T_l8OrdiTEhJ9iI~=e~NVys}I`kzqd(uWSqF=ENU;nIlX3o+@AGJ~DGp z!rt=!B)zQjvC5p%S#&yUA=A%EbpC!y_F?}yKKc%R*fVt&zB^T&^MB4C(mpve#9r@1 zv^uknr$h%vV{LWM_qj#?h!Z#ty$ju|_UN<3gL%x|<0Rhrk=*xAMPHJjM3~?;xBN?xytI{=C$&rUWvh^_+Za#?E5hK;P*Ar zXc+w>I&$vmf!u7v+@V>-=g~sU#$7aP>}SuG&fi6cj48=6#@%9nry~c}YPau8wzVhQw7q4Ur}Xcl=RL`r z;-l}&9(9Edi}tr@_-2WQAE3=KbuYCH$7oLfu+?Xn#f#1vNBhi@=*VZ+vHS90@9U3f zIq)M|{gczwGI-_`t+yBp;@?$I>VbTKH~pU3V*K<~K146$bL=9&JQwNH-ixYTp#>v`{7cfMn{eFk60YDkOt4$&~xszt5hV|2!MYg*1z*PZ=&>AYV%yq3-$ z%lE-avdi;1@$Ttq`KAX;WgUqv-(%wAd#C+Njro2=KPY~Ai9J3TMLS9kI*=F8<#<^~ z+mNwX#(U&%rZs+g#ADDtSo{%g?eXsMACj!z*`wZlA7#(=l4YRdMY8BG{vOhKVmd@$ z-(!5#Khsh}%;`vafnE5|eFGiPanQGWh?jA+`IF;Yhdw`DYwpjSS<`cp4ByR0opa6) z>D*N|f!ACch3+Prv-UZ2>iEMw+Iz^rUh8IThpwCA>{!rG9h-bFJ;%p5()XQPrai?z zH|;<3&%NiKzDJ$)T+ZdqkTT`3pUA;AviqzK_x73TuqL?er>U(Ii>! z!OVnTb^YUgy}hq*b(QaeuYT0$cl~4isH?pH^L_nR>Dd2L&;F|4@c3DuU+el=*O&Co z`t?7?tF%dqi{&ya5D3h*0y_X3OBe%^b$~&L5JDhM zVF_7C*ajmo!YBZRW9O5?M}+;^U;P{WSNt+N-%d{NEFz*`WOY?mR#sM4W|qwzH94d9 zKkWYJIi69|r6^~fn>XV4N1PlF>N;Rl?)`4JkGTcRaW?SdBOQ3>I$pt0VeXK#@$3R` z5&fp)knL^I_0!J7_Ahe!oL-#g*QHH{Li^qZ933d^gJ;RUL8s5KvpelFWcrM_vEdHw zxwcln+rxm_rQhw5vZ~gWcaLGDpv%qkwJ+;= zpI^HQYx_DSodMNHjAd>3J2S3R4efUA3hg=2pEL8F*p2l8&xmc-6D7AE z??mh<<@&o$AMkZC{oU7Z{wxz)tK{UD9s$O!l9OL@a(wMadH#*TIn4iFcV82DdnIm+ zXDsbrXDi-cUyqdB8pZb>Yt6)sb@EgHmXY=RTg%rx>&q)j8%!9QsT|ci!?Dn69>HDaMR{lu~(VD{fuZ;R4p49>C(V!Ptjs20YVLyBwo`LW}x z6#CirHV=jIqAU-}4WX5bysZ*9uVglfoZRAB7VX4&luN(%^#F4P^B`*~{?qpuLwt_+ zXGVXmyEgY&F0_*lZBoXi#L1cI?3o9dyI31Belnl3Ug5q6LaRRa^{~%Ztc7NoO-i9X zUL>LQ7Gf;v3axxA<9#-tv3ZU=JNgsjT931JF`u(u@oNveeX?HgF_G^m)}O3VxG&~- zAMa_i;OxM+UAL3NIsUC#cKUd`bh$Rqlm66WHllC(`i*`>-|2B{`P@f)^o5pR2(QFu ziN$=I`E_}gT&FvJy8 zuV?5pzCKPJzvmIm4=sNiaO12&c?Y{3<$dclK7zS?*4Nl;CiI5Rb%%$KN&emrhW7XB zOz?L-MvCsOr_Wo!0bmT+81gtPwcIh_A0}%B@NGMbZ-qRr%X-fOJ8Yg{ zrP1}kkAdgx|G3HfrpMy@#s58=$u-bjs(S(&Lzl$%-W8ot9V^jE)ww4+1-cG4IHmn*G!A{o zA?vKQ|E_16*&b8f$3Dn>9dxhyOC@?2{I`L3u#U7(U~C*?D`10h<*DiV8{mIOAnO+R zE&^wP`5FUWP@io={sD|%MSm0Y93Xv7Jzu?x(I)h5Qa$>jGwL(l(Mm;6^fdZq>?-uT z44NZ`J{8DF9)T>n0iGL5b8Lkjw_^TQ%-;i^2l#JdA5GP%4bbZuYp2u3&!F!bWFJSn z6Pg%10-j@N=g8Y)w{fhy4eRd$&u`Fo0XR7wSpNxaUjSb_N;r>HsqFK(>X+EMiJq(I ze8luVVmkZ(2k`Oh_o)JOi|%^3Hy`#mD3bd=2rFpbIkv##+-KAwDWs>8so0VX1_$~r|L^p(6o&nME|E# zK9HHuS8Pvd^d{Pu(7vSYhT7~+;4}Q+0gj?Am;`=}f5A=QHErkpClqOP8tdHAxXrkc zMb84;Aa@PudhAusU@zKtb#9`#4@m5~r|Z@bqh*Y8BrfE*th8+ZIhDI1cv1IUQk+&A z>pDBZ_nyj<{Z^v)F-LTMUt>iIpRK}YtMJPd{*^{=Od-=fUQ++ewC~TrdwNIn{T&9q z>*h>4T*0~zf%|~m<89dEOXxp{_EPL|6Yw1TA10@gvd9CeLnYti0qv1<)-M^pWz zgnJS|gSO>f?$#RZDXS&cTD>4O#43pmz!Iy0z6&h1T5h4$WJ|0LT5I`qnei+!9>KC` zzxkTPf_=bSSbHaQI;-{HxXoW}b8HMXZ^ zY6r;|lE2P@-qn1t3i~fdpFp3FfRpH#I3e-+fZ8gun4D-F%l)1;-Aco_)q2t{SkQ*&voZVM zY;>d9X^Z`jnZ4GT{-X0d>tAYp+d^J{3*UB)xo^OxFKc{?HMZ^q-3YsV0Q}zK^6xZ{ zq;_XgtwqGAuK|;=>22*R!Pn)!##6ZK+8=}GRpqN1%DCT&&btY;Xl840JYUb#!+P&Z znpcl#j%omPja#ok*H3I;*Nje@9J$wrv_7gvAEN*M6itnm5w~*Q4{fj4jo!9+@mq^^ zhczz7uv5PG4~$RfL*SJDCx)u#CQr}XypL_~LN{w2m+1V5;JKu_rzV?o6OGHBN{qY? z997;tPLom|_x_R9ag**m84KUGy|vT4=ATZhh_CtlJ9@t)7bOK6TdtBhau=d0x(iqf zEC%iYJAeg1Z+>Z}LEZ`z7H{*KA(zwCvE{%Mh>tbRFXy8Xt-JT(|ESjH(l>yyS%|mY zs7d85`n24S=qGqF%)Qy4@482VnDnllXa8XkZCr212z;s(yZE#(4V1E8rl&_)kPUzk$HaCNh=C#;m+@;Sj_9g6aN@Yr{kl06` z&i!Q4?m>Cw8b2lc#Bx{#T3c{n>SPcHhIXdX(m~2dJMFYXOYK;DP+PQvcGPNT=;!VC zv-vGQgNVgx|M={C-~GP#_U+r558wIN6cgn z4P;$^tfjNs|3%Xn)IVvAK~g(CX!p9?A0bk==CSSH^*C$w?f&UIEM(te`n{vQKa!6l zHXMy<&;L)^dL~)-o!tjP9!|U>r$)x^)IPVF9K)aQLFPNn>Dw$#uymWo{Fg_n&(}YXZ$fWp=#apN^l5 zzIhz4j2OW>K=(vXT^Gb%E#_IrEl8_Tm; z>CLC3c_n*&{{Og7foQua-q?LWZzi-q&7+#Pgw#aMGm+Hy(b><6+6y{PEcZ=k(k_he z5cWmSE1K`@eaA$}xR^V+P98oM|0rEw-*$-Hiu+G_eH+y9-l*nX@oDgR_;)qj=(v6!NV-mWSMsd_mh#R}Gyx4>J!HRC&f}M= zE_e%P=UV?M)8J%$-udI}MCsqq?~eGZAxb8Q&mmijH}LE=5aQu_`>%~)Y~PP)Uzp3M}VXU#o5Oi*_##+jhD);_JL@_|XfNKZ!V^9<5_+E9C1vp14g zn!}hBk%mo>pS3<8e z@K)9FGWlK1G1J+fPnu0Wle%5$v;He%yz(gL-Y_~&J@#Gje%m9lwyu4el>KTC?Kj>%&;5n8^L0@h;(9v?i_f#?D~8-5T|xzvc9E82#?azH-`{==`O zJcm-QqmKfQX3=&LZ9BaIQR6A?NA%@9im6vdnZDGkBrPE-JYN0j5e2oq61WqX3QPx@ zX=gC!KaQ~obL>*;b@?A5%(W__k6G-?;(98d%m2AV*n`e9zk{_IOt^QEu8rFlnT&NF z`|@a`D{X3?3Nznk=)2HF&XMjZt$Qn({}Ks(^Mt&dTnwnJ?&D#?x*L3}(RbSkNs~7~ zUxw~KLDvC$Bwdamzy1YdzH0Y;Sl&VZyU3Ym@Gkf>@LkB91^pZH>PL8UodExPYcC!4 zGUOEWPX%v7LeE*8T!hSfz+WN%E^q<9D$ZM(GzGp>Lncy?z1Irf> zArF2n=gwd%{Lg@&nHImaXV}IUbIy_<;o5&asFmc`n9n~j-!}Mh8hR%sTfPI`Gl=EC z;m2#xK}?{R4x1tLWx;plQ{-f8@M z6ZhZy=z9l!KLGs==*2+K#$+ev`4Z;&FZ_EG_RqqPi_m!y{D{TUnk?Ds3rE;QsBz?^rJf=)ZVb1E045r081?3<1WP;O;2&&ZoYW%5mmx zjsVqslOTH$hrOts_F~@!h$jsLIY7vM2YJEeY|Sy6%SRcl*Unysp!6?29&xbqu!7?X&e2P2>)|3Ex{W@1^i*lYJY-W1K|U0hz79e((n%yAyuw#=p&w*$4VK=mF3Jkl6)(KV-D8 z6?hK)JD~R*u)^l^KxY@`upjZ<3_lLS-bVPi8!`v&+!F0r%kgg?=qCHEw$ye!>aGxM zCm|N8R(_|AQ3~{vp_?o2Z$*qs2wMJa`w$=B5%lOxc}FZ z`>gthffsl_eT*`ZyCvSk1WzW8aA()`uK=C^mYARp(VBXp32HB`NwiMUy0nJ&lxn?P z%^2y~)EY?Z+bZfbQ+6c#76H2dLp=Xs<_8@=$3$uh?bCeW>bg=BsUK5#Zo5%7lk-U8 zKi8Ma{&dnbPd|q;<@~SrW(IBQcL~4KNZp;CO{8)hSGQ!-uKJososfyVD|9?PZ@C;J z)tjrkkF%(oOIhcutEtL8J@v7Gamc3s@$|>7|0&=VV6HcYFcyx^2j1g4O*6r}#O?p1 zjQcLeLHES%=KuR#{I_Rg9M^CpW4@4mdIsD(#nrsIjE`a{p}gi0_lD3Kw~~4aclO*H zu`A*1R5I3S-an`7>S$Zxk@Ko3CR{w+dFxAL5c!0Qql?)96L}lD|9W2P zIQM)LIdd&0*z+M1d0S}RqGu?S$jN&due~yG@WwHNLeRvy?G(@hmryoaS=&g@qkgG^*E z&o;q%UqD}UPd0F^>$$#lw7rmPt+wYd4nrBg5uDc~%1r0KYOY}o=ReVOkUOREnAA4S zK%3q)b#ulXM^#oNh2%?7&vz%^1NCqj`QE4_dy?-feWZf? z0O>FN$PYpdJdpel)YXG6e|XAdj5=`wnuhUc>c^rPGaAjvS~R!TpsB7xbIVY5Y?$04 zLuq8VR7(~45pt{4kRK%@rIvi1jFHjg$4R}6CEq9wGM@Y-nJ5#;H^~&495{B*VvKs% zA~XvZpqV!p%^kDR%$kX&Wd@pQ&1k0HrjFe%Q{^@qnJ&|$nfw=|MP`uyB5L`W@!7v+7|qD<4F&VmX>+ zOVQkapE|Zg?w9*$YNJooK%C6q@Z{NAu)1G*4_nvw4#`_V|Bjud-Ijt}1-? zJf3-~Th-N7x9;t#*q!c#J5&WCH0DKH$b+CS@j-;fK*T3O)F%Z&#YCK1F>y|eMiUb= znMn}@2T(x}!9QTc2|zuRC*=v96Ti;q69rj21kK7mB8+@#{ zKY^3S$9wzJ=>9+1+n)`t1fS{c&!bEKTyK9Ncp$jHx4#^GDfnV?(5qZq#R2!?MwjNzdN8^^vLJQO_Gf8?7uIy~Il-$qOSNN;}! zN3lnH`@1-LJ>J_-2Tui0_V)LJXM<;Y`-R~7;JM!Ze(+N8VrwIzFXR6J{tT&qd{|yy zU0$u4L@!QW1{G&GM~EjTC|1kG{III4vQTnwwwN!@WkL>0!xy^}U1z(lKx0fq;zN%F3yPBdRR*%;?| zcC_m3W$RP(_H1>~e+z!%4xZsXJXzhtPkG05oR7tDKoTw{WRb*Kbyms!IP=jIjz(N? zAtj?Beg&mNpRy=4LQ}$IlsZO8#Cc@BK4VjFLvLd;h*{{27LQfZ5-Nn^lh9I2@ry_j zmt|I29>rOadtB#vETrIEa~5h%=+1E9Ogy242(1P8v`7u2B+WZqUKfNI?FJLCche|M zk~UU3PMd!U9>w|a+#10Ktv1g1AIb)=4$&TiWeGg$s(E_+BR@8ZFz-qxK8o#nZxwS= zqy>+?V%()pe=3|#oE}zX#%>k6q$|PEA#+VhHQo$r4Y%-xz`cg;`&BkI7`wuW(Gn#UW&Em5Aaqe<;v5mcKXSCUT zyzH3T&1(42u6En7a6)?|lZ|UaNFrrvIe;T1w~}LvmipY0TlP;yk&A}8PXt1%eVQBR zTsgayQKtz}8kwuPmW(LD7e01YzJE;FFphx~<5H0-dDMcjIV@9r8O?foZEL!=AjZM6jBKx2=xw;ju=gBDBi=|qm97^|5hXC>v*;JFY67mm^oj+ zyST^I1J?LKiIloZPirX};c{vpo=f34x7fC^N=G7;=8WaWQSQ9ehBt`ZuF`x5dyo?4 zBbFk`6rrKdKSYm@MXUvtM#|*e0`-Nfh(TSPj}+()5!Hq!F;#AOXD*Ct=`68im=B5! zNkLRxjIF@ph&5r95s{>c16O&A)yt?Imx8wh?+V_xt#qA^{Lh#z*H_J~8(_EW*xWw- zAfOP}VL5UwmeT6I>#@{5mex}4U5n*iOy!iNAyQr5aRX3agKD&%^&Y9OgII|F2x3sO zh4`XMJR=YarRnGfSSOTjX0?ZieQ3n5gP#WP-snRscD)X?we@g~ZC7cx3b8?P+dDL9 zAGT`J$!6bQvsShW9LP^Z2mEu;X}#-v-kwdSG^T7~kE6##ja)Kt)Z}&F2|A zHHr%dkZ4n7M!KpPxUw^}N;drsP=u;Yrw~C}RX(>Guc8HMYU4h9`eX1DoZa5K)ud+S zCOTWc>T5fUWgGFLt@*N>b9`M@KwUZ7@CI)--Cq5A331g>bwGzSl3aOsoPv(l@cStf zbzMfa=0%jmRjREav}q}0W5O6qp^FugR>1epB8`}FWi;OLwb#yLN7_j}JDY2%2RmHc zinuX4o$gg}16Ec}$EOk1kP%c*ET0z%N0`x^5p;hIzuI2m0_x;%(W;j?o%VP%yJteJjxKf4*gMeeWPK1_B|&^XK<7$55qhy8AkY^o+bM29m|aAWSunFYJQnF#yqJ zn1fU{y^kw2Gfa3xB}x&H>1sD`{rY?GtJbgEaajHDd|R&b6Z7O%_N(;y4oKKqsPe1q zf4i3nq-ZTT)m3(vA4eyzV28ihGO@maqI7q!QIxg`+o(#{Vb1$=!+~l$;(Du9RsDkG z$N@^YO7fj-H_|TKM}i~ysr1#T7(lhtSrnBZYnhKr2n5>o29|6rd~+e;{W)hg`G3*JI}q zI=@Po9^uAeto+Bj;ZZ?JJaRZGPOi&w)f=;LIP6Zl&OCl5%`z|32DSklcJ@q1n#lDD znF1A4$|q^nRli=L}U%ZmfUV8S@#aXjvB6pUpENsQlzL`fy)E&Jhy-zyk?DhMZ4 zX*yR%xHA21JRZkJu{49oLnl?jndXeTxC^WZn2eK0lr*V?z@}Bh$xYqAtn2;&GS$7S z{kVy^3z)pWH7-$WT<#iHZ*C1%-Wsfi^VQ)$gTG_`SBYqQ;VTYS4!zEgKym3T)(m%X zh2g;pLp)Wx4xd+Fch&Udce0?POX}+#RM;R1RTt7Yk)WVZMOf>TJPzNCvA9A*EXEayiWlZ9wdvvSb(z^UYnN$luN4&=9Rd7&)Q7bXtbDWOb z&3lI5$B!ZSyNv5cTYEdaX>X^23VstjiQKTvi8Xe0BA6{xL*qdkP6KX_C4>H`NX+1x z5D%4BrGw2gig5*1hn#cq5gBE!%Iug>BD+x<>ud|ZmN1dXS%>Saim; z-b4THSAw76-RIU?eOvE8Zboi-t|wZ(maSgj>by@K-@FjJawB*tcy^s|7Mwa;xX8U` z`kU$A7OT2&*MYC=c_E|?xqN6iD9WLM0*nS5bIvzLQKV@tM}(&;zi{ChSTPmC9}WkD zNl}Ij16lS@%{G`2#HT>er4-uhO3iaOfbX+M6V4r;tvUwj+duP83v$td{0?e)$8qR; zpZQww0>0j~sIO`&IhfTmG+Stu_jUV?0v=R##iH#9nyK1;EVXIciwJ{kWifV}k0y!} zoGTJi?M{cW?%U0A1o;=8b1JoQn!vLS&T<2tw$M5~7-S3qO~FKmq0)lu#3ja*kZybo zHKMggeJyyoKJ&Ge!+Rs=K5iTCtey|H`b1iN`Y-GJcB^Nb?VizKeE3T6duYo!xV%rU ze9Bgxo0b`@kZo_b_};<+pWUoPE7!8$@_qHh%W9eF{O9vuM}?Cip{Fh8Opmijrx_fc z&S5XIEYZwO89&jpoRUxFbCgHJ5N~j$bCS7`F_*V=Ip(Rfixjmnd&S7eokOB*w`70n1HT9 z={70&Op?#y0|BS0D$k$O!@q#Le}trSI(X+2$7U`(dQ1FjpSQozUa`ol_-!*w4c`7f zKY8a{UK#iQAW1d+lU8X_Or7(wMZ2NfVWG_!pXOX<(P$XK(_JU}lsPL5_-TGboCP(yh#E z6$wUx2wn`n4~;yxthPDr!i8M;cbZu{-}TOX8AiI_19t&s)!)2-Z&c*Nea6o8(s*>K zlTkG&29{$Zo(A66wlr60W}KhwZ;pz|u$*XAG|C6Vbjsgz1tz2zY)>o~z8@2KrkBx= zw*(&xKDRvKTpXF?3-kJF(S_O4PdD4%-Cs>@RjziS)sOw<&;D;LD?He1{L^~A4}P9d zYqH8nWy;Kv?YvV^N158F!&1o z3Ed+Rrd?3`L|RBnb(VsgyF8WBV6ugzmnL9++?(;fwisJ%jQ2h^#@_=?pw;C5`xF#e zzKkBi)5&UX_?N@@Y|6lPv zj&Waj1GqnZ3*6t=!u?W-{9PA zYV%bV^A|g_i;)J;x`Z*E1CB_EII_y=Xm<~MNQgRT%59Ke+EEG~8|1;6ze5hX0^w7F zYdl8`4qpv^8~n7rfo1)^Mc<1fSN^(c7z1akj!x1=(M&H6Zj>2`hXm0Bz_PAQHk z%v0S|dln&Fjb{Zwhw6I#+@P9IG^1j38Y(+Pj8SewW=WbUSSE0Np2c~;V-utbV0|{-&ilnH0*U%4Bdx|DpaN;yhaNXRuwE; z$rz}X;0ekibQF&$ogolmI+$SgI_6E`zw7|d{P2&#pTTL51dq2mDrz;EwRf*km!``X z7aDUVT*6#+_ZPCfxB88j@!E#gEA6lR|wqj+RR@-%6**g3i^yepFqqnVmn|B^nca6hr z?NPc%if(et&FUnVjt6Kipm;Lc>?jvG(1@^GP=AcNwIW0@L(F(rSN;i`9N~f8G0C zHx}+zES$>Ct9dFpyO@2|gw@c7g*HqSrqac96k1}G$_FOkD$*tJ&NvvgunLw7$c0Z4 z7+Mr622U}t;1h{pavYW>w4ogoT2Nn`s?2qPOI7$v#aYC1!O#WY+L#M$j$(pt2UMcd zqX7xv*!(M{LJhkx>U@Z~{=oal`xD&z%Qx89Ex7W@{oZyZe0$ZovM`HKT1 zlX_CeK#l?Xf{v-oRg9R#D=>UG%AJQ+L*pom`}E6clofX9gSH1IOYq^?D$4VIVGt=8 zcZ@_J$s~w5P4FN0L0#-|-qv!3T7K&N@<~VB?b^}}PuA<|@{^khQ1}WbFaTfyQe-AH zB5C?Nf(`0{p^)`BN8%t{1e)@nq50vkmvDAB!+nSMo4%&99y~ZQRK^z;o0kpyQ{$A_ z;pPBm`!lp-l`Su3OUJgiOlvDA<+HUNS?o}6?fl!5^S1vjk`AQ!EMavmXdpF2!bYUX z;aQ-iOqojpbdC#~)JH?3xUi{JB)73mHnzr*3>bY?Nt1E4bzkt;V02KU)C@R;up)a= zs3Ut8POPxKCaFO{$Z1w3)W&7cCgUigYO16KyxN+h>kq*VzXmgWe%+zA8VL_Euj^vz zAtoL7!Ivx@%Gv2c7RzN9I*w?+$$g_^)2l|q{!!W+S&egYz>BG{%%!X~=gtwj3gpSS zAMkjipvi71CH2GRj_(Ho&Vl=J92(R)Of@l_4bP?9Cn^wpjmV1%4kM&Y@4%S=g`i1# zUOgZ0oN#d|Wi!4L&0Z8%P`g;#&F z7f)&?I#DbTg6rp932@N6&QF8g65tSUrWOJL*(`lxrA#22*d~mVOL?+C%A$1mfYQ@C zGq%5b8w&=1HuyvlX~K$wnPMrYG%SlGas80SCD@UL2O)4wd;&^F!~a65S3_F%z>XQ!*EpUu&}?AJPSI$zOk z``Z32HmKL$fqVX#Q(9d~+N6r9@wgJy@bqLal3_9yRQ0zBP%dRw%2;wL9Bk6mNG918)d0@UW6$~7VeC|dD2L#C`?j_&LL4M zpel1ANI+hh3Swo!IFK?%OW0!S0t%%?0S_uvR7>C*^YdDc8(ja-`*4-xQ1{YtEg50% zK^;QQTwdd%?P%Mrzvjd@P0{NUlBapt^C>_}cKQSwk{iPEtuo()^DC;8BSN2UiZt!_ z^YDyCl4x;tS22|9mvVAH-z==Hx^o?0|I_<}_lCE3WcJJsb52;3WS7kMf)$n@G_^*(Z2X3x^jisr4b8YOhIK5qUO6F4yg=$uFFr4D9+HJ zH~;Y7_KsH>7PGJRs+Q&Fh*+Yf#nGa7y=hUG=X;7;ikY$M(tJt;4>$=0vzqyPg9iuO zu!{r{@W(z5i3#CONQE6gng;CPVF_CB!I)?))QmW_C0%d!uHW;1;l1f?uWM}QcsumF z6SW(#P^TX$4b6eqt+N>HgwS_#i_uqhD0?%cZGeqR&Tbzo2Aqc5+q;I|I(O~B^P=nj zV9S1W^SqBg;l`P_lc>b^!Hyu%XKqXWwNpe1$z>uDFG`?SOowex@9`#YZc%#!8!T;Gr?+o#{@JTd(L#q#x>0m?3kF3$6luL$~u0b$Qv z29BgKVoqbU5cIK^h~l=V+poY=;qL!m%k-kV+jjG-!+{(kOcnLR;Cq)J%x*Qc6(>%Y(n?% z;u|4U9JAsq%Gw7|S62yt{TFP@ODmajdEO33H=Msrlar45XVne!FZOzo!|<86#pY)G zIYu7YW9TDQ&LKt3&^?*}%eke_;gG?=$pSFm=75m9grOAS7IH`FeI=EmoGh8>}o!%WH6dLV)kEh+8hH%6WBgU27Qx`O#UmicKunU7!3 zcc-nkRk!YS>x(+p>#l$QTm;zp44Ct^yr)1U8uHAnz2y8Xa8N`d5GFp<6bXoN5yKe- zbPE57Fv63k1+O?7oX0ZWR;>Q^QrJyMa-DVj`_6Yg_cOOMm)+UT z&Zaxr-6WgrH6+>C=2mQ)nwTabL~EtSc)^suRHU@}E?LkE>ij{&zDIy{$s1yXX z3M#(T2Sxi}Y^80A4;p{pIcLr}lkQ}vYV$B;X6N$1{Qkd7iLKVN4j*HcoyqaT)h%3+ z{C(3qI*oO~)~eV6)+hrPYVlPCDTi-CG4cZoeB(h%=cjppAKVKzWf>B{CRkF(E96(i zCv9?UP)oLjL^~Tx-0Op8emS>yA_s3mSF7^}D-bkcjnYsC#c2gYijuQDK6_&|*x+dGyd zzZ0{AOTEPQIW!23>6oT9Wc&sq5ur4(KmNcYh#Hk;Q!WDZ5FPsm(yEOvSUq?D8~+OSfx{ zUZaA7Z7+zIH*NXe1u9N)O?g(^k${zn6_%i9XL;kJ{+ps5LXyIT#zta zZwEGLUKrrRM$I;iDX>WI<_+>2`1Ym3k@j za;^?=VvNu1Fk6<`wO5Br!yoo;N_KpD!nOEJhg-haZ(dcn`lW+5?i3*l-AEHag(Z!` zP~GW5>fM7AeAoW|gh0pCYK1Z&gp)2jsp%lSiSyfEM5)@e{<*RHy-~i7dVU?trA8K$ z*5a|o@a$Ghwpr@$KGSf0oYABj9AlUNAU^{$^BkEQ316e5xg3pY9$Zg*@BjP& zy9Bq&PJ@-1k3eI)n;kX3U&*D_AY?EDuy# zodo-$Jf(#~bW+qd#+(>_UAy@=@;mYb3BhJLzoxq~^(20DczeZ823tA@JBMj8?PyRB z70VLi5W$R}DhEDzD4P|EkT~CRYRl@CnP0olIDBneTziYV@w$yvc+rY|kP_n& z@*%H;j|ael6HczhOwx(NiX91Y(DLgH@zW99O@bQu%XnFPnZx5S4?)JJ)C?X>YUb_Z ze*_ z#JujDFoWpR&JoED)GgKTz)}L-4w8?khL3y6I6CVMwx!@Zn1k>z1*KeAK5b@mhM%0} z3x~8e-Vc8g+57fja&>|SDlS}V@1s~8j@fM4{GIYnH@Sfe`2ClY-(M?GHdX~l zS|d02%y4a-!Br^RwuSj^uYRe#mQKEwD_fUrLIO)mreaUA0XN?OZlz5o$&2JOWTIf4 z*&I7-DRxTe7(z;cpy&PLhe0A1n3Bt|_K0mvyR_|ZR{aZ{xmtL=yAkQ|h5)Csk9ydy zhs?qp&v+4txv(xE=YesAF-%ZA<~Yf!F>4om^C$9avPn*nOSz7xE+}&lw_v@j(uNu9 z%{XPx4Wsec$4c3W#3^fK&+l2KCX$MF)e?8xo=GgOx!TBSH}`RqS%d&pK&rnMtyp7% zD$(r2tAd}CjSxweQ%8g=yb)Gx8*(4?-`27PFjOm;GSL=7PI(-1wm1iK zEbvs%FZ3hIo<;_;gOGdDew2bc@Lk%e*Agypu&L|h#|alKVj^QCg8p1HZk9S6a9ZYj zd+K@_R?Qq%s#5EM`>R#QQ&KASrG1+1pX4qVuJUn=PZp30a!B1@i>sVU&vQN3akN%b zOwO%(CSq-UHK_9zYhu&FGQ%*ru3c|jmVfjrEktMJcF zAFXX#`J#|oLtK(anSTtAC%5f~K?8koLE6uyal1+C9;ml87%e-}1kEYJ^%STQMebgV;<_J6COG=_y{OgbL{e&`DfkXLy4`LB98wDKGEhh;yWNNy+QX;t zNNKzI9tXDx)-=I}Qr~N(zGV)3eSv%%i7Qv!H|Woh2T)I)sT+m|?{n@~KB6HALMdzh znqVL5G4&N#0cOK}0GK#Pum|Vw@AJJ6DQafkx%qGMTILxKZLf&wZ*IX9gQ{LD-#{b3 zf#X*sf1q!P_%g;eC{{o0F%Py#(Py_hfiHB$%r$AbbWp!-p?+vP&+7gs`9*@2yT--J zw$;Bl0u!fiU;fud;@}gv>%k?vG5a4Rvp=yt1C^L|F7;IT^YxsslWv=TEpK5W-vW{@ zjGvyF+J%he)Lk$rbVfo-Y#g()+xSlDygm4Gv5qKT$2(ly0OxUiQn^jnF-i&wfbC*3 z`QTnf@}7Q_?B&#$dwDaR{dUBL+%a4G?8sG}7^6Qy+Bg3N&V4@F**y6m`PdjYlcH@k z?IQE_y|vW=4<}lhA#x){WXe|Qe0q%}krci%L4q9o-o{JiU3c?cKjC;tB9h7g27%Lc zN?o{0QFWQDgqk+us<42^0E`sXRw9ni#hf+TH3?ys%{%vnzEo7hJG*wBiSHJWaB@go zt;M!Lu5jyNDCKIsp6sP!bBg)f@*#K<%aWdiD`j=TQP4+YNSs7LOxeyP~-NB zi^M#PJCL`y*+OG~&!_fQg|P62t^crHb+K)oW%zvG`TowoeQY29$B7-=iJQc265DN> zwpq1iZJJhv(N(mxU56N&R1gwF>ctQU1QLkdAcVL>;tnwoNUa!?h6EB^@FT9+6&Fkh zF+kkxf(>rM^By~Pf)+LQiS7D(&+|U-^FEI)8}V}0)|Uq%b{`@Kym#oG{*WY#U|tc8 zN+#pUY#jKUIeu+HFcBcZy5w{XcgeRp%C=KKu!X$#bL(f|K@}eDNIs#yPHG#@^zlfi z*3-`2kK>>cXh=Yx`!|LOeFo+`; zuEZE2T$l^;5%UNC26k^)?P*VO{>|LH9pBM3r^jFUe4$`FM(DWUCpjs00@yMsW${@*6ZpVSsPbHOh}yXCGGW|$PiK6D zPvbBl-K_UrG!^d4hIv9#vN53n-cyj1!YOJCiy2K(|4-PZ9X?C7h%*CtKm}X|3CAqNT|rAP;V8TQrjC$7`MwgMuDAM8Wv>mS4zw_}D*(y3f)|<} zgBNj9wmBSCgpd&64%K!6wLM0LD$msXPhmrB+b|!F~*MwlSTWpFnW~q&^V{5mu_{{|_7O!?2 zhTdmf5e=Iyi|R7a^Z!~uNR#TMF6{2Zv)3nQQ=XZ+zr$2I)v8AZqv}eL^Of0Nm8`x| zMSeQFCHbk4aT_Z$0}*JUwD2w(idCm6?W~U~eJ(o-k&vpq#>B~|Jx-|%f+}p{;3&m>6t2 z+NG5S9D3Nczqh_)ty+UA4#Vzny0>Oqm6UmXa@`pxTbw?ghNO5NZISSO_!sNVGq!Cs zM1VUk!60>MbCE>q^qMhSL(ZzwFU_?yg;5rgSilxQ!S{8>Uz_CH}L$yV4&?w_ZTHzAM)9EQHH0$(2D2Qn#~PcU)vO% zdqE)W{lK7;f*Id)tW>K$3~&94)jHxs4l(bH{oK(kP)Ohfzt^hG$DF*nwh4I{B6n_M zBS4FhxHLC`f0q#%G02MCNC*({lgg`NoX*Wy&*NS{hda*yxP^0{FyapDJ+_b^ioKz3 z4K_x_ch#TXh;lD*6@^qQ^5^^3Z-CDt{huesaxCujtQ}Y4d*UD$2-f>41|XY>d9gRb z7bNsO13VSRe|+&qlvC=@_w!!nEM46d5f-ZYH7I+7u2Ow09{kmM5A&Q@OX)exu5GQQC;H8HlS?`=&gb&wd?imOV#kJytu{|^f2Cp>x7ZubV%!GpYV_%_ zj?@~_ovXp)T2;fq_NA)!2g<&>^zbp2^}sQaz6NICOkFje9!tVJkfRQ`nXEp37mYbP%G8SwYg@a zIa)fswB0<{q$+>1pE>a)&R@^-sJBz|Tz_2La4zzDk#P(Sb@#qRlK zQO_E`i{B-YHxUenP=OG6y%KcALzk0Xp#}eyU02ttw&Y*;y)VUCq3-zi0u^oJm6hB+ z9=G$ZQT(=tg(oSY=;xCAzIQwKyl@vdZ^84E4%?PF_?z_~sZmPABAF~TyYJ)U*O|gbKoUPc zn~}P$CEwNXSu&Ec?7a9QZa*S|o_gd5QC`{YLhM9tU~Xc-GbN)o5w{Sopv7>JFRM$q z-?PM6&R_Mtua(DvUnizn9eWPyDscMxLOTG4qcE5eHy;0gM(Nra4;;yc&*-3MuwY=0DYz_}8+dW3v z3HC=DbNHmj9cxh!dxe6G{>OH;g*cLx;kul2>T*t1rK*xjRW6-d=blbFNp*U<)3aD`uWaE!xVo zGu=!t6EV*$W=q+6xlwLsJ6QraT`<9fWiR*ovR7Cr)~fZ$2cHn?0%rUKfL}$(!NCiX zOKLhGKE_lKpW{r>emA8DX=jC_Ivw!y``brH?cfOaj-gx?QxcW{+Z!3bH6{*Qfr2{`B z0U;a1K^TDnZ#WK1jM1#lUE#`?sVb%<;_B*smwHK4vn?ZGDbnmC1;_TP zeGci}JzFy(a6d@p2N^8e`E=^^7S_e8OVFE)el=%fW%jzN$ggl*?}R|)R)jF_QpVYz zh5v$IRG>@EVr-hA3)Qd|M%Wx4#kxnmte5l3`AVL1Gk}y_T&V&=*@Jjy)W`(cQn8Ex z?CKoz=E*sKX-|0uK>qI7NDy)#+#yTkMbFh8RlUt&J-5t1IQgVwVX0}jV4)PNY}H^` znlk!sC6GyH7renSIjA0g{u6&TS2_n~-Yq(#iwpATV z%g_~lKZ6LRxjYr+M3yCGN4EpW-2=Tq+R&bge4K@LwULq$<}RE~AZ2YIGKljA3tH5v z9>Y$;b7n`lBV3OaKj;m6TjTBV&B?7vtaz~~6+J)g=lunrE56WQ9)!b{&5f-aCpVEN z@Qnnel3p&G2Lr&7`lDIFw0KjGoPE9towJE3t5+O?eLA5mcTfp!E9g5S~jeZU=YPc z5x%MV5*m#OCtliBbSysC_#Kga4{Y+=jD9WcNO(G0LoYG5{(he; z(-jgTP!c>9x>&P4+1ZuOBjbwcc;{}!6P{cc>*^Ipjkq|+NClW$_kblj^<9__k$+ag z%7UvCjNXw;Sx0qC#m^Tw^M16{Zo{NH@bdU{heqeMBMnP|M+i9Xw^BAz4%5&^9jd6r z!pSyM<%)SHvZVvE27~F2;aKKFJvcbvnU8>P|AuU72^+w+7vdJE5uLasN&HlhDih5-v1JOK0?s%H_JwXl&Wz84S@+LIVV2f5QW2y%_TSMuR@| zPv{xj!h^VFC{(4LU@2JXj=F1foklIgvx!4|H*lBSt~+v9-E}f1Fpo!dsLRbP>jIG2SGXMEbC%akUAz#WEjJk~gxs3Nlt*=3o-q+`@qwcaQja z6IR?OO?Znnp2za->o1QC3%xZ|h-|VD#MI(s2>Ee;uJW?y*>Qlf&uApfnNUKaeNQ?2 z0J!pV!MWH)4a>CnE($>v?V=YpT)r@s?^x0z+rO{A?zNV3mzTzB0ee#-=#;_VRqZcN17`{Lp~&WWvu0y!POAkFtkH zz~E;Yb!|ppg15U5LEWc(t-A}y^?f)_glM;+(f;;WCLJQ~lFZkYD?`opvH39)PE&7pp7X@9VgN&>1egacK@vMNuN7YMqo_P(Uq z-wcTy`YFu~Q%6kc*Y3z+&cm`!h=Md3NqVsI@ifZZBbw!xB+{8tP4YL(SSuVxT~Y-f z`iJlfXavs)C+AMIs4kYRiZyM{ng`9pX5>V=s%v^hU(^B4qb+cso#AB2-Nz%aW)#c2 zld0@MJ=osb;ctOxu^faVMs@;2b?f-O_ zOKcn06^1Wo=H5FqcV2wV3`L6M@GVgkB~l`X67{esS`sB$a%8&?JGL6zaqQHv;zyMt zX_GW{yXhuC5p>@Ih1*5DXn}6BDT;QH76qCtTcAMEO@N}^v_R8MdhU#5O9mo<#84aw zbME=i|9@vG{}Z7P(TD}>%t?1zk%_!3hTicv=qu;!9n=rc23c}Mi4?7Vd9}PAfDK;vRMiCBcKo1{~*bMFePVWeHaPBGQnGW>O^1!Pn<}*5?VCK!FF7JL60N< z`Dk70xM$C*!B&AU^rORM7f)Ug05eOt_IL@B* zUYv;FsV{bk!iaEfF{%(Ez&JnO&jA(0jHFnpH1ENopdcczu znZW0tqK{Atrg$E$p>ya3bSdN@AaKULD#garwe;4;_Qnp|Wqa%b3vxb&_9Ad%=W2cx?{1B&R*wIXbmx8UF0Rz_Z%!sgJ>USDh+7wq#DBPl+is1eX($ z3$NRAx;e|`L?t2-U6K;?Ft{`%$);ccd2A+w{pRoAwXc{Gv1Ljnd{xt|ge;`q%vH`#1Jq z_HX%j{8#;h!E1xB4Gssd`)~Mf`fvFuu8m{`&Hp2j4hI@*Nk_8VGvr?D|Vzx&GBx?_viS2o@G0(9y|d z?eyp!TTy7jFok^b3dIl+PX_%7h%DMZcovz8`0W#<8C>&!10u@^GwmweZNuwl*(``E z#}%ikDyG0a;5@95aK?!=9yM-HMipI@oR~~mnai%93E0z1^AFuFA-4r=bZ2Mtx|v&8 z81b-p+w&&#@bj4TL2X^$oiBNsN=3+EF(Tm1i*`GkHzm6;S|7$`j79jy;);y(d*?JJ zy8P3KDu^jlj>&1_!a}+y$4L^4(x&SY*Ui8i^jJm-@WTJ0KcOrtpb8Lu1GUi#+Cn$N z^aj`mLy!?qZzt}?^YKEw9IwQy5Q%jVcaYu%1OtYN>?xk>CA}=kl?tVzQ8C6!ZONfY&=#ZA81MLhfAUO8V#rZ0vIe+ol<~R9-=Sh_u*(Ub@zK>RBxD$Lwzjz5a9}dBj54BH0X+bhjA4>6`r2-B1z)+GQFMw`+=ZKWu5!DU&-~b(hAb4O|{;R2o0PW_y|7m8oet zy17QluzzogV83QzqmBy&qQ}LkVNMV^BPp5?p%w$j!jK|VV3ccY%EU^1u8~TRNI5Dc zYb7d7V@aDOQE9ZH5h3KL1f0`Bzb;ViMS2u3;7{Bl86K494|W0u`VA}|Ada1gCpO zlBs6Gimj*<%~uMQYH}>eE7o&auT(4xpkXIy6FDw6R4@(r$UHUbqzy)EzdhZDvCBJz zG*(QqP+q#o3_=dg{a~JN>i2K{dLtjf^&!Q=sv{|d{uf}E!op}UxZ4`j0OF&|%ZNX} z2i*P-^jqMUELhYm+6n#5>X*I%J-}%`ZpIZs`{dC zc8PI!pX>8mAMlPmf&GfZtRR9CfBYMbef<4at0}Ai86-7!6@*#ma^*EjpZygy`7tt( z4W8XX3t^9(iSbIU(wLa4v?@W5VhPhWN7AWutvS)0a;IHhn+~%yS#Jmq)X1yqJav_z zQAdx>1z9}m*y)CW7=PaAtPpWH9-~_AtSP*|$erb~Yp&W4?vp4s?0lffL;c%_hwruK zlTvYkU}3_dG|r72l)}+;tn{sEypXqfMx~uX)UYl8;*|N4RC&(tPulK!vzF!k3#D+K} z`e(amSL%cM`r^jou)baA*_1#=L{(TelLMatgPx!35vS&y&ZN%gv>k5Y7{Q6ad9M8s zUVKIM;ce9H1P9Xlok|Hg5<*Yszm4{Kk9xgb?nWlq(&JvYJJ(CIKP&ufb~L8E`=Rhl zjo?Ux00MwA?huXb!?#i{m%Av;!|7QXy96^m%x2$goXchrh8^eMkn4X0c3Va3kmtMT z-GD<0nK)ChlF|RuT_(ScWmOozZ@Bl(^JF_7|h5gB!onZ1rm)Y&VA3B3gJlaIoB^z z{GD^Y^ZR0M%!?(`W9eq4Rhh4JD(mS%dMiCl@1_sZ;Z~nP1~CLfGjzjpY-a-Y{*+Ox z)GICMl(o73++b&8XKR0Zf7jV_d{8lidBXS%g1|vU0gyujH38eIvo%OeBAuR#MRuNc zF5s>829k|h?%Ffq0d))7fN*R4IMq;L?JXte1w0*F>C|cfV|@x_v>TTy^!k-Pov+`X zluB@(q^{CR^uyO~L6)#HHJxKfrc6%A7~qzbgo{l(^n_lH>9~;zl7>^4`b{&DSb!fC z`iu(f^iN>?8hRIf0DSz7C?Q$8ty4#=cUqlx=T7IebHDST^KK_hNHbblFW+!V4(x+w zx7llMtZuFz4v&VnkKaB%J-&PVVEAzOc=b!GAC_N~sjB0qVZjzT`QjbU2T50!yMy(O zgZ;x>H*bIS!{=Xn{z9Mw9O@d$3i|%PWOad7Fyq%%9o;TcK9i!KpRw`8o`r9o* zfHoIc{7unSB}2hPaV(uBrZYDAWw1k$j>HV)F+TK2Vfv8B95){SgiJt%60|~TdVyu0 zqxbOARFxLc-ZTje5fFxF@3h~-Wi?_U8vrTx%NCX zKYMK~z;%5uxFA9(rW`Fx>cRQZtrZpEf)cL9n$c5T<{CM-inLIan9q|;+hE-DBm*bk zk1b=a;XBDD;pfLDzeVTc84+#?s-zQD)Ojp(ye$zCd)7M7t|(StGgd<1q6717i`J@K zB>a}36(%Qb#ayYSxooB6^QjJ@1Ea`Lf2Lu`ga_*6SxKF0XSm{22Q2GE9D$XR%%@UK zTAEdj!8t=Tl>zC2w?R$B*MC8u18bGhDSCh&qxaDFq9lR>>ieGU+vNags&%k&xbcOJ zw>IwC_w9%FW7~{sbH>n^QWHq35f(7812;N{(!ai8<51u`JPYMI)s6uas7I%@UcbRtJ zxpcy&7ywfkmFsf`rMxIk{YuOnJ<$-Lf&mO)0iMeH-Vc52wkRG-x@PQ!BxLgwGApnQ z55Oun)H1`%?gG?dmX`8{f)%$&-~BQr3X2#pDVv24HPsr^j_GR&Pb?+~)mZ&Ow zAw9KKg;aPs$Fg}0(S=jLD{3mqKs{VqQkbO_z3)jlZb+7JNS5KFx~jI_gm=t97a*vc z_WG~rA7PHnqkVK6ouRdeNT!CB;cTPY*oMi7h$O@2S!n&4&dkEh&de~PE!Y!Vo7=3P z&Ex>N=I1&bwYA8NB1R4kt`HjB2rC8ZL51*rJF=-OhW0}D2Oum6Vr13r=h z{@D&YQPyq4Uba_kKI}rIF3(K%qEMNd zo}H=UaQ0o=RJ7p&Ke+6-d;w;8?#kNq7eO=VF>;yq{2<(-!5@BN3%tfK9K-BFKkbSM zI&LtBELpEn74`+^fRNpVq?W~OLGUDt!+v({g=T)56?k6u3Fd?%$C9Mt2n4;}RQ7y2Efp(FHls>jbog@v{;wQ+OYj(c%Gz83Gt zg^-yUnFX4ZWV+*Q*Ksp$)-4)0j9IxVw^rM$l$mSLJFv?v)8>5CWH^?;IDq!aWyd4; zgg&ZO>#zmYFlXeW5e~bEUfzH^SGck~;q5z^Kd?^k@yzlv zGZ+A9L@F{<^tQ!thqTe27FRSZ|A^BCLF8F(2#*aFTToO%#tc8(a2PILBDzT|4F(dk z9u?Fu=+)9_%auhU{~{}5LAFFu%EBYQVvC&2dUs8I(MuWIGfPr_&C z-mtyvM^`8E1wn`deLh2~yoGP#TMzG_J~(~y@agIMr?GHaj05wa@L#&iFAF<;=?8J%eOyW4sFfmDlq6ordl5r3V zgft_u0l_R`!5=V-Y(N5m#EOT+jvYuK%?cI>1Y%>(t#bRpBa&~m7eNNq( zc4nM~^~Lq;^aj02Z_@`)_nto9da{)yOoN#~6c=abfZp%#?CwAMB291H-<&B!{2yrN zI>;q87!~Cd8dCZ=e!^Jg(ooc`pMerCqb?6jpOh`t8;TQ}Yt5bo_4yLGJk5g?&=SUa zYu2!)n}!w7s>)jHVROg&M)I|fS~9AB@1u`C)|g6Bmg8K7=_L6ua$;VsERr!nrVid` z0Wx6!GSfGdtj6@7oPlvG=HcJ2a`b)NU2P$`dGTHW)S({!QTQk9?GSpiCEOLh1i9*! z@J9GrN`YC^H!HzlFdVFitKyB|o#1ZpU}taVgWy&0VQ>&66c|xa7LAwY%fXjJFNa@8 zuNPl0z21y(#oJf!UVT6JDtB<_%^jE1IoKX7t1HVZ8|ycA?>~6B_b&C1F})te3zrvf zZf#ONmdBeZiLPl~&+s2Sb0@g|zkuZ|tkcOFyj6#Wo%Yyd1agyoQmH32->rQIEgBA` z@2LirGRnPSA_msClb%c&gpF6JGD0n48D?&np-OI`jZs|GbjKs8>6^AC;pzwsr=jD|Q7M~2G*=of z77yISpJbTHe+j<=?r#g%lU}<*0V!Ca1-Z~HoGY{o3h!-EkVHxL6ff@;yb2j4kyMvj zq)iy7NH81`AVJIddFU%xcfv4<$3PKJRrqYk?PuLCFZaQd(3+gehFChsJj28I4PS}d z9e%E_axZyeOilIZf;QF~5b@ZQOeIz2HA_sm!_8uq>0j@3_`NXXnZF6Y5Ms!eM;tP7 zp?hJvHPcEt#3{RFKcCAtS6VA$Bb^b>Az~dab<80`%-z+toW@%7{OB0x5I=j&7EyhY z8$?Z}^J1UH`Wl=Od&jrydq+3bWby+4(`Rc_!?_AU6_-I{RTI~!BR5CKWL0M25UdBl z+o6l=5}hvcyMMO=CNWg15i)U6XI3U(GHg|e%NA_hl3yf&Q>v?yc7>`;m1Zc&^;}SU zF0Jya(8pj9yWgaIM-*iZh+zisgdBP2uVMNf@XrgvtgxO`${uJ}VbY`E0%V2RcETpb zfiMWGVJ(c}dVDT!#}i>UoQkJo-hUsk15iWqOFr%5B?sIw6Tz-xkwVLSQ z@{~m-JkW(4(9T@L*)f|+v01uZLu6!)E>bR*MSeVI`i~d6FKLH=68;P`&=XdK4Pj5% z7ox-`mo6_~mf-SlACB#hNt_uL7nWdYN&chv_Qm9S|G94XJ-JcLi(C&U_5l_uAL~Cl zM$@AO)RWV1R>Tv(^>e&VmdHi+BPWPWDHv>?CwQV_GT$dCGzv)8Cc4bZj$cAL47to* z;HqO`+>=e+{VA%JOls(w>lj&c!we!UMLDagQ`oeIgcY@uWgB}V(E!H%} zFm)^<`MjcuABZ`_^#opL`SACN-e!RSHif6cSA-{t-pVDTYz!GyV|n4q!maJw+jqC` zZF6^dWb7LzS6`WhM(CLtvusvOuEO#5MEiPsvwiQ@&MgxfG*%7 zj`dU|AlEA#5<3Q*4*YBtkW{h_q#;{Gxsh7KQ~|n5IygX8!FfYA)nQtq425$bi@@c2 zpB<=q67?#N9AJ+FroV49k%Xg~jN)oACU+3R<4mVI(-&c1)K}q{D_W>f0q#s#TRr@T z@K@pILPMB@bocoq*46|KkVb20e6M~Q+O4-ypsCg49`ZHf=MUO~{w(;R#gue^F5qzPQRA*gSN|T5yctTXE zR~q?do+pvFKwF^xwx5u~D27007*#MOlH{UUkt}B{CBMXZPvjIyXkI=)< zU)oXgB*Y&Y>r=1Xo?@*T}v{4)^*1XWG)0k?UHo%NUAAC8b z4PcMNYL4dibSOLXNC!Nnk*MAu*drOGXOeZF5!12}iJ&$$K9!eB{G6_H7ykZQrxVLr zBD#!E;;=$d+r~&jCV1+n0Ry z&I1JurE{5FmK))UPRXfM$E)>b0}^kqxm;bTvNU8z!qG%L3D7OTP!xf3z|j1Kd{6#i zMRJ08JlFyocV-1dMlWF45m+JLiFRYqX_HK2Q zo#!5oz~~WOhs#MG!AKIG7jDTaL0b@cAUDB5huWI@q8zJ6CYbaQo5V>@z{~(d6lbT1 ztjm%{f1#;=g6o&`ge=IqK}3#|IqlWoxPLm++5sR z-d+}9y$d_ryWmS7p4=B~So6S_W~OK7`n`?yO=t()m)Hzn&^PzBzLCLJ$GuL=_1-ML zZSVnAfM+@Jck9JGf6=J2yx-4`^9@8t#S*EdU5AY(Dke)*fP|@o2n=5lL)i@&@-`cM z&y0pA*^3`3ZGGRueJD1l2pn{ismQLMb53>R!6`c=S(3sE2(GD%qAX#4C@O=JST@GT zBx;cq?10HOLq;j~%Qg#NW64G+fkCFRR)YJtS)7@Lm`WhT($U0lf^og{>My|czk`%| zo4dri^wl&OThJ&#tP;^o-4t1GLfmXZPRi5rjJ!2VVDghhqyPm|-Dv@&Fp)~8;UyH_ z&nW{Dbpug|#?MN7P6O~6C~A!QMfJ`>4>}R_fSDHw_9kw#aR(_0cA=IR`J{2cLy7na zR=)!h3Tt5{Y(!!Sf)q^Q>k1@41Y|GdQ(^ITRWekI#|T1S1PLjib^exxae;`!2hrxZ zAXdk3DMn~W5P-5QR=la~a9$>8Bt1-dF@wb{MFbjZ#iac7>E7Oi zCyM)P(Jx_48|<6b*r}@#k>`PSFhX*R)JP593UWjTA11(<-*Eo`9ThkVdu?!|z$qX3 z->S@|g)~mnw8X2t#v8oFhxy@jHtooxa-mYJlq##0%a!#?)ZcE7@C2KpDG`~lxyqsu zR4`q$X|_y8oF+JQKIcFj5bQ?1$@_sfkV^VmG6!q=dim&E(#Z()ZQ*4JV)Bo5IOa-l zcphlrxW8c!^w~lI-YLwJyiqE;14&IHQ7&Cw`JzYQXL$w&tIk&Fr_X9rXFpsl%1hdXxZmqShwbonL z54H{%tNVPOSD@G~=W*TE6x_ekTHoAYsk$nQ{WbHoCja+zz0;oRP`41P+gJ??^+DYtRQH@OD4?Aoh&#a(Yz~RZ=J53N z!(O8SANAOcw#BPU^?byyGz~W?!%);M=y?E9x?wZ4^^_`S>`|0>UeGc#=*CrfAXDAzl&|I z!wU!lH;t8n5^7*ai~Xh3j~+gL^yK^Bd!hI+6V|=Re-X3lH zJ)<4JXkUK78bm9n^Er(pObAwZg!of{Knd^@^TsGHv84}Or=vxsDU9;D9JEGct;vH# zUf6~(FUq-xaI?;Cu6s2dSL1rNNpX2(=Cf&uKv%HFfF4U>!V6Iz4>hqALnt12&_oX| zmB_S!NR72>TH{gp>R@XYWt|!d&BL>CcE1*;H0Nz->c&`>7l#_e&jm7Q>wmaka|N!= zb%8PNb1wp_(_(teZIrz+uifZ0CK^+X*~Z5F=KSvb-u%J*&G~@pbR%R$jhKM|4=5izXQKxYC_?`%D zwa;>??`T2Xy`a?g4733DYck-zbJ;>pj4>d2|60D;^y4%}j${){kdl%9OSUhYId)#s z%{n1f&pQCYS@h*>6^=czGU!^A>P6RuuBohR#WEijax;V=%Zh?^vSlf<(>Owkdm?M< z0c8@mq^Z?pl4M}1ZVh(vdI)^hs*o0RsOT?Sg!4Uuy!tEjY$Z11OE8>KR5!JAG zsHkR&2qaxLaJ)D=p3pIAEW+|+Y}Sf)ArVK)k1Hc3?OSeC;{_b@{oe=84n6N<{9<4lv^rSK zGpu*K3$5?CVuXr3B2NwXzjRmIZzES3KXbp&cx=x&9y|7oZ(~nWWO6($dfgzzYxXuzcr? zv&nAT6WLCV$Ig7e^L@WdEW#O%-@_-E*YXlu|&;I4!E#1(tHt&E?)y)pau( z$L|hsZcX41J^V4HgEfc>8Ck}uisMLX{g$e{lbCoE?_TCG+y>CEfVFT(Rkpn(uw;|> z_zFbb6n=ZH00-sZ4`RNfz<>P<{KF?`8TARz$znoEVE@F1zTA-%S+SLbvg}}A9uatv zvMEGcal6@ACRsEDq8F<9g|?3iXJ&g&LhXdzZo#FGwbvxUP5Q?tKpaPyY97qt`I`E$g^T+0h~4LyU1I~+cJAUIEyH3+y~~<$Z!{VmZo8~M zdQ-$@|MH@hf3L}RyX$!Sk*dg9Rr#SvRjaKAB08FQ`gfS=Phh6k&?XwAL-b~dh94`( zmSWXdLv5;UwWDqv3=b|Jj1IOBb`GZNSJw#|C8eddqFPMDY+jC6;#IAtHCxLq%;=-p zc(${CWj%^LYN_aN9d7SVri?AGDP|-Jw9Y&?*}ZecJU5|!FNCSz{R|5#%y;ZF&_aB_ z!e?Pn8U5@0sDlTxZsGwARE4Gllcs?aPfl(OS}kbmq89n6K$d1?g@|ZuP-;XqWc5B> z#Isk#qd3-h0dgSrCPU!TB433b_cZmv3O{&PF&tI-nTQAdI~Y$BeEz@D?@3PT6HLRD zk34p>+CNBp|G z;S#r>TyP*Ffw^SxuVuf|>-Ncf0}?nXg~snp^7=#oLv&tnCZyST;VfNkck!xR)9D?5 z@iND5I1x>dOp)$tM*IG+F_QOM7$dDqD0i+p-s&q?67pW*Sb@>DXPn z=k%S`%vxr6eRh5C=-Sc2_;BoC905Vl7;qGf%`!mADp>Xq$BRvPq3b>sfG$eVvyA$p z$0NJn+`=t*^B9BpThd`_CdOVDSm~ zfoGcG;9NL5innvB!Y?LT)=y$p=mti7LJ)sU@GdP_ zNh?#&)*Dt62()AMtrZJnyfeNszB-%@_lEn!D8@L5BMW6c*DHCx7oa87gs6M7*Wk%_%WfJYVU1U#0KJnN~3u@{Ph#9~o!q(e55Iy^k&WQvW)limXf z-|_njAkI=OLrE)M;z6r5Xt$v^gr`r?KhYn6p|(g@yo^rJE%Z8in^X{>gvHyuTlUI@ zanHV_^;`AZ_1Eihq5}3#VrMa%$$I%*zLW3fx2KcoE;XZ$ z^C$V&Ub*$k?HhM)U=@hPW7g_mjd*&f91;~7xX-EAzG&RSsk>-f;H3vXzC>)le+CU7 zy7RVe;lIxM0B!1EzW)26YzC^gc+R?H!Xvk){)7Wtf`s0SvGl$a1_xL4I{25)CILb7ikes z8prZ*#D1yF*zjsw3DARluD}w{0g!!G$O&if8FO_X09-($zrk3n@yyV_c?uv*vB|sd z?`quGwJ{)Vt<3N5c@$UO=X+2av37eIRx0h^!DX(f3ic5UQXm`r2eLsH70?J>3O#Cl zsj;-OG*}8fs+%sPi~TO#(x{L7KUu5R!JE>y=jPzH!69_o-OHCo+&tKw(L`w;@N)gR z^~chWWo>>%X!1)hmiimriuog*+st;?IcBwKiW#3{myvL$QfW0bRVP#j0G6E|(*Hi@H{ zG!PP6(k7WUKxqp%lr`@YX1ifDNs^n@a@r~iQ7{v%*;NBXXGPkK-KzVxB=W9hdc9*1}EnD8h4MlGn# z)Mjh*-G%P{_JQ`{_L26n_VM;o=XB>g-M6~$bl>gX_uup1_aFK{=zP%msPl2h7x*3R zV`>E`r8YhUYtanKN1b8YdJ#dYI#<65iRx-b04S}XwO!`qlw$0wi_`5-0H- zr#-*xZOb5q;wF)G#PgaxX&fjk!^2QYO_Z{jXA~=%85tnx$qv~N#$1bJfPiU-66bB>B57LO-mkQidIy6dJrPxxj8^YXRyL@I!_I4Hd$ zeJQ;W@}UBJ7(upd>$YKcAHR9)<}EI&?kbw94QQ^`-Mqf}>E>sfUu-_!)S!wLsQ?W@ zAS_Qh@CSwgd z2G!iWj1jRJL8u7z(+jZF5J}P0hbS(mPI94z8LUBA;&C6Y`WYEo$$;d^kSv#Ch-iWz zjxpUZY$c+D^)_WqmMJ2Hr_<>?C4(7L8J5%fP2Zt>YV4nfq0a?%15#iXWG0vca;M6Y$JqZYHK6OSSMU zF!LT*49%q|j1i7?MQ2#>QrtG;8ihetRL0Wq2MmtVNgbP6CuQoOUG~#|f_D8$ic0g+ zQK=&O?pMirsxFI0(^BPhxmK>12{e}m3X5D|2o!2msfxg{1_PoxVPm*qeS*-evF26@ z!-|${1gtE2YfIF&+onR0Vx$|i3Qj{eNKof=+J)IjF)|d7nlVLf>mF51mY}jT89Nan zb2iPKj!~teP%@ztSthqAyKN5ur4K+7b8^EIUO9>Rc!yy=7}sMIA)3InkXlV*efZd9 z<`a`3!{e$HdJr2vUxSOyN{yaw+hBzUBv%S`JK9fJ;Mx+IL^dJxN$*7_FmWJ9FC?ZO zul3#hM-9<0okig-{yquqHGchbalC$6lxI~q3U(K&`ORN2aoqD0^yz;fyF8IB>7=wF z-4pNi%ScIPqx-WGw|LIUJ0s4hQw!?B(O@xHSzBGZ(0;XTi8oF%#8IT;R7#a{Wxldd zIn(a6udZ*b8}R1i!07hLNHzn3rU2;#g37VQ({8jH=wJf@3C<_4KRIA6BIq>5#N0P4*@)J(L;B z5BWpA$wMhQHJD1KM7A2ujpYEpM^Y7yR7PbFz$)@!m;8ikQ$@8Fdd6OCkEX~(TkE!u zfSUp!raoGYKzNq_ve(9H4K;$1iCE@okC%^W*W442dpyNV(NNdfO~}96JFjFS`0e=Y-{fB zxL~^?9vHNH5idnAl^M?1qSq#wXT+hc7`Ey~9%rWG<%bQD%@+esXA=o)8RWpn7-<@o z5mIyuJesMgjAPTJ+=o_N-*c(r_z7ofi114Fbv2BfMilyxTOh#mhDqg8!Xr%A5^0lo zUaB;56Von>7&Zf^j{#n=1>^)6GpwncYl|wVK?Ks@{5)_khb;FM;QePwgETiLHKiqK zReDES3K5SoSTMV9Zr}3CnUzbI*DoufNWOaUwTss;Ze9eDd^A1VZY|AXyO&UBre{yD zE@Kz=Cr`9bwU@fru7?S=54~%nT@u=ZbS#9lz71)AxSMVc6}GI@oM`pH6SV-h&3b3c zOn9qjn?JN!%^l9ZJ;88EckHDxl7sN0sR*2l#w?vsOLzn_#26+vrV-^s1J)5olfj|@ zUlH>Re4htmp0F1V8&PMk(6O_F$5o5agsFpP!R$!0Ak#wCmoY8hp!^Nji7?w%^a$r< zg%J!tq3SL0JEkflto+`%3@cZN=F4(Xur$H?2AsKYBWgy`I4jDSC4?^ikM1hzX(Tyy8 z&SexSr$iblr(E&_CW(~)kVVR2q$KAYI`3O%8j~mn7pAIg#QQw&v*f8FK|az|fJ|hF zlNT~GdZbFiuoaKUQ}U90k34j7itViLt{SA-H z)$eV&f<1)A1&UpP6t+gQkHP)_c9RZ`h}30CLa)U443%kg&#>`?FQ0t@MA|PvBvgV- z0HG16u1@e%e#HzhaaL7>mN$!1wUR(Xyy5no>Li|ds!Cc9k$b2=cp&=CYUBp<%){U% ziQ_!5dOykFlbsH!ScSyLF`9F0!6-6>+ zo7cc`A;7~>5V37OQqe6b6Mn!OL4g*ef!9OFA)`OT?x#qS$nI|7RPWW%NA(NcNP*BT zUt9nHyde6AANK)U}04lRSWS=Uqs!n7~%!3YOMLL?%; z{X6*==zf7Lk#({|Zh`KflP6@|%^Vww{hQvoY@<)|9^MJ(!VmrD{tNyIkD8z8_qbqp zX9L2W$07yJo^$fK`3L9Ud35m!Qg?0`G+f0Wp=nmU)P4BMR&aDKnbWQTWUo9FSnj^U zAr2Kk6Lwo7aMZ!gbQS-`*6h(~Kn^lfRa21X!MPw`Xdp8>Rblj?4W1BBqsZl- zMpKmk+|ScAXo{^-HVz#vAv0d)1Tznk0RA9p9)X5b5z-0`PHN}uII5@>*6p!WL}6US zgwN$-l2_!S_^Jaz!~?ZT6ribTwWtr2PmugFC=t);urro!8k9G}DTsrnz`;_f!C!Hb zE-8}c^Sx9jrv2UtLS$mT{hE9Y*#*6!OZw!9+#`?4bMl(pb6Gn+L6T%DHJz$;+AFIo z-OlDpZ{-=>@RGbDZbBdT2)qy#VnXt1>gno6XQQ{+Uwrc7`HNSX*BLLSM9Amq$*ESe z4f$L^>yCsW35~hd?IL%H5^{K+yFzJ%!FY!S5R?H%*n`kz`o6rQQiYIYm9B7lr(dp~ zv7zd?i&BN8o`t&~%!=t-B7h}mGW1pj#twCs&uIlcryDa!e+G*I9X1d&8tyiBiKIrs_dW{h5e6 z@|7g$1_T3t=u-)QU(i%h)6_tA&BJsR_lahUAm%{6e`oO*d1gk4`$$k^204OV*{qF`eszAf4^+lP{`A9&L z@|2r4+?I3J6b;Exf@29?hzI>*Nj85DYLkSgiUPlva>qV3K{<LsOyY&|Jt4bqgDXeqpQd-qFs{{?Wma%kjy$Z_H==9N|Qdkv7a$vZ}ibdl&ClBHD*3H}Bx^vex*AcxQn(64YszrmtVTnQ47hx4D zBSrOcEvlvB^1C|lzm))fe5MIv9177#k|{zhv|x}54mz8s{DPj6v`R$u3BUE?IUA&g zQ6Hrd`Q+rZn#thgaq5dDyqqt<@Vq`nx>JYzqKDQ{HTB46%6_vEjqy~& z(@l6MYy~pC!KPS-W#A2C2tx)hj50}&OFpq zkD>Xr$%*vDOv#ze&E6=jXl-q+v|id=?XC8^gYN#>!P(K-@tK9l6uFkC9LmuI?h)4lraQ^e=Z#s0n-S+dgM z@V9whNyOu^0-~3e@R*vUytfPvTyv!+rKwaj^)!?TD**K)ve4JmmAuBWFGNkPyZ4|r zAyTo}vk83sP-lkPVpWD1R`IZ82!y)*?XTqbWRhe+dGe%4j)yzMCxv8Gi7DgpiFjI> zQfA__aXaqB3rbOOcPJLK0(;LRtNDJTp=+w&Rc*91|RE6 zb8rh_C$6@@#e#{LA=5BU%#bMT3ZF54gi{icjV7frxuY-hx!-mA%kb!TLM&f?CFB45 zrN%(MfwG|5^3uMh9u#NaluD)Z5kerZ@-Tyh0 zx99EBLV2NPFWRfkPIF^zb8V}+-Q4Nz_6~Z7z2oLd({%M?GLR0;R~I05EM`0VYx}+W zc70Iat?%^@`|tNp`lufP5RGD?)NZYI*Ea+!m2t;#1Ld=dt(Cb!+~$~gtZ`&q*GC^qK6qjscSwcNwgxFQphxuw(6OS8%E8e`V!15s`|3- z!@c*-1E;Fk~WTITU6w!w$s>67HQKI z=(OyjLE8WYyvVL-fg(T`1+pj*1Z{zK*JWFD(E>#mK^FxAxaVGyvSRx!o-b)aeEiQj z|M~uXaF_N&`o{avZDC#ejopK5tq&K~+j{a(*lE89inf48=D9An!uWZQd&u<8V?XiR z^|Ux8=EP~SlrQI7^||_deWBfH_u5PCetosR;otQ8spe(QC9dsy+z6ULi8IMFQz(O` z-Ml;3Yxg?6#okh7xw2YWt8Ai|fJ&eTi-l6N(Gr|+C^8vO2oz6-i;V#zo%>emInx~* z@-s#esHJFAGR21>$2k>TzhcPx?BxPR`J{o({RF&>(Gb%s()-^x+ijm=-DmUOXe>7x zjfV|;_SJ%j>K+7ac@JYDl>R0VMADG(b^40tlmxwz1W7Bpc7s914kVXEB9Wbh>ro;R zH$?$(5I7(D8*{-Y|KdIaCRc#|dR!m+d!6a*O!+hZQn%clt<)+@-F|nyyU|strrwN| zwaROiwIyrWT3y*#p>%G8gBE)w$djUz%TDvpt-DcZJUzuhHr;g7wY~s(qr#(-TP(I@$pu6bcb{@>lNPBVMNy(uWPY!JaE(cuY?smW*Xm z*;G5`#yYXZ*m7(orn6^D&ZXwuh53cWrS8&7xF4pKGvUdg)2GrIs2g%%-!+2ZHDjBl zk9#UqJ$?3*05vMIG=>t|?3s~KWvgLB(|PO@QAGA?w&#o~`!eaX?57?W@e~$6i6P?n zy?`R`9nfp9G)2U;FCYhZErSq+@JQh0MG+xan=oZD>Ziio)io8|j%GN_cor4u`}DxHN5FcYbAN#D zyvg0=9za-poBPp_6lTh^<*T~~yNA~X*KUXJgzts#hrb?vGyG`x?OjF+O_kU9kP$ZG zk;zCVkxi6x<=hbnnylFf%9_@c)KLVARsa9rcv-Q`m zT)lDq@M!QlcHl9CP6z@h^f=git2yVk=g-~Txp?8y<-L8C?N^p(7{v`sHu9iU;D!GT zk&l*dgyzFw8K^bcQXa?I)ble#ppqx>o}z#8F>Yh89&|uOmsm*!)_{?u09OmpdpSt& z)g-O(EyFa3n6N__DH1jW$eIyCY|VOC&-LlYvWgaEWsVxEO@#L**|iXj{=$?^MRbr9 z_MAx~ECeac#po@{PPF2duH6gh0?AhuO~Dwc0pKTWMKMDA%M1ahg0$>k)io=rYlDCf zOH~*-663dqUa3F%FR=ZmTntEQol+93HAFL_%*1Eo?#lcMVLlW<4r;aM+Vh=-&T?m^ z13vW2qFwlPIZ;Un7NjVsArGSx0w@O{f>+J;7BCTEJl>4+PlHc3Y4Nmd<3a@e^Zaa= zZw3Q?T8aXnWFB_1q)+OYX$^}dWqA;C6U=Ex4k2AZrX;E#LNFra+o+)OMBtGmiB?mG zbaavY~{|BCKgHs*Dth~d$Hk_1vwveq1R;vB##_Hzkx#~{! zV)at>+Ti-&c)%t_t!!7f``fGA2sX{)Os}?76G6lHbS}TVw6eao0fuy8_u}hE$HeI@ zEOr-r@U}>m46;Ta8&W1Hjrvz=WuETtENfqhWMNUgK--~bog$>hcw<2K2ZnVb4KfzH zdGcjWFs6hI%NtiP#4sC6@|4Ffdwo9tGy>(q7|>h{88M7MPNRZE86CkTxq8&ly`Jbq zOd^vJI0Ztw;&mcv&0`s#2o_enmg2vHiGURmOUnDCO(dbDNSbT{5OgOBNa3RsB219r zH4KbZ@usdFBTJ1`S`$g9gm-8TV(XFBkX5inY^g_Q4Qq{gO+0>`2OL8Lz${<#*MUb}->LnMvwN)TT}v zd*Un;+nvcWiIZu9Nei?n+M<_Uie7u^p(xNxKfp|8jE7uK( zU9SD#x*=RD35aCi`=;6Ws?g%+gK{$CY^)QvtD-hYEQ-A_o_ag~Wd+%us%z=07jV7b zX2RS|jI%5>?F>&FS!+0!(PbxUP)l=i2SF+tqIrhpX^SvjEn2Ew(HX(VDM83H1I8N> z96L}a@NF&7$DYl5*on5pc_k^&P3R(tT_=EIL4?L2!fD4@MNkh}|l zWXo|N#Z)aar~%cnJz~pm4?PxSj9&3&;tO)4jR-!QO^mY9{hCI;Yl&Sj{5lF8e*^cRkP{R>SQq#FC6GOxDbsfuG)6_aNg@QQc ziKjx0_yw>PMU^B4nC0&<^FM=@&vkuPTY{K7CLNb>tXa{bTE&s#qIO7ImX1IXI3o$o zrjot{Tn99A>fC9PKhTDoy1!>aKqYSzd5XO1PI5Hwj*bZS7PubI8}!$0QsXgjxS;;g z?UI=`m_t*!Vq4UkZ+gYqnnlyIedrc<2A>x=KruOTGQO!EI=vY+G(O%jB-WyBz zN^uu5fC>H~{YeUd1b~d8hi*z6iSPMxNp8!N^2OCltCv@=tX@5T?fiq)&DGfVtn-~q zop&!>x$q6X$swbDGvW*^8t#JvOm!?8j|iY%wdna1IVc@r&S7S8irR?uwcyXR2ZcrM3Fwj%8n&SkJHo7@D3ye-SI}Y0 z);UU-_aD6iQ>dkw$uo{M#ffqN88F3nN~LNL^o|<(Yfbp!+MYzJahI6_Kl=i9J1Z4{ z;zDUIaWtI+beJhK#|ym3eO}=qj~y*-l+AL^b3GrGP>>Jv&}n|Bsk&`BiVJr2CS~?T z4{T`!OB+C)d1Ypd`8WsenRcBWx)=X_j&Vu+x?dSOhkEu0ZQy2ethv@|iJf8+hu`=g z>5q~t`O>^}SK5X&{Z!gYwyHEx3+loAz{1M0#p8>o7tbu-UD;WAz5-kI+s*r1_Z237 zwTu*0KprYJg2wZ+FV2c4HU&*=ra9XbO{@;l3Z>!bkz;o@?t%joS90aNFScv4JvA*F z+dgGE&40LEN-4S4HtAbYrFwBG6JO9 zP3K%5;Pxjhe*xxfYuS9Hksi0F%1ED^(n##FWtYVr#@W5Ks~DYuD)xXXalzK8 zW!PpxTw_scVZBsS;N6LQ1KR7r%ICWzB#NnBxnIk8Tp19Rn>ujvwS--#j z;re$wA9X%yJZ(H5d@=a4@v2b}``Rpy_#^eO5f1OPcBYqSmd`GqTVCzlfX}UW?sV>U z9`8Kec^18hJ`G=mE_ik|D3zN-2Vv@m77qhz-Tq*Mx?Z7J>#d(TefHbeS8+_sv4bb6 zoP$(#qg{O7S4X-DnrI>R{f2n;W=Z1G*u63f1qDbsA+GMRT@7{ZK5m(?A_;kk$LBnY z4BggEhSa#sWlFh_V#j&cw8u3Ikth>u&Gj^!5ofDLWIuHu94HV;v0%tHre%sy)D-W} znIq=>Je(bY$0^U7o%K$YOsWJqOCvPExWcF=%RR-MOssU)(4VRrd+13x@8|0$gB;r=R-1pUagCh1ioQ@bkZ< zFM*^(X+)ZmrjyJqsGfQt8i?Y|wN&5pi+<=&j!un=PLqKw=x_a|rwJ*l7e6w9OMU=1oN~j=6bS0C z+V*7~WOV=cO2tJqto@hoa(iy#zT)^#tKHx3YIn7=E-PC`_q!!azDdH^#+EJ1vV14T z7w`?IPz*Q(C;=S8B`KHCX_989z1Yb-w3&&gUrgiz*c?78nkAj+3{kst7PjI&@CpE~&}|x1A3iQsW8) z4f~}7*y3O0Da>*ez==udnG56s`@I2|!|gD}ykn_&I$n+s$47(J;P_a5Y&tj-w6ok+ zG*#2fjYfSDjAzy}r!8oh+lI5rl}w~K19H5p zv%An!1m47ahBz>sMAX2*G?KW`2-1s*j3eMKxfpws1JI@?35N(rpQR9mX%EuPTM4xeG6Idpu?5%Qh}Eb#QIZOLQ5AD3F->DoSGdf zx7aKQHjc(>uQx~9I!Mx&@?i%FQbB}1=yrJ^3weXHSm6c~jYK>NHv~4TQ5NPG zDuikA-991i^$83owoMNlKWR~p2z*6p(eyW2)O>ueY*nDL^HdaUH8pvf{Z*@mh4&5E zHT5GILj%bs4)L}K$Hk!K^H%le!5|INkjZJGpJY ztS814j~LC~=CC{BPIaZbdUAzaU#LGcJTNjaUa41RC*~$#W_zN6@;c|>7&`#sL&X81 zGi_PkP!-L@exL?uA+@pbndw;(1M-s2FM5on0^JWz;`7)wjJO*~^YkfSmU$bb8V_i1 zn^pC}#d#K`a>S;!0bo&kUt62Ahy`kHr^KII2Z$VX*RLu{ld3ENHg@MzSgsPd#4zr0TriJhB0u{(`0CFMHXDW*FOhX}ifofRCP^MB z6(YsR;ZnIaT$`v()@BFi1{q1h*uV>3p;ajQOa8%;;gLz8w?&u$)|S_oPi~yrI2YOu zIU&{^5bLgZcN}A#>*+24iq*#_AgIh`&E6J(w0y1urT}9N_IGuK|R8#%<-Jc zTGeC-@M~1yx6ZpxR_ev4!SIQ<=^BlBuTnSiBw^HohQf1CV9_v zOAAZ@ekmY@rHIrsR2u3n94d?qRfd>bxyg>mmKK***VopYk+DFugVo;Q@`%-dDygYvu_wdwhpqsJFkHdoOuMcwjZ z^VvH!fT(elytL7RfS$bg)c+LMqAAt>Q^Gv`O%M3d2jv!Ai)mb|TCtc)^^AI($`X*U zZsle9a5UOsLbVn>NGloCWi+eU-E_60*kwAHQ0#x?GU$plF72#1sY)+xr)kYZUe7N{=F>oOY@XvR^1m6PrjDnw5$&bjpz`-AqPsrEg*W?OQ z#d&`F?d>lfe);gLM_)gB{P3HH602RJEXfHuDeqi<_ww!Q?_aqab1X2C%3#`<_Y53kc3(H&4>l`$jh8)$U-CM$ zdH4GgN28l|UU2BVCAp4bS*=u7sHF2e(3@xl0?l)RF2E3E6=g@3wX+2H3e z-EdUbnfEl!@YqyF^d2E?Y%$ zKnCs(3Gi{eS_M!pE;Hle!iq54UB&OgdhLXIeK?;d(9>;Dm!CmhZiUXCfDYJ827oXp z$Psd)QJDh=fCh4ze5Sjjr{iFzH*;uyV199aX?~?|wU6;-kr=9|i4IGX#cgMfdI(84EJHJo&1OF!s04-%wU^Z79>vVqzdb za~rsi#>MRKn1<(=W))56D!1eDqN$`diVtmSS!VMon-TVIAvsGf zl56A^x!0I?1FA){^tTPPjhE}?sq%DrWA()9$<0%nXI9UyGJV=Y?y$RB9xK-;Cngss zmnKhaZEl@jKD&J3+{JTOFI~HIbLZC1-P`wWyTSD(aD8v~P?mL3P^9lr|N7bnG)mrx zgrmhm2_{~+H(IHJY;T{xaOIt=H{QE>=f`(h7d7o3F)i)|iUkW}%%c(TI}Q!*hL^ps zXr{2)^KoHsm}NJ_m(_ip2r9mjT^)Jb!*w~f=3Bu?U_O_OYzZP|7uwl~u3wwvXFA|bRCwup*d zvE>B;Pe_GVc;bzl_zw_5Jb(l%AtWBk`Hhn_ZP~GAY|q8=@0{;B=kwK6k&zT7mZSY% zC|bn(Ssqc04t;`S*!B@VVZ3hBG*frg5kWSTs)4!m1{Ov|miT}ywRx1!XR#Qv$0U{Q z`ap$Xpv8@tAl*d`dhee(kDapiYjFZ?<+?yR9#8zrB5{ zb#L$f{)7Dw_rJFPaPJ#?kN3WxevR^ajC4XL!2~$HeSlz~qS9Wsn8*N%yT5TL4DRGCNMf9R#aFm9D|?I$uJld_ z5bkhW3OopJ$%jI83u#F7`yv^cjz{r-%p1HSqy?Fm&SsG9!!Shg%B@snHsJ<{9y!d8LmJ&W+pMM|-Y|lfF`YZ8Y(4O7Dm)5< zPazF85|w2m8gmU*R(U&)A`EG1nV>9%ViC7_6qLFz(TA9#rPj1}++^QWKDg;_5`rIP z6`m#q2K^{$P;5Av;#o=HflUmYfSfG#+8W9DGCk1MM0{R%M~E!lB?BButEO<(<^A)( zkFqRv0?3d21VhNr{|*fQCt{EoCQgCht##cOVM;~0IA|8kVY6(WGDpl&({*2Jp<1k# zYn9rla#}&8^GlMT2Komn-Klo_JckC!YS}nZnZct#y5x7neK>UEWZ50b<>Ze?7Fl}L zc@F@qtXc5iRI!YM5Y+;d8i;dumheu2F*H%rRkK7*K0X95b6v^O`4Yz_oi&7w~65Q1p$gR7s>0Cm^@tp z@bmLr-NnRam=e>bij)8>k3f*m&)s<-5J933a@qiLn{soiM$@r0&fHXOx`y0b#^OEk z@$#ASba|!>xqPPQ`f_;59sn+Iy1EIyd8|H8;~sp>=9w3ts>b2s$}cTB6nvLc%(_z+`i_FH#<(2J~D=W~go-NET&f^IC zA-Iun)Q%@;9fsc0Vw-XY9j9|AT++!}c>$=0S~I%Pi;i`t|G!+o`6`}MP-q4oitzc* zMh5W(tTqN53L{gLhbt)kidJMv+D|h+IdpkP(0&pGWpdEw1K4S%y7~;|-bH996j&(K z`(aZGKc~a8E5vP{VMr3Z5>1g@*pa2ayexev(yS`cj2J?K%t^Eq;JK&4pv-9AIrpiS zMTz3qBX~nm*xX!*Zcq9>I9eNg>`^wp+2xq95>XOP(#bekXQVn>Z8%NmoHOgpw=T36 zoVK&*4Jx^#MJvOZOB*59blF13~xmKT>-603=| zzGoQaYY&03f>O`M2HSz^NY zTU3@}C@jj-I-iavEeq1pV_A?FmXMzRgZK~eTVe>N`dQ*KIFGws$KfHoL;xC&32k+F zx;$O4j8z)b&FOOsvkR`{$gsFIfhY8GJ}wBbYK24LVt6QAZd4l0@i)e2=UQ_khHsWiGR3 z)o=%km+VrilrHsVoJ?IEQyaBrZDaTH?)B1*QkS``MyO$fJxkLWx|IAM+f@=9M^=Vk zEwA=h`_|R%Zo9kPw!7VJ_wFUJ<1BXKI1AvJiN_%eOvEG^!FZB*m?*PkNJ2);l?#Uv zCnO{gL?R$A!y+U=fP}=2D~k{sgoYa&F#mhiv7I4hS4)2Vs$BK`|Nkuu!lH1jv{E=; zxOn-}Xb0P+|xM?78*l!NA|Txy^=TP=Y5uz)u-%kIA~b z?LT0(0yh|wl=ISyVaJ}hMxUHBTDkVv{!zQnS9H^`>>?|L0w-`AsZ^$j6+__^QEHg< zD@X1H)M6*~3$7^DWKsONBwd)vN1Ut`Q@R_lfLjQvKDxwPNqQj8qHqhzRkHtYIC^ak1YPnYKG`r1(-eQmWvCvO~q%>Kc92@P9 z&i4-V&YjvgrE#gkfG?)DC7hd`huL8YBTJ=XDl1V4MyA*8jP>_|4*(lL=4s3OqtHQa zkeO1DrClGezqqA;5)Bl~5ClzABtgh~6T}+Bjzn^m2QxD>#OhE@C&4hWB1V z<8@%UHOEz~C`&PF0Rpg3ZF)DN#8se1L zt@J9ZGbd+Gt(;ytx3aMUx_-z-L?aFta3RT%CfDK=8DOuXn2U{=#7^wSVG<>UWH_mI zYMoZnPI|bHPbX)RjkOood>9v5S9D&lK00RC9**I46k8ae@on%ns^ z`Um%}viwpIwTX)~LSbTX0Ly4(&`KDGWvVXgoWSowBFxHdx}G-}gal4gno0@F11Z zv08N!wEoQLvr;&amOVVFd7>vJDmXv!HIPuyPrcRN#60EQy0uOU7$LK>vwR;8zQtDh zgX`DMrCM%)luNB#aGg#?e(lEBZhtql&56*%1y1LRM8l2p3l1 z=rlK7%@GwNDmuEU{)~aK4ray~3KB!&JzG`^)!APd`X4|Fp4F4e@AtnOm)9yaSYkgu1vzYo4ml8 zj8Tkf7=7J}@ca$xK@OYa47^ox^$7iYvVn!Ok|d3mwpZElB?+tE2>ANo1a`AENv!5R zkjoNv8?3v&0KkFud!H^`R>h3x5b32`L*u!H+^dqTc|_D4uph1|dejnvLl<}c4xaFr zNI~=9Iz9#5dI5b7-9hi5d*~thTI$(t)loB-M_Lk~KZtNB}OPlS@&gQ&({^DmZUdmj~eE!NySFT;Te&yDK z?FVnZ^42SN-+uS)`y&rWVlMTJ!-bLNbgS3x-+1ljmtTKF3d10}`tmi3c_>%wZr3ELNzB z60^d&q96|vnM*9QOa!ooBDa8xri?|=&fdV99*ZHKZ#J8+l}}K@Zn{N4 zl@q-f3iYk^gH-`fOueeoisopE7Y$urS7`r3Rs)@t&!~pJuH^3MB5%1c8k}sxgyGOA zNnAN6;L>OoC@78(N|fM7={;VCHUZ{&OOb}a`4kFBK!u(EqQ9aaql3US8z}evLXAU* zH2AkV(M>Qx)gOUoLxG?YJs=3?JZfAQKq*ql;U{djAk9*OfCguu-45(ypY0a&^K4tc zLQ$u(1{b6brb2H5EB8V=+E^#crYT}U5p{)xu7Jps zzKiERBzG~S2+~@#_P~Tq;WIA_!stWWF2s&4Vo4SR=F>P;wFAQ-h988cVQ8vrYC0A; zNN$oS5|YgkQ#Y(oKjwvm=$fTKGcyk6IXFcLn#uPyO;VJ=rkNL_k|1CK4#m_o!*D%S z<2gZ3-`7V==p%F+{M-N^_IOd+Kq)`MJNQY__RPSwiv+u6$0MQR<^A=FrkHvT|Bv0e zfr+w?;{g8SMZ}jWIxH-#r-g-z`1p=x25~4ZP7x?IEjhV|yBo*d_1puBGo|K=8YMX^ zTQ9O=4U1BjH7aXVv}kFgiOV%IE0@k}GhZ4NMZ~>zR2@yXK6r4q;O_2j!GpUy1Ub07 zy9I&<0wK7&yAy(i0Kwhe_26*kyzl$n``x*}J8RASX3d)V<8<||?&@dn-Bn%Z>FQl# zIS1e9W4lKByDz&}4stfYpnLx}4F92@TT-%#8RGb2oPhsx%GT>YelfIZbLymHF~-g* zC!ChUnNq+h$3(NAMdi1bVaQCTULq_|PySGNb}FE*#XFUuP*6`IE9=F>7JAr`E>e?d zg&SZQV8Yoo`9N1d{42)EvOddMGJ9CL{R966eaGNx{7!bKC!V@dgH=K3VT;H3nLO#B zd-j#lFb)2c<+^k19JRz%hJj*ghA(bc5K-=MlNA-GCU^FvpI^4s5c>FUjd7MWhY69+ zB@2~rR%{C?TGBj;_Px{zXH%=~-Gz^WAH1&wSrHeseOJeM>2FLJv#5*J-4hGsSwS3^ zOGVQDEW5o2kzGz$2Pzl~q?86mmF@gr849yTMm!1IyCZJcx0ch%E=P774TpTw&lW7N zZYH)5vd2#v3}f7wguP8YFj8RvfLn3n`}0I=VVXT24I1mM-H2xMW3p)#!=Mt@>l!bgHsljGSGg(~|aqakU|?^3V!cZ=JuGagf76B}VGn z!eR!9Z!T+Lk?`qy-7-k%l3_pP(Oo*qU##wo0s!k*A5eXymI5wI=+WNx%851@TD{MX z8hU)KR4*5o0dMC^kNvhQgaB~s8YV$bT$tCSHGB;|QJ-m--VrhTICO~kl|mEPzj<3h zSQoX98m98P2<*>_6gGas{J!G2^G@akm;h34Znp3I0KT+paP9^I03qVnEhzB6&Sy5A z?;hH_i$(68P{qMZ>B2r;y6fB*t?;?aOd*@M`J{k8e$i#gTUQpN^DlIWJf75n7c*Rd zkp6=k)V9p0qP}}+&xM}PP>3dI@_))f4%u@ z+uOZvxARLQ+*1Ka&gEGZ3R3T3uwy(&h-4Wqps!W(3w+|GB}DjFI*g~R^xSg@p8PN? zp4bfikMO_!_VH2?NnfZT+LF`HY;(kJf5nS-@6u1C7Fe$smST+bx>iCa9}=-R${>rr z&anmwe2&1J-f>BQ6G_+<__l+Y@F^i`_xMW9kHsUDC~@m;`;U+anF8^T{hy^O?@A`W z^Xtlab|_eWAFM#sZ+Tyuwi3zqrI3b_dN_%pXz?tJ&nAUd;_GUP5zDtos%ZTbxIrc) zFTN4xxDIqIzkK5!g$v_0W$m{a`;zTs-Sgv@lSI8*BY&cQlGl z!#N+@7D#-qe)6H525VnMghk9r>%S3Af)H98tdVlCZ^y0O;wPJF)r-#_G!N@vHZ`*_U8| zGdIySG8!__$_+oADuQE*T|GVkBBYx%kW*=3xaJU#&3E!=EfJe=MB z-j%U+0CG|Ab3zW(_*)<;>Fi_3LBYz&%}>F}!NEZxz$<9{cZrIbBamHANlIB(nps(s zRoT|b!p50h#=*?mor0fT(*x+JL%}EbcSeqan}=P>%ta1pYi;8}!OtPcuJ^Az4=)G1 zgu4aM$>Xn@+5dv`SDuxVhl5?-!_2|fLc+<~0Z75Yu4Lw9&2DD~snFK}2vI@J%*oju z$N&Wg4GsIRHpVC_`i~Z7jyNa`$qnX3sBHe!g@o;d6 zivFjSxc}2ix`teayc`_H#{ae#yQG;r@Grytuc~W$ntS|ZRw?-pe;x3biMjsT(e!nP z7(?F4${B)M)y)#A`nsOZ0LG-U81_#A-#w;}+`5Qtl#z$<_V04gFPA`&7h5@Z1*6l4@E zTntoH3|s8eVQ?P+3lUHT z#Q+0E1%Sqag293U|AZ2Q;DdwuJN@epf&oB5!@|KMAR-~7K>hbZC;&9fe-vT@pkSe3 zpkblm5a1EvU{JXsg;+4Klm{jaa5ehPxp~~erlb&PQ#3EP zt}NVn@d_Hk={|hXvXuT&=)s3St-TGrZj2b1@!YwQp-(M}Y)bn%yL(&QJUF)p(y{W2 z`dZR5G{1kxFRN?q9i3jjJb>H(3E}@50sX%rfR_QN zFn?bY3m^snX{E^1GSZ~TE6CHNXr#!~q!#^uBT)BWG9(2ipjv!rpWpzHjxsW)C`O<3 z?$DD(3zHYlbCK`}vgfJvo*Q>KAxPssc~1p(`Vxl;5tI@&Y`(y}6RRligGRN2q9 zmiJL?ylGWVUlIG|UwXwb>p4*=k=e*z`_$5Tt?=dC`aXKGbBVnBL3A_a+DNR{RPSmB zl%F*9*vcb(g?TaPVJ!S&rLj#oTdy3%_s1LKh7{q7NzknwzE5!!0d}aMc=sNO$ym6` zW1`gLg(S)dffb%atZJrASBnPICf1xH9z9l`Ch33AR@_(nZey0Pr(GL9O$m?bZ;+g}1$pmAmmU8W5b-z7`$w#_(!UcJS(Xyi?>+ zU^rvrb+A%11CLgF{raafCvM8ckB!)sV+rOvijCaZ9ZV$rq*F2Pai3eeAm`B^ zhq>DqMVrkno)`<)zLd*a7+-|J09%jS9g9DIelY=+NqFPY$X%r6r5Jz7?8+O+3#am% zZCmm?-Y(dyQl6oc$LNVD9wW@1ZYpb&FsowZ_2u#r+8w=9;7$$FkPM|Zf222j`ZV96 z<~hfI)>geRTSj_D{;M{(L-+j(;(_)>+_$G;5OE2}<@EDMj+=y@LfQI*H>|?zc#H&*99jww)w@0i6?hhL{VqIqB+-|P<|j^u6udNnUnU3^8V-`mG0Qfx8sGsU`|jHb2IzFai%A}h57m(RZ!PhA`-1^(UIwEy1<71A+46eI$B;G+ z_aBX1Q?~Nf0lhxP)xC0kUGJ)J@nYSg6L%L3&=;+;_CU>Uc}vF|ctTC$5gYXmPj95K z+A=@bUiy@-*An+ZFyW=Jue@$wVA2Of-tS>$vHM_1zW90=k|Y6-IE&fb)AXwK>rfD~ zDD6jsU@32xVAr?cGz-q3HjwyrGLqt$4tVSDL*j!LI-jaRSHG7+=W|)6nytuW(|RA- zyS>NVjsEN>8GH!ig~i=c3&2+eX`Up=%DcPVcpJ`)M&%gmeh)C*yJuQ@v^864}4 z2{9iF{YY#Kil0#)nR{N-6igeLGy^vqPzU!r;2w=B*OTEMoVkv{0FT@W>noJ{njwRJ zptZXZ4Q55q?{Z>t;y+0%Rzj0T!pB1AoB8t(j1KraLX1}_$JQbng`ghE<|P8z=F8Ycc4v3;zSJ9Hjz zEZh<+Q(YldM3>ow0`WZ;@vG>jdx%|?&)4NFcNEI14HF6eA#@?1ClcNlwV%7>uJ=p8 z6 zLs0KYsaol5f6#H%uZ&-7#!Bcy?URiUX(z$DesYIv_}C>*>!)5)>jLaF?YqG?MWvEs zgxXH^`viSPJDY%%E{sahTj`u%iB+KY>aSD(DtkhU5TJNeqj&(NU;4wZ6Vpb~>Lq2T zmE>8BrIQ3Hl@{_FkH;G47lT*5Qn5miQdP?{cZN#^eWUp5J;s^rYD!M{i@xUqNF~hG zjm-4R%-WIQ1Wmfmg{KqE%kZcd%3x2CCvi{ptJ5={+2UA^OGD@%1g9wBmy5nyTX{6L zrUU*$>-M7N0itchKVbxWTiw_vvU*2^AZzVp;0jN}casCoQ!)7>f!uEYL?bXD*)RGH z57O(1wEL9Ku7|76qZc}>G!L~3;|2$A^-47 z*JiWd`5SlF)X=?AAGE>NV!8TjNL!q9vLYDcK_ z!%YN`UGf-99`tm+>Ict@Cf?bR5T;8FF79o7XoE%}-D<;0dK{K`ssw#Mal`|OEeq?d zpam7*=^Y4eLVx7@XxHIf@rr%YD|Pa)__%~Idc^1KnBbUG{V__QRZ-+@q2HBf_toJk zH+8>tzRx|eJ<;jdA@Otl1}4NP<-I$k-PVlR+~u>Y0V`tPTH0?6=QTU$*N)o9Gj1Ot?26}p@XnVbkJ=|N;4MxbL-UQ@p<$zf0MFoF@0umO zD;@hu_FCa^f%lCq_=QU>PukT5VtHd&)W|S2sYhO$Q{l=<*i?1#3ozOZd*YmUeonS7sg9l4^ z2~7=M6XY;>b%DRp=N)YRynOg|H=FV>tn{=2Dm*UL6cACLx71XJeokdcZ`h2S3&Y9iwIg0Ps+Rx@6k~bGugK-IrM@t`}QcRxWI@^;-Yx~}`8{e4OTQ({@ zTYkuuoY>a{dwB=x;v|85;W^K!vlCw8`h=Y4*&1iuE5-|%7DP)`#>fsh2ReZ3};q%y#wBL7fE@HrdQ*W#q8kXg;`EuXLrl2 zFEIRw2MqALp1ex_{#|wcwBmTAr3GFS4VYjv7k`S3p$PfL@EBvBnX@6oSf0XiS~R}- z4HA<-7^5vOFlb`%m|VYle4x%SF;GjWHDPDQc~#aU^_fkDP1IE3_F9kCx`?!Sql=iL z#^}#)7WD9Mu?srKoEzExdP
+9ov@@AmNn7A)dliE5Aeuc^c@cOsHD19kBOOUn&? zT^ng{cLi%`qQ2X&6VTrqLecg@(WG|#)oFKalm^F#$9uMAyJPL$F7Ery0!RUn)ugW} zUXX7ib7%b!J{(7TtNkdY+__or?|eDe(A*_A5ds6GPnKqlr(M>h`Y()&c;KT*n`gGufbEi1>?D%N&|A^cvgS(yrvk63ITH6 z4szw*GXer03*)B7+49huW#4zANQ_eug*10ecbF^1Dg&*a(ckxU5e!!sc27_T@1Q-h zLh2o4H?k)}(5mUCsV^9Ty%|Uknydf=boEoYR%Ysl6mjor2ce{8_Rz55_aVPa3?j}CS*r?w1q>tMk+^*-& zmg9J$`dwGphYzsYxS$iM^x~4`PWxFaSuD-eR}KOr1kcLz^OC5PXi7-`d3YH7_3+pe z+s*|8aLJ!gtoN$@(V7=Loh#;}7c3M_X3AKp5SbDX=FX#MYM*7`(FhhCSwKu5?OSp_ zB!(%tiFO65RG#4BS0=y+<#4O!oBet3e)RrXvRDXtUA0b#INBx_oG!zUNHauRp!md0fz!&I}svpyLbb6b~5~JD? zE!{Mp6K%E750$SZ%SukUmgmy5jt$;84pA29V?`76&hY0k;OXgNkLhPHA%@V#@+)KtIi+r)u<- z4m$dwcbbX+rN6349=BiC+hTPI!*EfnyS(CXU5bm=WEigT($-s^qEmv}*V^!O;Mjqq z6=h#|!qMCX$C&5cNpOLY`HXf|mgcGj$I1V=l=L zwGu7A6)Qb;&Kg<~-AQ0FWiyzGCM(1=9U5o7m4{b7Io1ka=9AtPq>nwNtDk@Yrhapt zQ?h@EZSzy?%Ojq1Ex-WA=kz)c^hDJUM+9qpU)t0b{U26u&i#8V3(TgbFPUy#Dk_O; zSIhIm-(u@lDqNRIXfD$j^~tBs-U@rEuAHxI!GJgx)nj8YAZN9^E@ac-LwG)lFvjtQ zc;ASV4!&w3Ib{m5qXU}DDn&mTBV{3I_&A4uUM0Ix;ie33u{CG-p7bT19b@e0=#SAx zY^FvXX*QOIRyRabIhNCl%5Idhjl0jM$Xw1L8yZ6hLI{umluqVgfK266{7Wb zu^sH=tDmE!7P$3^DHgPaQOiEw{a`@)c3a;)3`Lqh38la%^r}lN9+QhV*Ti+XK#Oq7 zOUdorxJxhFI8Y1Kc{C#5bo4h<@4JPo$4d&S3y zG1+W)uI<(Bwe#3$v1oDU2z7x;Ul?1u-er7r=z3RpJ$7T7pk<#Q(3}uX8p~7@XILb$ z%L>0P=wa35hhR8zm@Uz+tyn3#a(sFh>~q?fA|4`vpr(%qtA6|(gl8q{#p>%biKprA z%{lP!7~#1G259s&lBK2Jv6Keor<|+eE_$q8iY%0dAtv|hx4V+K)nubc(QzZ`s>Btg zDDXn)iT_tr4#%zS>(FaIyG-t?^D54?ypjk}@KozLk{{$@TKHcj$Pk}xBH^cjH_Ws}8EQC>(a_9RO zL;EkX_%C{2iwkmizr<>8 z&K8IgpKpziCF+@cvV|HmD4_VE>G=rQXtI0{h$M?@E|Hk@n4*g$bG$%I) z|9_Ctkaq+gz<=oIe>2B&pML8qIM$AiQ=ftz%%~o3uBi-KM5p2 z+HUhie|#oQ@l$IkDhAX}5!4?Vqgy`&-aIrty1?viSzj4yJ5(sVqnIn_nAQJrNzXze zDyUXW81$&eajnMji@?2TdB=3FwxH|L`hMqNp_IJx_`8_Qpao5{q}}_Hj=Sf(!L_gY zJ)H)`6)wd-oegKlKdVGRUT2rs@v4JWhoT}Tf#srflrU;^xF4+T$;mOU(k|r07-Z09 zyf9PU#{2u*<5c0sOScchE%9b80SR0aCu3jx51uO?TGhlOhc=b_z8Eq^x~pK>5)4Mp zu!U8+IF7#6FTOmEjDj?;mNcj7CAVapX9^2JKvwOaA^B0*j5uam217KyqIjk0)|BN5 zntwvoCrc0=wvn~+ZtosW329?0y#Wun82heplIj-E);?o&)KsT|xfH%G*~^H80t}B< z#pNv00WPQkdsl&5^9?;KeOEE;FZ!&_5wS z0aS8Sd@eJn2S4oAUob)Q%jsgqpR`G?H^Ef2^ADI#+T1~bgMX54B)M+9)k>vefp&Y3 z;VfA6O)z+A))J-fZgUk1cEH}oeGWx!zQ5JhM|XM*Y*;P04_$Ir;RIiJfA1OBp0Q3x zY`MW{8S>d$eD!PswvBg@%YBv89rJhAUE4gE-Uo=+b!ObqKPZ&S*GJ3McjlEV*a6kb z8*?-AVbuxTW>QT%w@2Sa=DBCpj5nLwTFJY)^Y8+Cp0TSgXCjw#cbxkSq)Sz-@L2gg z$dTyBiG(bZ(fYBPQXZH*Yn~$gu5OV7O+%PKn|9qLfd@cBQx2Tm(9%bgkv_g~Lb3Ax zc#palatkePV*7#gcMP`U}Lo3ij!d)vR|vz!{7Df4w}%>KYc5t_$@6v!nI5PF+^35`a-5U^PzRuo_5RsCov zbZn`*EL%vK7%MY~F?6u~@j15U(TvQ%z`Q-L*i%PplXwpYR@*4Sb^{A*aI@fo2@QoW zI+9UqA4R52UETA%n*&eDJWF_47(0O3@(Iz2UC{eJM^Q)M%~Z~CA1sMA z!Diw1@v2KL;pW(EgmvBpdyoIB5qSLoUARPjJn7D`#WviIUZJqr&jfAHCZPX^-q0_u z7!srhw@_V-yL*7v7N z-?-^-!1vGK=U4En)j8}X05BlViW%Z7lrloeZq!UQxd8Z3%bOxUdMbF&05Hd+&Yjz8 zdF;EPLIY^3!1R6JX0YBmKYB*bziI@;n8yavp4)4_eT5P~6$4->{-o^l4+(X}DHeeDotR5ISxzkt%=P|=4TgZE2DaLPuK|?OVcQD@ zFPf_@3Z^3|N#P7V*jxF-`z1X_wrj|JJgDQXO9wzbEd-&GNY@=vu|4-=d>N>`SXl9_ z*nqC}FVApO61T)ieu;;sANvp8>S^-XTF*Q4yD)O_kv5GVgCL zJHK^Mg5ZKXQRPOgGg8!O9YrsiG4^9J7FspENl({~H^NMUlTDQ~`HYHz?nfzd_dO)6 z;y$Z6f>Xl!KB`oi&vhC>nMI24|D3X0=-K2gBG-ax=O6)!U`D8-Krp*WmjbCwf?xme zb9hmtcxfhCIy#Y`F^1CYv6qtK@c4FDG2tqnOVJa3R#UZUKol{{LE|-G&2b*`bQ9?3 zR2M-K6-40k+f@V6uqdZ}R{rrvJw~aSNl+Rz^0L8BQ3rIH^rfOeO+cDJzQ^FZ{(G2LXU@e2d3*~QUH3ciN3iLD<6;q;@v$5yRyPn$7#0y44u z%9ND}(PCfsEuW|2U?6M-+Z*qt(>P*0XdjW_#ih z_lM9_LSzb7Z|v;)gVTp~a;dM*i0-)WlS-;>ofq9q4p%bjMp|Ajf%->J{0Vp~jU_cE zxanPdHCua~()l|*BEI-XtuV$%FAOdm0fDV|cBkE^VS{LAOCaT|1*(Hr@F$;iyZ3k- z={~orGl#WWce4s$*4WqAKc0U z^X>6uJEG+(=BCXre*amKu!C`;YZl(`o!Tq$NiRnb2k2WL;LNRDvpKnW`CdgGg(n}r_na; z8=3x-+#&V!uV+=O4=ZAOmV%~gEXTg-lh`jYd22W4)z6QWw>_FD0iW*b3q4)-S1bw> z8eW8d^6$uYw^i2gu<~5pF(15LJKgLR3+MEXkc_1{EYEZ|3EKfXH&bZVncjX}+D+Kg zTLE)(9A5cac19Y%#Xjur5VMi^u^o(YpJ!bwIxgOAH4ocQSn9N{>SyOEeD3gPxjxRl zH>$S@SVH#Y#Y=sv&)aRpgUTH~h>qMV@-B);5foHNsrUO`GcX3vy-zK%5>#}eYMPIu zG}pR`l!%)T>R3zNkXSKFy2We6)Ua#P3@QZ|l( z^CbkkzN>IhTEORNE+~-HPk<)GDf94Ilea;*C)QX$UC9eZj?scG1(Nvrn#vs zD0J%&+X@<|eJX#xra3u$mnn_?PN>Xti2%Mt9PW1^X%Krj1L|envXMt}d~r8f8tNC9 z{%ypbNG<7)TUl5{l-WRwtiyH-EGksu`GsgqZ0+4UzgVrpdV&e+n9oEb)zYxtZ|hlN zkJHYS3v06xv9<$EsyY*bnEo1F8%+pe>aD)x>e3$>@iaF{=D$2OPL%B9`yXF8i)~k% zPBeLv@MH$}J_j!SRuAolU-~SiOpdEl>$4KnXT~s}TieBURE3DIzHmN@-{f z9UmDkKph3I?0_YQLoH5wA&S-J?IogRxczQ_H&Nu<#z>eUDHtvuUiwAnwm)*vO)292 zy402&%ex)X3V6{>8N>(5W&kg-M3E$C)JRJ$~*sw62#xGWR;n$5GoM(0QI7R-=BdolGE@8KtgQ>aK0t|vpzOfYJTy>u% zIN-Uea=q$mm>4y!a#aQOM*Q}YJT+YMkP>gGmihvE$NSy<(fm#tQ@>x=xj>t9smI!I zk%$-n{6n+Hw+w9T6rfYJB4z+AFQOjJAdm0r?I80jgu7sl=Ur+R191kpCPhBoJQX7@ zV+6P83S&VcUV`5y zZU);Ic6lpR1Kp7VRgmycR-6>dCn*cQ4%(4*j}LtLa~Y6GXwwcBkdb1J<7aGzgOXk`*V`tZ}Zh^t6O<`ryI(kF!ZOj0j95HVR|7Zj2T^3qWRM( zk-9cr+03r3n~TPy>Ut$?S-CsP1}q}-2vvi9d>Bh&nD?l%)6XyhNhk>)=mLjd@9^ND zDJdj&%{D`A;F801A|kn16&$bCM>d?aw_z?Zj!Jd4W0Z?mCwjf?_;nPm-4B+G6>!y>k=Tz zTSiAj(#n@1f5uca$K@^js^sYw0#KqAaq(=@UYQ)^$=s|Q(lGsg_G2W7(z1+;;G;mo@fcxRu!QwTaBjAl9Y26}@+~(Sep5{I z?zA`Wbjfn*ImX;!X&!MUC45uIfuqt95js4018p(5gR~CpFH8~s5+uwpV`-~2N>=!C zZ%>C>190ag*cGmeO z@~1z#20f4Xlsg2^tuO9Jzx)=~5Uzfg(Q6})G1Eys zufAMk&OnDvSGqr`HFB@YIJozx7NU|1Ayi6ABIR4^dW3C15-gn}QqJ(~oim3&F2g#1 zD^HV_zQxN=W5CW2Sf4l;Y=LuC$$geH-3biDR4!AFJMtP^2MzHD@roY=ZR(5^f6h+l z2~_^z?d&)vI(saEzF@*ia73WEyMBO5E(*M~Q7felV|QsVa;G$nTt&RfDW^- zdHT_2>f{L~($eA0)K@i>z#{uSz`)#(@B^K6M(uiCZ_&?6MhR>S2MeEo$$^ni!94lA z;rZ#MDEYoPk)vkhh31Sc6f=*3A!cKa^%)szp#Ez*`>ZokGb1x%XaS-?I&_$4_Z_!i z!Bncxdq>^1<5`qc+>Au%M6+MWVomK^+Rk(-o!i@dd;x6g(3lA_redu*KlNb_GMFHeInRG zNv48zwYrDsyWw<|g`_{Mxct%`Germ0+6VhRR*lMP?W#e4z#A-sv0Xry%Xpd0%t7Ng z;jiNEDi6sc2)h)oDStTeZ>jZgb_S8^Q39`64=(a35XmE5`zYZ)+{wIolvO_bELh@O z3A4|hoWexU!^xGB2tz;0H1?k8!U8VO3bL&nNlK`Z#fXL7FvtZ@hHtjCjCD((-z}lfx^K&YH+o{swE+4~Y8yGBA=CMnXAs|#~ihmv(yU}mA*YPJsa$QOHp8piq zXA}{QEuagv<(EMG%i4F`OITQRym`zhIxG+N$6)*Ir*~Ar=cI~NbnkPFJF})U{wO&| zPzOx>lsOrm05hS*%ll9FL|EV5P^U&+Vv0r;Y88-r-FXoE&wu^Qy3{=Gey~FY2Mf0g zH;zY%gXyfhvl}x-ez5VRYrLO1;c@%Xx+}#fc#XC%LD#Cz>oH8D2 zDN3*)(vU4SmSW~pr0FF{F3k^oKRvF*dlJSCCo(6pPU?W!3cwQhc+5m`h+)qiB=D!kQ_kOeSk9ZA z6hDHc8HqW$!&kqhaA^qoxhdBV=G>%UO?re*`kpiH&mr200!5gGOZ}v@@xh#>2UM(7 zu{vYPVTIYbU~N2p4l_44kvkm*+WUNFin^BChAQIPad%r0!Q%n663X{(EJ@jqujTDp z^t04(#zC^Lpu>`Abr=-u$Dk(1IcpgxZ4wk& z)^8rR+ZO5ZwWpSY##4J(Qs?L^Xm9F*iw-^Dn?h}iz;r(ispj#htS;cNVbq28`*VfS z>A0*x3!PPe^LJ;?vCW^0bZ2u%P){*x+{AYk5X{;&1hEmji+ase!sZ`1@2Q+hmTlh$ zs!y#Rm#Frkc@yE{l*A%ywLA(q@DLUsDZ~unKoy`)<}_%?@@$o>g0|Y7O|@jKnCyo; z;70gY0j2W?Cb zoJCyFkjs!vIM*Jxb%WIG1h-C}``C)d%Fe7V!)W~%7=3*$x!FZ0r@LAQ^Q>o`&jif? z2kK(n>omP}MiXt&mj2HxE_IlKg-|b^QNM5YXD;_OEZN>iD^$K&-UZOei|@1H%k#(3 zp3q;{yqTEzE_>=f=$Ev<|9rd$U`>aoD>eb%r!*~`(qttb?yxP=Y_ zNoio;_+B8ImypfoH9{i230xH4R8*~AWVfE`aq!rm2^;C75vvr(KJ7}TL1l0~et@I2 zCWFc(2@P5L1*N=YTv8-vA9&3bG_-Z;i&Qz$da}`T&OBR8%@n;s|Be%)k{pzeL&jp&6En$@J9n$5)4ne=hyHg3P z?3bR*Xs7B##$`SBdX6|rE%dWwZmQSmLq{>-(007ql?zgwGuh+PjmyM1ZY25x!iho$ zPfRxE25LzZy?R0^V)8v=>tQrPDbhrk2=orrdX-oiw)sUX;RGspPqU1CnDMTtG;!EgC~ODZUP~j(LKf#ciS(q1um3R z3kt6}f;amUh2{mdZEhk@1jG)#KTOm=-Mzea@m6#xhNp4!Xe`Cx=9F%I*q<}`^fucS z$w|N7I!N~rB)1WuBaw5aGY-DG?Z{*em~Q=W_?=L*vu6z^F;_H{N9ya;msCaPnSojP zxFhwXi$sDVs#9pETQQ;CGfRouKecS7sGU=8!w*o2r((twCR=Y9L3qU zB1hEb`DQ=fyr3fXd6(jE&99kQvGn-!C>n_T zy41W=*iAWnYQm2B=pV$C7rp_aaQMRF&32Yxb%y8b&SKo-6E_9lCyG%G#j0Exx~lIp z3y%wb#KBM*2>HkpUrLpUK7_k@&p_oY=_C~L;>#hdVvW_9GS}cYKXF%2eai6s`QT>h zg*wQvC@$Xoy8w$~+U45Kl<}09v~woozT^$?#<@(3igrqlD4H+(m-%>NR%-Z}cfE#4 z!;RDvmX8Bfw$~r0{Y9!>*d5t43Hyn%7seX1K*_eNi&C8~Eed`$v%3d3)Nk=;in z^#bm+i-aaxo$nk)S&NFBvW{KM$)t;`4D?BI^KwIh#Me(Wj)iAU>35+=?u&)dhqOXb z$GPHY8%1I>(x;&qe`=#qAY3X#2@q2 zT@*GKG&dTb67C)VPAu8$xksi2y^;feDzQCM=(dVh*xX;^;xRG{-B>5)e&$^FyzDzc4Po^C|mt-Fh|5SdX0*r5^2lA|-h;LIGX z&bETLtg`s#h%r>048<0GF0x9c$)gVAt{LxxCVWEWSx2?MTe#%7Of@-r?~|ic%q5ss z9CJ}GGV=SoKx4XI%DepmJu;O`dG$(%I$+9JPb^PXwn$g#^pd_{mZRk}P|)&h8(f|B7m3@_f99RscADH4Roz!3FNj`kuh7+uZzNMb zGgoAS{=@IzlxMdZbL4K`@jHP~o+C@;w_3NYC)wOb$~pUo%wrGdk#L{nh=+I8MRe=g zipdYKWk`Qeb6e#^cs^->TqDpi^Af+?X3bo0KWE-O)5C;<#C(AF1V3)1K5L|U*hsibd` z%3miduXJ2HdmBI4l+jrX1(~MwEmDqo5RY?qk0}Y3C)^rWPmC9?h@CxzIEO+?<|Mf{ z>71bnIp0!{M;n|~ht)*9aB+rof4kT~lKZ9DV5Qi3%&be7--wNxet4Pj?p-S0NXg*o zr}I_1f!b=9Li0STj@-No1reJc0WfZGxS=Ef;J($nrjZT&1Dj=TZK1` zXFl)rs_-*`7`k$0oRD3u1y^!*t)I6pJaHrQl==SI31y3z|T;| zOU@aifJc->+W6kKLKWj^i>{iJd~Fb zGP2q46mN}a^Y)n8Yc4MiI?m7e0lLNc$#P;2tMQyxmd+5w_6B}&>r3Z6eI@aCAsXB>V+)FA5)i%tT-cs27p-N!h(4ho*kBFAZ`uF7J8bOppzsT``|Cfds9r0S2 zuSppajaU{mr;ms1EzTuMn}&c+C@;Zvdro@OPo;Q^kp$l(GEA4*lS)oYS%AI1vL^Xl zn>~@9+*f3=_s%rmyz^==wl)DdRP8VipYRIBR3}RIG7h#`Zz)Wza#HARpl`44ur7Ng zX)kYn^dh?JnmhFfC?rxQVsq$(v>)~HVqLgmrniY}$Fv)m^ra6V9k;L2;n3tA?$$EsM93 zCsF6)=!GI=uCyg^z<1GMlI^d}+@`SoO0iIWP58wAyhlzv=sI}C|NI;vy0PTiSC7>B z(FWIOHxdsk2#0-N)|PEBJ*0lTR#?(Nef1YSu|ZjEZJLAjCkEMyBIWqdc`RwD$nd0} z8F=X0Xikhj%EL6vvDDO$HE8l?CDOv&UVGL=q?9XpUTfcVKAn1dLDK%Xzw^1!E~VRL zm8AcaqnKdhZ%=|)$I>Ox9u&CmJ`EVPGzC54C#8lqiteZBx7h~q$B@9 z9!&Ovi+D=UervdUdL90PWw!s7l9;0VZl{#j3S8>aFR|Fd@qqGrzqt@Aix3 zs_CAbL7Db%N|AU(^x$;h^I5P0+pQ$u{jzm3KG)n8nBW%N^Zc^hC>z*)e4?ysi+mtC zA)AFENY5zN+le>OVw%u{E*aRlVGYLeBDcLr{?(p(qd!4jOsdBm{N^MouH>!)S*eEa zvhpcU6D{tLs)Zf3}`n!W+FYbOEv`q@PZAfRfgp%n} z*GZonW(AvG9j_YoCRkl(&Ara<*F@$T`Z&hV@btH-AO#ZLH9$8J-UbXb&mrkdniz;2 zNFQ^QP|8@Vg@2VG4fp<7id54bAiVET{D$n0wi5f?B?WR|b|hbZFH;fP6VJ_XQTR=U zci9;ro9yf@;XGBkDpH0DuBa;=tu;3hX50Xs(5>d?2@-rcYalj?RxOCH$ouWy3qNQw zdPQm49|T1{eXTzEyd&1<_3#sO=`+^{S_4=i(${kt^sb%z(Pz?Ogr_v`{{2hS;0^!9 z_~>vSFwb&+{7TLZ9i_=JBjs!IX%b1K7vSR5?|8X=H>a=ftUmZZ23@*+0t zOO8A8>|S-CRlvu|zCozR$a%8xbq<7%3Z)x-bK;=lAxKax*_PXHA_Whidtt>RD6 zOB6^Nn{;ZUc-^}(CI^&9!(-3CVavdZxxQ(i3KyvNLFh5qJi;w^-%7U|$9?cO4!+$X zTSqogK_bP^_Rh^&=fI9b;s((wgyFOyaqt>Z_d)ZygfQs{J=*l z&g$1Qu43dPsDnR~uvTk9Ijz&&jCe+Q8p!NkT4Gr;%&yjObGK_uUCmr(T06xHRfI8@ zu~G!%F)pPYr<}5tDk=h{*{kYm>RpBs> z{KM%%9+z1;NG7w-;l*aGRl0U*9VyIOkY&J);!b4rkSf2LmuoAeEf?{WJ1TtdkX1M{rovD&B&lpiHCw_L?Nv7Vhm03jsOTImTWcoY-Hy&f{R|^bqh9+I zhdvJ1pbc|MN6SVau8Pd{Xr!P#=_cp@;O;HJvTT}$VM+u+kZu9FXprWjQ;_cN?(Xgo zk?!v9?o>fQK)OR|kOpb^FA#6_zJ0#ud;jl!{^NW9FLw{sf%l5iTSC3{u|u)RqO-^qGtw3A1h zV2ntCJv4Q?EU#RFdsKGelPu2hs0wF|pd|GODdy7SK1|a$bRr?hy3x{Rs8~o@?H_;# z@NYlCzYm9h7cayOc$u>vX@VqfI4*O9Md|J;>>T#N)x=qax(t0IlT08^Aub!g?A0?k zj+9glB=M~ZwBtbkQxATXbB(a{oMX-}NUfGMq8R-}+yNYnE$*&ZrnT;_{E#7q^*3Z# z&x4H2`skdl;(_*ukaL&0p^fXvayj)B$KI(nMI!GaFk4X758b{;;=kZ8^G5fHuXoRpmjASr{ zBMzUiXFm%EXskeS6A6E356? z*W7G^8mk{9ub~(hxp}ClmY2RfPt>Gq#buQtkdR9T zL`k54f>=kk${Y!ySxP_kaLZ?3(H(w~*&9~+qEre^GjDR~Q8${zI{_^=M=Dm^Zs`sF z%edYr_-P(iTrBv>hyxGTNI78Jl>C$UgCjzuk#l&m!Z?@1EDvtn$@Cf&-`9l2^t()a z)nCxK34uM>$oV|p?Y*}^*`Bi3Cd1SAtq;3*_e?*fRZP)IAR0_#hAMTh&!0hjR{BP8etqEn@95YNk*z2msS*58Z8^-9?f^^7?DKO?jPBW|meu z4Cwy0VTn41mK}*O&KAlghFPLn|2RyT)s zL&fq^$qj}3%rp=**}=`j+oiSEcBkpI&1)hUiM>{vZY#}?#$#YDk1nXtnOtRYxarwG zk49^+CsEciQ6gv z(9AwEzS4aB4s3J;%Pv%6Ap&LO0Tq=AP5VpB$Lm2#?}}}LumN?}ZN*CZnL+M2eVjcE zIyFwN2bx*2c+&z$?$g=kDlW`1;MsCCc)Vm-&||#1vaZ725Z}!|vAWt-+-g0>(b+N{zQWJ~Ga8tr z|C5*3t%L6WPP~pgkKMaK5qIG_sOgxQ2&h30w*++bjLe{fmhShE9g=(kl>8t!WqTXv z`+yyw_#EFOcCh>wsDqB>mp~m1KLT~IvM~J&)Im?j{I@_Ix4|z2zenJ>Z{)uef8*Ad z_-{_u_dd(F!8QKdoveYN=6-RqzJ2}C`i}q@|L>iwSqT{KU8DaKPS&?<`QF!iCuM6$t+9vK!rP7lcFW>-1U0u$z18Ku=nO*$^;!5k*71#N>KU~)>QM>o5t-o z%v~?W@ZWEGIwaLCAf9lya?Dy@l)(nT!Eb2wz>3{GJHu;2bVb>-I{auFi?&q%Xlc{T zhaIT#(0OUOhh(yEW~9IS`WT=OX8tMz$~E@jZSulufk_noG!BM=uyt`es}q%E!1;Kp zOe6`IrZ|C#FN>N(ly2+SrW^Ax}?LmDRI6ebbnfneXWMx_t>$`9?Ew;XO}GhFsR zwFna%!*zU#A7EU;)b&qScHW!Lde+x#^r$P`g~NW0I2M&D6FQDEvC!C-N&i8z==si3 zJVl}31S*&w+~IyD=uY@RbfT1EJZU3KT?lOiPEK9&2`%5Il9B3)74OJX=KUrZ95Ec` z2`6H7I+Ly`Jlo=a&%l|H>6j0`2uHxlR8VwyNdAL?kcSCiMNbDHn$cf{P}`gFqkS=H z`toUl`1$hd1|uffQZ{%C>#rv9-{x}`q>sZOu0*aigS!`ez=|8 z5~g~*`VmP2)b6CoZlTOhP7Jjl=ELiJg&b5kB3#tv`XT5&H$>S)7!Xcer?d8Vl z7`51@R~*z|MU;lomEvR6sx?I6o`0pZtLs=v5o{E6f(zjlT-qhC!<9{>UQ%RpTnsa~ z%vlzE8fj45Ib{|#Yr69ZnOv0%_6%E4nLOoT->rBk}PnTNr0kFo$-%Xx?hgz=iulj;`Mr`$Q8)xkSiKjnmFi#W7MgTlb* zW(hxb)<@KPM*AklqH)>AWgWTnLjOzeHLdkyKJzT3j9R1{i#G35;&w3RLd=st8FALX zwDhk-BXsviGyWq6jgIzri+1<^-*3`Dr%6DR8Sfgq&4Uh(+?i?6A(TIzCjp%uVF0Z} zw_O8e842jVACM6?2dz*4=D-Qxf8pH89cO>DiLA_wO#j9x7RRYu;?|)B?4Brol&_$m zc%8kCfYf#(ZY+l4gSle7*T42awah=^$o z=bO`ZC-@4Qv&E$r7H)=(Nmmqwg!U@ep%}iGDp`DGE1zd#c6Jn1j7tJ{3@C4!&gxY( zZ)`4h-o9OG3QkJ1WyoM$lDBD%Gq7m=xNELhrn#Y7=8*f$DKB(s*i((cY@%;*2~#pD+VL%|-@wa~Wu5gvh4$L z4w_u0t%IWUny(0G3=C>7tlxBSF=sKT>6k4#vuH{>89q`x*u`;P zGVFoVZ3?50-qD=f!nb!MEyvG&9FfI1u8tj9C}frc0yzLcDO;F#_|NIcDQ2q zZLXRaha{nszPs=oe>GI|^-kG>hUe9;<(e)c1-x;CB5{%IWN+%%Zu+4%GF66C8*=?; zvn!;!-mF}6VR1RtxUYMWtYjIQIELu=was>zw~tE@&ggfbi%NhVo_R~mp>@o|Lq~Sp zLgmd?+R_-w%WkQ=Zq|VFr4domrtzGNrs_%t@vD{B>wuC-TulD{_q&v4&Kir zSK5@Sak87o=lGySR{iR5U-u+0n5?O&$r*IZb#V8Bhimjr!12tE4)y`61Cg$E;Est& z>r>x!M+J!8Ze&)$e)HwDm}$%v2iWWZxNs3M`=G`dDmaJI2jA3`%;Xdh-C;#9`8(<5 z^VDp=W^{5kJ2&r^HsX6Ux>ijxgYKp{lH}KN?3z~JY!LodIe68;nn)|Sh?0w$DzSeI zXSl7ERWkrEbi+ratgv-lk*U0}(5=-rotujuWKzElr-1a-8Y^RC#{u9 z@LCWj*UEEXIWlQ1 z;hNglIFyROAQrR~1lkCGvsQSzma|sj#vM`22=>iKTTjAy~{a94rm?I&L<0coQDQL>0L9l39jv##Scf z*Be@*&TNk+<*LgZXBHNA8@B?1h%;~%5=|b>pD0Qes0;1o23~mPD)l8}pm0?^BBdO& zHfW)b{FD}t5y+57BUog+%P!#@{S7h;(e0tgK;4H2dSv>wW=oYX4v=(6kp^UQh$EKyBqCNi3l{ z8=cM+U7X-l^1~&Fcn{jBo(Hh&a_B4L28i!%ilb%iLuRh*$fnh!?IsP5W8OE7yg&R# z`c9&?8Zc=1;Hna^l!L3+-HuyV<6r-d{JH2M@|MtNKYOYP%SXJa>pF6ug)6VO`4`N& z?F^3g5N8~V`ZWBbZ54E4Gd11H6L&JA$`Ixn!VeTfLzE@#KQ2VvoY|g8tRh4AV4j7( z8rh}2Ud>%`RSa>?XzC+aQ#bsQ4t@4T+}cDE0u(?~O_9sC&C-mnr#sG#qo;hJ<}?~h zFAWMyz)0JLym)xEwwE^}3=nCS;E?JT9(k-!6 z@omRURfox9k*90JLWHN9(ZnF5Zb95dU+3~-P1L(X_oQT)i>Ji8P)RL>XJx*p5Q699 zFIHFRo~(9H&W{~b%^)#?7SI8rE}a=KRc_H*sMiQLRY|Uh-^*?Nj-YB$M{oul{&r22lfnY!zR=i%i>oS z;iJa4DFzN@=0qf02-?sV?^M_8^$->{U4bJ7o4kr=E;w=vN=PkHvmn6vAQWbW7rQ0H zAVAk1ydd7U-}XB~q0h_&F58CBi-cBbEtx~GoePc5ZAD(uQ)X2j)GWo)Uo@Ae=B8pO zB!X)bCnS^)!^2SarGI~Tl@G)Gd`mB{gnvZY@Aa=AJsmMT^r8G#FMqV6jfTi7!vQbl8E37mq zHTZ~fP)=JP3soVt;0~Vy1Zq%NejtQ)JFb-kid#~*gzqYNl$>+#MsgtbYyEADe?;tM zkXJGWVT8$P=U_egh2mWWXefq-cMSWz54WAaMf{~6*Z-C=gY;>n#eD|k+A%$S_=eMd z$Bf6#cldwt@9!MDW2*n3Irfu{!UiPYIYv;-2=N=^ZrS)(A&9s4EdJ*Mz<_c)yjxDj z^4<;hmj{T8R6d<9p=V;+>WqCbrU>yE21dx^45L+d1HGN^pNz->L37C54dkBLw~__o z&@Bglou$7f<5s$E>;HjxH%kSby+q%c31Y^drw_#JU-|$N)W1zH!%OWPq$lH5AJ<^F zDwRc)h(8FMqRjk{WxobyQO$Oe-!c4g@!d#4Gj%WMf0NgHZiD3UoLgp#>}A9XSmt`{ z=JA{Er7O#iM}d^j>)}$6+k}AO1Pu1gSV|4BN-h6LYsl{kv6MLfR`sLgk60i&_lU6n zAj{g(E8OlfbU;&|E{^%}+P>}d5|L8~I z_p0Ahv()xp@%BRTb`bGG@s7Lv_w>Hx_rjk5ulrGMy9nwo=xKE+aEB3CL)MC>@H zr_{RQ0_(QEJhX=^#u!sAcVQ?uk-bep9llK&%3bJxY z|BJ$3&HWv~)+Z*)>$vg^zPPLkVtkkX@PeiFy5Yfi@Fw-`%>6YDw^RFL&TjMnoS0uG z_#W$b_+Kf2(7zM;Tl!aXe+T&6tfybOGu|{j98W7c(OMzVdcO)=JPTDkje3_t6(|3d zNBvRwz3TULlEXVD$xA-T3&aBXB%izd_w>Hx_rjk5Xi22Evjk!)=xJ_SvzOt}UV zzR$5fdi(jYJ4;*W(!M&d-9^3yaw}vNiV_HZ`zQk5y%hmTl`H|Ix4f`qynFo2-531+ z0I}t+fVIPgh_z$0zuhJ4mj~=PP7kbtB{b-79H;*__lJiC#C_qPs&Cpid)i&*+@Qv9 zl8DQ>5RTH8oZMXCin$ecZ$ z@9BNX?}a}BD48X1r*|y(_V0Vw0pNqRjVa`-e)Yy8>9uG6r>$@srOjaUwN+|h2N`wOMhVf z2LCICe}(%4@t?#|ZWTMO-%!gv1tgpv%VkUT8)NucCu(B=m6~PPqQrNF@zI5eFAC$K z3RT_}#77q-z9@)CEr=h@PxQ-=m&;Ft%8wt-OZ3Z&m&;3p%8MV(jpZ1Ui~4{X)h-uY zj~Z1e7nP41l_?h$j~W#&7yJq}$_F*dMJ~z;HOfRTN((hgMJ`GTHA+M-if1&EG|&V& zKu5-3N5;E}G6oPD0|>6@ zy%+=Vt?2QL0k~H5IK}{MD|#$r0Ot4Ej4OKdV|uhJI?u-dR4aNEV*s)hJ(4j!z>3bZ zF#y3B;OUAU?ic`jMGtcffWD%KItD;q(R=bf8(~Ecehlzv3;?sD2R#OWTG4|T1Awh8 zALXHcUXwpa;L=ohkhWmix3F~Dm^TPoL%CZLxNFFHS`v5~V0l{-cpI?zI1~69VEJ1T z_#0qfGz7h9!4hZ)5@^8^YzPu;!Ft&c^s)s@s3AzGhFrKMLAU`+gfl^;0ammnL9_u@ ztR+FL0ZW`SLA(K0q9I741xvCaNU{Y>sv$_K1xvaiNV)|}rlvrq1xvOeNVWl1t|dXP z0am^xLB0W2p@p@kSGXRub6Op{+c~AX<8^a;?sy-sZF1hO=Rd6UZ%&l9!*0_TPm9zBm!JSg}7)%RK?D+@sCZ^XZ4H3F>kUIm_E653~~lrJ&X5 zHtoM%uE!=bBmS?p9%nQg$KzSdkq@OVQzScxilLTp7Go8z%BO-EWfZXe zhqwSm^3UfOg4m`+>66OZv}EuoS>cq>;QSEFp>JN%6A#NLRN4afwGYPE70-~4;_Lk1E zxYsQaP)`@2ZaZ*J(tg`VAoy*cTJJzW-To5_h-4#d`8nVg{+7h;JNU0n+>r#0{5#2i zf;=r|16O*PG}G?FRSaSJl!nj|__#Q(XzR9*6iMKB>Ai*Ao6-T@k_TNkYDnYqx7Ni#T zd?SB>gLL7(k)JL9XaFSkAHx;ly5?5;h9@NZk?4s zD&E+y75`wK>wRovk9R8H*}cH9Zc6#Sj#VE!QsAX-0!F?$G*4$so3z2w>lBws*?X>cuO}8ShmRfpTb*9Rn)OLKzXQ~;+??< z&DPH~0i>pqzZm$xuMt0F>kb4o?YB1nZz#X5AwQO(e=a*9`|w>{{{aG0e+jVhp;hMc zRK%k8#BZ|{gmo$Z6U>@vdm{e+%xLt2E}*^;$7&4NAwLsd)Cya=39WW4ZY2+TPlHml zhb%oOxviH6E*4t)6g7e?x}&I#J+9wOS}e3^mtVL8nGX09$}Pz`C`EVVTlo7X=DdDw z;*Ml3;XTQJf(**1cok(mrd9z$2B!jNO3#eHy{#IYIjh1rJfae+Q;}D9+W#`88Rh3G zW(i1fPpLaxJCx`WMk2*36ViQkw)EBZ+#+Fm`|@x`vg*L1>Um|@>r3P5mz&N}t@Zs= zOU2XKQ6d;{J=>i9#{Bcu z3+`NccTYOa9qwfsGl_1>!lnJ;;F0~r>Zt0u{lc?rZt^S9^SCng^9{{4{Ro=*-QZde z_3D*cBVd?7(sM!8HsP{`Imeeq&r_vGif6VLVFbANPMU__C~g}7HDk6+R29z@9q})X z7sU5x1`pv5rE=99-f`HC?0J?3jeLzcZp2Dy+2IGeHW*LGx40cucOK|nUank?T+r;| zb0sO0&up`8rzx&2({?W;#rJX7CdISBk;$t6^NDgX~j|WC6r=+|%XDBgZ zR&u2oL7Xw$QEWP1-2)wWz3h6s5n>lIT`7Fy5a<{P$Ex|tWahC0i^0$;;bGCyw`Pi$A&_T!;zcVu|_rA`Ez^a;-vRYihcU?s>3}izS(c<WszFPUawH zvRw^FX44dA_64q1%?ixhlufS0M-ePD4JxiDnz~1@gBPN19&JkGy2eOynUC7HsFK2| zFC-0XGsn+%P-*a3UYug_psu{{EO6wD z#NhdPdHL2+yO?O*6fX1Ioi@oTj12<(M)q`LgrW<(htcLq>LUw~Z*i8FzD~$mb+!wA zvL*0YIy9tW@q}Q)NW?J$~MWe+lpfwNy?B#pQh~b#hf)#uKa1=+dR)@|9bVy*b}e*8yA`+0F*Z7Bh8$? z#`4;X3MX7S1G_ASFIU}hB(GrL6n8MO>CcQ?IWA?vlrGU24cC*YFTj2BGN0BRX9|Y% zL21;du+Oce?*lPE$RA(nKC!BF#tb`d(mp_W-;)915XEQuAz^}v6yfm2muf0h+VB81 zp&WR*14e7^I1T34@`;;LrW*yy+X7z)-0?7+g$sPa2neAP&}!Sb^yZr2n6o)SKLBP_ z0%Rhfm|%~-wF$q|eX~Hv#}u2)4W1jpVhAovmQ&5N7&{z^nBFwUH!cBPZ)!%ynozrNB7;YOkCU6l)%o$UjKjV zf;%t>6qt5MuqP-GV36JrD36~&f`Ji%J%i){BLdyTmi>eX%nR-rJbyH(5CU|W917Tz zhu&b25MU!b$dJ5XkWdhig*=dd9L7IFCet(C592>Diu>#Cc)-HJp70QWJ-NNA4=ntT z{rX3!(f?q-2td8?0t4f@?a;sL*H7p8pMI5h&fMSU@xR?sobKL}`^P#>`Zwf51)Xprhc~)Er>!0J8_;;t8gYk$sdsyZz?gW)jZO zY^s9id`YPT``9Z3U@_HU>E}}n^rvmSwB{^aZc6*B4)3wnW`RxUH#6=kC6@EM_>zv@ z-Tga?Y=YgosJ1d#90n(e^QMa2Eng76O{n%UmNJS_0!yHGK1wy$bZf$UnC>iJntEP= zj*EZPC&W}#d7-O%fav47MUyy8K0pO5wGp}4U(}lIwxsUT)R&a7Aw3d!$gu=QK51Wm zHfC`=7=tc`Z8sm_=A$d(vTL73Wmv!0)xB(@)|Bh6r0#wK*1xs1X(<<3`2<@tn^S<5 zM0J2}PDwk#Ur>0?Di?RH(0Nnw?U}NY9HLmflyqS({MfsgPZ`;k7o>$ozRtvu5cs^4 zPZjx04Ah;Ww{ek>Ml_~TANg#!g~??=o7PWb=8n^QfU~t`T&5=2H#6dxG;4_(Yhf2+ z`j#9gU75F`MppW;9!FM{7*xK7#BIUzBISdyv&G$8B<4@-Q|ca;6Ptxm6siw(5Xg_; zk2FRrd_H38!B_L40*LQLyQi#}?)-XlyROW$z7u(24&Sl}x&tHiQ=H}AA*aP9nl~W* z%&!&bY3yr8cSm768 zlHLywzJS}(pB%c-rD8&Q_{uwc180xrz;IaDhwM&O99?~2G6AVv&tYm7_fJvN`r)rF+ zN;@WpE~TbLTNFnXg(YVHl$r9jMp!L))ykN?eUQtAK+H)*0>UqcW3dg-a$na~lcCLE zK9P!(zWU3#CSrGK+l}J}sZO7bbcH8lqu$WBfEj)ak1r(H*D7!P5Qo?Fk)9NM)z%%? zOLV_{Sx4?pJRiO%_LLRf@+*>Ee{F3({23Aww%e4*dk(EIvj?E7kEUbVgXcvr*VkKC z9roxZUaOYn1!3FFjWlSp`r@Ai*fB$z$5l>0#pnL!LIQ~bgd_hF$G%n`x`oAh3JBKt7#6& z1pPX+Xk{i|6ZasSo`ghZ!`|#r81kna+T4{|{a_z_G*UEKkUwssLi--e=L=5Eo>lbo z2SXy!b*By}=_VBVuVOcbc4JiJML>nO1bL^<&eMQbfvWDOI>PF0 z_)yl#U>WTM-u=cBdBp01FE?VEwvKFI8LlTcGL8a6{n>utbYQ4eKzCQnHXLg14UG}M z2$jOH3IW~R(_}e{c2XSD2%<;yeOycON5Xw*n~Xg*?Y6? zCojkhZJ(zBP4gcH+TwO~5ZV`gQlx8~(-qB7z$FBQRA8ilq|}vx0{RIGy=FofmG6|bd($EOPkV7*B1qzE{CHF_$PA-(j8RH zOjGZQ`^C=Ll|ArFT5)!EE*!%y0J_o-Go7T6V4DnUf|tL9-Q zRZZY(1rR8*GgV+I>6l=eU})085b4#wgF;b})OxjDU}>?lvpd~CPOpRyoTS+5-fY!R zKvmH9-Y@6wd6RG~bI@0AfU8eoqRv|X0AH2y$SdX8Et%1>&HakMq>^P&77t$1PbHap zKb733hb9x@%F69#$0I92=>(_YTFB?Q(j4)OA2yg7d*a?$Cw3gt%ErosBoHJ@@@WM)LJ4PoE|Sj7wT*H zx+ppJxG=I|tIp*EItMMUs$j9B<2gaPwpL;`pTdXxDz6wekS|`Sqo5-CE31K{ELMsJ z_4I}VvUSxiuxo@lLsqbu#$Qd_^yY279g8C!sm>FG>hLhZA56F`n%m@t1Z$pRRQ=5skLCO) z_HK8)`|V#KdIs8mcj{$SaYhFBB{JwJV1D=0z})-`0YVsUSX>(=gqb&v_<%s2+`JAJ zuZV|c+a6wR?dMu)#hdJp4S?VDdGm`J3+by4lADh@6b&QQXVEoFU;B>r()K8<`LEH@ zdM_}(a-!%dK~ZXc4%I{kg~9itwvblUouaoYY%6J|Z?0eG7%r$n`ORluoQHHp6V+uD z^DR$!OTuDPRo@hE3TEJ>1TPM}Y#Mi3+N*xHer@i4G_twn-6Lb8UHq{(RxeHDTg>3( zBw0s`m9|cFNXcS0$7){8wyJtm#519bbnpncoW#CZ;kBN^)0*-~(}zp$2YHWX*DpfaZKo1#AxgVZ7eUTs-Rw7n7v3=)CkeHrc|Y%If(Ku!PF%ck4H%_6Cg4zBI(dB~1?DtaF*C27mEMq$=l&h|$D; z+e^8KMaPwml};;7jmz4y1fAf3R&k|IA(_~I0+p+CaKxt6ZXt^(5^`g!A6mk#WqXv^ z;oq|f7PEb(3~qa^G1R3sZfsQd3J{Scye7}Dtv4*?@|q|)?9t7747a8!`C!s#Kxg#l zA!t^3I;yTN=@4HuI(BdT4;51=^n?Ws%Lb8;7ZW*4&(W@1yY@AoFg@9a<*BIqIw$F4 z4mZc*4@DflfxNXbHy!-gl6ZVZrI9R5F!qrQIXGEoj-w+homnqdBUbzv^pl#z zBtrGV1}r2=^aBMM_A}Qy`z9BJNfM*WBo@Trc~VhJXC^j$UsMd?*w1_AhhxV)b04+< z4DmxXwuo<<`nK7#F|NL_G-P@kWLFCj=4VVZnR=Yy#6NLij!w#S2q|vTu~t2 zj)uErCXy5V3>2>xv~h8$KbU1*s_J$>U@6FV>w~n}0DD(#jLJ84Q_i0qB2GZ87NJSc z`AVN{hF5Ipv?^$?pW-y!SX+jcS!-zwbGIfM;*82dfI5hS!i@QaZ@^0wplNrONt9I7 zwrwmL*UIjiS*{L&i~Wn?G|6v8F^q^WTE6f;4&{m_W(4-0B=BW5NL6#^0n-=5M`UW_ z2h~`Q0(y#$^OIiiZ6S=7CBtHDPViM*Q#2BtF^;;4Ou;VX4pa?F)_gt( zi&ovSy!u?l(zXLlYSq$2ndd11!qonL6-R8~$7zFNgoNk>Nr<87&3UCxYoix_{3Lp| zR64~f*5Qu_qh5_+2%O1$k|ae6AT*AcTw1EYHf>^{{e10#Y=_%r==XJ?UG-!TW^VWj zoV)u2o{OHA$+Tt2OOYkNqh4i3o-?&)ot}IrEZG+Tr0clsAwDb4%1z;F>G5w9X+#6m z*E8EF)AU@rq@;uUn+U@@4qul%9ACP2)i>jUF$5Ezdk=YgT=YdnB|xS;saA$a*=r$L z&9DpbX2_3rH(hNckZtj4Scrk>5} zRMbHImKzJr5!zVAg3+CERfl>WP2AqB2QRiFQ=WR-3R=oJN4CKe)&j|d?UgC?+#$iM zmE-cl4g31uN4|^PQyPynD1^$1dm0@0^6OyIoH%`ZOd1BnE*qNUle|<4gyf4Fqh^y9 zVn!k&j#o%GdcYUH$}q)&nGId=$Zct#D+J+*9-)Lm8lmctRKkWftTSLiddDgnc^+Or z#p#ANe&EWhF2}?AB{RYunQYe~J(Zl>qrOn~=E&7Ujrs#O?hb`#_orxXnmuV5iz&ZM zKeM!AoMc0CV)i}zaW`j3k%-c!2a%c$tv&H_ehuKbR9hye6lQ71Iz+;+bB|5Q2j=6l z_|56Sp*{BoIz#=mh0Nz<*#V8GFSb9Lr!_oYE%rE#_?Q(g0I|_?!ZQhvxq(b1Z=i?6 znXsre2k^UYzCHKG2Z+WJfR+S`p9)2A-NhI6w({cORN>7%|2@g8UA&1IQIdR+CgJF_UhgILY@R6CSO#QkhD%?B_h2(jM@Oyfq%#Fj0?1z%2k|cEE_rgjgia7X#9H zt}zDd&?BRCiOO*XN4&2R`b>oa<)^nE7uo^5jpcI^`dq~|s=!^PR~qDmixfWbE2J-^ zvvRS}?Qdg?t7%khq!Yq2`j>hbeq_H$l6yZ`{=qh+3PB^gh#Wi5BBw3EewO{?AbXOP zQ2aPbKAg1GQX&eoJ}gEua@;cD{s^KqpozMyThI-T#) zI8wa*%R`0rugid$ZeUNUP+AkSNul5r8ah*tp<;Ti)}t?l%Rz0>V2G2|f83VR|GeK% z?sgk`8_42?zOAl}v6Y>r&9Ct_80ZM7>2Kp}FoJH`qobvz{UyGJg1(KOwuLseu${J< zvF?3*4OZs+_!_LV&lwm&7z{N0+EzmP#)d|A1VB*q4W;`$6C?AFFdHDKU*l}hvi=rl zgPIPs!TT9$~^j(5Lp z!|535|8y(YuMs(B6{Rg_n4fq|lzqyA7lYpwdad{5RNH8zM9KRx(>XG#uWpZV6JS2F zy zK|!ex9nYAZMJ454&^psmyzC;!BJCUsZZ?b#Z7F#YP08uBQc>L%qcW9VL%rLmuH9WBqgoH87-HuBf=Y@@-TBB0lJi3It3f4 z&pnyawe%Z4%cnm3ob)(Hlf}zUU9tB0xDq<3s$*qaMHbHiTf7f0m<(O>J^~QnFKeG5 zLV;=S)PiD(5$1{aE=|foSfo>aYi9P{sLpI=8Y+S&<;C*9>YB6!Bq#SfX^21amZ;An zEn7cK)VO%z2Tq0mq5DAGd0!)rIwfrW{2Cr1a*!3rBqEsSVV}PC#?ngDZoX5wFq7%Y zNnBPsV^XfuE4zy-EEorwX1}M;qn%PnDQufzH83F*Xc4f`oS8B9wG_PV6ZilFin|^z z`+e|?f>?147-70M=b+s|yKF%`vY#*W3&GFOTO*ju`nJrIt1F`%bJLhFEsLES5L8>n zpPPRY{AS_RdZ6+34LG3WklLgzMY11k+_8&g6W6n zV9;(Q^iRcN!3&tAuf;q21vTK3OHW#n+qihM zkf`5JLS}u;V!Lr6t!OQGNXW2V^{giXcr=<2A0D{t(+ozFf&C!jIK;bc)57y+Z8r=G zba~Xu%@yB>=dp6Dn~~&-$~CtvEycX^p8vOnk4{hI^K2kixgb5OOq)zs&&jn#W4g}w z@R3`%jOaTq%kx7_3g_nVWz&_3#Vu&HIo2~Ld#X2JraLtFvU9|aq;>xZf(F0;=9s;|G7xtOF}T7)aGhiC1J zL;*;`L6}OB?Hk}ar8AzbvH2);oj+ATcdbg^^T#SNTpUv75`1p`IZ{!sY2u{erNy3* zD>qi~RTnp0IEhy?fecRS@lbZNKo1W7C+Vz)S^Ch$>ZO2@;pc3M2=#!=1_tviMm*lh z?I~x1E$;%?#UNG>utjS%QMP>|ejYF`!w5`AXZ;dyU5VlughZGE(yrx++$E(A-HTQB zZ=@8A6=~=c$+`3|zS?pw^!dNiM6%}~8;bMwpxB&#aqiD!D-~Oq(3v96@_DGVqjm-g z;;B3&_L4#UO9A20tu336?9auLQCAPE9%npQ4+#%aBG#ZAWZqg{CT3vRH|_IFyq412 zG;(UpL-2Lv@=-C2sk0>_^H_qx9)_8ob8ntk?-$EZ(4N2PKS^yjd_mT?W=BzjdG@mN z=|i_^S4!UxjAf$()jOYTwZ&P|R3bm6+J4L;pWDnEdG{VbB+Nf-H)HyWN3k2t{A4)GShU)h2#D z5Gk2|!zwojA;XR%LR~||FuX+#<_gg_yFpj}>dT8XjE+9}{arAUp%bb<{bEJ`hp&zF z|H-e7^nd%>c=!I_zf}Hp5&j9>)3*o5Zlm%`#ntNK=diPTT*FPva(b!`a8e)e9vGJb10$(i{-JMSr@ro%a~g%FiO;A3h~5NZ6-`Au9s>ncii(+y z*VPv@){YJwn<8@E+G|RCXn~%_NQ;V(45$L*@Ew~Q=dHU~5yvWg+d|v6H;dAe(zxbk zud2DPUv*=$2{M#b`|F0rovPQldJeRhJx2(|Qo>>_yKKg;uY0>$1f8mM$~0TFV%&WC z`BZ$h^2r-hq7RecS5ZA}=QLx}@qGQ^;SvML+vQw&tEsVSaV1Cvu92t1C2O`>=`CRdPHj!Y7Bq~6^9S|MDKkzg@K zY{r;4T6>^uusucgrPTBUvwv)lUF*vYIbW63ZR(MlOnlhTUAi_>15V8(ai;n5oDe-h zbUG5%W5<5`*+;_c9nBsCQv))CoMy#xNd{8ItCn1WZvXglh=>&Ki;WXEZ#Y*5>?w{ zLbrw#28K0_GDn$DeTIs{dCf60NB>^i+Qy$oRIZ<6CYYfIMUqcWiRpmRO3%SJZBdAvTvp1Fw)){^Myd`gz7MiaA?e(gq*Ble-KyhnRT z9;eD1o-je9f9ORPBhjIkR$#jqfRQr?tDEH}iYiOE8L8V2JBp@@>nlwEoEpyq&Wte@ z5pz}%*|qAoFm*U{5)&;5S)_1j@V&>jGzBZ0WvwACej=K$kjSt z(zWyGx$;>-Mh(jOiM^G+7K7RV2uPt6bj%8<07Ng^K99zzlyPnl}B9)3BaYxP-${X78?K@+K*O+!FI9PkcOeP+!*jYI;q z9#TMLqcUGp9rZZC;S+DM$efp%N{mc28014;q6F+P&kGa$^gIc~ zZ!k^%0Ek{R>gA%2fW¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m z4qNW+*3dYM&*7(z9T-s6!O>5xRU!Nq!1p#{$q4zJM0n35p0-WCB%JK6vBXo1PzVcY zgj;UoM($DgfSV!qd~If8!E#+is^7}ZqY)Jh zzS;aKuVIb%fB~OjpA&6sdls4DB~|t&yo;Yrf*e{Uar8UU_miw?NKiNG>d^(@lunCJ zyj`K4K8#u%JMLfC>JernQ^M==NfAIEJI%d03SK16mbFWG?WaP^kr(9}?ybC`C>FmE z$lTix<~rINTrisT^g)u~Hy$+MOu;DFOlR7r5-|dKvGPk#3Tf*%`$%Gy(Louo@7A9y z8acTXk>N-Yf6;kMHNiy#gGMtEMaieML0&;S*#B1i((ap%Cm5h`SNHIVq%v5crQVe6 zOk9~V6UW*?%*iJMQqyBQ(yT&!Sd2aHIZLm{P9u*2&O*^n`fIh_Em<(s7r5!_3E{fE z+C%-vf#;uh);#CBG?%C^ju);1uco!bg9)PG0zdOXM80HH`Y4U%Mdq`CiNiO*CsD|V zUg9-TAnu3f5-E0WEl+5ck*p?B_*qow_z0aiSaoSQ4xA1yj@68i`C-3+HIB&S8xomn z04E(H)H@~Q=JcGd#BiMXUW14tb01SoXdjrUbJO$i;Rf71+BnR&(Gr2^=iUK$XL90C zW(6kajt;Y4ktRJ`f3{Ch4gvEeIR#;)O2#e+JxvZm#23;2_yGEycYc{?Ls$%(v{SgE zaxVnf8*n|l@~xg&IL09X@&vj1tm|?^d7JI6rJXQvunO?pvOjKL|M0<;;XnDomHuxZ zT<_lh`?jxtMH~G6i|c>(E9)J@e&5y7GXeiiY{6NOha3**E9>p9R=eEHUU8v913Uk`{QtiEI5c|bLvkcCymL4BV&f#Y9`jU`K_w* zhD9-GD#hm%A5i@}+h&DMA5f<#vNV)M*B3;~i4a$ql-HfBjK!sm*9C6h{(uyZjs{9NtC=P?*6GgMdFB&_$TIpt1Mp{E13okUFL=jt$YNq(qA$o5SLQC7G*ITk;O7G^fW z+Qw&PXE8Q#;K?3i-LrGxL3ZSPdKpcS2fxIE_C9pU%DqTbsV}@4jYJrwn)N+;7vA3M z9N1x1w0FZoMU2b!B)V798R1Ngg$ovz=n{Na&fXQ$3yz&s#s3d`Zvj=+_U(_;-Hn7G zorgGdNq498p^-x$8bLrp8dOj~q`Ol>kVd+Z6a=KZLEwMDd)0g2{l4#ezZ&B|#@h_e zS$plZ*PJW%K69=4nR6<6nm%8Sr}k_YVLpVv_LF$)-zL{;-kfppRl@M9Kq}&TXgG>n zXw&Z)4Pvde#-UA^!wO_JOEG7E>!a{sBPrf2nYz-J8DiXKmHF14x$3D{N=3NGqIif- ztuIxLWTMUE%(2*@4&rbiauri6KklIM{YD!s32O|je*5Y%vDcYWBm)3;k7oUEw`%w4Zu3-+t6cB~wo@6ch z_F+wsC$EmgFqJ~4!4** z{8-6r(ZwQuxFJ~;MW9zXgli(SV`M2eJErim1J7|=f23;+b8wqjF@kkYv_~Jq!1K{= zXLYb@I()cO&*a(zs@G z^5RwT>Dy1Rz5|$4kn+&-%P3$$1k|=N?>%w14KC_#uBqLgn{4~O|J1GCUneG@E4qEY zL=hZg*dvJ=giL~!OM;itCQ4y6eIzjQ{hn{-w@U?vfnfQ(dy}WMU*9;9@uLUGxobR4 z>1OT@Yvhy2O8uZ3Vurh`h>~sEZbng7Hkt5Pntia$=}7MdD6skiY?b2x;)+Jcg^SBp zd93@{ex|wW_K}=XqB5yKz&o7)+eL29SEcuf^n7xlDorf5i)Zz1g7_P4q^HLCu#dAa zgq0`f>WfyS6CKa;YPlukM;b`JF|EGiN`l=nwnD0pBt1EjO6gnTiS{(tuzZqi!gPr^ z7CZ0%@!<07y;Almu`TNh^KN8Jzt%A6)c{;fq6AkNRtV)icEFe+cjNsc*G!50#*96B z>3)e1ZGvAWAlctS+BZ*z?K4u|xIV%U$*|X;gk0!hMfc?9%dA88DNM3*>yxkZb~?l5 z`QN>Jq>t=d+@nRA=e515829BF>caERmCbi7%BpzJz0S3ze4|YLS(srM8aa$I~wyc)Xc}6_B^HkQevSFz6^83Pv%z7i9fpR^s&yS@+oV{F~FrF3mXI zLhiS5`%Ejpiw`pN#r+mah0Z)aGI!PH;Ny7~%=aw=4KfD5mYsJYGFZ|?y4x?`GhI@1 zxxI}^NRn=I&9{+tk%Biok+FSoygCQp3>Se@kEGb0{NlQq_4-1%3dyxCM{a&XeZ>T6 zLI&U)hM}VM{rG0uY9+-=SBS|q z*Y9Bp3fnQ*Aai+TBZ?0>Tk>(2 zgyqVGTg`hljQHdMvAHUBEWzbkjs!z6KfA1I@GIVd$e?2aSrQ5Si0drJ#haemdoM{E z8_0E11NURR)YWZqL(W7Np^6D&#smlgD{WlQ{&O0_m7H`9IZt0F{qkNB{JKrV zs%PG*t7Tg@2l^J8jg+qUMp>7Q7pfChofIX>*?DlOt+>+2N8ommHps-^a`dTp9Yzk4 z6+<{Z_H{^gkRBZ8(TJ!GQrq5+j1%M9uetR;po~8r ze2yqXVjw$ZS~hHMq9A5i(&UhBTW_IuvdeIJ;68~ZBd22B>rJ^C_p)P!u%N-{xGA4V z*_^N-r?fFzJis>`cSSyLDga!abJw`aiQ5*C#sjpfxNf@zPW{^ zhz(~(grv)(t+aZ#>a!|(xAOcZOZiTTGX8JeGy>6j)HXVlA5OB0K#0>wFoiYw8z!B2 z>NK_x>EWUrrpMvIhO}3yHILNky!v4n4YZ=MiSA8^Mw&0b2n{D05$%*xM7;POSuP!v zM8utIZy$n;y8mck7yUDg`R9y%7QG2?ds~;TKy82f-4Q$8iUC{48-^Mi*%v1&_Ol*R-(ub^ zDdK&5UISAF+R-5UCWWaLEpLJ39I_lNHvt*cL|P?XcXYDnsojd*cvD{l+k66LXE8co z1ej(-OZlkFg}O|pB*iD6gM3s*a)m#UFI$=qFT2rrNmPmzj_I9tgud0BbLcLfc8ej@ zw{JXqN1smHc=TDYm~Uok*0$iLZ)mcaFFEw>bsS~t{C28Uk@;K?V8Zg{Ce-kkjWIJg zOY!YkkrEL^CbM6Ynw+8cQMn3)ci7qyxk!@#+AC#8fG>^W1>n&~xy;3L-KVfH1=jZI z|M+V854LBVe7rxO7AZ+BDNA!l3(G&uFwbBxP*6}%Q7}+ZF>uk* z&~XW|F)*+RN$~Lr@$pHB@d%&?9x*W)IVCw6F)b|v11&8NH#awr(9Z)F6CE8B3lj$m z3x@y;8;gJd2NxHIfP#R4kbr=K?jAApxJO4tLrF#l^wJ_49tAn~yNK zC@{h>cJQzdVBm0J;c;Pa+F`|@{2{{L9Z*(p52zI)90DRVmH{dnI_%#s!a}VS|GbC; z1B(C)4~GDUh>V1S2#>)Hy@(5sK#j+VD6S5|f8ZRzg+vgSUM@jHOQ_Le#tn1{9F|0; zi`U#++&6dSA~3E?Fk(f(?AQ2DHF)NScdhT&yaaMi2!vE`%e>W=Z1 zV;w8^kc6C?&WUd)e6qUM9-)c3wOx~|r?@b1a8Pa$?s!5*Lgcw)ftnK!0m^~%1AIiT zfH;C%4q7yZ_qb`z7F`14B{d1nU4i>_NVg0i)AO{BK$*xSwvg85g;;+5$-=+pfZ-Pl zH`6c}@OLzEVZ>mLwc_RJm}q0UT{+8~!M#16B}vcfx(=}Md=P3iAc?>&$D$7&M+2Wc zq&|8a0(D?Nx%voB-cJ{+CnRsq|Dv~sG@m%>SkY3N>yyH8DGrTdB_1tA`qb}Bhf~-l zvkx#adHi^EQ%thw^1ealL`;7fl5h->-k@F6$}~i^=n0@$mp?(eAMd-zy1AcG*J}k& zYgnJI)66`j@^18553CG%+DyHyI}YRJ73Ap#7q1+w-0e2n*3bDst;nFkYi$F@Iw}_OsZUv?i}^FJm^aA zVkY4DRUHFf0~3FV4O~{MwQJuMK9Tj@Q!jMw41~ebe>q*xKt? zY-fXRALORi^*&F3k#88-xq)%1obW6EdSt*^Car62y#jyYtN#$-YS5dqnotFk9Q!dj ztQ0}19r}rEOBXlPRAJ_pxNKfi=*;cZP0FA6lydHiRIg%^_yMD*n1P_XwMp+9Y-u4k ze$;-=M;P|c;@cvlL=CpA#&3^PQ!_`&#>)4Lj-nFAzVX*O9mylCDGiL+30`6{5W0!&~osKEHVIYK}HO)ozn- zd@Hql;({kl7-W`wJ#Md)RAl1=V>Jm3eJpFqUOeQ`c2Vjfb5Z@!`~W*g@f~7u)pgRO z$Tvgx!KAejc~#O;(IU56kS={ zpF<)94eEXN-&rkC&O{}D))S4TiPhDLSMV~)|A1T!NlhOw+Ni;Zsj82Y(F)u&&@}wG z3Ve(q)idZnK2Y38ydCbVFOko6j^#Hu%IY_uOG@oGJj+ME-}s4n`m9E&>$e$X;pzmhtKDKH zXCMMO;(OHIeB+KqZf<>S10hzL@DI|@M4CS_E2T810h~SwYlMBBeQ*&oQXeC~#@4=} zWbb8MT_eoX(l&pvAnq8xh9@u4{_EMMjn{~mr+t}?{n7^R3InBl#CiJnAB6(T8w^K}lD0ir3gsUq&U-3v z>(6ofHH2O?OVh?HRHENZ{o`-%FT}%7FeE_Q0s4Du>tGH2#dQ#OaJBt;E&+12yhS4d zY(Zc)2}iJnvKCa}{wKaTxj27H0so3I?jNWRU0Vx?%^hb@X8zS5 zl<&K1JUq87-+ul`{Zn}XzS}1M@BRIv^Ml%LZM@KsIDhhS`_0cUaF=(RfBVk?joTw| z#}`yS`AHvI)9*e0%QpOHkN+C0-+-~aT>Q|$b9}s1TpZlc7(X1GzXN0cIsjmhwd?Jq z_z`xFlN&0Y{Q|`P7I%&ZigOirHHSv4qZ0TF9+ng8zu^vIEAC(owxr_t9SwU&>fd2u z`8YU!n^eCvBtM(@U!7F{ay~&L5B=D5Ry?eq5wlKJRFcc!RSHIKj!?k_D^rGySP;U@*N>>0i8~^5HB`4!0#_EHF0?sO)q;h zM=*3me-0dUNx<<(xI-we8*=-Wb2R|oMes5LXgO*-*xs%|sJQ>8@wzMVg9BXyXb46F zAdi3%^oBoy<^P_tq`cHEvD-Vi0MHXnFIR}Ay}W~!BQzkPs*8oC3-nFQ_-9*~02-Fo zwyqEtFUGsI3KO&iPEKG;``af6I??YQk6#Zh74XLjNJ{q(zy9k%0R94n|1q(61^EAI zW&wU&hT`8jIe<_CP|}tldrUOB=d-%#TKLvPslowL#>#4w*%$EAi18e-K?g(kBtAL^ znBtjLP4J+?KmXRz2cw}Sr-e|Q!2I<^_;h&qnCyPJhyig-2{to<389e*%cjm|roM^x z!_)hDfi*j+m8)B+B0{d$+^)MfbC>=%{=5BesW1@4FR1BI&`FcCS~S>+cvS)U~eIj?d0>doG-#tU%N5{2(6w`KD`bqMrjQc#*sNy7Q+=M z_C<@^QQX6EL*H@!(5l$=O7z6alf!N{uu#qI`6pAkCqsUQgQ=wSp+RY*?;BCrgZiCf zEVw@NJO;uO9uFfpkQm~H(L%m3w}-`s!IwYamuTS(X;R-S5UcqzQja*9*EZmSFH^Eni3pB0Nd% z?XfsSxN_qM4ePmVJycwdBarLLhePI+6okP{gY^vi$BCS)$E{Uc#G=jhEbp zF{t0Rd=&;$W!XT9UrmVoB?RH#cu=&QZh)3jYFM_}wEV*oHAe2L9$H)y2eb$ZRAVD} z3gM4J?zGG=WYTHWJ(WYuih#`e7nNtt&9Ia8P1XYoRIHO`o;xc_iRc1!upa%DQfALt zoESWG+5AhJPumZZY8p?>hZh@E#16b2+pow7p&qBJuUBec+zfr6%dB`i9)&L9I52S; zH)`$omTbsP?}o8RMXWk}j*j?v-`mah!EDy1=1XQ_<{nEbn#a+p`7lxdH)k zyW;GqB~2YA$Ik?=Iirfc1=Q}CFA!f`RKGM8H+H_ZTXpSBX;dFkhgkIn*$2N(8Cc15 zm8_A%X#SoK1MsKU|9EC|@Ywu?zx}7650}9{s%tv^dq8Gv$Fr@*qSyGo&v7ah1*$6> zF97(=JEA-9PKvwYdHi&)xKqK>n&OtMoz7cx zAEoXJ3!f8wbL1xH?1Ncmxfx$2tPK*3KR)b9j_+lb*hR^`x}n?WUFQH+b?q zoIB30H%sq#obUNLi(cmeL>8&{+P4T)K0BkiY2Q4^CT?M5P1CF&aB4{RbCy=<2u8Ze zPe5-pGe^{&o;_&XT3W8uGhB%po%JZ(UJpHLa59tcrl{ z$>uOS3>WC1hU3kg6-S&ZKWWO%s{T-r&QGFvRGF$@7nDBZxkvV?{ylO>@^SJ2($b`8 zQF7f$%&G=n|L${Zk8LY1z2^9#8e57&znlD(2u#*Ng#YMlcj(Ts~*}<*5#;d*PPcFzGw| z!hwxV(r7I05W)v{oT|hZ6adspA+HzM+~tGE60Iftq}|96y*Eqr>0y6P-fNcJe*af) zAjfKLx36Dpo|%eWen!TQ5wL$%8|_~%LT*Hn{jS=&H*zRNJ4zS5Y1QyD{lkW{$PHhz zsOsz0#)}u`;g4(Dbc+p1oQRrnu=%$$Ck=Gl&-Ww|YlE7Q6wSmq23E+?NyqX_=5^lc zyYW&RiA@_px)gI}>>ZS}9KsSEwrmXMuH$LdZV-amlx*h*}}o(CHz`B?a$lpIelIGzhs`su6bHL)evy0wn7Kgg>*x@yDj zyqp~&lNizW=(IG#_2oKV^EG&Uvz;koO6>@7WzTRJsM}dE!*VtVZB*R&H<|u){ihl9Ei^ww4WjZLzr=t zXtJAVCI>N zuDAd3P!bz0$0CB|r<&Io1X!$dh>{FsDkIvG3sd|7Gs^E#NVXn*l!&8>dB%YkO90|j zpOBz@W1SM6%=l11>M7S!+9{6lMfN6L5XWoAdg|5*sYTvdm4L-qc@pdqTHB{ufvwU9 zm_&swHra0)H;O&rKR)c(pRXGBOsduZ2RTq-eI#s0NKFoXK_GCVof5PlzJ|U~$VnK$ z_y`Qd$b@y5^Ag1(w2c-PvV2+uA!>YxAcV)UDg8O~ znC@bov>aU8@6-=Ks-2az57V{mR`diNGYpFpa_u;?k!V5pqzlLuHR)l!yfxm5ri5pM z$}kl@fr1o@s?Xu4ofTs9)#0?cd^>=1J7pG1)RWAx1U&jYIYT)ra7lgb`wGECHriFF zs<~R`dokMH_l0v5kVzlcNklNc9KsTm)6B7>w)aL=%KY?f6ZTx}b?HG_UI~le&WGLp zg|rMRc2fueu9_q=v7y?7-m-3H8pezS5Fw(>6dart$uJyqgk2!xSN%YBxxkF)53&Mv zigYk|q?Dx)6~|*}cS5`b;NcQ#zDzb>9KZE~$}J76^M{vjSLRonyZgJa?csEPmtT5yNsC)NA{5^P zXVKYqIW9>`sT208F;ykvjNK~p!u{)f(u1gIjSxM>OneUF>vIUIQ6l(E=+(f>(HGCl zrWbR+)X92i%&dD+bu6sEdI%PFu3otr?0=w$nL&83 zbxG@RLdFLd!dT*C*dhk)O^owB)^X#l^zuI zZV$$EOkfK#9X_!>dq^fb_5F%wyiFXI2?w4!Ezkz))$zJhLgEv`v8NI617^Wxt|4Q4KNS=D@=pZ3f=cqPWVQ+NQ7s73T1JsMRXBYia&H>!-f!N=2Qf^B16&D>xoC-h(;*@m>2c)DYWU{Q1s@ryC%eHV@1< z{gJk#iPws+YlxSz>zyBJl>0U8wc6wc$lj#&sP$@2b|G~1IVmY$?6marltzYn6Cm*N zWKE*PiJt5ajyOp7;gn(}Vv~Wc9Q={oXNuxEhk$DZHq@h{M(GfeP4QR2~Go{wx)6Y+? zY%@JJ6DmB7)M;i3knGJcPgUiQonW!K!FG9~cP2|0xtgYk7NFcwX^43WMS=`(hv0Dd~2 z@M3x@EJi3QM`+$dgiajP%WgI&WbBkSEJJFtuX{e!C(Trqd#JFetX<5U^`Jtg7DJL8o1LNFc_*Wyst&*6+{=_D#2B@bX9 z$(O`3Kyb82AJ0QwDV$KM&7Bu7Fbj9_Ahq&WxpNkUSd7gg&47p>CoJguORPUtF;mqle_{LB5OIb_bQ)N&9>+9@tq7#Lf-J{{131fWUV2kB=s#UzBEc~yA z2)(A5?QNm4NRO-7iRtc7u}Ct>iWaIj1Gw5|D;dyip~>@jvjv zlmGh3!6jZR&UG2imO*tL@>tPY^Zte`&HBBhhljQT#cAV5qF0E;DQ(NFsZZK_^w=7@ zODe6f-Xo^OM|{Prqc9XWWt(gfS*a4)~cPCLTSSyF^%-cDJlo7sh6WJz>7H2IGR4H+CvVT0zZPKFcEluNOnF>G$Z96a>LD?`i7sF93PK? z-m}lt8ovt_HF0*fJ$n12S-kSshaw+q+{s4~)bZF7nX}dE87=J+x(i>Kjz`oN47u|) zJdT0a8hEUDIMK9)uc7}+^kH2Uc6N~tt9C8IshBwft-;tyxklIZfWO#{KRdVeH{N-J zpjn|arT41WR3Dy=vmJ=ZzSA6%XBT4&KE=34Ot)FrYjOH@s^iPPSoig7Ef;?TJyxS5 zXTMozp9=0-H&2wr)N7;nh?8~6WytUDIbRK&6YPF)TzFvx5MB)5_d{E9wP>9gA3vv4 zmGv>O>#Zp^NJ{4A<9)wrzBu0#FW!;RhpU&(a7v)+%fO@2snf~%s6^5S z4a1xyvI8%){ae>cLaWMgrX-eaf(7H~3ExUtzYjO{NrJB8z>$ES^azzbvjyeWf!|El3GpBx?w++JHitGW_eb79A6Y%CvQ1 zL8I%Gff}J!yd>_pN<&cr5qgnoqPUCGfkL)!zM;MIWUg{{-E-x{qEFn?9V~C!E0k9u z9-YBRiPi~a;bX+kvTAfCrgXT3U1L2-QY^Gf#cLsnG92O23*nK&aQ;Bs$JX9Ns+d?W z3TVaPXJI#jnu{jd5AF?vE-*-XPd*(OOJ3rs8nNr^cGZL}cky)G6LRxPZn%~TIn2kW zM?_V*f3!5)S#=_l;@9w&ZSOpiI7B_o8tH++qX5t*t0$S!y_JkUu4aozwV{s&SRW;{ zWisz97kc`^7G+kro;P=DHSzLKtH_@>b27M`sOe#1ZbdM*SOCRp)6=yz2IlL*y{?dA zu~vgR;jTwsbK%JcA1k==A4qFCEtrh)9m~nYJL_)T%Q#Zggjko1N4j77lfL}q*O~!2 zU}ZI-xA!Pc5YqWn*u$c5pjWoAEFpOrFTbQfRwn-f{hhm6!|D2^>b+(23t&lO3Htq| z{GO6QSd(oWZl_5nLNmChk|Y7J&PeWI_GK@`(6?>KB;F67AWf66`O~U?S(vVPG`1_@ z8<;2i3>VFeB%RuwrYV?YVR`|+-7E6A%v0tZ9S797IH_j!8J#RHDcDDiZZ_cFFq%*> zSz5-x^YdDg@HA|%&_#lm^5d-Zm)0*mBCw9mStgtaQd(t)!pkW_m>9dJJ<^KD)zIg@ z!uEL}_msbT7w-QcGGGif-;yXL}7fdHtF<7w? zs_9AUq-XcPzBb&0J1Dv)TIR_zUmFcAXRq4*czy&bzWSb9cHfrfq~YBS+bq?W&|W#> zA^*ZXl8N}i<3`HB!eGuB=aPp6AQgg7R$2a%!U?Am#SmX52L z*h@Ru}aPj`9wG$-Bw*=!2PObChXKM$-dMp$=(__Dh!{IyE*BN{)}h;*<@FgRXH6Y7ouT-iSQD?AtT90L7$MU!4-?OW>?YQ1@2oL*rg5rlLyaEl zY+iZGibuSk=v?B!FD)OvM11o?oW0k=(aUJ-8vtK9G7QcR@hzWoktLs?C@TL0*E2WS z$pdP3f}Nb=5;d6~tPvvJFomm28e54Ro-vJ`YK(w%xe$vtk9&GlwgsqYh1^<_a+72v zAfj05pkPs~LQ=DKB`8J}`0GlTxWY7 z=lGdK-d1|*BlC9W#0b_9e$gHqR`JsO=P<_wuyor(=j4a-RwwxZz!VHD=@Etx&p#Fo zZlV{IKjlS!V!?03_knrtG-0G)oPzXvl9JovwcDdEt`lW3h9w~PX?f%*>k_c{^Xm2} zH&R#Y9PQYB`QD-8#l_4~7Q=MhMCQlUc5^E^&sCnx32r5fPGBQa?MhImc1WKY>qeT= z*A8x*)6a7BX|)=kAJF%%V>KL09yrWfNVw%sW0owH01RcP5EB;kp2D)c=^b#jw(763 zO6(jUjiwMkI}WYoWY-V%2x9C|x5oJ@Od>6rvRYRFCm)8N_tMUQtweN`Ms+tMckt-* zsGa`N!$j-hwxOyibjCchBUyEJZ z-k6KIlP(?|T=v$ws&be%*kCFM7(etA9E|9`K`EvpNIN1B?LI`{jeR3LD2{rroVu#s z9J`9Re1F9Ym)GfA`lsjZEqcP~jky?6^e^Z4X_mUwvd_9q-jMjyxr4#q!?>LJ=hG0( zy3B4`^5fico^@g0w@%9J5mU_e9)H%t=#BI2Y0#5^*4l_>0~=eit=NYev{r!f9QCuY zcq!`SAjgq>yH%_w&#;;v=BiLM6fo#+e#XMv`BJy)w~AE4y<#{6G;pg|k$j}j;!hq^ zp>?i)k1oQ-reQ91W$fbIf@9Qp&*M3aKq}56E;S_yp|K6DOuWx)kU}pOYcPA^Gp|L- zujU}e2T6yRR<(hl3{7Lg4p2vIvgUrvS?%PVAB@T9n~63;i)ivXQ2WAzvUQ9Abp zWYg&lVT0OMC`BqL#`0d62L|MMjR8J$y78PUUN5GO%$ckTRrk0=(WUI)IKF<8SQtof zHG+5FW3upaV%;LZ2nT~ z{ZNA2f-SkI?i6_%cNr2Aj-Cb_P?uFuN1>dYoZPo6Kc3%QRzX1?PR98DhO)Q?^JrQ^7y+(MAahHAJ-`uQ0k8ys0ZveTw4(*U9bf~n1~>rR z9H0tnS93=fOMn{y06&ye(ZE0p?KHt^+^{paHOSb_0Q-=l1p>fTM#Yz{=L$5&-dV1l;*i131`1 z^B^`ZmX-hz1RxD?c5{SST9|=PA|U@?Fa(_c zK>`04h!Zcz-=ROZIe+HT{wKQsk@A05>ObS^M@|1!;-9bl zoz8##97^Lie9Yam^WzQj2aJIm_>acAe;p*r-*F5UTDDpQQ>4WkIR)Zr0wbFI>-5^& zc)Gx}$Z!Q1acM*ZFhUlgg`-scBLtA1)x#WzN+sQ~G9?f`P03x4TbP=P&0yS%-@Hz_Y$_ zbun7?o)3Z$MDPyN@h2khe}H{){n@IC9PmD3^>n8EL)Aq#OBshM*2skFho!AjWQ8~q z%BQJbtJu6`Pc5$2?)evZfHuLbua>+@UTc@)MV~Y`p&x<*48uwJRa&i_2-=W2tid+K zzA5+8vTR=a_4ecU)NA1_UBk^ziC*`7P? zG0SB0I(@`SMdo9KFO~tPC3Ko2tnIm|ZIL)*B<;RfhSq|I#=+QSU!;*I-?M0F9K>X~ z6yj%qu?0z1JHG7>yaWiuoId6DB$C`>+)V5uPv}!^tK5$ytoJwUv#b4Q=@fcZLSyNLqzV)()oD$BFCXNq{=-C(lgpBmuvkVeiS;7Y_yJZ$25 z`062j3mWUy>>eU2KdkJNdrcEpO2)}XiC%FOVeSR{8t*;VzQYUf1zGHYw)?wIgC=rT zEy+KbR+>%Jb>uG4Zk=S;nxY5lE%NCdn2=x{^~jv*>2)@`7LBHuS?(V3TukR4gtTcR z4_0nJ_fy_M^Vp^B$0`wiePOp!%mN<{x{7}KkwcX(v6MN}lBT*^*7foG&NibBRHL>TL}suWdqOfen?0ZqWkC%ih(peA5#G*6`(uMjftq=hTgU0nr;Bl15%?+i)-R$@b*;7nPc5935HkV(E2KM4>+ zsp%8@a4%Eg(UhLKm+Tz+x#?$=gu$y9gNB1iB1Wi1TW!}xQ6Tq&SJ)G+N<^$7lrc^f zoVt0Y!rxEdKh}BKNP1sD`|`cwHceH+5_4yZ`f9PU%eUj1cY`%zq$qPA6}TN+zlk#9 zWW6R?2&YnF%=eI4$rYdoSrZ?u|Wzu(b95b>r)l z*;ex4=3T0}3^6bL!IsErb*hgBO-6%KR$$Errmbt1so@{d5j${>(OalyKT z?4J`jmFmyrvq<{^$y6nzVOAPnj&|wKDkzC~BhH0}+Jxmd#;VHsf(#1{2|Sm~zyaIk zM?PS9Q9$VC5xk){K4F=e`LtDVrO(wBhl9WCL=?L~m_qBc#c`bW_(9I{l4DqG)c#F{gdZOHK%&N39@@7N z&rJ))mHa>(3q=#eq(Juz10~G}ts_f0vpseF6T`AYES~D9bj>N#r<1KhGEPAOE7JZZFElOIiBCQ&w_bg2+?UXQ3Ccqe5EaIGLkF5se+~L@GgaQbb=7^vqVcoV{ zVFuh}7b}-kgb&JhD}b)dMPkmFIS}b2f)>3y2LwxKk1c#hfI^N4`k<<#Nh)u%;BSg% zv4c*Ywfhf06}of8VHbv$F+~Vz59X|)=#=31<*X&7fxuH0!~E}R&C5{8D5g5uVc7c8 zh3XF_nCnJurIF)TG~bYgc00pkptW_KX;8ORYQNiyMKIv+DtaEtuZ`Qa^SFD5uREPs z?%ARC;J)^!3w-vg$L@}s{YpU@t17mcsdjdPK9{NFlxTHR{jxN@VnJA&XP_e3sI34T zH!;Qjzq*=v11>wv%!N_8e5aF zQPFdlJ)3PMxyU0e>*Jsz#L&<6@$%-xaEDXfP@SA;eFqF~OQ4Wtq2boZ1O|t5j@aPh z4iU0NWwf=y1wKuCCY=?Sp=bN*A`LC@K~aVd;{#aYGGR%>lRzn)R}a<-%8tbe;dRLD z2dhHGygh7_mAFcUPE!vXzIZ7$%u&D%uFvbtejN#Wz&0+l#!a~@8&W&WgPMZ09+yN+3=%SwKDk)-+8tuKAV1rv z(@#!UM6sFPt`}NR&i!EM_G)G>C+y&4AZ&q#ml80?N^dyyW;z9J*$cx4?jxm$b4Ua- z8hlILC1hVC zpLb_q?3-GtOta^z5r;=lNyk&5&i;qsP?2C^JxUu&O~1#Wrpk-kZwY6U zA&{=9qY2c)5F%+GbHL0y__~h|(0cDL%z;ic+h{O-@ggj`uaSeIsn$jNQ$7wgi(dKQ z8Dm>((9)HAS*EtQd#*{TWWeE(@wQ;s>d8W-Nxcjxp+&i3g*thm2B-cZlfP*;!@G5r z=7<8q!moTGsA;n5-az9(y(hdMi~WPq~LoPi3gRpMy@%1M}fZf$zyIKG96|8#9wk9^lZ3%k4DqEq^kaTvsd3L8E)y7ZSs=E&I)BKH2B(p zD7DUZ_wyLnR{fcR)9Lk`z#e8UyM)VP=69x_bCTer>bVw`yfxJMOEHI}L!KAak-eQX z*qeVg55XYd=s&K-oIDRXDXo4$q(_(g1f@7s=D}c=pD`lEDTKl|3~zgP{!v(^bEhKT zYwVp&0H~gdV$tx!ceUrf3x_Rne&~(ZspD%n;FTyCMbpncGc5RxR4-oyX>f^{95ls@Lg< zCllOK4FT)pc^G)~z!*+js+1wHF3su3FSF^c$chyMc|9j!vAFgIoh+SH3+bvtJ1~A2okbTSs_QwE?1bYUyT6yeJDx=K*VkI4?Lzd(}Q19i}g2 zzgJetS+3Y5|0WGrLORDM8u<-odAj<$L#9t%$Lkq8q3}pS_=Xit9hpjf`LBDKT6JH! zeKB6#jO@DHeZEx!6aI#Y(?|zDiZUL=+deA5RX|Xme zelMAXZF~Of zT?1aIvD3f4`ro<2$NBF{^YGtJS6<#*6QA3^KY9D{%?EX2#>;=Z1I0lF6u8~$T`1g zxqq0uC|g2679a@d=TPb?EB)GM5f<}=?j+h-La5B31}qLD47&}@3{@7VUUF@hh*?Adm>vXZO64a2A`J+bYnFxao1mYwJ0C;$KuzPT`JGxi{ zI0Xa*032KZE-p4`2{uXlF~ttu)dbk;0XW$?06!`H z`TnqVbfCJW3^H?cgNQJ=x!GC>a$525SaO;1vzhbrbFl%rK~`)6TpSi`7FN7`KyGdj z2R~5YPkK(j@%a~m&~3rrM1P9O(M zS4(yaNAn-k7Hs>+(B0Jx_(ctxGXF85eh}2ObpDgFs4J9&gQd&gYPc(LTf@)${^`NE z%Y(i)Zo3-r^R)y$qxyev{11`;Rww^Ycl}Ry{kMAHzg75uX4n68*MF-A{#%9rXLkMn ztGl49m_OG(mJZMbj|X&RgNX)B{$WcGO+gpem^{A#BT&iaRxD+df(orrt9z)M4NjC6I=V3aD;b*!@aO7*@t+qDhJUUe44Ie! z;%*QdXk~xMRKFoIJY6iUFwvk3U0&$t&x4AWhliVo>h{X*!NbPy#o9|XaMQI-YdY*!~6Gk2=MdWMuPqeU8wJd+YOSx=0ThG z|Fw1PItW7{bZ_EkboRo16cSfm9sGh04z9J6U+*C%M!=Quy5*6SkVDW1s20XN!tsHI zQ-z7v?W*;!J}Oo1lAou+ vital-amd-serial-s25fl-REL-s25fl256s-2009-11-16-1.tar.gz +# Release Date (DD/MM/YYYY) => 16/11/2009 +# Release Version => 1.0 + +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2009-11-19-2.tar.gz +# Release Date (DD/MM/YYYY) => 19/11/2009 +# Release Version => 1.1 + +# Corrections: +# 1.Negative tests which show how model behaves when reset pulse +# width is less than specified and when write and erase operations are interrupted . +# with reset signal are interrupted with reset signal are added. +# 2.Implementation of Continuous Read Mode +# 3.After 8 clock cycles for instruction, first address bit is latched on the next +# rising edge of clock. + +# Files modified +-s25fl256s.vhd +-testbench_s25fl256s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl256s.ftm +-s25fl256s_vhdl.sdf +-s25fl256s.v +-testbench_s25fl256s_verilog.vhd +-s25fl256s.ftmv +-s25fl256s_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-03-04-1.tar.gz +# Release Date (DD/MM/YYYY) => 04/03/2010 +# Release Version => 1.2 + +# Corrections: +# 1.Array variable WByte in sensitivity list is replaced with signal WB_flag to enable +# compilation in NCSim +# 2.addr_cnt for second read in high performance read continuous mode can change its +# value only when CSNeg = '0' + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-04-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/04/2010 +# Release Version => 1.3 + +# Corrections: +# 1.HOLD mode corrected +# 2.Condition for PP operation corrected + +# Files modified +-s25fl256s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-05-21-1.tar.gz +# Release Date (DD/MM/YYYY) => 21/05/2010 +# Release Version => 1.4 + +# Corrections: +# 1.SRWD bit assignment is corrected +# 2.Condition for WRR command in write_cycle_decode section is corrected +# 3.Blocking assignments for signals WSTART and PSTART are replaced with +# nonblocking assignments +# 4.Conditions in Page Program section are fixed +# + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-05-25-1.tar.gz +# Release Date (DD/MM/YYYY) => 25/05/2010 +# Release Version => 1.5 + +# Corrections: +# 1. Timing control sections for Program and Erase operation are changed +# 2. Conditions in Page Program section are fixed +# + +# Files modified +-s25fl256s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-06-03-2.tar.gz +# Release Date (DD/MM/YYYY) => 03/06/2010 +# Release Version => 1.6 + +# Corrections: +# 1. bus_cycle_state section for PGSP command is fixed +# + +# Files modified +-s25fl256s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-07-28-1.tar.gz +# Release Date (DD/MM/YYYY) => 28/07/2010 +# Release Version => 1.7 + +# Corrections: +# 1. During the QUAD mode HOLD# input is not monitored for its normal function +# 2. Internal pull-up resistors for HOLD# and WP# inputs are implemented + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +########################################## +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-08-24-1.tar.gz +# Release Date (DD/MM/YYYY) => 24/08/2010 +# Release Version => 1.8 + +# Corrections: +# 1. All redundant signals are removed from BusCycle process + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-10-14-1.tar.gz +# Release Date (DD/MM/YYYY) => 14/10/2010 +# Release Version => 1.9 + +# Corrections: +# 1. Latest datasheet aligned (VERILOG files only) + +# Files modified +-spansion_tc_pkg.vhd +-s25fl256s.v +-testbench_s25fl256s_verilog.vhd +-s25fl256s.ftmv +-s25fl256s_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-10-20-1.tar.gz +# Release Date (DD/MM/YYYY) => 20/10/2010 +# Release Version => 2.0 + +# Corrections: +# 1. Latest datasheet aligned (VHDL files added) + +# Files modified +-s25fl256s.vhd +-testbench_s25fl256s_vhdl.vhd +-s25fl256s.ftm +-s25fl256s_vhdl.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-11-05-1.tar.gz +# Release Date (DD/MM/YYYY) => 05/11/2010 +# Release Version => 2.1 + +# Corrections: +# 1. Hybrid configuration added + +# Files modified +-spansion_tc_pkg.vhd +-s25fl256s.v +-testbench_s25fl256s_verilog.vhd +-s25fl256s.vhd +-testbench_s25fl256s_vhdl.vhd +-s25fl256s.ftm +-s25fl256s_vhdl.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2010-11-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/11/2010 +# Release Version => 2.2 + +# Corrections: +# 1. QUAD Program operation during Erase Suspend is added +# 2. Warning for Resume to Suspend time is added +# 3. During Erase Suspend, after Program operation is completed, WEL bit is cleared +# 4. Implementation of Software Reset is Changed + +# Files modified +-spansion_tc_pkg.vhd +-s25fl256s.v +-s25fl256s.vhd +########################################## +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2011-04-18-1.tar.gz +# Release Date (DD/MM/YYYY) => 18/04/2011 +# Release Version => 2.3 + +# Corrections: +- corrected timing for internal signal rising_edge_CSNeg_ipd + +# Files modified +-s25fl256s.v +########################################## +########################################## +VITAL model author - Branislav Colakovic + b-colakovic@hdl-dh.com + Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2011-07-05-1.tar.gz +# Release Date (DD/MM/YYYY) => 05/07/2011 +# Release Version => 2.4 + +# Corrections: +- Latest Datasheet Aligned + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +-testbench_s25fl256s_verilog.vhd +-testbench_s25fl256s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl256s.ftmv +-s25fl256s.ftm +-s25fl256s_verilog.sdf +-s25fl256s_vhdl.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2011-07-14-1.tar.gz +# Release Date (DD/MM/YYYY) => 14/07/2011 +# Release Version => 2.5 + +# Corrections: +- Optimization issue is fixed + +# Files modified +-s25fl256s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2011-07-19-1.tar.gz +# Release Date (DD/MM/YYYY) => 19/07/2011 +# Release Version => 2.6 + +# Corrections: +- Timing check issue is fixed + +# Files modified +-s25fl256s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2011-11-18-1.tar.gz +# Release Date (DD/MM/YYYY) => 18/11/2011 +# Release Version => 2.7 + +# Corrections: +- Time tHO is changed to 1 ns (customer's request) +- Setting of Device protection mode is modified (customer's request) +- BRWR instruction is corrected + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +-testbench_s25fl256s_verilog.vhd +-testbench_s25fl256s_vhdl.vhd +-s25fl256s.ftmv +-s25fl256s.ftm +-s25fl256s_verilog.sdf +-s25fl256s_vhdl.sdf +########################################## +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl256s-2012-08-28-2.tar.gz +# Release Date (DD/MM/YYYY) => 28/08/2012 +# Release Version => 2.8 + +# Corrections: +- QPP Instruction allowed on previosly programmed page + +# Files modified +-s25fl256s.v +-s25fl256s.vhd +-testbench_s25fl256s_verilog.vhd +-testbench_s25fl256s_vhdl.vhd +-spansion_tc_pkg.vhd + diff --git a/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.v b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.v new file mode 100644 index 0000000..7981057 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.v @@ -0,0 +1,8062 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl256s.v +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 V.Mancev 19 Nov 09 Initial +// R.Prokopovic +// V1.1 V.Mancev 04 Mar 10 addr_cnt for second read in +// high performance read continuous +// mode can change its value only +// when CSNeg = '0' +// V1.2 V.Mancev 23 Mar 10 During read operations read_out +// signal changes its value in +// shorter interval +// V1.3 V.Mancev 12 Apr 10 HOLD mode corrected +// Condition for PP operation +// corrected +// V1.4 V.Mancev 20 May 10 SRWD bit assignment is corrected +// Condition for WRR command in +// write_cycle _decode section is +// corrected +// Blocking assignments for signals +// WSTART and PSTART are replaced +// with nonblocking assignments +// Conditions in Page Program +// section are fixed +// V1.5 V.Mancev 25 May 10 Conditions in programming +// sections are fixed +// Timing control sections for +// Program and Erase operation are +// changed +// V1.6 V.Mancev 03 June 10 bus_cycle_state section for +// PGSP command is fixed +// V1.7 V.Mancev 28 July 10 During the QUAD mode HOLD# input +// is not monitored for its normal +// function +// write cycle decode section is +// changed +// V1.8 B.Colakovic 24 Aug 10 All redundant signals are removed +// from BusCycle process +// V1.9 V.Mancev 30 Sep 10 Latest datasheet aligned +// B.Colakovic +// +// V2.0 V.Mancev 05 Nov 10 Hybrid configuration added +// +// V2.1 V.Mancev 12 Nov 10 QUAD Program operation during Erase +// Suspend is added +// Warning for Resume to Suspend time +// is added +// During Erase Suspend, after Program +// operation is completed, WEL bit is +// cleared +// Implemetation of Software Reset is +// Changed +// V2.2 S.Petrovic 18 Apr 11 Corrected timing in always block +// that generates rising_edge_CSNeg_ipd +// V2.3 B.Colakovic 05 July 11 Latest datasheet aligned +// V2.4 B.Colakovic 14 July 11 Optimization issue is fixed +// V2.5 V.Mancev 19 July 11 Timing check issue is fixed +// V2.6 V. Mancev 18 Nov 11 Time tHO is changed to 1 ns +// (customer's request) +// BRWR instruction is corrected +// V2.7 S.Petrovic 28 Aug 12 QPP Instruction is allowed on +// previously programmed page +// +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL256S +// +// Description: 256 Megabit Serial Flash Memory +// +////////////////////////////////////////////////////////////////////////////// +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// A device ordering (trim) option determines whether a feature is enabled +// or not, or provide relevant parameters: +// -15th character in TimingModel determines if enhanced high +// performance option is available +// (0,2,3,R,A,B,C,D) EHPLC +// (Y,Z,S,T,K,L) Security EHPLC +// (4,6,7,8,9,Q) HPLC +// -15th character in TimingModel determines if RESET# input +// is available +// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +// state,inside the package. +// -16th character in TimingModel determines Sector and Page Size: +// (0) Sector Size = 64 kB; Page Size = 256 bytes +// Hybrid Top/Bottom sector size architecture +// (1) Sector Size = 256 kB; Page Size = 512 bytes +// Uniform sector size architecture +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl256s + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + RSTNeg , + WPNeg , + HOLDNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + + inout SI ; + inout SO ; + + input SCK ; + input CSNeg ; + input RSTNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire RSTNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire RSTNeg_in ; + //Internal pull-up + assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd; + + // internal delays + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg WRR_in ; + reg WRR_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg PU_in ; + reg PU_out ; + reg RST_in ; + reg RST_out ; + reg PPBERASE_in ; + reg PPBERASE_out; + reg PASSULCK_in ; + reg PASSULCK_out; + reg PASSACC_in ; + reg PASSACC_out; + + // event control registers + reg PRGSUSP_out_event; + reg ERSSUSP_out_event; + reg Reseted_event; + reg SCK_ipd_event; + reg next_state_event; + + reg rising_edge_PoweredUp; + reg rising_edge_Reseted; + reg rising_edge_PASSULCK_in; + reg rising_edge_RES_out; + reg rising_edge_PSTART; + reg rising_edge_WSTART; + reg rising_edge_ESTART; + reg rising_edge_RSTNeg; + reg rising_edge_RST; + reg falling_edge_RSTNeg; + reg falling_edge_RST; + reg rising_edge_RST_out; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg RST ; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl256s.mem"; + parameter otp_file_name = "s25fl256sOTP.mem";//"none"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl256s"; + parameter MaxData = 255; + parameter MemSize = 28'h1FFFFFF; + parameter SecSize256 = 20'h3FFFF; + parameter SecSize64 = 16'hFFFF; + parameter SecSize4 = 12'hFFF; + parameter SecNum64 = 541; + parameter SecNum256 = 127; + parameter PageNum64 = 20'h3FFFF; + parameter PageNum256 = 16'hFFFF; + parameter AddrRANGE = 28'h1FFFFFF; + parameter HiAddrBit = 31; + parameter OTPSize = 1023; + parameter OTPLoAddr = 12'h000; + parameter OTPHiAddr = 12'h3FF; + parameter BYTE = 8; + + // Manufacturer Identification + parameter Manuf_ID = 8'h01; + parameter DeviceID = 8'h18; + // Electronic Signature + parameter ESignature = 8'h18; + // Device ID + //Manufacturer Identification && Memory Type && Memory Capacity + parameter Jedec_ID = 8'h01; + parameter DeviceID1 = 8'h02; + parameter DeviceID2 = 8'h19; + parameter ExtendedBytes = 8'h4D; + parameter ExtendedID64 = 8'h01; + parameter ExtendedID256 = 8'h00; + parameter DieRev = 8'h00; + parameter MaskRev = 8'h00; + + integer PageSize; + integer PageNum; + integer SecSize; + integer b_act = 0; + + integer ASP_ProtSE = 0; + integer Sec_ProtSE = 0; + + integer EHP; //Enhanced High Performance Mode active + + integer BAR_ACC = 0; //Bank Register Access active + + //varaibles to resolve architecture used + reg [24*8-1:0] tmp_timing;//stores copy of TimingModel + reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode + reg [7:0] tmp_char2;//stores "0" or "1" character defining sector/page size + integer found = 1'b0; + + // If speedsimulation is needed uncomment following line + +// `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // Memory Array Configuration + reg BottomBoot = 1'b0; + reg TopBoot = 1'b0; + reg UniformSec = 1'b0; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; + + reg RES_TO_SUSP_MIN_TIME; + reg RES_TO_SUSP_TYP_TIME; + + reg WDONE ; + reg WSTART ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + + reg Reseted ; + + reg PARAM_REGION = 1'b0; + + // Lock Bit is enabled for customer programming + reg WRLOCKENABLE = 1'b1; + // Flag that mark if ASP Register is allready programmed + reg ASPOTPFLAG = 1'b0; + + //Flag for Password unlock command + reg PASS_UNLOCKED = 1'b0; + reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF; + + reg QUADRD = 1'b0; + reg INITIAL_CONFIG = 1'b0; + reg CHECK_FREQ = 1'b0; + + // Programming buffer + integer WByte[0:511]; + // CFI array + integer CFI_array[8'h00:8'h50]; + // OTP Memory Array + integer OTPMem[OTPLoAddr:OTPHiAddr]; + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // VDLR Register + reg[7:0] VDLR_reg = 8'h00; + reg[7:0] VDLR_reg_in = 8'h00; + // NVDLR Register + reg[7:0] NVDLR_reg = 8'h00; + reg[7:0] NVDLR_reg_in = 8'h00; + reg dlp_act = 1'b0; + + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRWD ; + wire P_ERR; + wire E_ERR; + wire [2:0]BP; + wire WEL; + wire WIP; + assign SRWD = Status_reg1[7]; + assign P_ERR = Status_reg1[6]; + assign E_ERR = Status_reg1[5]; + assign BP = Status_reg1[4:2]; + assign WEL = Status_reg1[1]; + assign WIP = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire ES ; + wire PS ; + assign ES = Status_reg2[1]; + assign PS = Status_reg2[0]; + + // Configuration Register 1 + reg[7:0] Config_reg1 = 8'h00; + reg[7:0] Config_reg1_in = 8'h00; + + wire LC1 ; + wire LC0 ; + wire TBPROT ; + wire LOCK ; + wire BPNV ; + wire TBPARM ; + wire QUAD ; + wire FREEZE ; + assign LC1 = Config_reg1[7]; + assign LC0 = Config_reg1[6]; + assign TBPROT = Config_reg1[5]; + assign LOCK = Config_reg1[4]; + assign BPNV = Config_reg1[3]; + assign TBPARM = Config_reg1[2]; + assign QUAD = Config_reg1[1]; + assign FREEZE = Config_reg1[0]; + + // Autoboot Register + reg[31:0] AutoBoot_reg = 32'h00000000; + reg[31:0] AutoBoot_reg_in = 32'h00000000; + + wire ABE; + assign ABE = AutoBoot_reg[0]; + + // Bank Address Register + reg [7:0] Bank_Addr_reg = 8'h00; + reg [7:0] Bank_Addr_reg_in = 8'h00; + + wire EXTADD; + wire BA24; + + assign EXTADD = Bank_Addr_reg[7]; + assign BA24 = Bank_Addr_reg[0]; + + // ASP Register + reg[15:0] ASP_reg; + reg[15:0] ASP_reg_in; + + wire RPME ; + wire PPBOTP ; + wire PWDMLB ; + wire PSTMLB ; + assign RPME = ASP_reg[5]; + assign PPBOTP = ASP_reg[3]; + assign PWDMLB = ASP_reg[2]; + assign PSTMLB = ASP_reg[1]; + + // Password register + reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF; + reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF; + + // PPB Lock Register + reg[7:0] PPBL = 8'h00; + reg[7:0] PPBL_in = 8'h00; + + wire PPB_LOCK ; + assign PPB_LOCK = PPBL[0]; + + // PPB Access Register + reg[7:0] PPBAR = 8'hFF; + reg[7:0] PPBAR_in = 8'hFF; + + reg[SecNum64:0] PPB_bits = {542{1'b1}}; + + // DYB Access Register + reg[7:0] DYBAR = 8'hFF; + reg[7:0] DYBAR_in = 8'hFF; + + reg[SecNum64:0] DYB_bits = {542{1'b1}}; + + //The Lock Protection Registers for OTP Memory space + reg[7:0] LOCK_BYTE1; + reg[7:0] LOCK_BYTE2; + reg[7:0] LOCK_BYTE3; + reg[7:0] LOCK_BYTE4; + + // Command Register + reg write; + reg cfg_write; + reg read_out; + reg dual = 1'b0; + reg rd_fast = 1'b1; + reg rd_slow = 1'b0; + reg ddr = 1'b0; + reg ddr_fast = 1'b0; + reg hold_mode = 1'b0; + reg any_read = 1'b0; + reg quad_pg = 1'b0; + + wire rd ; + wire fast_rd ; + wire ddrd ; + wire fast_ddr ; + + wire quadpg ; + assign quadpg = quad_pg; + + wire RD_EQU_1; + assign RD_EQU_1 = any_read; + + wire RD_EQU_0; + assign RD_EQU_0 = ~any_read; + + reg change_TBPARM = 0; + + reg change_BP = 0; + reg [2:0] BP_bits = 3'b0; + + reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag + + reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag + reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag + + integer Byte_number = 0; + + reg oe = 1'b0; + reg oe_z = 1'b0; + + reg [647:0] CFI_array_tmp ; + reg [7:0] CFI_tmp; + + integer start_delay; + reg start_autoboot; + integer ABSD; + + reg change_addr ; + integer Address = 0; + integer SectorSuspend = 0; + + //Sector and subsector addresses + integer SA = 0; + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [SecNum64:0] Sec_Prot = 542'b0; + + // timing check violation + reg Viol = 1'b0; + + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + reg[63:0] old_pass; + reg[63:0] new_pass; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer byte_cnt = 1; + integer read_addr = 0; + integer read_addr_tmp = 0; + integer Sec_addr = 0; + integer SecAddr = 0; + integer Page_addr = 0; + integer pgm_page = 0; + + reg[7:0] data_out; + reg[647:0] ident_out; + + time SCK_cycle = 0; + time prev_SCK; + time start_ddr; + time out_time; + time SCK_SO_DDR; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (RSTNeg_ipd, RSTNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + //VHDL VITAL CheckEnable equivalents + wire quad_rd; + assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz); + wire wr_prot; + assign wr_prot = SRWD && WEL && ~QUAD; + wire dual_rd; + assign dual_rd = dual ; + wire ddro; + assign ddro = ddr && ~dual ; + wire ddr_rd; + assign ddr_rd = PoweredUp && ddr; + wire sdr_rd; + assign sdr_rd = PoweredUp && ~ddr; + +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_normal =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + specparam tpd_RSTNeg_SO =1; + //DDR operation values + specparam tpd_SCK_SO_DDR =1; + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; + specparam tsetup_SI_SCK_normal =1; + specparam tsetup_WPNeg_CSNeg =1; + specparam tsetup_HOLDNeg_SCK =1; + specparam tsetup_RSTNeg_CSNeg =1; + // DDR operation values + specparam tsetup_SI_SCK_DDR =1; + specparam tsetup_SI_SCK_DDR_fast =1; + specparam tsetup_CSNeg_SCK_DDR =1; + + //thold values: hold times + specparam thold_CSNeg_SCK =1; + specparam thold_SI_SCK_normal =1; + specparam thold_WPNeg_CSNeg =1; + specparam thold_HOLDNeg_SCK =1; + specparam thold_CSNeg_RSTNeg =1; + // DDR operation values + specparam thold_SI_SCK_DDR =1; + specparam thold_SI_SCK_DDR_fast =1; + specparam thold_CSNeg_SCK_DDR =1; + + // tpw values: pulse width + specparam tpw_SCK_serial_posedge =1; + specparam tpw_SCK_dual_posedge =1; + specparam tpw_SCK_fast_posedge =1; + specparam tpw_SCK_quadpg_posedge =1; + specparam tpw_SCK_serial_negedge =1; + specparam tpw_SCK_dual_negedge =1; + specparam tpw_SCK_fast_negedge =1; + specparam tpw_SCK_quadpg_negedge =1; + specparam tpw_CSNeg_read_posedge =1; + specparam tpw_CSNeg_pgers_posedge =1; + specparam tpw_RSTNeg_negedge =1; + specparam tpw_RSTNeg_posedge =1; + // DDR operation values + specparam tpw_SCK_DDR_posedge =1; + specparam tpw_SCK_DDR_negedge =1; + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_serial_rd =1;// 50 MHz + specparam tperiod_SCK_fast_rd =1;//133 MHz + specparam tperiod_SCK_dual_rd =1;//104 MHz + specparam tperiod_SCK_quadpg =1;// 80 MHz + // DDR operation values + specparam tperiod_SCK_DDR_rd =1;// 66 MHz + + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e7;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e7;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 330e9;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e9;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `else + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e9;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e9;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 330e12;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e11;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~ddr) (SCK => SO) = tpd_SCK_SO_normal; + if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR; + + if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal; + if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR; + + if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR; + if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR; + + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO; + + if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; + if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO; + + if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + (RSTNeg => SO) = tpd_RSTNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& sdr_rd, + tsetup_CSNeg_SCK, Viol); + $setup ( CSNeg , posedge SCK &&& ddr_rd, + tsetup_CSNeg_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK_normal, Viol); + $setup ( WPNeg , negedge CSNeg &&& wr_prot, + tsetup_WPNeg_CSNeg, Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_rd, + tsetup_HOLDNeg_SCK, Viol); + $setup ( SI , posedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + + $setup ( RSTNeg , negedge CSNeg, + tsetup_RSTNeg_CSNeg, Viol); + + $hold ( posedge SCK &&& sdr_rd , CSNeg, + thold_CSNeg_SCK, Viol); + $hold ( posedge SCK &&& ddr_rd , CSNeg, + thold_CSNeg_SCK_DDR, Viol); + $hold ( posedge SCK &&& deg_sin , SI , + thold_SI_SCK_normal, Viol); + $hold ( posedge CSNeg &&& wr_prot , WPNeg , + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK &&& quad_rd , HOLDNeg , + thold_HOLDNeg_SCK, Viol); + $hold ( posedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + + $hold ( negedge RSTNeg , CSNeg, + thold_CSNeg_RSTNeg, Viol); + + $width ( posedge SCK &&& rd , tpw_SCK_serial_posedge); + $width ( negedge SCK &&& rd , tpw_SCK_serial_negedge); + $width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge); + $width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge); + $width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge); + $width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge); + + $width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge); + $width ( negedge RSTNeg , tpw_RSTNeg_negedge); + $width ( posedge RSTNeg , tpw_RSTNeg_posedge); + + $period ( posedge SCK &&& rd , tperiod_SCK_serial_rd); + $period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); + $period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); + $period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg); + $period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 5'd0; + parameter RESET_STATE = 5'd1; + parameter AUTOBOOT = 5'd2; + parameter WRITE_SR = 5'd3; + parameter PAGE_PG = 5'd4; + parameter OTP_PG = 5'd5; + parameter PG_SUSP = 5'd6; + parameter SECTOR_ERS = 5'd7; + parameter BULK_ERS = 5'd8; + parameter ERS_SUSP = 5'd9; + parameter ERS_SUSP_PG = 5'd10; + parameter ERS_SUSP_PG_SUSP= 5'd11; + parameter PASS_PG = 5'd12; + parameter PASS_UNLOCK = 5'd13; + parameter PPB_PG = 5'd14; + parameter PPB_ERS = 5'd15; + parameter AUTOBOOT_PG = 5'd16; + parameter ASP_PG = 5'd17; + parameter PLB_PG = 5'd18; + parameter DYB_PG = 5'd19; + parameter NVDLR_PG = 5'd20; + + reg [4:0] current_state; + reg [4:0] next_state; + +// Instruction type + parameter NONE = 7'd0; + parameter WRR = 7'd1; + parameter PP = 7'd2; + parameter READ = 7'd3; + parameter WRDI = 7'd4; + parameter RDSR = 7'd5; + parameter WREN = 7'd6; + parameter RDSR2 = 7'd7; + parameter FSTRD = 7'd8; + parameter FSTRD4 = 7'd9; + parameter DDRFR = 7'd10; + parameter DDRFR4 = 7'd11; + parameter PP4 = 7'd12; + parameter RD4 = 7'd13; + parameter ABRD = 7'd14; + parameter ABWR = 7'd15; + parameter BRRD = 7'd16; + parameter BRWR = 7'd17; + parameter P4E = 7'd19; + parameter P4E4 = 7'd20; + parameter ASPRD = 7'd21; + parameter ASPP = 7'd22; + parameter CLSR = 7'd23; + parameter QPP = 7'd24; + parameter QPP4 = 7'd25; + parameter RDCR = 7'd26; + parameter DOR = 7'd27; + parameter DOR4 = 7'd28; + parameter DLPRD = 7'd29; + parameter OTPP = 7'd30; + parameter PNVDLR = 7'd31; + parameter OTPR = 7'd32; + parameter WVDLR = 7'd33; + parameter BE = 7'd34; + parameter QOR = 7'd35; + parameter QOR4 = 7'd36; + parameter ERSP = 7'd37; + parameter ERRS = 7'd38; + parameter PGSP = 7'd39; + parameter PGRS = 7'd40; + parameter REMS = 7'd41; + parameter RDID = 7'd42; + parameter MPM = 7'd43; + parameter PLBWR = 7'd44; + parameter PLBRD = 7'd45; + parameter RES = 7'd46; + parameter DIOR = 7'd47; + parameter DIOR4 = 7'd48; + parameter DDRDIOR = 7'd49; + parameter DDRDIOR4 = 7'd50; + parameter SE = 7'd51; + parameter SE4 = 7'd52; + parameter DYBRD = 7'd53; + parameter DYBWR = 7'd54; + parameter PPBRD = 7'd55; + parameter PPBP = 7'd56; + parameter PPBERS = 7'd57; + parameter PASSRD = 7'd58; + parameter PASSP = 7'd59; + parameter PASSU = 7'd60; + parameter QIOR = 7'd61; + parameter QIOR4 = 7'd62; + parameter DDRQIOR = 7'd63; + parameter DDRQIOR4 = 7'd64; + parameter RESET = 7'd65; + parameter MBR = 7'd66; + parameter BRAC = 7'd67; + + reg [6:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SO_in, SO_z) + begin + if (SO_in==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_pin=deq_pin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_sin=deq_sin + && (ddr == 1'b0) && (Instruct !== DDRFR) + && (Instruct !== DDRFR4) && (Instruct !== DDRDIOR) + && (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR) + && (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz); + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + initial + begin : Init + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + cnt = 0; + RST = 1'b0; + RST_in = 1'b0; + RST_out = 1'b1; + PDONE = 1'b1; + PSTART = 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + PRGSUSP_in = 1'b0; + ERSSUSP_in = 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + Reseted = 1'b0; + + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl256s.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl256s_otp memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at OTPMem(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + + LOCK_BYTE1[7:0] = OTPMem[16]; + LOCK_BYTE2[7:0] = OTPMem[17]; + LOCK_BYTE3[7:0] = OTPMem[18]; + LOCK_BYTE4[7:0] = OTPMem[19]; + end + + // initialize memory and load preload files if any + initial + begin: InitTimingModel + integer i; + integer j; + //UNIFORM OR HYBRID arch model is used + //assumptions: + //1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF + //it is important that 16-th character from first one is "0" or "1" + //2. TimingModel does not have more then 24 characters + tmp_timing = TimingModel;//copy of TimingModel + + i = 23; + while ((i >= 0) && (found != 1'b1))//search for first non null character + begin //i keeps position of first non null character + j = 7; + while ((j >= 0) && (found != 1'b1)) + begin + if (tmp_timing[i*8+j] != 1'd0) + found = 1'b1; + else + j = j-1; + end + i = i - 1; + end + i = i +1; + if (found)//if non null character is found + begin + for (j=0;j<=7;j=j+1) + begin + //EHPLC/HPLC character is 15 + tmp_char1[j] = TimingModel[(i-14)*8+j]; + //256B/512B Page character is 16 + tmp_char2[j] = TimingModel[(i-15)*8+j]; + end + end + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" || + tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L") + begin + EHP = 1; + if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y") + begin + RdPswdProtEnable = 1; + end + end + else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" || + tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q") + begin + EHP = 0; + end + + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" || + tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" || + tmp_char1 == "9" || tmp_char1 == "Q") + begin + ASP_reg = 16'hFE7F; + ASP_reg_in = 16'hFE7F; + end + else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" || + tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L") + begin + ASP_reg = 16'hFE4F; + ASP_reg_in = 16'hFE4F; + end + + if (tmp_char2 == "0") + begin + PageSize = 255; + PageNum = PageNum64; + SecSize = SecSize64; + end + else if (tmp_char2 == "1") + begin + PageSize = 511; + PageNum = PageNum256; + SecSize = SecSize256; + end + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + /////////////////////////////////////////////////////////////////////// + // ID-CFI array data + /////////////////////////////////////////////////////////////////////// + // Manufacturer and Device ID + CFI_array[8'h00] = Jedec_ID; + CFI_array[8'h01] = DeviceID1; + CFI_array[8'h02] = DeviceID2; + CFI_array[8'h03] = 8'h00; + if (tmp_char2 == "0") + // Uniform 64kB sectors + CFI_array[8'h04] = ExtendedID64; + else if (tmp_char2 == "1") + // Uniform 256kB sectors + CFI_array[8'h04] = ExtendedID256; + CFI_array[8'h05] = 8'h80; + CFI_array[8'h06] = 8'h00; + CFI_array[8'h07] = 8'h00; + CFI_array[8'h08] = 8'h00; + CFI_array[8'h09] = 8'h00; + CFI_array[8'h0A] = 8'h00; + CFI_array[8'h0B] = 8'h00; + CFI_array[8'h0C] = 8'h00; + CFI_array[8'h0D] = 8'h00; + CFI_array[8'h0E] = 8'h00; + CFI_array[8'h0F] = 8'h00; + // CFI Query Identification String + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h53; + CFI_array[8'h18] = 8'h46; + CFI_array[8'h19] = 8'h51; + CFI_array[8'h1A] = 8'h00; + //CFI system interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h06; + if (tmp_char2 == "0") + begin + // 64kB sector and 256B page + CFI_array[8'h20] = 8'h08; + CFI_array[8'h21] = 8'h08; + end + else if (tmp_char2 == "1") + begin + // 256kB sector and 512B page + CFI_array[8'h20] = 8'h09; + CFI_array[8'h21] = 8'h09; + end + CFI_array[8'h22] = 8'h10; + CFI_array[8'h23] = 8'h02; + CFI_array[8'h24] = 8'h02; + CFI_array[8'h25] = 8'h03; + CFI_array[8'h26] = 8'h03; + // Device Geometry Definition(Uniform Sector Devices) + CFI_array[8'h27] = 8'h19; + CFI_array[8'h28] = 8'h02; + CFI_array[8'h29] = 8'h01; + if (tmp_char2 == "0") + // 64kB sectors + CFI_array[8'h2A] = 8'h08; + else if (tmp_char2 == "1") + CFI_array[8'h2A] = 8'h09; + + CFI_array[8'h2B] = 8'h00; + if (tmp_char2 == "1") + begin + CFI_array[8'h2C] = 8'h01; + CFI_array[8'h2D] = 8'h7F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h04; + CFI_array[8'h31] = 8'hFF; + CFI_array[8'h32] = 8'hFF; + CFI_array[8'h33] = 8'hFF; + CFI_array[8'h34] = 8'hFF; + end + else + begin + CFI_array[8'h2C] = 8'h02; + if (TBPARM) + begin + // 4KB physical sectors at top + CFI_array[8'h2D] = 8'hFD; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h01; + CFI_array[8'h31] = 8'h1F; + CFI_array[8'h32] = 8'h01; + CFI_array[8'h33] = 8'h10; + CFI_array[8'h34] = 8'h00; + end + else + begin + // 4KB physical sectors at bottom + CFI_array[8'h2D] = 8'h1F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h10; + CFI_array[8'h30] = 8'h00; + CFI_array[8'h31] = 8'hFD; + CFI_array[8'h32] = 8'h01; + CFI_array[8'h33] = 8'h00; + CFI_array[8'h34] = 8'h01; + end + end + CFI_array[8'h35] = 8'hFF; + CFI_array[8'h36] = 8'hFF; + CFI_array[8'h37] = 8'hFF; + CFI_array[8'h38] = 8'hFF; + CFI_array[8'h39] = 8'hFF; + CFI_array[8'h3A] = 8'hFF; + CFI_array[8'h3B] = 8'hFF; + CFI_array[8'h3C] = 8'hFF; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + // CFI Primary Vendor-Specific Extended Query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h21; + CFI_array[8'h46] = 8'h02; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h08; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h00; + CFI_array[8'h4D] = 8'h00; + CFI_array[8'h4E] = 8'h00; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h01; + + begin + for(i=80;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h00-i+80]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + end + + always @(next_state_event or PoweredUp or RST or RST_out) + begin: StateTransition + if (PoweredUp) + begin + if ((RSTNeg_in) && RST_out == 1'b1) + current_state = #(1000) next_state; + else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST) + begin + // no state transition while RESET# low + current_state = RESET_STATE; + RST_in = 1'b1; + #1000 RST_in = 1'b0; + end + end + end + + always @(posedge RST_in) + begin:Threset + RST_out = 1'b0; + #(35000000-200000) RST_out = 1'b1; + end + + always @(negedge CSNeg_ipd) + begin:CheckCEOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_PRGSUSP PRGSUSP_out = 1'b1; + end + + always @(posedge PPBERASE_in) + begin:PPBErs + PPBERASE_out = 1'b0; + #tdevice_PPBERASE PPBERASE_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_ERSSUSP ERSSUSP_out = 1'b1; + end + + always @(posedge PASSULCK_in) + begin:PASSULock + PASSULCK_out = 1'b0; + #tdevice_PASSULCK PASSULCK_out = 1'b1; + end + + always @(posedge PASSACC_in) + begin:PASSAcc + PASSACC_out = 1'b0; + #tdevice_PASSACC PASSACC_out = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [7:0] opcode_in; + reg [7:0] opcode_tmp; + reg [31:0] addr_bytes; + reg [31:0] hiaddr_bytes; + reg [31:0] Address_in; + reg [7:0] mode_bytes; + reg [7:0] mode_in; + integer Latency_code; + integer quad_data_in [0:1023]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle + integer i; + integer j; + integer k; + time CLK_PER; + time LAST_CLK; + + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + Instruct = NONE; + write = 1'b1; + cfg_write = 0; + opcode_cnt = 0; + addr_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + data_cnt = 0; + opcode_tmp = 0; + DOUBLE = 1'b0; + QUADRD = 1'b0; + CLK_PER = 1'b0; + LAST_CLK = 1'b0; + if (current_state == AUTOBOOT) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = OPCODE_BYTE; + end + end + end + + if (rising_edge_SCK_ipd) // Instructions, addresses or data present + begin // at SI are latched on the rising edge of SCK + + CLK_PER = $time - LAST_CLK; + LAST_CLK = $time; + if (CHECK_FREQ) + begin + if ((CLK_PER < 20000 && Latency_code == 3) || + (CLK_PER < 12500 && Latency_code == 0) || + (CLK_PER < 11100 && Latency_code == 1) || + (CLK_PER < 9600 && Latency_code == 2)) + begin + $display ("More wait states are required for"); + $display ("this clock frequency value"); + end + CHECK_FREQ = 0; + end + + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + Latency_code = Config_reg1[7:6]; + if (opcode_cnt == BYTE) + begin + for(i=7;i>=0;i=i-1) + begin + opcode[i] = opcode_in[7-i]; + end + case (opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010011 : // 13h + begin + Instruct = RD4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : // 4Bh + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000111 : // 07h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 35h + begin + Instruct = RDCR; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : // 90h + begin + Instruct = REMS; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : // 9Fh + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011 : // ABh + begin + Instruct = RES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FSTRD; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001100 : // 0Ch + begin + Instruct = FSTRD4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001101 : // 0Dh + begin + Instruct = DDRFR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001110 : // 0Eh + begin + Instruct = DDRFR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111011 : // 3Bh + begin + Instruct = DOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111100 : // 3Ch + begin + Instruct = DOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111011 : // BBh + begin + Instruct = DIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111100 : // BCh + begin + Instruct = DIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111101 : // BDh + begin + Instruct = DDRDIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111110 : // BEh + begin + Instruct = DDRDIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101011 : // 6Bh + begin + Instruct = QOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101100 : // 6Ch + begin + Instruct = QOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101011 : // EBh + begin + Instruct = QIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101100 : // ECh + begin + Instruct = QIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101101 : // EDh + begin + Instruct = DDRQIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101110 : // EEh + begin + Instruct = DDRQIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010010 : // 12h + begin + Instruct = PP4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010: // 32h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00111000: // 38h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00110100 : // 34h + begin + Instruct = QPP4; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b01000010 : // 42h + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10000101 : // 85h + begin + Instruct = PGSP; + bus_cycle_state = DATA_BYTES; + end + 8'b10001010 : // 8Ah + begin + Instruct = PGRS; + bus_cycle_state = DATA_BYTES; + end + 8'b11000111 : // C7h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b01100000 : // 60h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011100 : // DCh + begin + Instruct = SE4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERRS; + bus_cycle_state = DATA_BYTES; + end + 8'b00010100 : // 14h + begin + Instruct = ABRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010101 : // 15h + begin + Instruct = ABWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00010110 : // 16h + begin + Instruct = BRRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010111 : // 17h + begin + Instruct = BRWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00101011 : // 2Bh + begin + Instruct = ASPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00101111 : // 2Fh + begin + Instruct = ASPP; + bus_cycle_state = DATA_BYTES; + end + 8'b11100000 : // E0h + begin + Instruct = DYBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100001 : // E1h + begin + Instruct = DYBWR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100010 : // E2h + begin + Instruct = PPBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100011 : // E3h + begin + Instruct = PPBP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100100 : // E4h + begin + Instruct = PPBERS; + bus_cycle_state = DATA_BYTES; + end + 8'b10100110 : // A6h + begin + Instruct = PLBWR; + bus_cycle_state = DATA_BYTES; + end + 8'b10100111 : // A7h + begin + Instruct = PLBRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11100111 : // E7h + begin + Instruct = PASSRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11101000 : // E8h + begin + Instruct = PASSP; + bus_cycle_state = DATA_BYTES; + end + 8'b11101001 : // E9h + begin + Instruct = PASSU; + bus_cycle_state = DATA_BYTES; + end + 8'b11110000 : // F0h + begin + Instruct = RESET; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : // 30h + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00100000 : // 20h + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00100001 : // 21h + begin + Instruct = P4E4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000001 : // 41h + begin + Instruct = DLPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b01000011 : // 43h + begin + Instruct = PNVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b01001010 : // 4Ah + begin + Instruct = WVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = BRAC; + bus_cycle_state = DATA_BYTES; + end + 8'b11111111 : // FFh + begin + Instruct = MBR; + bus_cycle_state = MODE_BYTE; + end + endcase + end + end + end //end of OPCODE BYTE + + ADDRESS_BYTES : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4) || + (Instruct == DDRDIOR) || (Instruct == DDRDIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + DOUBLE = 1'b1; + else + DOUBLE = 1'b0; + if ((Instruct == QOR) || (Instruct == QOR4) || + (Instruct == QIOR) || (Instruct == QIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + QUADRD = 1'b1; + else + QUADRD = 1'b0; + if (DOUBLE == 1'b0) + begin + if (((((Instruct == FSTRD) && (~EXTADD)) || + ((Instruct == DOR) && (~EXTADD)) || + (Instruct == OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QOR) && QUAD && (~EXTADD))) + begin + //Instruction + 3 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + Address = addr_bytes ; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct==FSTRD || Instruct==DOR || + Instruct == QOR) + begin + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((((Instruct==FSTRD4) || + (Instruct==DOR4) || + ((Instruct==FSTRD) && EXTADD) || + ((Instruct==DOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct==QOR4) && QUAD) || + ((Instruct==QOR) && QUAD && EXTADD)) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + end + end + end + else if ((Instruct==DIOR) && (~EXTADD) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + //DUAL I/O High Performance Read(3 Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i]=Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==DIOR4) || + ((Instruct==DIOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin //DUAL I/O High Performance Read(4Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == QIOR) && (~EXTADD)) + begin + //QUAD I/O High Performance Read (3Bytes Address) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((Instruct==QIOR4) || ((Instruct==QIOR) + && EXTADD)) + begin + //QUAD I/O High Performance Read (4Bytes Addr) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt +1; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt =0; + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((((Instruct==RD4) || (Instruct==PP4) || + (Instruct==SE4) ||(Instruct==PPBRD) || + (Instruct==DYBRD) ||(Instruct==DYBWR) || + (Instruct==PPBP) || (Instruct==P4E4) || + ((Instruct==READ) && EXTADD) || + ((Instruct==PP) && EXTADD) || + ((Instruct==P4E) && EXTADD) || + ((Instruct==SE) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (QUAD && (Instruct==QPP4 || + ((Instruct==QPP) && EXTADD)))) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + else if (((HOLDNeg_in && ~QUAD) || QUAD) && + (~EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + else + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + end + end + + MODE_BYTE : + begin + if (((Instruct==DIOR) || (Instruct == DIOR4)) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + if (Latency_code == 0 || Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + mode_in[2*mode_cnt] = SI_in; + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt] = SO_in; + mode_in[4*mode_cnt+1] = SI_in; + end + else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4)) + && QUAD) + begin + mode_in[0] = HOLDNeg_in; + mode_in[1] = WPNeg_in; + mode_in[2] = SO_in; + mode_in[3] = SI_in; + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + if ((((Instruct==FSTRD) || (Instruct==FSTRD4) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (((Instruct==QOR)||(Instruct==QOR4)) && QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + begin + bus_cycle_state = DATA_BYTES; + end + end + + else if ((Instruct==DDRFR) || (Instruct==DDRFR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==2)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==5)) || + ((Latency_code == 1) && (dummy_cnt==6)) || + ((Latency_code == 2) && (dummy_cnt==7))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (Instruct==RES) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + else if ((Instruct == DIOR) || (Instruct == DIOR4) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 1) && (dummy_cnt==1)) || + ((Latency_code == 2) && (dummy_cnt==2))) + bus_cycle_state = DATA_BYTES; + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + bus_cycle_state = DATA_BYTES; + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==2)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (((Instruct == QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + + if (((Latency_code == 3) && (dummy_cnt==3)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + + DATA_BYTES : + begin + + if (DOUBLE == 1'b1 && (hold_mode==0)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + + if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4))) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in}; + if (data_cnt > ((PageSize+1)*2-1)) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for(i=0;i<=(PageSize*2-1);i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[(PageSize+1)*2-1] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + else if ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (data_cnt > ((PageSize+1)*8-1)) + begin + //In case of serial mode and PP, + //if more than PageSize are sent to the device + //previously latched data are discarded and last + //256/512 data bytes are guaranteed to be programmed + //correctly within the same page. + if (bit_cnt == 0) + begin + for(i=0;i<=(PageSize*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[PageSize*BYTE + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + + if (falling_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + ADDRESS_BYTES : + begin + if (DOUBLE == 1'b1) + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:25] = 7'b0000000; + addr_bytes[24] = Bank_Addr_reg[0]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + end + + MODE_BYTE : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + begin + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + begin + mode_in[4] = HOLDNeg_in; + mode_in[5] = WPNeg_in; + mode_in[6] = SO_in; + mode_in[7] = SI_in; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + DATA_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 ) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + else + begin + if ((Instruct==READ) || (Instruct==RD4) || + (Instruct==FSTRD)|| (Instruct==FSTRD4)|| + (Instruct==RDSR) || (Instruct==RDSR2) || + (Instruct==RDCR) || (Instruct==OTPR) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==DIOR)|| (Instruct==DIOR4)|| + (Instruct==ABRD) || (Instruct==BRRD) || + (Instruct==ASPRD)|| (Instruct==DYBRD) || + (Instruct==PPBRD)|| + (Instruct==PASSRD)|| (Instruct==RDID)|| + (Instruct==RES) || (Instruct==REMS) || + (Instruct==PLBRD)|| (Instruct==DLPRD) || + (current_state == AUTOBOOT && + start_delay == 0) || + (((Instruct==QOR) || (Instruct==QIOR) || + (Instruct==QOR4) || + (Instruct==QIOR4)) && QUAD)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + + DUMMY_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + endcase + end + end + + if (rising_edge_CSNeg_ipd) + begin + if ((bus_cycle_state != DATA_BYTES) && + (bus_cycle_state != DUMMY_BYTES)) + begin + if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF) + begin + Instruct = MBR; + end + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (((mode_bytes[7:4] == 4'b1010) && + (Instruct==DIOR || Instruct==DIOR4 || + Instruct==QIOR || Instruct==QIOR4)) || + ((mode_bytes[7:4] == ~mode_bytes[3:0]) && + (Instruct == DDRFR || Instruct == DDRFR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4))) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + + case (Instruct) + WREN, + WRDI, + BE, + SE, + SE4, + P4E, + P4E4, + CLSR, + BRAC, + RESET, + PPBERS, + PPBP, + PLBWR, + PGSP, + PGRS, + ERSP, + ERRS: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 0) + write = 1'b0; + end + end + + WRR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + if (BAR_ACC == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else + begin + if (P_ERR == 0 && E_ERR == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Bank_Addr_reg_in[i]= + Data_in[7-i]; + end + end + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + if (BAR_ACC == 0) + begin + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Config_reg1_in[i]= + Data_in[15-i]; + end + end + else + begin + if (P_ERR == 0 && E_ERR == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Bank_Addr_reg_in[i]= + Data_in[7-i]; + end + end + end + end + end + end + + PP, + PP4, + OTPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=7;j>=0;j=j-1) + begin + if ((Data_in[(i*8)+(7-j)]) + !== 1'bX) + begin + Byte_slv[j] = + Data_in[(i*8)+(7-j)]; + end + end + WByte[i] = Byte_slv; + end + + if (data_cnt > (PageSize+1)*BYTE) + Byte_number = PageSize; + else + Byte_number = + ((data_cnt/8) - 1); + end + end + end + end + + QPP, + QPP4: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + quad_pg = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > (PageSize+1)*2) + Byte_number = PageSize; + else + Byte_number = ((data_cnt/2)-1); + end + end + end + + ABWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 32) + begin + write = 1'b0; + for(j=0;j<=31;j=j+1) + begin + AutoBoot_reg_in[j] = Data_in[31-j]; + end + end + end + end + + BRWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + Bank_Addr_reg_in[j] = Data_in[7-j]; + end + end + end + end + + ASPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 16) + begin + write = 1'b0; + for(j=0;j<=15;j=j+1) + begin + ASP_reg_in[j] = Data_in[15-j]; + end + end + end + end + + DYBWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + DYBAR_in[j] = Data_in[7-j]; + end + end + end + end + + PNVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + NVDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + WVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + VDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + PASSP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + Password_reg_in[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + + PASSU: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + PASS_TEMP[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + endcase + end + end + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Page Program +/////////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed_pgm; + time start_pgm; + time duration_pgm; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) || + (Instruct == QPP) || (Instruct == QPP4)) + if (PageSize == 255) + begin + pob = tdevice_PP_256; + end + else + begin + pob = tdevice_PP_512; + end + else + pob = tdevice_BP; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed_pgm = 0; + duration_pgm = pob; + PDONE = 1'b0; + ->pdone_event; + start_pgm = $time; + end + end + + always @(posedge PGSUSP) + begin + if (PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed_pgm = $time - start_pgm; + duration_pgm = pob - elapsed_pgm; + PDONE = 1'b0; + end + end + + always @(posedge PGRES) + begin + start_pgm = $time; + ->pdone_event; + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #duration_pgm PDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Write Status Register +/////////////////////////////////////////////////////////////////////////////// + time wob; + always @(posedge WSTART) + begin:wdone_process + wob = tdevice_WRR; + if (WSTART && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Reset Timing +/////////////////////////////////////////////////////////////////////////////// + + time startlo; + time starthi; + time durationlo; + time durationhi; + + always @(negedge RSTNeg_in or Instruct) + begin + if (~RSTNeg_in) + begin + RST = 1'b1; + #200000 RST = 1'b0; // 200 ns + end + else if (Instruct == RESET) + begin + Reseted = 1'b0; + #10000 Reseted = 1'b1; // 10 ns + end + end + + always @(RST_in or rising_edge_Reseted) // Reset done,program terminated + begin + if ((RST_in && ~RST) || (rising_edge_Reseted)) + disable pdone_process; + disable edone_process; + disable wdone_process; + PDONE = 1'b1; + EDONE = 1'b1; + WDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Bulk Erase +/////////////////////////////////////////////////////////////////////////////// + time seo; + time beo; + event edone_event; + time elapsed_ers; + time start_ers; + time duration_ers; + + always @(rising_edge_ESTART) + begin + if (UniformSec) + begin + seo = tdevice_SE256; + end + else + begin + seo = tdevice_SE64; + end + beo = tdevice_BE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == BE) + begin + duration_ers = beo; + end + else + begin + duration_ers = seo; + end + elapsed_ers = 0; + EDONE = 1'b0; + ->edone_event; + start_ers = $time; + end + end + + always @(posedge ESUSP) + begin + if (ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed_ers = $time - start_ers; + duration_ers = seo - elapsed_ers; + EDONE = 1'b0; + end + end + + always @(posedge ERES) + begin + if (ERES && (~EDONE)) + begin + start_ers = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_ers EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg falling_edge_PPBERASE_in = 1'b0; + reg falling_edge_PASSULCK_in = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or + falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or + rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or + PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out + or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in) + begin: StateGen1 + + integer sect; + + if (rising_edge_PoweredUp) + begin + if (ABE == 1 && RPME !== 0 ) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + else + begin + if (RST_out == 1'b0) + next_state = current_state; + else if (falling_edge_write && Instruct == RESET) + begin + if (ABE == 1 && RPME !== 0) + begin + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + ABSD = AutoBoot_reg[8:1]; + start_autoboot = 0; + next_state = AUTOBOOT; + end + else + next_state = IDLE; + end + else + begin + case (current_state) + RESET_STATE : + begin + if (rising_edge_RST_out) + begin + if (ABE == 1 && RPME!== 0) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9],9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + end + + IDLE : + begin + if (falling_edge_write && RdPswdProtMode == 0) + begin + if (Instruct == WRR && WEL == 1 && BAR_ACC == 0 + && (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)) + // can not execute if HPM is entered or + // if WEL bit is zero + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + $display ("WARNING: Changing value of "); + $display ("Configuration Register OTP "); + $display ("bit from 1 to 0 is not"); + $display ("allowed!!!"); + end + else + begin + next_state = WRITE_SR; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + next_state = IDLE; + end + end + else if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = PAGE_PG; + end + end + else if (Instruct==OTPP && WEL==1 && FREEZE==0) + begin + if (((((Address>=16'h0010 && Address<=16'h0013) + ||(Address>=16'h0020 && Address<=16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address>=16'h0100 && Address<=16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32]==1) || + ((Address>=16'h0200 && Address<=16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32]==1) || + ((Address>=16'h0300 && Address<=16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) + && (Address + Byte_number <= OTPHiAddr)) + next_state = OTP_PG; + end + else if ((Instruct == SE || Instruct == SE4) + && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 510) || + (BottomBoot && sect > 31)) + begin + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 + && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + else if ((TopBoot && sect >= 510) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a + //64 KB range that includes 4 KB sectors. + next_state = SECTOR_ERS; + end + end + else if ((Instruct == P4E || Instruct == P4E4) + && WEL == 1) + begin + if (UniformSec || (TopBoot && sect < 510) || + (BottomBoot && sect > 31)) + begin + $display("The instruction is applied to"); + $display("a sector that is larger than"); + $display("4 KB."); + $display("Instruction is ignored!!!"); + end + else + begin + if (Sec_Prot[sect]== 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + end + else if (Instruct == BE && WEL == 1 && + (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0)) + next_state = BULK_ERS; + else if (Instruct == ABWR && WEL == 1) + //Autoboot Register Write Command + next_state = AUTOBOOT_PG; + else if (Instruct == BRWR) + //Bank Register Write Command + next_state = IDLE; + else if (Instruct == ASPP && WEL == 1) + begin + //ASP Register Program Command + if (~(ASPOTPFLAG)) + next_state = ASP_PG; + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + next_state = PLB_PG; + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + next_state = PASS_PG; + end + else if (Instruct == PASSU && WEL && ~WIP) + next_state = PASS_UNLOCK; + else if (Instruct == PPBP && WEL == 1) + next_state <= PPB_PG; + else if (Instruct == PPBERS && WEL && PPBOTP) + next_state <= PPB_ERS; + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == PNVDLR && WEL == 1) + next_state = NVDLR_PG; + else + next_state = IDLE; + end + if (falling_edge_write && RdPswdProtMode == 1 && ~WIP) + begin + if (Instruct == PASSU) + next_state = PASS_UNLOCK; + end + end + + AUTOBOOT : + begin + if (rising_edge_CSNeg_ipd) + next_state = IDLE; + end + + WRITE_SR : + begin + if (rising_edge_WDONE) + next_state = IDLE; + end + + PAGE_PG : + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end + + PG_SUSP : + begin + if (falling_edge_write) + begin + if (Instruct == PGRS) + next_state = PAGE_PG; + end + end + + OTP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + BULK_ERS : + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS : + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP : + begin + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && SectorSuspend != + Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = ERS_SUSP_PG; + end + end + end + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == ERRS) + next_state = SECTOR_ERS; + end + end + + ERS_SUSP_PG : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = ERS_SUSP_PG_SUSP; + end + + ERS_SUSP_PG_SUSP : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + if (falling_edge_write) + begin + if (Instruct == PGRS) + begin + next_state = ERS_SUSP_PG; + end + end + end + + PASS_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PASS_UNLOCK : + begin + if (falling_edge_PASSULCK_in) + next_state = IDLE; + end + + PPB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PPB_ERS : + begin + if (falling_edge_PPBERASE_in) + next_state = IDLE; + end + + AUTOBOOT_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PLB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + DYB_PG : + begin + if (rising_edge_PDONE) + if (ES) + next_state = ERS_SUSP; + else + next_state = IDLE; + end + + ASP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + NVDLR_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + endcase + end + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer WData [0:511]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(Instruct_event) + begin + read_cnt = 0; + byte_cnt = 1; + rd_fast = 1'b1; + dual = 1'b0; + rd_slow = 1'b0; + any_read = 1'b0; + end + + always @(rising_edge_read_out) + begin + if (rising_edge_read_out == 1'b1) + begin + if (PoweredUp == 1'b1) + begin + oe_z = 1'b1; + #1000 oe_z = 1'b0; + oe = 1'b1; + #1000 oe = 1'b0; + end + end + end + + always @(change_addr_event) + begin + if (change_addr_event) + begin + read_addr = Address; + end + end + + always @(posedge PASSACC_out) + begin + Status_reg1[0] = 1'b0; //WIP + PASSACC_in = 1'b0; + end + + always @(Instruct or posedge start_autoboot or oe or current_state_event or + falling_edge_write or posedge PDONE or posedge WDONE or oe_z or + posedge EDONE or ERSSUSP_out or rising_edge_Reseted or + rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or + Address) + begin: Functionality + integer i,j; + integer sect; + + if (rising_edge_PoweredUp) + begin + //the default condition after power-up + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + //The Configuration Register FREEZE bit is cleared. + Config_reg1[0] = 0; + //The WEL bit is cleared. + Status_reg1[1] = 0; + //When BPNV is set to '1'. the BP2-0 bits in Status Register are + //volatile and will be reset binary 111 after power-on reset + if (BPNV == 1 && LOCK == 0 && FREEZE == 0 ) + begin + Status_reg1[4] = 1'b0;// BP2 + Status_reg1[3] = 1'b0;// BP1 + Status_reg1[2] = 1'b0;// BP0 + BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + + //As shipped from the factory, all devices default ASP to the + //Persistent Protection mode, with all sectors unprotected, + //when power is applied. The device programmer or host system must + //then choose which sector protection method to use. + //For Persistent Protection mode, PPBLOCK defaults to "1" + PPBL[0] = 1'b1; + + //All the DYB power-up in the unprotected state + DYB_bits = {542{1'b1}}; + + end + + if (Instruct == RESET) + begin + //EXTADD is cleared to “0” + Bank_Addr_reg[7] = 1'b0; + //P_ERR bit is cleared + Status_reg1[6] = 1'b0; + //E_ERR bit is cleared + Status_reg1[5] = 1'b0; + //The WEL bit is cleared. + Status_reg1[1] = 1'b0; + //The WIP bit is cleared. + Status_reg1[0] = 1'b0; + //The ES bit is cleared. + Status_reg2[1] = 1'b0; + //The PS bit is cleared. + Status_reg2[0] = 1'b0; + //When BPNV is set to '1'. the BP2-0 bits in Status + //Register are volatile and will be reseted after + //reset command + if (BPNV == 1 && LOCK== 0 && FREEZE == 0) + begin + Status_reg1[4] = 1'b1; + Status_reg1[3] = 1'b1; + Status_reg1[2] = 1'b1; + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + case (current_state) + IDLE : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + ASP_ProtSE = 0; + Sec_ProtSE = 0; + + if (BottomBoot) + begin + for (j=31;j>=0;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + else if (TopBoot) + begin + for (j=541;j>=510;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + + if (falling_edge_write && RdPswdProtMode == 1) + begin + if(Instruct == PASSU) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + end + + if (falling_edge_write && RdPswdProtMode == 0) + begin + read_cnt = 0; + byte_cnt = 1; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 0; + else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 && + BAR_ACC == 0) + begin + if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD) + begin + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + // P_ERR bit is set to 1 + Status_reg1[6] = 1'b1; + end + else + begin + // can not execute if Hardware Protection Mode + // is entered or if WEL bit is zero + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + end + else + Status_reg1[1] = 0; + end + else if ((Instruct == PP || Instruct == PP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if (Instruct == OTPP && WEL == 1) + begin + // As long as the FREEZE bit remains cleared to a logic + // '0' the OTP address space is programmable. + if (FREEZE == 0) + begin + if (((((Address>= 16'h0010 && Address<= 16'h0013) || + (Address >= 16'h0020 && Address <= 16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address >= 16'h0100 && Address <= 16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32] == 1) || + ((Address >= 16'h0200 && Address <= 16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32] == 1) || + ((Address >= 16'h0300 && Address <= 16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) && + (Address + Byte_number <= OTPHiAddr)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else if ((Address < 8'h10 || (Address > 8'h13 && + Address < 8'h20) || Address > 12'h3FF )) + begin + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + if (Address < 8'h20) + begin + $display ("Given address is "); + $display ("in reserved address range"); + end + else if (Address > 12'h3FF) + begin + $display ("Given address is "); + $display ("out of OTP address range"); + end + end + else + begin + //P_ERR bit will be set when the user attempts to + // to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == SE || Instruct == SE4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 510) || + (BottomBoot && sect > 31)) + begin + SectorSuspend = sect; + PARAM_REGION = 0; + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((TopBoot && sect >= 510) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a 64 KB range + //that includes 4 KB sectors + begin + if (TopBoot) + begin + SectorSuspend = 510 + (541 - sect)/16; + end + else + begin + SectorSuspend = sect/16; + end + PARAM_REGION = 1; + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if ((Instruct == P4E || Instruct == P4E4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 510) || + (BottomBoot && sect > 31)) + begin + Status_reg1[1] = 1'b0;//WEL + end + else + begin + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + //A P4E instruction applied to a sector + //that has been Write Protected through the + //Block Protect Bits or ASP will not be + //executed and will set the E_ERR status + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if (Instruct == BE && WEL == 1) + begin + if (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + end + else + begin + //The Bulk Erase command will not set E_ERR if a + //protected sector is found during the command + //execution. + Status_reg1[1] = 1'b0;//WEL + end + end + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + $display ("Password programming is not allowed"); + $display (" in Password Protection Mode."); + end + end + else if (Instruct == PASSU && WEL) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + end + else if (Instruct == ASPP && WEL == 1) + begin + if (~(ASPOTPFLAG)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + $display ("Once the Protection Mode is selected,"); + $display ("no further changes to the ASP "); + $display ("register is allowed."); + end + end + else if (Instruct == ABWR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBP && WEL == 1) + begin + ReturnSectorID(sect,Address); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBERS && WEL == 1) + begin + if (PPBOTP) + begin + PPBERASE_in = 1'b1; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[5] = 1'b1; + end + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PNVDLR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == WVDLR && WEL == 1) + begin + VDLR_reg = VDLR_reg_in; + Status_reg1[1] = 1'b0; + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4 || + Instruct == RES || + (Instruct == DLPRD && RdPswdProtMode == 0)) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4 || + ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + else if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES + && VDLR_reg != 8'b00000000) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + && QUAD) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd = data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr + && RdPswdProtMode == 0) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + data_out[7:0] = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if ((read_addr > OTPHiAddr)||(RdPswdProtMode==1)) + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum or Read Password Protection Mode + //is selected instead, the data beyond the + //maximum OTP address will be undefined. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == REMS) + begin + //Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + data_out[7:0] = DeviceID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + else if (Instruct == RDID) + begin + ident_out = CFI_array_tmp; + if(read_cnt < 648) + begin + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + //Continued shifting of output beyond the end of + //the defined ID-CFI address space will + //provide undefined data. + SOut_zd = 1'bX; + end + end + else if (Instruct == RES) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + data_out = ESignature; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DLPRD && RdPswdProtMode == 0) + begin + //Read DLP + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = VDLR_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ABRD && RdPswdProtMode == 0) + begin + //Read AutoBoot register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = AutoBoot_reg[31-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 32) + read_cnt = 0; + end + else if (Instruct == BRRD && RdPswdProtMode == 0) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ASPRD && RdPswdProtMode == 0) + begin + //Read ASP Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = ASP_reg[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == PASSRD && RdPswdProtMode == 0) + begin + //Read Password Register + if (~(PWDMLB == 0 && PSTMLB == 1)) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = + Password_reg[(8*byte_cnt-1)-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + byte_cnt = byte_cnt + 1; + if (byte_cnt == 9) + byte_cnt = 1; + end + end + end + else if (Instruct == PLBRD) + begin + //Read PPB Lock Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = PPBL[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + DYBAR[7:0] = 8'bXXXXXXXX; + + if (RdPswdProtMode == 0) + begin + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end + + AUTOBOOT: + begin + if (start_autoboot == 1) + begin + if (oe) + begin + any_read = 1'b1; + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + end + else if (oe_z) + begin + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + end + end + + WRITE_SR: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (WDONE == 1) + begin + Status_reg1[0] = 1'b0; //WIP + Status_reg1[1] = 1'b0; //WEL + //SRWD bit + Status_reg1[7] = Status_reg1_in[7]; //MSB first + + if (LOCK == 0) + begin + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT and TBPARM bits in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg1[4] = Status_reg1_in[4];//BP2 + Status_reg1[3] = Status_reg1_in[3];//BP1 + Status_reg1[2] = Status_reg1_in[2];//BP0 + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + if (TBPROT == 1'b0 && INITIAL_CONFIG == 1'b0) + begin + Config_reg1[5] = Config_reg1_in[5];//TBPROT + end + if (TBPARM == 1'b0 && INITIAL_CONFIG == 1'b0 && + tmp_char2 == "0") + begin + Config_reg1[2] = Config_reg1_in[2];//TBPARM + change_TBPARM = 1'b1; + #1000 change_TBPARM = 1'b0; + end + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + Config_reg1[7] = Config_reg1_in[7];//LC1 + Config_reg1[6] = Config_reg1_in[6];//LC0 + Config_reg1[1] = Config_reg1_in[1];//QUAD + + if (FREEZE == 1'b0) + begin + Config_reg1[0] = Config_reg1_in[0];//FREEZE + end + + if (WRLOCKENABLE== 1'b1 && LOCK == 1'b0) + begin + Config_reg1[4] = Config_reg1_in[4];//LOCK + WRLOCKENABLE = 1'b0; + end + if (BPNV == 1'b0) + begin + Config_reg1[3] = Config_reg1_in[3];//BPNV + end + end + end + + PAGE_PG : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == PAGE_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt = 0; + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + quad_pg = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + PDONE = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd =data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + OTP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == OTP_PG) + begin + if (~PDONE) + begin + if (Address + wr_cnt <= OTPHiAddr) + begin + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = OTPMem[Addr + i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + OTPMem[Addr + i] = -1; + end + end + else + begin + $display ("Programming will reach over "); + $display ("address limit of OTP array"); + end + end + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + OTPMem[Addr + i] = WData[i]; + end + LOCK_BYTE1 = OTPMem[16]; + LOCK_BYTE2 = OTPMem[17]; + LOCK_BYTE3 = OTPMem[18]; + LOCK_BYTE4 = OTPMem[19]; + end + end + + SECTOR_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == SECTOR_ERS) + begin + if (~EDONE) + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + else if (Instruct == ERSP && ~ERSSUSP_in) + begin + ESUSP = 1'b1; + ESUSP <= #5 1'b0; + ERSSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + end + + BULK_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == BULK_ERS) + begin + if (~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = -1; + end + end + + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = MaxData; + end + end + end + end + + ERS_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (ERSSUSP_out == 1) + begin + ERSSUSP_in = 0; + //The Erase Suspend (ES) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //erase operation has been suspended. + Status_reg2[1] = 1'b1; + //The WIP bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == PP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + + if (Sec_Prot[sect] == 0 + && PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + if(Bank_Addr_reg_in[1] == 1) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("BA25 is not allowed!!!"); + end + end + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == ERRS) + begin + Status_reg2[1] = 1'b0; + Status_reg1[0] = 1'b1; + if (BottomBoot) + begin + if (PARAM_REGION) + begin + Addr = SectorSuspend*(SecSize+1); + end + else + begin + Addr = (SectorSuspend-30)*(SecSize+1); + end + end + else + begin + Addr = SectorSuspend*(SecSize+1); + end + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + ERES = 1'b1; + ERES <= #5 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == ERS_SUSP_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt =0; + end + + if(PDONE == 1) + begin + Status_reg1[0] = 1'b0;//WIP + Status_reg1[1] = 1'b0;//WEL + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi ) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PASS_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + new_pass = Password_reg_in; + old_pass = Password_reg; + for (i=0;i<=63;i=i+1) + begin + if (old_pass[j] == 0) + new_pass[j] = 0; + end + + if (PDONE == 1) + begin + Password_reg = new_pass; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PASS_UNLOCK: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PASS_TEMP == Password_reg) + begin + PASS_UNLOCKED = 1'b1; + end + else + begin + PASS_UNLOCKED = 1'b0; + end + if (PASSULCK_out == 1'b1) + begin + if ((PASS_UNLOCKED == 1'b1) && (~PWDMLB)) + begin + PPBL[0] = 1'b1; + Status_reg1[0] = 1'b0; //WIP + end + else + begin + Status_reg1[6] = 1'b1; + $display ("Incorrect Password"); + PASSACC_in = 1'b1; + end + Status_reg1[1] = 1'b0; + PASSULCK_in = 1'b0; + end + end + + PPB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (PPB_LOCK !== 0) + begin + PPB_bits[sect]= 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[5] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + end + + PPB_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PPBERASE_out == 1'b1) + begin + if ((PPB_LOCK !== 0) && PPBOTP) + begin + PPB_bits = {542{1'b1}}; + end + else + begin + Status_reg1[5] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + PPBERASE_in = 1'b0; + end + end + + AUTOBOOT_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + AutoBoot_reg = AutoBoot_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PLB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + PPBL[0] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + DYB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + DYBAR = DYBAR_in; + if (DYBAR == 8'hFF) + begin + DYB_bits[sect]= 1'b1; + end + else if (DYBAR == 8'h00) + begin + DYB_bits[sect]= 1'b0; + end + else + begin + Status_reg1[6] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + ASP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + + if (RPME == 1'b0 && ASP_reg_in[5] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("RPME bit is allready programmed"); + end + else + begin + ASP_reg[5] = ASP_reg_in[5];//RPME + end + + if (PPBOTP == 1'b0 && ASP_reg_in[3] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("PPBOTP bit is allready programmed"); + end + else + begin + ASP_reg[3] = ASP_reg_in[3];//PPBOTP + end + + if (PWDMLB == 1'b1 && PSTMLB == 1'b1) + begin + if (ASP_reg_in[2] == 1'b0 && ASP_reg_in[1] == 1'b0) + begin + $display("ASPR[2:1] = 00 Illegal condition"); + Status_reg1[6] = 1'b1; //P_ERR + end + else + begin + if (ASP_reg_in[2]!==1'b1 || ASP_reg_in[1]!==1'b1) + begin + ASPOTPFLAG = 1'b1; + end + ASP_reg[2] = ASP_reg_in[2];//PWDMLB + ASP_reg[1] = ASP_reg_in[1];//PSTMLB + end + end + + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + NVDLR_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (NVDLR_reg == 0) + begin + NVDLR_reg = NVDLR_reg_in; + VDLR_reg = NVDLR_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; //P_ERR + $display("NVDLR bits allready programmed"); + end + end + end + + RESET_STATE: + begin + //the default condition hardware reset + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + if (BPNV && ~LOCK && ~FREEZE) + begin + Status_reg1[2] = 1'b1;// BP0 + Status_reg1[3] = 1'b1;// BP1 + Status_reg1[4] = 1'b1;// BP2 + BP_bits = 3'b111; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + //Resets the volatile bits in the Status register 1 + Status_reg1[6] = 1'b0; + Status_reg1[5] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[0] = 1'b0; + //Resets the volatile bits in the Status register 2 + Status_reg2[1] = 1'b0; + Status_reg2[0] = 1'b0; + //Resets the volatile bits in the Configuration register 1 + Config_reg1[0] = 1'b0; + //On reset cycles the data pattern reverts back + //to what is in the NVDLR + VDLR_reg = NVDLR_reg; + dlp_act = 1'b0; + //Loads the Program Buffer with all ones + for(i=0;i<=511;i=i+1) + begin + WData[i] = MaxData; + end + if (~PWDMLB) + PPBL[0] = 1'b0; + else + PPBL[0] = 1'b1; + end + + endcase + + //Output Disable Control + if (CSNeg_ipd ) + begin + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign ddrd = ddr; + assign fast_ddr = ddr_fast; + + always @(change_TBPARM, posedge PoweredUp) + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + BottomBoot = 1; + b_act = 1; + end + else + begin + TopBoot = 1; + BottomBoot = 0; + b_act = 0; + end + end + else if (tmp_char2 == "1") + begin + UniformSec = 1; + end + end + + always @(posedge change_BP) + begin + case (Status_reg1[4:2]) + + 3'b000: + begin + Sec_Prot[541:0] = {542{1'b0}}; + end + 3'b001: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256:(SecNum256+1)*63/64] = 2'b11; + Sec_Prot[(SecNum256+1)*63/64-1 : 0] = 126'h0; + end + else + begin + Sec_Prot[(SecNum256+1)/64-1 : 0] = 2'b11; + Sec_Prot[SecNum256 : (SecNum256+1)/64] = 126'h0; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64] = {38{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64-1 : 0] = 504'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/64-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64] = 534'h0; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64+30] = {8{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64+29 : 0] = 534'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/64+29 : 0] = {38{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64+30] = 504'h0; + end + end + end + + 3'b010: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*31/32] = {4{1'b1}}; + Sec_Prot[(SecNum256+1)*31/32-1 : 0] = 124'h0; + end + else + begin + Sec_Prot[(SecNum256+1)/32-1 : 0] = {4{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/32] = 124'h0; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*31/32] = {46{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32-1 : 0] = 496'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/32-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32] = 526'h0; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*31/32+30] = {16{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32+29 : 0] = 526'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/32+29 : 0] = {46{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32+30] = 496'h0; + end + end + end + + 3'b011: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*15/16] = 8'hFF; + Sec_Prot[(SecNum256+1)*15/16-1 : 0] = 120'h0; + end + else + begin + Sec_Prot[(SecNum256+1)/16-1 : 0] = 8'hFF; + Sec_Prot[SecNum256 : (SecNum256+1)/16] = 120'h0; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16] = {62{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16-1 : 0] = 480'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/16-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16] = 510'h0; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16+30]={32{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16+29 : 0] = 510'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/16+29 : 0] ={62{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16+30] = 480'h0; + end + end + end + + 3'b100: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*7/8] = {16{1'b1}}; + Sec_Prot[(SecNum256+1)*7/8-1 : 0] = 112'h0; + end + else + begin + Sec_Prot[(SecNum256+1)/8-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/8] = 112'h0; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8] = {94{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8-1 : 0] = 448'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/8-1 : 0] = {64{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8] = 478'h0; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8+30] ={64{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8+29 : 0] = 478'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/8+29 : 0] = {94{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8+30] = 448'h0; + end + end + end + + 3'b101: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*3/4] = {32{1'b1}}; + Sec_Prot[(SecNum256+1)*3/4-1 : 0] = 96'h0; + end + else + begin + Sec_Prot[(SecNum256+1)/4-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/4] = 96'h0; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4] = {158{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4-1 : 0] = 384'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/4-1 : 0] = {128{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4] = 414'h0; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4+30] = {128{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4+29 : 0] = 414'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/4+29 : 0] = {158{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4+30] = 384'h0; + end + end + end + + 3'b110: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {64{1'b1}}; + Sec_Prot[(SecNum256+1)/2-1 : 0] = 64'h0; + end + else + begin + Sec_Prot[(SecNum256+1)/2-1 : 0] = {64{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/2] = 64'h0; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {286{1'b1}}; + Sec_Prot[(SecNum64-29)/2-1 : 0] = 256'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/2-1 : 0] = {256{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2] = 286'h0; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {256{1'b1}}; + Sec_Prot[(SecNum64-29)/2+29 : 0] = 286'h0; + end + else + begin + Sec_Prot[(SecNum64-29)/2+29 : 0] = {286{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = 256'h0; + end + end + end + + 3'b111: + begin + Sec_Prot[SecNum64:0] = {542{1'b1}}; + end + endcase + end + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // autoboot control logic + //////////////////////////////////////////////////////////////////////// + always @(rising_edge_SCK_ipd or current_state_event) + begin + if(current_state == AUTOBOOT) + begin + if (rising_edge_SCK_ipd) + begin + if (start_delay > 0) + start_delay = start_delay - 1; + end + + if (start_delay == 0) + begin + start_autoboot = 1; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure FDDR_DPL + task Return_DLP; + input integer Instruct; + input integer EHP; + input integer Latency_code; + input integer dummy_cnt; + inout dlp_act; + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + if (EHP) + begin + if (Latency_code == 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b1; + else if (Latency_code == 0 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 1 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 3) + dlp_act = 1'b1; + end + end + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + if (EHP) + begin + if (Latency_code == 1 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if( Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b0; + else if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + end + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && QUAD) + begin + if (EHP) + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + end + end + endtask + + function integer ReturnSectorIDRdPswdMd; + input reg TBPROT; + begin + if(TBPROT == 0) + begin + ReturnSectorIDRdPswdMd = 0; + end + else + begin + if (UniformSec) + begin + ReturnSectorIDRdPswdMd = SecNum256; + end + else + begin + ReturnSectorIDRdPswdMd = 511; + end + end + end + endfunction + + // Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + if (Addr/(SecSize64+1) <= 1 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = Addr/(SecSize4+1); + AddrLOW = sector*(SecSize4+1); + AddrHIGH = sector*(SecSize4+1) + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + else + begin + if (Addr/(SecSize64+1) >= 510 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = 510 + (Addr-(SecSize64+1)*510)/(SecSize4+1); + AddrLOW = 510*(SecSize64+1)+(sector-510)*(SecSize4+1); + AddrHIGH = 510*(SecSize64+1)+ + (sector-510)*(SecSize4+1) + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + end + else if (tmp_char2 == "1") + begin + sector = Addr/(SecSize256+1); + AddrLOW = sector*(SecSize256+1); + AddrHIGH = sector*(SecSize256+1) + SecSize256; + end + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / (PageSize + 1); + AddrLOW = page * (PageSize + 1); + AddrHIGH = page * (PageSize + 1) + PageSize; + end + endtask + + // Procedure ReturnSectorID + task ReturnSectorID; + inout sect; + input Address; + integer sect; + integer Address; + integer conv; + begin + if (tmp_char2 == "0") + begin + conv = Address / (SecSize64+1); + if (BottomBoot) + begin + if (conv <= 1) //4KB Sectors + begin + sect = Address/(SecSize4+1); + end + else + begin + sect = conv + 30; + end + end + else if (TopBoot) + begin + if (conv >= 510) //4KB Sectors + begin + sect = 510 + (Address-(SecSize64+1)*510)/(SecSize4+1); + end + else + begin + sect = conv; + end + end + end + else + begin + sect = Address/(SecSize256+1); + end + end + endtask + + always @(PPBL[0], ASP_reg) + begin + if (PPBL[0] == 0 && PWDMLB == 0 && RPME == 0 && RdPswdProtEnable) + begin + RdPswdProtMode = 1; + AutoBoot_reg[0] = 0;//AUTOBOOT is disabled when Read Password + end //Protection is enabled + else + begin + RdPswdProtMode = 0; + end + end + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1; + #1000 falling_edge_write = 0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge RSTNeg_in) + begin + falling_edge_RSTNeg = 1'b1; + #50000 falling_edge_RSTNeg = 1'b0; + end + + always @(posedge RSTNeg_in) + begin + rising_edge_RSTNeg = 1'b1; + #10000 rising_edge_RSTNeg = 1'b0; + end + + always @(negedge RST) + begin + falling_edge_RST = 1'b1; + #10000 falling_edge_RST = 1'b0; + end + + always @(posedge RST) + begin + rising_edge_RST = 1'b1; + #1000 rising_edge_RST = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge Reseted) + begin + rising_edge_Reseted = 1'b1; + #1000 rising_edge_Reseted = 1'b0; + end + + always @(negedge PASSULCK_in) + begin + falling_edge_PASSULCK_in = 1'b1; + #1000 falling_edge_PASSULCK_in = 1'b0; + end + + always @(negedge PPBERASE_in) + begin + falling_edge_PPBERASE_in = 1'b1; + #1000 falling_edge_PPBERASE_in = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge RST_out) + begin + rising_edge_RST_out = 1'b1; + #1000 rising_edge_RST_out = 1'b0; + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.vhd b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.vhd new file mode 100644 index 0000000..e53efb8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s.vhd @@ -0,0 +1,7222 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl256s.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2012 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 V.Mancev 09 Nov 26 Inital Release +-- V1.1 V.Mancev 10 Mar 04 addr_cnt for second read in +-- high performance read continuous +-- mode can change its value only +-- when CSNeg = '0' +-- V1.2 V.Mancev 10 July 28 During the QUAD mode HOLD# input +-- is not monitored for its normal +-- function +-- V1.3 V.Mancev 10 Oct 15 Latest datasheet aligned +-- V1.4 V.Mancev 10 Oct 21 Hybrid configuration added +-- V1.5 V.Mancev 10 Nov 12 QUAD Program operation during Erase +-- Suspend is added +-- Warning for Resume to Suspend time +-- is added +-- During Erase Suspend, after Program +-- operation is completed, WEL bit is +-- cleared +-- Implemetation of Software Reset is +-- Changed +-- V1.6 V. Mancev 11 July 04 Latest datasheet aligned +-- V1.7 V. Mancev 11 Nov 18 Time tHO is changed to 1 ns +-- (customer's request) +-- BRWR instruction is corrected +-- V1.8 S.Petrovic 12 Aug 28 QPP Instruction is allowed on +-- previously programmed page +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: FLASH MEMORY +-- Part: S25FL256S +-- +-- Description: 256 Megabit Serial Flash Memory +-- +------------------------------------------------------------------------------- +-- Comments : +-- For correct simulation, simulator resolution should be set to 1 ps +-- A device ordering (trim) option determines whether a feature is enabled +-- or not, or provide relevant parameters: +-- -15th character in TimingModel determines if enhanced high +-- performance option is available +-- (0,2,3,R,A,B,C,D) EHPLC +-- (Y,Z,S,T,K,L) Security EHPLC +-- (4,6,7,8,9,Q) HPLC +-- -15th character in TimingModel determines if RESET# input +-- is available +-- (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +-- (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +-- state,inside the package. +-- -16th character in TimingModel determines Sector and Page Size: +-- (0) Sector Size = 64 kB; Page Size = 256 bytes +-- Hybrid Top/Bottom sector size architecture +-- (1) Sector Size = 256 kB; Page Size = 512 bytes +-- Uniform sector size architecture +-- +-------------------------------------------------------------------------------- +-- Known Bugs: +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl256s IS + GENERIC ( + --------------------------------------------------------------------------- + -- TIMING GENERICS: + --------------------------------------------------------------------------- + -- tipd delays: interconnect path delays (delay between components) + -- There should be one for each IN or INOUT pin in the port list + -- They are given default values of zero delay. + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_SO : VitalDelayType01 := VitalZeroDelay01; + + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RSTNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays: propagation delays (pin-to-pin delay within a component) + tpd_SCK_SO_normal : VitalDelayType01Z := UnitDelay01Z; -- tV, tHO + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tDIS + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;-- + tpd_RSTNeg_SO : VitalDelayType01Z := UnitDelay01Z;-- + -- DDR operation values + tpd_SCK_SO_DDR : VitalDelayType01Z := UnitDelay01Z;--tV(66MHz) + + -- tsetup values: setup times + -- setup time is minimum time before the referent signal edge the + -- input should be stable + tsetup_CSNeg_SCK_normal_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSS / + tsetup_CSNeg_SCK_DDR_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSS / + tsetup_SI_SCK_normal_noedge_posedge: VitalDelayType + := UnitDelay; -- tSU:DAT / + tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPS \ + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; + tsetup_RSTNeg_CSNeg : VitalDelayType := UnitDelay; -- tRP + -- DDR operation values + tsetup_SI_SCK_DDR_noedge_posedge: VitalDelayType + := UnitDelay; -- tSU / + tsetup_SI_SCK_DDR_noedge_negedge: VitalDelayType + := UnitDelay; -- tSU \ + + -- thold values: hold times + -- hold time is minimum time the input should be present stable + -- after the referent signal edge + thold_CSNeg_SCK_normal_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSH / + thold_CSNeg_SCK_DDR_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSH / + thold_SI_SCK_normal_noedge_posedge: VitalDelayType + := UnitDelay; -- tHD:DAT / + thold_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPH / + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- + thold_CSNeg_RSTNeg : VitalDelayType := UnitDelay; -- tRPH + -- DDR operation values + thold_SI_SCK_DDR_noedge_posedge: VitalDelayType + := UnitDelay; -- tHD / + thold_SI_SCK_DDR_noedge_negedge: VitalDelayType + := UnitDelay; -- tHD \ + + --tpw values: pulse width + tpw_SCK_serial_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_dual_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_fast_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_quadpg_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_serial_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_dual_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_fast_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_quadpg_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_CSNeg_pgers_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_RSTNeg_negedge : VitalDelayType := UnitDelay; -- tRP + tpw_RSTNeg_posedge : VitalDelayType := UnitDelay; -- tRS + -- DDR operation values + tpw_SCK_DDR_posedge : VitalDelayType := UnitDelay; -- tWH(66MHz) + tpw_SCK_DDR_negedge : VitalDelayType := UnitDelay; -- tWL(66Hz) + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_serial_rd : VitalDelayType := UnitDelay; --fSCK=50MHz + tperiod_SCK_fast_rd : VitalDelayType := UnitDelay; --fSCK=133MHz + tperiod_SCK_dual_rd : VitalDelayType := UnitDelay; --fSCK=104MHz + tperiod_SCK_quadpg : VitalDelayType := UnitDelay; --fSCK=80MHz + -- DDR operation values + tperiod_SCK_DDR_rd : VitalDelayType := UnitDelay; --fSCK=66MHz + + -- tdevice values: values for internal delays + --timing values that are internal to the model and not associated + --with any port. + -- Page Program Operation (Page Size 256) + tdevice_PP256 : VitalDelayType := 550 us; --tPP + -- Page Program Operation (Page Size 512) + tdevice_PP512 : VitalDelayType := 750 us; --tPP + -- Typical Byte Programming Time + tdevice_BP : VitalDelayType := 400 us; --tBP + -- Sector Erase Operation(256KB Sectors) + tdevice_SE256 : VitalDelayType := 1875 ms; --tSE + -- Sector Erase Operation(64KB Sectors) + tdevice_SE64 : VitalDelayType := 650 ms; --tSE + -- Bulk Erase Operation + tdevice_BE : VitalDelayType := 330 sec; --tBE + -- WRR Cycle Time + tdevice_WRR : VitalDelayType := 200 ms; --tW + -- Erase Suspend/Erase Resume Time + tdevice_ERSSUSP : VitalDelayType := 40 us; --tESL + -- Program Suspend/Program Resume Time + tdevice_PRGSUSP : VitalDelayType := 40 us; -- + -- VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 300 us; --tPU + -- PPB Erase Time + tdevice_PPBERASE :VitalDelayType := 15 ms; -- + -- Password Unlock Time + tdevice_PASSULCK :VitalDelayType := 1 us; -- + -- Password Unlock Time + tdevice_PASSACC :VitalDelayType := 100 us; + + --------------------------------------------------------------------------- + -- CONTROL GENERICS: + --------------------------------------------------------------------------- + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING := "s25fl256s.mem"; + otp_file_name : STRING := "s25fl256sOTP.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING + ); + PORT ( + -- Data Inputs/Outputs + SI : INOUT std_ulogic := 'U'; -- serial data input/IO0 + SO : INOUT std_ulogic := 'U'; -- serial data output/IO1 + -- Controls + SCK : IN std_ulogic := 'U'; -- serial clock input + CSNeg : IN std_ulogic := 'U'; -- chip select input + RSTNeg : IN std_ulogic := 'U'; -- hardware reset pin + WPNeg : INOUT std_ulogic := 'U'; -- write protect input/IO2 + HOLDNeg : INOUT std_ulogic := 'U' -- hold input/IO3 + ); + + ATTRIBUTE VITAL_LEVEL0 of s25fl256s : ENTITY IS TRUE; +END s25fl256s; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of s25fl256s IS + ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; + + --------------------------------------------------------------------------- + -- CONSTANT AND SIGNAL DECLARATION + --------------------------------------------------------------------------- + --Declaration of constants - memory characteristics + -- The constant declared here are used to enable the creation of models + -- of memories within a family with a minimum amount of editing + + CONSTANT PartID : STRING := "s25fl256s"; + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT MemSize : NATURAL := 16#1FFFFFF#; --256Mbyte + CONSTANT SecSize256 : NATURAL := 16#3FFFF#; --256KB + CONSTANT SecSize64 : NATURAL := 16#FFFF#; --64KB + CONSTANT SecSize4 : NATURAL := 16#FFF#; --4KB + CONSTANT SecNum64 : NATURAL := 541; + CONSTANT SecNum256 : NATURAL := 127; + CONSTANT PageNum64 : NATURAL := 16#3FFFF#; + CONSTANT PageNum256 : NATURAL := 16#FFFF#; + CONSTANT AddrRANGE : NATURAL := 16#1FFFFFF#; + CONSTANT HiAddrBit : NATURAL := 31; + CONSTANT OTPSize : NATURAL := 1023; + CONSTANT OTPLoAddr : NATURAL := 16#000#; + CONSTANT OTPHiAddr : NATURAL := 16#3FF#; + CONSTANT BYTE : NATURAL := 8; + + --Manufacturer Identification + CONSTANT Manuf_ID : NATURAL := 16#01#; + CONSTANT DeviceID : NATURAL := 16#18#; + --Electronic Signature + CONSTANT ESignature : NATURAL := 16#18#; + --Device ID + --Manufacturer Identification && Memory Type && Memory Capacity + CONSTANT Jedec_ID : NATURAL := 16#01#; -- first byte of Device ID + CONSTANT DeviceID1 : NATURAL := 16#02#; + CONSTANT DeviceID2 : NATURAL := 16#19#; + CONSTANT ExtendedBytes : NATURAL := 16#4D#; + CONSTANT ExtendedID64 : NATURAL := 16#01#; + CONSTANT ExtendedID256 : NATURAL := 16#00#; + CONSTANT DieRev : NATURAL := 16#00#; + CONSTANT MaskRev : NATURAL := 16#00#; + + -- Declaration of signals that will hold the delayed values of ports + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL RSTNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + SIGNAL RSTNeg_pullup : std_ulogic := 'U'; + + -- internal delays + SIGNAL PP256_in : std_ulogic := '0'; + SIGNAL PP256_out : std_ulogic := '0'; + SIGNAL PP512_in : std_ulogic := '0'; + SIGNAL PP512_out : std_ulogic := '0'; + SIGNAL BP_in : std_ulogic := '0'; + SIGNAL BP_out : std_ulogic := '0'; + SIGNAL SE64_in : std_ulogic := '0'; + SIGNAL SE64_out : std_ulogic := '0'; + SIGNAL SE256_in : std_ulogic := '0'; + SIGNAL SE256_out : std_ulogic := '0'; + SIGNAL BE_in : std_ulogic := '0'; + SIGNAL BE_out : std_ulogic := '0'; + SIGNAL WRR_in : std_ulogic := '0'; + SIGNAL WRR_out : std_ulogic := '0'; + SIGNAL ERSSUSP_in : std_ulogic := '0'; + SIGNAL ERSSUSP_out : std_ulogic := '0'; + SIGNAL PRGSUSP_in : std_ulogic := '0'; + SIGNAL PRGSUSP_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL RST_in : std_ulogic := '0';-- Hardware Reset Timeout + SIGNAL RST_out : std_ulogic := '1';-- + SIGNAL PPBERASE_in : std_ulogic := '0'; + SIGNAL PPBERASE_out : std_ulogic := '0'; + SIGNAL PASSULCK_in : std_ulogic := '0'; + SIGNAL PASSULCK_out : std_ulogic := '0'; + SIGNAL PASSACC_in : std_ulogic := '0'; + SIGNAL PASSACC_out : std_ulogic := '0'; + + FUNCTION ReturnSectorIDRdPswdMd(TBPROT : std_logic) RETURN NATURAL IS + VARIABLE result : NATURAL; + BEGIN + IF TBPROT = '0' THEN + result := 0; + ELSE + IF (TimingModel(16) = '1') THEN + result := SecNum256; + ELSE + result := 511; + END IF; + END IF; + RETURN result; + END ReturnSectorIDRdPswdMd; + +BEGIN + + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + -- Because a tdevice generics is used, there must be a VITAL_primitives + -- assotiated with them + PP256 :VitalBuf(PP256_out, PP256_in, (tdevice_PP256 ,UnitDelay)); + PP512 :VitalBuf(PP512_out, PP512_in, (tdevice_PP512 ,UnitDelay)); + BP :VitalBuf(BP_out, BP_in, (tdevice_BP ,UnitDelay)); + SE64 :VitalBuf(SE64_out, SE64_in, (tdevice_SE64 ,UnitDelay)); + SE256 :VitalBuf(SE256_out, SE256_in, (tdevice_SE256 ,UnitDelay)); + BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); + WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay)); + ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay)); + PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + PPBERASE :VitalBuf(PPBERASE_out,PPBERASE_in,(tdevice_PPBERASE,UnitDelay)); + PASSULCK :VitalBuf(PASSULCK_out,PASSULCK_in,(tdevice_PASSULCK,UnitDelay)); + PASSACC :VitalBuf(PASSACC_out, PASSACC_in, (tdevice_PASSACC ,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO); + w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_5 : VitalWireDelay (RSTNeg_ipd, RSTNeg, tipd_RSTNeg); + w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + SCK : IN std_ulogic := 'U'; + CSNeg : IN std_ulogic := 'U'; + RSTNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + + PORT MAP ( + SIIn => SI_ipd, + SIOut => SI, + SOIn => SO_ipd, + SOut => SO, + SCK => SCK_ipd, + CSNeg => CSNeg_ipd, + RSTNeg => RSTNeg_ipd, + HOLDNegIn => HOLDNeg_ipd, + HOLDNegOut => HOLDNeg, + WPNegIn => WPNeg_ipd, + WPNegOut => WPNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + RESET_STATE, + AUTOBOOT, + WRITE_SR, + PAGE_PG, + OTP_PG, + PG_SUSP, + SECTOR_ERS, + BULK_ERS, + ERS_SUSP, + ERS_SUSP_PG, + ERS_SUSP_PG_SUSP, + PASS_PG, + PASS_UNLOCK, + PPB_PG, + PPB_ERS, + AUTOBOOT_PG, + ASP_PG, + PLB_PG, + DYB_PG, + NVDLR_PG + ); + + -- Instruction Type + TYPE instruction_type IS ( NONE, + WREN, -- Write Enable + WRDI, -- Write Disable + WRR, -- Write Register + READ, -- Read Normal (3Byte Address) + RD4, -- Read Normal (4Byte +) + OTPR, -- OTP Read + RDSR, -- Read Status Register 1 + RDSR2, -- Read Status Register 2 + RDCR, -- Read Configuration Register 1 + REMS, -- Read ID (SST) + RDID, -- Read ID JEDEC + RES, -- Read ID + FSTRD, -- Fast Read (3Byte Address) + FSTRD4, -- Fast Read (4Byte +) + DDRFR, -- Fast Read DDR (3Byte Address) + DDRFR4, -- Fast Read DDR (4Byte +) + DOR, -- Read Dual Out (3Byte Address) + DOR4, -- Read Dual Out (4Byte +) + DIOR, -- Read Dual I/O (3Byte Address) + DIOR4, -- Read Dual I/O (4Byte +) + DDRDIOR, -- Read DDR Dual I/O (3Byte) + DDRDIOR4, -- Read DDR Dual I/O (4Byte +) + QOR, -- Read Quad Out (3Byte Address) + QOR4, -- Read Quad Out (4Byte +) + QIOR, -- Read Quad I/O (3Byte Address) + QIOR4, -- Read Quad I/O (4Byte +) + DDRQIOR, -- Read DDR Quad I/O (3Byte) + DDRQIOR4, -- Read DDR Quad I/O (4Byte +) + PP, -- Program Page (3Byte Address) + PP4, -- Program Page (4Byte +) + QPP, -- Quad Page Program (3Byte) + QPP4, -- Quad Page Program (4Byte +) + OTPP, -- OTP Program + PGSP, -- Program Suspend + PGRS, -- Program Resume + BE, -- Bulk Erase + SE, -- Erase 128/256KB (3Byte) + SE4, -- Erase 128/256KB (4Byte +) + P4E, -- 4KB-sector Erase (3Byte Addr) + P4E4, -- 4KB-sector Erase (4Byte Addr) + ERSP, -- Erase Suspend + ERRS, -- Erase Resume + ABRD, -- AutoBoot Register Read + ABWR, -- AutoBoot Register Write + BRRD, -- Bank Register Read + BRWR, -- Bank Register Write + BRAC, -- Bank Register Access + DLPRD, -- Read Data Learning Pattern + PNVDLR, -- Program NVDLP Reg + WVDLR, -- Write Volatile DLP Reg + ASPRD, -- ASP Read + ASPP, -- ASP Program + DYBRD, -- DYB Read + DYBWR, -- DYB Write + PPBRD, -- PPB Read + PPBP, -- PPB Program + PPBERS, -- PPB Erase + PLBWR, -- PPB Lock Bit Write + PLBRD, -- PPB Lock Bit Read + PASSRD, -- Password Read + PASSP, -- Password Program + PASSU, -- Password Unlock + RESET, -- Reset + MBR, -- Mode Bit Reset + MPM, -- Multi-I/O-High Perf Mode + CLSR -- Clear Status Register + ); + + TYPE WByteType IS ARRAY (0 TO 511) OF INTEGER RANGE -1 TO MaxData; + -- Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; + -- OTP Memory Array + TYPE OTPArray IS ARRAY (OTPLoAddr TO OTPHiAddr) OF INTEGER + RANGE -1 TO MaxData; + --CFI Array (Common Flash Interface Query codes) + TYPE CFItype IS ARRAY (16#00# TO 16#55#) OF + INTEGER RANGE -1 TO 16#FF#; + ----------------------------------------------------------------------- + -- memory declaration + ----------------------------------------------------------------------- + -- Memory + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + -- OTP Sector + SHARED VARIABLE OTPMem : OTPArray := (OTHERS => MaxData); + --CFI Array + SHARED VARIABLE CFI_array : CFItype := (OTHERS => 0); + -- Programming Buffer + SIGNAL WByte : WByteType := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + ----------------------------------------------------------------------- + -- Registers + ----------------------------------------------------------------------- + -- *** Status Register 1 *** + SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Disable Bit + ALIAS SRWD :std_logic IS Status_reg1(7); + -- Status Register Programming Error Bit + ALIAS P_ERR :std_logic IS Status_reg1(6); + -- Status Register Erase Error Bit + ALIAS E_ERR :std_logic IS Status_reg1(5); + -- Status Register Block Protection Bits + ALIAS BP2 :std_logic IS Status_reg1(4); + ALIAS BP1 :std_logic IS Status_reg1(3); + ALIAS BP0 :std_logic IS Status_reg1(2); + -- Status Register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg1(1); + -- Status Register Write In Progress Bit + ALIAS WIP :std_logic IS Status_reg1(0); + + -- *** Status Register 2 *** + SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg2_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Enable Latch Bit + ALIAS ES :std_logic IS Status_reg2(1); + -- Status Register Write In Progress Bit + ALIAS PS :std_logic IS Status_reg2(0); + + -- *** Configuration Register 1 *** + SHARED VARIABLE Config_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Config_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Latency code + ALIAS LC1 :std_logic IS Config_reg1(7); + ALIAS LC0 :std_logic IS Config_reg1(6); + -- Configuration Register TBPROT bit + ALIAS TBPROT :std_logic IS Config_reg1(5); + -- Configuration Register LOCK bit + ALIAS LOCK :std_logic IS Config_reg1(4); + -- Configuration Register BPNV bit + ALIAS BPNV :std_logic IS Config_reg1(3); + -- Configuration Register TBPARM bit + ALIAS TBPARM :std_logic IS Config_reg1(2); + -- Configuration Register QUAD bit + ALIAS QUAD :std_logic IS Config_reg1(1); + -- Configuration Register FREEZE bit + ALIAS FREEZE :std_logic IS Config_reg1(0); + + -- *** VDLR Register *** + SHARED VARIABLE VDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL VDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** NVDLR Register *** + SHARED VARIABLE NVDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL NVDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** AutoBoot Register *** + SHARED VARIABLE AutoBoot_reg : std_logic_vector(31 downto 0) + := (others => '0'); + SIGNAL AutoBoot_reg_in : std_logic_vector(31 downto 0) + := (others => '0'); + --AutoBoot Enable Bit + ALIAS ABE :std_logic IS AutoBoot_reg(0); + + -- *** Bank Address Register *** + SHARED VARIABLE Bank_Addr_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Bank_Addr_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Bank Address Register EXTADD bit + ALIAS EXTADD :std_logic IS Bank_Addr_reg(7); + + -- *** ASP Register *** + SHARED VARIABLE ASP_reg : std_logic_vector(15 downto 0); + SIGNAL ASP_reg_in : std_logic_vector(15 downto 0) + := (others => '1'); + --Read Password Mode Enable Bit + ALIAS RPME :std_logic IS ASP_reg(5); + --PPB OTP Bit + ALIAS PPBOTP :std_logic IS ASP_reg(3); + -- Password Protection Mode Lock Bit + ALIAS PWDMLB :std_logic IS ASP_reg(2); + --Persistent Protection Mode Lock Bit + ALIAS PSTMLB :std_logic IS ASP_reg(1); + + -- *** Password Register *** + SHARED VARIABLE Password_reg : std_logic_vector(63 downto 0) + := (others => '1'); + SIGNAL Password_reg_in : std_logic_vector(63 downto 0) + := (others => '1'); + -- *** PPB Lock Register *** + SHARED VARIABLE PPBL : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL PPBL_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Persistent Protection Mode Lock Bit + ALIAS PPB_LOCK : std_logic IS PPBL(0); + SIGNAL PPB_LOCK_temp : std_ulogic := '0'; + + -- *** PPB Access Register *** + SHARED VARIABLE PPBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL PPBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- PPB_bits(Sec) + SHARED VARIABLE PPB_bits : std_logic_vector(SecNum64 downto 0) + := (OTHERS => '1'); + -- *** DYB Access Register *** + SHARED VARIABLE DYBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL DYBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- DYB(Sec) + SHARED VARIABLE DYB_bits : std_logic_vector(SecNum64 downto 0); + + -- The Lock Protection Registers for OTP Memory space + SHARED VARIABLE LOCK_BYTE1 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE2 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE3 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE4 :std_logic_vector(7 downto 0); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL cfg_write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL rd : boolean := false; + SIGNAL dual : boolean := false; + SIGNAL fast_rd : boolean := true; + SIGNAL ddr : boolean := false; + SIGNAL any_read : boolean := false; + + SIGNAL quadpg : boolean := false; + + SIGNAL oe : boolean := false; + SIGNAL oe_z : boolean := false; + + SHARED VARIABLE hold_mode : boolean := false; + + -- Memory Array Configuration + SIGNAL BottomBoot : boolean := false; + SIGNAL TopBoot : boolean := false; + SIGNAL UniformSec : boolean := false; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; --Page Prog. Done + SIGNAL PSTART : std_logic := '0'; --Start Page Programming + SIGNAL PGSUSP : std_logic := '0'; --Suspend Program + SIGNAL PGRES : std_logic := '0'; --Resume Program + + SIGNAL RES_TO_SUSP_MIN_TIME : std_logic := '0';--Resume to Suspend Flag + SIGNAL RES_TO_SUSP_TYP_TIME : std_logic := '0';--Resume to Suspend Flag + + SIGNAL WDONE : std_logic := '1'; --Write operation Done + SIGNAL WSTART : std_logic := '0'; --Start Write operation + + SIGNAL ESTART : std_logic := '0'; --Start Erase operation + SIGNAL EDONE : std_logic := '1'; --Erase operation Done + SIGNAL ESUSP : std_logic := '0'; --Suspend Erase + SIGNAL ERES : std_logic := '0'; --Resume Erase + + --reset timing + SIGNAL RST : std_logic := '0'; + SIGNAL Reseted : std_logic := '0'; --Reset Timing Control + --Lock Bit is enabled for customer programming + SIGNAL WRLOCKENABLE : BOOLEAN := TRUE; + --Flag that mark if ASP Register is allready programmed + SIGNAL ASPOTPFLAG : BOOLEAN := FALSE; + SIGNAL ASP_INIT : NATURAL RANGE 0 TO 1; + SIGNAL INITIAL_CONFIG : std_logic := '0'; + + SHARED VARIABLE PageSize : NATURAL := 0 ; + SHARED VARIABLE PageNum : NATURAL := 0 ; + SHARED VARIABLE SecNum : NATURAL := 0 ; + SHARED VARIABLE SecNumMax : NATURAL := 0 ; + SHARED VARIABLE SecSize : NATURAL := 0 ; + SHARED VARIABLE b_act : NATURAL := 0 ; + + SHARED VARIABLE ASP_ProtSE : NATURAL := 0; + SHARED VARIABLE Sec_ProtSE : NATURAL := 0; + + SHARED VARIABLE SecAddr : NATURAL RANGE 0 TO SecNum64:= 0; + + SHARED VARIABLE Sec_addr : NATURAL := 0; + + SHARED VARIABLE Page_addr : NATURAL; + SHARED VARIABLE pgm_page : NATURAL; + + --Flag for Password unlock command + SIGNAL PASS_UNLOCKED : boolean := FALSE; + SIGNAL PASS_TEMP : std_logic_vector(63 downto 0) + := (others => '1'); + + SHARED VARIABLE DOUBLE : BOOLEAN := FALSE; + SHARED VARIABLE EHP : BOOLEAN := FALSE; + + SHARED VARIABLE read_cnt : NATURAL := 0; + SHARED VARIABLE byte_cnt : NATURAL := 1; + SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ; + SHARED VARIABLE read_addr_tmp : NATURAL RANGE 0 TO AddrRANGE ; + + SHARED VARIABLE start_delay : NATURAL RANGE 0 TO 7; + SHARED VARIABLE ABSD : NATURAL RANGE 0 TO 7; + SIGNAL start_autoboot : std_logic := '0'; + + SIGNAL change_addr : std_logic := '0'; + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + SIGNAL SectorSuspend : NATURAL RANGE 0 TO SecNum64 := 0; + + -- Sector address + SIGNAL SA : NATURAL RANGE 0 TO SecNum64 := 0; + + -- Sector is protect if Sec_Prot(SecNum) = '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum64 downto 0) := + (OTHERS => '0'); + + SIGNAL change_TBPARM : std_logic := '0'; + + SIGNAL change_BP : std_logic := '0'; + SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000"; + + SHARED VARIABLE CFI_array_tmp : std_logic_vector(647 downto 0); + + SIGNAL Byte_number : NATURAL RANGE 0 TO 511 := 0; + + TYPE bus_cycle_type IS (STAND_BY, + OPCODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + SHARED VARIABLE bus_cycle_state : bus_cycle_type; + -- switch between Data bytes and Dummy bytes + SHARED VARIABLE DummyBytes_act : X01 := '0'; + SIGNAL dummy_cnt_act_temp : NATURAL := 0; + SIGNAL dummy_cnt_act : NATURAL := 0; + --Read Password Protection Mode Active flag + SIGNAL RdPswdProtMode : std_ulogic := '0'; + --Read Password Protection Mode Support flag + SIGNAL RdPswdProtEnable : std_ulogic := '0'; + SIGNAL BAR_ACC : std_ulogic := '0'; + + SHARED VARIABLE Latency_code : NATURAL RANGE 0 TO 7; + SHARED VARIABLE opcode_cnt : NATURAL := 0; + SHARED VARIABLE addr_cnt : NATURAL := 0; + SHARED VARIABLE mode_cnt : NATURAL := 0; + SHARED VARIABLE dummy_cnt : NATURAL := 0; + SHARED VARIABLE data_cnt : NATURAL := 0; + + SHARED VARIABLE PARAM_REGION : BOOLEAN := FALSE; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO 541; + BEGIN + + IF (TimingModel(16) = '0') THEN + IF TBPARM = '0' THEN + IF Addr/(SecSize64+1) <= 1 AND + (Instruct = P4E OR Instruct = P4E4) THEN --4KB Sectors + sector := Addr/(SecSize4+1); + AddrLOW := sector*(SecSize4+1); + AddrHIGH := sector*(SecSize4+1) + SecSize4; + ELSE + sector := Addr/(SecSize64+1); + AddrLOW := sector*(SecSize64+1); + AddrHIGH := sector*(SecSize64+1) + SecSize64; + END IF; + ELSE + IF Addr/(SecSize64+1) >= 510 AND + (Instruct = P4E OR Instruct = P4E4) THEN --4KB Sectors + sector := 510 + (Addr-(SecSize64+1)*510)/(SecSize4+1); + AddrLOW := 510*(SecSize64+1)+(sector-510)*(SecSize4+1); + AddrHIGH := 510*(SecSize64+1) + + (sector-510)*(SecSize4+1) + SecSize4; + ELSE + sector := Addr/(SecSize64+1); + AddrLOW := sector*(SecSize64+1); + AddrHIGH := sector*(SecSize64+1) + SecSize64; + END IF; + END IF; + ELSE + sector := Addr/(SecSize256+1); + AddrLOW := sector*(SecSize256+1); + AddrHIGH := sector*(SecSize256+1) + SecSize256; + END IF; + END ADDRHILO_SEC; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + BEGIN + page := Addr/PageSize; + AddrLOW := Page*PageSize; + AddrHIGH := Page*PageSize + (PageSize-1); + END AddrHILO_PG; + + PROCEDURE ReturnSectorID( + VARIABLE result : INOUT NATURAL; + SIGNAL ADDR : NATURAL RANGE 0 TO AddrRANGE) IS + VARIABLE conv : NATURAL; + BEGIN + IF (TimingModel(16) = '0') THEN + conv := ADDR / (SecSize64+1); + IF BottomBoot = TRUE THEN + IF conv <= 1 THEN --4KB Sectors + result := ADDR/(SecSize4+1); + ELSE + result := conv + 30; + END IF; + ELSIF TopBoot = TRUE THEN + IF conv >= 510 THEN --4KB Sectors + result := 510 + (Addr-(SecSize64+1)*510)/(SecSize4+1); + ELSE + result := conv; + END IF; + END IF; + ELSE + result := ADDR/(SecSize256+1); + END IF; + END ReturnSectorID; + + BEGIN + --------------------------------------------------------------------------- + --Power Up time + --------------------------------------------------------------------------- + + PoweredUp <= '1' AFTER tdevice_PU; + + --------------------------------------------------------------------------- + --sector structure + --------------------------------------------------------------------------- + UniformSec <= TRUE WHEN (TimingModel(16) = '1') + ELSE FALSE; + + TimingModelSel: PROCESS + BEGIN + IF TimingModel(16) = '1' THEN + -- Sector Number/Sector Size + SecNumMax:= SecNum256; + SecNum := SecNum256; + SecSize := SecSize256; + -- 256B/512B Page Size + PageSize := 512; + PageNum := PageNum256; + ELSE + -- Sector Number/Sector Size + SecNumMax:= SecNum64; + SecNum := 511; + SecSize := SecSize64; + -- 256B/512B Page Size + PageSize := 256; + PageNum := PageNum64; + END IF; + --Enhanced High Performance Flag + IF (TimingModel(15) = '0' OR TimingModel(15) = '2' OR + TimingModel(15) = '3' OR TimingModel(15) = 'R' OR + TimingModel(15) = 'A' OR TimingModel(15) = 'B' OR + TimingModel(15) = 'C' OR TimingModel(15) = 'D' OR + TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + EHP := TRUE; + IF (TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + RdPswdProtEnable <= '1'; + END IF; + ELSIF (TimingModel(15) = '4' OR TimingModel(15) = '6' OR + TimingModel(15) = '7' OR TimingModel(15) = '8' OR + TimingModel(15) = '9' OR TimingModel(15) = 'Q') THEN + EHP := FALSE; + END IF; + + IF (TimingModel(15) ='0' OR TimingModel(15) ='2' OR + TimingModel(15) ='3' OR TimingModel(15) ='R' OR + TimingModel(15) ='A' OR TimingModel(15) ='B' OR + TimingModel(15) ='C' OR TimingModel(15) ='D' OR + TimingModel(15) ='4' OR TimingModel(15) ='6' OR + TimingModel(15) ='7' OR TimingModel(15) ='8' OR + TimingModel(15) ='9' OR TimingModel(15) ='Q') THEN + ASP_INIT <= 1; + ELSIF (TimingModel(15) ='Y' OR TimingModel(15) ='Z' OR + TimingModel(15) ='S' OR TimingModel(15) ='T' OR + TimingModel(15) ='K' OR TimingModel(15) ='L') THEN + ASP_INIT <= 0; + END IF; + WAIT; + END PROCESS; + + RSTtiming: PROCESS(RSTNeg_pullup,Instruct) + BEGIN + IF falling_edge(RSTNeg_pullup) THEN + RST <= '1', '0' AFTER 200 ns; + ELSIF Instruct = RESET THEN + Reseted <= '0', '1' AFTER 10 ns; + END IF; + END PROCESS; + + DUMMYcnt: PROCESS(dummy_cnt_act_temp) + BEGIN + dummy_cnt_act <= dummy_cnt_act_temp; + END PROCESS; + + ReadPasswordProtectionMode: PROCESS(PPB_LOCK_temp, + ASP_reg_in(2), ASP_reg_in(5)) + BEGIN + IF (PPB_LOCK = '0' AND PWDMLB = '0' AND RPME = '0' AND + RdPswdProtEnable = '1') THEN + RdPswdProtMode <= '1'; + ABE := '0'; + ELSE + RdPswdProtMode <= '0'; + END IF; + END PROCESS; + --------------------------------------------------------------------------- + -- autoboot control logic + --------------------------------------------------------------------------- + AutoBootControl: PROCESS(SCK_ipd, current_state) + BEGIN + IF (current_state = AUTOBOOT) THEN + IF rising_edge(SCK_ipd) THEN + IF (start_delay > 0) THEN + start_delay := start_delay - 1; + END IF; + END IF; + + IF (start_delay = 0) THEN + start_autoboot <= '1'; + ELSE + start_autoboot <= '0'; + END IF; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn, SOIn, SCK_ipd, CSNeg_ipd, RSTNeg_ipd, + HOLDNegIn, WPNegIn) + + -- Timing Check Variables + -- Setup/Hold Checks variables + VARIABLE Tviol_CSNeg_SCK_normal : X01 := '0'; + VARIABLE TD_CSNeg_SCK_normal : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_SCK_DDR : X01 := '0'; + VARIABLE TD_CSNeg_SCK_DDR : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_RSTNeg : X01 := '0'; + VARIABLE TD_CSNeg_RSTNeg : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType; + + VARIABLE Tviol_HOLDNeg_SCK : X01 := '0'; + VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_R : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_R : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_F : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_F : VitalTimingDataType; + + VARIABLE Tviol_RSTNeg_CSNeg : X01 := '0'; + VARIABLE TD_RSTNeg_CSNeg : VitalTimingDataType; + + --Pulse Width and Period Check Variables + VARIABLE Pviol_SCK_serial : X01 := '0'; + VARIABLE PD_SCK_serial : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual : X01 := '0'; + VARIABLE PD_SCK_dual : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast : X01 := '0'; + VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quadpg : X01 := '0'; + VARIABLE PD_SCK_quadpg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR : X01 := '0'; + VARIABLE PD_SCK_DDR : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_read : X01 := '0'; + VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_pgers : X01 := '0'; + VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_RSTNeg : X01 := '0'; + VARIABLE PD_RSTNeg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_rd : X01 := '0'; + VARIABLE PD_SCK_serial_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_rd : X01 := '0'; + VARIABLE PD_SCK_fast_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual_rd : X01 := '0'; + VARIABLE PD_SCK_dual_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR_rd : X01 := '0'; + VARIABLE PD_SCK_DDR_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quad_pg : X01 := '0'; + VARIABLE PD_SCK_quad_pg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_normal_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_normal_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_normal_noedge_posedge, + HoldLow => thold_CSNeg_SCK_normal_noedge_posedge, + CheckEnabled => ddr = false, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_normal, + Violation => Tviol_CSNeg_SCK_normal + ); + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_DDR_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_DDR_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_DDR_noedge_posedge, + HoldLow => thold_CSNeg_SCK_DDR_noedge_posedge, + CheckEnabled => ddr, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_DDR, + Violation => Tviol_CSNeg_SCK_DDR + ); + + -- Hold Check between CSNeg and RSTNeg + VitalSetupHoldCheck ( + TestSignal => CSNeg, + TestSignalName => "CSNeg", + RefSignal => RSTNeg, + RefSignalName => "RSTNeg", + HoldHigh => thold_CSNeg_RSTNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_RSTNeg, + Violation => Tviol_CSNeg_RSTNeg + ); + + -- Setup/Hold Check between SI and SCK, serial mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => NOT(DOUBLE) AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => true, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_setup, + Violation => Tviol_WPNeg_CSNeg_setup + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => SRWD = '1' AND WEL = '1', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_hold, + Violation => Tviol_WPNeg_CSNeg_hold + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupLow => tsetup_HOLDNeg_SCK, + SetupHigh => tsetup_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + CheckEnabled => QUAD = '0' + AND HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNeg_SCK, + Violation => Tviol_HOLDNeg_SCK + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_posedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_posedge, + HoldHigh => thold_SI_SCK_DDR_noedge_posedge, + HoldLow => thold_SI_SCK_DDR_noedge_posedge, + CheckEnabled => DOUBLE AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_R, + Violation => Tviol_SI_SCK_DDR_R + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_negedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_negedge, + HoldHigh => thold_SI_SCK_DDR_noedge_negedge, + HoldLow => thold_SI_SCK_DDR_noedge_negedge, + CheckEnabled => ddr AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_F, + Violation => Tviol_SI_SCK_DDR_F + ); + + -- Setup Check between RSTNeg and SCK, DDR fast mode + VitalSetupHoldCheck ( + TestSignal => RSTNeg, + TestSignalName => "RSTNeg", + RefSignal => CSNeg, + RefSignalName => "CSNeg", + SetupHigh => tsetup_RSTNeg_CSNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_RSTNeg_CSNeg, + Violation => Tviol_RSTNeg_CSNeg + ); + + --Pulse Width and Period Check Variables + -- Pulse Width Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_serial_negedge, + PulseWidthHigh => tpw_SCK_serial_posedge, + PeriodData => PD_SCK_serial, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd); + + -- Pulse Width Check SCK for DUAL_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_dual_negedge, + PulseWidthHigh => tpw_SCK_dual_posedge, + PeriodData => PD_SCK_dual, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual); + + -- Pulse Width Check SCK for FAST_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_fast_negedge, + PulseWidthHigh => tpw_SCK_fast_posedge, + PeriodData => PD_SCK_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Pulse Width Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_quadpg_negedge, + PulseWidthHigh => tpw_SCK_quadpg_posedge, + PeriodData => PD_SCK_quadpg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quadpg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg); + + -- Pulse Width Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CSNeg_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => any_read ); + + -- Pulse Width Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pgers_posedge, + PeriodData => PD_CSNeg_pgers, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_pgers, + HeaderMsg => InstancePath & PartID, + CheckEnabled => NOT(any_read)); + + -- Pulse Width Check RSTNeg + VitalPeriodPulseCheck ( + TestSignal => RSTNeg_ipd, + TestSignalName => "RSTNeg", + PulseWidthLow => tpw_RSTNeg_negedge, + PulseWidthHigh => tpw_RSTNeg_posedge, + CheckEnabled => TRUE, + HeaderMsg => InstancePath & PartID, + PeriodData => PD_RSTNeg, + Violation => Pviol_RSTNeg + ); + + -- Pulse Width Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_DDR_negedge, + PulseWidthHigh => tpw_SCK_DDR_posedge, + PeriodData => PD_SCK_DDR, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_rd, + PeriodData => PD_SCK_serial_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for FAST READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast_rd, + PeriodData => PD_SCK_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Period Check SCK for DUAL READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_dual_rd, + PeriodData => PD_SCK_dual_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual ); + + -- Period Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_quadpg, + PeriodData => PD_SCK_quad_pg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quad_pg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg ); + + -- Period Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_DDR_rd, + PeriodData => PD_SCK_DDR_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr ); + + Violation := Tviol_CSNeg_SCK_normal OR + Tviol_CSNeg_SCK_DDR OR + Tviol_CSNeg_RSTNeg OR + Tviol_SI_SCK OR + Tviol_WPNeg_CSNeg_setup OR + Tviol_WPNeg_CSNeg_hold OR + Tviol_HOLDNeg_SCK OR + Tviol_SI_SCK_DDR_R OR + Tviol_SI_SCK_DDR_F OR + Tviol_RSTNeg_CSNeg OR + Pviol_SCK_serial OR + Pviol_SCK_dual OR + Pviol_SCK_fast OR + Pviol_SCK_quadpg OR + Pviol_CSNeg_read OR + Pviol_CSNeg_pgers OR + Pviol_SCK_DDR OR + Pviol_SCK_serial_rd OR + Pviol_SCK_fast_rd OR + Pviol_SCK_dual_rd OR + Pviol_SCK_quad_pg OR + Pviol_SCK_DDR_rd; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + + ---------------------------------------------------------------------------- + -- sequential process for FSM state transition + ---------------------------------------------------------------------------- + StateTransition : PROCESS(next_state, RST, PoweredUp, RST_out) + + BEGIN + IF PoweredUp = '1' THEN + IF RSTNeg_pullup = '1' and RST_out= '1' THEN + IF next_state'EVENT THEN + current_state <= next_state; + END IF; + ELSIF RSTNeg_pullup = '0' AND falling_edge(RST) THEN + --no state transition while RESET# low + current_state <= RESET_STATE; + RST_in <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END PROCESS StateTransition; + + Threset : PROCESS(RST_in) + BEGIN + IF rising_edge(RST_in) THEN + RST_out <= '0', '1' AFTER (thold_CSNeg_RSTNeg-200 ns); + END IF; + END PROCESS Threset; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_pullup, SIIn, RST_out, + WPNeg_pullup) + + TYPE quad_data_type IS ARRAY (0 TO 1023) OF INTEGER RANGE 0 TO 15; + + VARIABLE bit_cnt : NATURAL := 0; + VARIABLE Data_in : std_logic_vector(4095 downto 0) + := (others => '0'); + + VARIABLE opcode : std_logic_vector(7 downto 0); + VARIABLE opcode_in : std_logic_vector(7 downto 0); + VARIABLE addr_bytes : std_logic_vector(31 downto 0); + VARIABLE hiaddr_bytes : std_logic_vector(31 downto 0); + VARIABLE Address_in : std_logic_vector(31 downto 0); + VARIABLE mode_bytes : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + + VARIABLE CLK_PER : time; + VARIABLE LAST_CLK : time; + VARIABLE Check_freq : boolean := FALSE; + + BEGIN + + IF rising_edge(CSNeg_ipd) AND NOT(bus_cycle_state = DATA_BYTES) + AND NOT(bus_cycle_state = DUMMY_BYTES) THEN + bus_cycle_state := STAND_BY; + ELSE + CASE bus_cycle_state IS + WHEN STAND_BY => + IF falling_edge(CSNeg_ipd) THEN + Instruct <= NONE; + write <= '1'; + cfg_write <= '0'; + opcode_cnt:= 0; + addr_cnt := 0; + mode_cnt := 0; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + data_cnt := 0; + DOUBLE := FALSE; + CLK_PER := 0 ns; + LAST_CLK := 0 ns; + IF current_state = AUTOBOOT THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := OPCODE_BYTE; + END IF; + END IF; + + WHEN OPCODE_BYTE => + IF rising_edge(SCK_ipd) THEN + + Latency_code := to_nat(LC1 & LC0); + CLK_PER := NOW - LAST_CLK; + LAST_CLK := NOW; + IF Check_freq THEN + IF (CLK_PER < 20 ns AND Latency_code = 3) OR + (CLK_PER < 12.5 ns AND Latency_code = 0) OR + (CLK_PER < 11.1 ns AND Latency_code = 1) OR + (CLK_PER < 9.6 ns AND Latency_code = 2) THEN + ASSERT FALSE + REPORT "More wait states are required for " & + "this clock frequency value" + SEVERITY warning; + END IF; + END IF; + Check_freq := FALSE; + + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + --One-byte of instruction opcode is shifted into the + --device on the SI serial input pin with the most + --significant bit (MSB) first.Each bit input on the + --SI serial input pin is latched on the rising edge of + --the SCK serial clock signal. + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF opcode_cnt = BYTE THEN + --MSB first + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := opcode_in(7-i); + END LOOP; + + CASE opcode IS + WHEN "00000110" => --06h + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => --01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => --03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010011" => --13h + Instruct <= RD4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001011" => --4Bh + Instruct <= OTPR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00000101" => --05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000111" => --07h + Instruct <= RDSR2; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => --35h + Instruct <= RDCR; + bus_cycle_state := DATA_BYTES; + WHEN "10010000" => --90h + Instruct <= REMS; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10011111" => --9Fh + Instruct <= RDID; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => --ABh + Instruct <= RES; + bus_cycle_state := DUMMY_BYTES; + WHEN "00001011" => --0Bh + Instruct <= FSTRD; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001100" => --0Ch + Instruct <= FSTRD4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001101" => --0Dh + Instruct <= DDRFR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001110" => --0Eh + Instruct <= DDRFR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00111011" => --3Bh + Instruct <= DOR; + Check_freq := TRUE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111100" => --3Ch + Instruct <= DOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111011" => --BBh + Instruct <= DIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111100" => --BCh + Instruct <= DIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111101" => --BDh + Instruct <= DDRDIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111110" => --BEh + Instruct <= DDRDIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101011" => --6Bh + Instruct <= QOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101100" => --6Ch + Instruct <= QOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101011" => --EBh + Instruct <= QIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101100" => --ECh + Instruct <= QIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101101" => --EDh + Instruct <= DDRQIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101110" => --EEh + Instruct <= DDRQIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00000010" => --02h + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010010" => --12h + Instruct <= PP4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => --32h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00111000" => --38h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00110100" => --34h + Instruct <= QPP4; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "01000010" => --42h + Instruct <= OTPP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10000101" => --85h + Instruct <= PGSP; + bus_cycle_state := DATA_BYTES; + WHEN "10001010" => --8Ah + Instruct <= PGRS; + bus_cycle_state := DATA_BYTES; + WHEN "11000111" => --C7h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "01100000" => --60h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "11011000" => --D8h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11011100" => --DCh + Instruct <= SE4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100000" => --20h + Instruct <= P4E; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100001" => --21h + Instruct <= P4E4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01110101" => --75h + Instruct <= ERSP; + bus_cycle_state := DATA_BYTES; + WHEN "01111010" => --7Ah + Instruct <= ERRS; + bus_cycle_state := DATA_BYTES; + WHEN "00010100" => --14h + Instruct <= ABRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010101" => --15h + Instruct <= ABWR; + bus_cycle_state := DATA_BYTES; + WHEN "00010110" => --16h + Instruct <= BRRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010111" => --17h + Instruct <= BRWR; + bus_cycle_state := DATA_BYTES; + WHEN "10111001" => --B9h + Instruct <= BRAC; + bus_cycle_state := DATA_BYTES; + WHEN "00101011" => --2Bh + Instruct <= ASPRD; + bus_cycle_state := DATA_BYTES; + WHEN "00101111" => --2Fh + Instruct <= ASPP; + bus_cycle_state := DATA_BYTES; + WHEN "11100000" => --E0h + Instruct <= DYBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100001" => --E1h + Instruct <= DYBWR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100010" => --E2h + Instruct <= PPBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100011" => --E3h + Instruct <= PPBP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100100" => --E4h + Instruct <= PPBERS; + bus_cycle_state := DATA_BYTES; + WHEN "10100110" => --A6h + Instruct <= PLBWR; + bus_cycle_state := DATA_BYTES; + WHEN "10100111" => --A7h + Instruct <= PLBRD; + bus_cycle_state := DATA_BYTES; + WHEN "11100111" => --E7h + Instruct <= PASSRD; + bus_cycle_state := DATA_BYTES; + WHEN "11101000" => --E8h + Instruct <= PASSP; + bus_cycle_state := DATA_BYTES; + WHEN "11101001" => --E9h + Instruct <= PASSU; + bus_cycle_state := DATA_BYTES; + WHEN "11110000" => --F0h + Instruct <= RESET; + bus_cycle_state := DATA_BYTES; + WHEN "11111111" => --FFh + Instruct <= MBR; + bus_cycle_state := MODE_BYTE; + WHEN "01000001" => -- 41h + Instruct <= DLPRD; + bus_cycle_state := DATA_BYTES; + WHEN "01000011" => -- 43h + Instruct <= PNVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "01001010" => -- 4Ah + Instruct <= WVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "00110000" => --30h + Instruct <= CLSR; + bus_cycle_state := DATA_BYTES; + WHEN others => + null; + + END CASE; + END IF; + END IF; + END IF; + + WHEN ADDRESS_BYTES => + IF Instruct= DDRFR OR Instruct= DDRFR4 OR Instruct= DDRDIOR + OR Instruct = DDRDIOR4 OR Instruct = DDRQIOR OR + Instruct = DDRQIOR4 THEN + DOUBLE := TRUE; + ELSE + DOUBLE := FALSE; + END IF; + + IF (rising_edge(SCK_ipd) AND NOT(DOUBLE) AND + (CSNeg_ipd= '0')) THEN + IF (((Instruct=FSTRD AND EXTADD= '0' ) + OR (Instruct=DOR AND EXTADD= '0') + OR Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (Instruct=QOR AND QUAD= '1' AND EXTADD='0') THEN + --Instruction + 3 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF (Instruct=FSTRD OR Instruct=DOR OR + Instruct=QOR) THEN + IF (Latency_code = 3) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF ((((Instruct=FSTRD4) OR (Instruct=DOR4) OR + ((Instruct=FSTRD) AND EXTADD= '1') OR + ((Instruct=DOR) AND EXTADD= '1')) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct=QOR4) AND QUAD='1') OR + ((Instruct=QOR) AND QUAD='1' AND EXTADD='1')) THEN + --Instruction + 4 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF (DOUBLE AND NOT(hold_mode) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF Instruct = DIOR AND EXTADD= '0' AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + -- DUAL I/O High Performance Read (3Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF ((Instruct = DIOR4 OR + (Instruct = DIOR AND EXTADD= '1')) AND + ((HOLDNeg_pullup = '1' AND QUAD = '0') OR + QUAD = '1')) THEN + -- DUAL I/O High Performance Read (4Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR AND EXTADD= '0') THEN + -- QUAD I/O High Performance Read (3Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR4 OR + (Instruct = QIOR AND EXTADD= '1')) THEN + -- QUAD I/O High Performance Read (4Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) + := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (((Instruct = RD4 OR Instruct = PP4 OR + Instruct = SE4 OR Instruct = PPBRD OR + Instruct = DYBRD OR Instruct = DYBWR OR + Instruct = PPBP OR Instruct = P4E4 OR + (Instruct = READ AND EXTADD= '1' ) OR + (Instruct = PP AND EXTADD= '1' ) OR + (Instruct = P4E AND EXTADD= '1' ) OR + (Instruct = SE AND EXTADD= '1' )) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (QUAD ='1' AND (Instruct=QPP4 OR + (Instruct = QPP AND EXTADD= '1' ))))THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') AND EXTADD= '0') THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF (SCK_ipd'EVENT AND DOUBLE AND addr_cnt /= 0 ) OR + (rising_edge(SCK_ipd) AND DOUBLE AND addr_cnt = 0 ) THEN + IF (Instruct=DDRFR AND EXTADD= '0' ) THEN + --Fast DDR Read Mode + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 3*BYTE THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRFR4 OR + (Instruct=DDRFR AND EXTADD= '1' )) THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 4*BYTE THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct= DDRDIOR AND EXTADD= '0' ) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1):= SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRDIOR4 OR + (Instruct=DDRDIOR AND EXTADD= '1' )) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR AND EXTADD= '0' ) AND + QUAD = '1' THEN + --Quad I/O DDR Read Mode + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 25) := "0000000"; + addr_bytes(24) := Bank_Addr_reg(0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 5 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF QUAD = '1' AND (Instruct=DDRQIOR4 OR + (Instruct=DDRQIOR AND EXTADD= '1' )) THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + + WHEN MODE_BYTE => + IF rising_edge(SCK_ipd) THEN + IF ((Instruct=DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + IF Latency_code = 0 OR Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=QIOR OR Instruct = QIOR4) + AND QUAD = '1' THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSIF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt) := SIIn; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt) := SOIn; + mode_in(4*mode_cnt+1) := SIIn; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(0) := HOLDNegIn; + mode_in(1) := WPNegIn; + mode_in(2) := SOIn; + mode_in(3) := SIIn; + END IF; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + ELSIF falling_edge(SCK_ipd) THEN + IF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(4) := HOLDNegIn; + mode_in(5) := WPNegIn; + mode_in(6) := SOIn; + mode_in(7) := SIIn; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DUMMY_BYTES => + IF rising_edge(SCK_ipd) THEN + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + IF (((Instruct=FSTRD OR Instruct=FSTRD4 OR + Instruct=DOR OR Instruct=DOR4 OR + Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct = QOR OR Instruct = QOR4) AND + QUAD = '1'))THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt=1) OR + (Latency_code = 0 AND dummy_cnt=2) OR + (Latency_code = 1 AND dummy_cnt=4) OR + (Latency_code = 2 AND dummy_cnt=5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 5) OR + (Latency_code = 1 AND dummy_cnt = 6) OR + (Latency_code = 2 AND dummy_cnt = 7)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct=RES THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = 3*BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 1 AND dummy_cnt = 1) OR + (Latency_code = 2 AND dummy_cnt = 2)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt = 2) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF ((Instruct = QIOR OR Instruct = QIOR4) AND + QUAD = '1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 1) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 4) OR + (Latency_code = 2 AND dummy_cnt = 5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 3) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF falling_edge(SCK_ipd) THEN + IF NOT(hold_mode) THEN + IF (DOUBLE AND VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DATA_BYTES => + IF rising_edge(CSNeg_ipd) THEN + IF ((mode_bytes(7 downto 4) = "1010" AND + (Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QIOR OR Instruct = QIOR4)) OR + ((mode_bytes(7 downto 4) = + NOT(mode_bytes(3 downto 0))) AND + (Instruct = DDRFR OR Instruct = DDRFR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 OR + Instruct = DDRQIOR OR Instruct = DDRQIOR4))) THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + END IF; + IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' AND + NOT(DOUBLE) THEN + IF ((Instruct = READ OR Instruct=RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = RDSR OR Instruct = RDSR2 OR + Instruct = RDCR OR Instruct = OTPR OR + Instruct = DOR OR Instruct = DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = ABRD OR Instruct = BRRD OR + Instruct = ASPRD OR Instruct = DYBRD OR + Instruct = PPBRD OR + Instruct = PASSRD OR Instruct = RDID OR + Instruct = RES OR Instruct = REMS OR + Instruct = PLBRD OR Instruct = DLPRD) + AND ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (current_state = AUTOBOOT AND start_delay = 0)OR + ((Instruct=QOR OR Instruct=QIOR OR Instruct=QOR4 + OR Instruct= QIOR4) AND QUAD = '1') THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + ELSIF SCK_ipd'EVENT AND CSNeg_ipd = '0' AND DOUBLE THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + + IF rising_edge(SCK_ipd) THEN + IF QUAD = '1' AND (Instruct=QPP OR Instruct = QPP4)THEN + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF data_cnt > (PageSize*2-1) THEN + --In case of quad mode and QPP, + --if more than 512 bytes are sent to the device + FOR I IN 0 TO (PageSize*2-2) LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in((PageSize*2-1)) := + to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF quad_nybble /= "ZZZZ" THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt > (PageSize*8-1) THEN + --In case of serial mode and PP, + -- if more than 512 bytes are sent to the device + -- previously latched data are discarded and last + -- 512 data bytes are guaranteed to be programmed + -- correctly within the same page. + IF bit_cnt = 0 THEN + FOR I IN 0 TO ((PageSize-1)*BYTE - 1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in((PageSize-1)*BYTE + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF bit_cnt = 8 THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + CASE Instruct IS + WHEN WREN | WRDI | BE | SE | SE4 | CLSR | RESET | + PPBP | PPBERS | PGSP | PGRS | ERSP | BRAC | + ERRS | P4E | P4E4 | PLBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt = 0 THEN + write <= '0'; + END IF; + END IF; + + WHEN WRR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF ((data_cnt mod 8) = 0 AND data_cnt > 0) THEN + IF data_cnt = 8 THEN + --If CS# is driven high after eight + --cycle,only the Status Register is + --written to. + write <= '0'; + IF BAR_ACC = '0' THEN + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= + Data_in(7-i); + END LOOP; + ELSIF P_ERR = '0' AND E_ERR = '0' THEN + FOR i IN 0 TO 7 LOOP + Bank_Addr_reg_in(i) <= + Data_in(7-i); + END LOOP; + END IF; + ELSIF data_cnt = 16 THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + IF BAR_ACC = '0' THEN + FOR i IN 0 TO 7 LOOP + cfg_write <= '1'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= + Data_in(7-i); + Config_reg1_in(i) <= + Data_in(15-i); + END LOOP; + END LOOP; + ELSIF P_ERR = '0' AND E_ERR = '0' THEN + FOR i IN 0 TO 7 LOOP + Bank_Addr_reg_in(i) <= + Data_in(7-i); + END LOOP; + END IF; + END IF; + END IF; + END IF; + + WHEN PP | PP4 | OTPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt > 0 THEN + IF (data_cnt mod 8) = 0 THEN + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 7 DOWNTO 0 LOOP + IF Data_in((i*8) + (7-j)) + /= 'X' THEN + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END IF; + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*BYTE THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/8-1; + END IF; + END IF; + END IF; + END IF; + + WHEN QPP | QPP4=> + IF data_cnt > 0 THEN + IF data_cnt mod 2 = 0 THEN + quadpg <= FALSE; + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*2 THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/2-1; + END IF; + END IF; + END IF; + + WHEN ABWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 32 THEN + write <= '0'; + FOR J IN 0 TO 31 LOOP + AutoBoot_reg_in(J) <= + Data_in(31-J); + END LOOP; + END IF; + END IF; + + WHEN BRWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + Bank_Addr_reg_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN ASPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 16 THEN + write <= '0'; + FOR J IN 0 TO 15 LOOP + ASP_reg_in(J) <= + Data_in(15-J); + END LOOP; + END IF; + END IF; + + WHEN DYBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + DYBAR_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PNVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + NVDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN WVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + VDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PASSP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + Password_reg_in(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN PASSU => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + PASS_TEMP(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN others => + null; + + END CASE; + END IF; + END CASE; + END IF; + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART, PGSUSP, PGRES, RST, Reseted) + VARIABLE pob : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF rising_edge(PSTART) AND PDONE = '1' THEN + IF Instruct = PP OR Instruct = PP4 OR Instruct = OTPP OR + Instruct = QPP OR Instruct = QPP4 THEN + IF PageSize = 256 THEN + pob := tdevice_PP256; + ELSE + pob := tdevice_PP512; + END IF; + ELSE + pob := tdevice_BP; + END IF; + elapsed := 0 ns; + start := NOW; + PDONE <= '0', '1' AFTER pob; + ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN + elapsed := NOW - start; + duration := pob - elapsed; + PDONE <= '0'; + ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN + start := NOW; + PDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + PDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + PDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WRR; + ELSE + wob := tdevice_WRR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + WDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + WDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Bulk Erase + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART, ESUSP, ERES, RST, Reseted) + VARIABLE seo : time; + VARIABLE beo : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + IF UniformSec THEN + seo := tdevice_SE256; + ELSE + seo := tdevice_SE64; + END IF; + beo := tdevice_BE; + ELSE + IF UniformSec THEN + seo := tdevice_SE256 / 1000; + ELSE + seo := tdevice_SE64 / 1000; + END IF; + beo := tdevice_BE / 1000; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = BE THEN + duration := beo; + ELSE --Instruct = SE OR SE4 OR P4E OR P4E4 + duration := seo; + END IF; + elapsed := 0 ns; + EDONE <= '0', '1' AFTER duration; + start := NOW; + ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN + elapsed := NOW - start; + duration := duration - elapsed; + EDONE <= '0'; + ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN + start := NOW; + EDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + EDONE <= '1'; -- reset done, eras terminated + ELSIF rising_edge(Reseted) THEN + EDONE <= '1'; -- reset done, erase terminated + END IF; + + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS(CSNeg_ipd) + BEGIN + IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, RSTNeg_pullup, WDONE, PDONE, + ERSSUSP_out, PRGSUSP_out, EDONE, RST_out, PPBERASE_in, + PASSULCK_in) + + VARIABLE sect : NATURAL RANGE 0 TO SecNum64; + + BEGIN + + IF rising_edge(PoweredUp) THEN + IF ABE = '1' AND RPME /= '0' THEN + --Autoboot is enabled and The Read Password feature is not enabled + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)&"000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + ELSE + IF RST_out= '0' then + next_state <= current_state; + ELSIF falling_edge(write) AND Instruct = RESET THEN + IF ABE = '1' AND RPME /= '0' THEN + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay:= to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + next_state <= AUTOBOOT; + ELSE + next_state <= IDLE; + END IF; + ELSE + CASE current_state IS + WHEN RESET_STATE => + IF rising_edge(RST_out) THEN + IF ABE = '1' AND RPME /= '0' + AND RdPswdProtMode = '0' THEN + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN IDLE => + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + IF (Instruct = WRR AND WEL = '1' AND BAR_ACC = '0') THEN + IF ((not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD = '0') OR QUAD = '1') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (TBPARM='1' AND Config_reg1_in(2)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + ASSERT cfg_write = '0' + REPORT "Changing value of Configuration " & + "Register OTP bit from 1 to 0 is " & + "not allowed!!!" + SEVERITY WARNING; + ELSE + next_state <= WRITE_SR; + END IF; + END IF; + ELSIF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + ReturnSectorID(sect,Address); + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + next_state <= PAGE_PG; + END IF; + ELSIF Instruct=OTPP AND WEL = '1' AND FREEZE = '0' THEN + IF ((((Address >= 16#10# AND Address <= 16#13#) OR + (Address >= 16#20# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + next_state <= OTP_PG; + END IF; + ELSIF (Instruct= SE OR Instruct= SE4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 510) OR + (BottomBoot = TRUE AND sect > 31) THEN + IF (Sec_Prot(sect) = '0' AND PPB_bits(sect)='1' + AND DYB_bits(sect)='1') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF (TopBoot = TRUE AND sect >= 510) OR + (BottomBoot = TRUE AND sect <= 31) THEN + IF Sec_ProtSE = 32 AND ASP_ProtSE = 32 THEN + --Sector erase command is applied to a 64 KB + --range that includes 4 KB sectors. + next_state <= SECTOR_ERS; + END IF; + END IF; + ELSIF (Instruct=P4E OR Instruct=P4E4) AND WEL='1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 510) OR + (BottomBoot = TRUE AND sect > 31) THEN + --A P4E instruction applied to a sector that + --is larger than 4 KB will not be executed + --and will not set the E_ERR status. + REPORT "The instruction is applied to a "& + "sector that is larger than 4 KB. "& + "Instruction is ignored!!!" + SEVERITY warning; + ELSE + IF Sec_Prot(sect) = '0' AND PPB_bits(sect)='1' + AND DYB_bits(sect)='1' THEN + next_state <= SECTOR_ERS; + END IF; + END IF; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0='0' AND BP1='0' AND BP2='0') THEN + next_state <= BULK_ERS; + ELSIF Instruct = ABWR AND WEL = '1' THEN + --Autoboot Register Write Command + next_state <= AUTOBOOT_PG; + ELSIF Instruct = ASPP AND WEL = '1' THEN + --ASP Register Program Command + IF not(ASPOTPFLAG) THEN + next_state <= ASP_PG; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + next_state <= PLB_PG; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + next_state <= PASS_PG; + END IF; + ELSIF Instruct = PASSU AND WEL= '1' AND WIP= '0' THEN + next_state <= PASS_UNLOCK; + ELSIF Instruct = PPBP AND WEL = '1' THEN + next_state <= PPB_PG; + ELSIF (Instruct=PPBERS AND WEL='1' AND PPBOTP='1') THEN + next_state <= PPB_ERS; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + next_state <= DYB_PG; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + next_state <= NVDLR_PG; + ELSE + next_state <= IDLE; + END IF; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '1' AND + WIP = '0' THEN + IF Instruct = PASSU THEN + next_state <= PASS_UNLOCK; + END IF; + END IF; + + WHEN AUTOBOOT => + IF rising_edge(CSNeg_ipd) THEN + next_state <= IDLE; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = PGRS THEN + next_state <= PAGE_PG; + ELSE + next_state <= PG_SUSP; + END IF; + ELSE + next_state <= PG_SUSP; + END IF; + + WHEN OTP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN BULK_ERS => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN SECTOR_ERS => + IF ERSSUSP_out'EVENT AND ERSSUSP_out = '1' THEN + next_state <= ERS_SUSP; + ELSIF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN ERS_SUSP => + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + IF (PARAM_REGION = TRUE AND + SectorSuspend /= Address/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend/=Address/(SecSize+1)+30*b_act) THEN + ReturnSectorID(sect,Address); + pgm_page := Address / (PageSize+1); + IF PPB_bits(sect)='1' AND + DYB_bits(sect)='1' THEN + next_state <= ERS_SUSP_PG; + END IF; + END IF; + ELSIF (Instruct = DYBWR AND WEL = '1') THEN + next_state <= DYB_PG; + ELSIF Instruct = ERRS THEN + next_state <= SECTOR_ERS; + ELSE + next_state <= ERS_SUSP; + END IF; + ELSE + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= ERS_SUSP_PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = PGRS THEN + next_state <= ERS_SUSP_PG; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + + WHEN PASS_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PASS_UNLOCK => + IF falling_edge(PASSULCK_in) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_ERS => + IF falling_edge(PPBERASE_in) THEN + next_state <= IDLE; + END IF; + + WHEN AUTOBOOT_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PLB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN DYB_PG => + IF rising_edge(PDONE) THEN + IF ES = '1' THEN + next_state <= ERS_SUSP; + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN ASP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN NVDLR_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + END CASE; + END IF; + END IF; + + END PROCESS StateGen; + + ReadEnable: PROCESS (read_out) + BEGIN + oe_z <= rising_edge(read_out) AND PoweredUp = '1'; + + IF read_out'EVENT AND read_out = '0' AND PoweredUp = '1' THEN + oe <= TRUE, FALSE AFTER 1 ns; + END IF; + END PROCESS ReadEnable; + + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(write,current_state,start_autoboot,CSNeg_ipd, + HOLDNeg_pullup, Instruct, Address, WByte,change_addr, + PoweredUp, WPNeg_pullup, WDONE, PDONE, EDONE, + PRGSUSP_out,ERSSUSP_out, PASSACC_out, oe, oe_z) + + VARIABLE WData : WByteType:= (OTHERS => MaxData); + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + VARIABLE Addr : NATURAL; + VARIABLE Addr_tmp : NATURAL; + + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(647 downto 0); + + VARIABLE ExtendedID : NATURAL; + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + VARIABLE old_pass : std_logic_vector(63 downto 0); + VARIABLE new_pass : std_logic_vector(63 downto 0); + VARIABLE wr_cnt : NATURAL RANGE 0 TO 511; + --Data Learning Pattern Enable + VARIABLE dlp_act : BOOLEAN := FALSE; + + VARIABLE sect : NATURAL RANGE 0 TO SecNum64; + VARIABLE cnt : NATURAL RANGE 0 TO 512 := 0; + + VARIABLE sec_tmp : NATURAL RANGE 0 TO SecNum64; + + BEGIN + + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + IF Instruct'EVENT THEN + read_cnt := 0; + byte_cnt := 1; + fast_rd <= true; + dual <= false; + rd <= false; + any_read <= false; + END IF; + + IF PASSACC_out'EVENT AND PASSACC_out = '1' THEN + WIP := '0'; + PASSACC_in <= '0'; + END IF; + + IF rising_edge(PoweredUp) THEN + --the default condition after power-up + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + --The Configuration Register FREEZE bit is cleared. + FREEZE := '0'; + --The WEL bit is cleared. + WEL := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status Register are + --volatile and will be reset binary 111 after power-on reset + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --As shipped from the factory, all devices default ASP to the + --Persistent Protection mode, with all sectors unprotected, + --when power is applied. The device programmer or host system must + --then choose which sector protection method to use. + --For Persistent Protection mode, PPBLOCK defaults to "1" + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + DYB_bits := (OTHERS => '1'); + END IF; + + IF falling_edge(write) AND Instruct = RESET THEN + --The Configuration Register is set for Address mode + Bank_Addr_reg := (others => '0'); + --P_ERR bit is cleared + P_ERR := '0'; + --E_ERR bit is cleared + E_ERR := '0'; + --The WEL bit is cleared. + WEL := '0'; + --The WIP bit is cleared. + WIP := '0'; + --The ES bit is cleared. + ES := '0'; + --The PS bit is cleared. + PS := '0'; + + DummyBytes_act := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status + --Register are volatile and will be reseted after + --reset command + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF change_addr'EVENT THEN + read_addr := Address; + END IF; + + CASE current_state IS + WHEN IDLE => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + ASP_ProtSE := 0; + Sec_ProtSE := 0; + PARAM_REGION := false; + IF falling_edge(write) AND RdPswdProtMode = '1' THEN + IF Instruct = PASSU THEN + IF WIP = '0' THEN + PASSULCK_in <= '1'; + ELSE + REPORT "The PASSU command cannot be accepted"& + " any faster than once every 100us" + SEVERITY WARNING; + END IF; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + END IF; + IF BottomBoot = TRUE THEN + FOR J IN 31 DOWNTO 0 LOOP + IF (PPB_bits(J)='1' AND DYB_bits(J)='1') THEN + ASP_ProtSE := ASP_ProtSE + 1; + END IF; + IF (Sec_Prot(J)='0') THEN + Sec_ProtSE := Sec_ProtSE + 1; + END IF; + END LOOP; + ELSIF TopBoot = TRUE THEN + FOR J IN 541 DOWNTO 510 LOOP + IF (PPB_bits(J)='1' AND DYB_bits(J)='1') THEN + ASP_ProtSE := ASP_ProtSE + 1; + END IF; + IF (Sec_Prot(J)='0') THEN + Sec_ProtSE := Sec_ProtSE + 1; + END IF; + END LOOP; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + read_cnt := 0; + byte_cnt := 1; + IF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = WRDI THEN + WEL := '0'; + ELSIF Instruct = WRR AND WEL = '1' AND BAR_ACC = '0' THEN + IF (not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD ='0') OR QUAD ='1' THEN + -- can not execute if Hardware Protection Mode + -- is entered or if WEL bit is zero + + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (TBPARM='1' AND Config_reg1_in(2)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + P_ERR := '1'; + ELSE + WSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + END IF; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect)= '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF Instruct = OTPP AND WEL = '1' THEN + -- As long as the FREEZE bit remains cleared to a logic '0' + --the OTP address space is programmable. + IF FREEZE = '0' THEN + IF ((((Address >= 16#0010# AND Address <= 16#13#)OR + (Address >= 16#0020# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + PSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSIF (Address < 16#0010# OR (Address > 16#0013# AND + Address < 16#0020#) OR Address > 16#3FF# ) THEN + P_ERR := '1'; + WEL := '0'; + IF Address < 16#0020# THEN + ASSERT false + REPORT "Given address is in" & + "reserved address range" + SEVERITY warning; + ELSIF Address > 16#3FF# THEN + ASSERT false + REPORT "Given address is out of" & + "OTP address range" + SEVERITY warning; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = SE OR Instruct = SE4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 510) OR + (BottomBoot = TRUE AND sect > 31) THEN + SectorSuspend <= sect; + PARAM_REGION := FALSE; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (TopBoot = TRUE AND sect >= 510) OR + (BottomBoot = TRUE AND sect <= 31) THEN + IF Sec_ProtSE = 32 AND ASP_ProtSE = 32 THEN + --Sector erase command is applied to a 64 KB range + --that includes 4 KB sectors + IF TopBoot = TRUE THEN + SectorSuspend <= 510 + (541 - sect)/16; + ELSE + SectorSuspend <= sect/16; + END IF; + PARAM_REGION := TRUE; + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + END IF; + ELSIF (Instruct = P4E OR Instruct = P4E4) AND WEL = '1' THEN + ReturnSectorID(sect,Address); + IF UniformSec = TRUE OR + (TopBoot = TRUE AND sect < 510) OR + (BottomBoot = TRUE AND sect > 31) THEN + WEL := '0'; + ELSE + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + --A P4E instruction applied to a sector + --that has been Write Protected through the + --Block Protect Bits or ASP will not be + --executed and will set the E_ERR status + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + END IF; + ELSIF Instruct = BE AND WEL = '1' THEN + IF (BP0='0' AND BP1='0' AND BP2='0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + ELSE + --The Bulk Erase command will not set E_ERR if a + --protected sector is found during the command + --execution. + WEL := '0'; + END IF; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + REPORT "Password programming is not allowed" & + " in Password Protection Mode." + SEVERITY warning; + END IF; + ELSIF Instruct = PASSU AND WEL = '1' THEN + PASSULCK_in <= '1'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank Address" & + " Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + IF (P_ERR = '0' AND E_ERR = '0') THEN + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank " & + "Address Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = ASPP AND WEL = '1' THEN + IF not(ASPOTPFLAG) THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + WEL := '0'; + P_ERR := '1'; + REPORT "Once the Protection Mode is selected," & + "no further changes to the ASP register" & + "is allowed." + SEVERITY warning; + END IF; + ELSIF Instruct = ABWR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBP AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBERS AND WEL = '1' THEN + IF PPBOTP = '1' THEN + PPBERASE_in <= '1'; + WIP := '1'; + ELSE + E_ERR := '1'; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = WVDLR AND WEL = '1' THEN + VDLR_reg := VDLR_reg_in; + WEL := '0'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 OR + Instruct = RES OR Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES OR + DummyBytes_act='1') AND VDLR_reg/="00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRFR OR Instruct = DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + dlp_act := FALSE; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := read_addr/(SecSize+1); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + IF Mem(read_addr) /= -1 THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRDIOR OR Instruct = DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := read_addr/(SecSize+1); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF ((Instruct = DDRQIOR OR Instruct = DDRQIOR4) AND + QUAD = '1') THEN + IF EHP THEN + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := read_addr/(SecSize+1); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = OTPR THEN + IF (read_addr>=OTPLoAddr) AND + (read_addr<=OTPHiAddr) AND RdPswdProtMode = '0' THEN + --Read OTP Memory array + fast_rd <= true; + rd <= false; + data_out := to_slv(OTPMem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSIF (read_addr > OTPHiAddr) + OR RdPswdProtMode = '1' THEN + --OTP Read operation will not wrap to the + --starting address after the OTP address is at + --its maximum or Read Password Protection Mode + --is selected; instead, the data beyond the + --maximum OTP address will be undefined. + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF Instruct = REMS THEN + --Read Manufacturer and Device ID + IF read_addr MOD 2 = 0 THEN + data_out := to_slv(Manuf_ID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + data_out := to_slv(DeviceID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := 0; + END IF; + END IF; + ELSIF Instruct = RDID THEN + IF UniformSec THEN + ExtendedID := ExtendedID256; + ELSE + ExtendedID := ExtendedID64; + END IF; + ident_out := CFI_array_tmp; + IF read_cnt < 648 THEN + SOut_zd <= ident_out(647-read_cnt); + read_cnt := read_cnt + 1; + ELSE + --Continued shifting of output beyond the end of + --the defined ID-CFI address space will provide + --undefined data. + SOut_zd <= 'U'; + END IF; + ELSIF Instruct = RES THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + data_out := to_slv(ESignature,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + SOut_zd <= VDLR_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ABRD THEN + --Read AutoBoot register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= AutoBoot_reg(31-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 32 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ASPRD THEN + --Read ASP Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= ASP_reg(15-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 16 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PASSRD THEN + --Read Password Register + IF not (PWDMLB='0' AND PSTMLB='1') THEN + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Password_reg((8*byte_cnt-1)-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + byte_cnt := byte_cnt + 1; + IF byte_cnt = 9 THEN + byte_cnt := 1; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 64 THEN + read_cnt := 0; + END IF; + IF read_cnt = 0 THEN + ASSERT false + REPORT "Verification of password is not " & + " allowed in Password Protection Mode." + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = PLBRD THEN + --Read PPB Lock Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= PPBL(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + DYBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + + WHEN AUTOBOOT => + IF start_autoboot = '1' THEN + IF (oe) THEN + any_read <= true; + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF oe_z THEN + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + END IF; + + WHEN WRITE_SR => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF WDONE = '1' THEN + WIP := '0'; + WEL := '0'; + SRWD := Status_reg1_in(7);--MSB first + + IF LOCK='0' THEN + IF FREEZE='0' THEN + --The Freeze Bit, when set to 1, locks the current + --state of the BP2-0 bits in Status Register, + --the TBPROT and TBPARM bits in the Config Register + --As long as the FREEZE bit remains cleared to logic + --'0', the other bits of the Configuration register + --including FREEZE are writeable. + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + + BP_bits := BP2 & BP1 & BP0; + + IF TBPROT = '0' AND INITIAL_CONFIG = '0' THEN + TBPROT := Config_reg1_in(5); + END IF; + + IF (TBPARM = '0' AND INITIAL_CONFIG = '0' AND + TimingModel(16) = '0') THEN + TBPARM := Config_reg1_in(2); + change_TBPARM <= '1', '0' AFTER 1 ns; + END IF; + + change_BP <= '1', '0' AFTER 1 ns; + + LC1 := Config_reg1_in(7); + LC0 := Config_reg1_in(6); + QUAD := Config_reg1_in(1); + + IF FREEZE = '0' THEN + FREEZE := Config_reg1_in(0); + END IF; + + IF WRLOCKENABLE AND LOCK = '0' THEN + LOCK := Config_reg1_in(4); + WRLOCKENABLE <= false; + END IF; + + IF BPNV = '0' THEN + BPNV := Config_reg1_in(3); + END IF; + END IF; + END IF; + END IF; + + WHEN PAGE_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(PDONE) THEN + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + Mem(Addr + i - cnt) := -1; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + IF RES_TO_SUSP_MIN_TIME = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + ELSE + ASSERT FALSE + REPORT "Minimum for tPRS is not satisfied! " & + "PGSP command is ignored" + SEVERITY warning; + END IF; + END IF; + + WHEN PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + + IF pgm_page /= read_addr/(PageSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF pgm_page /= read_addr/(PageSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + + IF pgm_page /= read_addr/(PageSize+1) THEN + + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF falling_edge(write) THEN + IF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank Address" & + " Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank " & + "Address Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1)+30*b_act AND + pgm_page /= read_addr/(PageSize+1)) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1)+30*b_act AND + pgm_page /= read_addr/(PageSize+1)) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1)+30*b_act AND + pgm_page /= read_addr/(PageSize+1)) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF falling_edge(write) THEN + IF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank Address" & + " Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank " & + "Address Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN OTP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF Address + wr_cnt <= OTPHiAddr THEN + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := OTPMem(Addr + i); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + OTPMem(Addr + i) := -1; + END LOOP; + ELSE + ASSERT false + REPORT "Programming will reach over address limit"& + " of OTP array" + SEVERITY warning; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + OTPMem(Addr_tmp + i) := WData(i); + END LOOP; + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + END IF; + + WHEN SECTOR_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + ELSIF Instruct = ERSP AND ERSSUSP_in = '0' THEN + ESUSP <= '1', '0' AFTER 10 ns; + ERSSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + END IF; + + WHEN BULK_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(EDONE) THEN + FOR i IN 0 TO AddrRANGE LOOP + -- Sector ID calculation + IF TimingModel(16) = '0' THEN + sec_tmp := i / (SecSize64+1); + IF BottomBoot THEN + IF sec_tmp <= 1 THEN --4KB Sectors + sect := i/(SecSize4+1); + ELSE + sect := sec_tmp + 30; + END IF; + ELSIF TopBoot THEN + IF sec_tmp >= 510 THEN --4KB Sectors + sect := + 510+(i-(SecSize64+1)*510)/(SecSize4+1); + ELSE + sect := sec_tmp; + END IF; + END IF; + ELSE + sect := i/(SecSize256+1); + END IF; + IF PPB_bits(sect) = '1' AND DYB_bits(sect) = '1' THEN + Mem(i) := -1; + END IF; + END LOOP; + END IF; + + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO AddrRANGE LOOP + -- Sector ID calculation + IF TimingModel(16) = '0' THEN + sec_tmp := i / (SecSize64+1); + IF BottomBoot THEN + IF sec_tmp <= 1 THEN --4KB Sectors + sect := i/(SecSize4+1); + ELSE + sect := sec_tmp + 30; + END IF; + ELSIF TopBoot THEN + IF sec_tmp >= 510 THEN --4KB Sectors + sect := + 510+(i-(SecSize64+1)*510)/(SecSize4+1); + ELSE + sect := sec_tmp; + END IF; + END IF; + ELSE + sect := i/(SecSize256+1); + END IF; + IF PPB_bits(sect) = '1' AND DYB_bits(sect) = '1' THEN + Mem(i) := MaxData; + END IF; + END LOOP; + END IF; + + WHEN ERS_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF ERSSUSP_out = '1' THEN + ERSSUSP_in <= '0'; + --The Erase Suspend (ES) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --erase operation has been suspended. + ES := '1'; + --The WIP bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + ReturnSectorID(sect,Address); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + + IF (PARAM_REGION = TRUE AND + SectorSuspend /= read_addr/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend /= read_addr/(SecSize+1)+30*b_act) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (PARAM_REGION = TRUE AND + SectorSuspend /= read_addr/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend /= read_addr/(SecSize+1)+30*b_act) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (PARAM_REGION = TRUE AND + SectorSuspend /= read_addr/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend /= read_addr/(SecSize+1)+30*b_act) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + IF (PARAM_REGION = TRUE AND + SectorSuspend /= Address/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend/=Address/(SecSize+1)+30*b_act) THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + IF (PARAM_REGION = TRUE AND + SectorSuspend /= Address/(SecSize+1)) OR + (PARAM_REGION = FALSE AND + SectorSuspend/=Address/(SecSize+1)+30*b_act) THEN + ReturnSectorID(sect,Address); + Addr := Address; + pgm_page := Address/(PageSize+1); + IF (Sec_Prot(sect)='0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank Address" & + " Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + IF Bank_Addr_reg_in(1) = '1' THEN + REPORT "WARNING: Changing values of Bank " & + "Address Register BA25 is not allowed!!!" + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + ReturnSectorID(sect,Address); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = ERRS THEN + ERES <= '1', '0' AFTER 5 ns; + ES := '0'; + WIP := '1'; + IF BottomBoot = TRUE THEN + IF PARAM_REGION = TRUE THEN + Addr := SectorSuspend*(SecSize+1); + ELSE + Addr := (SectorSuspend-30)*(SecSize+1); + END IF; + ELSE + Addr := SectorSuspend*(SecSize+1); + END IF; + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + END IF; + + WHEN PASS_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + new_pass := Password_reg_in; + old_pass := Password_reg; + FOR j IN 0 TO 63 LOOP + IF old_pass(j) = '0' THEN + new_pass(j) := '0'; + END IF; + END LOOP; + + IF PDONE = '1' THEN + Password_reg := new_pass; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PASS_UNLOCK => + WIP := '1'; + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PASS_TEMP = Password_reg THEN + PASS_UNLOCKED <= TRUE; + ELSE + PASS_UNLOCKED <= FALSE; + END IF; + + IF PASSULCK_out = '1' THEN + IF PASS_UNLOCKED AND PWDMLB = '0' THEN + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + WIP := '0'; + ELSE + P_ERR := '1'; + REPORT "Incorrect Password!" + SEVERITY warning; + PASSACC_in <= '1'; + END IF; + WEL := '0'; + PASSULCK_in <= '0'; + END IF; + + WHEN PPB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF PPB_LOCK /= '0' THEN + PPB_bits(sect):= '0'; + WIP := '0'; + WEL := '0'; + ELSE + P_ERR := '0'; + WIP := '0'; + WEL := '0'; + END IF; + END IF; + + WHEN PPB_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PPBERASE_out = '1' THEN + IF PPB_LOCK /= '0' AND PPBOTP = '1' THEN + PPB_bits:= (OTHERS => '1'); + ELSE + E_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + PPBERASE_in <= '0'; + END IF; + + WHEN AUTOBOOT_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + AutoBoot_reg := AutoBoot_reg_in; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PLB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN DYB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + DYBAR := DYBAR_in; + IF DYBAR = "11111111" THEN + DYB_bits(sect):= '1'; + ELSIF DYBAR = "00000000" THEN + DYB_bits(sect):= '0'; + ELSE + P_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN ASP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + + IF (RPME = '0' AND ASP_reg_in(5) = '1') THEN + P_ERR := '1'; + REPORT "RPME bit is allready programmed" + SEVERITY warning; + ELSE + RPME := ASP_reg_in(5); + END IF; + + IF (PPBOTP = '0' AND ASP_reg_in(3) ='1') THEN + P_ERR := '1'; + REPORT "PPBOTP bit is allready programmed" + SEVERITY warning; + ELSE + PPBOTP := ASP_reg_in(3); + END IF; + + IF (PWDMLB = '1' AND PSTMLB = '1') THEN + IF (ASP_reg_in(2) = '0' AND ASP_reg_in(1) = '0') THEN + REPORT "ASPR[2:1] = 00 Illegal condition" + SEVERITY warning; + P_ERR := '1'; + ELSE + IF (ASP_reg_in(2) /= '1' OR + ASP_reg_in(1) /= '1') THEN + ASPOTPFLAG <= TRUE; + END IF; + PWDMLB := ASP_reg_in(2); + PSTMLB := ASP_reg_in(1); + END IF; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN NVDLR_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF NVDLR_reg = "00000000" THEN + NVDLR_reg :=NVDLR_reg_in; + VDLR_reg := NVDLR_reg_in; + WIP := '0'; + WEL := '0'; + ELSE + WIP := '0'; + WEL := '0'; + P_ERR := '1'; + REPORT "NVDLR is allready programmed" + SEVERITY warning; + END IF; + END IF; + + WHEN RESET_STATE => + --the default condition hardware reset + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --Resets the Status register 1 + P_ERR := '0'; + E_ERR := '0'; + WEL := '0'; + WIP := '0'; + --Resets the Status register 2 + ES := '0'; + PS := '0'; + --Resets the Configuration register 1 + FREEZE := '0'; + --On reset cycles the data pattern reverts back + --to what is in the NVDLR + VDLR_reg := NVDLR_reg; + dlp_act := FALSE; + --Loads the Program Buffer with all ones + WData := (OTHERS => MaxData); + + IF PWDMLB = '0' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + ELSE + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + END PROCESS Functional; + + --------------------------------------------------------------------------- + -- CFI Process + --------------------------------------------------------------------------- + CFIPreload: PROCESS + + BEGIN + ------------------------------------------------------------------------ + --CFI array data + ------------------------------------------------------------------------ + -- Manufacturer and Device ID + CFI_array(16#00#) := 16#01#; + CFI_array(16#01#) := 16#02#; + CFI_array(16#02#) := 16#19#; + CFI_array(16#03#) := 16#00#; + IF TimingModel(16) = '0' THEN + CFI_array(16#04#) := 16#01#;--256B page + ELSIF TimingModel(16) = '1' THEN + CFI_array(16#04#) := 16#00#;--512B page + END IF; + CFI_array(16#05#) := 16#80#; + + CFI_array(16#06#) := 16#00#; + CFI_array(16#07#) := 16#00#; + CFI_array(16#08#) := 16#00#; + CFI_array(16#09#) := 16#00#; + CFI_array(16#0A#) := 16#00#; + CFI_array(16#0B#) := 16#00#; + CFI_array(16#0C#) := 16#00#; + CFI_array(16#0D#) := 16#00#; + CFI_array(16#0E#) := 16#00#; + CFI_array(16#0F#) := 16#00#; + --CFI Query Identification String + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#53#; + CFI_array(16#18#) := 16#46#; + CFI_array(16#19#) := 16#51#; + CFI_array(16#1A#) := 16#00#; + --CFI system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#06#; + IF TimingModel(16) = '0' THEN + CFI_array(16#20#) := 16#08#;--256B page + CFI_array(16#21#) := 16#08#;--64KB + ELSIF TimingModel(16) = '1' THEN + CFI_array(16#20#) := 16#09#;--512B page + CFI_array(16#21#) := 16#09#;--256KB + END IF; + + CFI_array(16#22#) := 16#10#; + CFI_array(16#23#) := 16#02#; + CFI_array(16#24#) := 16#02#; + CFI_array(16#25#) := 16#03#; + CFI_array(16#26#) := 16#03#; + --Device Geometry Definition + CFI_array(16#27#) := 16#19#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#01#; + IF TimingModel(16) = '0' THEN + CFI_array(16#2A#) := 16#08#;--256B page + ELSIF TimingModel(16) = '1' THEN + CFI_array(16#2A#) := 16#09#;--512B page + END IF; + CFI_array(16#2B#) := 16#00#; + IF TimingModel(16) = '1' THEN + CFI_array(16#2C#) := 16#01#; --Uniform Device + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#04#; + CFI_array(16#31#) := 16#FF#; + CFI_array(16#32#) := 16#FF#; + CFI_array(16#33#) := 16#FF#; + CFI_array(16#34#) := 16#FF#; + ELSE + CFI_array(16#2C#) := 16#02#; --Boot device + IF TBPARM = '1' THEN + CFI_array(16#2D#) := 16#FD#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#1F#; + CFI_array(16#32#) := 16#01#; + CFI_array(16#33#) := 16#10#; + CFI_array(16#34#) := 16#00#; + ELSE + CFI_array(16#2D#) := 16#1F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#10#; + CFI_array(16#30#) := 16#00#; + CFI_array(16#31#) := 16#FD#; + CFI_array(16#32#) := 16#01#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#01#; + END IF; + END IF; + CFI_array(16#35#) := 16#FF#; + CFI_array(16#36#) := 16#FF#; + CFI_array(16#37#) := 16#FF#; + CFI_array(16#38#) := 16#FF#; + CFI_array(16#39#) := 16#FF#; + CFI_array(16#3A#) := 16#FF#; + CFI_array(16#3B#) := 16#FF#; + CFI_array(16#3C#) := 16#FF#; + CFI_array(16#3D#) := 16#FF#; + CFI_array(16#3E#) := 16#FF#; + CFI_array(16#3F#) := 16#FF#; + --CFI Primary Vendor-Specific Extended Query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#21#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#00#; + CFI_array(16#49#) := 16#08#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#01#; + CFI_array(16#4C#) := 16#00#; + CFI_array(16#4D#) := 16#00#; + CFI_array(16#4E#) := 16#00#; + CFI_array(16#4F#) := 16#07#; + CFI_array(16#50#) := 16#01#; + + CFI_array_tmp :=to_slv(CFI_array(16#00#), 8) & + to_slv(CFI_array(16#01#), 8) & + to_slv(CFI_array(16#02#), 8) & + to_slv(CFI_array(16#03#), 8) & + to_slv(CFI_array(16#04#), 8) & + to_slv(CFI_array(16#05#), 8) & + to_slv(CFI_array(16#06#), 8) & + to_slv(CFI_array(16#07#), 8) & + to_slv(CFI_array(16#08#), 8) & + to_slv(CFI_array(16#09#), 8) & + to_slv(CFI_array(16#0A#), 8) & + to_slv(CFI_array(16#0B#), 8) & + to_slv(CFI_array(16#0C#), 8) & + to_slv(CFI_array(16#0D#), 8) & + to_slv(CFI_array(16#0E#), 8) & + to_slv(CFI_array(16#0F#), 8) & + to_slv(CFI_array(16#10#), 8) & + to_slv(CFI_array(16#11#), 8) & + to_slv(CFI_array(16#12#), 8) & + to_slv(CFI_array(16#13#), 8) & + to_slv(CFI_array(16#14#), 8) & + to_slv(CFI_array(16#15#), 8) & + to_slv(CFI_array(16#16#), 8) & + to_slv(CFI_array(16#17#), 8) & + to_slv(CFI_array(16#18#), 8) & + to_slv(CFI_array(16#19#), 8) & + to_slv(CFI_array(16#1A#), 8) & + to_slv(CFI_array(16#1B#), 8) & + to_slv(CFI_array(16#1C#), 8) & + to_slv(CFI_array(16#1D#), 8) & + to_slv(CFI_array(16#1E#), 8) & + to_slv(CFI_array(16#1F#), 8) & + to_slv(CFI_array(16#20#), 8) & + to_slv(CFI_array(16#21#), 8) & + to_slv(CFI_array(16#22#), 8) & + to_slv(CFI_array(16#23#), 8) & + to_slv(CFI_array(16#24#), 8) & + to_slv(CFI_array(16#25#), 8) & + to_slv(CFI_array(16#26#), 8) & + to_slv(CFI_array(16#27#), 8) & + to_slv(CFI_array(16#28#), 8) & + to_slv(CFI_array(16#29#), 8) & + to_slv(CFI_array(16#2A#), 8) & + to_slv(CFI_array(16#2B#), 8) & + to_slv(CFI_array(16#2C#), 8) & + to_slv(CFI_array(16#2D#), 8) & + to_slv(CFI_array(16#2E#), 8) & + to_slv(CFI_array(16#2F#), 8) & + to_slv(CFI_array(16#30#), 8) & + to_slv(CFI_array(16#31#), 8) & + to_slv(CFI_array(16#32#), 8) & + to_slv(CFI_array(16#33#), 8) & + to_slv(CFI_array(16#34#), 8) & + to_slv(CFI_array(16#35#), 8) & + to_slv(CFI_array(16#36#), 8) & + to_slv(CFI_array(16#37#), 8) & + to_slv(CFI_array(16#38#), 8) & + to_slv(CFI_array(16#39#), 8) & + to_slv(CFI_array(16#3A#), 8) & + to_slv(CFI_array(16#3B#), 8) & + to_slv(CFI_array(16#3C#), 8) & + to_slv(CFI_array(16#3D#), 8) & + to_slv(CFI_array(16#3E#), 8) & + to_slv(CFI_array(16#3F#), 8) & + to_slv(CFI_array(16#40#), 8) & + to_slv(CFI_array(16#41#), 8) & + to_slv(CFI_array(16#42#), 8) & + to_slv(CFI_array(16#43#), 8) & + to_slv(CFI_array(16#44#), 8) & + to_slv(CFI_array(16#45#), 8) & + to_slv(CFI_array(16#46#), 8) & + to_slv(CFI_array(16#47#), 8) & + to_slv(CFI_array(16#48#), 8) & + to_slv(CFI_array(16#49#), 8) & + to_slv(CFI_array(16#4A#), 8) & + to_slv(CFI_array(16#4B#), 8) & + to_slv(CFI_array(16#4C#), 8) & + to_slv(CFI_array(16#4D#), 8) & + to_slv(CFI_array(16#4E#), 8) & + to_slv(CFI_array(16#4F#), 8) & + to_slv(CFI_array(16#50#), 8); + + WAIT; + + END PROCESS CFIPreload; + + AspRegInit: PROCESS(ASP_INIT) + BEGIN + IF ASP_INIT = 0 THEN + ASP_reg := to_slv(16#FE4F#,16); + ELSE + ASP_reg := to_slv(16#FE7F#,16); + END IF; + END PROCESS AspRegInit; + + TopBottom: PROCESS(change_TBPARM, PoweredUp) + BEGIN + IF (TimingModel(16)= '0') THEN + IF TBPARM = '0' THEN + BottomBoot <= TRUE; + b_act := 1; + ELSE + TopBoot <= TRUE; + BottomBoot <= FALSE; + b_act := 0; + END IF; + END IF; + END PROCESS TopBottom; + + Protect : PROCESS(change_BP) + BEGIN + IF rising_edge(change_BP) THEN + + CASE BP_bits IS + WHEN "000" => + Sec_Prot := (OTHERS => '0'); + WHEN "001" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*63/64+30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*63/64 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/64 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/64 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "010" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*31/32+30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*31/32+30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/32 + 30*b_act - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/32 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "011" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*15/16+30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*15/16 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/16 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/16 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "100" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*7/8 + 30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*7/8 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/8 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/8 + 30*b_act) + := (OTHERS => '0'); + END IF; + WHEN "101" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)*3/4 + 30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)*3/4 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/4 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/4 + 30*b_act) + := (OTHERS => '0'); + END IF; + + WHEN "110" => + IF TBPROT = '0' THEN + Sec_Prot(SecNumMax downto ((SecNum+1)/2 + 30*b_act)) + := (OTHERS => '1'); + Sec_Prot(((SecNum+1)/2 + 30*b_act) - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/2 + 30*b_act - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNumMax downto (SecNum+1)/2 + 30*b_act) + := (OTHERS => '0'); + END IF; + + WHEN OTHERS => + Sec_Prot := (OTHERS => '1'); + END CASE; + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNeg_pullup) + BEGIN + IF (HOLDNeg_pullup = '0' AND QUAD /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + RST_PULL_UP : PROCESS(RSTNeg) + BEGIN + IF (RSTNeg = 'Z') THEN + RSTNeg_pullup <= '1'; + ELSE + RSTNeg_pullup <= RSTNeg; + END IF; + END PROCESS RST_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + MemPreload : PROCESS + + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE otp_file : text is otp_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0; + VARIABLE otp_ind : NATURAL RANGE 16#000# TO 16#3FF# := 16#000#; + VARIABLE buf : line; + + BEGIN + --------------------------------------------------------------------------- + --s25fl256s memory preload file format +----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaaaaa - stands for address + -- dd -
is byte to be written at Mem(aaaaaa++) + -- (aaaaaa is incremented at every load) + -- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (mem_file_name /= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF ind > AddrRANGE THEN + ASSERT false + REPORT "Given preload address is out of" & + "memory address range" + SEVERITY warning; + ELSE + ind := h(buf(2 to 8)); --address + END IF; + ELSE + Mem(ind) := h(buf(1 to 2)); + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --------------------------------------------------------------------------- + --s25fl256s_otp memory preload file format + --------------------------------------------------------------------------- + -- / - comment + -- @aaa - stands for address + -- dd -
is byte to be written at OTPMem(aaa++) + -- (aaa is incremented at every load) + -- only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (otp_file_name /= "none" AND UserPreload) THEN + otp_ind := 16#000#; + OTPMem := (OTHERS => MaxData); + WHILE (not ENDFILE (otp_file)) LOOP + READLINE (otp_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF otp_ind > 16#3FF# OR otp_ind < 16#000# THEN + ASSERT false + REPORT "Given preload address is out of" & + "OTP address range" + SEVERITY warning; + ELSE + otp_ind := h(buf(2 to 4)); --address + END IF; + ELSE + OTPMem(otp_ind) := h(buf(1 to 2)); + otp_ind := otp_ind + 1; + END IF; + END LOOP; + END IF; + + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + + WAIT; + END PROCESS MemPreload; + + ---------------------------------------------------------------------------- + -- Path Delay Section + ---------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "SO", + OutTemp => SOut_z, + Mode => VitalTransport, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => (ddr OR fast_rd)), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => QUAD = '0') + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + Mode => VitalTransport, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => dual AND ddr), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => dual AND QUAD = '0') + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + Mode => VitalTransport, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + HOLDNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + Mode => VitalTransport, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + WPNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + END BLOCK behavior; +END vhdl_behavioral; \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_ver.ftm b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_ver.ftm new file mode 100644 index 0000000..341b37c --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_ver.ftm @@ -0,0 +1,725 @@ + +FMF Timing for s25fl256s Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 09 Nov 27 Initial release + V1.1 V.Mancev 10 Oct 20 Latest datasheet aligned + V1.2 B.Colakovic 11 June 29 Latest datasheet aligned + V1.3 V.Mancev 11 Nov 17 Time tHO is changed to 1 ns + +1ns +s25fl256s + +S25FL256SAGMFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for VIO=VCC=2.7V to 3.6V, CL=30pF + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL256SAGMFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL256SAGMFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL256SDPMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for Vcc range VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (5)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (4)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (7.5)) + (WIDTH (COND dual_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL256SDPMFIR00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR01_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR11_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI000_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI001_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI003_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI010_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI011_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI013_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI200_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI203_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI210_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI213_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI300_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI303_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI310_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI313_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for Vcc range VCC=2.7V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (5)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (4)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (7.5)) + (WIDTH (COND dual_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND ddrd SCK) (15)) +) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_vhd.ftm b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_vhd.ftm new file mode 100644 index 0000000..fa35d87 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/model/s25fl256s_vhd.ftm @@ -0,0 +1,781 @@ + +FMF Timing for s25fl256s Parts + + +version: | author: | mod date: | changes made: + V1.0 V.Mancev 09 Nov 26 Initial release + V1.1 V.Mancev 11 July 04 Latest datasheet aligned + V1.2 V.Mancev 11 Nov 17 Time tHO is changed to 1 ns + +1ns +s25fl256s + +S25FL256SAGMFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(33e9:66e9:330e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL256SAGMFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR01_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV000_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV001_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV003_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV200_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV203_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV300_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV303_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL00_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL03_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(33e9:66e9:330e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL256SAGMFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFIR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR01_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGMFVR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV000_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV001_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV003_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGNFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHI313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHID13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV200_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV203_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV300_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV303_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHV313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHVD13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIY13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIZ13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIS13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIT13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIK13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL00_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL03_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SAGBHIL13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(33e9:66e9:330e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL256SDPMFIR00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR01_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI000_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI001_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI003_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI200_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI203_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI300_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI303_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID00_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID03_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (10:12:14) (10:12:14) (10:12:14) (10:12:14)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (5)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (5)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (4)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (5)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (7.5)) + (WIDTH (COND dual (negedge SCK)) (7.5)) + (WIDTH (COND fast (negedge SCK)) (7.5)) + (WIDTH (COND fast (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(33e9:66e9:330e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL256SDPMFIR00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR01_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR11_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPMFIR13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI000_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI001_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI003_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI010_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI011_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPNFI013_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI200_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI203_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI210_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI213_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI300_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI303_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI310_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHI313_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHIC13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID00_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID03_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL256SDPBHID13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (10:12:14) (10:12:14) (10:12:14) (10:12:14)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (5)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (5)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (4)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (5)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (7.5)) + (WIDTH (COND dual (negedge SCK)) (7.5)) + (WIDTH (COND fast (negedge SCK)) (7.5)) + (WIDTH (COND fast (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP256) (DELAY (ABSOLUTE (DEVICE(183e3:366e3:550e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP512) (DELAY (ABSOLUTE (DEVICE(250e3:500e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(133e3:266e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE64) (DELAY (ABSOLUTE (DEVICE(217e6:434e6:650e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE256) (DELAY (ABSOLUTE (DEVICE(625e6:1250e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(33e9:66e9:330e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl256s/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl256s/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl256s/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl256s/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/flash/serial/S25fl512s/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl512s/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl512s/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl512s/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 vital-amd-serial-s25fl-REL-s25fl512s-2009-11-16-1.tar.gz +# Release Date (DD/MM/YYYY) => 16/11/2009 +# Release Version => 1.0 + +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2009-11-19-2.tar.gz +# Release Date (DD/MM/YYYY) => 19/11/2009 +# Release Version => 1.1 + +# Corrections: +# 1.Negative tests which show how model behaves when reset pulse +# width is less than specified and when write and erase operations are interrupted . +# with reset signal are interrupted with reset signal are added. +# 2.Implementation of Continuous Read Mode +# 3.After 8 clock cycles for instruction, first address bit is latched on the next +# rising edge of clock. + +# Files modified +-s25fl512s.vhd +-testbench_s25fl512s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl512s.ftm +-s25fl512s_vhdl.sdf +-s25fl512s.v +-testbench_s25fl512s_verilog.vhd +-s25fl512s.ftmv +-s25fl512s_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-03-04-1.tar.gz +# Release Date (DD/MM/YYYY) => 04/03/2010 +# Release Version => 1.2 + +# Corrections: +# 1.Array variable WByte in sensitivity list is replaced with signal WB_flag to enable +# compilation in NCSim +# 2.addr_cnt for second read in high performance read continuous mode can change its +# value only when CSNeg = '0' + +# Files modified +-s25fl512s.v +-s25fl512s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-04-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/04/2010 +# Release Version => 1.3 + +# Corrections: +# 1.HOLD mode corrected +# 2.Condition for PP operation corrected + +# Files modified +-s25fl512s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-05-21-1.tar.gz +# Release Date (DD/MM/YYYY) => 21/05/2010 +# Release Version => 1.4 + +# Corrections: +# 1.SRWD bit assignment is corrected +# 2.Condition for WRR command in write_cycle_decode section is corrected +# 3.Blocking assignments for signals WSTART and PSTART are replaced with +# nonblocking assignments +# 4.Conditions in Page Program section are fixed +# + +# Files modified +-s25fl512s.v +-s25fl512s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-05-25-1.tar.gz +# Release Date (DD/MM/YYYY) => 25/05/2010 +# Release Version => 1.5 + +# Corrections: +# 1. Timing control sections for Program and Erase operation are changed +# 2. Conditions in Page Program section are fixed +# + +# Files modified +-s25fl512s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-06-03-2.tar.gz +# Release Date (DD/MM/YYYY) => 03/06/2010 +# Release Version => 1.6 + +# Corrections: +# 1. bus_cycle_state section for PGSP command is fixed +# + +# Files modified +-s25fl512s.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-07-28-1.tar.gz +# Release Date (DD/MM/YYYY) => 28/07/2010 +# Release Version => 1.7 + +# Corrections: +# 1. During the QUAD mode HOLD# input is not monitored for its normal function +# 2. Internal pull-up resistors for HOLD# and WP# inputs are implemented + +# Files modified +-s25fl512s.v +-s25fl512s.vhd +########################################## +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-08-24-1.tar.gz +# Release Date (DD/MM/YYYY) => 24/08/2010 +# Release Version => 1.8 + +# Corrections: +# 1. All redundant signals are removed from BusCycle process + +# Files modified +-s25fl512s.v +-s25fl512s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-10-14-1.tar.gz +# Release Date (DD/MM/YYYY) => 14/10/2010 +# Release Version => 1.9 + +# Corrections: +# 1. Latest datasheet aligned (VERILOG files only) + +# Files modified +-spansion_tc_pkg.vhd +-s25fl512s.v +-testbench_s25fl512s_verilog.vhd +-s25fl512s.ftmv +-s25fl512s_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-10-20-1.tar.gz +# Release Date (DD/MM/YYYY) => 20/10/2010 +# Release Version => 2.0 + +# Corrections: +# 1. Latest datasheet aligned (VHDL files added) + +# Files modified +-s25fl512s.vhd +-testbench_s25fl512s_vhdl.vhd +-s25fl512s.ftm +-s25fl512s_vhdl.sdf +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-10-22-2.tar.gz +# Release Date (DD/MM/YYYY) => 22/10/2010 +# Release Version => 2.1 + +# Corrections: +# 1. Latest datasheet aligned (VHDL files added) + +# Files modified +-s25fl512s.vhd +-testbench_s25fl512s_vhdl.vhd +-s25fl512s.ftm +-s25fl512s_verilog.sdf +-s25fl512s.v +-s25fl512s.sv +-testbench_s25fl512s_verilog.vhd +-s25fl512s.ftmv +-s25fl512s_vhdl.sdf +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-11-05-1.tar.gz +# Release Date (DD/MM/YYYY) => 05/11/2010 +# Release Version => 2.2 + +# Corrections: +# 1. Latest datasheet aligned + +# Files modified +-spansion_tc_pkg.vhd +-s25fl512s.vhd +-testbench_s25fl512s_vhdl.vhd +-s25fl512s.v +-s25fl512s.sv +-testbench_s25fl512s_verilog.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Ranko Prokopovic + r-prokopovic@hdl-dh.com + Hana Dimitrijevic + h-dimitrijevic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2010-11-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/11/2010 +# Release Version => 2.3 + +# Corrections: +# 1. QUAD Program operation during Erase Suspend is added +# 2. Warning for Resume to Suspend time is added +# 3. During Erase Suspend, after Program operation is completed, WEL bit is cleared +# 4. Implementation of Software Reset is Changed +# 5. ADDRHILO_PG procedure corrected + +# Files modified +-spansion_tc_pkg.vhd +-s25fl512s.v +-s25fl512s.vhd +########################################## +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2011-04-18-1.tar.gz +# Release Date (DD/MM/YYYY) => 18/04/2011 +# Release Version => 2.4 + +# Corrections: +- corrected timing for internal signal rising_edge_CSNeg_ipd + +# Files modified +-s25fl512s.v +-s25fl512s.sv +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2011-07-11-1.tar.gz +# Release Date (DD/MM/YYYY) => 11/07/2011 +# Release Version => 2.5 + +# Corrections: +- Latest Datasheet Aligned + +# Files modified +-s25fl512s.v +-s25fl512s.vhd +-testbench_s25fl512s_verilog.vhd +-testbench_s25fl512s_vhdl.vhd +-spansion_tc_pkg.vhd +-s25fl512s.ftmv +-s25fl512s.ftm +-s25fl512s_verilog.sdf +-s25fl512s_vhdl.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2011-07-15-2.tar.gz +# Release Date (DD/MM/YYYY) => 15/07/2011 +# Release Version => 2.6 + +# Corrections: +- Optimization issue is fixed +- Timingmodel is corrected + +# Files modified +-s25fl512s.v +-s25fl512s.sv +-testbench_s25fl512s_vhdl.vhd +-testbench_s25fl512s_verilog.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com + Branislav Colakovic + b-colakovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2011-07-22-1.tar.gz +# Release Date (DD/MM/YYYY) => 22/07/2011 +# Release Version => 2.7 + +# Corrections: +- Timing check issue is fixed +- Correction for P4E and P4E4 instructions + +# Files modified +-s25fl512s.v +-s25fl512s.sv +-s25fl512s.vhd +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2011-11-18-1.tar.gz +# Release Date (DD/MM/YYYY) => 18/11/2011 +# Release Version => 2.8 + +# Corrections: +- Time tHO is changed to 1 ns (customer's request) +- Setting of Device protection mode is modified (customer's request) +- BRWR instruction is corrected + +# Files modified +-s25fl512s.v +-s25fl512s.vhd +-testbench_s25fl512s_verilog.vhd +-testbench_s25fl512s_vhdl.vhd +-s25fl512s.ftmv +-s25fl512s.ftm +-s25fl512s_verilog.sdf +-s25fl512s_vhdl.sdf +########################################## +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl512s-2012-06-02-1.tar.gz +# Release Date (DD/MM/YYYY) => 02/06/2012 +# Release Version => 2.9 + +# Corrections: +- OPP instruction is allowed in previously programmed page + +# Files modified +-s25fl512s.v +-s25fl512s.sv +-s25fl512s.vhd +-testbench_s25fl512s_verilog.vhd +-testbench_s25fl512s_vhdl.vhd +-spansion_tc_pkg.vhd + +########################################## \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.sv b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.sv new file mode 100644 index 0000000..1e25c19 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.sv @@ -0,0 +1,8080 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl512s.sv +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2011 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 V.Mancev 19 Nov 09 Initial +// R.Prokopovic +// V1.1 V.Mancev 04 Mar 10 addr_cnt for second read in +// high performance read continuous +// mode can change its value only +// when CSNeg = '0' +// V1.2 V.Mancev 23 Mar 10 During read operations read_out +// signal changes its value in +// shorter interval +// V1.3 V.Mancev 12 Apr 10 HOLD mode corrected +// Condition for PP operation +// corrected +// V1.4 V.Mancev 20 May 10 SRWD bit assignment is corrected +// Condition for WRR command in +// write_cycle _decode section is +// corrected +// Blocking assignments for signals +// WSTART and PSTART are replaced +// with nonblocking assignments +// Conditions in Page Program +// section are fixed +// V1.5 V.Mancev 25 May 10 Conditions in programming +// sections are fixed +// Timing control sections for +// Program and Erase operation are +// changed +// V1.6 V.Mancev 03 June 10 bus_cycle_state section for +// PGSP command is fixed +// V1.7 V.Mancev 28 July 10 During the QUAD mode HOLD# input +// is not monitored for its normal +// function +// write cycle decode section is +// changed +// V1.8 B.Colakovic 24 Aug 10 All redundant signals are +// removed from BusCycle process +// V1.9 V.Mancev 05 Nov 10 Latest datasheet aligned +// B.Colakovic +// V2.0 H.Dimitrijevic 15 Nov 10 QUAD Program operation during +// Erase Suspend is added. +// Warning for Resume to Suspend +// time is added. +// During Erase Suspend, after +// Program operation is completed, +// WEL bit is cleared. +// Implemetation of Software Reset +// is Changed. +// V2.1 S.Petrovic 18 Apr 11 Corrected timing in always block +// that generates +// rising_edge_CSNeg_ipd +// V2.2 V.Mancev 11 July 11 Latest datasheet aligned +// B.Colakovic +// V2.3 B.Colakovic 15 July 11 Optimization issue is fixed +// V2.4 V.Mancev 22 July 11 Timing check issue is fixed +// B.Colakovic +// V2.5 V. Mancev 18 Nov 11 Time tHO is changed to 1 ns +// (customer's request) +// BRWR instruction is corrected +// V2.6 S.Petrovic 02 Jun 12 QPP Instruction is allowed on +// previously programmed page +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL512S +// +// Description: 512 Megabit Serial Flash Memory +// +////////////////////////////////////////////////////////////////////////////// +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// A device ordering (trim) option determines whether a feature is enabled +// or not, or provide relevant parameters: +// -15th character in TimingModel determines if enhanced high +// performance option is available +// (0,2,3,R,A,B,C,D) EHPLC +// (Y,Z,S,T,K,L) Security EHPLC +// (4,6,7,8,9,Q) HPLC +// -15th character in TimingModel determines if RESET# input +// is available +// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +// state,inside the package. +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl512s + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + RSTNeg , + WPNeg , + HOLDNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + + inout SI ; + inout SO ; + + input SCK ; + input CSNeg ; + input RSTNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire RSTNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire RSTNeg_in ; + //Internal pull-up + assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd; + + // internal delays + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg WRR_in ; + reg WRR_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg PU_in ; + reg PU_out ; + reg RST_in ; + reg RST_out ; + reg PPBERASE_in ; + reg PPBERASE_out; + reg PASSULCK_in ; + reg PASSULCK_out; + reg PASSACC_in ; + reg PASSACC_out; + + // event control registers + reg PRGSUSP_out_event; + reg ERSSUSP_out_event; + reg Reseted_event; + reg SCK_ipd_event; + reg next_state_event; + + reg rising_edge_PoweredUp; + reg rising_edge_Reseted; + reg rising_edge_PASSULCK_in; + reg rising_edge_RES_out; + reg rising_edge_PSTART; + reg rising_edge_WSTART; + reg rising_edge_ESTART; + reg rising_edge_RSTNeg; + reg rising_edge_RST; + reg falling_edge_RSTNeg; + reg falling_edge_RST; + reg rising_edge_RST_out; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg RST ; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl512s.mem"; + parameter otp_file_name = "s25fl512sOTP.mem";//"none"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl512s"; + parameter MaxData = 255; + parameter MemSize = 28'h3FFFFFF; + parameter SecSize = 20'h3FFFF; + parameter SecNum = 255; + parameter PageNum = 17'h1FFFF; + parameter AddrRANGE = 28'h3FFFFFF; + parameter HiAddrBit = 31; + parameter OTPSize = 1023; + parameter OTPLoAddr = 12'h000; + parameter OTPHiAddr = 12'h3FF; + parameter BYTE = 8; + + // Manufacturer Identification + parameter Manuf_ID = 8'h01; + parameter DeviceID = 8'h19; + // Electronic Signature + parameter ESignature = 8'h19; + // Device ID + //Manufacturer Identification && Memory Type && Memory Capacity + parameter Jedec_ID = 8'h01; + parameter DeviceID1 = 8'h02; + parameter DeviceID2 = 8'h20; + parameter ExtendedBytes = 8'h4D; + parameter ExtendedID = 8'h00; + parameter DieRev = 8'h00; + parameter MaskRev = 8'h00; + + integer PageSize = 511; + + integer EHP; //Enhanced High Performance Mode active + + integer BAR_ACC = 0; //Bank Register Access active + + //varaibles to resolve architecture used + reg [24*8-1:0] tmp_timing;//stores copy of TimingModel + reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode + integer found = 1'b0; + + // If speedsimulation is needed uncomment following line + +// `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; + + reg RES_TO_SUSP_MIN_TIME; + reg RES_TO_SUSP_TYP_TIME; + + reg WDONE ; + reg WSTART ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + + reg Reseted ; + + // Lock Bit is enabled for customer programming + reg WRLOCKENABLE = 1'b1; + // Flag that mark if ASP Register is allready programmed + reg ASPOTPFLAG = 1'b0; + + //Flag for Password unlock command + reg PASS_UNLOCKED = 1'b0; + reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF; + + reg QUADRD = 1'b0; + reg INITIAL_CONFIG = 1'b0; + reg CHECK_FREQ = 1'b0; + + // Programming buffer + integer WByte[0:511]; + // CFI array + integer CFI_array[8'h00:8'h50]; + // OTP Memory Array + integer OTPMem[OTPLoAddr:OTPHiAddr]; + // Flash Memory Array + + // Registers + // VDLR Register + reg[7:0] VDLR_reg = 8'h00; + reg[7:0] VDLR_reg_in = 8'h00; + // NVDLR Register + reg[7:0] NVDLR_reg = 8'h00; + reg[7:0] NVDLR_reg_in = 8'h00; + reg dlp_act = 1'b0; + + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRWD ; + wire P_ERR; + wire E_ERR; + wire [2:0]BP; + wire WEL; + wire WIP; + assign SRWD = Status_reg1[7]; + assign P_ERR = Status_reg1[6]; + assign E_ERR = Status_reg1[5]; + assign BP = Status_reg1[4:2]; + assign WEL = Status_reg1[1]; + assign WIP = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire ES ; + wire PS ; + assign ES = Status_reg2[1]; + assign PS = Status_reg2[0]; + + // Configuration Register 1 + reg[7:0] Config_reg1 = 8'h00; + reg[7:0] Config_reg1_in = 8'h00; + + wire LC1 ; + wire LC0 ; + wire TBPROT ; + wire LOCK ; + wire BPNV ; + wire QUAD ; + wire FREEZE ; + assign LC1 = Config_reg1[7]; + assign LC0 = Config_reg1[6]; + assign TBPROT = Config_reg1[5]; + assign LOCK = Config_reg1[4]; + assign BPNV = Config_reg1[3]; + assign QUAD = Config_reg1[1]; + assign FREEZE = Config_reg1[0]; + + // Autoboot Register + reg[31:0] AutoBoot_reg = 32'h00000000; + reg[31:0] AutoBoot_reg_in = 32'h00000000; + + wire ABE; + assign ABE = AutoBoot_reg[0]; + + // Bank Address Register + reg [7:0] Bank_Addr_reg = 8'h00; + reg [7:0] Bank_Addr_reg_in = 8'h00; + + wire EXTADD; + wire BA25; + wire BA24; + + assign EXTADD = Bank_Addr_reg[7]; + assign BA25 = Bank_Addr_reg[1]; + assign BA24 = Bank_Addr_reg[0]; + + // ASP Register + reg[15:0] ASP_reg; + reg[15:0] ASP_reg_in; + + wire RPME ; + wire PPBOTP ; + wire PWDMLB ; + wire PSTMLB ; + assign RPME = ASP_reg[5]; + assign PPBOTP = ASP_reg[3]; + assign PWDMLB = ASP_reg[2]; + assign PSTMLB = ASP_reg[1]; + + // Password register + reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF; + reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF; + + // PPB Lock Register + reg[7:0] PPBL = 8'h00; + reg[7:0] PPBL_in = 8'h00; + + wire PPB_LOCK ; + assign PPB_LOCK = PPBL[0]; + + // PPB Access Register + reg[7:0] PPBAR = 8'hFF; + reg[7:0] PPBAR_in = 8'hFF; + + reg[SecNum:0] PPB_bits = {512{1'b1}}; + + // DYB Access Register + reg[7:0] DYBAR = 8'hFF; + reg[7:0] DYBAR_in = 8'hFF; + + reg[SecNum:0] DYB_bits = {512{1'b1}}; + + //The Lock Protection Registers for OTP Memory space + reg[7:0] LOCK_BYTE1; + reg[7:0] LOCK_BYTE2; + reg[7:0] LOCK_BYTE3; + reg[7:0] LOCK_BYTE4; + + // Command Register + reg write; + reg cfg_write; + reg read_out; + reg dual = 1'b0; + reg rd_fast = 1'b1; + reg rd_slow = 1'b0; + reg ddr = 1'b0; + reg ddr_fast = 1'b0; + reg hold_mode = 1'b0; + reg any_read = 1'b0; + reg quad_pg = 1'b0; + + wire rd ; + wire fast_rd ; + wire ddrd ; + wire fast_ddr ; + + wire quadpg ; + assign quadpg = quad_pg; + + wire RD_EQU_1; + assign RD_EQU_1 = any_read; + + wire RD_EQU_0; + assign RD_EQU_0 = ~any_read; + + reg change_BP = 0; + reg [2:0] BP_bits = 3'b0; + + reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag + + reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag + reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag + + integer Byte_number = 0; + + reg oe = 1'b0; + reg oe_z = 1'b0; + + reg [647:0] CFI_array_tmp ; + reg [7:0] CFI_tmp; + + integer start_delay; + reg start_autoboot; + integer ABSD; + + reg change_addr ; + integer Address = 0; + integer SectorSuspend = 0; + integer mem_data; + + //Sector and subsector addresses + integer SA = 0; + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [SecNum:0] Sec_Prot = 512'b0; + + // Page Number for QPP operations + reg[PageNum:0] QPP_page = 0; + + // timing check violation + reg Viol = 1'b0; + + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + reg[63:0] old_pass; + reg[63:0] new_pass; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer byte_cnt = 1; + integer read_addr = 0; + integer read_addr_tmp = 0; + integer Sec_addr = 0; + integer SecAddr = 0; + integer SecAddrERS = 0; + + integer Page_addr = 0; + integer pgm_page = 0; + integer SecAddr_tmp; + + reg [SecNum : 0] corrupt_Sec; + reg [7:0] OutputD; + + reg[7:0] data_out; + reg[647:0] ident_out; + + time SCK_cycle = 0; + time prev_SCK; + time start_ddr; + time out_time; + time SCK_SO_DDR; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (RSTNeg_ipd, RSTNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + //VHDL VITAL CheckEnable equivalents + wire quad_rd; + assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz); + wire wr_prot; + assign wr_prot = SRWD && WEL && ~QUAD; + wire dual_rd; + assign dual_rd = dual ; + wire ddro; + assign ddro = ddr && ~dual ; + wire ddr_rd; + assign ddr_rd = PoweredUp && ddr; + wire sdr_rd; + assign sdr_rd = PoweredUp && ~ddr; + + memory_features memory_features_i0(); + +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_normal =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + specparam tpd_RSTNeg_SO =1; + //DDR operation values + specparam tpd_SCK_SO_DDR =1; + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; + specparam tsetup_SI_SCK_normal =1; + specparam tsetup_WPNeg_CSNeg =1; + specparam tsetup_HOLDNeg_SCK =1; + specparam tsetup_RSTNeg_CSNeg =1; + // DDR operation values + specparam tsetup_SI_SCK_DDR =1; + specparam tsetup_SI_SCK_DDR_fast =1; + specparam tsetup_CSNeg_SCK_DDR =1; + + //thold values: hold times + specparam thold_CSNeg_SCK =1; + specparam thold_SI_SCK_normal =1; + specparam thold_WPNeg_CSNeg =1; + specparam thold_HOLDNeg_SCK =1; + specparam thold_CSNeg_RSTNeg =1; + // DDR operation values + specparam thold_SI_SCK_DDR =1; + specparam thold_SI_SCK_DDR_fast =1; + specparam thold_CSNeg_SCK_DDR =1; + + // tpw values: pulse width + specparam tpw_SCK_serial_posedge =1; + specparam tpw_SCK_dual_posedge =1; + specparam tpw_SCK_fast_posedge =1; + specparam tpw_SCK_quadpg_posedge =1; + specparam tpw_SCK_serial_negedge =1; + specparam tpw_SCK_dual_negedge =1; + specparam tpw_SCK_fast_negedge =1; + specparam tpw_SCK_quadpg_negedge =1; + specparam tpw_CSNeg_read_posedge =1; + specparam tpw_CSNeg_pgers_posedge =1; + specparam tpw_RSTNeg_negedge =1; + specparam tpw_RSTNeg_posedge =1; + // DDR operation values + specparam tpw_SCK_DDR_posedge =1; + specparam tpw_SCK_DDR_negedge =1; + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_serial_rd =1;// 50 MHz + specparam tperiod_SCK_fast_rd =1;//133 MHz + specparam tperiod_SCK_dual_rd =1;//104 MHz + specparam tperiod_SCK_quadpg =1;// 80 MHz + // DDR operation values + specparam tperiod_SCK_DDR_rd =1;// 66 MHz + + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE = 1875e7;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 460e9;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e9;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `else + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE = 1875e9;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 460e12;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e11;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~ddr) (SCK => SO) = tpd_SCK_SO_normal; + if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR; + + if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal; + if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR; + + if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR; + if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR; + + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO; + + if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; + if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO; + + if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + (RSTNeg => SO) = tpd_RSTNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& sdr_rd, + tsetup_CSNeg_SCK, Viol); + $setup ( CSNeg , posedge SCK &&& ddr_rd, + tsetup_CSNeg_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK_normal, Viol); + $setup ( WPNeg , negedge CSNeg &&& wr_prot, + tsetup_WPNeg_CSNeg, Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_rd, + tsetup_HOLDNeg_SCK, Viol); + $setup ( SI , posedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + + $setup ( RSTNeg , negedge CSNeg, + tsetup_RSTNeg_CSNeg, Viol); + + $hold ( posedge SCK &&& sdr_rd , CSNeg, + thold_CSNeg_SCK, Viol); + $hold ( posedge SCK &&& ddr_rd , CSNeg, + thold_CSNeg_SCK_DDR, Viol); + $hold ( posedge SCK &&& deg_sin , SI , + thold_SI_SCK_normal, Viol); + $hold ( posedge CSNeg &&& wr_prot , WPNeg , + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK &&& quad_rd , HOLDNeg , + thold_HOLDNeg_SCK, Viol); + $hold ( posedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + + $hold ( negedge RSTNeg , CSNeg, + thold_CSNeg_RSTNeg, Viol); + + $width ( posedge SCK &&& rd , tpw_SCK_serial_posedge); + $width ( negedge SCK &&& rd , tpw_SCK_serial_negedge); + $width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge); + $width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge); + $width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge); + $width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge); + + $width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge); + $width ( negedge RSTNeg , tpw_RSTNeg_negedge); + $width ( posedge RSTNeg , tpw_RSTNeg_posedge); + + $period ( posedge SCK &&& rd , tperiod_SCK_serial_rd); + $period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); + $period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); + $period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg); + $period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 5'd0; + parameter RESET_STATE = 5'd1; + parameter AUTOBOOT = 5'd2; + parameter WRITE_SR = 5'd3; + parameter PAGE_PG = 5'd4; + parameter OTP_PG = 5'd5; + parameter PG_SUSP = 5'd6; + parameter SECTOR_ERS = 5'd7; + parameter BULK_ERS = 5'd8; + parameter ERS_SUSP = 5'd9; + parameter ERS_SUSP_PG = 5'd10; + parameter ERS_SUSP_PG_SUSP= 5'd11; + parameter PASS_PG = 5'd12; + parameter PASS_UNLOCK = 5'd13; + parameter PPB_PG = 5'd14; + parameter PPB_ERS = 5'd15; + parameter AUTOBOOT_PG = 5'd16; + parameter ASP_PG = 5'd17; + parameter PLB_PG = 5'd18; + parameter DYB_PG = 5'd19; + parameter NVDLR_PG = 5'd20; + + reg [4:0] current_state; + reg [4:0] next_state; + +// Instruction type + parameter NONE = 7'd0; + parameter WRR = 7'd1; + parameter PP = 7'd2; + parameter READ = 7'd3; + parameter WRDI = 7'd4; + parameter RDSR = 7'd5; + parameter WREN = 7'd6; + parameter RDSR2 = 7'd7; + parameter FSTRD = 7'd8; + parameter FSTRD4 = 7'd9; + parameter DDRFR = 7'd10; + parameter DDRFR4 = 7'd11; + parameter PP4 = 7'd12; + parameter RD4 = 7'd13; + parameter ABRD = 7'd14; + parameter ABWR = 7'd15; + parameter BRRD = 7'd16; + parameter BRWR = 7'd17; + parameter P4E = 7'd18; + parameter P4E4 = 7'd19; + parameter ASPRD = 7'd20; + parameter ASPP = 7'd21; + parameter CLSR = 7'd22; + parameter QPP = 7'd23; + parameter QPP4 = 7'd24; + parameter RDCR = 7'd25; + parameter DOR = 7'd26; + parameter DOR4 = 7'd27; + parameter DLPRD = 7'd28; + parameter OTPP = 7'd29; + parameter PNVDLR = 7'd30; + parameter OTPR = 7'd31; + parameter WVDLR = 7'd32; + parameter BE = 7'd33; + parameter QOR = 7'd34; + parameter QOR4 = 7'd35; + parameter ERSP = 7'd36; + parameter ERRS = 7'd37; + parameter PGSP = 7'd38; + parameter PGRS = 7'd39; + parameter REMS = 7'd40; + parameter RDID = 7'd41; + parameter MPM = 7'd42; + parameter PLBWR = 7'd43; + parameter PLBRD = 7'd44; + parameter RES = 7'd45; + parameter DIOR = 7'd46; + parameter DIOR4 = 7'd47; + parameter DDRDIOR = 7'd48; + parameter DDRDIOR4 = 7'd49; + parameter SE = 7'd50; + parameter SE4 = 7'd51; + parameter DYBRD = 7'd52; + parameter DYBWR = 7'd53; + parameter PPBRD = 7'd54; + parameter PPBP = 7'd55; + parameter PPBERS = 7'd56; + parameter PASSRD = 7'd57; + parameter PASSP = 7'd58; + parameter PASSU = 7'd69; + parameter QIOR = 7'd70; + parameter QIOR4 = 7'd71; + parameter DDRQIOR = 7'd72; + parameter DDRQIOR4 = 7'd73; + parameter RESET = 7'd74; + parameter MBR = 7'd75; + parameter BRAC = 7'd76; + + reg [6:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SO_in, SO_z) + begin + if (SO_in==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_pin=deq_pin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_sin=deq_sin + && (ddr == 1'b0) && (Instruct !== DDRFR) + && (Instruct !== DDRFR4) && (Instruct !== DDRDIOR) + && (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR) + && (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz); + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + initial + begin : Init + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + cnt = 0; + RST = 1'b0; + RST_in = 1'b0; + RST_out = 1'b1; + PDONE = 1'b1; + PSTART = 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + PRGSUSP_in = 1'b0; + ERSSUSP_in = 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + Reseted = 1'b0; + + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + end + // constraint memory preload file parameters + parameter preload_line_width = 160; + parameter preload_address_width = 7; + parameter preload_data_width = 2; + + // preload dedicated declarations + reg [preload_line_width*8 : 1] scanf_str; + reg [8:1] fetch_char; + integer preload_iter; + integer preload_file; + integer scanf_address; + integer scanf_data; + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + // memory region implicitly initialized + memory_features_i0.initialize_w(); + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl512s.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + scanf_address = 0; + preload_file = $fopen(mem_file_name, "r"); + + while($fgets(scanf_str, preload_file)) + begin + fetch_char = scanf_str + [preload_line_width * 8 : preload_line_width * 8 - 7]; + while (!fetch_char) + begin + scanf_str = scanf_str << 8; + fetch_char = scanf_str + [preload_line_width * 8 : preload_line_width * 8 - 7]; + end + + if ((fetch_char == "/") || (fetch_char == "\n")) + begin + // empty lines and comments not processed + end + else + begin + if (fetch_char == "@") + begin + scanf_address = 0; + for(preload_iter = 0; + preload_iter < preload_address_width; + preload_iter = preload_iter + 1) + begin + scanf_str = scanf_str << 8; + fetch_char = scanf_str[ + preload_line_width * 8 : + preload_line_width * 8 - 7 + ]; + scanf_address = scanf_address * 16; + if ((fetch_char >= "0")&&(fetch_char <= "9")) + scanf_address = + scanf_address + (fetch_char - "0"); + else if ((fetch_char >= "A")&&(fetch_char <= "F")) + scanf_address = + scanf_address + (fetch_char - "A") + 10; + else if ((fetch_char >= "a")&&(fetch_char <= "f")) + scanf_address = + scanf_address + (fetch_char - "a") + 10; + end + end + else + begin + scanf_data = 0; + for(preload_iter = 0; + preload_iter < preload_data_width; + preload_iter = preload_iter + 1) + begin + scanf_data = scanf_data * 16; + if ((fetch_char >= "0") && (fetch_char <= "9")) + scanf_data = scanf_data + (fetch_char - "0"); + else if ((fetch_char >= "A")&&(fetch_char <= "F")) + scanf_data = + scanf_data + (fetch_char - "A") + 10; + else if ((fetch_char >= "a")&&(fetch_char <= "f")) + scanf_data = + scanf_data + (fetch_char - "a") + 10; + scanf_str = scanf_str << 8; + fetch_char = scanf_str[ + preload_line_width * 8 : + preload_line_width * 8-7 + ]; + end + if (scanf_data !== MaxData) + begin + if (scanf_address <= AddrRANGE) + begin + memory_features_i0.write_mem_w(scanf_address, + scanf_data); + end + else + $display("Memory address out of range."); + end + scanf_address++; + end + end + end + $fclose(preload_file); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl512s_otp memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at OTPMem(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + + LOCK_BYTE1[7:0] = OTPMem[16]; + LOCK_BYTE2[7:0] = OTPMem[17]; + LOCK_BYTE3[7:0] = OTPMem[18]; + LOCK_BYTE4[7:0] = OTPMem[19]; + end + + // initialize memory and load preload files if any + initial + begin: InitTimingModel + integer i; + integer j; + //UNIFORM OR HYBRID arch model is used + //assumptions: + //1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF + //it is important that 16-th character from first one is "0" or "1" + //2. TimingModel does not have more then 24 characters + tmp_timing = TimingModel;//copy of TimingModel + + i = 23; + while ((i >= 0) && (found != 1'b1))//search for first non null character + begin //i keeps position of first non null character + j = 7; + while ((j >= 0) && (found != 1'b1)) + begin + if (tmp_timing[i*8+j] != 1'd0) + found = 1'b1; + else + j = j-1; + end + i = i - 1; + end + i = i +1; + if (found)//if non null character is found + begin + for (j=0;j<=7;j=j+1) + begin + //EHPLC/HPLC character is 15 + tmp_char1[j] = TimingModel[(i-14)*8+j]; + end + end + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" || + tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L") + begin + EHP = 1; + if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y") + begin + RdPswdProtEnable = 1; + end + end + else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" || + tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q") + begin + EHP = 0; + end + + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" || + tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" || + tmp_char1 == "9" || tmp_char1 == "Q") + begin + ASP_reg = 16'hFE7F; + ASP_reg_in = 16'hFE7F; + end + else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" || + tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L") + begin + ASP_reg = 16'hFE4F; + ASP_reg_in = 16'hFE4F; + end + + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + /////////////////////////////////////////////////////////////////////// + // ID-CFI array data + /////////////////////////////////////////////////////////////////////// + // Manufacturer and Device ID + CFI_array[8'h00] = Jedec_ID; + CFI_array[8'h01] = DeviceID1; + CFI_array[8'h02] = DeviceID2; + CFI_array[8'h03] = 8'h00; + // Uniform 256kB sectors + CFI_array[8'h04] = ExtendedID; + CFI_array[8'h05] = 8'h80; + CFI_array[8'h06] = 8'h00; + CFI_array[8'h07] = 8'h00; + CFI_array[8'h08] = 8'h00; + CFI_array[8'h09] = 8'h00; + CFI_array[8'h0A] = 8'h00; + CFI_array[8'h0B] = 8'h00; + CFI_array[8'h0C] = 8'h00; + CFI_array[8'h0D] = 8'h00; + CFI_array[8'h0E] = 8'h00; + CFI_array[8'h0F] = 8'h00; + // CFI Query Identification String + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h53; + CFI_array[8'h18] = 8'h46; + CFI_array[8'h19] = 8'h51; + CFI_array[8'h1A] = 8'h00; + //CFI system interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h06; + //512B page + CFI_array[8'h20] = 8'h09; + // 256kB sector + CFI_array[8'h21] = 8'h09; + CFI_array[8'h22] = 8'h11; + CFI_array[8'h23] = 8'h02; + CFI_array[8'h24] = 8'h02; + CFI_array[8'h25] = 8'h03; + CFI_array[8'h26] = 8'h03; + // Device Geometry Definition(Uniform Sector Devices) + CFI_array[8'h27] = 8'h1A; + CFI_array[8'h28] = 8'h02; + CFI_array[8'h29] = 8'h01; + CFI_array[8'h2A] = 8'h09; + CFI_array[8'h2B] = 8'h00; + CFI_array[8'h2C] = 8'h01; + CFI_array[8'h2D] = 8'hFF; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h04; + CFI_array[8'h31] = 8'hFF; + CFI_array[8'h32] = 8'hFF; + CFI_array[8'h33] = 8'hFF; + CFI_array[8'h34] = 8'hFF; + CFI_array[8'h35] = 8'hFF; + CFI_array[8'h36] = 8'hFF; + CFI_array[8'h37] = 8'hFF; + CFI_array[8'h38] = 8'hFF; + CFI_array[8'h39] = 8'hFF; + CFI_array[8'h3A] = 8'hFF; + CFI_array[8'h3B] = 8'hFF; + CFI_array[8'h3C] = 8'hFF; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + // CFI Primary Vendor-Specific Extended Query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h21; + CFI_array[8'h46] = 8'h02; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h08; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h04; + CFI_array[8'h4D] = 8'h00; + CFI_array[8'h4E] = 8'h00; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h01; + + begin + for(i=80;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h00-i+80]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + end + + always @(next_state_event or PoweredUp or RST or RST_out) + begin: StateTransition + if (PoweredUp) + begin + if ((RSTNeg_in) && RST_out == 1'b1) + current_state = #(1000) next_state; + else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST) + begin + // no state transition while RESET# low + current_state = RESET_STATE; + RST_in = 1'b1; + #1000 RST_in = 1'b0; + end + end + end + + always @(posedge RST_in) + begin:Threset + RST_out = 1'b0; + #(35000000-200000) RST_out = 1'b1; + end + + always @(negedge CSNeg_ipd) + begin:CheckCEOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_PRGSUSP PRGSUSP_out = 1'b1; + end + + always @(posedge PPBERASE_in) + begin:PPBErs + PPBERASE_out = 1'b0; + #tdevice_PPBERASE PPBERASE_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_ERSSUSP ERSSUSP_out = 1'b1; + end + + always @(posedge PASSULCK_in) + begin:PASSULock + PASSULCK_out = 1'b0; + #tdevice_PASSULCK PASSULCK_out = 1'b1; + end + + always @(posedge PASSACC_in) + begin:PASSAcc + PASSACC_out = 1'b0; + #tdevice_PASSACC PASSACC_out = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [7:0] opcode_in; + reg [7:0] opcode_tmp; + reg [31:0] addr_bytes; + reg [31:0] hiaddr_bytes; + reg [31:0] Address_in; + reg [7:0] mode_bytes; + reg [7:0] mode_in; + integer Latency_code; + integer quad_data_in [0:1023]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle + integer i; + integer j; + integer k; + time CLK_PER; + time LAST_CLK; + + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + Instruct = NONE; + write = 1'b1; + cfg_write = 0; + opcode_cnt = 0; + addr_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + data_cnt = 0; + opcode_tmp = 0; + DOUBLE = 1'b0; + QUADRD = 1'b0; + CLK_PER = 1'b0; + LAST_CLK = 1'b0; + if (current_state == AUTOBOOT) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = OPCODE_BYTE; + end + end + end + + if (rising_edge_SCK_ipd) // Instructions, addresses or data present + begin // at SI are latched on the rising edge of SCK + + CLK_PER = $time - LAST_CLK; + LAST_CLK = $time; + if (CHECK_FREQ) + begin + if ((CLK_PER < 20000 && Latency_code == 3) || + (CLK_PER < 12500 && Latency_code == 0) || + (CLK_PER < 11100 && Latency_code == 1) || + (CLK_PER < 9600 && Latency_code == 2)) + begin + $display ("More wait states are required for"); + $display ("this clock frequency value"); + end + CHECK_FREQ = 0; + end + + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + Latency_code = Config_reg1[7:6]; + if (opcode_cnt == BYTE) + begin + for(i=7;i>=0;i=i-1) + begin + opcode[i] = opcode_in[7-i]; + end + case (opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010011 : // 13h + begin + Instruct = RD4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : // 4Bh + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000111 : // 07h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 35h + begin + Instruct = RDCR; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : // 90h + begin + Instruct = REMS; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : // 9Fh + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011 : // ABh + begin + Instruct = RES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FSTRD; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001100 : // 0Ch + begin + Instruct = FSTRD4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001101 : // 0Dh + begin + Instruct = DDRFR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001110 : // 0Eh + begin + Instruct = DDRFR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111011 : // 3Bh + begin + Instruct = DOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111100 : // 3Ch + begin + Instruct = DOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111011 : // BBh + begin + Instruct = DIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111100 : // BCh + begin + Instruct = DIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111101 : // BDh + begin + Instruct = DDRDIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111110 : // BEh + begin + Instruct = DDRDIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101011 : // 6Bh + begin + Instruct = QOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101100 : // 6Ch + begin + Instruct = QOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101011 : // EBh + begin + Instruct = QIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101100 : // ECh + begin + Instruct = QIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101101 : // EDh + begin + Instruct = DDRQIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101110 : // EEh + begin + Instruct = DDRQIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010010 : // 12h + begin + Instruct = PP4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010: // 32h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00111000: // 38h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00110100 : // 34h + begin + Instruct = QPP4; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b01000010 : // 42h + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10000101 : // 85h + begin + Instruct = PGSP; + bus_cycle_state = DATA_BYTES; + end + 8'b10001010 : // 8Ah + begin + Instruct = PGRS; + bus_cycle_state = DATA_BYTES; + end + 8'b11000111 : // C7h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b01100000 : // 60h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011100 : // DCh + begin + Instruct = SE4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERRS; + bus_cycle_state = DATA_BYTES; + end + 8'b00010100 : // 14h + begin + Instruct = ABRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010101 : // 15h + begin + Instruct = ABWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00010110 : // 16h + begin + Instruct = BRRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010111 : // 17h + begin + Instruct = BRWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00101011 : // 2Bh + begin + Instruct = ASPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00101111 : // 2Fh + begin + Instruct = ASPP; + bus_cycle_state = DATA_BYTES; + end + 8'b11100000 : // E0h + begin + Instruct = DYBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100001 : // E1h + begin + Instruct = DYBWR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100010 : // E2h + begin + Instruct = PPBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100011 : // E3h + begin + Instruct = PPBP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100100 : // E4h + begin + Instruct = PPBERS; + bus_cycle_state = DATA_BYTES; + end + 8'b10100110 : // A6h + begin + Instruct = PLBWR; + bus_cycle_state = DATA_BYTES; + end + 8'b10100111 : // A7h + begin + Instruct = PLBRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11100111 : // E7h + begin + Instruct = PASSRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11101000 : // E8h + begin + Instruct = PASSP; + bus_cycle_state = DATA_BYTES; + end + 8'b11101001 : // E9h + begin + Instruct = PASSU; + bus_cycle_state = DATA_BYTES; + end + 8'b11110000 : // F0h + begin + Instruct = RESET; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : // 30h + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b01000001 : // 41h + begin + Instruct = DLPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b01000011 : // 43h + begin + Instruct = PNVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b01001010 : // 4Ah + begin + Instruct = WVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = BRAC; + bus_cycle_state = DATA_BYTES; + end + 8'b11111111 : // FFh + begin + Instruct = MBR; + bus_cycle_state = MODE_BYTE; + end + 8'b00100000 : // 20h + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00100001 : // 21h + begin + Instruct = P4E4; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + end //end of OPCODE BYTE + + ADDRESS_BYTES : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4) || + (Instruct == DDRDIOR) || (Instruct == DDRDIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + DOUBLE = 1'b1; + else + DOUBLE = 1'b0; + if ((Instruct == QOR) || (Instruct == QOR4) || + (Instruct == QIOR) || (Instruct == QIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + QUADRD = 1'b1; + else + QUADRD = 1'b0; + if (DOUBLE == 1'b0) + begin + if (((((Instruct == FSTRD) && (~EXTADD)) || + ((Instruct == DOR) && (~EXTADD)) || + (Instruct == OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QOR) && QUAD && (~EXTADD))) + begin + //Instruction + 3 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes ; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct==FSTRD || Instruct==DOR || + Instruct == QOR) + begin + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((((Instruct==FSTRD4) || + (Instruct==DOR4) || + ((Instruct==FSTRD) && EXTADD) || + ((Instruct==DOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct==QOR4) && QUAD) || + ((Instruct==QOR) && QUAD && EXTADD)) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + end + end + end + else if ((Instruct==DIOR) && (~EXTADD) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + //DUAL I/O High Performance Read(3 Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i]=Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==DIOR4) || + ((Instruct==DIOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin //DUAL I/O High Performance Read(4Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == QIOR) && (~EXTADD)) + begin + //QUAD I/O High Performance Read (3Bytes Address) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((Instruct==QIOR4) || ((Instruct==QIOR) + && EXTADD)) + begin + //QUAD I/O High Performance Read (4Bytes Addr) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt +1; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt =0; + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((((Instruct==RD4) || (Instruct==PP4) || + (Instruct==SE4) ||(Instruct==PPBRD) || + (Instruct==DYBRD) ||(Instruct==DYBWR) || + (Instruct==PPBP) || (Instruct==P4E4) || + ((Instruct==READ) && EXTADD) || + ((Instruct==PP) && EXTADD) || + ((Instruct==P4E) && EXTADD) || + ((Instruct==SE) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (QUAD && (Instruct==QPP4 || + ((Instruct==QPP) && EXTADD)))) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + else if (((HOLDNeg_in && ~QUAD) || QUAD) && + (~EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + else + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + end + end + + MODE_BYTE : + begin + if (((Instruct==DIOR) || (Instruct == DIOR4)) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + if (Latency_code == 0 || Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + mode_in[2*mode_cnt] = SI_in; + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt] = SO_in; + mode_in[4*mode_cnt+1] = SI_in; + end + else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4)) + && QUAD) + begin + mode_in[0] = HOLDNeg_in; + mode_in[1] = WPNeg_in; + mode_in[2] = SO_in; + mode_in[3] = SI_in; + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + if ((((Instruct==FSTRD) || (Instruct==FSTRD4) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (((Instruct==QOR)||(Instruct==QOR4)) && QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + begin + bus_cycle_state = DATA_BYTES; + end + end + + else if ((Instruct==DDRFR) || (Instruct==DDRFR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==2)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==5)) || + ((Latency_code == 1) && (dummy_cnt==6)) || + ((Latency_code == 2) && (dummy_cnt==7))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (Instruct==RES) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + else if ((Instruct == DIOR) || (Instruct == DIOR4) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 1) && (dummy_cnt==1)) || + ((Latency_code == 2) && (dummy_cnt==2))) + bus_cycle_state = DATA_BYTES; + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + bus_cycle_state = DATA_BYTES; + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==2)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (((Instruct == QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + + if (((Latency_code == 3) && (dummy_cnt==3)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + + DATA_BYTES : + begin + + if (DOUBLE == 1'b1 && (hold_mode==0)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + + if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4))) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in}; + if (data_cnt > ((PageSize+1)*2-1)) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for(i=0;i<=(PageSize*2-1);i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[(PageSize+1)*2-1] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + else if ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (data_cnt > ((PageSize+1)*8-1)) + begin + //In case of serial mode and PP, + //if more than PageSize are sent to the device + //previously latched data are discarded and last + //256/512 data bytes are guaranteed to be programmed + //correctly within the same page. + if (bit_cnt == 0) + begin + for(i=0;i<=(PageSize*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[PageSize*BYTE + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + + if (falling_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + ADDRESS_BYTES : + begin + if (DOUBLE == 1'b1) + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + end + + MODE_BYTE : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + begin + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + begin + mode_in[4] = HOLDNeg_in; + mode_in[5] = WPNeg_in; + mode_in[6] = SO_in; + mode_in[7] = SI_in; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + DATA_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 ) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + else + begin + if ((Instruct==READ) || (Instruct==RD4) || + (Instruct==FSTRD)|| (Instruct==FSTRD4)|| + (Instruct==RDSR) || (Instruct==RDSR2) || + (Instruct==RDCR) || (Instruct==OTPR) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==DIOR)|| (Instruct==DIOR4)|| + (Instruct==ABRD) || (Instruct==BRRD) || + (Instruct==ASPRD)|| (Instruct==DYBRD) || + (Instruct==PPBRD)|| + (Instruct==PASSRD)|| (Instruct==RDID)|| + (Instruct==RES) || (Instruct==REMS) || + (Instruct==PLBRD)|| (Instruct==DLPRD) || + (current_state == AUTOBOOT && + start_delay == 0) || + (((Instruct==QOR) || (Instruct==QIOR) || + (Instruct==QOR4) || + (Instruct==QIOR4)) && QUAD)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + + DUMMY_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + endcase + end + end + + if (rising_edge_CSNeg_ipd) + begin + if ((bus_cycle_state != DATA_BYTES) && + (bus_cycle_state != DUMMY_BYTES)) + begin + if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF) + begin + Instruct = MBR; + end + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (((mode_bytes[7:4] == 4'b1010) && + (Instruct==DIOR || Instruct==DIOR4 || + Instruct==QIOR || Instruct==QIOR4)) || + ((mode_bytes[7:4] == ~mode_bytes[3:0]) && + (Instruct == DDRFR || Instruct == DDRFR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4))) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + + case (Instruct) + WREN, + WRDI, + BE, + SE, + SE4, + CLSR, + P4E, + P4E4, + BRAC, + RESET, + PPBERS, + PPBP, + PLBWR, + PGSP, + PGRS, + ERSP, + ERRS: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 0) + write = 1'b0; + end + end + + WRR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + if (BAR_ACC == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else + begin + if (P_ERR == 0 && E_ERR == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Bank_Addr_reg_in[i]= + Data_in[7-i]; + end + end + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + if (BAR_ACC == 0) + begin + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Config_reg1_in[i]= + Data_in[15-i]; + end + end + else + begin + if (P_ERR == 0 && E_ERR == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Bank_Addr_reg_in[i]= + Data_in[7-i]; + end + end + end + end + end + end + + PP, + PP4, + OTPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=7;j>=0;j=j-1) + begin + if ((Data_in[(i*8)+(7-j)]) + !== 1'bX) + begin + Byte_slv[j] = + Data_in[(i*8)+(7-j)]; + end + end + WByte[i] = Byte_slv; + end + + if (data_cnt > (PageSize+1)*BYTE) + Byte_number = PageSize; + else + Byte_number = + ((data_cnt/8) - 1); + end + end + end + end + + QPP, + QPP4: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + quad_pg = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > (PageSize+1)*2) + Byte_number = PageSize; + else + Byte_number = ((data_cnt/2)-1); + end + end + end + + ABWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 32) + begin + write = 1'b0; + for(j=0;j<=31;j=j+1) + begin + AutoBoot_reg_in[j] = Data_in[31-j]; + end + end + end + end + + BRWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + Bank_Addr_reg_in[j] = Data_in[7-j]; + end + end + end + end + + ASPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 16) + begin + write = 1'b0; + for(j=0;j<=15;j=j+1) + begin + ASP_reg_in[j] = Data_in[15-j]; + end + end + end + end + + DYBWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + DYBAR_in[j] = Data_in[7-j]; + end + end + end + end + + PNVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + NVDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + WVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + VDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + PASSP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + Password_reg_in[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + + PASSU: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + PASS_TEMP[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + endcase + end + end + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Page Program +/////////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed_pgm; + time start_pgm; + time duration_pgm; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) || + (Instruct == QPP) || (Instruct == QPP4)) + if (PageSize == 255) + begin + pob = tdevice_PP_256; + end + else + begin + pob = tdevice_PP_512; + end + else + pob = tdevice_BP; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed_pgm = 0; + duration_pgm = pob; + PDONE = 1'b0; + ->pdone_event; + start_pgm = $time; + end + end + + always @(posedge PGSUSP) + begin + if (PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed_pgm = $time - start_pgm; + duration_pgm = pob - elapsed_pgm; + PDONE = 1'b0; + end + end + + always @(posedge PGRES) + begin + start_pgm = $time; + ->pdone_event; + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #duration_pgm PDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Write Status Register +/////////////////////////////////////////////////////////////////////////////// + time wob; + always @(posedge WSTART) + begin:wdone_process + wob = tdevice_WRR; + if (WSTART && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Reset Timing +/////////////////////////////////////////////////////////////////////////////// + + time startlo; + time starthi; + time durationlo; + time durationhi; + + always @(negedge RSTNeg_in or Instruct) + begin + if (~RSTNeg_in) + begin + RST = 1'b1; + #200000 RST = 1'b0; // 200 ns + end + else if (Instruct == RESET) + begin + Reseted = 1'b0; + #10000 Reseted = 1'b1; // 10 ns + end + end + + always @(RST_in or rising_edge_Reseted) // Reset done,program terminated + begin + if ((RST_in && ~RST) || (rising_edge_Reseted)) + disable pdone_process; + disable edone_process; + disable wdone_process; + PDONE = 1'b1; + EDONE = 1'b1; + WDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Bulk Erase +/////////////////////////////////////////////////////////////////////////////// + time seo; + time beo; + event edone_event; + time elapsed_ers; + time start_ers; + time duration_ers; + + always @(rising_edge_ESTART) + begin + seo = tdevice_SE; + beo = tdevice_BE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == BE) + begin + duration_ers = beo; + end + else + begin + duration_ers = seo; + end + elapsed_ers = 0; + EDONE = 1'b0; + ->edone_event; + start_ers = $time; + end + end + + always @(posedge ESUSP) + begin + if (ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed_ers = $time - start_ers; + duration_ers = seo - elapsed_ers; + EDONE = 1'b0; + end + end + + always @(posedge ERES) + begin + if (ERES && (~EDONE)) + begin + start_ers = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_ers EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg falling_edge_PPBERASE_in = 1'b0; + reg falling_edge_PASSULCK_in = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or + falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or + rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or + PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out + or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in) + begin: StateGen1 + + integer sect; + + if (rising_edge_PoweredUp) + begin + if (ABE == 1 && RPME !== 0 ) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + else + begin + if (RST_out == 1'b0) + next_state = current_state; + else if (falling_edge_write && Instruct == RESET) + begin + if (ABE == 1 && RPME !== 0) + begin + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + ABSD = AutoBoot_reg[8:1]; + start_autoboot = 0; + next_state = AUTOBOOT; + end + else + next_state = IDLE; + end + else + begin + case (current_state) + RESET_STATE : + begin + if (rising_edge_RST_out) + begin + if (ABE == 1 && RPME!== 0) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9],9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + end + + IDLE : + begin + if (falling_edge_write && RdPswdProtMode == 0) + begin + if (Instruct == WRR && WEL == 1 && BAR_ACC == 0 + && (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)) + // can not execute if HPM is entered or + // if WEL bit is zero + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + $display ("WARNING: Changing value of "); + $display ("Configuration Register OTP "); + $display ("bit from 1 to 0 is not"); + $display ("allowed!!!"); + end + else + begin + next_state = WRITE_SR; + end + else if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = PAGE_PG; + if ((Instruct==QPP || Instruct==QPP4) && + QPP_page[pgm_page] == 1) + begin + $display ("WARNING:The same page"); + $display (" must not be"); + $display (" programmed more"); + $display (" than once!!!"); + end + end + end + else if (Instruct==OTPP && WEL==1 && FREEZE==0) + begin + if (((((Address>=16'h0010 && Address<=16'h0013) + ||(Address>=16'h0020 && Address<=16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address>=16'h0100 && Address<=16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32]==1) || + ((Address>=16'h0200 && Address<=16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32]==1) || + ((Address>=16'h0300 && Address<=16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) + && (Address + Byte_number <= OTPHiAddr)) + next_state = OTP_PG; + end + else if ((Instruct == SE || Instruct == SE4) + && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 + && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + else if (Instruct == BE && WEL == 1 && + (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0)) + next_state = BULK_ERS; + else if (Instruct == ABWR && WEL == 1) + //Autoboot Register Write Command + next_state = AUTOBOOT_PG; + else if (Instruct == ASPP && WEL == 1) + begin + //ASP Register Program Command + if (~(ASPOTPFLAG)) + next_state = ASP_PG; + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + next_state = PLB_PG; + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + next_state = PASS_PG; + end + else if (Instruct == PASSU && WEL && ~WIP) + next_state = PASS_UNLOCK; + else if (Instruct == PPBP && WEL == 1) + next_state <= PPB_PG; + else if (Instruct == PPBERS && WEL && PPBOTP) + next_state <= PPB_ERS; + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == PNVDLR && WEL == 1) + next_state = NVDLR_PG; + else if (Instruct == P4E || Instruct == P4E4 + && WEL == 1) + begin + $display("Warning!"); + $display("Instructions:"); + $display("Parameter 4KB-sector Erase"); + $display("are not allowed"); + $display("for 512Mbit memory size"); + end + else + next_state = IDLE; + end + if (falling_edge_write && RdPswdProtMode == 1 && ~WIP) + begin + if (Instruct == PASSU) + next_state = PASS_UNLOCK; + end + end + + AUTOBOOT : + begin + if (rising_edge_CSNeg_ipd) + next_state = IDLE; + end + + WRITE_SR : + begin + if (rising_edge_WDONE) + next_state = IDLE; + end + + PAGE_PG : + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end + + PG_SUSP : + begin + if (falling_edge_write) + begin + if (Instruct == PGRS) + begin + next_state = PAGE_PG; + end + else + begin + next_state = PG_SUSP; + end + end + end + + OTP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + BULK_ERS : + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS : + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP : + begin + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + if (SectorSuspend != Address/(SecSize+1)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = ERS_SUSP_PG; + if ((Instruct==QPP || Instruct==QPP4) && + QPP_page[pgm_page] == 1) + begin + $display ("WARNING:The same page"); + $display (" must not be"); + $display (" programmed more"); + $display (" than once!!!"); + end + end + end + end + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == ERRS) + next_state = SECTOR_ERS; + else + next_state = ERS_SUSP; + end + end + + ERS_SUSP_PG : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = ERS_SUSP_PG_SUSP; + end + + ERS_SUSP_PG_SUSP : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + if (falling_edge_write) + begin + if (Instruct == PGRS) + begin + next_state = ERS_SUSP_PG; + end + else + begin + next_state = ERS_SUSP_PG_SUSP; + end + end + end + + PASS_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PASS_UNLOCK : + begin + if (falling_edge_PASSULCK_in) + next_state = IDLE; + end + + PPB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PPB_ERS : + begin + if (falling_edge_PPBERASE_in) + next_state = IDLE; + end + + AUTOBOOT_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PLB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + DYB_PG : + begin + if (rising_edge_PDONE) + if (ES) + next_state = ERS_SUSP; + else + next_state = IDLE; + end + + ASP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + NVDLR_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + endcase + end + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer WData [0:511]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(Instruct_event) + begin + read_cnt = 0; + byte_cnt = 1; + rd_fast = 1'b1; + dual = 1'b0; + rd_slow = 1'b0; + any_read = 1'b0; + end + + always @(rising_edge_read_out) + begin + if (rising_edge_read_out == 1'b1) + begin + if (PoweredUp == 1'b1) + begin + oe_z = 1'b1; + #1000 oe_z = 1'b0; + oe = 1'b1; + #1000 oe = 1'b0; + end + end + end + + always @(change_addr_event) + begin + if (change_addr_event) + begin + read_addr = Address; + end + end + + always @(posedge PASSACC_out) + begin + Status_reg1[0] = 1'b0; //WIP + PASSACC_in = 1'b0; + end + + always @(Instruct or posedge start_autoboot or oe or current_state_event or + falling_edge_write or posedge PDONE or posedge WDONE or oe_z or + posedge EDONE or ERSSUSP_out or rising_edge_Reseted or + rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or + Address) + begin: Functionality + integer i,j; + integer sect; + + if (rising_edge_PoweredUp) + begin + //the default condition after power-up + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + //The Configuration Register FREEZE bit is cleared. + Config_reg1[0] = 0; + //The WEL bit is cleared. + Status_reg1[1] = 0; + //When BPNV is set to '1'. the BP2-0 bits in Status Register are + //volatile and will be reset binary 111 after power-on reset + if (BPNV == 1 && LOCK == 0 && FREEZE == 0 ) + begin + Status_reg1[4] = 1'b0;// BP2 + Status_reg1[3] = 1'b0;// BP1 + Status_reg1[2] = 1'b0;// BP0 + BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + + //As shipped from the factory, all devices default ASP to the + //Persistent Protection mode, with all sectors unprotected, + //when power is applied. The device programmer or host system must + //then choose which sector protection method to use. + //For Persistent Protection mode, PPBLOCK defaults to "1" + PPBL[0] = 1'b1; + + //All the DYB power-up in the unprotected state + DYB_bits = {512{1'b1}}; + + end + + if (Instruct == RESET) + begin + //EXTADD is cleared to “0” + Bank_Addr_reg[7] = 1'b0; + //P_ERR bit is cleared + Status_reg1[6] = 1'b0; + //E_ERR bit is cleared + Status_reg1[5] = 1'b0; + //The WEL bit is cleared. + Status_reg1[1] = 1'b0; + //The WIP bit is cleared. + Status_reg1[0] = 1'b0; + //The ES bit is cleared. + Status_reg2[1] = 1'b0; + //The PS bit is cleared. + Status_reg2[0] = 1'b0; + //When BPNV is set to '1'. the BP2-0 bits in Status + //Register are volatile and will be reseted after + //reset command + if (BPNV == 1 && LOCK== 0 && FREEZE == 0) + begin + Status_reg1[4] = 1'b1; + Status_reg1[3] = 1'b1; + Status_reg1[2] = 1'b1; + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + case (current_state) + IDLE : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (falling_edge_write && RdPswdProtMode == 1) + begin + if(Instruct == PASSU) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + end + + if (falling_edge_write && RdPswdProtMode == 0) + begin + read_cnt = 0; + byte_cnt = 1; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 0; + else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 && + BAR_ACC == 0) + begin + if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD) + begin + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + // P_ERR bit is set to 1 + Status_reg1[6] = 1'b1; + end + else + begin + // can not execute if Hardware Protection Mode + // is entered or if WEL bit is zero + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + end + else + Status_reg1[1] = 0; + end + else if ((Instruct == PP || Instruct == PP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + QPP_page[pgm_page] = 1'b1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if (Instruct == OTPP && WEL == 1) + begin + // As long as the FREEZE bit remains cleared to a logic + // '0' the OTP address space is programmable. + if (FREEZE == 0) + begin + if (((((Address>= 16'h0010 && Address<= 16'h0013) || + (Address >= 16'h0020 && Address <= 16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address >= 16'h0100 && Address <= 16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32] == 1) || + ((Address >= 16'h0200 && Address <= 16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32] == 1) || + ((Address >= 16'h0300 && Address <= 16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) && + (Address + Byte_number <= OTPHiAddr)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else if ((Address < 8'h10 || (Address > 8'h13 && + Address < 8'h20) || Address > 12'h3FF )) + begin + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + if (Address < 8'h20) + begin + $display ("Given address is "); + $display ("in reserved address range"); + end + else if (Address > 12'h3FF) + begin + $display ("Given address is "); + $display ("out of OTP address range"); + end + end + else + begin + //P_ERR bit will be set when the user attempts to + // to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == SE || Instruct == SE4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + SectorSuspend = sect; + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + SecAddrERS = sect; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == P4E || Instruct == P4E4) && WEL == 1) + begin + Status_reg1[1] = 1'b0;//WEL + end + else if (Instruct == BE && WEL == 1) + begin + if (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + end + else + begin + //The Bulk Erase command will not set E_ERR if a + //protected sector is found during the command + //execution. + Status_reg1[1] = 1'b0;//WEL + end + end + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + $display ("Password programming is not allowed"); + $display (" in Password Protection Mode."); + end + end + else if (Instruct == PASSU && WEL) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == ASPP && WEL == 1) + begin + if (~(ASPOTPFLAG)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + $display ("Once the Protection Mode is selected,"); + $display ("no further changes to the ASP "); + $display ("register is allowed."); + end + end + else if (Instruct == ABWR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBP && WEL == 1) + begin + ReturnSectorID(sect,Address); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBERS && WEL == 1) + begin + if (PPBOTP) + begin + PPBERASE_in = 1'b1; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[5] = 1'b1; + end + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PNVDLR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == WVDLR && WEL == 1) + begin + VDLR_reg = VDLR_reg_in; + Status_reg1[1] = 1'b0; + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4 || + Instruct == RES || + (Instruct == DLPRD && RdPswdProtMode == 0)) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4 || + ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + else if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES + && VDLR_reg != 8'b00000000) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + ReturnSectorID(sect,read_addr); + SecAddr = sect; + SecAddr_tmp = SecAddr; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + SecAddr = SecAddr_tmp; + end + + READMEM(read_addr,SecAddr); + if (OutputD !== -1) + begin + data_out[7:0] = OutputD; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + ReturnSectorID(sect,read_addr); + SecAddr = sect; + SecAddr_tmp = SecAddr; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + SecAddr = SecAddr_tmp; + end + + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + && QUAD) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd = data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + ReturnSectorID(sect,read_addr); + SecAddr = sect; + SecAddr_tmp = SecAddr; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + SecAddr = SecAddr_tmp; + end + + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr + && RdPswdProtMode == 0) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + data_out[7:0] = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if ((read_addr > OTPHiAddr)||(RdPswdProtMode==1)) + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum or Read Password Protection Mode + //is selected instead, the data beyond the + //maximum OTP address will be undefined. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == REMS) + begin + //Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + data_out[7:0] = DeviceID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + else if (Instruct == RDID) + begin + ident_out = CFI_array_tmp; + if(read_cnt < 648) + begin + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + //Continued shifting of output beyond the end of + //the defined ID-CFI address space will + //provide undefined data. + SOut_zd = 1'bX; + end + end + else if (Instruct == RES) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + data_out = ESignature; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DLPRD && RdPswdProtMode == 0) + begin + //Read DLP + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = VDLR_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ABRD && RdPswdProtMode == 0) + begin + //Read AutoBoot register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = AutoBoot_reg[31-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 32) + read_cnt = 0; + end + else if (Instruct == BRRD && RdPswdProtMode == 0) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ASPRD && RdPswdProtMode == 0) + begin + //Read ASP Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = ASP_reg[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == PASSRD && RdPswdProtMode == 0) + begin + //Read Password Register + if (~(PWDMLB == 0 && PSTMLB == 1)) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = + Password_reg[(8*byte_cnt-1)-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + byte_cnt = byte_cnt + 1; + if (byte_cnt == 9) + byte_cnt = 1; + end + end + end + else if (Instruct == PLBRD) + begin + //Read PPB Lock Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = PPBL[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + DYBAR[7:0] = 8'bXXXXXXXX; + + if (RdPswdProtMode == 0) + begin + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + end + + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end + + AUTOBOOT: + begin + if (start_autoboot == 1) + begin + if (oe) + begin + any_read = 1'b1; + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + end + else if (oe_z) + begin + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + end + end + + WRITE_SR: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (WDONE == 1) + begin + Status_reg1[0] = 1'b0; //WIP + Status_reg1[1] = 1'b0; //WEL + //SRWD bit + Status_reg1[7] = Status_reg1_in[7]; //MSB first + + if (LOCK == 0) + begin + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT bit in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg1[4] = Status_reg1_in[4];//BP2 + Status_reg1[3] = Status_reg1_in[3];//BP1 + Status_reg1[2] = Status_reg1_in[2];//BP0 + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + if (TBPROT == 1'b0 && INITIAL_CONFIG == 1'b0) + begin + Config_reg1[5] = Config_reg1_in[5];//TBPROT + end + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + Config_reg1[7] = Config_reg1_in[7];//LC1 + Config_reg1[6] = Config_reg1_in[6];//LC0 + Config_reg1[1] = Config_reg1_in[1];//QUAD + + if (FREEZE == 1'b0) + begin + Config_reg1[0] = Config_reg1_in[0];//FREEZE + end + + if (WRLOCKENABLE== 1'b1 && LOCK == 1'b0) + begin + Config_reg1[4] = Config_reg1_in[4];//LOCK + WRLOCKENABLE = 1'b0; + end + if (BPNV == 1'b0) + begin + Config_reg1[3] = Config_reg1_in[3];//BPNV + end + end + end + + PAGE_PG : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == PAGE_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + ReturnSectorID(sect,read_addr); + SecAddr = sect; + memory_features_i0.read_mem_w( + mem_data, + Addr + i - cnt + ); + if (corrupt_Sec[SecAddr]) + begin + if (mem_data== MaxData+1) + mem_data = MaxData; + else if (mem_data == MaxData) + mem_data = -1; + end + old_int = mem_data; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + memory_features_i0.write_mem_w( + Addr + i -cnt, + -1 + ); + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt = 0; + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + memory_features_i0.write_mem_w( + Addr_tmp + i -cnt, + WData[i] + ); + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + PDONE = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd=data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd =data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + OTP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == OTP_PG) + begin + if (~PDONE) + begin + if (Address + wr_cnt <= OTPHiAddr) + begin + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = OTPMem[Addr + i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + OTPMem[Addr + i] = -1; + end + end + else + begin + $display ("Programming will reach over "); + $display ("address limit of OTP array"); + end + end + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + OTPMem[Addr + i] = WData[i]; + end + LOCK_BYTE1 = OTPMem[16]; + LOCK_BYTE2 = OTPMem[17]; + LOCK_BYTE3 = OTPMem[18]; + LOCK_BYTE4 = OTPMem[19]; + end + end + + SECTOR_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == SECTOR_ERS) + begin + if (~EDONE) + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + memory_features_i0.erase_mem_w( + AddrLo, + AddrHi + ); + corrupt_Sec[SecAddrERS] = 1; + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + corrupt_Sec[SecAddrERS] = 0; + end + else if (Instruct == ERSP && ~ERSSUSP_in) + begin + ESUSP = 1'b1; + ESUSP <= #5 1'b0; + ERSSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + end + + BULK_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == BULK_ERS) + begin + if (~EDONE) + begin + for (i=SecNum; i>=0; i=i-1) + begin + if (PPB_bits[i] == 1 && DYB_bits[i] == 1) + begin + memory_features_i0.erase_mem_w( + i*(SecSize+1), + i*(SecSize+1)+SecSize + ); + corrupt_Sec[i] = 1; + end + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (j=0; j<=SecNum; j=j+1) + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + corrupt_Sec[j] = 0; + end + end + end + + ERS_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (ERSSUSP_out == 1) + begin + ERSSUSP_in = 0; + //The Erase Suspend (ES) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //erase operation has been suspended. + Status_reg2[1] = 1'b1; + //The WIP bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (SectorSuspend != read_addr/(SecSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (SectorSuspend != read_addr/(SecSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (SectorSuspend != read_addr/(SecSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd=data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + ReturnSectorID(sect,read_addr); + SecAddr = sect; + READMEM(read_addr,SecAddr); + data_out[7:0] = OutputD; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == PP4) && WEL == 1) + begin + if (SectorSuspend != Address/(SecSize+1)) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL == 1) + begin + if (SectorSuspend != Address/(SecSize+1)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + + if (Sec_Prot[sect] == 0 + && PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + QPP_page[pgm_page] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == ERRS) + begin + Status_reg2[1] = 1'b0; + Status_reg1[0] = 1'b1; + Addr = SectorSuspend*(SecSize+1); + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + ERES = 1'b1; + ERES <= #5 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == ERS_SUSP_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + ReturnSectorID(sect,read_addr); + SecAddr = sect; + memory_features_i0.read_mem_w( + mem_data, + Addr + i - cnt + ); + if (corrupt_Sec[SecAddr]) + begin + if (mem_data== MaxData+1) + mem_data = MaxData; + else if (mem_data == MaxData) + mem_data = -1; + end + old_int = mem_data; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt =0; + end + + if(PDONE == 1) + begin + Status_reg1[0] = 1'b0;//WIP + Status_reg1[1] = 1'b0;//WEL + for (i=0;i<=wr_cnt;i=i+1) + begin + memory_features_i0.write_mem_w( + Addr_tmp + i -cnt, + WData[i] + ); + if ((Addr_tmp + i) == AddrHi ) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PASS_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + new_pass = Password_reg_in; + old_pass = Password_reg; + for (i=0;i<=63;i=i+1) + begin + if (old_pass[j] == 0) + new_pass[j] = 0; + end + + if (PDONE == 1) + begin + Password_reg = new_pass; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PASS_UNLOCK: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PASS_TEMP == Password_reg) + begin + PASS_UNLOCKED = 1'b1; + end + else + begin + PASS_UNLOCKED = 1'b0; + end + if (PASSULCK_out == 1'b1) + begin + if ((PASS_UNLOCKED == 1'b1) && (~PWDMLB)) + begin + PPBL[0] = 1'b1; + Status_reg1[0] = 1'b0; //WIP + end + else + begin + Status_reg1[6] = 1'b1; + $display ("Incorrect Password"); + PASSACC_in = 1'b1; + end + Status_reg1[1] = 1'b0; + PASSULCK_in = 1'b0; + end + end + + PPB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (PPB_LOCK !== 0) + begin + PPB_bits[sect]= 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[5] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + end + + PPB_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PPBERASE_out == 1'b1) + begin + if ((PPB_LOCK !== 0) && PPBOTP) + begin + PPB_bits = {512{1'b1}}; + end + else + begin + Status_reg1[5] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + PPBERASE_in = 1'b0; + end + end + + AUTOBOOT_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + AutoBoot_reg = AutoBoot_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PLB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + PPBL[0] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + DYB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + DYBAR = DYBAR_in; + if (DYBAR == 8'hFF) + begin + DYB_bits[sect]= 1'b1; + end + else if (DYBAR == 8'h00) + begin + DYB_bits[sect]= 1'b0; + end + else + begin + Status_reg1[6] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + ASP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + + if (RPME == 1'b0 && ASP_reg_in[5] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("RPME bit is allready programmed"); + end + else + begin + ASP_reg[5] = ASP_reg_in[5];//RPME + end + + if (PPBOTP == 1'b0 && ASP_reg_in[3] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("PPBOTP bit is allready programmed"); + end + else + begin + ASP_reg[3] = ASP_reg_in[3];//PPBOTP + end + + if (PWDMLB == 1'b1 && PSTMLB == 1'b1) + begin + if (ASP_reg_in[2] == 1'b0 && ASP_reg_in[1] == 1'b0) + begin + $display("ASPR[2:1] = 00 Illegal condition"); + Status_reg1[6] = 1'b1; //P_ERR + end + else + begin + if (ASP_reg_in[2]!==1'b1 || ASP_reg_in[1]!==1'b1) + begin + ASPOTPFLAG = 1'b1; + end + ASP_reg[2] = ASP_reg_in[2];//PWDMLB + ASP_reg[1] = ASP_reg_in[1];//PSTMLB + end + end + + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + NVDLR_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (NVDLR_reg == 0) + begin + NVDLR_reg = NVDLR_reg_in; + VDLR_reg = NVDLR_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; //P_ERR + $display("NVDLR bits allready programmed"); + end + end + end + + RESET_STATE: + begin + //the default condition hardware reset + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + if (BPNV && ~LOCK && ~FREEZE) + begin + Status_reg1[2] = 1'b1;// BP0 + Status_reg1[3] = 1'b1;// BP1 + Status_reg1[4] = 1'b1;// BP2 + BP_bits = 3'b111; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + //Resets the volatile bits in the Status register 1 + Status_reg1[6] = 1'b0; + Status_reg1[5] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[0] = 1'b0; + //Resets the volatile bits in the Status register 2 + Status_reg2[1] = 1'b0; + Status_reg2[0] = 1'b0; + //Resets the volatile bits in the Configuration register 1 + Config_reg1[0] = 1'b0; + //On reset cycles the data pattern reverts back + //to what is in the NVDLR + VDLR_reg = NVDLR_reg; + dlp_act = 1'b0; + //Loads the Program Buffer with all ones + for(i=0;i<=511;i=i+1) + begin + WData[i] = MaxData; + end + if (~PWDMLB) + PPBL[0] = 1'b0; + else + PPBL[0] = 1'b1; + end + + endcase + + //Output Disable Control + if (CSNeg_ipd ) + begin + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign ddrd = ddr; + assign fast_ddr = ddr_fast; + + always @(posedge change_BP) + begin + case (Status_reg1[4:2]) + + 3'b000: + begin + Sec_Prot = 256'b0; + end + + 3'b001: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum:(SecNum+1)*63/64] = 4'b1111; + Sec_Prot[(SecNum+1)*63/64-1 : 0] = 252'h0; + end + else + begin + Sec_Prot[(SecNum+1)/64-1 : 0] = 4'b1111; + Sec_Prot[SecNum : (SecNum+1)/64] = 252'h0; + end + end + + 3'b010: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*31/32] = 8'b11111111; + Sec_Prot[(SecNum+1)*31/32-1 : 0] = 248'h0; + end + else + begin + Sec_Prot[(SecNum+1)/32-1 : 0] = 8'b11111111; + Sec_Prot[SecNum : (SecNum+1)/32] = 248'h0; + end + end + + 3'b011: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*15/16] = 16'hFFFF; + Sec_Prot[(SecNum+1)*15/16-1 : 0] = 240'h0; + end + else + begin + Sec_Prot[(SecNum+1)/16-1 : 0] = 16'hFFFF; + Sec_Prot[SecNum : (SecNum+1)/16] = 240'h0; + end + end + + 3'b100: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*7/8] = 32'hFFFFFFFF; + Sec_Prot[(SecNum+1)*7/8-1 : 0] = 224'h0; + end + else + begin + Sec_Prot[(SecNum+1)/8-1 : 0] = 32'hFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/8] = 224'h0; + end + end + + 3'b101: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*3/4] + = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[(SecNum+1)*3/4-1 : 0] = 192'h0; + end + else + begin + Sec_Prot[(SecNum+1)/4-1 : 0] = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/4] = 192'h0; + end + end + + 3'b110: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)/2] + = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + Sec_Prot[(SecNum+1)/2-1 : 0] = 128'h0; + end + else + begin + Sec_Prot[(SecNum+1)/2-1 : 0] + = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/2] = 128'h0; + end + end + + 3'b111: + begin + Sec_Prot[127:0] = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + Sec_Prot[255:128] = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + end + endcase + end + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // autoboot control logic + //////////////////////////////////////////////////////////////////////// + always @(rising_edge_SCK_ipd or current_state_event) + begin + if(current_state == AUTOBOOT) + begin + if (rising_edge_SCK_ipd) + begin + if (start_delay > 0) + start_delay = start_delay - 1; + end + + if (start_delay == 0) + begin + start_autoboot = 1; + end + end + end + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure FDDR_DPL + task Return_DLP; + input integer Instruct; + input integer EHP; + input integer Latency_code; + input integer dummy_cnt; + inout dlp_act; + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + if (EHP) + begin + if (Latency_code == 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b1; + else if (Latency_code == 0 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 1 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 3) + dlp_act = 1'b1; + end + end + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + if (EHP) + begin + if (Latency_code == 1 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if( Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b0; + else if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + end + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && QUAD) + begin + if (EHP) + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + end + end + endtask + + task READMEM; + input integer Address; + input integer SecAddr; + reg [15:0] ReadData; + begin + memory_features_i0.read_mem_w( + mem_data, + Address); + if (mem_data != -1) + begin + if (corrupt_Sec[SecAddr] == 1) + begin + if (mem_data == MaxData) + ReadData = 8'hx; + else if (mem_data == MaxData+1) + begin + mem_data = MaxData; + ReadData = mem_data; + end + else + ReadData = mem_data; + end + else + ReadData = mem_data; + end + else + ReadData = 8'bx; + + OutputD = ReadData; + end + endtask + + function integer ReturnSectorIDRdPswdMd; + input reg TBPROT; + begin + if(TBPROT == 0) + begin + ReturnSectorIDRdPswdMd = 0; + end + else + begin + ReturnSectorIDRdPswdMd = SecNum; + end + end + endfunction + + // Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr/(SecSize+1); + AddrLOW = sector*(SecSize+1); + AddrHIGH = sector*(SecSize+1) + SecSize; + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / (PageSize + 1); + AddrLOW = page * (PageSize + 1); + AddrHIGH = page * (PageSize + 1) + PageSize; + end + endtask + + // Procedure ReturnSectorID + task ReturnSectorID; + inout sect; + input Address; + integer sect; + integer Address; + integer conv; + begin + sect = Address/(SecSize+1); + end + endtask + + always @(PPBL[0], ASP_reg) + begin + if (PPBL[0] == 0 && PWDMLB == 0 && RPME == 0 && RdPswdProtEnable) + begin + RdPswdProtMode = 1; + AutoBoot_reg[0] = 0;//AUTOBOOT is disabled when Read Password + end //Protection is enabled + else + begin + RdPswdProtMode = 0; + end + end + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1; + #1000 falling_edge_write = 0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge RSTNeg_in) + begin + falling_edge_RSTNeg = 1'b1; + #50000 falling_edge_RSTNeg = 1'b0; + end + + always @(posedge RSTNeg_in) + begin + rising_edge_RSTNeg = 1'b1; + #10000 rising_edge_RSTNeg = 1'b0; + end + + always @(negedge RST) + begin + falling_edge_RST = 1'b1; + #10000 falling_edge_RST = 1'b0; + end + + always @(posedge RST) + begin + rising_edge_RST = 1'b1; + #1000 rising_edge_RST = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge Reseted) + begin + rising_edge_Reseted = 1'b1; + #1000 rising_edge_Reseted = 1'b0; + end + + always @(negedge PASSULCK_in) + begin + falling_edge_PASSULCK_in = 1'b1; + #1000 falling_edge_PASSULCK_in = 1'b0; + end + + always @(negedge PPBERASE_in) + begin + falling_edge_PPBERASE_in = 1'b1; + #1000 falling_edge_PPBERASE_in = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge RST_out) + begin + rising_edge_RST_out = 1'b1; + #1000 rising_edge_RST_out = 1'b0; + end + +endmodule +module memory_features(); +// ------------------------------------------------------------------------ +// ---------------- start of memory management section -------------- +// ------------------------------------------------------------------------ + + // memory partitioning parameters + parameter list_num = 256; + parameter list_size = 20'h40000; + // memory initial data value + parameter MaxData = 8'hFF; + + // memory management routines + // handle dynamic memory allocation + + // abstract memory region model + class linked_list_c; + // memory element model + reg[31:0] key_address; + integer val_data; + // organize memory storage elements into a linked list + linked_list_c successor; + + function new( + integer address_a, + integer data_a); + begin + key_address = address_a; + val_data = data_a; + successor = null; + end + endfunction + endclass + + // partition memory region for faster access + linked_list_c linked_list [list_num]; + // class methods internal communication pool + linked_list_c found; + linked_list_c prev; + linked_list_c sub_linked_list; + linked_list_c sub_linked_list_last; + + // low-level routines + class low_level_interface_c; + + // assure proper initialization + function new; + integer new_iter; + begin + // initialize linked list handles + for(new_iter=0; new_iter < list_num; new_iter = new_iter + 1) + linked_list[new_iter] = null; + found = null; + prev = null; + sub_linked_list = null; + sub_linked_list_last = null; + end + endfunction + + // Iterate through linked listed comapring key values + // Stop when key value greater or equal + task position_list( + input integer address_a, + input linked_list_c root); + begin + found = root; + prev = null; + while ((found != null) && (found.key_address < address_a)) + begin + prev = found; + found = found.successor; + end + end + endtask + + // Add new element to a linked list + task insert_list( + input integer address_a, + input integer data_a, + input integer list_id); + + linked_list_c new_element; + begin + this.position_list( + address_a, + linked_list[list_id]); + + // Insert at list tail + if (found == null) + begin + prev.successor = new(address_a, data_a); + end + else + begin + // Element exists, update memory data value + if (found.key_address == address_a) + begin + found.val_data = data_a; + end + else + begin + // No element found, allocate and link + new_element = new(address_a, data_a); + new_element.successor = found; + // Possible root position + if (prev != null) + begin + prev.successor = new_element; + end + else + begin + linked_list[list_id] = new_element; + end + end + end + end + endtask + + // Remove element from a linked list + task remove_list( + input integer address_a, + input integer list_id); + + begin + this.position_list( + address_a, + linked_list[list_id]); + + if (found != null) + // Key value match + if (found.key_address == address_a) + begin + // Handle root position removal + if (prev != null) + prev.successor = found.successor; + else + linked_list[list_id] = found.successor; + // garbage collector + found = null; + end + end + endtask + + // Remove range of elements from a linked list + // Higher performance than one-by-one removal + task remove_list_range( + input integer address_low, + input integer address_high, + input integer list_id); + linked_list_c iter; + linked_list_c prev_remove; + linked_list_c link_element; + integer flag_test; + begin + iter = linked_list[list_id]; + prev_remove = null; + flag_test = 1; + // Find first linked list element belonging to + // a specified address range [address_low, address_high] + if (iter != null) + while (flag_test == 1) + if (iter == null) + flag_test = 0; + else if (!((iter.key_address >= address_low) && + (iter.key_address <= address_high))) + begin + prev_remove = iter; + iter = iter.successor; + end + else + flag_test = 0; + // Continue until address_high reached + // Deallocate linked list elements pointed by iterator + if (iter != null) + begin + while ((iter != null) && + (iter.key_address >= address_low) && + (iter.key_address <= address_high)) + begin + link_element = iter.successor; + //garbage collector + iter.successor = null; + iter = link_element; + end + // Handle possible root value change + if ( prev_remove != null ) + prev_remove.successor = link_element; + else + linked_list[list_id] = link_element; + end + end + endtask + + endclass + + // higher-level routines + // provided memory RW operation class interface + class rw_interface_c; + + low_level_interface_c low_level_interface; + + // assure proper initialization + function new; + integer new_iter; + begin + // allocate low level interface object + low_level_interface = new; + end + endfunction + + task read_mem( + inout integer data_a, + input integer address_a); + + integer mem_data; + integer list_id; + begin + // Higher performance, segment paritioning + list_id = address_a / list_size; + if (linked_list[list_id] == null) + // Not allocated, not written, initial value + mem_data = MaxData; + else + begin + low_level_interface.position_list( + address_a, + linked_list[list_id]); + if (found != null) + begin + if (found.key_address == address_a) + // Allocated, val_data stored + mem_data = found.val_data; + else + // Not allocated, not written, initial value + mem_data = MaxData; + end + else + begin + // Not allocated, not written, initial value + mem_data = MaxData; + end + end + data_a = mem_data; + end + endtask + + // Memory WRITE operation performed above dynamically allocated space + task write_mem( + input integer address_a, + input integer data_a); + + integer list_id; + begin + // Higher performance, segment paritioning + list_id = address_a / list_size; + if (data_a !== MaxData) + begin + // Handle possible root value update + if (linked_list[list_id] !== null) + begin + low_level_interface.insert_list( + address_a, + data_a, + list_id); + end + else + begin + linked_list[list_id] = + new(address_a, data_a); + end + end + else + begin + // Deallocate if initial value written + // No linked list, NOP, initial value implicit + if (linked_list[list_id] !== null) + begin + low_level_interface.remove_list( + address_a, + list_id); + end + end + end + endtask + + // Address range to be erased + task erase_mem( + input integer address_low, + input integer address_high); + + integer list_id; + begin + list_id = address_low / list_size; + + low_level_interface.remove_list_range( + address_low, + address_high, + list_id + ); + end + endtask + + endclass + + // object declaration holding memory management model + rw_interface_c rw_interface; + + //interface towards higher hierarchy instances routine calls + //wrapped from within the memory_features module + //low-level routine access forbidden + task initialize_w; + begin + rw_interface = new; + end + endtask + + task read_mem_w( + inout integer data_a, + input integer address_a); + begin + rw_interface.read_mem(data_a, address_a); + end + endtask + + task write_mem_w( + input integer address_a, + input integer data_a); + begin + rw_interface.write_mem(address_a, data_a); + end + endtask + + task erase_mem_w( + input integer address_low, + input integer address_high); + begin + rw_interface.erase_mem(address_low, address_high); + end + endtask +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.v b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.v new file mode 100644 index 0000000..d4a8250 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.v @@ -0,0 +1,7523 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl512s.v +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2011 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 V.Mancev 19 Nov 09 Initial +// R.Prokopovic +// V1.1 V.Mancev 04 Mar 10 addr_cnt for second read in +// high performance read continuous +// mode can change its value only +// when CSNeg = '0' +// V1.2 V.Mancev 23 Mar 10 During read operations read_out +// signal changes its value in +// shorter interval +// V1.3 V.Mancev 12 Apr 10 HOLD mode corrected +// Condition for PP operation +// corrected +// V1.4 V.Mancev 20 May 10 SRWD bit assignment is corrected +// Condition for WRR command in +// write_cycle _decode section is +// corrected +// Blocking assignments for signals +// WSTART and PSTART are replaced +// with nonblocking assignments +// Conditions in Page Program +// section are fixed +// V1.5 V.Mancev 25 May 10 Conditions in programming +// sections are fixed +// Timing control sections for +// Program and Erase operation are +// changed +// V1.6 V.Mancev 03 June 10 bus_cycle_state section for +// PGSP command is fixed +// V1.7 V.Mancev 28 July 10 During the QUAD mode HOLD# input +// is not monitored for its normal +// function +// write cycle decode section is +// changed +// V1.8 B.Colakovic 24 Aug 10 All redundant signals are +// removed from BusCycle process +// V1.9 V.Mancev 05 Nov 10 Latest datasheet aligned +// B.Colakovic +// V2.0 H.Dimitrijevic 15 Nov 10 QUAD Program operation during +// Erase Suspend is added. +// Warning for Resume to Suspend +// time is added. +// During Erase Suspend, after +// Program operation is completed, +// WEL bit is cleared. +// Implemetation of Software Reset +// is Changed. +// V2.1 S.Petrovic 18 Apr 11 Corrected timing in always block +// that generates +// rising_edge_CSNeg_ipd +// V2.2 V.Mancev 11 July 11 Latest datasheet aligned +// B.Colakovic +// V2.3 B.Colakovic 15 July 11 Optimization issue is fixed +// V2.4 V.Mancev 22 July 11 Timing check issue is fixed +// B.Colakovic +// V2.5 V. Mancev 18 Nov 11 Time tHO is changed to 1 ns +// (customer's request) +// BRWR instruction is corrected +// V2.6 S.Petrovic 02 Jun 12 QPP Instruction is allowed on +// previously programmed page +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL512S +// +// Description: 512 Megabit Serial Flash Memory +// +////////////////////////////////////////////////////////////////////////////// +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// A device ordering (trim) option determines whether a feature is enabled +// or not, or provide relevant parameters: +// -15th character in TimingModel determines if enhanced high +// performance option is available +// (0,2,3,R,A,B,C,D) EHPLC +// (Y,Z,S,T,K,L) Security EHPLC +// (4,6,7,8,9,Q) HPLC +// -15th character in TimingModel determines if RESET# input +// is available +// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +// state,inside the package. +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl512s + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + RSTNeg , + WPNeg , + HOLDNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + + inout SI ; + inout SO ; + + input SCK ; + input CSNeg ; + input RSTNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire RSTNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire RSTNeg_in ; + //Internal pull-up + assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd; + + // internal delays + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg WRR_in ; + reg WRR_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg PU_in ; + reg PU_out ; + reg RST_in ; + reg RST_out ; + reg PPBERASE_in ; + reg PPBERASE_out; + reg PASSULCK_in ; + reg PASSULCK_out; + reg PASSACC_in ; + reg PASSACC_out; + + // event control registers + reg PRGSUSP_out_event; + reg ERSSUSP_out_event; + reg Reseted_event; + reg SCK_ipd_event; + reg next_state_event; + + reg rising_edge_PoweredUp; + reg rising_edge_Reseted; + reg rising_edge_PASSULCK_in; + reg rising_edge_RES_out; + reg rising_edge_PSTART; + reg rising_edge_WSTART; + reg rising_edge_ESTART; + reg rising_edge_RSTNeg; + reg rising_edge_RST; + reg falling_edge_RSTNeg; + reg falling_edge_RST; + reg rising_edge_RST_out; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg RST ; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl512s.mem"; + parameter otp_file_name = "s25fl512sOTP.mem";//"none"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl512s"; + parameter MaxData = 255; + parameter MemSize = 28'h3FFFFFF; + parameter SecSize = 20'h3FFFF; + parameter SecNum = 255; + parameter PageNum = 17'h1FFFF; + parameter AddrRANGE = 28'h3FFFFFF; + parameter HiAddrBit = 31; + parameter OTPSize = 1023; + parameter OTPLoAddr = 12'h000; + parameter OTPHiAddr = 12'h3FF; + parameter BYTE = 8; + + // Manufacturer Identification + parameter Manuf_ID = 8'h01; + parameter DeviceID = 8'h19; + // Electronic Signature + parameter ESignature = 8'h19; + // Device ID + //Manufacturer Identification && Memory Type && Memory Capacity + parameter Jedec_ID = 8'h01; + parameter DeviceID1 = 8'h02; + parameter DeviceID2 = 8'h20; + parameter ExtendedBytes = 8'h4D; + parameter ExtendedID = 8'h00; + parameter DieRev = 8'h00; + parameter MaskRev = 8'h00; + + integer PageSize = 511; + + integer EHP; //Enhanced High Performance Mode active + + integer BAR_ACC = 0; //Bank Register Access active + + //varaibles to resolve architecture used + reg [24*8-1:0] tmp_timing;//stores copy of TimingModel + reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode + integer found = 1'b0; + + // If speedsimulation is needed uncomment following line + +// `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; + + reg RES_TO_SUSP_MIN_TIME; + reg RES_TO_SUSP_TYP_TIME; + + reg WDONE ; + reg WSTART ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + + reg Reseted ; + + // Lock Bit is enabled for customer programming + reg WRLOCKENABLE = 1'b1; + // Flag that mark if ASP Register is allready programmed + reg ASPOTPFLAG = 1'b0; + + //Flag for Password unlock command + reg PASS_UNLOCKED = 1'b0; + reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF; + + reg QUADRD = 1'b0; + reg INITIAL_CONFIG = 1'b0; + reg CHECK_FREQ = 1'b0; + + // Programming buffer + integer WByte[0:511]; + // CFI array + integer CFI_array[8'h00:8'h50]; + // OTP Memory Array + integer OTPMem[OTPLoAddr:OTPHiAddr]; + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // VDLR Register + reg[7:0] VDLR_reg = 8'h00; + reg[7:0] VDLR_reg_in = 8'h00; + // NVDLR Register + reg[7:0] NVDLR_reg = 8'h00; + reg[7:0] NVDLR_reg_in = 8'h00; + reg dlp_act = 1'b0; + + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRWD ; + wire P_ERR; + wire E_ERR; + wire [2:0]BP; + wire WEL; + wire WIP; + assign SRWD = Status_reg1[7]; + assign P_ERR = Status_reg1[6]; + assign E_ERR = Status_reg1[5]; + assign BP = Status_reg1[4:2]; + assign WEL = Status_reg1[1]; + assign WIP = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire ES ; + wire PS ; + assign ES = Status_reg2[1]; + assign PS = Status_reg2[0]; + + // Configuration Register 1 + reg[7:0] Config_reg1 = 8'h00; + reg[7:0] Config_reg1_in = 8'h00; + + wire LC1 ; + wire LC0 ; + wire TBPROT ; + wire LOCK ; + wire BPNV ; + wire QUAD ; + wire FREEZE ; + assign LC1 = Config_reg1[7]; + assign LC0 = Config_reg1[6]; + assign TBPROT = Config_reg1[5]; + assign LOCK = Config_reg1[4]; + assign BPNV = Config_reg1[3]; + assign QUAD = Config_reg1[1]; + assign FREEZE = Config_reg1[0]; + + // Autoboot Register + reg[31:0] AutoBoot_reg = 32'h00000000; + reg[31:0] AutoBoot_reg_in = 32'h00000000; + + wire ABE; + assign ABE = AutoBoot_reg[0]; + + // Bank Address Register + reg [7:0] Bank_Addr_reg = 8'h00; + reg [7:0] Bank_Addr_reg_in = 8'h00; + + wire EXTADD; + wire BA25; + wire BA24; + + assign EXTADD = Bank_Addr_reg[7]; + assign BA25 = Bank_Addr_reg[1]; + assign BA24 = Bank_Addr_reg[0]; + + // ASP Register + reg[15:0] ASP_reg; + reg[15:0] ASP_reg_in; + + wire RPME ; + wire PPBOTP ; + wire PWDMLB ; + wire PSTMLB ; + assign RPME = ASP_reg[5]; + assign PPBOTP = ASP_reg[3]; + assign PWDMLB = ASP_reg[2]; + assign PSTMLB = ASP_reg[1]; + + // Password register + reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF; + reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF; + + // PPB Lock Register + reg[7:0] PPBL = 8'h00; + reg[7:0] PPBL_in = 8'h00; + + wire PPB_LOCK ; + assign PPB_LOCK = PPBL[0]; + + // PPB Access Register + reg[7:0] PPBAR = 8'hFF; + reg[7:0] PPBAR_in = 8'hFF; + + reg[SecNum:0] PPB_bits = {512{1'b1}}; + + // DYB Access Register + reg[7:0] DYBAR = 8'hFF; + reg[7:0] DYBAR_in = 8'hFF; + + reg[SecNum:0] DYB_bits = {512{1'b1}}; + + //The Lock Protection Registers for OTP Memory space + reg[7:0] LOCK_BYTE1; + reg[7:0] LOCK_BYTE2; + reg[7:0] LOCK_BYTE3; + reg[7:0] LOCK_BYTE4; + + // Command Register + reg write; + reg cfg_write; + reg read_out; + reg dual = 1'b0; + reg rd_fast = 1'b1; + reg rd_slow = 1'b0; + reg ddr = 1'b0; + reg ddr_fast = 1'b0; + reg hold_mode = 1'b0; + reg any_read = 1'b0; + reg quad_pg = 1'b0; + + wire rd ; + wire fast_rd ; + wire ddrd ; + wire fast_ddr ; + + wire quadpg ; + assign quadpg = quad_pg; + + wire RD_EQU_1; + assign RD_EQU_1 = any_read; + + wire RD_EQU_0; + assign RD_EQU_0 = ~any_read; + + reg change_BP = 0; + reg [2:0] BP_bits = 3'b0; + + reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag + + reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag + reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag + + integer Byte_number = 0; + + reg oe = 1'b0; + reg oe_z = 1'b0; + + reg [647:0] CFI_array_tmp ; + reg [7:0] CFI_tmp; + + integer start_delay; + reg start_autoboot; + integer ABSD; + + reg change_addr ; + integer Address = 0; + integer SectorSuspend = 0; + + //Sector and subsector addresses + integer SA = 0; + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [SecNum:0] Sec_Prot = 512'b0; + + // Page Number for QPP operations + reg[PageNum:0] QPP_page = 0; + + // timing check violation + reg Viol = 1'b0; + + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + reg[63:0] old_pass; + reg[63:0] new_pass; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer byte_cnt = 1; + integer read_addr = 0; + integer read_addr_tmp = 0; + integer Sec_addr = 0; + integer SecAddr = 0; + integer Page_addr = 0; + integer pgm_page = 0; + + reg[7:0] data_out; + reg[647:0] ident_out; + + time SCK_cycle = 0; + time prev_SCK; + time start_ddr; + time out_time; + time SCK_SO_DDR; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (RSTNeg_ipd, RSTNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + //VHDL VITAL CheckEnable equivalents + wire quad_rd; + assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz); + wire wr_prot; + assign wr_prot = SRWD && WEL && ~QUAD; + wire dual_rd; + assign dual_rd = dual ; + wire ddro; + assign ddro = ddr && ~dual ; + wire ddr_rd; + assign ddr_rd = PoweredUp && ddr; + wire sdr_rd; + assign sdr_rd = PoweredUp && ~ddr; + +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_normal =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + specparam tpd_RSTNeg_SO =1; + //DDR operation values + specparam tpd_SCK_SO_DDR =1; + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; + specparam tsetup_SI_SCK_normal =1; + specparam tsetup_WPNeg_CSNeg =1; + specparam tsetup_HOLDNeg_SCK =1; + specparam tsetup_RSTNeg_CSNeg =1; + // DDR operation values + specparam tsetup_SI_SCK_DDR =1; + specparam tsetup_SI_SCK_DDR_fast =1; + specparam tsetup_CSNeg_SCK_DDR =1; + + //thold values: hold times + specparam thold_CSNeg_SCK =1; + specparam thold_SI_SCK_normal =1; + specparam thold_WPNeg_CSNeg =1; + specparam thold_HOLDNeg_SCK =1; + specparam thold_CSNeg_RSTNeg =1; + // DDR operation values + specparam thold_SI_SCK_DDR =1; + specparam thold_SI_SCK_DDR_fast =1; + specparam thold_CSNeg_SCK_DDR =1; + + // tpw values: pulse width + specparam tpw_SCK_serial_posedge =1; + specparam tpw_SCK_dual_posedge =1; + specparam tpw_SCK_fast_posedge =1; + specparam tpw_SCK_quadpg_posedge =1; + specparam tpw_SCK_serial_negedge =1; + specparam tpw_SCK_dual_negedge =1; + specparam tpw_SCK_fast_negedge =1; + specparam tpw_SCK_quadpg_negedge =1; + specparam tpw_CSNeg_read_posedge =1; + specparam tpw_CSNeg_pgers_posedge =1; + specparam tpw_RSTNeg_negedge =1; + specparam tpw_RSTNeg_posedge =1; + // DDR operation values + specparam tpw_SCK_DDR_posedge =1; + specparam tpw_SCK_DDR_negedge =1; + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_serial_rd =1;// 50 MHz + specparam tperiod_SCK_fast_rd =1;//133 MHz + specparam tperiod_SCK_dual_rd =1;//104 MHz + specparam tperiod_SCK_quadpg =1;// 80 MHz + // DDR operation values + specparam tperiod_SCK_DDR_rd =1;// 66 MHz + + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE = 1875e7;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 460e9;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e9;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `else + // Page Program Operation + specparam tdevice_PP_256 = 55e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE = 1875e9;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 460e12;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e11;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~ddr) (SCK => SO) = tpd_SCK_SO_normal; + if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR; + + if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal; + if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR; + + if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR; + if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR; + + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO; + + if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; + if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO; + + if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + (RSTNeg => SO) = tpd_RSTNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& sdr_rd, + tsetup_CSNeg_SCK, Viol); + $setup ( CSNeg , posedge SCK &&& ddr_rd, + tsetup_CSNeg_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK_normal, Viol); + $setup ( WPNeg , negedge CSNeg &&& wr_prot, + tsetup_WPNeg_CSNeg, Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_rd, + tsetup_HOLDNeg_SCK, Viol); + $setup ( SI , posedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + + $setup ( RSTNeg , negedge CSNeg, + tsetup_RSTNeg_CSNeg, Viol); + + $hold ( posedge SCK &&& sdr_rd , CSNeg, + thold_CSNeg_SCK, Viol); + $hold ( posedge SCK &&& ddr_rd , CSNeg, + thold_CSNeg_SCK_DDR, Viol); + $hold ( posedge SCK &&& deg_sin , SI , + thold_SI_SCK_normal, Viol); + $hold ( posedge CSNeg &&& wr_prot , WPNeg , + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK &&& quad_rd , HOLDNeg , + thold_HOLDNeg_SCK, Viol); + $hold ( posedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + + $hold ( negedge RSTNeg , CSNeg, + thold_CSNeg_RSTNeg, Viol); + + $width ( posedge SCK &&& rd , tpw_SCK_serial_posedge); + $width ( negedge SCK &&& rd , tpw_SCK_serial_negedge); + $width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge); + $width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge); + $width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge); + $width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge); + + $width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge); + $width ( negedge RSTNeg , tpw_RSTNeg_negedge); + $width ( posedge RSTNeg , tpw_RSTNeg_posedge); + + $period ( posedge SCK &&& rd , tperiod_SCK_serial_rd); + $period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); + $period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); + $period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg); + $period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 5'd0; + parameter RESET_STATE = 5'd1; + parameter AUTOBOOT = 5'd2; + parameter WRITE_SR = 5'd3; + parameter PAGE_PG = 5'd4; + parameter OTP_PG = 5'd5; + parameter PG_SUSP = 5'd6; + parameter SECTOR_ERS = 5'd7; + parameter BULK_ERS = 5'd8; + parameter ERS_SUSP = 5'd9; + parameter ERS_SUSP_PG = 5'd10; + parameter ERS_SUSP_PG_SUSP= 5'd11; + parameter PASS_PG = 5'd12; + parameter PASS_UNLOCK = 5'd13; + parameter PPB_PG = 5'd14; + parameter PPB_ERS = 5'd15; + parameter AUTOBOOT_PG = 5'd16; + parameter ASP_PG = 5'd17; + parameter PLB_PG = 5'd18; + parameter DYB_PG = 5'd19; + parameter NVDLR_PG = 5'd20; + + reg [4:0] current_state; + reg [4:0] next_state; + +// Instruction type + parameter NONE = 7'd0; + parameter WRR = 7'd1; + parameter PP = 7'd2; + parameter READ = 7'd3; + parameter WRDI = 7'd4; + parameter RDSR = 7'd5; + parameter WREN = 7'd6; + parameter RDSR2 = 7'd7; + parameter FSTRD = 7'd8; + parameter FSTRD4 = 7'd9; + parameter DDRFR = 7'd10; + parameter DDRFR4 = 7'd11; + parameter PP4 = 7'd12; + parameter RD4 = 7'd13; + parameter ABRD = 7'd14; + parameter ABWR = 7'd15; + parameter BRRD = 7'd16; + parameter BRWR = 7'd17; + parameter P4E = 7'd18; + parameter P4E4 = 7'd19; + parameter ASPRD = 7'd20; + parameter ASPP = 7'd21; + parameter CLSR = 7'd22; + parameter QPP = 7'd23; + parameter QPP4 = 7'd24; + parameter RDCR = 7'd25; + parameter DOR = 7'd26; + parameter DOR4 = 7'd27; + parameter DLPRD = 7'd28; + parameter OTPP = 7'd29; + parameter PNVDLR = 7'd30; + parameter OTPR = 7'd31; + parameter WVDLR = 7'd32; + parameter BE = 7'd33; + parameter QOR = 7'd34; + parameter QOR4 = 7'd35; + parameter ERSP = 7'd36; + parameter ERRS = 7'd37; + parameter PGSP = 7'd38; + parameter PGRS = 7'd39; + parameter REMS = 7'd40; + parameter RDID = 7'd41; + parameter MPM = 7'd42; + parameter PLBWR = 7'd43; + parameter PLBRD = 7'd44; + parameter RES = 7'd45; + parameter DIOR = 7'd46; + parameter DIOR4 = 7'd47; + parameter DDRDIOR = 7'd48; + parameter DDRDIOR4 = 7'd49; + parameter SE = 7'd50; + parameter SE4 = 7'd51; + parameter DYBRD = 7'd52; + parameter DYBWR = 7'd53; + parameter PPBRD = 7'd54; + parameter PPBP = 7'd55; + parameter PPBERS = 7'd56; + parameter PASSRD = 7'd57; + parameter PASSP = 7'd58; + parameter PASSU = 7'd69; + parameter QIOR = 7'd70; + parameter QIOR4 = 7'd71; + parameter DDRQIOR = 7'd72; + parameter DDRQIOR4 = 7'd73; + parameter RESET = 7'd74; + parameter MBR = 7'd75; + parameter BRAC = 7'd76; + + reg [6:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SO_in, SO_z) + begin + if (SO_in==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_pin=deq_pin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_sin=deq_sin + && (ddr == 1'b0) && (Instruct !== DDRFR) + && (Instruct !== DDRFR4) && (Instruct !== DDRDIOR) + && (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR) + && (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz); + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + initial + begin : Init + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + cnt = 0; + RST = 1'b0; + RST_in = 1'b0; + RST_out = 1'b1; + PDONE = 1'b1; + PSTART = 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + PRGSUSP_in = 1'b0; + ERSSUSP_in = 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + Reseted = 1'b0; + + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl512s.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl512s_otp memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at OTPMem(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + + LOCK_BYTE1[7:0] = OTPMem[16]; + LOCK_BYTE2[7:0] = OTPMem[17]; + LOCK_BYTE3[7:0] = OTPMem[18]; + LOCK_BYTE4[7:0] = OTPMem[19]; + end + + // initialize memory and load preload files if any + initial + begin: InitTimingModel + integer i; + integer j; + //UNIFORM OR HYBRID arch model is used + //assumptions: + //1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF + //it is important that 16-th character from first one is "0" or "1" + //2. TimingModel does not have more then 24 characters + tmp_timing = TimingModel;//copy of TimingModel + + i = 23; + while ((i >= 0) && (found != 1'b1))//search for first non null character + begin //i keeps position of first non null character + j = 7; + while ((j >= 0) && (found != 1'b1)) + begin + if (tmp_timing[i*8+j] != 1'd0) + found = 1'b1; + else + j = j-1; + end + i = i - 1; + end + i = i +1; + if (found)//if non null character is found + begin + for (j=0;j<=7;j=j+1) + begin + //EHPLC/HPLC character is 15 + tmp_char1[j] = TimingModel[(i-14)*8+j]; + end + end + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" || + tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L") + begin + EHP = 1; + if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y") + begin + RdPswdProtEnable = 1; + end + end + else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" || + tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q") + begin + EHP = 0; + end + + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" || + tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" || + tmp_char1 == "9" || tmp_char1 == "Q") + begin + ASP_reg = 16'hFE7F; + ASP_reg_in = 16'hFE7F; + end + else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" || + tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L") + begin + ASP_reg = 16'hFE4F; + ASP_reg_in = 16'hFE4F; + end + + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + /////////////////////////////////////////////////////////////////////// + // ID-CFI array data + /////////////////////////////////////////////////////////////////////// + // Manufacturer and Device ID + CFI_array[8'h00] = Jedec_ID; + CFI_array[8'h01] = DeviceID1; + CFI_array[8'h02] = DeviceID2; + CFI_array[8'h03] = 8'h00; + // Uniform 256kB sectors + CFI_array[8'h04] = ExtendedID; + CFI_array[8'h05] = 8'h80; + CFI_array[8'h06] = 8'h00; + CFI_array[8'h07] = 8'h00; + CFI_array[8'h08] = 8'h00; + CFI_array[8'h09] = 8'h00; + CFI_array[8'h0A] = 8'h00; + CFI_array[8'h0B] = 8'h00; + CFI_array[8'h0C] = 8'h00; + CFI_array[8'h0D] = 8'h00; + CFI_array[8'h0E] = 8'h00; + CFI_array[8'h0F] = 8'h00; + // CFI Query Identification String + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h53; + CFI_array[8'h18] = 8'h46; + CFI_array[8'h19] = 8'h51; + CFI_array[8'h1A] = 8'h00; + //CFI system interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h06; + //512B page + CFI_array[8'h20] = 8'h09; + // 256kB sector + CFI_array[8'h21] = 8'h09; + CFI_array[8'h22] = 8'h11; + CFI_array[8'h23] = 8'h02; + CFI_array[8'h24] = 8'h02; + CFI_array[8'h25] = 8'h03; + CFI_array[8'h26] = 8'h03; + // Device Geometry Definition(Uniform Sector Devices) + CFI_array[8'h27] = 8'h1A; + CFI_array[8'h28] = 8'h02; + CFI_array[8'h29] = 8'h01; + CFI_array[8'h2A] = 8'h09; + CFI_array[8'h2B] = 8'h00; + CFI_array[8'h2C] = 8'h01; + CFI_array[8'h2D] = 8'hFF; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h04; + CFI_array[8'h31] = 8'hFF; + CFI_array[8'h32] = 8'hFF; + CFI_array[8'h33] = 8'hFF; + CFI_array[8'h34] = 8'hFF; + CFI_array[8'h35] = 8'hFF; + CFI_array[8'h36] = 8'hFF; + CFI_array[8'h37] = 8'hFF; + CFI_array[8'h38] = 8'hFF; + CFI_array[8'h39] = 8'hFF; + CFI_array[8'h3A] = 8'hFF; + CFI_array[8'h3B] = 8'hFF; + CFI_array[8'h3C] = 8'hFF; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + // CFI Primary Vendor-Specific Extended Query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h21; + CFI_array[8'h46] = 8'h02; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h08; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h04; + CFI_array[8'h4D] = 8'h00; + CFI_array[8'h4E] = 8'h00; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h01; + + begin + for(i=80;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h00-i+80]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + end + + always @(next_state_event or PoweredUp or RST or RST_out) + begin: StateTransition + if (PoweredUp) + begin + if ((RSTNeg_in) && RST_out == 1'b1) + current_state = #(1000) next_state; + else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST) + begin + // no state transition while RESET# low + current_state = RESET_STATE; + RST_in = 1'b1; + #1000 RST_in = 1'b0; + end + end + end + + always @(posedge RST_in) + begin:Threset + RST_out = 1'b0; + #(35000000-200000) RST_out = 1'b1; + end + + always @(negedge CSNeg_ipd) + begin:CheckCEOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_PRGSUSP PRGSUSP_out = 1'b1; + end + + always @(posedge PPBERASE_in) + begin:PPBErs + PPBERASE_out = 1'b0; + #tdevice_PPBERASE PPBERASE_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_ERSSUSP ERSSUSP_out = 1'b1; + end + + always @(posedge PASSULCK_in) + begin:PASSULock + PASSULCK_out = 1'b0; + #tdevice_PASSULCK PASSULCK_out = 1'b1; + end + + always @(posedge PASSACC_in) + begin:PASSAcc + PASSACC_out = 1'b0; + #tdevice_PASSACC PASSACC_out = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [7:0] opcode_in; + reg [7:0] opcode_tmp; + reg [31:0] addr_bytes; + reg [31:0] hiaddr_bytes; + reg [31:0] Address_in; + reg [7:0] mode_bytes; + reg [7:0] mode_in; + integer Latency_code; + integer quad_data_in [0:1023]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle + integer i; + integer j; + integer k; + time CLK_PER; + time LAST_CLK; + + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + Instruct = NONE; + write = 1'b1; + cfg_write = 0; + opcode_cnt = 0; + addr_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + data_cnt = 0; + opcode_tmp = 0; + DOUBLE = 1'b0; + QUADRD = 1'b0; + CLK_PER = 1'b0; + LAST_CLK = 1'b0; + if (current_state == AUTOBOOT) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = OPCODE_BYTE; + end + end + end + + if (rising_edge_SCK_ipd) // Instructions, addresses or data present + begin // at SI are latched on the rising edge of SCK + + CLK_PER = $time - LAST_CLK; + LAST_CLK = $time; + if (CHECK_FREQ) + begin + if ((CLK_PER < 20000 && Latency_code == 3) || + (CLK_PER < 12500 && Latency_code == 0) || + (CLK_PER < 11100 && Latency_code == 1) || + (CLK_PER < 9600 && Latency_code == 2)) + begin + $display ("More wait states are required for"); + $display ("this clock frequency value"); + end + CHECK_FREQ = 0; + end + + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + Latency_code = Config_reg1[7:6]; + if (opcode_cnt == BYTE) + begin + for(i=7;i>=0;i=i-1) + begin + opcode[i] = opcode_in[7-i]; + end + case (opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010011 : // 13h + begin + Instruct = RD4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : // 4Bh + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000111 : // 07h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 35h + begin + Instruct = RDCR; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : // 90h + begin + Instruct = REMS; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : // 9Fh + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011 : // ABh + begin + Instruct = RES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FSTRD; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001100 : // 0Ch + begin + Instruct = FSTRD4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001101 : // 0Dh + begin + Instruct = DDRFR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001110 : // 0Eh + begin + Instruct = DDRFR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111011 : // 3Bh + begin + Instruct = DOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111100 : // 3Ch + begin + Instruct = DOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111011 : // BBh + begin + Instruct = DIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111100 : // BCh + begin + Instruct = DIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111101 : // BDh + begin + Instruct = DDRDIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111110 : // BEh + begin + Instruct = DDRDIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101011 : // 6Bh + begin + Instruct = QOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101100 : // 6Ch + begin + Instruct = QOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101011 : // EBh + begin + Instruct = QIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101100 : // ECh + begin + Instruct = QIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101101 : // EDh + begin + Instruct = DDRQIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101110 : // EEh + begin + Instruct = DDRQIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010010 : // 12h + begin + Instruct = PP4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010: // 32h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00111000: // 38h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00110100 : // 34h + begin + Instruct = QPP4; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b01000010 : // 42h + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10000101 : // 85h + begin + Instruct = PGSP; + bus_cycle_state = DATA_BYTES; + end + 8'b10001010 : // 8Ah + begin + Instruct = PGRS; + bus_cycle_state = DATA_BYTES; + end + 8'b11000111 : // C7h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b01100000 : // 60h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011100 : // DCh + begin + Instruct = SE4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERRS; + bus_cycle_state = DATA_BYTES; + end + 8'b00010100 : // 14h + begin + Instruct = ABRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010101 : // 15h + begin + Instruct = ABWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00010110 : // 16h + begin + Instruct = BRRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010111 : // 17h + begin + Instruct = BRWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00101011 : // 2Bh + begin + Instruct = ASPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00101111 : // 2Fh + begin + Instruct = ASPP; + bus_cycle_state = DATA_BYTES; + end + 8'b11100000 : // E0h + begin + Instruct = DYBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100001 : // E1h + begin + Instruct = DYBWR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100010 : // E2h + begin + Instruct = PPBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100011 : // E3h + begin + Instruct = PPBP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100100 : // E4h + begin + Instruct = PPBERS; + bus_cycle_state = DATA_BYTES; + end + 8'b10100110 : // A6h + begin + Instruct = PLBWR; + bus_cycle_state = DATA_BYTES; + end + 8'b10100111 : // A7h + begin + Instruct = PLBRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11100111 : // E7h + begin + Instruct = PASSRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11101000 : // E8h + begin + Instruct = PASSP; + bus_cycle_state = DATA_BYTES; + end + 8'b11101001 : // E9h + begin + Instruct = PASSU; + bus_cycle_state = DATA_BYTES; + end + 8'b11110000 : // F0h + begin + Instruct = RESET; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : // 30h + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b01000001 : // 41h + begin + Instruct = DLPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b01000011 : // 43h + begin + Instruct = PNVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b01001010 : // 4Ah + begin + Instruct = WVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = BRAC; + bus_cycle_state = DATA_BYTES; + end + 8'b11111111 : // FFh + begin + Instruct = MBR; + bus_cycle_state = MODE_BYTE; + end + 8'b00100000 : // 20h + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00100001 : // 21h + begin + Instruct = P4E4; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + end //end of OPCODE BYTE + + ADDRESS_BYTES : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4) || + (Instruct == DDRDIOR) || (Instruct == DDRDIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + DOUBLE = 1'b1; + else + DOUBLE = 1'b0; + if ((Instruct == QOR) || (Instruct == QOR4) || + (Instruct == QIOR) || (Instruct == QIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + QUADRD = 1'b1; + else + QUADRD = 1'b0; + if (DOUBLE == 1'b0) + begin + if (((((Instruct == FSTRD) && (~EXTADD)) || + ((Instruct == DOR) && (~EXTADD)) || + (Instruct == OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QOR) && QUAD && (~EXTADD))) + begin + //Instruction + 3 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes ; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct==FSTRD || Instruct==DOR || + Instruct == QOR) + begin + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((((Instruct==FSTRD4) || + (Instruct==DOR4) || + ((Instruct==FSTRD) && EXTADD) || + ((Instruct==DOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct==QOR4) && QUAD) || + ((Instruct==QOR) && QUAD && EXTADD)) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + end + end + end + else if ((Instruct==DIOR) && (~EXTADD) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + //DUAL I/O High Performance Read(3 Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i]=Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==DIOR4) || + ((Instruct==DIOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin //DUAL I/O High Performance Read(4Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == QIOR) && (~EXTADD)) + begin + //QUAD I/O High Performance Read (3Bytes Address) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((Instruct==QIOR4) || ((Instruct==QIOR) + && EXTADD)) + begin + //QUAD I/O High Performance Read (4Bytes Addr) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt +1; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt =0; + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((((Instruct==RD4) || (Instruct==PP4) || + (Instruct==SE4) ||(Instruct==PPBRD) || + (Instruct==DYBRD) ||(Instruct==DYBWR) || + (Instruct==PPBP) || (Instruct==P4E4) || + ((Instruct==READ) && EXTADD) || + ((Instruct==PP) && EXTADD) || + ((Instruct==P4E) && EXTADD) || + ((Instruct==SE) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (QUAD && (Instruct==QPP4 || + ((Instruct==QPP) && EXTADD)))) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + Address = hiaddr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + else if (((HOLDNeg_in && ~QUAD) || QUAD) && + (~EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + else + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + end + end + + MODE_BYTE : + begin + if (((Instruct==DIOR) || (Instruct == DIOR4)) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + if (Latency_code == 0 || Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + mode_in[2*mode_cnt] = SI_in; + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt] = SO_in; + mode_in[4*mode_cnt+1] = SI_in; + end + else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4)) + && QUAD) + begin + mode_in[0] = HOLDNeg_in; + mode_in[1] = WPNeg_in; + mode_in[2] = SO_in; + mode_in[3] = SI_in; + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + if ((((Instruct==FSTRD) || (Instruct==FSTRD4) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (((Instruct==QOR)||(Instruct==QOR4)) && QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + begin + bus_cycle_state = DATA_BYTES; + end + end + + else if ((Instruct==DDRFR) || (Instruct==DDRFR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==2)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==5)) || + ((Latency_code == 1) && (dummy_cnt==6)) || + ((Latency_code == 2) && (dummy_cnt==7))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (Instruct==RES) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + else if ((Instruct == DIOR) || (Instruct == DIOR4) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 1) && (dummy_cnt==1)) || + ((Latency_code == 2) && (dummy_cnt==2))) + bus_cycle_state = DATA_BYTES; + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + bus_cycle_state = DATA_BYTES; + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==2)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (((Instruct == QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + + if (((Latency_code == 3) && (dummy_cnt==3)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + + DATA_BYTES : + begin + + if (DOUBLE == 1'b1 && (hold_mode==0)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + + if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4))) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in}; + if (data_cnt > ((PageSize+1)*2-1)) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for(i=0;i<=(PageSize*2-1);i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[(PageSize+1)*2-1] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + else if ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (data_cnt > ((PageSize+1)*8-1)) + begin + //In case of serial mode and PP, + //if more than PageSize are sent to the device + //previously latched data are discarded and last + //256/512 data bytes are guaranteed to be programmed + //correctly within the same page. + if (bit_cnt == 0) + begin + for(i=0;i<=(PageSize*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[PageSize*BYTE + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + + if (falling_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + ADDRESS_BYTES : + begin + if (DOUBLE == 1'b1) + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:26] = 6'b000000; + addr_bytes[24] = Bank_Addr_reg[0]; + addr_bytes[25] = Bank_Addr_reg[1]; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = addr_bytes[31:0]; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + end + + MODE_BYTE : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + begin + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + begin + mode_in[4] = HOLDNeg_in; + mode_in[5] = WPNeg_in; + mode_in[6] = SO_in; + mode_in[7] = SI_in; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + DATA_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 ) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + else + begin + if ((Instruct==READ) || (Instruct==RD4) || + (Instruct==FSTRD)|| (Instruct==FSTRD4)|| + (Instruct==RDSR) || (Instruct==RDSR2) || + (Instruct==RDCR) || (Instruct==OTPR) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==DIOR)|| (Instruct==DIOR4)|| + (Instruct==ABRD) || (Instruct==BRRD) || + (Instruct==ASPRD)|| (Instruct==DYBRD) || + (Instruct==PPBRD)|| + (Instruct==PASSRD)|| (Instruct==RDID)|| + (Instruct==RES) || (Instruct==REMS) || + (Instruct==PLBRD)|| (Instruct==DLPRD) || + (current_state == AUTOBOOT && + start_delay == 0) || + (((Instruct==QOR) || (Instruct==QIOR) || + (Instruct==QOR4) || + (Instruct==QIOR4)) && QUAD)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + + DUMMY_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + endcase + end + end + + if (rising_edge_CSNeg_ipd) + begin + if ((bus_cycle_state != DATA_BYTES) && + (bus_cycle_state != DUMMY_BYTES)) + begin + if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF) + begin + Instruct = MBR; + end + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (((mode_bytes[7:4] == 4'b1010) && + (Instruct==DIOR || Instruct==DIOR4 || + Instruct==QIOR || Instruct==QIOR4)) || + ((mode_bytes[7:4] == ~mode_bytes[3:0]) && + (Instruct == DDRFR || Instruct == DDRFR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4))) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + + case (Instruct) + WREN, + WRDI, + BE, + SE, + SE4, + CLSR, + P4E, + P4E4, + BRAC, + RESET, + PPBERS, + PPBP, + PLBWR, + PGSP, + PGRS, + ERSP, + ERRS: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 0) + write = 1'b0; + end + end + + WRR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + if (BAR_ACC == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else + begin + if (P_ERR == 0 && E_ERR == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Bank_Addr_reg_in[i]= + Data_in[7-i]; + end + end + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + if (BAR_ACC == 0) + begin + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Config_reg1_in[i]= + Data_in[15-i]; + end + end + else + begin + if (P_ERR == 0 && E_ERR == 0) + begin + for(i=0;i<=7;i=i+1) + begin + Bank_Addr_reg_in[i]= + Data_in[7-i]; + end + end + end + end + end + end + + PP, + PP4, + OTPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=7;j>=0;j=j-1) + begin + if ((Data_in[(i*8)+(7-j)]) + !== 1'bX) + begin + Byte_slv[j] = + Data_in[(i*8)+(7-j)]; + end + end + WByte[i] = Byte_slv; + end + + if (data_cnt > (PageSize+1)*BYTE) + Byte_number = PageSize; + else + Byte_number = + ((data_cnt/8) - 1); + end + end + end + end + + QPP, + QPP4: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + quad_pg = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > (PageSize+1)*2) + Byte_number = PageSize; + else + Byte_number = ((data_cnt/2)-1); + end + end + end + + ABWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 32) + begin + write = 1'b0; + for(j=0;j<=31;j=j+1) + begin + AutoBoot_reg_in[j] = Data_in[31-j]; + end + end + end + end + + BRWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + Bank_Addr_reg_in[j] = Data_in[7-j]; + end + end + end + end + + ASPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 16) + begin + write = 1'b0; + for(j=0;j<=15;j=j+1) + begin + ASP_reg_in[j] = Data_in[15-j]; + end + end + end + end + + DYBWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + DYBAR_in[j] = Data_in[7-j]; + end + end + end + end + + PNVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + NVDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + WVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + VDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + PASSP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + Password_reg_in[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + + PASSU: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + PASS_TEMP[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + endcase + end + end + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Page Program +/////////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed_pgm; + time start_pgm; + time duration_pgm; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) || + (Instruct == QPP) || (Instruct == QPP4)) + if (PageSize == 255) + begin + pob = tdevice_PP_256; + end + else + begin + pob = tdevice_PP_512; + end + else + pob = tdevice_BP; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed_pgm = 0; + duration_pgm = pob; + PDONE = 1'b0; + ->pdone_event; + start_pgm = $time; + end + end + + always @(posedge PGSUSP) + begin + if (PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed_pgm = $time - start_pgm; + duration_pgm = pob - elapsed_pgm; + PDONE = 1'b0; + end + end + + always @(posedge PGRES) + begin + start_pgm = $time; + ->pdone_event; + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #duration_pgm PDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Write Status Register +/////////////////////////////////////////////////////////////////////////////// + time wob; + always @(posedge WSTART) + begin:wdone_process + wob = tdevice_WRR; + if (WSTART && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Reset Timing +/////////////////////////////////////////////////////////////////////////////// + + time startlo; + time starthi; + time durationlo; + time durationhi; + + always @(negedge RSTNeg_in or Instruct) + begin + if (~RSTNeg_in) + begin + RST = 1'b1; + #200000 RST = 1'b0; // 200 ns + end + else if (Instruct == RESET) + begin + Reseted = 1'b0; + #10000 Reseted = 1'b1; // 10 ns + end + end + + always @(RST_in or rising_edge_Reseted) // Reset done,program terminated + begin + if ((RST_in && ~RST) || (rising_edge_Reseted)) + disable pdone_process; + disable edone_process; + disable wdone_process; + PDONE = 1'b1; + EDONE = 1'b1; + WDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Bulk Erase +/////////////////////////////////////////////////////////////////////////////// + time seo; + time beo; + event edone_event; + time elapsed_ers; + time start_ers; + time duration_ers; + + always @(rising_edge_ESTART) + begin + seo = tdevice_SE; + beo = tdevice_BE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == BE) + begin + duration_ers = beo; + end + else + begin + duration_ers = seo; + end + elapsed_ers = 0; + EDONE = 1'b0; + ->edone_event; + start_ers = $time; + end + end + + always @(posedge ESUSP) + begin + if (ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed_ers = $time - start_ers; + duration_ers = seo - elapsed_ers; + EDONE = 1'b0; + end + end + + always @(posedge ERES) + begin + if (ERES && (~EDONE)) + begin + start_ers = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_ers EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg falling_edge_PPBERASE_in = 1'b0; + reg falling_edge_PASSULCK_in = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or + falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or + rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or + PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out + or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in) + begin: StateGen1 + + integer sect; + + if (rising_edge_PoweredUp) + begin + if (ABE == 1 && RPME !== 0 ) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + else + begin + if (RST_out == 1'b0) + next_state = current_state; + else if (falling_edge_write && Instruct == RESET) + begin + if (ABE == 1 && RPME !== 0) + begin + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + ABSD = AutoBoot_reg[8:1]; + start_autoboot = 0; + next_state = AUTOBOOT; + end + else + next_state = IDLE; + end + else + begin + case (current_state) + RESET_STATE : + begin + if (rising_edge_RST_out) + begin + if (ABE == 1 && RPME!== 0) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9],9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + end + + IDLE : + begin + if (falling_edge_write && RdPswdProtMode == 0) + begin + if (Instruct == WRR && WEL == 1 && BAR_ACC == 0 + && (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)) + // can not execute if HPM is entered or + // if WEL bit is zero + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + $display ("WARNING: Changing value of "); + $display ("Configuration Register OTP "); + $display ("bit from 1 to 0 is not"); + $display ("allowed!!!"); + end + else + begin + next_state = WRITE_SR; + end + else if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = PAGE_PG; + if ((Instruct==QPP || Instruct==QPP4) && + QPP_page[pgm_page] == 1) + begin + $display ("WARNING:The same page"); + $display (" must not be"); + $display (" programmed more"); + $display (" than once!!!"); + end + end + end + else if (Instruct==OTPP && WEL==1 && FREEZE==0) + begin + if (((((Address>=16'h0010 && Address<=16'h0013) + ||(Address>=16'h0020 && Address<=16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address>=16'h0100 && Address<=16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32]==1) || + ((Address>=16'h0200 && Address<=16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32]==1) || + ((Address>=16'h0300 && Address<=16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) + && (Address + Byte_number <= OTPHiAddr)) + next_state = OTP_PG; + end + else if ((Instruct == SE || Instruct == SE4) + && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 + && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + else if (Instruct == BE && WEL == 1 && + (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0)) + next_state = BULK_ERS; + else if (Instruct == ABWR && WEL == 1) + //Autoboot Register Write Command + next_state = AUTOBOOT_PG; + else if (Instruct == ASPP && WEL == 1) + begin + //ASP Register Program Command + if (~(ASPOTPFLAG)) + next_state = ASP_PG; + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + next_state = PLB_PG; + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + next_state = PASS_PG; + end + else if (Instruct == PASSU && WEL && ~WIP) + next_state = PASS_UNLOCK; + else if (Instruct == PPBP && WEL == 1) + next_state <= PPB_PG; + else if (Instruct == PPBERS && WEL && PPBOTP) + next_state <= PPB_ERS; + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == PNVDLR && WEL == 1) + next_state = NVDLR_PG; + else if (Instruct == P4E || Instruct == P4E4 + && WEL == 1) + begin + $display("Warning!"); + $display("Instructions:"); + $display("Parameter 4KB-sector Erase"); + $display("are not allowed"); + $display("for 512Mbit memory size"); + end + else + next_state = IDLE; + end + if (falling_edge_write && RdPswdProtMode == 1 && ~WIP) + begin + if (Instruct == PASSU) + next_state = PASS_UNLOCK; + end + end + + AUTOBOOT : + begin + if (rising_edge_CSNeg_ipd) + next_state = IDLE; + end + + WRITE_SR : + begin + if (rising_edge_WDONE) + next_state = IDLE; + end + + PAGE_PG : + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end + + PG_SUSP : + begin + if (falling_edge_write) + begin + if (Instruct == PGRS) + begin + next_state = PAGE_PG; + end + else + begin + next_state = PG_SUSP; + end + end + end + + OTP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + BULK_ERS : + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS : + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP : + begin + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + if (SectorSuspend != Address/(SecSize+1)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = ERS_SUSP_PG; + if ((Instruct==QPP || Instruct==QPP4) && + QPP_page[pgm_page] == 1) + begin + $display ("WARNING:The same page"); + $display (" must not be"); + $display (" programmed more"); + $display (" than once!!!"); + end + end + end + end + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == ERRS) + next_state = SECTOR_ERS; + else + next_state = ERS_SUSP; + end + end + + ERS_SUSP_PG : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = ERS_SUSP_PG_SUSP; + end + + ERS_SUSP_PG_SUSP : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + if (falling_edge_write) + begin + if (Instruct == PGRS) + begin + next_state = ERS_SUSP_PG; + end + else + begin + next_state = ERS_SUSP_PG_SUSP; + end + end + end + + PASS_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PASS_UNLOCK : + begin + if (falling_edge_PASSULCK_in) + next_state = IDLE; + end + + PPB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PPB_ERS : + begin + if (falling_edge_PPBERASE_in) + next_state = IDLE; + end + + AUTOBOOT_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PLB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + DYB_PG : + begin + if (rising_edge_PDONE) + if (ES) + next_state = ERS_SUSP; + else + next_state = IDLE; + end + + ASP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + NVDLR_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + endcase + end + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer WData [0:511]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(Instruct_event) + begin + read_cnt = 0; + byte_cnt = 1; + rd_fast = 1'b1; + dual = 1'b0; + rd_slow = 1'b0; + any_read = 1'b0; + end + + always @(rising_edge_read_out) + begin + if (rising_edge_read_out == 1'b1) + begin + if (PoweredUp == 1'b1) + begin + oe_z = 1'b1; + #1000 oe_z = 1'b0; + oe = 1'b1; + #1000 oe = 1'b0; + end + end + end + + always @(change_addr_event) + begin + if (change_addr_event) + begin + read_addr = Address; + end + end + + always @(posedge PASSACC_out) + begin + Status_reg1[0] = 1'b0; //WIP + PASSACC_in = 1'b0; + end + + always @(Instruct or posedge start_autoboot or oe or current_state_event or + falling_edge_write or posedge PDONE or posedge WDONE or oe_z or + posedge EDONE or ERSSUSP_out or rising_edge_Reseted or + rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or + Address) + begin: Functionality + integer i,j; + integer sect; + + if (rising_edge_PoweredUp) + begin + //the default condition after power-up + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + //The Configuration Register FREEZE bit is cleared. + Config_reg1[0] = 0; + //The WEL bit is cleared. + Status_reg1[1] = 0; + //When BPNV is set to '1'. the BP2-0 bits in Status Register are + //volatile and will be reset binary 111 after power-on reset + if (BPNV == 1 && LOCK == 0 && FREEZE == 0 ) + begin + Status_reg1[4] = 1'b0;// BP2 + Status_reg1[3] = 1'b0;// BP1 + Status_reg1[2] = 1'b0;// BP0 + BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + + //As shipped from the factory, all devices default ASP to the + //Persistent Protection mode, with all sectors unprotected, + //when power is applied. The device programmer or host system must + //then choose which sector protection method to use. + //For Persistent Protection mode, PPBLOCK defaults to "1" + PPBL[0] = 1'b1; + + //All the DYB power-up in the unprotected state + DYB_bits = {512{1'b1}}; + + end + + if (Instruct == RESET) + begin + //EXTADD is cleared to “0” + Bank_Addr_reg[7] = 1'b0; + //P_ERR bit is cleared + Status_reg1[6] = 1'b0; + //E_ERR bit is cleared + Status_reg1[5] = 1'b0; + //The WEL bit is cleared. + Status_reg1[1] = 1'b0; + //The WIP bit is cleared. + Status_reg1[0] = 1'b0; + //The ES bit is cleared. + Status_reg2[1] = 1'b0; + //The PS bit is cleared. + Status_reg2[0] = 1'b0; + //When BPNV is set to '1'. the BP2-0 bits in Status + //Register are volatile and will be reseted after + //reset command + if (BPNV == 1 && LOCK== 0 && FREEZE == 0) + begin + Status_reg1[4] = 1'b1; + Status_reg1[3] = 1'b1; + Status_reg1[2] = 1'b1; + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + case (current_state) + IDLE : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (falling_edge_write && RdPswdProtMode == 1) + begin + if(Instruct == PASSU) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + end + + if (falling_edge_write && RdPswdProtMode == 0) + begin + read_cnt = 0; + byte_cnt = 1; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 0; + else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 && + BAR_ACC == 0) + begin + if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD) + begin + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + // P_ERR bit is set to 1 + Status_reg1[6] = 1'b1; + end + else + begin + // can not execute if Hardware Protection Mode + // is entered or if WEL bit is zero + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + end + else + Status_reg1[1] = 0; + end + else if ((Instruct == PP || Instruct == PP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + QPP_page[pgm_page] = 1'b1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if (Instruct == OTPP && WEL == 1) + begin + // As long as the FREEZE bit remains cleared to a logic + // '0' the OTP address space is programmable. + if (FREEZE == 0) + begin + if (((((Address>= 16'h0010 && Address<= 16'h0013) || + (Address >= 16'h0020 && Address <= 16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address >= 16'h0100 && Address <= 16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32] == 1) || + ((Address >= 16'h0200 && Address <= 16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32] == 1) || + ((Address >= 16'h0300 && Address <= 16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) && + (Address + Byte_number <= OTPHiAddr)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else if ((Address < 8'h10 || (Address > 8'h13 && + Address < 8'h20) || Address > 12'h3FF )) + begin + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + if (Address < 8'h20) + begin + $display ("Given address is "); + $display ("in reserved address range"); + end + else if (Address > 12'h3FF) + begin + $display ("Given address is "); + $display ("out of OTP address range"); + end + end + else + begin + //P_ERR bit will be set when the user attempts to + // to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == SE || Instruct == SE4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + SectorSuspend = sect; + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == P4E || Instruct == P4E4) && WEL == 1) + begin + Status_reg1[1] = 1'b0;//WEL + end + else if (Instruct == BE && WEL == 1) + begin + if (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + end + else + begin + //The Bulk Erase command will not set E_ERR if a + //protected sector is found during the command + //execution. + Status_reg1[1] = 1'b0;//WEL + end + end + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + $display ("Password programming is not allowed"); + $display (" in Password Protection Mode."); + end + end + else if (Instruct == PASSU && WEL) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == ASPP && WEL == 1) + begin + if (~(ASPOTPFLAG)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + $display ("Once the Protection Mode is selected,"); + $display ("no further changes to the ASP "); + $display ("register is allowed."); + end + end + else if (Instruct == ABWR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBP && WEL == 1) + begin + ReturnSectorID(sect,Address); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBERS && WEL == 1) + begin + if (PPBOTP) + begin + PPBERASE_in = 1'b1; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[5] = 1'b1; + end + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PNVDLR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == WVDLR && WEL == 1) + begin + VDLR_reg = VDLR_reg_in; + Status_reg1[1] = 1'b0; + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4 || + Instruct == RES || + (Instruct == DLPRD && RdPswdProtMode == 0)) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4 || + ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + else if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES + && VDLR_reg != 8'b00000000) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + && QUAD) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) is enabled + // Optional DLP + if (VDLR_reg != 8'b00000000 && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd = data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr + && RdPswdProtMode == 0) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + data_out[7:0] = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if ((read_addr > OTPHiAddr)||(RdPswdProtMode==1)) + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum or Read Password Protection Mode + //is selected instead, the data beyond the + //maximum OTP address will be undefined. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == REMS) + begin + //Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + data_out[7:0] = DeviceID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + else if (Instruct == RDID) + begin + ident_out = CFI_array_tmp; + if(read_cnt < 648) + begin + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + //Continued shifting of output beyond the end of + //the defined ID-CFI address space will + //provide undefined data. + SOut_zd = 1'bX; + end + end + else if (Instruct == RES) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + data_out = ESignature; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DLPRD && RdPswdProtMode == 0) + begin + //Read DLP + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = VDLR_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ABRD && RdPswdProtMode == 0) + begin + //Read AutoBoot register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = AutoBoot_reg[31-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 32) + read_cnt = 0; + end + else if (Instruct == BRRD && RdPswdProtMode == 0) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ASPRD && RdPswdProtMode == 0) + begin + //Read ASP Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = ASP_reg[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == PASSRD && RdPswdProtMode == 0) + begin + //Read Password Register + if (~(PWDMLB == 0 && PSTMLB == 1)) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = + Password_reg[(8*byte_cnt-1)-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + byte_cnt = byte_cnt + 1; + if (byte_cnt == 9) + byte_cnt = 1; + end + end + end + else if (Instruct == PLBRD) + begin + //Read PPB Lock Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = PPBL[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + DYBAR[7:0] = 8'bXXXXXXXX; + + if (RdPswdProtMode == 0) + begin + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end + + AUTOBOOT: + begin + if (start_autoboot == 1) + begin + if (oe) + begin + any_read = 1'b1; + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + end + else if (oe_z) + begin + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + end + end + + WRITE_SR: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (WDONE == 1) + begin + Status_reg1[0] = 1'b0; //WIP + Status_reg1[1] = 1'b0; //WEL + //SRWD bit + Status_reg1[7] = Status_reg1_in[7]; //MSB first + + if (LOCK == 0) + begin + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT bit in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg1[4] = Status_reg1_in[4];//BP2 + Status_reg1[3] = Status_reg1_in[3];//BP1 + Status_reg1[2] = Status_reg1_in[2];//BP0 + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + if (TBPROT == 1'b0 && INITIAL_CONFIG == 1'b0) + begin + Config_reg1[5] = Config_reg1_in[5];//TBPROT + end + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + Config_reg1[7] = Config_reg1_in[7];//LC1 + Config_reg1[6] = Config_reg1_in[6];//LC0 + Config_reg1[1] = Config_reg1_in[1];//QUAD + + if (FREEZE == 1'b0) + begin + Config_reg1[0] = Config_reg1_in[0];//FREEZE + end + + if (WRLOCKENABLE== 1'b1 && LOCK == 1'b0) + begin + Config_reg1[4] = Config_reg1_in[4];//LOCK + WRLOCKENABLE = 1'b0; + end + if (BPNV == 1'b0) + begin + Config_reg1[3] = Config_reg1_in[3];//BPNV + end + end + end + + PAGE_PG : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == PAGE_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt = 0; + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + quad_pg = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + PDONE = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd =data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + OTP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == OTP_PG) + begin + if (~PDONE) + begin + if (Address + wr_cnt <= OTPHiAddr) + begin + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = OTPMem[Addr + i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + OTPMem[Addr + i] = -1; + end + end + else + begin + $display ("Programming will reach over "); + $display ("address limit of OTP array"); + end + end + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + OTPMem[Addr + i] = WData[i]; + end + LOCK_BYTE1 = OTPMem[16]; + LOCK_BYTE2 = OTPMem[17]; + LOCK_BYTE3 = OTPMem[18]; + LOCK_BYTE4 = OTPMem[19]; + end + end + + SECTOR_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == SECTOR_ERS) + begin + if (~EDONE) + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + else if (Instruct == ERSP && ~ERSSUSP_in) + begin + ESUSP = 1'b1; + ESUSP <= #5 1'b0; + ERSSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + end + + BULK_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == BULK_ERS) + begin + if (~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = -1; + end + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = MaxData; + end + end + end + end + + ERS_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (ERSSUSP_out == 1) + begin + ERSSUSP_in = 0; + //The Erase Suspend (ES) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //erase operation has been suspended. + Status_reg2[1] = 1'b1; + //The WIP bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (SectorSuspend != read_addr/(SecSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (SectorSuspend != read_addr/(SecSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (SectorSuspend != read_addr/(SecSize+1)) + begin + if (bus_cycle_state == DUMMY_BYTES) + begin + if ((Instruct == DDRQIOR + || Instruct == DDRQIOR4) && QUAD) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, dlp_act); + // Data Learning Pattern (DLP) + // is enabled Optional DLP + if (VDLR_reg != 8'b00000000 + && dlp_act == 1'b1) + begin + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + dlp_act = 1'b0; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + end + end + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == PP4) && WEL == 1) + begin + if (SectorSuspend != Address/(SecSize+1)) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL == 1) + begin + if (SectorSuspend != Address/(SecSize+1)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + + if (Sec_Prot[sect] == 0 + && PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + QPP_page[pgm_page] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + Bank_Addr_reg[1] = Bank_Addr_reg_in[1]; + Bank_Addr_reg[0] = Bank_Addr_reg_in[0]; + end + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == ERRS) + begin + Status_reg2[1] = 1'b0; + Status_reg1[0] = 1'b1; + Addr = SectorSuspend*(SecSize+1); + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + ERES = 1'b1; + ERES <= #5 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == ERS_SUSP_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt =0; + end + + if(PDONE == 1) + begin + Status_reg1[0] = 1'b0;//WIP + Status_reg1[1] = 1'b0;//WEL + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi ) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PASS_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + new_pass = Password_reg_in; + old_pass = Password_reg; + for (i=0;i<=63;i=i+1) + begin + if (old_pass[j] == 0) + new_pass[j] = 0; + end + + if (PDONE == 1) + begin + Password_reg = new_pass; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PASS_UNLOCK: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PASS_TEMP == Password_reg) + begin + PASS_UNLOCKED = 1'b1; + end + else + begin + PASS_UNLOCKED = 1'b0; + end + if (PASSULCK_out == 1'b1) + begin + if ((PASS_UNLOCKED == 1'b1) && (~PWDMLB)) + begin + PPBL[0] = 1'b1; + Status_reg1[0] = 1'b0; //WIP + end + else + begin + Status_reg1[6] = 1'b1; + $display ("Incorrect Password"); + PASSACC_in = 1'b1; + end + Status_reg1[1] = 1'b0; + PASSULCK_in = 1'b0; + end + end + + PPB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (PPB_LOCK !== 0) + begin + PPB_bits[sect]= 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[5] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + end + + PPB_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PPBERASE_out == 1'b1) + begin + if ((PPB_LOCK !== 0) && PPBOTP) + begin + PPB_bits = {512{1'b1}}; + end + else + begin + Status_reg1[5] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + PPBERASE_in = 1'b0; + end + end + + AUTOBOOT_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + AutoBoot_reg = AutoBoot_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PLB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + PPBL[0] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + DYB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + DYBAR = DYBAR_in; + if (DYBAR == 8'hFF) + begin + DYB_bits[sect]= 1'b1; + end + else if (DYBAR == 8'h00) + begin + DYB_bits[sect]= 1'b0; + end + else + begin + Status_reg1[6] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + ASP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + + if (RPME == 1'b0 && ASP_reg_in[5] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("RPME bit is allready programmed"); + end + else + begin + ASP_reg[5] = ASP_reg_in[5];//RPME + end + + if (PPBOTP == 1'b0 && ASP_reg_in[3] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("PPBOTP bit is allready programmed"); + end + else + begin + ASP_reg[3] = ASP_reg_in[3];//PPBOTP + end + + if (PWDMLB == 1'b1 && PSTMLB == 1'b1) + begin + if (ASP_reg_in[2] == 1'b0 && ASP_reg_in[1] == 1'b0) + begin + $display("ASPR[2:1] = 00 Illegal condition"); + Status_reg1[6] = 1'b1; //P_ERR + end + else + begin + if (ASP_reg_in[2]!==1'b1 || ASP_reg_in[1]!==1'b1) + begin + ASPOTPFLAG = 1'b1; + end + ASP_reg[2] = ASP_reg_in[2];//PWDMLB + ASP_reg[1] = ASP_reg_in[1];//PSTMLB + end + end + + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + NVDLR_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (NVDLR_reg == 0) + begin + NVDLR_reg = NVDLR_reg_in; + VDLR_reg = NVDLR_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; //P_ERR + $display("NVDLR bits allready programmed"); + end + end + end + + RESET_STATE: + begin + //the default condition hardware reset + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + if (BPNV && ~LOCK && ~FREEZE) + begin + Status_reg1[2] = 1'b1;// BP0 + Status_reg1[3] = 1'b1;// BP1 + Status_reg1[4] = 1'b1;// BP2 + BP_bits = 3'b111; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + //Resets the volatile bits in the Status register 1 + Status_reg1[6] = 1'b0; + Status_reg1[5] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[0] = 1'b0; + //Resets the volatile bits in the Status register 2 + Status_reg2[1] = 1'b0; + Status_reg2[0] = 1'b0; + //Resets the volatile bits in the Configuration register 1 + Config_reg1[0] = 1'b0; + //On reset cycles the data pattern reverts back + //to what is in the NVDLR + VDLR_reg = NVDLR_reg; + dlp_act = 1'b0; + //Loads the Program Buffer with all ones + for(i=0;i<=511;i=i+1) + begin + WData[i] = MaxData; + end + if (~PWDMLB) + PPBL[0] = 1'b0; + else + PPBL[0] = 1'b1; + end + + endcase + + //Output Disable Control + if (CSNeg_ipd ) + begin + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign ddrd = ddr; + assign fast_ddr = ddr_fast; + + always @(posedge change_BP) + begin + case (Status_reg1[4:2]) + + 3'b000: + begin + Sec_Prot = 256'b0; + end + + 3'b001: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum:(SecNum+1)*63/64] = 4'b1111; + Sec_Prot[(SecNum+1)*63/64-1 : 0] = 252'h0; + end + else + begin + Sec_Prot[(SecNum+1)/64-1 : 0] = 4'b1111; + Sec_Prot[SecNum : (SecNum+1)/64] = 252'h0; + end + end + + 3'b010: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*31/32] = 8'b11111111; + Sec_Prot[(SecNum+1)*31/32-1 : 0] = 248'h0; + end + else + begin + Sec_Prot[(SecNum+1)/32-1 : 0] = 8'b11111111; + Sec_Prot[SecNum : (SecNum+1)/32] = 248'h0; + end + end + + 3'b011: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*15/16] = 16'hFFFF; + Sec_Prot[(SecNum+1)*15/16-1 : 0] = 240'h0; + end + else + begin + Sec_Prot[(SecNum+1)/16-1 : 0] = 16'hFFFF; + Sec_Prot[SecNum : (SecNum+1)/16] = 240'h0; + end + end + + 3'b100: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*7/8] = 32'hFFFFFFFF; + Sec_Prot[(SecNum+1)*7/8-1 : 0] = 224'h0; + end + else + begin + Sec_Prot[(SecNum+1)/8-1 : 0] = 32'hFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/8] = 224'h0; + end + end + + 3'b101: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)*3/4] + = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[(SecNum+1)*3/4-1 : 0] = 192'h0; + end + else + begin + Sec_Prot[(SecNum+1)/4-1 : 0] = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/4] = 192'h0; + end + end + + 3'b110: + begin + if (~TBPROT) + begin + Sec_Prot[SecNum : (SecNum+1)/2] + = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + Sec_Prot[(SecNum+1)/2-1 : 0] = 128'h0; + end + else + begin + Sec_Prot[(SecNum+1)/2-1 : 0] + = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/2] = 128'h0; + end + end + + 3'b111: + begin + Sec_Prot[127:0] = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + Sec_Prot[255:128] = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + end + endcase + end + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // autoboot control logic + //////////////////////////////////////////////////////////////////////// + always @(rising_edge_SCK_ipd or current_state_event) + begin + if(current_state == AUTOBOOT) + begin + if (rising_edge_SCK_ipd) + begin + if (start_delay > 0) + start_delay = start_delay - 1; + end + + if (start_delay == 0) + begin + start_autoboot = 1; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure FDDR_DPL + task Return_DLP; + input integer Instruct; + input integer EHP; + input integer Latency_code; + input integer dummy_cnt; + inout dlp_act; + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + if (EHP) + begin + if (Latency_code == 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b1; + else if (Latency_code == 0 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if(Latency_code == 1 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 3) + dlp_act = 1'b1; + end + end + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + if (EHP) + begin + if (Latency_code == 1 && dummy_cnt >= 1) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if( Latency_code == 3 || Latency_code == 0) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + if (Latency_code == 3) + dlp_act = 1'b0; + else if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + end + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && QUAD) + begin + if (EHP) + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + dlp_act = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + dlp_act = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + dlp_act = 1'b1; + else if( Latency_code == 3) + begin + dlp_act = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + end + end + end + endtask + + function integer ReturnSectorIDRdPswdMd; + input reg TBPROT; + begin + if(TBPROT == 0) + begin + ReturnSectorIDRdPswdMd = 0; + end + else + begin + ReturnSectorIDRdPswdMd = SecNum; + end + end + endfunction + + // Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr/(SecSize+1); + AddrLOW = sector*(SecSize+1); + AddrHIGH = sector*(SecSize+1) + SecSize; + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / (PageSize + 1); + AddrLOW = page * (PageSize + 1); + AddrHIGH = page * (PageSize + 1) + PageSize; + end + endtask + + // Procedure ReturnSectorID + task ReturnSectorID; + inout sect; + input Address; + integer sect; + integer Address; + integer conv; + begin + sect = Address/(SecSize+1); + end + endtask + + always @(PPBL[0], ASP_reg) + begin + if (PPBL[0] == 0 && PWDMLB == 0 && RPME == 0 && RdPswdProtEnable) + begin + RdPswdProtMode = 1; + AutoBoot_reg[0] = 0;//AUTOBOOT is disabled when Read Password + end //Protection is enabled + else + begin + RdPswdProtMode = 0; + end + end + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1; + #1000 falling_edge_write = 0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge RSTNeg_in) + begin + falling_edge_RSTNeg = 1'b1; + #50000 falling_edge_RSTNeg = 1'b0; + end + + always @(posedge RSTNeg_in) + begin + rising_edge_RSTNeg = 1'b1; + #10000 rising_edge_RSTNeg = 1'b0; + end + + always @(negedge RST) + begin + falling_edge_RST = 1'b1; + #10000 falling_edge_RST = 1'b0; + end + + always @(posedge RST) + begin + rising_edge_RST = 1'b1; + #1000 rising_edge_RST = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge Reseted) + begin + rising_edge_Reseted = 1'b1; + #1000 rising_edge_Reseted = 1'b0; + end + + always @(negedge PASSULCK_in) + begin + falling_edge_PASSULCK_in = 1'b1; + #1000 falling_edge_PASSULCK_in = 1'b0; + end + + always @(negedge PPBERASE_in) + begin + falling_edge_PPBERASE_in = 1'b1; + #1000 falling_edge_PPBERASE_in = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge RST_out) + begin + rising_edge_RST_out = 1'b1; + #1000 rising_edge_RST_out = 1'b0; + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.vhd b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.vhd new file mode 100644 index 0000000..2867468 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s.vhd @@ -0,0 +1,13905 @@ +------------------------------------------------------------------------------- +-- File Name: s25fl512s.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2011 Spansion, LLC. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 V.Mancev 09 Nov 26 Inital Release +-- V1.1 V.Mancev 10 Mar 04 addr_cnt for second read in +-- high performance read continuous +-- mode can change its value only +-- when CSNeg = '0' +-- V1.2 V.Mancev 10 July 28 During the QUAD mode HOLD# input +-- is not monitored for its normal +-- function +-- V1.3 V.Mancev 10 Oct 28 Latest datasheet aligned +-- V1.4 V.Mancev 10 Nov 15 QUAD Program operation during Erase +-- Suspend is added +-- Warning for Resume to Suspend time +-- is added +-- During Erase Suspend, after Program +-- operation is completed, WEL bit is +-- cleared +-- Implemetation of Software Reset is +-- Changed +-- V1.2 V.Mancev 11 July 11 Latest datasheet aligned +-- V1.3 V.Mancev 22 July 11 Corrections for P4E and P4E4 +-- V1.4 V. Mancev 18 Nov 11 Time tHO is changed to 1 ns +-- (customer's request) +-- BRWR instruction is corrected +-- V1.5 S.Petrovic 02 Jun 12 QPP Instruction is allowed on +-- previously programmed page +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Library: FLASH +-- Technology: FLASH MEMORY +-- Part: S25FL512S +-- +-- Description: 512 Megabit Serial Flash Memory +-- +------------------------------------------------------------------------------- +-- Comments : +-- For correct simulation, simulator resolution should be set to 1 ps +-- A device ordering (trim) option determines whether a feature is enabled +-- or not, or provide relevant parameters: +-- -15th character in TimingModel determines if enhanced high +-- performance option is available +-- (0,2,3,R,A,B,C,D) EHPLC +-- (Y,Z,S,T,K,L) Security EHPLC +-- (4,6,7,8,9,Q) HPLC +-- -15th character in TimingModel determines if RESET# input +-- is available +-- (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +-- (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +-- state,inside the package. +-- +-------------------------------------------------------------------------------- +-- Known Bugs: +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + USE STD.textio.ALL; + USE IEEE.VITAL_timing.ALL; + USE IEEE.VITAL_primitives.ALL; + +LIBRARY FMF; USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY s25fl512s IS + GENERIC ( + --------------------------------------------------------------------------- + -- TIMING GENERICS: + --------------------------------------------------------------------------- + -- tipd delays: interconnect path delays (delay between components) + -- There should be one for each IN or INOUT pin in the port list + -- They are given default values of zero delay. + tipd_SCK : VitalDelayType01 := VitalZeroDelay01; + tipd_SI : VitalDelayType01 := VitalZeroDelay01; + tipd_SO : VitalDelayType01 := VitalZeroDelay01; + + tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RSTNeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays: propagation delays (pin-to-pin delay within a component) + tpd_SCK_SO_normal : VitalDelayType01Z := UnitDelay01Z; -- tV, tHO + tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tDIS + tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;-- + tpd_RSTNeg_SO : VitalDelayType01Z := UnitDelay01Z;-- + -- DDR operation values + tpd_SCK_SO_DDR : VitalDelayType01Z := UnitDelay01Z;--tV(66MHz) + + -- tsetup values: setup times + -- setup time is minimum time before the referent signal edge the + -- input should be stable + tsetup_CSNeg_SCK_normal_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSS / + tsetup_CSNeg_SCK_DDR_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSS / + tsetup_SI_SCK_normal_noedge_posedge: VitalDelayType + := UnitDelay; -- tSU:DAT / + tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPS \ + tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; + tsetup_RSTNeg_CSNeg : VitalDelayType := UnitDelay; -- tRP + -- DDR operation values + tsetup_SI_SCK_DDR_noedge_posedge: VitalDelayType + := UnitDelay; -- tSU / + tsetup_SI_SCK_DDR_noedge_negedge: VitalDelayType + := UnitDelay; -- tSU \ + + -- thold values: hold times + -- hold time is minimum time the input should be present stable + -- after the referent signal edge + thold_CSNeg_SCK_normal_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSH / + thold_CSNeg_SCK_DDR_noedge_posedge + : VitalDelayType := UnitDelay; -- tCSH / + thold_SI_SCK_normal_noedge_posedge: VitalDelayType + := UnitDelay; -- tHD:DAT / + thold_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPH / + thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- + thold_CSNeg_RSTNeg : VitalDelayType := UnitDelay; -- tRPH + -- DDR operation values + thold_SI_SCK_DDR_noedge_posedge: VitalDelayType + := UnitDelay; -- tHD / + thold_SI_SCK_DDR_noedge_negedge: VitalDelayType + := UnitDelay; -- tHD \ + + --tpw values: pulse width + tpw_SCK_serial_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_dual_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_fast_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_quadpg_posedge : VitalDelayType := UnitDelay; -- tWH + tpw_SCK_serial_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_dual_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_fast_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_SCK_quadpg_negedge : VitalDelayType := UnitDelay; -- tWL + tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_CSNeg_pgers_posedge : VitalDelayType := UnitDelay; -- tCS + tpw_RSTNeg_negedge : VitalDelayType := UnitDelay; -- tRP + tpw_RSTNeg_posedge : VitalDelayType := UnitDelay; -- tRS + -- DDR operation values + tpw_SCK_DDR_posedge : VitalDelayType := UnitDelay; -- tWH(66MHz) + tpw_SCK_DDR_negedge : VitalDelayType := UnitDelay; -- tWL(66Hz) + + -- tperiod min (calculated as 1/max freq) + tperiod_SCK_serial_rd : VitalDelayType := UnitDelay; --fSCK=50MHz + tperiod_SCK_fast_rd : VitalDelayType := UnitDelay; --fSCK=133MHz + tperiod_SCK_dual_rd : VitalDelayType := UnitDelay; --fSCK=104MHz + tperiod_SCK_quadpg : VitalDelayType := UnitDelay; --fSCK=80MHz + -- DDR operation values + tperiod_SCK_DDR_rd : VitalDelayType := UnitDelay; --fSCK=66MHz + + -- tdevice values: values for internal delays + --timing values that are internal to the model and not associated + --with any port. + tdevice_PP : VitalDelayType := 750 us; --tPP + -- Typical Byte Programming Time + tdevice_BP : VitalDelayType := 400 us; --tBP + -- Sector Erase Operation + tdevice_SE : VitalDelayType := 1875 ms; --tSE + -- Bulk Erase Operation + tdevice_BE : VitalDelayType := 460 sec; --tBE + -- WRR Cycle Time + tdevice_WRR : VitalDelayType := 200 ms; --tW + -- Erase Suspend/Erase Resume Time + tdevice_ERSSUSP : VitalDelayType := 40 us; --tESL + -- Program Suspend/Program Resume Time + tdevice_PRGSUSP : VitalDelayType := 40 us; --tPSL + -- VCC (min) to CS# Low + tdevice_PU : VitalDelayType := 300 us; --tPU + -- PPB Erase Time + tdevice_PPBERASE :VitalDelayType := 15 ms; + -- Password Unlock Time + tdevice_PASSULCK :VitalDelayType := 1 us; + -- Password Unlock Time + tdevice_PASSACC :VitalDelayType := 100 us; + + --------------------------------------------------------------------------- + -- CONTROL GENERICS: + --------------------------------------------------------------------------- + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING := "s25fl512s.mem"; + otp_file_name : STRING := "s25fl512sOTP.mem"; + + UserPreload : BOOLEAN := FALSE; --TRUE; + LongTimming : BOOLEAN := TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING + ); + PORT ( + -- Data Inputs/Outputs + SI : INOUT std_ulogic := 'U'; -- serial data input/IO0 + SO : INOUT std_ulogic := 'U'; -- serial data output/IO1 + -- Controls + SCK : IN std_ulogic := 'U'; -- serial clock input + CSNeg : IN std_ulogic := 'U'; -- chip select input + RSTNeg : IN std_ulogic := 'U'; -- hardware reset pin + WPNeg : INOUT std_ulogic := 'U'; -- write protect input/IO2 + HOLDNeg : INOUT std_ulogic := 'U' -- hold input/IO3 + ); + + ATTRIBUTE VITAL_LEVEL0 of s25fl512s : ENTITY IS TRUE; +END s25fl512s; + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral_dynamic_memory_allocation of s25fl512s IS + ATTRIBUTE VITAL_LEVEL0 OF + vhdl_behavioral_dynamic_memory_allocation : ARCHITECTURE IS TRUE; + + --------------------------------------------------------------------------- + -- CONSTANT AND SIGNAL DECLARATION + --------------------------------------------------------------------------- + --Declaration of constants - memory characteristics + -- The constant declared here are used to enable the creation of models + -- of memories within a family with a minimum amount of editing + + CONSTANT PartID : STRING := "s25fl512s"; + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT MemSize : NATURAL := 16#3FFFFFF#; + CONSTANT SecNum : NATURAL := 255; + CONSTANT SecSize : NATURAL := 16#3FFFF#; --256KB + CONSTANT PageNum : NATURAL := 16#1FFFF#; + CONSTANT PageSize : NATURAL := 512; + CONSTANT AddrRANGE : NATURAL := 16#3FFFFFF#; + CONSTANT HiAddrBit : NATURAL := 31; + CONSTANT OTPSize : NATURAL := 1023; + CONSTANT OTPLoAddr : NATURAL := 16#000#; + CONSTANT OTPHiAddr : NATURAL := 16#3FF#; + CONSTANT BYTE : NATURAL := 8; + + --Manufacturer Identification + CONSTANT Manuf_ID : NATURAL := 16#01#; + CONSTANT DeviceID : NATURAL := 16#19#; + --Electronic Signature + CONSTANT ESignature : NATURAL := 16#19#; + --Device ID + --Manufacturer Identification && Memory Type && Memory Capacity + CONSTANT Jedec_ID : NATURAL := 16#01#; -- first byte of Device ID + CONSTANT DeviceID1 : NATURAL := 16#02#; + CONSTANT DeviceID2 : NATURAL := 16#20#; + CONSTANT ExtendedBytes : NATURAL := 16#4D#; + CONSTANT ExtendedID : NATURAL := 16#00#; + CONSTANT DieRev : NATURAL := 16#00#; + CONSTANT MaskRev : NATURAL := 16#00#; + + -- Declaration of signals that will hold the delayed values of ports + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL RSTNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + SIGNAL RSTNeg_pullup : std_ulogic := 'U'; + + -- internal delays + SIGNAL PP_in : std_ulogic := '0'; + SIGNAL PP_out : std_ulogic := '0'; + SIGNAL BP_in : std_ulogic := '0'; + SIGNAL BP_out : std_ulogic := '0'; + SIGNAL SE_in : std_ulogic := '0'; + SIGNAL SE_out : std_ulogic := '0'; + SIGNAL BE_in : std_ulogic := '0'; + SIGNAL BE_out : std_ulogic := '0'; + SIGNAL WRR_in : std_ulogic := '0'; + SIGNAL WRR_out : std_ulogic := '0'; + SIGNAL ERSSUSP_in : std_ulogic := '0'; + SIGNAL ERSSUSP_out : std_ulogic := '0'; + SIGNAL PRGSUSP_in : std_ulogic := '0'; + SIGNAL PRGSUSP_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL RST_in : std_ulogic := '0';-- Hardware Reset Timeout + SIGNAL RST_out : std_ulogic := '1';-- + SIGNAL PPBERASE_in : std_ulogic := '0'; + SIGNAL PPBERASE_out : std_ulogic := '0'; + SIGNAL PASSULCK_in : std_ulogic := '0'; + SIGNAL PASSULCK_out : std_ulogic := '0'; + SIGNAL PASSACC_in : std_ulogic := '0'; + SIGNAL PASSACC_out : std_ulogic := '0'; + + --------------------------------------------------------------------------- + -- Memory data initial value. + -- Default value may be overridden by conigure_memory procedure + --------------------------------------------------------------------------- + SHARED VARIABLE max_data : NATURAL := 16#FF#; + + --------------------------------------------------------------------------- + -- Handle dynamic memory allocation + --------------------------------------------------------------------------- + -- Partition dynamically allocated space for performance + + SHARED VARIABLE corrupt_Sec : std_logic_vector(SecNum downto 0) + :=(OTHERS=>'0'); + + -- ------------------------------------------------------------------------ + -- Data types required to implement link list structure + -- ------------------------------------------------------------------------ + TYPE mem_data_t; + TYPE mem_data_pointer_t IS ACCESS mem_data_t; + TYPE mem_data_t IS RECORD + key_address : INTEGER; + val_data : INTEGER; + successor : mem_data_pointer_t; + END RECORD; + + -- --------------------------------------------------------------------- + -- Array of linked lists. + -- Support memory region partitioning for faster access. + -- --------------------------------------------------------------------- + TYPE mem_data_pointer_array_t IS + ARRAY(NATURAL RANGE <>) OF mem_data_pointer_t; + + SHARED VARIABLE linked_list : + mem_data_pointer_array_t(0 TO SecNum); + + -- --------------------------------------------------------------------- + -- Override mechanism provided for default parameter values + -- --------------------------------------------------------------------- + PROCEDURE configure_memory( + max_data_c : IN INTEGER) IS + BEGIN + max_data := max_data_c; + END PROCEDURE configure_memory; + + -- Asure proper initialization + PROCEDURE initialize IS + VARIABLE I : INTEGER; + BEGIN + FOR I IN 0 TO SecNum LOOP + linked_list(I) := NULL; + END LOOP; + END PROCEDURE initialize; + + -- --------------------------------------------------------------------- + -- Create linked listed + -- --------------------------------------------------------------------- + PROCEDURE create_list( + key_address : IN INTEGER; + val_data : IN INTEGER; + root : INOUT mem_data_pointer_t) IS + BEGIN + root := NEW mem_data_t; + root.successor := NULL; + root.key_address := key_address; + root.val_data := val_data; + END PROCEDURE create_list; + + -- -------------------------------------------------------------------- + -- Iterate through linked listed comapring key values + -- Stop when key value greater or equal + -- -------------------------------------------------------------------- + PROCEDURE position_list( + key_address : IN INTEGER; + root : INOUT mem_data_pointer_t; + found : INOUT mem_data_pointer_t; + prev : INOUT mem_data_pointer_t) IS + BEGIN + found := root; + prev := NULL; + WHILE ((found /= NULL) AND (found.key_address < key_address)) LOOP + prev := found; + found := found.successor; + END LOOP; + END PROCEDURE position_list; + + -- ------------------------------------------------------------------- + -- Add new element to a linked list + -- ------------------------------------------------------------------- + PROCEDURE insert_list( + key_address : IN INTEGER; + val_data : IN INTEGER; + root : INOUT mem_data_pointer_t) IS + + VARIABLE new_element : mem_data_pointer_t; + VARIABLE found : mem_data_pointer_t; + VARIABLE prev : mem_data_pointer_t; + BEGIN + position_list(key_address, root, found, prev); + + -- Insert at list tail + IF (found = NULL) THEN + prev.successor := NEW mem_data_t; + prev.successor.key_address := key_address; + prev.successor.val_data := val_data; + prev.successor.successor := NULL; + ELSE + -- Element exists, update memory data value + IF (found.key_address = key_address) THEN + found.val_data := val_data; + ELSE + -- No element found, allocate and link + new_element := NEW mem_data_t; + new_element.key_address := key_address; + new_element.val_data := val_data; + new_element.successor := found; + -- Possible root position + IF (prev /= NULL) THEN + prev.successor := new_element; + ELSE + root := new_element; + END IF; + END IF; + END IF; + END PROCEDURE insert_list; + + -- -------------------------------------------------------------------- + -- Remove element from a linked list + -- -------------------------------------------------------------------- + PROCEDURE remove_list( + key_address : IN INTEGER; + root : INOUT mem_data_pointer_t) IS + + VARIABLE found : mem_data_pointer_t; + VARIABLE prev : mem_data_pointer_t; + BEGIN + position_list(key_address, root, found, prev); + IF (found /= NULL) THEN + -- Key value match + IF (found.key_address = key_address) THEN + -- Handle root position removal + IF (prev /= NULL) THEN + prev.successor := found.successor; + ELSE + root := found.successor; + END IF; + DEALLOCATE(found); + END IF; + END IF; + END PROCEDURE remove_list; + + -- ------------------------------------------------------------------- + -- Remove range of elements from a linked list + -- Higher performance than one-by-one removal + -- ------------------------------------------------------------------- + PROCEDURE remove_list_range( + address_low : IN INTEGER; + address_high : IN INTEGER; + root : INOUT mem_data_pointer_t) IS + + VARIABLE iter : mem_data_pointer_t; + VARIABLE prev : mem_data_pointer_t; + VARIABLE link_element : mem_data_pointer_t; + BEGIN + iter := root; + prev := NULL; + -- Find first linked list element belonging to + -- a specified address range [address_low, address_high] + WHILE ((iter /= NULL) AND NOT ( + (iter.key_address >= address_low) AND + (iter.key_address <= address_high))) LOOP + prev := iter; + iter := iter.successor; + END LOOP; + -- Continue until address_high reached + -- Deallocate linked list elements pointed by iterator + IF (iter /= NULL) THEN + WHILE ((iter /= NULL) AND + (iter.key_address >= address_low) AND + (iter.key_address <= address_high)) LOOP + link_element := iter.successor; + DEALLOCATE(iter); + iter := link_element; + END LOOP; + -- Handle possible root value change + IF prev /= NULL THEN + prev.successor := link_element; + ELSE + root := link_element; + END IF; + END IF; + END PROCEDURE remove_list_range; + + -- --------------------------------------------------------------------- + -- Address range to be erased + -- --------------------------------------------------------------------- + PROCEDURE erase_mem( + address_low : IN INTEGER; + address_high : IN INTEGER; + linked_list : INOUT mem_data_pointer_t) IS + + BEGIN + remove_list_range( + address_low, + address_high, + linked_list + ); + END PROCEDURE erase_mem; + + -- -------------------------------------------------------------------- + -- Memory READ operation performed above dynamically allocated space + -- -------------------------------------------------------------------- + PROCEDURE read_mem( + linked_list : INOUT mem_data_pointer_t; + data : INOUT INTEGER; + address : IN INTEGER) IS + + VARIABLE found : mem_data_pointer_t; + VARIABLE prev : mem_data_pointer_t; + VARIABLE mem_data : INTEGER; + BEGIN + IF (linked_list = NULL) THEN + -- Not allocated, not written, initial value + mem_data := max_data ; + ELSE + position_list(address, linked_list, found, prev); + IF (found /= NULL) THEN + IF found.key_address = address THEN + -- Allocated, val_data stored + mem_data := found.val_data; + ELSE + -- Not allocated, not written, initial value + mem_data := max_data ; + END IF; + ELSE + -- Not allocated, not written, initial value + mem_data := max_data ; + END IF; + END IF; + data := mem_data; + END PROCEDURE read_mem; + + -- ------------------------------------------------------------------ + -- Memory WRITE operation performed above dynamically allocated space + -- ------------------------------------------------------------------ + PROCEDURE write_mem( + linked_list : INOUT mem_data_pointer_t; + address : IN INTEGER; + data : IN INTEGER) IS + + BEGIN + IF (data /= max_data ) THEN + -- Handle possible root value update + IF (linked_list /= NULL) THEN + insert_list(address, data, linked_list); + ELSE + create_list(address, data, linked_list); + END IF; + ELSE + -- Deallocate if initial value written + -- No linked list, NOP, initial value implicit + IF (linked_list /= NULL) THEN + remove_list(address, linked_list); + END IF; + END IF; + END PROCEDURE write_mem; + + PROCEDURE READ_DATA( + sectoraddr : IN NATURAL RANGE 0 TO Secnum; + addressinsec : IN NATURAL RANGE 0 TO SecSize; + ReadData : INOUT INTEGER) IS + BEGIN + read_mem(linked_list(sectoraddr), + ReadData, + addressinsec + ); + IF (ReadData = MaxData AND Corrupt_Sec(sectoraddr) = '1') THEN + ReadData := -1; + ELSIF (ReadData = MaxData+1) AND Corrupt_Sec(sectoraddr) = '1' THEN + ReadData := MaxData; + END IF; + END READ_DATA; + + PROCEDURE WRITE_DATA( + sectoraddr : IN NATURAL RANGE 0 TO Secnum; + addressinsec : IN NATURAL RANGE 0 TO SecSize; + WriteData : IN INTEGER) IS + BEGIN + IF (WriteData = MaxData AND Corrupt_Sec(sectoraddr) = '1') THEN + write_mem(linked_list(sectoraddr), + addressinsec, + WriteData+1 + ); + ELSE + write_mem(linked_list(sectoraddr), + addressinsec, + WriteData + ); + END IF; + END WRITE_DATA; + + FUNCTION ReturnSectorID(ADDR : NATURAL) RETURN NATURAL IS + VARIABLE result : NATURAL; + BEGIN + IF ADDR <= AddrRange THEN + result := ADDR / (SecSize+1); + ELSE + result := SecNum+1; + END IF; + RETURN result; + END ReturnSectorID; + + FUNCTION ReturnSectorIDRdPswdMd(TBPROT : std_logic) RETURN NATURAL IS + VARIABLE result : NATURAL; + BEGIN + result := SecNum; + IF TBPROT = '0' THEN + result := 0; + END IF; + RETURN result; + END ReturnSectorIDRdPswdMd; + +BEGIN + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + -- Because a tdevice generics is used, there must be a VITAL_primitives + -- assotiated with them + PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); + BP :VitalBuf(BP_out, BP_in, (tdevice_BP ,UnitDelay)); + SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); + BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); + WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay)); + ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay)); + PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + PPBERASE :VitalBuf(PPBERASE_out,PPBERASE_in,(tdevice_PPBERASE,UnitDelay)); + PASSULCK :VitalBuf(PASSULCK_out,PASSULCK_in,(tdevice_PASSULCK,UnitDelay)); + PASSACC :VitalBuf(PASSACC_out, PASSACC_in, (tdevice_PASSACC ,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO); + w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_5 : VitalWireDelay (RSTNeg_ipd, RSTNeg, tipd_RSTNeg); + w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + SCK : IN std_ulogic := 'U'; + CSNeg : IN std_ulogic := 'U'; + RSTNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + + PORT MAP ( + SIIn => SI_ipd, + SIOut => SI, + SOIn => SO_ipd, + SOut => SO, + SCK => SCK_ipd, + CSNeg => CSNeg_ipd, + RSTNeg => RSTNeg_ipd, + HOLDNegIn => HOLDNeg_ipd, + HOLDNegOut => HOLDNeg, + WPNegIn => WPNeg_ipd, + WPNegOut => WPNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + RESET_STATE, + AUTOBOOT, + WRITE_SR, + PAGE_PG, + OTP_PG, + PG_SUSP, + SECTOR_ERS, + BULK_ERS, + ERS_SUSP, + ERS_SUSP_PG, + ERS_SUSP_PG_SUSP, + PASS_PG, + PASS_UNLOCK, + PPB_PG, + PPB_ERS, + AUTOBOOT_PG, + ASP_PG, + PLB_PG, + DYB_PG, + NVDLR_PG + ); + + -- Instruction Type + TYPE instruction_type IS ( NONE, + WREN, -- Write Enable + WRDI, -- Write Disable + WRR, -- Write Register + READ, -- Read Normal (3Byte Address) + RD4, -- Read Normal (4Byte +) + OTPR, -- OTP Read + RDSR, -- Read Status Register 1 + RDSR2, -- Read Status Register 2 + RDCR, -- Read Configuration Register 1 + REMS, -- Read ID (SST) + RDID, -- Read ID JEDEC + RES, -- Read ID + FSTRD, -- Fast Read (3Byte Address) + FSTRD4, -- Fast Read (4Byte +) + DDRFR, -- Fast Read DDR (3Byte Address) + DDRFR4, -- Fast Read DDR (4Byte +) + DOR, -- Read Dual Out (3Byte Address) + DOR4, -- Read Dual Out (4Byte +) + DIOR, -- Read Dual I/O (3Byte Address) + DIOR4, -- Read Dual I/O (4Byte +) + DDRDIOR, -- Read DDR Dual I/O (3Byte) + DDRDIOR4, -- Read DDR Dual I/O (4Byte +) + QOR, -- Read Quad Out (3Byte Address) + QOR4, -- Read Quad Out (4Byte +) + QIOR, -- Read Quad I/O (3Byte Address) + QIOR4, -- Read Quad I/O (4Byte +) + DDRQIOR, -- Read DDR Quad I/O (3Byte) + DDRQIOR4, -- Read DDR Quad I/O (4Byte +) + PP, -- Program Page (3Byte Address) + PP4, -- Program Page (4Byte +) + QPP, -- Quad Page Program (3Byte) + QPP4, -- Quad Page Program (4Byte +) + OTPP, -- OTP Program + PGSP, -- Program Suspend + PGRS, -- Program Resume + BE, -- Bulk Erase + SE, -- Erase 128/256KB (3Byte) + SE4, -- Erase 128/256KB (4Byte +) + P4E, -- 4KB-sector Erase (3Byte Addr) + P4E4, -- 4KB-sector Erase (4Byte Addr) + ERSP, -- Erase Suspend + ERRS, -- Erase Resume + ABRD, -- AutoBoot Register Read + ABWR, -- AutoBoot Register Write + BRRD, -- Bank Register Read + BRWR, -- Bank Register Write + BRAC, -- Bank Register Access + DLPRD, -- Read Data Learning Pattern + PNVDLR, -- Program NVDLP Reg + WVDLR, -- Write Volatile DLP Reg + ASPRD, -- ASP Read + ASPP, -- ASP Program + DYBRD, -- DYB Read + DYBWR, -- DYB Write + PPBRD, -- PPB Read + PPBP, -- PPB Program + PPBERS, -- PPB Erase + PLBWR, -- PPB Lock Bit Write + PLBRD, -- PPB Lock Bit Read + PASSRD, -- Password Read + PASSP, -- Password Program + PASSU, -- Password Unlock + RESET, -- Reset + MBR, -- Mode Bit Reset + MPM, -- Multi-I/O-High Perf Mode + CLSR -- Clear Status Register + ); + + TYPE WByteType IS ARRAY (0 TO 511) OF INTEGER RANGE -1 TO MaxData; + -- OTP Memory Array + TYPE OTPArray IS ARRAY (OTPLoAddr TO OTPHiAddr) OF INTEGER + RANGE -1 TO MaxData; + --CFI Array (Common Flash Interface Query codes) + TYPE CFItype IS ARRAY (16#00# TO 16#55#) OF + INTEGER RANGE -1 TO 16#FF#; + ----------------------------------------------------------------------- + -- memory declaration + ----------------------------------------------------------------------- + -- OTP Sector + SHARED VARIABLE OTPMem : OTPArray := (OTHERS => MaxData); + --CFI Array + SHARED VARIABLE CFI_array : CFItype := (OTHERS => 0); + -- Programming Buffer + SIGNAL WByte : WByteType := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + ----------------------------------------------------------------------- + -- Registers + ----------------------------------------------------------------------- + -- *** Status Register 1 *** + SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Disable Bit + ALIAS SRWD :std_logic IS Status_reg1(7); + -- Status Register Programming Error Bit + ALIAS P_ERR :std_logic IS Status_reg1(6); + -- Status Register Erase Error Bit + ALIAS E_ERR :std_logic IS Status_reg1(5); + -- Status Register Block Protection Bits + ALIAS BP2 :std_logic IS Status_reg1(4); + ALIAS BP1 :std_logic IS Status_reg1(3); + ALIAS BP0 :std_logic IS Status_reg1(2); + -- Status Register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg1(1); + -- Status Register Write In Progress Bit + ALIAS WIP :std_logic IS Status_reg1(0); + + -- *** Status Register 2 *** + SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg2_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Enable Latch Bit + ALIAS ES :std_logic IS Status_reg2(1); + -- Status Register Write In Progress Bit + ALIAS PS :std_logic IS Status_reg2(0); + + -- *** Configuration Register 1 *** + SHARED VARIABLE Config_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Config_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Latency code + ALIAS LC1 :std_logic IS Config_reg1(7); + ALIAS LC0 :std_logic IS Config_reg1(6); + -- Configuration Register TBPROT bit + ALIAS TBPROT :std_logic IS Config_reg1(5); + -- Configuration Register LOCK bit + ALIAS LOCK :std_logic IS Config_reg1(4); + -- Configuration Register BPNV bit + ALIAS BPNV :std_logic IS Config_reg1(3); + -- Configuration Register QUAD bit + ALIAS QUAD :std_logic IS Config_reg1(1); + -- Configuration Register FREEZE bit + ALIAS FREEZE :std_logic IS Config_reg1(0); + + -- *** VDLR Register *** + SHARED VARIABLE VDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL VDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** NVDLR Register *** + SHARED VARIABLE NVDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL NVDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** AutoBoot Register *** + SHARED VARIABLE AutoBoot_reg : std_logic_vector(31 downto 0) + := (others => '0'); + SIGNAL AutoBoot_reg_in : std_logic_vector(31 downto 0) + := (others => '0'); + + --AutoBoot Enable Bit + ALIAS ABE :std_logic IS AutoBoot_reg(0); + + -- *** Bank Address Register *** + SHARED VARIABLE Bank_Addr_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Bank_Addr_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Bank Address Register EXTADD bit + ALIAS EXTADD :std_logic IS Bank_Addr_reg(7); + + -- *** ASP Register *** + SHARED VARIABLE ASP_reg : std_logic_vector(15 downto 0); + SIGNAL ASP_reg_in : std_logic_vector(15 downto 0) + := (others => '1'); + --Read Password Mode Enable Bit + ALIAS RPME :std_logic IS ASP_reg(5); + --PPB OTP Bit + ALIAS PPBOTP :std_logic IS ASP_reg(3); + -- Password Protection Mode Lock Bit + ALIAS PWDMLB :std_logic IS ASP_reg(2); + --Persistent Protection Mode Lock Bit + ALIAS PSTMLB :std_logic IS ASP_reg(1); + + -- *** Password Register *** + SHARED VARIABLE Password_reg : std_logic_vector(63 downto 0) + := (others => '1'); + SIGNAL Password_reg_in : std_logic_vector(63 downto 0) + := (others => '1'); + -- *** PPB Lock Register *** + SHARED VARIABLE PPBL : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL PPBL_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Persistent Protection Mode Lock Bit + ALIAS PPB_LOCK : std_logic IS PPBL(0); + SIGNAL PPB_LOCK_temp : std_ulogic := '0'; + -- *** PPB Access Register *** + SHARED VARIABLE PPBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL PPBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- PPB_bits(Sec) + SHARED VARIABLE PPB_bits : std_logic_vector(SecNum downto 0) + := (OTHERS => '1'); + -- *** DYB Access Register *** + SHARED VARIABLE DYBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL DYBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- DYB(Sec) + SHARED VARIABLE DYB_bits : std_logic_vector(SecNum downto 0); + + -- The Lock Protection Registers for OTP Memory space + SHARED VARIABLE LOCK_BYTE1 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE2 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE3 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE4 :std_logic_vector(7 downto 0); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL cfg_write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL rd : boolean := false; + SIGNAL dual : boolean := false; + SIGNAL fast_rd : boolean := true; + SIGNAL ddr : boolean := false; + SIGNAL any_read : boolean := false; + + SIGNAL quadpg : boolean := false; + + SIGNAL oe : boolean := false; + SIGNAL oe_z : boolean := false; + + SHARED VARIABLE hold_mode : boolean := false; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; --Page Prog. Done + SIGNAL PSTART : std_logic := '0'; --Start Page Programming + SIGNAL PGSUSP : std_logic := '0'; --Suspend Program + SIGNAL PGRES : std_logic := '0'; --Resume Program + + SIGNAL RES_TO_SUSP_MIN_TIME : std_logic := '0';--Resume to Suspend Flag + SIGNAL RES_TO_SUSP_TYP_TIME : std_logic := '0';--Resume to Suspend Flag + + SIGNAL WDONE : std_logic := '1'; --Write operation Done + SIGNAL WSTART : std_logic := '0'; --Start Write operation + + SIGNAL ESTART : std_logic := '0'; --Start Erase operation + SIGNAL EDONE : std_logic := '1'; --Erase operation Done + SIGNAL ESUSP : std_logic := '0'; --Suspend Erase + SIGNAL ERES : std_logic := '0'; --Resume Erase + + --reset timing + SIGNAL RST : std_logic := '0'; + SIGNAL Reseted : std_logic := '0'; --Reset Timing Control + --Lock Bit is enabled for customer programming + SIGNAL WRLOCKENABLE : BOOLEAN := TRUE; + --Flag that mark if ASP Register is allready programmed + SIGNAL ASPOTPFLAG : BOOLEAN := FALSE; + SIGNAL ASP_INIT : NATURAL RANGE 0 TO 1; + SIGNAL INITIAL_CONFIG : std_logic := '0'; + + SHARED VARIABLE SecAddr : NATURAL RANGE 0 TO SecNum:= 0; + + SHARED VARIABLE Sec_addr : NATURAL := 0; + + SHARED VARIABLE Page_addr : NATURAL; + SHARED VARIABLE pgm_page : NATURAL; + + SHARED VARIABLE QPP_page : std_logic_vector(PageNum downto 0) + := (OTHERS => '0'); + + --Flag for Password unlock command + SIGNAL PASS_UNLOCKED : boolean := FALSE; + SIGNAL PASS_TEMP : std_logic_vector(63 downto 0) + := (others => '1'); + + SHARED VARIABLE DOUBLE : BOOLEAN := FALSE; + SHARED VARIABLE EHP : BOOLEAN := FALSE; + + SHARED VARIABLE read_cnt : NATURAL := 0; + SHARED VARIABLE byte_cnt : NATURAL := 1; + SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ; + + SHARED VARIABLE start_delay : NATURAL RANGE 0 TO 7; + SHARED VARIABLE ABSD : NATURAL RANGE 0 TO 7; + SIGNAL start_autoboot : std_logic := '0'; + + SIGNAL change_addr : std_logic := '0'; + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + SIGNAL SectorSuspend : NATURAL RANGE 0 TO SecNum := 0; + + -- Sector address + SIGNAL SA : NATURAL RANGE 0 TO SecNum := 0; + + -- Sector is protect if Sec_Prot(SecNum) = '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum downto 0) := + (OTHERS => '0'); + + SIGNAL change_BP : std_logic := '0'; + SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000"; + + SHARED VARIABLE CFI_array_tmp : std_logic_vector(647 downto 0); + + SIGNAL Byte_number : NATURAL RANGE 0 TO 511 := 0; + + TYPE bus_cycle_type IS (STAND_BY, + OPCODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + SHARED VARIABLE bus_cycle_state : bus_cycle_type; + -- switch between Data bytes and Dummy bytes + SHARED VARIABLE DummyBytes_act : X01 := '0'; + SIGNAL dummy_cnt_act_temp : NATURAL := 0; + SIGNAL dummy_cnt_act : NATURAL := 0; + --Read Password Protection Mode Active flag + SIGNAL RdPswdProtMode : std_ulogic := '0'; + --Read Password Protection Mode Support flag + SIGNAL RdPswdProtEnable : std_ulogic := '0'; + SIGNAL BAR_ACC : std_ulogic := '0'; + + SHARED VARIABLE Latency_code : NATURAL RANGE 0 TO 7; + SHARED VARIABLE opcode_cnt : NATURAL := 0; + SHARED VARIABLE addr_cnt : NATURAL := 0; + SHARED VARIABLE mode_cnt : NATURAL := 0; + SHARED VARIABLE dummy_cnt : NATURAL := 0; + SHARED VARIABLE data_cnt : NATURAL := 0; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO SecNum; + BEGIN + sector := Addr/16#40000#; + AddrLOW := sector*16#40000#; + AddrHIGH := sector*16#40000# + 16#3FFFF#; + END ADDRHILO_SEC; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Sec_address : INOUT NATURAL RANGE 0 TO SecSize; + VARIABLE Page_address : INOUT NATURAL; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + VARIABLE Sec : NATURAL RANGE 0 TO SecNum; + VARIABLE Sec_addr_tmp : NATURAL RANGE 0 TO ADDRRange; + BEGIN + Sec := Addr/(SecSize+1); + Sec_addr_tmp := Sec*(SecSize+1); + page := Addr/PageSize; + AddrLOW := Page*PageSize; + AddrLOW := AddrLOW - Sec_addr_tmp; + AddrHIGH := AddrLOW + PageSize-1; + Sec_address := Addr - Sec_addr_tmp; + Page_address := page; + END ADDRHILO_PG; + + BEGIN + --------------------------------------------------------------------------- + --Power Up time + --------------------------------------------------------------------------- + + PoweredUp <= '1' AFTER tdevice_PU; + + TimingModelSel: PROCESS + BEGIN + --Enhanced High Performance Flag + IF (TimingModel(15) = '0' OR TimingModel(15) = '2' OR + TimingModel(15) = '3' OR TimingModel(15) = 'R' OR + TimingModel(15) = 'A' OR TimingModel(15) = 'B' OR + TimingModel(15) = 'C' OR TimingModel(15) = 'D' OR + TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + EHP := TRUE; + IF (TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + RdPswdProtEnable <= '1'; + END IF; + ELSIF (TimingModel(15) = '4' OR TimingModel(15) = '6' OR + TimingModel(15) = '7' OR TimingModel(15) = '8' OR + TimingModel(15) = '9' OR TimingModel(15) = 'Q') THEN + EHP := FALSE; + END IF; + + IF (TimingModel(15) ='0' OR TimingModel(15) ='2' OR + TimingModel(15) ='3' OR TimingModel(15) ='R' OR + TimingModel(15) ='A' OR TimingModel(15) ='B' OR + TimingModel(15) ='C' OR TimingModel(15) ='D' OR + TimingModel(15) ='4' OR TimingModel(15) ='6' OR + TimingModel(15) ='7' OR TimingModel(15) ='8' OR + TimingModel(15) ='9' OR TimingModel(15) ='Q') THEN + ASP_INIT <= 1; + ELSIF (TimingModel(15) ='Y' OR TimingModel(15) ='Z' OR + TimingModel(15) ='S' OR TimingModel(15) ='T' OR + TimingModel(15) ='K' OR TimingModel(15) ='L') THEN + ASP_INIT <= 0; + END IF; + WAIT; + END PROCESS; + + RSTtiming: PROCESS(RSTNeg_pullup,Instruct) + BEGIN + IF falling_edge(RSTNeg_pullup) THEN + RST <= '1', '0' AFTER 200 ns; + ELSIF Instruct = RESET THEN + Reseted <= '0', '1' AFTER 10 ns; + END IF; + END PROCESS; + + DUMMYcnt: PROCESS(dummy_cnt_act_temp) + BEGIN + dummy_cnt_act <= dummy_cnt_act_temp; + END PROCESS; + + ReadPasswordProtectionMode: PROCESS(PPB_LOCK_temp, + ASP_reg_in(2), ASP_reg_in(5)) + BEGIN + IF (PPB_LOCK = '0' AND PWDMLB = '0' AND RPME = '0' AND + RdPswdProtEnable = '1') THEN + RdPswdProtMode <= '1'; + ABE := '0'; + ELSE + RdPswdProtMode <= '0'; + END IF; + END PROCESS; + --------------------------------------------------------------------------- + -- autoboot control logic + --------------------------------------------------------------------------- + AutoBootControl: PROCESS(SCK_ipd, current_state) + BEGIN + IF (current_state = AUTOBOOT) THEN + IF rising_edge(SCK_ipd) THEN + IF (start_delay > 0) THEN + start_delay := start_delay - 1; + END IF; + END IF; + + IF (start_delay = 0) THEN + start_autoboot <= '1'; + ELSE + start_autoboot <= '0'; + END IF; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn, SOIn, SCK_ipd, CSNeg_ipd, RSTNeg_ipd, + HOLDNegIn, WPNegIn) + + -- Timing Check Variables + -- Setup/Hold Checks variables + VARIABLE Tviol_CSNeg_SCK_normal : X01 := '0'; + VARIABLE TD_CSNeg_SCK_normal : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_SCK_DDR : X01 := '0'; + VARIABLE TD_CSNeg_SCK_DDR : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_RSTNeg : X01 := '0'; + VARIABLE TD_CSNeg_RSTNeg : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType; + + VARIABLE Tviol_HOLDNeg_SCK : X01 := '0'; + VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_R : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_R : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_F : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_F : VitalTimingDataType; + + VARIABLE Tviol_RSTNeg_CSNeg : X01 := '0'; + VARIABLE TD_RSTNeg_CSNeg : VitalTimingDataType; + + --Pulse Width and Period Check Variables + VARIABLE Pviol_SCK_serial : X01 := '0'; + VARIABLE PD_SCK_serial : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual : X01 := '0'; + VARIABLE PD_SCK_dual : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast : X01 := '0'; + VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quadpg : X01 := '0'; + VARIABLE PD_SCK_quadpg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR : X01 := '0'; + VARIABLE PD_SCK_DDR : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_read : X01 := '0'; + VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_pgers : X01 := '0'; + VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_RSTNeg : X01 := '0'; + VARIABLE PD_RSTNeg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_rd : X01 := '0'; + VARIABLE PD_SCK_serial_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_rd : X01 := '0'; + VARIABLE PD_SCK_fast_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual_rd : X01 := '0'; + VARIABLE PD_SCK_dual_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR_rd : X01 := '0'; + VARIABLE PD_SCK_DDR_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quad_pg : X01 := '0'; + VARIABLE PD_SCK_quad_pg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_normal_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_normal_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_normal_noedge_posedge, + HoldLow => thold_CSNeg_SCK_normal_noedge_posedge, + CheckEnabled => ddr = false, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_normal, + Violation => Tviol_CSNeg_SCK_normal + ); + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_DDR_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_DDR_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_DDR_noedge_posedge, + HoldLow => thold_CSNeg_SCK_DDR_noedge_posedge, + CheckEnabled => ddr, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_DDR, + Violation => Tviol_CSNeg_SCK_DDR + ); + + -- Hold Check between CSNeg and RSTNeg + VitalSetupHoldCheck ( + TestSignal => CSNeg, + TestSignalName => "CSNeg", + RefSignal => RSTNeg, + RefSignalName => "RSTNeg", + HoldHigh => thold_CSNeg_RSTNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_RSTNeg, + Violation => Tviol_CSNeg_RSTNeg + ); + + -- Setup/Hold Check between SI and SCK, serial mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => NOT(DOUBLE) AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => true, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_setup, + Violation => Tviol_WPNeg_CSNeg_setup + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => SRWD = '1' AND WEL = '1', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_hold, + Violation => Tviol_WPNeg_CSNeg_hold + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupLow => tsetup_HOLDNeg_SCK, + SetupHigh => tsetup_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + CheckEnabled => QUAD = '0' + AND HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNeg_SCK, + Violation => Tviol_HOLDNeg_SCK + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_posedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_posedge, + HoldHigh => thold_SI_SCK_DDR_noedge_posedge, + HoldLow => thold_SI_SCK_DDR_noedge_posedge, + CheckEnabled => DOUBLE AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_R, + Violation => Tviol_SI_SCK_DDR_R + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_negedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_negedge, + HoldHigh => thold_SI_SCK_DDR_noedge_negedge, + HoldLow => thold_SI_SCK_DDR_noedge_negedge, + CheckEnabled => ddr AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_F, + Violation => Tviol_SI_SCK_DDR_F + ); + + -- Setup Check between RSTNeg and SCK, DDR fast mode + VitalSetupHoldCheck ( + TestSignal => RSTNeg, + TestSignalName => "RSTNeg", + RefSignal => CSNeg, + RefSignalName => "CSNeg", + SetupHigh => tsetup_RSTNeg_CSNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_RSTNeg_CSNeg, + Violation => Tviol_RSTNeg_CSNeg + ); + + --Pulse Width and Period Check Variables + -- Pulse Width Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_serial_negedge, + PulseWidthHigh => tpw_SCK_serial_posedge, + PeriodData => PD_SCK_serial, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd); + + -- Pulse Width Check SCK for DUAL_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_dual_negedge, + PulseWidthHigh => tpw_SCK_dual_posedge, + PeriodData => PD_SCK_dual, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual); + + -- Pulse Width Check SCK for FAST_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_fast_negedge, + PulseWidthHigh => tpw_SCK_fast_posedge, + PeriodData => PD_SCK_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Pulse Width Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_quadpg_negedge, + PulseWidthHigh => tpw_SCK_quadpg_posedge, + PeriodData => PD_SCK_quadpg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quadpg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg); + + -- Pulse Width Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CSNeg_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => any_read ); + + -- Pulse Width Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pgers_posedge, + PeriodData => PD_CSNeg_pgers, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_pgers, + HeaderMsg => InstancePath & PartID, + CheckEnabled => NOT(any_read)); + + -- Pulse Width Check RSTNeg + VitalPeriodPulseCheck ( + TestSignal => RSTNeg_ipd, + TestSignalName => "RSTNeg", + PulseWidthLow => tpw_RSTNeg_negedge, + PulseWidthHigh => tpw_RSTNeg_posedge, + CheckEnabled => TRUE, + HeaderMsg => InstancePath & PartID, + PeriodData => PD_RSTNeg, + Violation => Pviol_RSTNeg + ); + + -- Pulse Width Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_DDR_negedge, + PulseWidthHigh => tpw_SCK_DDR_posedge, + PeriodData => PD_SCK_DDR, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_rd, + PeriodData => PD_SCK_serial_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for FAST READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast_rd, + PeriodData => PD_SCK_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Period Check SCK for DUAL READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_dual_rd, + PeriodData => PD_SCK_dual_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual ); + + -- Period Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_quadpg, + PeriodData => PD_SCK_quad_pg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quad_pg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg ); + + -- Period Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_DDR_rd, + PeriodData => PD_SCK_DDR_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr ); + + Violation := Tviol_CSNeg_SCK_normal OR + Tviol_CSNeg_SCK_DDR OR + Tviol_CSNeg_RSTNeg OR + Tviol_SI_SCK OR + Tviol_WPNeg_CSNeg_setup OR + Tviol_WPNeg_CSNeg_hold OR + Tviol_HOLDNeg_SCK OR + Tviol_SI_SCK_DDR_R OR + Tviol_SI_SCK_DDR_F OR + Tviol_RSTNeg_CSNeg OR + Pviol_SCK_serial OR + Pviol_SCK_dual OR + Pviol_SCK_fast OR + Pviol_SCK_quadpg OR + Pviol_CSNeg_read OR + Pviol_CSNeg_pgers OR + Pviol_SCK_DDR OR + Pviol_SCK_serial_rd OR + Pviol_SCK_fast_rd OR + Pviol_SCK_dual_rd OR + Pviol_SCK_quad_pg OR + Pviol_SCK_DDR_rd; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + + ---------------------------------------------------------------------------- + -- sequential process for FSM state transition + ---------------------------------------------------------------------------- + StateTransition : PROCESS(next_state, RST, PoweredUp, RST_out) + + BEGIN + IF PoweredUp = '1' THEN + IF RSTNeg_pullup = '1' and RST_out= '1' THEN + IF next_state'EVENT THEN + current_state <= next_state; + END IF; + ELSIF RSTNeg_pullup = '0' AND falling_edge(RST) THEN + --no state transition while RESET# low + current_state <= RESET_STATE; + RST_in <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END PROCESS StateTransition; + + Threset : PROCESS(RST_in) + BEGIN + IF rising_edge(RST_in) THEN + RST_out <= '0', '1' AFTER (thold_CSNeg_RSTNeg-200 ns); + END IF; + END PROCESS Threset; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_pullup, SIIn, RST_out, + WPNeg_pullup) + + TYPE quad_data_type IS ARRAY (0 TO 1023) OF INTEGER RANGE 0 TO 15; + + VARIABLE bit_cnt : NATURAL := 0; + VARIABLE Data_in : std_logic_vector(4095 downto 0) + := (others => '0'); + + VARIABLE opcode : std_logic_vector(7 downto 0); + VARIABLE opcode_in : std_logic_vector(7 downto 0); + VARIABLE addr_bytes : std_logic_vector(31 downto 0); + VARIABLE hiaddr_bytes : std_logic_vector(31 downto 0); + VARIABLE Address_in : std_logic_vector(31 downto 0); + VARIABLE mode_bytes : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + + VARIABLE CLK_PER : time; + VARIABLE LAST_CLK : time; + VARIABLE Check_freq : boolean := FALSE; + + BEGIN + + IF rising_edge(CSNeg_ipd) AND NOT(bus_cycle_state = DATA_BYTES) + AND NOT(bus_cycle_state = DUMMY_BYTES) THEN + bus_cycle_state := STAND_BY; + ELSE + CASE bus_cycle_state IS + WHEN STAND_BY => + IF falling_edge(CSNeg_ipd) THEN + Instruct <= NONE; + write <= '1'; + cfg_write <= '0'; + opcode_cnt:= 0; + addr_cnt := 0; + mode_cnt := 0; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + data_cnt := 0; + DOUBLE := FALSE; + CLK_PER := 0 ns; + LAST_CLK := 0 ns; + IF current_state = AUTOBOOT THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := OPCODE_BYTE; + END IF; + END IF; + + WHEN OPCODE_BYTE => + IF rising_edge(SCK_ipd) THEN + + Latency_code := to_nat(LC1 & LC0); + CLK_PER := NOW - LAST_CLK; + LAST_CLK := NOW; + IF Check_freq THEN + IF (CLK_PER < 20 ns AND Latency_code = 3) OR + (CLK_PER < 12.5 ns AND Latency_code = 0) OR + (CLK_PER < 11.1 ns AND Latency_code = 1) OR + (CLK_PER < 9.6 ns AND Latency_code = 2) THEN + ASSERT FALSE + REPORT "More wait states are required for " & + "this clock frequency value" + SEVERITY warning; + END IF; + END IF; + Check_freq := FALSE; + + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + --One-byte of instruction opcode is shifted into the + --device on the SI serial input pin with the most + --significant bit (MSB) first.Each bit input on the + --SI serial input pin is latched on the rising edge of + --the SCK serial clock signal. + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF opcode_cnt = BYTE THEN + --MSB first + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := opcode_in(7-i); + END LOOP; + + CASE opcode IS + WHEN "00000110" => --06h + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => --01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => --03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010011" => --13h + Instruct <= RD4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001011" => --4Bh + Instruct <= OTPR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00000101" => --05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000111" => --07h + Instruct <= RDSR2; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => --35h + Instruct <= RDCR; + bus_cycle_state := DATA_BYTES; + WHEN "10010000" => --90h + Instruct <= REMS; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10011111" => --9Fh + Instruct <= RDID; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => --ABh + Instruct <= RES; + bus_cycle_state := DUMMY_BYTES; + WHEN "00001011" => --0Bh + Instruct <= FSTRD; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001100" => --0Ch + Instruct <= FSTRD4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001101" => --0Dh + Instruct <= DDRFR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001110" => --0Eh + Instruct <= DDRFR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00111011" => --3Bh + Instruct <= DOR; + Check_freq := TRUE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111100" => --3Ch + Instruct <= DOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111011" => --BBh + Instruct <= DIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111100" => --BCh + Instruct <= DIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111101" => --BDh + Instruct <= DDRDIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111110" => --BEh + Instruct <= DDRDIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101011" => --6Bh + Instruct <= QOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101100" => --6Ch + Instruct <= QOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101011" => --EBh + Instruct <= QIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101100" => --ECh + Instruct <= QIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101101" => --EDh + Instruct <= DDRQIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101110" => --EEh + Instruct <= DDRQIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00000010" => --02h + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010010" => --12h + Instruct <= PP4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => --32h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00111000" => --38h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00110100" => --34h + Instruct <= QPP4; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "01000010" => --42h + Instruct <= OTPP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10000101" => --85h + Instruct <= PGSP; + bus_cycle_state := DATA_BYTES; + WHEN "10001010" => --8Ah + Instruct <= PGRS; + bus_cycle_state := DATA_BYTES; + WHEN "11000111" => --C7h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "01100000" => --60h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "11011000" => --D8h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11011100" => --DCh + Instruct <= SE4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100000" => --20h + Instruct <= P4E; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100001" => --21h + Instruct <= P4E4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01110101" => --75h + Instruct <= ERSP; + bus_cycle_state := DATA_BYTES; + WHEN "01111010" => --7Ah + Instruct <= ERRS; + bus_cycle_state := DATA_BYTES; + WHEN "00010100" => --14h + Instruct <= ABRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010101" => --15h + Instruct <= ABWR; + bus_cycle_state := DATA_BYTES; + WHEN "00010110" => --16h + Instruct <= BRRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010111" => --17h + Instruct <= BRWR; + bus_cycle_state := DATA_BYTES; + WHEN "10111001" => --B9h + Instruct <= BRAC; + bus_cycle_state := DATA_BYTES; + WHEN "00101011" => --2Bh + Instruct <= ASPRD; + bus_cycle_state := DATA_BYTES; + WHEN "00101111" => --2Fh + Instruct <= ASPP; + bus_cycle_state := DATA_BYTES; + WHEN "11100000" => --E0h + Instruct <= DYBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100001" => --E1h + Instruct <= DYBWR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100010" => --E2h + Instruct <= PPBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100011" => --E3h + Instruct <= PPBP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100100" => --E4h + Instruct <= PPBERS; + bus_cycle_state := DATA_BYTES; + WHEN "10100110" => --A6h + Instruct <= PLBWR; + bus_cycle_state := DATA_BYTES; + WHEN "10100111" => --A7h + Instruct <= PLBRD; + bus_cycle_state := DATA_BYTES; + WHEN "11100111" => --E7h + Instruct <= PASSRD; + bus_cycle_state := DATA_BYTES; + WHEN "11101000" => --E8h + Instruct <= PASSP; + bus_cycle_state := DATA_BYTES; + WHEN "11101001" => --E9h + Instruct <= PASSU; + bus_cycle_state := DATA_BYTES; + WHEN "11110000" => --F0h + Instruct <= RESET; + bus_cycle_state := DATA_BYTES; + WHEN "11111111" => --FFh + Instruct <= MBR; + bus_cycle_state := MODE_BYTE; + WHEN "01000001" => -- 41h + Instruct <= DLPRD; + bus_cycle_state := DATA_BYTES; + WHEN "01000011" => -- 43h + Instruct <= PNVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "01001010" => -- 4Ah + Instruct <= WVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "00110000" => --30h + Instruct <= CLSR; + bus_cycle_state := DATA_BYTES; + WHEN others => + null; + + END CASE; + END IF; + END IF; + END IF; + + WHEN ADDRESS_BYTES => + IF Instruct= DDRFR OR Instruct= DDRFR4 OR Instruct= DDRDIOR + OR Instruct = DDRDIOR4 OR Instruct = DDRQIOR OR + Instruct = DDRQIOR4 THEN + DOUBLE := TRUE; + ELSE + DOUBLE := FALSE; + END IF; + + IF (rising_edge(SCK_ipd) AND NOT(DOUBLE) AND + (CSNeg_ipd= '0')) THEN + IF (((Instruct=FSTRD AND EXTADD= '0' ) + OR (Instruct=DOR AND EXTADD= '0') + OR Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (Instruct=QOR AND QUAD= '1' AND EXTADD='0') THEN + --Instruction + 3 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF (Instruct=FSTRD OR Instruct=DOR OR + Instruct=QOR) THEN + IF (Latency_code = 3) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF ((((Instruct=FSTRD4) OR (Instruct=DOR4) OR + ((Instruct=FSTRD) AND EXTADD= '1') OR + ((Instruct=DOR) AND EXTADD= '1')) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct=QOR4) AND QUAD='1') OR + ((Instruct=QOR) AND QUAD='1' AND EXTADD='1')) THEN + --Instruction + 4 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF (DOUBLE AND NOT(hold_mode) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF Instruct = DIOR AND EXTADD= '0' AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + -- DUAL I/O High Performance Read (3Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF ((Instruct = DIOR4 OR + (Instruct = DIOR AND EXTADD= '1')) AND + ((HOLDNeg_pullup = '1' AND QUAD = '0') OR + QUAD = '1')) THEN + -- DUAL I/O High Performance Read (4Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR AND EXTADD= '0') THEN + -- QUAD I/O High Performance Read (3Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR4 OR + (Instruct = QIOR AND EXTADD= '1')) THEN + -- QUAD I/O High Performance Read (4Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) + := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (((Instruct = RD4 OR Instruct = PP4 OR + Instruct = SE4 OR Instruct = PPBRD OR + Instruct = DYBRD OR Instruct = DYBWR OR + Instruct = PPBP OR Instruct = P4E4 OR + (Instruct = READ AND EXTADD= '1' ) OR + (Instruct = PP AND EXTADD= '1' ) OR + (Instruct = P4E AND EXTADD= '1' ) OR + (Instruct = SE AND EXTADD= '1' )) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (QUAD ='1' AND (Instruct=QPP4 OR + (Instruct = QPP AND EXTADD= '1' ))))THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') AND EXTADD= '0') THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF (SCK_ipd'EVENT AND DOUBLE AND addr_cnt /= 0 ) OR + (rising_edge(SCK_ipd) AND DOUBLE AND addr_cnt = 0 ) THEN + IF (Instruct=DDRFR AND EXTADD= '0' ) THEN + --Fast DDR Read Mode + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 3*BYTE THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRFR4 OR + (Instruct=DDRFR AND EXTADD= '1' )) THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 4*BYTE THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct= DDRDIOR AND EXTADD= '0' ) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1):= SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRDIOR4 OR + (Instruct=DDRDIOR AND EXTADD= '1' )) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR AND EXTADD= '0' ) AND + QUAD = '1' THEN + --Quad I/O DDR Read Mode + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 5 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF QUAD = '1' AND (Instruct=DDRQIOR4 OR + (Instruct=DDRQIOR AND EXTADD= '1' )) THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + + WHEN MODE_BYTE => + IF rising_edge(SCK_ipd) THEN + IF ((Instruct=DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + IF Latency_code = 0 OR Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=QIOR OR Instruct = QIOR4) + AND QUAD = '1' THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSIF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt) := SIIn; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt) := SOIn; + mode_in(4*mode_cnt+1) := SIIn; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(0) := HOLDNegIn; + mode_in(1) := WPNegIn; + mode_in(2) := SOIn; + mode_in(3) := SIIn; + END IF; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + ELSIF falling_edge(SCK_ipd) THEN + IF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(4) := HOLDNegIn; + mode_in(5) := WPNegIn; + mode_in(6) := SOIn; + mode_in(7) := SIIn; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DUMMY_BYTES => + IF rising_edge(SCK_ipd) THEN + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + IF (((Instruct=FSTRD OR Instruct=FSTRD4 OR + Instruct=DOR OR Instruct=DOR4 OR + Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct = QOR OR Instruct = QOR4) AND + QUAD = '1'))THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt=1) OR + (Latency_code = 0 AND dummy_cnt=2) OR + (Latency_code = 1 AND dummy_cnt=4) OR + (Latency_code = 2 AND dummy_cnt=5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 5) OR + (Latency_code = 1 AND dummy_cnt = 6) OR + (Latency_code = 2 AND dummy_cnt = 7)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct=RES THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = 3*BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 1 AND dummy_cnt = 1) OR + (Latency_code = 2 AND dummy_cnt = 2)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt = 2) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF ((Instruct = QIOR OR Instruct = QIOR4) AND + QUAD = '1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 1) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 4) OR + (Latency_code = 2 AND dummy_cnt = 5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 3) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF falling_edge(SCK_ipd) THEN + IF NOT(hold_mode) THEN + IF (DOUBLE AND VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DATA_BYTES => + IF rising_edge(CSNeg_ipd) THEN + IF ((mode_bytes(7 downto 4) = "1010" AND + (Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QIOR OR Instruct = QIOR4)) OR + ((mode_bytes(7 downto 4) = + NOT(mode_bytes(3 downto 0))) AND + (Instruct = DDRFR OR Instruct = DDRFR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 OR + Instruct = DDRQIOR OR Instruct = DDRQIOR4))) THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + END IF; + IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' AND + NOT(DOUBLE) THEN + IF ((Instruct = READ OR Instruct=RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = RDSR OR Instruct = RDSR2 OR + Instruct = RDCR OR Instruct = OTPR OR + Instruct = DOR OR Instruct = DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = ABRD OR Instruct = BRRD OR + Instruct = ASPRD OR Instruct = DYBRD OR + Instruct = PPBRD OR + Instruct = PASSRD OR Instruct = RDID OR + Instruct = RES OR Instruct = REMS OR + Instruct = PLBRD OR Instruct = DLPRD) + AND ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (current_state = AUTOBOOT AND start_delay = 0)OR + ((Instruct=QOR OR Instruct=QIOR OR Instruct=QOR4 + OR Instruct= QIOR4) AND QUAD = '1') THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + ELSIF SCK_ipd'EVENT AND CSNeg_ipd = '0' AND DOUBLE THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + + IF rising_edge(SCK_ipd) THEN + IF QUAD = '1' AND (Instruct=QPP OR Instruct = QPP4)THEN + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF data_cnt > (PageSize*2-1) THEN + --In case of quad mode and QPP, + --if more than 512 bytes are sent to the device + FOR I IN 0 TO (PageSize*2-2) LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in((PageSize*2-1)) := + to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF quad_nybble /= "ZZZZ" THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt > (PageSize*8-1) THEN + --In case of serial mode and PP, + -- if more than 512 bytes are sent to the device + -- previously latched data are discarded and last + -- 512 data bytes are guaranteed to be programmed + -- correctly within the same page. + IF bit_cnt = 0 THEN + FOR I IN 0 TO ((PageSize-1)*BYTE - 1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in((PageSize-1)*BYTE + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF bit_cnt = 8 THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + CASE Instruct IS + WHEN WREN | WRDI | BE | SE | SE4 | CLSR | RESET | + PPBP | PPBERS | PGSP | PGRS | ERSP | BRAC | + ERRS | P4E | P4E4 | PLBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt = 0 THEN + write <= '0'; + END IF; + END IF; + + WHEN WRR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF ((data_cnt mod 8) = 0 AND data_cnt > 0) THEN + IF data_cnt = 8 THEN + --If CS# is driven high after eight + --cycle,only the Status Register is + --written to. + write <= '0'; + IF BAR_ACC = '0' THEN + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= + Data_in(7-i); + END LOOP; + ELSIF P_ERR = '0' AND E_ERR = '0' THEN + FOR i IN 0 TO 7 LOOP + Bank_Addr_reg_in(i) <= + Data_in(7-i); + END LOOP; + END IF; + ELSIF data_cnt = 16 THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + IF BAR_ACC = '0' THEN + FOR i IN 0 TO 7 LOOP + cfg_write <= '1'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= + Data_in(7-i); + Config_reg1_in(i) <= + Data_in(15-i); + END LOOP; + END LOOP; + ELSIF P_ERR = '0' AND E_ERR = '0' THEN + FOR i IN 0 TO 7 LOOP + Bank_Addr_reg_in(i) <= + Data_in(7-i); + END LOOP; + END IF; + END IF; + END IF; + END IF; + + WHEN PP | PP4 | OTPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt > 0 THEN + IF (data_cnt mod 8) = 0 THEN + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 7 DOWNTO 0 LOOP + IF Data_in((i*8) + (7-j)) + /= 'X' THEN + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END IF; + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*BYTE THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/8-1; + END IF; + END IF; + END IF; + END IF; + + WHEN QPP | QPP4=> + IF data_cnt > 0 THEN + IF data_cnt mod 2 = 0 THEN + quadpg <= FALSE; + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*2 THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/2-1; + END IF; + END IF; + END IF; + + WHEN ABWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 32 THEN + write <= '0'; + FOR J IN 0 TO 31 LOOP + AutoBoot_reg_in(J) <= + Data_in(31-J); + END LOOP; + END IF; + END IF; + + WHEN BRWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + Bank_Addr_reg_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN ASPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 16 THEN + write <= '0'; + FOR J IN 0 TO 15 LOOP + ASP_reg_in(J) <= + Data_in(15-J); + END LOOP; + END IF; + END IF; + + WHEN DYBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + DYBAR_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PNVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + NVDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN WVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + VDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PASSP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + Password_reg_in(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN PASSU => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + PASS_TEMP(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN others => + null; + + END CASE; + END IF; + END CASE; + END IF; + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART, PGSUSP, PGRES, RST, Reseted) + VARIABLE pob : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF rising_edge(PSTART) AND PDONE = '1' THEN + IF Instruct = PP OR Instruct = PP4 OR Instruct = OTPP OR + Instruct = QPP OR Instruct = QPP4 THEN + pob := tdevice_PP; + ELSE + pob := tdevice_BP; + END IF; + elapsed := 0 ns; + start := NOW; + PDONE <= '0', '1' AFTER pob; + ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN + elapsed := NOW - start; + duration := pob - elapsed; + PDONE <= '0'; + ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN + start := NOW; + PDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + PDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + PDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WRR; + ELSE + wob := tdevice_WRR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + WDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + WDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Bulk Erase + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART, ESUSP, ERES, RST, Reseted) + VARIABLE seo : time; + VARIABLE beo : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + seo := tdevice_SE; + beo := tdevice_BE; + ELSE + seo := tdevice_SE / 1000; + beo := tdevice_BE / 1000; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = BE THEN + duration := beo; + ELSE --Instruct = SE OR SE4 + duration := seo; + END IF; + elapsed := 0 ns; + EDONE <= '0', '1' AFTER duration; + start := NOW; + ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN + elapsed := NOW - start; + duration := duration - elapsed; + EDONE <= '0'; + ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN + start := NOW; + EDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + EDONE <= '1'; -- reset done, eras terminated + ELSIF rising_edge(Reseted) THEN + EDONE <= '1'; -- reset done, erase terminated + END IF; + + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS(CSNeg_ipd) + BEGIN + IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, RSTNeg_pullup, WDONE, PDONE, + ERSSUSP_out, PRGSUSP_out, EDONE, RST_out, PPBERASE_in, + PASSULCK_in) + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + + BEGIN + + IF rising_edge(PoweredUp) THEN + IF ABE = '1' AND RPME /= '0' THEN + --Autoboot is enabled and The Read Password feature is not enabled + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)&"000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + ELSE + IF RST_out= '0' then + next_state <= current_state; + ELSIF falling_edge(write) AND Instruct = RESET THEN + IF ABE = '1' AND RPME /= '0' THEN + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay:= to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + next_state <= AUTOBOOT; + ELSE + next_state <= IDLE; + END IF; + ELSE + CASE current_state IS + WHEN RESET_STATE => + IF rising_edge(RST_out) THEN + IF ABE = '1' AND RPME /= '0' + AND RdPswdProtMode = '0' THEN + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN IDLE => + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + IF (Instruct = WRR AND WEL = '1' AND BAR_ACC = '0') THEN + IF ((not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD = '0') OR QUAD = '1') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + ASSERT cfg_write = '0' + REPORT "Changing value of Configuration " & + "Register OTP bit from 1 to 0 is " & + "not allowed!!!" + SEVERITY WARNING; + ELSE + next_state <= WRITE_SR; + END IF; + END IF; + ELSIF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + next_state <= PAGE_PG; + IF (Instruct = QPP OR Instruct = QPP4) AND + QPP_page(pgm_page) = '1' THEN + REPORT "WARNING:The same page must not be" & + " programmed more than once!!!" + SEVERITY WARNING; + END IF; + END IF; + ELSIF Instruct=OTPP AND WEL = '1' AND FREEZE = '0' THEN + IF ((((Address >= 16#10# AND Address <= 16#13#) OR + (Address >= 16#20# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + next_state <= OTP_PG; + END IF; + ELSIF (Instruct= SE OR Instruct= SE4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + IF (Sec_Prot(sect) = '0' AND PPB_bits(sect)='1' + AND DYB_bits(sect)='1') THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF (Instruct=P4E OR Instruct=P4E4) AND WEL='1' THEN + --A P4E instruction applied to a sector that + --is larger than 4 KB will not be executed + --and will not set the E_ERR status. + REPORT "Warning! Parameter 4KB-sector Erase "& + "Instruction is not allowed for "& + "512Mbit memory size!!! "& + "Instruction is ignored!!!" + SEVERITY warning; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0='0' AND BP1='0' AND BP2='0') THEN + next_state <= BULK_ERS; + ELSIF Instruct = ABWR AND WEL = '1' THEN + --Autoboot Register Write Command + next_state <= AUTOBOOT_PG; + ELSIF Instruct = ASPP AND WEL = '1' THEN + --ASP Register Program Command + IF not(ASPOTPFLAG) THEN + next_state <= ASP_PG; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + next_state <= PLB_PG; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + next_state <= PASS_PG; + END IF; + ELSIF Instruct = PASSU AND WEL= '1' AND WIP= '0' THEN + next_state <= PASS_UNLOCK; + ELSIF Instruct = PPBP AND WEL = '1' THEN + next_state <= PPB_PG; + ELSIF (Instruct=PPBERS AND WEL='1' AND PPBOTP='1') THEN + next_state <= PPB_ERS; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + next_state <= DYB_PG; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + next_state <= NVDLR_PG; + ELSE + next_state <= IDLE; + END IF; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '1' AND + WIP = '0' THEN + IF Instruct = PASSU THEN + next_state <= PASS_UNLOCK; + END IF; + END IF; + + WHEN AUTOBOOT => + IF rising_edge(CSNeg_ipd) THEN + next_state <= IDLE; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = PGRS THEN + next_state <= PAGE_PG; + ELSE + next_state <= PG_SUSP; + END IF; + ELSE + next_state <= PG_SUSP; + END IF; + + WHEN OTP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN BULK_ERS => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN SECTOR_ERS => + IF ERSSUSP_out'EVENT AND ERSSUSP_out = '1' THEN + next_state <= ERS_SUSP; + ELSIF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN ERS_SUSP => + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + IF SectorSuspend /= (Address/(SecSize+1)) THEN + pgm_page := Address / PageSize; + IF PPB_bits(Address/SecSize)='1' AND + DYB_bits(Address/SecSize)='1' THEN + next_state <= ERS_SUSP_PG; + IF (Instruct = QPP OR Instruct = QPP4) AND + QPP_page(pgm_page) = '1' THEN + REPORT "WARNING:The same page must " & + "not be programmed more than once!!!" + SEVERITY WARNING; + END IF; + END IF; + END IF; + ELSIF (Instruct = DYBWR AND WEL = '1') THEN + next_state <= DYB_PG; + ELSIF Instruct = ERRS THEN + next_state <= SECTOR_ERS; + END IF; + ELSE + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= ERS_SUSP_PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = PGRS THEN + next_state <= ERS_SUSP_PG; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + + WHEN PASS_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PASS_UNLOCK => + IF falling_edge(PASSULCK_in) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_ERS => + IF falling_edge(PPBERASE_in) THEN + next_state <= IDLE; + END IF; + + WHEN AUTOBOOT_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PLB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN DYB_PG => + IF rising_edge(PDONE) THEN + IF ES = '1' THEN + next_state <= ERS_SUSP; + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN ASP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN NVDLR_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + END CASE; + END IF; + END IF; + + END PROCESS StateGen; + + ReadEnable: PROCESS (read_out) + BEGIN + oe_z <= rising_edge(read_out) AND PoweredUp = '1'; + + IF read_out'EVENT AND read_out = '0' AND PoweredUp = '1' THEN + oe <= TRUE, FALSE AFTER 1 ns; + END IF; + END PROCESS ReadEnable; + + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(write,current_state,start_autoboot,CSNeg_ipd, + HOLDNeg_pullup, Instruct, Address, WByte,change_addr, + PoweredUp, WPNeg_pullup, WDONE, PDONE, EDONE, + PRGSUSP_out,ERSSUSP_out, PASSACC_out, oe, oe_z) + + VARIABLE WData : WByteType:= (OTHERS => MaxData); + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + VARIABLE Addr : NATURAL; + VARIABLE Addr_tmp : NATURAL; + + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(647 downto 0); + + VARIABLE ExtendedID : NATURAL; + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + VARIABLE old_pass : std_logic_vector(63 downto 0); + VARIABLE new_pass : std_logic_vector(63 downto 0); + VARIABLE wr_cnt : NATURAL RANGE 0 TO 511; + --Data Learning Pattern Enable + VARIABLE dlp_act : BOOLEAN := FALSE; + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + VARIABLE cnt : NATURAL RANGE 0 TO 512 := 0; + VARIABLE mem_data : INTEGER; + + BEGIN + + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + IF Instruct'EVENT THEN + read_cnt := 0; + byte_cnt := 1; + fast_rd <= true; + dual <= false; + rd <= false; + any_read <= false; + END IF; + + IF PASSACC_out'EVENT AND PASSACC_out = '1' THEN + WIP := '0'; + PASSACC_in <= '0'; + END IF; + + IF rising_edge(PoweredUp) THEN + --the default condition after power-up + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + --The Configuration Register FREEZE bit is cleared. + FREEZE := '0'; + --The WEL bit is cleared. + WEL := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status Register are + --volatile and will be reset binary 111 after power-on reset + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --As shipped from the factory, all devices default ASP to the + --Persistent Protection mode, with all sectors unprotected, + --when power is applied. The device programmer or host system must + --then choose which sector protection method to use. + --For Persistent Protection mode, PPBLOCK defaults to "1" + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + DYB_bits := (OTHERS => '1'); + END IF; + + IF falling_edge(write) AND Instruct = RESET THEN + --The Configuration Register is set for Address mode + Bank_Addr_reg := (others => '0'); + --P_ERR bit is cleared + P_ERR := '0'; + --E_ERR bit is cleared + E_ERR := '0'; + --The WEL bit is cleared. + WEL := '0'; + --The WIP bit is cleared. + WIP := '0'; + --The ES bit is cleared. + ES := '0'; + --The PS bit is cleared. + PS := '0'; + + DummyBytes_act := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status + --Register are volatile and will be reseted after + --reset command + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF change_addr'EVENT THEN + read_addr := Address; + END IF; + + CASE current_state IS + WHEN IDLE => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF falling_edge(write) AND RdPswdProtMode = '1' THEN + IF Instruct = PASSU THEN + IF WIP = '0' THEN + PASSULCK_in <= '1'; + ELSE + REPORT "The PASSU command cannot be accepted"& + " any faster than once every 100us" + SEVERITY WARNING; + END IF; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + read_cnt := 0; + byte_cnt := 1; + IF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = WRDI THEN + WEL := '0'; + ELSIF Instruct = WRR AND WEL = '1' AND BAR_ACC = '0' THEN + IF (not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD ='0') OR QUAD ='1' THEN + -- can not execute if Hardware Protection Mode + -- is entered or if WEL bit is zero + + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + P_ERR := '1'; + ELSE + WSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + END IF; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF (Sec_Prot(sect)= '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF Instruct = OTPP AND WEL = '1' THEN + -- As long as the FREEZE bit remains cleared to a logic '0' + --the OTP address space is programmable. + IF FREEZE = '0' THEN + IF ((((Address >= 16#0010# AND Address <= 16#13#)OR + (Address >= 16#0020# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + PSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSIF (Address < 16#0010# OR (Address > 16#0013# AND + Address < 16#0020#) OR Address > 16#3FF# ) THEN + P_ERR := '1'; + WEL := '0'; + IF Address < 16#0020# THEN + ASSERT false + REPORT "Given address is in" & + "reserved address range" + SEVERITY warning; + ELSIF Address > 16#3FF# THEN + ASSERT false + REPORT "Given address is out of" & + "OTP address range" + SEVERITY warning; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = SE OR Instruct = SE4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + SectorSuspend <= sect; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (Instruct = P4E OR Instruct = P4E4) AND WEL = '1' THEN + WEL := '0'; + ELSIF Instruct = BE AND WEL = '1' THEN + IF (BP0='0' AND BP1='0' AND BP2='0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + ELSE + --The Bulk Erase command will not set E_ERR if a + --protected sector is found during the command + --execution. + WEL := '0'; + END IF; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + REPORT "Password programming is not allowed" & + " in Password Protection Mode." + SEVERITY warning; + END IF; + ELSIF Instruct = PASSU AND WEL= '1' AND WIP= '0' THEN + PASSULCK_in <= '1'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + IF (P_ERR = '0' AND E_ERR = '0') THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = ASPP AND WEL = '1' THEN + IF not(ASPOTPFLAG) THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + WEL := '0'; + P_ERR := '1'; + REPORT "Once the Protection Mode is selected," & + "no further changes to the ASP register" & + "is allowed." + SEVERITY warning; + END IF; + ELSIF Instruct = ABWR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBP AND WEL = '1' THEN + sect := Address/(SecSize+1); + Addr := Address; + pgm_page := Address/PageSize; + + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBERS AND WEL = '1' THEN + IF PPBOTP = '1' THEN + PPBERASE_in <= '1'; + WIP := '1'; + ELSE + E_ERR := '1'; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + sect := Address/(SecSize+1); + Addr := Address; + pgm_page := Address/PageSize; + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = WVDLR AND WEL = '1' THEN + VDLR_reg := VDLR_reg_in; + WEL := '0'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 OR + Instruct = RES OR Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES OR + DummyBytes_act='1') AND VDLR_reg/="00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRFR OR Instruct = DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + dlp_act := FALSE; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + IF RdPswdProtMode = '0' THEN + SecAddr := ReturnSectorID(read_addr); + END IF; + READ_DATA(SecAddr,Sec_addr,mem_data); + IF mem_data /= -1 THEN + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRDIOR OR Instruct = DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + IF RdPswdProtMode = '0' THEN + SecAddr := ReturnSectorID(read_addr); + END IF; + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF ((Instruct = DDRQIOR OR Instruct = DDRQIOR4) AND + QUAD = '1') THEN + IF EHP THEN + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + IF RdPswdProtMode = '0' THEN + SecAddr := ReturnSectorID(read_addr); + END IF; + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = OTPR THEN + IF (read_addr>=OTPLoAddr) AND + (read_addr<=OTPHiAddr) AND RdPswdProtMode = '0' THEN + --Read OTP Memory array + fast_rd <= true; + rd <= false; + data_out := to_slv(OTPMem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSIF (read_addr > OTPHiAddr) + OR RdPswdProtMode = '1' THEN + --OTP Read operation will not wrap to the + --starting address after the OTP address is at + --its maximum or Read Password Protection Mode + --is selected; instead, the data beyond the + --maximum OTP address will be undefined. + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF Instruct = REMS THEN + --Read Manufacturer and Device ID + IF read_addr MOD 2 = 0 THEN + data_out := to_slv(Manuf_ID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + data_out := to_slv(DeviceID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := 0; + END IF; + END IF; + ELSIF Instruct = RDID THEN + ident_out := CFI_array_tmp; + IF read_cnt < 648 THEN + SOut_zd <= ident_out(647-read_cnt); + read_cnt := read_cnt + 1; + ELSE + --Continued shifting of output beyond the end of + --the defined ID-CFI address space will provide + --undefined data. + SOut_zd <= 'U'; + END IF; + ELSIF Instruct = RES THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + data_out := to_slv(ESignature,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + SOut_zd <= VDLR_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ABRD THEN + --Read AutoBoot register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= AutoBoot_reg(31-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 32 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ASPRD THEN + --Read ASP Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= ASP_reg(15-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 16 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PASSRD THEN + --Read Password Register + IF not (PWDMLB='0' AND PSTMLB='1') THEN + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Password_reg((8*byte_cnt-1)-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + byte_cnt := byte_cnt + 1; + IF byte_cnt = 9 THEN + byte_cnt := 1; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 64 THEN + read_cnt := 0; + END IF; + IF read_cnt = 0 THEN + ASSERT false + REPORT "Verification of password is not " & + " allowed in Password Protection Mode." + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = PLBRD THEN + --Read PPB Lock Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= PPBL(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + DYBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + + WHEN AUTOBOOT => + IF start_autoboot = '1' THEN + IF (oe) THEN + any_read <= true; + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF oe_z THEN + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + END IF; + + WHEN WRITE_SR => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF WDONE = '1' THEN + WIP := '0'; + WEL := '0'; + SRWD := Status_reg1_in(7);--MSB first + + IF LOCK='0' THEN + IF FREEZE='0' THEN + --The Freeze Bit, when set to 1, locks the current + --state of the BP2-0 bits in Status Register and + --the TBPROT bit in the Config Register + --As long as the FREEZE bit remains cleared to logic + --'0', the other bits of the Configuration register + --including FREEZE are writeable. + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + + BP_bits := BP2 & BP1 & BP0; + + IF TBPROT = '0' AND INITIAL_CONFIG = '0' THEN + TBPROT := Config_reg1_in(5); + END IF; + + change_BP <= '1', '0' AFTER 1 ns; + + LC1 := Config_reg1_in(7); + LC0 := Config_reg1_in(6); + QUAD := Config_reg1_in(1); + + IF FREEZE = '0' THEN + FREEZE := Config_reg1_in(0); + END IF; + + IF WRLOCKENABLE AND LOCK = '0' THEN + LOCK := Config_reg1_in(4); + WRLOCKENABLE <= false; + END IF; + + IF BPNV = '0' THEN + BPNV := Config_reg1_in(3); + END IF; + END IF; + END IF; + END IF; + + WHEN PAGE_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(PDONE) THEN + IF (Instruct = QPP OR Instruct = QPP4) THEN + QPP_page(pgm_page) := '1'; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi,Sec_addr,Page_addr,Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + SecAddr := ReturnSectorID(Addr); + READ_DATA(SecAddr, + Sec_addr+i-cnt, + mem_data); + old_int := mem_data; + + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + write_mem(linked_list(SecAddr), + Sec_addr + i - cnt, + -1); + IF (Sec_addr + i) = AddrHi THEN + Sec_addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + ADDRHILO_PG(AddrLo, AddrHi,Sec_addr,Page_addr,Addr); + FOR i IN 0 TO wr_cnt LOOP + SecAddr := ReturnSectorID(Addr); + WRITE_DATA(SecAddr, + Sec_addr + i - cnt, + WData(i)); + IF (Sec_addr + i) = AddrHi THEN + Sec_addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + IF RES_TO_SUSP_MIN_TIME = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + ELSE + ASSERT FALSE + REPORT "Minimum for tPRS is not satisfied! " & + "PGSP command is ignored" + SEVERITY warning; + END IF; + END IF; + + WHEN PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF pgm_page /= read_addr/PageSize THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF pgm_page /= read_addr/PageSize THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF pgm_page /= read_addr/PageSize THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF falling_edge(write) THEN + IF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1) AND + pgm_page /= read_addr/PageSize) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1) AND + pgm_page /= read_addr/PageSize) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1) AND + pgm_page /= read_addr/PageSize) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF falling_edge(write) THEN + IF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN OTP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF Address + wr_cnt <= OTPHiAddr THEN + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := OTPMem(Addr + i); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + OTPMem(Addr + i) := -1; + END LOOP; + ELSE + ASSERT false + REPORT "Programming will reach over address limit"& + " of OTP array" + SEVERITY warning; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + OTPMem(Addr_tmp + i) := WData(i); + END LOOP; + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + END IF; + + WHEN SECTOR_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + SecAddr := ReturnSectorID(Addr); + Corrupt_Sec(SecAddr) := '1'; + erase_mem( + 0, + SecSize, + linked_list(SecAddr) + ); + + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + Corrupt_Sec(SecAddr) := '0'; + erase_mem( + 0, + SecSize, + linked_list(SecAddr) + ); + ELSIF Instruct = ERSP AND ERSSUSP_in = '0' THEN + ESUSP <= '1', '0' AFTER 10 ns; + ERSSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + END IF; + + WHEN BULK_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(EDONE) THEN + FOR i IN 0 TO SecNum LOOP + IF PPB_bits(i) = '1' AND DYB_bits(i) = '1' THEN + Corrupt_Sec(i) := '1'; + erase_mem( + 0, + SecSize, + linked_list(i) + ); + END IF; + END LOOP; + END IF; + + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO SecNum LOOP + IF PPB_bits(i) = '1' AND DYB_bits(i) = '1' THEN + Corrupt_Sec(i) := '0'; + erase_mem( + 0, + SecSize, + linked_list(i) + ); + END IF; + END LOOP; + END IF; + + WHEN ERS_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF ERSSUSP_out = '1' THEN + ERSSUSP_in <= '0'; + --The Erase Suspend (ES) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --erase operation has been suspended. + ES := '1'; + --The WIP bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF SectorSuspend /= read_addr/(SecSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF SectorSuspend /= read_addr/(SecSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF SectorSuspend /= read_addr/(SecSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + data_out := to_slv((mem_data),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF SectorSuspend /= sect THEN + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF SectorSuspend /= sect THEN + IF (Sec_Prot(sect)='0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = ERRS THEN + ERES <= '1', '0' AFTER 5 ns; + ES := '0'; + WIP := '1'; + Addr := SectorSuspend*(SecSize+1); + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF (Instruct = QPP OR Instruct = QPP4) THEN + QPP_page(pgm_page) := '1'; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi,Sec_addr,Page_addr,Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + SecAddr := ReturnSectorID(Addr + i - cnt); + Sec_addr := Addr + i - cnt - SecAddr*(SecSize+1); + READ_DATA(SecAddr,Sec_addr,mem_data); + old_int := mem_data; + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + + IF PDONE = '1' THEN + ADDRHILO_PG(AddrLo, AddrHi,Sec_addr,Page_addr,Addr); + SecAddr := ReturnSectorID(Addr); + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + WRITE_DATA(SecAddr, + Sec_addr + i - cnt, + WData(i)); + IF (Sec_addr + i) = AddrHi THEN + Sec_addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + IF RES_TO_SUSP_MIN_TIME = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + ELSE + ASSERT FALSE + REPORT "Minimum for tPRS is not satisfied! " & + "PGSP command is ignored" + SEVERITY warning; + END IF; + END IF; + + WHEN PASS_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + new_pass := Password_reg_in; + old_pass := Password_reg; + FOR j IN 0 TO 63 LOOP + IF old_pass(j) = '0' THEN + new_pass(j) := '0'; + END IF; + END LOOP; + + IF PDONE = '1' THEN + Password_reg := new_pass; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PASS_UNLOCK => + WIP := '1'; + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PASS_TEMP = Password_reg THEN + PASS_UNLOCKED <= TRUE; + ELSE + PASS_UNLOCKED <= FALSE; + END IF; + + IF PASSULCK_out = '1' THEN + IF PASS_UNLOCKED AND PWDMLB = '0' THEN + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + WIP := '0'; + ELSE + P_ERR := '1'; + REPORT "Incorrect Password!" + SEVERITY warning; + PASSACC_in <= '1'; + END IF; + WEL := '0'; + PASSULCK_in <= '0'; + END IF; + + WHEN PPB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF PPB_LOCK /= '0' THEN + PPB_bits(sect):= '0'; + WIP := '0'; + WEL := '0'; + ELSE + P_ERR := '0'; + WIP := '0'; + WEL := '0'; + END IF; + END IF; + + WHEN PPB_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PPBERASE_out = '1' THEN + IF PPB_LOCK /= '0' AND PPBOTP = '1' THEN + PPB_bits:= (OTHERS => '1'); + ELSE + E_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + PPBERASE_in <= '0'; + END IF; + + WHEN AUTOBOOT_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + AutoBoot_reg := AutoBoot_reg_in; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PLB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN DYB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + DYBAR := DYBAR_in; + IF DYBAR = "11111111" THEN + DYB_bits(sect):= '1'; + ELSIF DYBAR = "00000000" THEN + DYB_bits(sect):= '0'; + ELSE + P_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN ASP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + + IF (RPME = '0' AND ASP_reg_in(5) = '1') THEN + P_ERR := '1'; + REPORT "RPME bit is allready programmed" + SEVERITY warning; + ELSE + RPME := ASP_reg_in(5); + END IF; + + IF (PPBOTP = '0' AND ASP_reg_in(3) ='1') THEN + P_ERR := '1'; + REPORT "PPBOTP bit is allready programmed" + SEVERITY warning; + ELSE + PPBOTP := ASP_reg_in(3); + END IF; + + IF (PWDMLB = '1' AND PSTMLB = '1') THEN + IF (ASP_reg_in(2) = '0' AND ASP_reg_in(1) = '0') THEN + REPORT "ASPR[2:1] = 00 Illegal condition" + SEVERITY warning; + P_ERR := '1'; + ELSE + IF (ASP_reg_in(2) /= '1' OR + ASP_reg_in(1) /= '1') THEN + ASPOTPFLAG <= TRUE; + END IF; + PWDMLB := ASP_reg_in(2); + PSTMLB := ASP_reg_in(1); + END IF; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN NVDLR_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF NVDLR_reg = "00000000" THEN + NVDLR_reg :=NVDLR_reg_in; + VDLR_reg := NVDLR_reg_in; + WIP := '0'; + WEL := '0'; + ELSE + WIP := '0'; + WEL := '0'; + P_ERR := '1'; + REPORT "NVDLR is allready programmed" + SEVERITY warning; + END IF; + END IF; + + WHEN RESET_STATE => + --the default condition hardware reset + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --Resets the Status register 1 + P_ERR := '0'; + E_ERR := '0'; + WEL := '0'; + WIP := '0'; + --Resets the Status register 2 + ES := '0'; + PS := '0'; + --Resets the Configuration register 1 + FREEZE := '0'; + --On reset cycles the data pattern reverts back + --to what is in the NVDLR + VDLR_reg := NVDLR_reg; + dlp_act := FALSE; + --Loads the Program Buffer with all ones + WData := (OTHERS => MaxData); + + IF PWDMLB = '0' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + ELSE + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + END PROCESS Functional; + + --------------------------------------------------------------------------- + -- CFI Process + --------------------------------------------------------------------------- + CFIPreload: PROCESS + + BEGIN + ------------------------------------------------------------------------ + --CFI array data + ------------------------------------------------------------------------ + -- Manufacturer and Device ID + CFI_array(16#00#) := 16#01#; + CFI_array(16#01#) := 16#02#; + CFI_array(16#02#) := 16#20#; + CFI_array(16#03#) := 16#00#; + CFI_array(16#04#) := 16#00#;--Uniform 256KB sectors + CFI_array(16#05#) := 16#80#; + CFI_array(16#06#) := 16#00#; + CFI_array(16#07#) := 16#00#; + CFI_array(16#08#) := 16#00#; + CFI_array(16#09#) := 16#00#; + CFI_array(16#0A#) := 16#00#; + CFI_array(16#0B#) := 16#00#; + CFI_array(16#0C#) := 16#00#; + CFI_array(16#0D#) := 16#00#; + CFI_array(16#0E#) := 16#00#; + CFI_array(16#0F#) := 16#00#; + --CFI Query Identification String + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#53#; + CFI_array(16#18#) := 16#46#; + CFI_array(16#19#) := 16#51#; + CFI_array(16#1A#) := 16#00#; + --CFI system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#06#; + CFI_array(16#20#) := 16#09#;-- 512B page + CFI_array(16#21#) := 16#09#;-- 256KB + CFI_array(16#22#) := 16#11#; + CFI_array(16#23#) := 16#02#; + CFI_array(16#24#) := 16#02#; + CFI_array(16#25#) := 16#03#; + CFI_array(16#26#) := 16#03#; + -- Device Geometry Definition + CFI_array(16#27#) := 16#1A#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#01#; + CFI_array(16#2A#) := 16#09#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#FF#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#04#; + CFI_array(16#31#) := 16#FF#; + CFI_array(16#32#) := 16#FF#; + CFI_array(16#33#) := 16#FF#; + CFI_array(16#34#) := 16#FF#; + CFI_array(16#35#) := 16#FF#; + CFI_array(16#36#) := 16#FF#; + CFI_array(16#37#) := 16#FF#; + CFI_array(16#38#) := 16#FF#; + CFI_array(16#39#) := 16#FF#; + CFI_array(16#3A#) := 16#FF#; + CFI_array(16#3B#) := 16#FF#; + CFI_array(16#3C#) := 16#FF#; + CFI_array(16#3D#) := 16#FF#; + CFI_array(16#3E#) := 16#FF#; + CFI_array(16#3F#) := 16#FF#; + -- CFI Primary Vendor-Specific Extended Query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#21#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#00#; + CFI_array(16#49#) := 16#08#; + + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#01#; + CFI_array(16#4C#) := 16#04#; + CFI_array(16#4D#) := 16#00#; + CFI_array(16#4E#) := 16#00#; + CFI_array(16#4F#) := 16#07#; + CFI_array(16#50#) := 16#01#; + + CFI_array_tmp :=to_slv(CFI_array(16#00#), 8) & + to_slv(CFI_array(16#01#), 8) & + to_slv(CFI_array(16#02#), 8) & + to_slv(CFI_array(16#03#), 8) & + to_slv(CFI_array(16#04#), 8) & + to_slv(CFI_array(16#05#), 8) & + to_slv(CFI_array(16#06#), 8) & + to_slv(CFI_array(16#07#), 8) & + to_slv(CFI_array(16#08#), 8) & + to_slv(CFI_array(16#09#), 8) & + to_slv(CFI_array(16#0A#), 8) & + to_slv(CFI_array(16#0B#), 8) & + to_slv(CFI_array(16#0C#), 8) & + to_slv(CFI_array(16#0D#), 8) & + to_slv(CFI_array(16#0E#), 8) & + to_slv(CFI_array(16#0F#), 8) & + to_slv(CFI_array(16#10#), 8) & + to_slv(CFI_array(16#11#), 8) & + to_slv(CFI_array(16#12#), 8) & + to_slv(CFI_array(16#13#), 8) & + to_slv(CFI_array(16#14#), 8) & + to_slv(CFI_array(16#15#), 8) & + to_slv(CFI_array(16#16#), 8) & + to_slv(CFI_array(16#17#), 8) & + to_slv(CFI_array(16#18#), 8) & + to_slv(CFI_array(16#19#), 8) & + to_slv(CFI_array(16#1A#), 8) & + to_slv(CFI_array(16#1B#), 8) & + to_slv(CFI_array(16#1C#), 8) & + to_slv(CFI_array(16#1D#), 8) & + to_slv(CFI_array(16#1E#), 8) & + to_slv(CFI_array(16#1F#), 8) & + to_slv(CFI_array(16#20#), 8) & + to_slv(CFI_array(16#21#), 8) & + to_slv(CFI_array(16#22#), 8) & + to_slv(CFI_array(16#23#), 8) & + to_slv(CFI_array(16#24#), 8) & + to_slv(CFI_array(16#25#), 8) & + to_slv(CFI_array(16#26#), 8) & + to_slv(CFI_array(16#27#), 8) & + to_slv(CFI_array(16#28#), 8) & + to_slv(CFI_array(16#29#), 8) & + to_slv(CFI_array(16#2A#), 8) & + to_slv(CFI_array(16#2B#), 8) & + to_slv(CFI_array(16#2C#), 8) & + to_slv(CFI_array(16#2D#), 8) & + to_slv(CFI_array(16#2E#), 8) & + to_slv(CFI_array(16#2F#), 8) & + to_slv(CFI_array(16#30#), 8) & + to_slv(CFI_array(16#31#), 8) & + to_slv(CFI_array(16#32#), 8) & + to_slv(CFI_array(16#33#), 8) & + to_slv(CFI_array(16#34#), 8) & + to_slv(CFI_array(16#35#), 8) & + to_slv(CFI_array(16#36#), 8) & + to_slv(CFI_array(16#37#), 8) & + to_slv(CFI_array(16#38#), 8) & + to_slv(CFI_array(16#39#), 8) & + to_slv(CFI_array(16#3A#), 8) & + to_slv(CFI_array(16#3B#), 8) & + to_slv(CFI_array(16#3C#), 8) & + to_slv(CFI_array(16#3D#), 8) & + to_slv(CFI_array(16#3E#), 8) & + to_slv(CFI_array(16#3F#), 8) & + to_slv(CFI_array(16#40#), 8) & + to_slv(CFI_array(16#41#), 8) & + to_slv(CFI_array(16#42#), 8) & + to_slv(CFI_array(16#43#), 8) & + to_slv(CFI_array(16#44#), 8) & + to_slv(CFI_array(16#45#), 8) & + to_slv(CFI_array(16#46#), 8) & + to_slv(CFI_array(16#47#), 8) & + to_slv(CFI_array(16#48#), 8) & + to_slv(CFI_array(16#49#), 8) & + to_slv(CFI_array(16#4A#), 8) & + to_slv(CFI_array(16#4B#), 8) & + to_slv(CFI_array(16#4C#), 8) & + to_slv(CFI_array(16#4D#), 8) & + to_slv(CFI_array(16#4E#), 8) & + to_slv(CFI_array(16#4F#), 8) & + to_slv(CFI_array(16#50#), 8); + + WAIT; + + END PROCESS CFIPreload; + + AspRegInit: PROCESS(ASP_INIT) + BEGIN + IF ASP_INIT = 0 THEN + ASP_reg := to_slv(16#FE4F#,16); + ELSE + ASP_reg := to_slv(16#FE7F#,16); + END IF; + END PROCESS AspRegInit; + + Protect : PROCESS(change_BP) + BEGIN + IF rising_edge(change_BP) THEN + + CASE BP_bits IS + WHEN "000" => + Sec_Prot := (OTHERS => '0'); + WHEN "001" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*63/64) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*63/64 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/64 - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/64) + := (OTHERS => '0'); + END IF; + WHEN "010" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*31/32) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*31/32 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/32 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/32) + := (OTHERS => '0'); + END IF; + WHEN "011" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*15/16) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*15/16 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/16 - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/16) + := (OTHERS => '0'); + END IF; + WHEN "100" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*7/8) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*7/8 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/8 - 1 downto 0) := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/8):= (OTHERS => '0'); + END IF; + WHEN "101" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*3/4) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*3/4 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/4 - 1 downto 0) := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/4):= (OTHERS => '0'); + END IF; + + WHEN "110" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)/2):= (OTHERS => '1'); + Sec_Prot((SecNum+1)/2 - 1 downto 0) := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/2 - 1 downto 0) := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/2):= (OTHERS => '0'); + END IF; + + WHEN OTHERS => + Sec_Prot := (OTHERS => '1'); + END CASE; + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNeg_pullup) + BEGIN + IF (HOLDNeg_pullup = '0' AND QUAD /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + RST_PULL_UP : PROCESS(RSTNeg) + BEGIN + IF (RSTNeg = 'Z') THEN + RSTNeg_pullup <= '1'; + ELSE + RSTNeg_pullup <= RSTNeg; + END IF; + END PROCESS RST_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + MemPreload : PROCESS + + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE otp_file : text is otp_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0; + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE index : NATURAL RANGE 0 TO SecSize:=0; + VARIABLE otp_ind : NATURAL RANGE 16#000# TO 16#3FF# := 16#000#; + VARIABLE buf : line; + VARIABLE reported : NATURAL; + VARIABLE mem_data : INTEGER; + + BEGIN + --------------------------------------------------------------------------- + --s25fl512s memory preload file format +----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaaaaa - stands for address + -- dd -
is byte to be written at Mem(aaaaaa++) + -- (aaaaaa is incremented at every load) + -- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + -- memory preload + configure_memory(16#FF#); + initialize; + IF (mem_file_name /= "none" AND UserPreload ) THEN + ind := 0; + reported := 0; + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN --comment + NEXT; + ELSIF buf(1) = '@' THEN --address + ind := h(buf(2 to 8)); + ELSE + IF ind <= AddrRANGE THEN + mem_data := h(buf(1 to 2)); + IF ind=0 THEN + S_ind := 0; + index := 0; + ELSIF ind < SecSize+1 THEN + S_ind := 0; + index := ind; + ELSE + S_ind := NATURAL(ind / (SecSize +1)); + index := ind - S_ind*(SecSize+1); + END IF; + WRITE_DATA(S_ind,index,mem_data); + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + ELSIF reported = 0 THEN + REPORT " Memory address out of range" + SEVERITY warning; + reported := 1; + END IF; + END IF; + END LOOP; + END IF; + + --------------------------------------------------------------------------- + --s25fl512s_otp memory preload file format + --------------------------------------------------------------------------- + -- / - comment + -- @aaa - stands for address + -- dd -
is byte to be written at OTPMem(aaa++) + -- (aaa is incremented at every load) + -- only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (otp_file_name /= "none" AND UserPreload) THEN + otp_ind := 16#000#; + OTPMem := (OTHERS => MaxData); + WHILE (not ENDFILE (otp_file)) LOOP + READLINE (otp_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF otp_ind > 16#3FF# OR otp_ind < 16#000# THEN + ASSERT false + REPORT "Given preload address is out of" & + "OTP address range" + SEVERITY warning; + ELSE + otp_ind := h(buf(2 to 4)); --address + END IF; + ELSE + OTPMem(otp_ind) := h(buf(1 to 2)); + otp_ind := otp_ind + 1; + END IF; + END LOOP; + END IF; + + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + + WAIT; + END PROCESS MemPreload; + + ---------------------------------------------------------------------------- + -- Path Delay Section + ---------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "SO", + OutTemp => SOut_z, + Mode => VitalTransport, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => (ddr OR fast_rd)), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => QUAD = '0') + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + Mode => VitalTransport, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => dual AND ddr), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => dual AND QUAD = '0') + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + Mode => VitalTransport, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + HOLDNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + Mode => VitalTransport, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + WPNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + END BLOCK behavior; +END vhdl_behavioral_dynamic_memory_allocation; +ARCHITECTURE vhdl_behavioral_static_memory_allocation of s25fl512s IS + ATTRIBUTE VITAL_LEVEL0 OF + vhdl_behavioral_static_memory_allocation : ARCHITECTURE IS TRUE; + + --------------------------------------------------------------------------- + -- CONSTANT AND SIGNAL DECLARATION + --------------------------------------------------------------------------- + --Declaration of constants - memory characteristics + -- The constant declared here are used to enable the creation of models + -- of memories within a family with a minimum amount of editing + + CONSTANT PartID : STRING := "s25fl512s"; + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT MemSize : NATURAL := 16#3FFFFFF#; + CONSTANT SecNum : NATURAL := 255; + CONSTANT SecSize : NATURAL := 16#3FFFF#; --256KB + CONSTANT PageNum : NATURAL := 16#1FFFF#; + CONSTANT PageSize : NATURAL := 512; + CONSTANT AddrRANGE : NATURAL := 16#3FFFFFF#; + CONSTANT HiAddrBit : NATURAL := 31; + CONSTANT OTPSize : NATURAL := 1023; + CONSTANT OTPLoAddr : NATURAL := 16#000#; + CONSTANT OTPHiAddr : NATURAL := 16#3FF#; + CONSTANT BYTE : NATURAL := 8; + + --Manufacturer Identification + CONSTANT Manuf_ID : NATURAL := 16#01#; + CONSTANT DeviceID : NATURAL := 16#19#; + --Electronic Signature + CONSTANT ESignature : NATURAL := 16#19#; + --Device ID + --Manufacturer Identification && Memory Type && Memory Capacity + CONSTANT Jedec_ID : NATURAL := 16#01#; -- first byte of Device ID + CONSTANT DeviceID1 : NATURAL := 16#02#; + CONSTANT DeviceID2 : NATURAL := 16#20#; + CONSTANT ExtendedBytes : NATURAL := 16#4D#; + CONSTANT ExtendedID : NATURAL := 16#00#; + CONSTANT DieRev : NATURAL := 16#00#; + CONSTANT MaskRev : NATURAL := 16#00#; + + -- Declaration of signals that will hold the delayed values of ports + SIGNAL SI_ipd : std_ulogic := 'U'; + SIGNAL SO_ipd : std_ulogic := 'U'; + SIGNAL SCK_ipd : std_ulogic := 'U'; + SIGNAL CSNeg_ipd : std_ulogic := 'U'; + SIGNAL RSTNeg_ipd : std_ulogic := 'U'; + SIGNAL WPNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; + SIGNAL HOLDNeg_pullup : std_ulogic := 'U'; + SIGNAL WPNeg_pullup : std_ulogic := 'U'; + SIGNAL RSTNeg_pullup : std_ulogic := 'U'; + + -- internal delays + SIGNAL PP_in : std_ulogic := '0'; + SIGNAL PP_out : std_ulogic := '0'; + SIGNAL BP_in : std_ulogic := '0'; + SIGNAL BP_out : std_ulogic := '0'; + SIGNAL SE_in : std_ulogic := '0'; + SIGNAL SE_out : std_ulogic := '0'; + SIGNAL BE_in : std_ulogic := '0'; + SIGNAL BE_out : std_ulogic := '0'; + SIGNAL WRR_in : std_ulogic := '0'; + SIGNAL WRR_out : std_ulogic := '0'; + SIGNAL ERSSUSP_in : std_ulogic := '0'; + SIGNAL ERSSUSP_out : std_ulogic := '0'; + SIGNAL PRGSUSP_in : std_ulogic := '0'; + SIGNAL PRGSUSP_out : std_ulogic := '0'; + SIGNAL PU_in : std_ulogic := '0'; + SIGNAL PU_out : std_ulogic := '0'; + SIGNAL RST_in : std_ulogic := '0';-- Hardware Reset Timeout + SIGNAL RST_out : std_ulogic := '1';-- + SIGNAL PPBERASE_in : std_ulogic := '0'; + SIGNAL PPBERASE_out : std_ulogic := '0'; + SIGNAL PASSULCK_in : std_ulogic := '0'; + SIGNAL PASSULCK_out : std_ulogic := '0'; + SIGNAL PASSACC_in : std_ulogic := '0'; + SIGNAL PASSACC_out : std_ulogic := '0'; + + FUNCTION ReturnSectorID(ADDR : NATURAL) RETURN NATURAL IS + VARIABLE result : NATURAL; + BEGIN + IF ADDR <= AddrRange THEN + result := ADDR / (SecSize+1); + ELSE + result := SecNum+1; + END IF; + RETURN result; + END ReturnSectorID; + + FUNCTION ReturnSectorIDRdPswdMd(TBPROT : std_logic) RETURN NATURAL IS + VARIABLE result : NATURAL; + BEGIN + result := SecNum; + IF TBPROT = '0' THEN + result := 0; + END IF; + RETURN result; + END ReturnSectorIDRdPswdMd; + +BEGIN + --------------------------------------------------------------------------- + -- Internal Delays + --------------------------------------------------------------------------- + -- Artificial VITAL primitives to incorporate internal delays + -- Because a tdevice generics is used, there must be a VITAL_primitives + -- assotiated with them + PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); + BP :VitalBuf(BP_out, BP_in, (tdevice_BP ,UnitDelay)); + SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); + BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); + WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay)); + ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay)); + PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay)); + PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay)); + PPBERASE :VitalBuf(PPBERASE_out,PPBERASE_in,(tdevice_PPBERASE,UnitDelay)); + PASSULCK :VitalBuf(PASSULCK_out,PASSULCK_in,(tdevice_PASSULCK,UnitDelay)); + PASSACC :VitalBuf(PASSACC_out, PASSACC_in, (tdevice_PASSACC ,UnitDelay)); + + --------------------------------------------------------------------------- + -- Wire Delays + --------------------------------------------------------------------------- + WireDelay : BLOCK + BEGIN + + w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI); + w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO); + w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); + w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); + w_5 : VitalWireDelay (RSTNeg_ipd, RSTNeg, tipd_RSTNeg); + w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg); + w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); + + END BLOCK; + + --------------------------------------------------------------------------- + -- Main Behavior Block + --------------------------------------------------------------------------- + Behavior: BLOCK + + PORT ( + SIIn : IN std_ulogic := 'U'; + SIOut : OUT std_ulogic := 'U'; + SOIn : IN std_logic := 'U'; + SOut : OUT std_logic := 'U'; + SCK : IN std_ulogic := 'U'; + CSNeg : IN std_ulogic := 'U'; + RSTNeg : IN std_ulogic := 'U'; + HOLDNegIn : IN std_ulogic := 'U'; + HOLDNegOut : OUT std_ulogic := 'U'; + WPNegIn : IN std_ulogic := 'U'; + WPNegOut : OUT std_ulogic := 'U' + ); + + PORT MAP ( + SIIn => SI_ipd, + SIOut => SI, + SOIn => SO_ipd, + SOut => SO, + SCK => SCK_ipd, + CSNeg => CSNeg_ipd, + RSTNeg => RSTNeg_ipd, + HOLDNegIn => HOLDNeg_ipd, + HOLDNegOut => HOLDNeg, + WPNegIn => WPNeg_ipd, + WPNegOut => WPNeg + ); + + -- State Machine : State_Type + TYPE state_type IS (IDLE, + RESET_STATE, + AUTOBOOT, + WRITE_SR, + PAGE_PG, + OTP_PG, + PG_SUSP, + SECTOR_ERS, + BULK_ERS, + ERS_SUSP, + ERS_SUSP_PG, + ERS_SUSP_PG_SUSP, + PASS_PG, + PASS_UNLOCK, + PPB_PG, + PPB_ERS, + AUTOBOOT_PG, + ASP_PG, + PLB_PG, + DYB_PG, + NVDLR_PG + ); + + -- Instruction Type + TYPE instruction_type IS ( NONE, + WREN, -- Write Enable + WRDI, -- Write Disable + WRR, -- Write Register + READ, -- Read Normal (3Byte Address) + RD4, -- Read Normal (4Byte +) + OTPR, -- OTP Read + RDSR, -- Read Status Register 1 + RDSR2, -- Read Status Register 2 + RDCR, -- Read Configuration Register 1 + REMS, -- Read ID (SST) + RDID, -- Read ID JEDEC + RES, -- Read ID + FSTRD, -- Fast Read (3Byte Address) + FSTRD4, -- Fast Read (4Byte +) + DDRFR, -- Fast Read DDR (3Byte Address) + DDRFR4, -- Fast Read DDR (4Byte +) + DOR, -- Read Dual Out (3Byte Address) + DOR4, -- Read Dual Out (4Byte +) + DIOR, -- Read Dual I/O (3Byte Address) + DIOR4, -- Read Dual I/O (4Byte +) + DDRDIOR, -- Read DDR Dual I/O (3Byte) + DDRDIOR4, -- Read DDR Dual I/O (4Byte +) + QOR, -- Read Quad Out (3Byte Address) + QOR4, -- Read Quad Out (4Byte +) + QIOR, -- Read Quad I/O (3Byte Address) + QIOR4, -- Read Quad I/O (4Byte +) + DDRQIOR, -- Read DDR Quad I/O (3Byte) + DDRQIOR4, -- Read DDR Quad I/O (4Byte +) + PP, -- Program Page (3Byte Address) + PP4, -- Program Page (4Byte +) + QPP, -- Quad Page Program (3Byte) + QPP4, -- Quad Page Program (4Byte +) + OTPP, -- OTP Program + PGSP, -- Program Suspend + PGRS, -- Program Resume + BE, -- Bulk Erase + SE, -- Erase 128/256KB (3Byte) + SE4, -- Erase 128/256KB (4Byte +) + P4E, -- 4KB-sector Erase (3Byte Addr) + P4E4, -- 4KB-sector Erase (4Byte Addr) + ERSP, -- Erase Suspend + ERRS, -- Erase Resume + ABRD, -- AutoBoot Register Read + ABWR, -- AutoBoot Register Write + BRRD, -- Bank Register Read + BRWR, -- Bank Register Write + BRAC, -- Bank Register Access + DLPRD, -- Read Data Learning Pattern + PNVDLR, -- Program NVDLP Reg + WVDLR, -- Write Volatile DLP Reg + ASPRD, -- ASP Read + ASPP, -- ASP Program + DYBRD, -- DYB Read + DYBWR, -- DYB Write + PPBRD, -- PPB Read + PPBP, -- PPB Program + PPBERS, -- PPB Erase + PLBWR, -- PPB Lock Bit Write + PLBRD, -- PPB Lock Bit Read + PASSRD, -- Password Read + PASSP, -- Password Program + PASSU, -- Password Unlock + RESET, -- Reset + MBR, -- Mode Bit Reset + MPM, -- Multi-I/O-High Perf Mode + CLSR -- Clear Status Register + ); + + TYPE WByteType IS ARRAY (0 TO 511) OF INTEGER RANGE -1 TO MaxData; + -- Flash Memory Array + TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; + -- OTP Memory Array + TYPE OTPArray IS ARRAY (OTPLoAddr TO OTPHiAddr) OF INTEGER + RANGE -1 TO MaxData; + --CFI Array (Common Flash Interface Query codes) + TYPE CFItype IS ARRAY (16#00# TO 16#55#) OF + INTEGER RANGE -1 TO 16#FF#; + ----------------------------------------------------------------------- + -- memory declaration + ----------------------------------------------------------------------- + -- Memory + SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); + -- OTP Sector + SHARED VARIABLE OTPMem : OTPArray := (OTHERS => MaxData); + --CFI Array + SHARED VARIABLE CFI_array : CFItype := (OTHERS => 0); + -- Programming Buffer + SIGNAL WByte : WByteType := (OTHERS => MaxData); + + -- states + SIGNAL current_state : state_type; + SIGNAL next_state : state_type; + + SIGNAL Instruct : instruction_type; + --zero delay signal + SIGNAL SOut_zd : std_logic := 'Z'; + SIGNAL SIOut_zd : std_logic := 'Z'; + SIGNAL HOLDNegOut_zd : std_logic := 'Z'; + SIGNAL WPNegOut_zd : std_logic := 'Z'; + --HOLD delay on output data + SIGNAL SOut_z : std_logic := 'Z'; + SIGNAL SIOut_z : std_logic := 'Z'; + -- powerup + SIGNAL PoweredUp : std_logic := '0'; + + ----------------------------------------------------------------------- + -- Registers + ----------------------------------------------------------------------- + -- *** Status Register 1 *** + SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Disable Bit + ALIAS SRWD :std_logic IS Status_reg1(7); + -- Status Register Programming Error Bit + ALIAS P_ERR :std_logic IS Status_reg1(6); + -- Status Register Erase Error Bit + ALIAS E_ERR :std_logic IS Status_reg1(5); + -- Status Register Block Protection Bits + ALIAS BP2 :std_logic IS Status_reg1(4); + ALIAS BP1 :std_logic IS Status_reg1(3); + ALIAS BP0 :std_logic IS Status_reg1(2); + -- Status Register Write Enable Latch Bit + ALIAS WEL :std_logic IS Status_reg1(1); + -- Status Register Write In Progress Bit + ALIAS WIP :std_logic IS Status_reg1(0); + + -- *** Status Register 2 *** + SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Status_reg2_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Status Register Write Enable Latch Bit + ALIAS ES :std_logic IS Status_reg2(1); + -- Status Register Write In Progress Bit + ALIAS PS :std_logic IS Status_reg2(0); + + -- *** Configuration Register 1 *** + SHARED VARIABLE Config_reg1 : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Config_reg1_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- Latency code + ALIAS LC1 :std_logic IS Config_reg1(7); + ALIAS LC0 :std_logic IS Config_reg1(6); + -- Configuration Register TBPROT bit + ALIAS TBPROT :std_logic IS Config_reg1(5); + -- Configuration Register LOCK bit + ALIAS LOCK :std_logic IS Config_reg1(4); + -- Configuration Register BPNV bit + ALIAS BPNV :std_logic IS Config_reg1(3); + -- Configuration Register QUAD bit + ALIAS QUAD :std_logic IS Config_reg1(1); + -- Configuration Register FREEZE bit + ALIAS FREEZE :std_logic IS Config_reg1(0); + + -- *** VDLR Register *** + SHARED VARIABLE VDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL VDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** NVDLR Register *** + SHARED VARIABLE NVDLR_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL NVDLR_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + + -- *** AutoBoot Register *** + SHARED VARIABLE AutoBoot_reg : std_logic_vector(31 downto 0) + := (others => '0'); + SIGNAL AutoBoot_reg_in : std_logic_vector(31 downto 0) + := (others => '0'); + + --AutoBoot Enable Bit + ALIAS ABE :std_logic IS AutoBoot_reg(0); + + -- *** Bank Address Register *** + SHARED VARIABLE Bank_Addr_reg : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL Bank_Addr_reg_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Bank Address Register EXTADD bit + ALIAS EXTADD :std_logic IS Bank_Addr_reg(7); + + -- *** ASP Register *** + SHARED VARIABLE ASP_reg : std_logic_vector(15 downto 0); + SIGNAL ASP_reg_in : std_logic_vector(15 downto 0) + := (others => '1'); + --Read Password Mode Enable Bit + ALIAS RPME :std_logic IS ASP_reg(5); + --PPB OTP Bit + ALIAS PPBOTP :std_logic IS ASP_reg(3); + -- Password Protection Mode Lock Bit + ALIAS PWDMLB :std_logic IS ASP_reg(2); + --Persistent Protection Mode Lock Bit + ALIAS PSTMLB :std_logic IS ASP_reg(1); + + -- *** Password Register *** + SHARED VARIABLE Password_reg : std_logic_vector(63 downto 0) + := (others => '1'); + SIGNAL Password_reg_in : std_logic_vector(63 downto 0) + := (others => '1'); + -- *** PPB Lock Register *** + SHARED VARIABLE PPBL : std_logic_vector(7 downto 0) + := (others => '0'); + SIGNAL PPBL_in : std_logic_vector(7 downto 0) + := (others => '0'); + --Persistent Protection Mode Lock Bit + ALIAS PPB_LOCK : std_logic IS PPBL(0); + SIGNAL PPB_LOCK_temp : std_ulogic := '0'; + + -- *** PPB Access Register *** + SHARED VARIABLE PPBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL PPBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- PPB_bits(Sec) + SHARED VARIABLE PPB_bits : std_logic_vector(SecNum downto 0) + := (OTHERS => '1'); + -- *** DYB Access Register *** + SHARED VARIABLE DYBAR : std_logic_vector(7 downto 0) + := (others => '1'); + SIGNAL DYBAR_in : std_logic_vector(7 downto 0) + := (others => '1'); + -- DYB(Sec) + SHARED VARIABLE DYB_bits : std_logic_vector(SecNum downto 0); + + -- The Lock Protection Registers for OTP Memory space + SHARED VARIABLE LOCK_BYTE1 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE2 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE3 :std_logic_vector(7 downto 0); + SHARED VARIABLE LOCK_BYTE4 :std_logic_vector(7 downto 0); + + --Command Register + SIGNAL write : std_logic := '0'; + SIGNAL cfg_write : std_logic := '0'; + SIGNAL read_out : std_logic := '0'; + + SIGNAL rd : boolean := false; + SIGNAL dual : boolean := false; + SIGNAL fast_rd : boolean := true; + SIGNAL ddr : boolean := false; + SIGNAL any_read : boolean := false; + + SIGNAL quadpg : boolean := false; + + SIGNAL oe : boolean := false; + SIGNAL oe_z : boolean := false; + + SHARED VARIABLE hold_mode : boolean := false; + + --FSM control signals + SIGNAL PDONE : std_logic := '1'; --Page Prog. Done + SIGNAL PSTART : std_logic := '0'; --Start Page Programming + SIGNAL PGSUSP : std_logic := '0'; --Suspend Program + SIGNAL PGRES : std_logic := '0'; --Resume Program + + SIGNAL RES_TO_SUSP_MIN_TIME : std_logic := '0';--Resume to Suspend Flag + SIGNAL RES_TO_SUSP_TYP_TIME : std_logic := '0';--Resume to Suspend Flag + + SIGNAL WDONE : std_logic := '1'; --Write operation Done + SIGNAL WSTART : std_logic := '0'; --Start Write operation + + SIGNAL ESTART : std_logic := '0'; --Start Erase operation + SIGNAL EDONE : std_logic := '1'; --Erase operation Done + SIGNAL ESUSP : std_logic := '0'; --Suspend Erase + SIGNAL ERES : std_logic := '0'; --Resume Erase + + --reset timing + SIGNAL RST : std_logic := '0'; + SIGNAL Reseted : std_logic := '0'; --Reset Timing Control + --Lock Bit is enabled for customer programming + SIGNAL WRLOCKENABLE : BOOLEAN := TRUE; + --Flag that mark if ASP Register is allready programmed + SIGNAL ASPOTPFLAG : BOOLEAN := FALSE; + SIGNAL ASP_INIT : NATURAL RANGE 0 TO 1; + SIGNAL INITIAL_CONFIG : std_logic := '0'; + + SHARED VARIABLE SecAddr : NATURAL RANGE 0 TO SecNum:= 0; + + SHARED VARIABLE Sec_addr : NATURAL := 0; + + SHARED VARIABLE Page_addr : NATURAL; + SHARED VARIABLE pgm_page : NATURAL; + + SHARED VARIABLE QPP_page : std_logic_vector(PageNum downto 0) + := (OTHERS => '0'); + + --Flag for Password unlock command + SIGNAL PASS_UNLOCKED : boolean := FALSE; + SIGNAL PASS_TEMP : std_logic_vector(63 downto 0) + := (others => '1'); + + SHARED VARIABLE DOUBLE : BOOLEAN := FALSE; + SHARED VARIABLE EHP : BOOLEAN := FALSE; + + SHARED VARIABLE read_cnt : NATURAL := 0; + SHARED VARIABLE byte_cnt : NATURAL := 1; + SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ; + SHARED VARIABLE read_addr_tmp : NATURAL RANGE 0 TO AddrRANGE ; + + SHARED VARIABLE start_delay : NATURAL RANGE 0 TO 7; + SHARED VARIABLE ABSD : NATURAL RANGE 0 TO 7; + SIGNAL start_autoboot : std_logic := '0'; + + SIGNAL change_addr : std_logic := '0'; + SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; + SIGNAL SectorSuspend : NATURAL RANGE 0 TO SecNum := 0; + + -- Sector address + SIGNAL SA : NATURAL RANGE 0 TO SecNum := 0; + + -- Sector is protect if Sec_Prot(SecNum) = '1' + SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum downto 0) := + (OTHERS => '0'); + + SIGNAL change_BP : std_logic := '0'; + SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000"; + + SHARED VARIABLE CFI_array_tmp : std_logic_vector(647 downto 0); + + SIGNAL Byte_number : NATURAL RANGE 0 TO 511 := 0; + + TYPE bus_cycle_type IS (STAND_BY, + OPCODE_BYTE, + ADDRESS_BYTES, + DUMMY_BYTES, + MODE_BYTE, + DATA_BYTES + ); + SHARED VARIABLE bus_cycle_state : bus_cycle_type; + -- switch between Data bytes and Dummy bytes + SHARED VARIABLE DummyBytes_act : X01 := '0'; + SIGNAL dummy_cnt_act_temp : NATURAL := 0; + SIGNAL dummy_cnt_act : NATURAL := 0; + --Read Password Protection Mode Active flag + SIGNAL RdPswdProtMode : std_ulogic := '0'; + --Read Password Protection Mode Support flag + SIGNAL RdPswdProtEnable : std_ulogic := '0'; + SIGNAL BAR_ACC : std_ulogic := '0'; + + SHARED VARIABLE Latency_code : NATURAL RANGE 0 TO 7; + SHARED VARIABLE opcode_cnt : NATURAL := 0; + SHARED VARIABLE addr_cnt : NATURAL := 0; + SHARED VARIABLE mode_cnt : NATURAL := 0; + SHARED VARIABLE dummy_cnt : NATURAL := 0; + SHARED VARIABLE data_cnt : NATURAL := 0; + + -- timing check violation + SIGNAL Viol : X01 := '0'; + + PROCEDURE ADDRHILO_SEC( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE sector : NATURAL RANGE 0 TO SecNum; + BEGIN + sector := Addr/16#40000#; + AddrLOW := sector*16#40000#; + AddrHIGH := sector*16#40000# + 16#3FFFF#; + END ADDRHILO_SEC; + + PROCEDURE ADDRHILO_PG( + VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; + VARIABLE Addr : NATURAL) IS + VARIABLE page : NATURAL RANGE 0 TO PageNum; + BEGIN + page := Addr/PageSize; + AddrLOW := Page*PageSize; + AddrHIGH := Page*PageSize + (PageSize-1); + END AddrHILO_PG; + + BEGIN + --------------------------------------------------------------------------- + --Power Up time + --------------------------------------------------------------------------- + + PoweredUp <= '1' AFTER tdevice_PU; + + TimingModelSel: PROCESS + BEGIN + --Enhanced High Performance Flag + IF (TimingModel(15) = '0' OR TimingModel(15) = '2' OR + TimingModel(15) = '3' OR TimingModel(15) = 'R' OR + TimingModel(15) = 'A' OR TimingModel(15) = 'B' OR + TimingModel(15) = 'C' OR TimingModel(15) = 'D' OR + TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + EHP := TRUE; + IF (TimingModel(15) = 'Y' OR TimingModel(15) = 'Z' OR + TimingModel(15) = 'S' OR TimingModel(15) = 'T' OR + TimingModel(15) = 'K' OR TimingModel(15) = 'L') THEN + RdPswdProtEnable <= '1'; + END IF; + ELSIF (TimingModel(15) = '4' OR TimingModel(15) = '6' OR + TimingModel(15) = '7' OR TimingModel(15) = '8' OR + TimingModel(15) = '9' OR TimingModel(15) = 'Q') THEN + EHP := FALSE; + END IF; + + IF (TimingModel(15) ='0' OR TimingModel(15) ='2' OR + TimingModel(15) ='3' OR TimingModel(15) ='R' OR + TimingModel(15) ='A' OR TimingModel(15) ='B' OR + TimingModel(15) ='C' OR TimingModel(15) ='D' OR + TimingModel(15) ='4' OR TimingModel(15) ='6' OR + TimingModel(15) ='7' OR TimingModel(15) ='8' OR + TimingModel(15) ='9' OR TimingModel(15) ='Q') THEN + ASP_INIT <= 1; + ELSIF (TimingModel(15) ='Y' OR TimingModel(15) ='Z' OR + TimingModel(15) ='S' OR TimingModel(15) ='T' OR + TimingModel(15) ='K' OR TimingModel(15) ='L') THEN + ASP_INIT <= 0; + END IF; + WAIT; + END PROCESS; + + RSTtiming: PROCESS(RSTNeg_pullup,Instruct) + BEGIN + IF falling_edge(RSTNeg_pullup) THEN + RST <= '1', '0' AFTER 200 ns; + ELSIF Instruct = RESET THEN + Reseted <= '0', '1' AFTER 10 ns; + END IF; + END PROCESS; + + DUMMYcnt: PROCESS(dummy_cnt_act_temp) + BEGIN + dummy_cnt_act <= dummy_cnt_act_temp; + END PROCESS; + + ReadPasswordProtectionMode: PROCESS(PPB_LOCK_temp, + ASP_reg_in(2), ASP_reg_in(5)) + BEGIN + IF (PPB_LOCK = '0' AND PWDMLB = '0' AND RPME = '0' AND + RdPswdProtEnable = '1') THEN + RdPswdProtMode <= '1'; + ABE := '0'; + ELSE + RdPswdProtMode <= '0'; + END IF; + END PROCESS; + --------------------------------------------------------------------------- + -- autoboot control logic + --------------------------------------------------------------------------- + AutoBootControl: PROCESS(SCK_ipd, current_state) + BEGIN + IF (current_state = AUTOBOOT) THEN + IF rising_edge(SCK_ipd) THEN + IF (start_delay > 0) THEN + start_delay := start_delay - 1; + END IF; + END IF; + + IF (start_delay = 0) THEN + start_autoboot <= '1'; + ELSE + start_autoboot <= '0'; + END IF; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- VITAL Timing Checks Procedures + --------------------------------------------------------------------------- + VITALTimingCheck: PROCESS(SIIn, SOIn, SCK_ipd, CSNeg_ipd, RSTNeg_ipd, + HOLDNegIn, WPNegIn) + + -- Timing Check Variables + -- Setup/Hold Checks variables + VARIABLE Tviol_CSNeg_SCK_normal : X01 := '0'; + VARIABLE TD_CSNeg_SCK_normal : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_SCK_DDR : X01 := '0'; + VARIABLE TD_CSNeg_SCK_DDR : VitalTimingDataType; + + VARIABLE Tviol_CSNeg_RSTNeg : X01 := '0'; + VARIABLE TD_CSNeg_RSTNeg : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK : X01 := '0'; + VARIABLE TD_SI_SCK : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType; + + VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0'; + VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType; + + VARIABLE Tviol_HOLDNeg_SCK : X01 := '0'; + VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_R : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_R : VitalTimingDataType; + + VARIABLE Tviol_SI_SCK_DDR_F : X01 := '0'; + VARIABLE TD_SI_SCK_DDR_F : VitalTimingDataType; + + VARIABLE Tviol_RSTNeg_CSNeg : X01 := '0'; + VARIABLE TD_RSTNeg_CSNeg : VitalTimingDataType; + + --Pulse Width and Period Check Variables + VARIABLE Pviol_SCK_serial : X01 := '0'; + VARIABLE PD_SCK_serial : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual : X01 := '0'; + VARIABLE PD_SCK_dual : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast : X01 := '0'; + VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quadpg : X01 := '0'; + VARIABLE PD_SCK_quadpg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR : X01 := '0'; + VARIABLE PD_SCK_DDR : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_read : X01 := '0'; + VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_CSNeg_pgers : X01 := '0'; + VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_RSTNeg : X01 := '0'; + VARIABLE PD_RSTNeg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_serial_rd : X01 := '0'; + VARIABLE PD_SCK_serial_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_fast_rd : X01 := '0'; + VARIABLE PD_SCK_fast_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_dual_rd : X01 := '0'; + VARIABLE PD_SCK_dual_rd : VitalPeriodDataType:=VitalPeriodDataInit; + + VARIABLE Pviol_SCK_DDR_rd : X01 := '0'; + VARIABLE PD_SCK_DDR_rd : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Pviol_SCK_quad_pg : X01 := '0'; + VARIABLE PD_SCK_quad_pg : VitalPeriodDataType:= VitalPeriodDataInit; + + VARIABLE Violation : X01 := '0'; + + BEGIN + --------------------------------------------------------------------------- + -- Timing Check Section + --------------------------------------------------------------------------- + IF (TimingChecksOn) THEN + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_normal_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_normal_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_normal_noedge_posedge, + HoldLow => thold_CSNeg_SCK_normal_noedge_posedge, + CheckEnabled => ddr = false, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_normal, + Violation => Tviol_CSNeg_SCK_normal + ); + + -- Setup/Hold Check between CS# and SCK + VitalSetupHoldCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_CSNeg_SCK_DDR_noedge_posedge, + SetupLow => tsetup_CSNeg_SCK_DDR_noedge_posedge, + HoldHigh => thold_CSNeg_SCK_DDR_noedge_posedge, + HoldLow => thold_CSNeg_SCK_DDR_noedge_posedge, + CheckEnabled => ddr, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_SCK_DDR, + Violation => Tviol_CSNeg_SCK_DDR + ); + + -- Hold Check between CSNeg and RSTNeg + VitalSetupHoldCheck ( + TestSignal => CSNeg, + TestSignalName => "CSNeg", + RefSignal => RSTNeg, + RefSignalName => "RSTNeg", + HoldHigh => thold_CSNeg_RSTNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_CSNeg_RSTNeg, + Violation => Tviol_CSNeg_RSTNeg + ); + + -- Setup/Hold Check between SI and SCK, serial mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_normal_noedge_posedge, + SetupLow => tsetup_SI_SCK_normal_noedge_posedge, + HoldHigh => thold_SI_SCK_normal_noedge_posedge, + HoldLow => thold_SI_SCK_normal_noedge_posedge, + CheckEnabled => NOT(DOUBLE) AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK, + Violation => Tviol_SI_SCK + ); + + -- Setup Check between WP# and CS# \ + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + SetupHigh => tsetup_WPNeg_CSNeg, + CheckEnabled => true, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_setup, + Violation => Tviol_WPNeg_CSNeg_setup + ); + + -- Hold Check between WP# and CS# / + VitalSetupHoldCheck ( + TestSignal => WPNegIn, + TestSignalName => "WP#", + RefSignal => CSNeg_ipd, + RefSignalName => "CS#", + HoldHigh => thold_WPNeg_CSNeg, + CheckEnabled => SRWD = '1' AND WEL = '1', + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_WPNeg_CSNeg_hold, + Violation => Tviol_WPNeg_CSNeg_hold + ); + + -- Setup/Hold Check between HOLD# and SCK / + VitalSetupHoldCheck ( + TestSignal => HOLDNegIn, + TestSignalName => "HOLD#", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupLow => tsetup_HOLDNeg_SCK, + SetupHigh => tsetup_HOLDNeg_SCK, + HoldLow => thold_HOLDNeg_SCK, + HoldHigh => thold_HOLDNeg_SCK, + CheckEnabled => QUAD = '0' + AND HOLDNegOut_zd /= HOLDNegIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_HOLDNeg_SCK, + Violation => Tviol_HOLDNeg_SCK + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_posedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_posedge, + HoldHigh => thold_SI_SCK_DDR_noedge_posedge, + HoldLow => thold_SI_SCK_DDR_noedge_posedge, + CheckEnabled => DOUBLE AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '/', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_R, + Violation => Tviol_SI_SCK_DDR_R + ); + + -- Setup/Hold Check between SI and SCK, DDR mode + VitalSetupHoldCheck ( + TestSignal => SIIn, + TestSignalName => "SI", + RefSignal => SCK_ipd, + RefSignalName => "SCK", + SetupHigh => tsetup_SI_SCK_DDR_noedge_negedge, + SetupLow => tsetup_SI_SCK_DDR_noedge_negedge, + HoldHigh => thold_SI_SCK_DDR_noedge_negedge, + HoldLow => thold_SI_SCK_DDR_noedge_negedge, + CheckEnabled => ddr AND dual = false + AND SIOut_z /= SIIn, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_SI_SCK_DDR_F, + Violation => Tviol_SI_SCK_DDR_F + ); + + -- Setup Check between RSTNeg and SCK, DDR fast mode + VitalSetupHoldCheck ( + TestSignal => RSTNeg, + TestSignalName => "RSTNeg", + RefSignal => CSNeg, + RefSignalName => "CSNeg", + SetupHigh => tsetup_RSTNeg_CSNeg, + CheckEnabled => TRUE, + RefTransition => '\', + HeaderMsg => InstancePath & PartID, + TimingData => TD_RSTNeg_CSNeg, + Violation => Tviol_RSTNeg_CSNeg + ); + + --Pulse Width and Period Check Variables + -- Pulse Width Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_serial_negedge, + PulseWidthHigh => tpw_SCK_serial_posedge, + PeriodData => PD_SCK_serial, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd); + + -- Pulse Width Check SCK for DUAL_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_dual_negedge, + PulseWidthHigh => tpw_SCK_dual_posedge, + PeriodData => PD_SCK_dual, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual); + + -- Pulse Width Check SCK for FAST_READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_fast_negedge, + PulseWidthHigh => tpw_SCK_fast_posedge, + PeriodData => PD_SCK_fast, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Pulse Width Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_quadpg_negedge, + PulseWidthHigh => tpw_SCK_quadpg_posedge, + PeriodData => PD_SCK_quadpg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quadpg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg); + + -- Pulse Width Check CS# for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_read_posedge, + PeriodData => PD_CSNeg_read, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_read, + HeaderMsg => InstancePath & PartID, + CheckEnabled => any_read ); + + -- Pulse Width Check CS# for Program/Erase, serial mode + VitalPeriodPulseCheck ( + TestSignal => CSNeg_ipd, + TestSignalName => "CS#", + PulseWidthHigh => tpw_CSNeg_pgers_posedge, + PeriodData => PD_CSNeg_pgers, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_CSNeg_pgers, + HeaderMsg => InstancePath & PartID, + CheckEnabled => NOT(any_read)); + + -- Pulse Width Check RSTNeg + VitalPeriodPulseCheck ( + TestSignal => RSTNeg_ipd, + TestSignalName => "RSTNeg", + PulseWidthLow => tpw_RSTNeg_negedge, + PulseWidthHigh => tpw_RSTNeg_posedge, + CheckEnabled => TRUE, + HeaderMsg => InstancePath & PartID, + PeriodData => PD_RSTNeg, + Violation => Pviol_RSTNeg + ); + + -- Pulse Width Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + PulseWidthLow => tpw_SCK_DDR_negedge, + PulseWidthHigh => tpw_SCK_DDR_posedge, + PeriodData => PD_SCK_DDR, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr); + + -- Period Check SCK for READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_serial_rd, + PeriodData => PD_SCK_serial_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_serial_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => rd ); + + -- Period Check SCK for FAST READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_fast_rd, + PeriodData => PD_SCK_fast_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_fast_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => fast_rd ); + + -- Period Check SCK for DUAL READ, serial mode + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_dual_rd, + PeriodData => PD_SCK_dual_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_dual_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => dual ); + + -- Period Check SCK for QPP + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_quadpg, + PeriodData => PD_SCK_quad_pg, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_quad_pg, + HeaderMsg => InstancePath & PartID, + CheckEnabled => quadpg ); + + -- Period Check SCK for DDR READ + VitalPeriodPulseCheck ( + TestSignal => SCK_ipd, + TestSignalName => "SCK", + Period => tperiod_SCK_DDR_rd, + PeriodData => PD_SCK_DDR_rd, + XOn => XOn, + MsgOn => MsgOn, + Violation => Pviol_SCK_DDR_rd, + HeaderMsg => InstancePath & PartID, + CheckEnabled => ddr ); + + Violation := Tviol_CSNeg_SCK_normal OR + Tviol_CSNeg_SCK_DDR OR + Tviol_CSNeg_RSTNeg OR + Tviol_SI_SCK OR + Tviol_WPNeg_CSNeg_setup OR + Tviol_WPNeg_CSNeg_hold OR + Tviol_HOLDNeg_SCK OR + Tviol_SI_SCK_DDR_R OR + Tviol_SI_SCK_DDR_F OR + Tviol_RSTNeg_CSNeg OR + Pviol_SCK_serial OR + Pviol_SCK_dual OR + Pviol_SCK_fast OR + Pviol_SCK_quadpg OR + Pviol_CSNeg_read OR + Pviol_CSNeg_pgers OR + Pviol_SCK_DDR OR + Pviol_SCK_serial_rd OR + Pviol_SCK_fast_rd OR + Pviol_SCK_dual_rd OR + Pviol_SCK_quad_pg OR + Pviol_SCK_DDR_rd; + + Viol <= Violation; + + ASSERT Violation = '0' + REPORT InstancePath & partID & ": simulation may be" & + " inaccurate due to timing violations" + SEVERITY WARNING; + + END IF; + END PROCESS VITALTimingCheck; + + ---------------------------------------------------------------------------- + -- sequential process for FSM state transition + ---------------------------------------------------------------------------- + StateTransition : PROCESS(next_state, RST, PoweredUp, RST_out) + + BEGIN + IF PoweredUp = '1' THEN + IF RSTNeg_pullup = '1' and RST_out= '1' THEN + IF next_state'EVENT THEN + current_state <= next_state; + END IF; + ELSIF RSTNeg_pullup = '0' AND falling_edge(RST) THEN + --no state transition while RESET# low + current_state <= RESET_STATE; + RST_in <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END PROCESS StateTransition; + + Threset : PROCESS(RST_in) + BEGIN + IF rising_edge(RST_in) THEN + RST_out <= '0', '1' AFTER (thold_CSNeg_RSTNeg-200 ns); + END IF; + END PROCESS Threset; + + --------------------------------------------------------------------------- + -- Write cycle decode + --------------------------------------------------------------------------- + + BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_pullup, SIIn, RST_out, + WPNeg_pullup) + + TYPE quad_data_type IS ARRAY (0 TO 1023) OF INTEGER RANGE 0 TO 15; + + VARIABLE bit_cnt : NATURAL := 0; + VARIABLE Data_in : std_logic_vector(4095 downto 0) + := (others => '0'); + + VARIABLE opcode : std_logic_vector(7 downto 0); + VARIABLE opcode_in : std_logic_vector(7 downto 0); + VARIABLE addr_bytes : std_logic_vector(31 downto 0); + VARIABLE hiaddr_bytes : std_logic_vector(31 downto 0); + VARIABLE Address_in : std_logic_vector(31 downto 0); + VARIABLE mode_bytes : std_logic_vector(7 downto 0); + VARIABLE mode_in : std_logic_vector(7 downto 0); + VARIABLE quad_data_in : quad_data_type; + VARIABLE quad_nybble : std_logic_vector(3 downto 0); + VARIABLE Quad_slv : std_logic_vector(3 downto 0); + VARIABLE Byte_slv : std_logic_vector(7 downto 0); + + VARIABLE CLK_PER : time; + VARIABLE LAST_CLK : time; + VARIABLE Check_freq : boolean := FALSE; + + BEGIN + + IF rising_edge(CSNeg_ipd) AND NOT(bus_cycle_state = DATA_BYTES) + AND NOT(bus_cycle_state = DUMMY_BYTES) THEN + bus_cycle_state := STAND_BY; + ELSE + CASE bus_cycle_state IS + WHEN STAND_BY => + IF falling_edge(CSNeg_ipd) THEN + Instruct <= NONE; + write <= '1'; + cfg_write <= '0'; + opcode_cnt:= 0; + addr_cnt := 0; + mode_cnt := 0; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + data_cnt := 0; + DOUBLE := FALSE; + CLK_PER := 0 ns; + LAST_CLK := 0 ns; + IF current_state = AUTOBOOT THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := OPCODE_BYTE; + END IF; + END IF; + + WHEN OPCODE_BYTE => + IF rising_edge(SCK_ipd) THEN + + Latency_code := to_nat(LC1 & LC0); + CLK_PER := NOW - LAST_CLK; + LAST_CLK := NOW; + IF Check_freq THEN + IF (CLK_PER < 20 ns AND Latency_code = 3) OR + (CLK_PER < 12.5 ns AND Latency_code = 0) OR + (CLK_PER < 11.1 ns AND Latency_code = 1) OR + (CLK_PER < 9.6 ns AND Latency_code = 2) THEN + ASSERT FALSE + REPORT "More wait states are required for " & + "this clock frequency value" + SEVERITY warning; + END IF; + END IF; + Check_freq := FALSE; + + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + --One-byte of instruction opcode is shifted into the + --device on the SI serial input pin with the most + --significant bit (MSB) first.Each bit input on the + --SI serial input pin is latched on the rising edge of + --the SCK serial clock signal. + opcode_in(opcode_cnt) := SIIn; + opcode_cnt := opcode_cnt + 1; + IF opcode_cnt = BYTE THEN + --MSB first + FOR I IN 7 DOWNTO 0 LOOP + opcode(i) := opcode_in(7-i); + END LOOP; + + CASE opcode IS + WHEN "00000110" => --06h + Instruct <= WREN; + bus_cycle_state := DATA_BYTES; + WHEN "00000100" => --04h + Instruct <= WRDI; + bus_cycle_state := DATA_BYTES; + WHEN "00000001" => --01h + Instruct <= WRR; + bus_cycle_state := DATA_BYTES; + WHEN "00000011" => --03h + Instruct <= READ; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010011" => --13h + Instruct <= RD4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01001011" => --4Bh + Instruct <= OTPR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00000101" => --05h + Instruct <= RDSR; + bus_cycle_state := DATA_BYTES; + WHEN "00000111" => --07h + Instruct <= RDSR2; + bus_cycle_state := DATA_BYTES; + WHEN "00110101" => --35h + Instruct <= RDCR; + bus_cycle_state := DATA_BYTES; + WHEN "10010000" => --90h + Instruct <= REMS; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10011111" => --9Fh + Instruct <= RDID; + bus_cycle_state := DATA_BYTES; + WHEN "10101011" => --ABh + Instruct <= RES; + bus_cycle_state := DUMMY_BYTES; + WHEN "00001011" => --0Bh + Instruct <= FSTRD; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001100" => --0Ch + Instruct <= FSTRD4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001101" => --0Dh + Instruct <= DDRFR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00001110" => --0Eh + Instruct <= DDRFR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00111011" => --3Bh + Instruct <= DOR; + Check_freq := TRUE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00111100" => --3Ch + Instruct <= DOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111011" => --BBh + Instruct <= DIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111100" => --BCh + Instruct <= DIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111101" => --BDh + Instruct <= DDRDIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "10111110" => --BEh + Instruct <= DDRDIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101011" => --6Bh + Instruct <= QOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "01101100" => --6Ch + Instruct <= QOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101011" => --EBh + Instruct <= QIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101100" => --ECh + Instruct <= QIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101101" => --EDh + Instruct <= DDRQIOR; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "11101110" => --EEh + Instruct <= DDRQIOR4; + bus_cycle_state := ADDRESS_BYTES; + Check_freq := TRUE; + WHEN "00000010" => --02h + Instruct <= PP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00010010" => --12h + Instruct <= PP4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00110010" => --32h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00111000" => --38h + Instruct <= QPP; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "00110100" => --34h + Instruct <= QPP4; + bus_cycle_state := ADDRESS_BYTES; + quadpg <= TRUE; + WHEN "01000010" => --42h + Instruct <= OTPP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "10000101" => --85h + Instruct <= PGSP; + bus_cycle_state := DATA_BYTES; + WHEN "10001010" => --8Ah + Instruct <= PGRS; + bus_cycle_state := DATA_BYTES; + WHEN "11000111" => --C7h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "01100000" => --60h + Instruct <= BE; + bus_cycle_state := DATA_BYTES; + WHEN "11011000" => --D8h + Instruct <= SE; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11011100" => --DCh + Instruct <= SE4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100000" => --20h + Instruct <= P4E; + bus_cycle_state := ADDRESS_BYTES; + WHEN "00100001" => --21h + Instruct <= P4E4; + bus_cycle_state := ADDRESS_BYTES; + WHEN "01110101" => --75h + Instruct <= ERSP; + bus_cycle_state := DATA_BYTES; + WHEN "01111010" => --7Ah + Instruct <= ERRS; + bus_cycle_state := DATA_BYTES; + WHEN "00010100" => --14h + Instruct <= ABRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010101" => --15h + Instruct <= ABWR; + bus_cycle_state := DATA_BYTES; + WHEN "00010110" => --16h + Instruct <= BRRD; + bus_cycle_state := DATA_BYTES; + WHEN "00010111" => --17h + Instruct <= BRWR; + bus_cycle_state := DATA_BYTES; + WHEN "10111001" => --B9h + Instruct <= BRAC; + bus_cycle_state := DATA_BYTES; + WHEN "00101011" => --2Bh + Instruct <= ASPRD; + bus_cycle_state := DATA_BYTES; + WHEN "00101111" => --2Fh + Instruct <= ASPP; + bus_cycle_state := DATA_BYTES; + WHEN "11100000" => --E0h + Instruct <= DYBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100001" => --E1h + Instruct <= DYBWR; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100010" => --E2h + Instruct <= PPBRD; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100011" => --E3h + Instruct <= PPBP; + bus_cycle_state := ADDRESS_BYTES; + WHEN "11100100" => --E4h + Instruct <= PPBERS; + bus_cycle_state := DATA_BYTES; + WHEN "10100110" => --A6h + Instruct <= PLBWR; + bus_cycle_state := DATA_BYTES; + WHEN "10100111" => --A7h + Instruct <= PLBRD; + bus_cycle_state := DATA_BYTES; + WHEN "11100111" => --E7h + Instruct <= PASSRD; + bus_cycle_state := DATA_BYTES; + WHEN "11101000" => --E8h + Instruct <= PASSP; + bus_cycle_state := DATA_BYTES; + WHEN "11101001" => --E9h + Instruct <= PASSU; + bus_cycle_state := DATA_BYTES; + WHEN "11110000" => --F0h + Instruct <= RESET; + bus_cycle_state := DATA_BYTES; + WHEN "11111111" => --FFh + Instruct <= MBR; + bus_cycle_state := MODE_BYTE; + WHEN "01000001" => -- 41h + Instruct <= DLPRD; + bus_cycle_state := DATA_BYTES; + WHEN "01000011" => -- 43h + Instruct <= PNVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "01001010" => -- 4Ah + Instruct <= WVDLR; + bus_cycle_state := DATA_BYTES; + WHEN "00110000" => --30h + Instruct <= CLSR; + bus_cycle_state := DATA_BYTES; + WHEN others => + null; + + END CASE; + END IF; + END IF; + END IF; + + WHEN ADDRESS_BYTES => + IF Instruct= DDRFR OR Instruct= DDRFR4 OR Instruct= DDRDIOR + OR Instruct = DDRDIOR4 OR Instruct = DDRQIOR OR + Instruct = DDRQIOR4 THEN + DOUBLE := TRUE; + ELSE + DOUBLE := FALSE; + END IF; + + IF (rising_edge(SCK_ipd) AND NOT(DOUBLE) AND + (CSNeg_ipd= '0')) THEN + IF (((Instruct=FSTRD AND EXTADD= '0' ) + OR (Instruct=DOR AND EXTADD= '0') + OR Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (Instruct=QOR AND QUAD= '1' AND EXTADD='0') THEN + --Instruction + 3 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF (Instruct=FSTRD OR Instruct=DOR OR + Instruct=QOR) THEN + IF (Latency_code = 3) THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF ((((Instruct=FSTRD4) OR (Instruct=DOR4) OR + ((Instruct=FSTRD) AND EXTADD= '1') OR + ((Instruct=DOR) AND EXTADD= '1')) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct=QOR4) AND QUAD='1') OR + ((Instruct=QOR) AND QUAD='1' AND EXTADD='1')) THEN + --Instruction + 4 Bytes Address + Dummy Byte + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF (DOUBLE AND NOT(hold_mode) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF Instruct = DIOR AND EXTADD= '0' AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + -- DUAL I/O High Performance Read (3Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF ((Instruct = DIOR4 OR + (Instruct = DIOR AND EXTADD= '1')) AND + ((HOLDNeg_pullup = '1' AND QUAD = '0') OR + QUAD = '1')) THEN + -- DUAL I/O High Performance Read (4Bytes Address) + IF SOIn /= 'Z' THEN + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR AND EXTADD= '0') THEN + -- QUAD I/O High Performance Read (3Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (3*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (Instruct = QIOR4 OR + (Instruct = QIOR AND EXTADD= '1')) THEN + -- QUAD I/O High Performance Read (4Bytes Address) + IF QUAD = '1' THEN + IF SOIn /= 'Z' THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + read_cnt := 0; + addr_cnt := addr_cnt + 1; + IF addr_cnt = (4*BYTE) / 4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) + := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + ELSE + bus_cycle_state := STAND_BY; + END IF; + ELSIF (((Instruct = RD4 OR Instruct = PP4 OR + Instruct = SE4 OR Instruct = PPBRD OR + Instruct = DYBRD OR Instruct = DYBWR OR + Instruct = PPBP OR Instruct = P4E4 OR + (Instruct = READ AND EXTADD= '1' ) OR + (Instruct = PP AND EXTADD= '1' ) OR + (Instruct = P4E AND EXTADD= '1' ) OR + (Instruct = SE AND EXTADD= '1' )) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (QUAD ='1' AND (Instruct=QPP4 OR + (Instruct = QPP AND EXTADD= '1' ))))THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 4*BYTE THEN + FOR I IN 31 DOWNTO 0 LOOP + hiaddr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(hiaddr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') AND EXTADD= '0') THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + IF addr_cnt = 3*BYTE THEN + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF (SCK_ipd'EVENT AND DOUBLE AND addr_cnt /= 0 ) OR + (rising_edge(SCK_ipd) AND DOUBLE AND addr_cnt = 0 ) THEN + IF (Instruct=DDRFR AND EXTADD= '0' ) THEN + --Fast DDR Read Mode + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 3*BYTE THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRFR4 OR + (Instruct=DDRFR AND EXTADD= '1' )) THEN + Address_in(addr_cnt) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = 4*BYTE THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct= DDRDIOR AND EXTADD= '0' ) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1):= SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=DDRDIOR4 OR + (Instruct=DDRDIOR AND EXTADD= '1' )) THEN + --Dual I/O DDR Read Mode + Address_in(2*addr_cnt) := SOIn; + Address_in(2*addr_cnt+1) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/2 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + IF EHP THEN + bus_cycle_state := MODE_BYTE; + ELSE + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR AND EXTADD= '0' ) AND + QUAD = '1' THEN + --Quad I/O DDR Read Mode + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (3*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 23 DOWNTO 0 LOOP + addr_bytes(23-i) := Address_in(i); + END LOOP; + addr_bytes(31 downto 26) := "000000"; + addr_bytes(25 downto 24) := + Bank_Addr_reg (1 downto 0); + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 5 ns; + bus_cycle_state := MODE_BYTE; + END IF; + ELSIF QUAD = '1' AND (Instruct=DDRQIOR4 OR + (Instruct=DDRQIOR AND EXTADD= '1' )) THEN + Address_in(4*addr_cnt) := HOLDNegIn; + Address_in(4*addr_cnt+1) := WPNegIn; + Address_in(4*addr_cnt+2) := SOIn; + Address_in(4*addr_cnt+3) := SIIn; + addr_cnt := addr_cnt + 1; + read_cnt := 0; + IF addr_cnt = (4*BYTE)/4 THEN + addr_cnt := 0; + FOR I IN 31 DOWNTO 0 LOOP + addr_bytes(31-i) := Address_in(i); + END LOOP; + Address <= to_nat(addr_bytes); + change_addr <= '1','0' AFTER 1 ns; + bus_cycle_state := MODE_BYTE; + END IF; + END IF; + END IF; + + WHEN MODE_BYTE => + IF rising_edge(SCK_ipd) THEN + IF ((Instruct=DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) THEN + mode_in(2*mode_cnt) := SOIn; + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + IF Latency_code = 0 OR Latency_code = 3 THEN + bus_cycle_state := DATA_BYTES; + ELSE + bus_cycle_state := DUMMY_BYTES; + END IF; + END IF; + ELSIF (Instruct=QIOR OR Instruct = QIOR4) + AND QUAD = '1' THEN + mode_in(4*mode_cnt) := HOLDNegIn; + mode_in(4*mode_cnt+1) := WPNegIn; + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + END IF; + ELSIF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt) := SIIn; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt) := SOIn; + mode_in(4*mode_cnt+1) := SIIn; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(0) := HOLDNegIn; + mode_in(1) := WPNegIn; + mode_in(2) := SOIn; + mode_in(3) := SIIn; + END IF; + dummy_cnt := 0; + dummy_cnt_act_temp <= dummy_cnt; + ELSIF falling_edge(SCK_ipd) THEN + IF Instruct=DDRFR OR Instruct = DDRFR4 THEN + mode_in(2*mode_cnt+1) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/2 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF Instruct=DDRDIOR OR Instruct = DDRDIOR4 THEN + mode_in(4*mode_cnt+2) := SOIn; + mode_in(4*mode_cnt+3) := SIIn; + mode_cnt := mode_cnt + 1; + IF mode_cnt = BYTE/4 THEN + mode_cnt := 0; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + ELSIF (Instruct=DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + mode_in(4) := HOLDNegIn; + mode_in(5) := WPNegIn; + mode_in(6) := SOIn; + mode_in(7) := SIIn; + FOR I IN 7 DOWNTO 0 LOOP + mode_bytes(i) := mode_in(7-i); + END LOOP; + bus_cycle_state := DUMMY_BYTES; + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DUMMY_BYTES => + IF rising_edge(SCK_ipd) THEN + IF ((DOUBLE AND NOT(hold_mode)) AND + VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + IF (((Instruct=FSTRD OR Instruct=FSTRD4 OR + Instruct=DOR OR Instruct=DOR4 OR + Instruct=OTPR) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) OR + ((Instruct = QOR OR Instruct = QOR4) AND + QUAD = '1'))THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt=1) OR + (Latency_code = 0 AND dummy_cnt=2) OR + (Latency_code = 1 AND dummy_cnt=4) OR + (Latency_code = 2 AND dummy_cnt=5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 5) OR + (Latency_code = 1 AND dummy_cnt = 6) OR + (Latency_code = 2 AND dummy_cnt = 7)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct=RES THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF dummy_cnt = 3*BYTE THEN + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DIOR OR Instruct = DIOR4) AND + ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 1 AND dummy_cnt = 1) OR + (Latency_code = 2 AND dummy_cnt = 2)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF EHP THEN + IF ((Latency_code = 3 AND dummy_cnt = 2) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 5) OR + (Latency_code = 2 AND dummy_cnt = 6)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSE + IF ((Latency_code = 3 AND dummy_cnt = 4) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF ((Instruct = QIOR OR Instruct = QIOR4) AND + QUAD = '1') THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 1) OR + (Latency_code = 0 AND dummy_cnt = 4) OR + (Latency_code = 1 AND dummy_cnt = 4) OR + (Latency_code = 2 AND dummy_cnt = 5)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + ELSIF (Instruct = DDRQIOR OR Instruct = DDRQIOR4) + AND QUAD = '1' THEN + dummy_cnt := dummy_cnt + 1; + dummy_cnt_act_temp <= dummy_cnt; + IF ((Latency_code = 3 AND dummy_cnt = 3) OR + (Latency_code = 0 AND dummy_cnt = 6) OR + (Latency_code = 1 AND dummy_cnt = 7) OR + (Latency_code = 2 AND dummy_cnt = 8)) THEN + DummyBytes_act := '1'; + bus_cycle_state := DATA_BYTES; + END IF; + END IF; + ELSIF falling_edge(SCK_ipd) THEN + IF NOT(hold_mode) THEN + IF (DOUBLE AND VDLR_reg /= "00000000") THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + END IF; + END IF; + + WHEN DATA_BYTES => + IF rising_edge(CSNeg_ipd) THEN + IF ((mode_bytes(7 downto 4) = "1010" AND + (Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QIOR OR Instruct = QIOR4)) OR + ((mode_bytes(7 downto 4) = + NOT(mode_bytes(3 downto 0))) AND + (Instruct = DDRFR OR Instruct = DDRFR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 OR + Instruct = DDRQIOR OR Instruct = DDRQIOR4))) THEN + bus_cycle_state := ADDRESS_BYTES; + ELSE + bus_cycle_state := STAND_BY; + END IF; + END IF; + IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' AND + NOT(DOUBLE) THEN + IF ((Instruct = READ OR Instruct=RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = RDSR OR Instruct = RDSR2 OR + Instruct = RDCR OR Instruct = OTPR OR + Instruct = DOR OR Instruct = DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = ABRD OR Instruct = BRRD OR + Instruct = ASPRD OR Instruct = DYBRD OR + Instruct = PPBRD OR + Instruct = PASSRD OR Instruct = RDID OR + Instruct = RES OR Instruct = REMS OR + Instruct = PLBRD OR Instruct = DLPRD) + AND ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD='1')) + OR (current_state = AUTOBOOT AND start_delay = 0)OR + ((Instruct=QOR OR Instruct=QIOR OR Instruct=QOR4 + OR Instruct= QIOR4) AND QUAD = '1') THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + ELSIF SCK_ipd'EVENT AND CSNeg_ipd = '0' AND DOUBLE THEN + read_out <= '1', '0' AFTER 1 ns; + END IF; + + IF rising_edge(SCK_ipd) THEN + IF QUAD = '1' AND (Instruct=QPP OR Instruct = QPP4)THEN + quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn; + IF data_cnt > (PageSize*2-1) THEN + --In case of quad mode and QPP, + --if more than 512 bytes are sent to the device + FOR I IN 0 TO (PageSize*2-2) LOOP + quad_data_in(i) := quad_data_in(i+1); + END LOOP; + quad_data_in((PageSize*2-1)) := + to_nat(quad_nybble); + data_cnt := data_cnt +1; + ELSE + IF quad_nybble /= "ZZZZ" THEN + quad_data_in(data_cnt) := + to_nat(quad_nybble); + END IF; + data_cnt := data_cnt +1; + END IF; + ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt > (PageSize*8-1) THEN + --In case of serial mode and PP, + -- if more than 512 bytes are sent to the device + -- previously latched data are discarded and last + -- 512 data bytes are guaranteed to be programmed + -- correctly within the same page. + IF bit_cnt = 0 THEN + FOR I IN 0 TO ((PageSize-1)*BYTE - 1) LOOP + Data_in(i) := Data_in(i+8); + END LOOP; + END IF; + Data_in((PageSize-1)*BYTE + bit_cnt) := SIIn; + bit_cnt := bit_cnt + 1; + IF bit_cnt = 8 THEN + bit_cnt := 0; + END IF; + data_cnt := data_cnt + 1; + ELSE + Data_in(data_cnt) := SIIn; + data_cnt := data_cnt + 1; + bit_cnt := 0; + END IF; + END IF; + END IF; + + IF rising_edge(CSNeg_ipd) THEN + CASE Instruct IS + WHEN WREN | WRDI | BE | SE | SE4 | CLSR | RESET | + PPBP | PPBERS | PGSP | PGRS | ERSP | BRAC | + ERRS | P4E | P4E4 | PLBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF data_cnt = 0 THEN + write <= '0'; + END IF; + END IF; + + WHEN WRR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') + OR QUAD='1') THEN + IF ((data_cnt mod 8) = 0 AND data_cnt > 0) THEN + IF data_cnt = 8 THEN + --If CS# is driven high after eight + --cycle,only the Status Register is + --written to. + write <= '0'; + IF BAR_ACC = '0' THEN + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= + Data_in(7-i); + END LOOP; + ELSIF P_ERR = '0' AND E_ERR = '0' THEN + FOR i IN 0 TO 7 LOOP + Bank_Addr_reg_in(i) <= + Data_in(7-i); + END LOOP; + END IF; + ELSIF data_cnt = 16 THEN + --After the 16th cycle both the + --Status and Configuration Registers + --are written to. + write <= '0'; + IF BAR_ACC = '0' THEN + FOR i IN 0 TO 7 LOOP + cfg_write <= '1'; + FOR i IN 0 TO 7 LOOP + Status_reg1_in(i) <= + Data_in(7-i); + Config_reg1_in(i) <= + Data_in(15-i); + END LOOP; + END LOOP; + ELSIF P_ERR = '0' AND E_ERR = '0' THEN + FOR i IN 0 TO 7 LOOP + Bank_Addr_reg_in(i) <= + Data_in(7-i); + END LOOP; + END IF; + END IF; + END IF; + END IF; + + WHEN PP | PP4 | OTPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt > 0 THEN + IF (data_cnt mod 8) = 0 THEN + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 7 DOWNTO 0 LOOP + IF Data_in((i*8) + (7-j)) + /= 'X' THEN + Byte_slv(j) := + Data_in((i*8) + (7-j)); + END IF; + END LOOP; + WByte(i) <= + to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*BYTE THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/8-1; + END IF; + END IF; + END IF; + END IF; + + WHEN QPP | QPP4=> + IF data_cnt > 0 THEN + IF data_cnt mod 2 = 0 THEN + quadpg <= FALSE; + write <= '0'; + FOR I IN 0 TO (PageSize-1) LOOP + FOR J IN 1 DOWNTO 0 LOOP + Quad_slv := + to_slv(quad_data_in((i*2) + + (1-j)),4); + + Byte_slv(4*j+3 DOWNTO 4*j) := + Quad_slv; + END LOOP; + WByte(i) <= to_nat(Byte_slv); + END LOOP; + IF data_cnt > PageSize*2 THEN + Byte_number <= PageSize-1; + ELSE + Byte_number <= data_cnt/2-1; + END IF; + END IF; + END IF; + + WHEN ABWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 32 THEN + write <= '0'; + FOR J IN 0 TO 31 LOOP + AutoBoot_reg_in(J) <= + Data_in(31-J); + END LOOP; + END IF; + END IF; + + WHEN BRWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + Bank_Addr_reg_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN ASPP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 16 THEN + write <= '0'; + FOR J IN 0 TO 15 LOOP + ASP_reg_in(J) <= + Data_in(15-J); + END LOOP; + END IF; + END IF; + + WHEN DYBWR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + DYBAR_in(J) <= + Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PNVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + NVDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN WVDLR => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 8 THEN + write <= '0'; + FOR J IN 0 TO 7 LOOP + VDLR_reg_in(J) <= Data_in(7-J); + END LOOP; + END IF; + END IF; + + WHEN PASSP => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + Password_reg_in(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN PASSU => + IF ((HOLDNeg_pullup='1' AND QUAD='0') OR + QUAD='1') THEN + IF data_cnt = 64 THEN + write <= '0'; + FOR J IN 1 TO 8 LOOP + FOR K IN 1 TO 8 LOOP + PASS_TEMP(J*8-K) <= + Data_in(8*(J-1)+K-1); + END LOOP; + END LOOP; + END IF; + END IF; + + WHEN others => + null; + + END CASE; + END IF; + END CASE; + END IF; + + END PROCESS BusCycleDecode; + + --------------------------------------------------------------------------- + -- Timing control for the Page Program + --------------------------------------------------------------------------- + ProgTime : PROCESS(PSTART, PGSUSP, PGRES, RST, Reseted) + VARIABLE pob : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF rising_edge(PSTART) AND PDONE = '1' THEN + IF Instruct = PP OR Instruct = PP4 OR Instruct = OTPP OR + Instruct = QPP OR Instruct = QPP4 THEN + pob := tdevice_PP; + ELSE + pob := tdevice_BP; + END IF; + elapsed := 0 ns; + start := NOW; + PDONE <= '0', '1' AFTER pob; + ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN + elapsed := NOW - start; + duration := pob - elapsed; + PDONE <= '0'; + ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN + start := NOW; + PDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + PDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + PDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS ProgTime; + + --------------------------------------------------------------------------- + -- Timing control for the Write Status Register + --------------------------------------------------------------------------- + WriteTime : PROCESS(WSTART) + VARIABLE wob : time; + BEGIN + IF LongTimming THEN + wob := tdevice_WRR; + ELSE + wob := tdevice_WRR / 100; + END IF; + IF rising_edge(WSTART) AND WDONE = '1' THEN + WDONE <= '0', '1' AFTER wob; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + WDONE <= '1'; -- reset done, programing terminated + ELSIF rising_edge(Reseted) THEN + WDONE <= '1'; -- reset done, programing terminated + END IF; + + END PROCESS WriteTime; + + --------------------------------------------------------------------------- + -- Timing control for the Bulk Erase + --------------------------------------------------------------------------- + ErsTime : PROCESS(ESTART, ESUSP, ERES, RST, Reseted) + VARIABLE seo : time; + VARIABLE beo : time; + VARIABLE elapsed : time; + VARIABLE start : time; + VARIABLE duration : time; + BEGIN + IF LongTimming THEN + seo := tdevice_SE; + beo := tdevice_BE; + ELSE + seo := tdevice_SE / 1000; + beo := tdevice_BE / 1000; + END IF; + IF rising_edge(ESTART) AND EDONE = '1' THEN + IF Instruct = BE THEN + duration := beo; + ELSE --Instruct = SE OR SE4 + duration := seo; + END IF; + elapsed := 0 ns; + EDONE <= '0', '1' AFTER duration; + start := NOW; + ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN + elapsed := NOW - start; + duration := duration - elapsed; + EDONE <= '0'; + ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN + start := NOW; + EDONE <= '0', '1' AFTER duration; + END IF; + + IF (RST'EVENT AND RST = '0') THEN + EDONE <= '1'; -- reset done, eras terminated + ELSIF rising_edge(Reseted) THEN + EDONE <= '1'; -- reset done, erase terminated + END IF; + + END PROCESS ErsTime; + + CheckCEOnPowerUP :PROCESS(CSNeg_ipd) + BEGIN + IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN + REPORT InstancePath & partID & + ": Device is selected during Power Up" + SEVERITY WARNING; + END IF; + END PROCESS; + + --------------------------------------------------------------------------- + -- Main Behavior Process + -- combinational process for next state generation + --------------------------------------------------------------------------- + StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, RSTNeg_pullup, WDONE, PDONE, + ERSSUSP_out, PRGSUSP_out, EDONE, RST_out, PPBERASE_in, + PASSULCK_in) + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + + BEGIN + + IF rising_edge(PoweredUp) THEN + IF ABE = '1' AND RPME /= '0' THEN + --Autoboot is enabled and The Read Password feature is not enabled + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)&"000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + ELSE + IF RST_out= '0' then + next_state <= current_state; + ELSIF falling_edge(write) AND Instruct = RESET THEN + IF ABE = '1' AND RPME /= '0' THEN + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay:= to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + next_state <= AUTOBOOT; + ELSE + next_state <= IDLE; + END IF; + ELSE + CASE current_state IS + WHEN RESET_STATE => + IF rising_edge(RST_out) THEN + IF ABE = '1' AND RPME /= '0' + AND RdPswdProtMode = '0' THEN + next_state <= AUTOBOOT; + read_cnt := 0; + byte_cnt := 1; + read_addr := to_nat(AutoBoot_reg(31 DOWNTO 9)& + "000000000"); + start_delay := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ABSD := to_nat(AutoBoot_reg(8 DOWNTO 1)); + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN IDLE => + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + IF (Instruct = WRR AND WEL = '1' AND BAR_ACC = '0') THEN + IF ((not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD = '0') OR QUAD = '1') THEN + -- can not execute if HPM is entered + -- or if WEL bit is zero + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + ASSERT cfg_write = '0' + REPORT "Changing value of Configuration " & + "Register OTP bit from 1 to 0 is " & + "not allowed!!!" + SEVERITY WARNING; + ELSE + next_state <= WRITE_SR; + END IF; + END IF; + ELSIF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + next_state <= PAGE_PG; + IF (Instruct = QPP OR Instruct = QPP4) AND + QPP_page(pgm_page) = '1' THEN + REPORT "WARNING:The same page must not be" & + " programmed more than once!!!" + SEVERITY WARNING; + END IF; + END IF; + ELSIF Instruct=OTPP AND WEL = '1' AND FREEZE = '0' THEN + IF ((((Address >= 16#10# AND Address <= 16#13#) OR + (Address >= 16#20# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + next_state <= OTP_PG; + END IF; + ELSIF (Instruct= SE OR Instruct= SE4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + IF Sec_Prot(sect) = '0' AND PPB_bits(sect)='1' + AND DYB_bits(sect)='1' THEN + next_state <= SECTOR_ERS; + END IF; + ELSIF (Instruct=P4E OR Instruct=P4E4) AND WEL='1' THEN + --A P4E instruction applied to a sector that + --is larger than 4 KB will not be executed + --and will not set the E_ERR status. + REPORT "Warning! Parameter 4KB-sector Erase "& + "Instruction is not allowed for "& + "512Mbit memory size!!! "& + "Instruction is ignored!!!" + SEVERITY warning; + ELSIF Instruct = BE AND WEL = '1' AND + (BP0='0' AND BP1='0' AND BP2='0') THEN + next_state <= BULK_ERS; + ELSIF Instruct = ABWR AND WEL = '1' THEN + --Autoboot Register Write Command + next_state <= AUTOBOOT_PG; + ELSIF Instruct = ASPP AND WEL = '1' THEN + --ASP Register Program Command + IF not(ASPOTPFLAG) THEN + next_state <= ASP_PG; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + next_state <= PLB_PG; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + next_state <= PASS_PG; + END IF; + ELSIF Instruct = PASSU AND WEL= '1' AND WIP= '0' THEN + next_state <= PASS_UNLOCK; + ELSIF Instruct = PPBP AND WEL = '1' THEN + next_state <= PPB_PG; + ELSIF (Instruct=PPBERS AND WEL='1' AND PPBOTP='1') THEN + next_state <= PPB_ERS; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + next_state <= DYB_PG; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + next_state <= NVDLR_PG; + ELSE + next_state <= IDLE; + END IF; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '1' AND + WIP = '0' THEN + IF Instruct = PASSU THEN + next_state <= PASS_UNLOCK; + END IF; + END IF; + + WHEN AUTOBOOT => + IF rising_edge(CSNeg_ipd) THEN + next_state <= IDLE; + END IF; + + WHEN WRITE_SR => + IF rising_edge(WDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PAGE_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = PGRS THEN + next_state <= PAGE_PG; + ELSE + next_state <= PG_SUSP; + END IF; + ELSE + next_state <= PG_SUSP; + END IF; + + WHEN OTP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN BULK_ERS => + IF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN SECTOR_ERS => + IF ERSSUSP_out'EVENT AND ERSSUSP_out = '1' THEN + next_state <= ERS_SUSP; + ELSIF rising_edge(EDONE) THEN + next_state <= IDLE; + END IF; + + WHEN ERS_SUSP => + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = QPP OR + Instruct = PP4 OR Instruct = QPP4) AND + WEL = '1' THEN + IF SectorSuspend /= (Address/(SecSize+1)) THEN + pgm_page := Address / PageSize; + IF PPB_bits(Address/SecSize)='1' AND + DYB_bits(Address/SecSize)='1' THEN + next_state <= ERS_SUSP_PG; + IF (Instruct = QPP OR Instruct = QPP4) AND + QPP_page(pgm_page) = '1' THEN + REPORT "WARNING:The same page must " & + "not be programmed more than once!!!" + SEVERITY WARNING; + END IF; + END IF; + END IF; + ELSIF (Instruct = DYBWR AND WEL = '1') THEN + next_state <= DYB_PG; + ELSIF Instruct = ERRS THEN + next_state <= SECTOR_ERS; + END IF; + ELSE + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG => + IF PRGSUSP_out'EVENT AND PRGSUSP_out = '1' THEN + next_state <= ERS_SUSP_PG_SUSP; + ELSIF rising_edge(PDONE) THEN + next_state <= ERS_SUSP; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + IF falling_edge(write) THEN + IF Instruct = PGRS THEN + next_state <= ERS_SUSP_PG; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + ELSE + next_state <= ERS_SUSP_PG_SUSP; + END IF; + + WHEN PASS_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PASS_UNLOCK => + IF falling_edge(PASSULCK_in) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PPB_ERS => + IF falling_edge(PPBERASE_in) THEN + next_state <= IDLE; + END IF; + + WHEN AUTOBOOT_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN PLB_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN DYB_PG => + IF rising_edge(PDONE) THEN + IF ES = '1' THEN + next_state <= ERS_SUSP; + ELSE + next_state <= IDLE; + END IF; + END IF; + + WHEN ASP_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + WHEN NVDLR_PG => + IF rising_edge(PDONE) THEN + next_state <= IDLE; + END IF; + + END CASE; + END IF; + END IF; + + END PROCESS StateGen; + + ReadEnable: PROCESS (read_out) + BEGIN + oe_z <= rising_edge(read_out) AND PoweredUp = '1'; + + IF read_out'EVENT AND read_out = '0' AND PoweredUp = '1' THEN + oe <= TRUE, FALSE AFTER 1 ns; + END IF; + END PROCESS ReadEnable; + + --------------------------------------------------------------------------- + --FSM Output generation and general funcionality + --------------------------------------------------------------------------- + Functional : PROCESS(write,current_state,start_autoboot,CSNeg_ipd, + HOLDNeg_pullup, Instruct, Address, WByte,change_addr, + PoweredUp, WPNeg_pullup, WDONE, PDONE, EDONE, + PRGSUSP_out,ERSSUSP_out, PASSACC_out, oe, oe_z) + + VARIABLE WData : WByteType:= (OTHERS => MaxData); + + VARIABLE AddrLo : NATURAL; + VARIABLE AddrHi : NATURAL; + VARIABLE Addr : NATURAL; + VARIABLE Addr_tmp : NATURAL; + + VARIABLE data_out : std_logic_vector(7 downto 0); + VARIABLE ident_out : std_logic_vector(647 downto 0); + + VARIABLE ExtendedID : NATURAL; + + VARIABLE old_bit : std_logic_vector(7 downto 0); + VARIABLE new_bit : std_logic_vector(7 downto 0); + VARIABLE old_int : INTEGER RANGE -1 to MaxData; + VARIABLE new_int : INTEGER RANGE -1 to MaxData; + VARIABLE old_pass : std_logic_vector(63 downto 0); + VARIABLE new_pass : std_logic_vector(63 downto 0); + VARIABLE wr_cnt : NATURAL RANGE 0 TO 511; + --Data Learning Pattern Enable + VARIABLE dlp_act : BOOLEAN := FALSE; + + VARIABLE sect : NATURAL RANGE 0 TO SecNum; + VARIABLE cnt : NATURAL RANGE 0 TO 512 := 0; + + BEGIN + + ----------------------------------------------------------------------- + -- Functionality Section + ----------------------------------------------------------------------- + + IF Instruct'EVENT THEN + read_cnt := 0; + byte_cnt := 1; + fast_rd <= true; + dual <= false; + rd <= false; + any_read <= false; + END IF; + + IF PASSACC_out'EVENT AND PASSACC_out = '1' THEN + WIP := '0'; + PASSACC_in <= '0'; + END IF; + + IF rising_edge(PoweredUp) THEN + --the default condition after power-up + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + --The Configuration Register FREEZE bit is cleared. + FREEZE := '0'; + --The WEL bit is cleared. + WEL := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status Register are + --volatile and will be reset binary 111 after power-on reset + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --As shipped from the factory, all devices default ASP to the + --Persistent Protection mode, with all sectors unprotected, + --when power is applied. The device programmer or host system must + --then choose which sector protection method to use. + --For Persistent Protection mode, PPBLOCK defaults to "1" + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + DYB_bits := (OTHERS => '1'); + END IF; + + IF falling_edge(write) AND Instruct = RESET THEN + --The Configuration Register is set for Address mode + Bank_Addr_reg := (others => '0'); + --P_ERR bit is cleared + P_ERR := '0'; + --E_ERR bit is cleared + E_ERR := '0'; + --The WEL bit is cleared. + WEL := '0'; + --The WIP bit is cleared. + WIP := '0'; + --The ES bit is cleared. + ES := '0'; + --The PS bit is cleared. + PS := '0'; + + DummyBytes_act := '0'; + --When BPNV is set to '1'. the BP2-0 bits in Status + --Register are volatile and will be reseted after + --reset command + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + END IF; + + IF change_addr'EVENT THEN + read_addr := Address; + END IF; + + CASE current_state IS + WHEN IDLE => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF falling_edge(write) AND RdPswdProtMode = '1' THEN + IF Instruct = PASSU THEN + IF WIP = '0' THEN + PASSULCK_in <= '1'; + ELSE + REPORT "The PASSU command cannot be accepted"& + " any faster than once every 100us" + SEVERITY WARNING; + END IF; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + END IF; + IF falling_edge(write) AND RdPswdProtMode = '0' THEN + read_cnt := 0; + byte_cnt := 1; + IF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = WRDI THEN + WEL := '0'; + ELSIF Instruct = WRR AND WEL = '1' AND BAR_ACC = '0' THEN + IF (not(SRWD = '1' AND WPNeg_pullup = '0') AND + QUAD ='0') OR QUAD ='1' THEN + -- can not execute if Hardware Protection Mode + -- is entered or if WEL bit is zero + + IF ((TBPROT='1' AND Config_reg1_in(5)='0') OR + (BPNV ='1' AND Config_reg1_in(3)='0')) AND + cfg_write = '1' THEN + P_ERR := '1'; + ELSE + WSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + END IF; + ELSE + WEL := '0'; + END IF; + ELSIF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF (Sec_Prot(sect)= '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + P_ERR := '1'; + WEL := '0'; + END IF; + ELSIF Instruct = OTPP AND WEL = '1' THEN + -- As long as the FREEZE bit remains cleared to a logic '0' + --the OTP address space is programmable. + IF FREEZE = '0' THEN + IF ((((Address >= 16#0010# AND Address <= 16#13#)OR + (Address >= 16#0020# AND Address <= 16#FF#)) + AND LOCK_BYTE1(Address/32) = '1') OR + ((Address >= 16#100# AND Address <= 16#1FF#) + AND LOCK_BYTE2((Address-16#100#)/32) = '1') OR + ((Address >= 16#200# AND Address <= 16#2FF#) + AND LOCK_BYTE3((Address-16#200#)/32) = '1') OR + ((Address >= 16#300# AND Address <= 16#3FF#) + AND LOCK_BYTE4((Address-16#300#)/32) = '1')) AND + (Address + Byte_number <= OTPHiAddr) THEN + PSTART <= '1', '0' AFTER 1 ns; + WIP := '1'; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSIF (Address < 16#0010# OR (Address > 16#0013# AND + Address < 16#0020#) OR Address > 16#3FF# ) THEN + P_ERR := '1'; + WEL := '0'; + IF Address < 16#0020# THEN + ASSERT false + REPORT "Given address is in" & + "reserved address range" + SEVERITY warning; + ELSIF Address > 16#3FF# THEN + ASSERT false + REPORT "Given address is out of" & + "OTP address range" + SEVERITY warning; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = SE OR Instruct = SE4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + SectorSuspend <= sect; + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + Addr := Address; + ELSE + E_ERR := '1'; + WEL := '0'; + END IF; + ELSIF (Instruct = P4E OR Instruct = P4E4) AND WEL = '1' THEN + WEL := '0'; + ELSIF Instruct = BE AND WEL = '1' THEN + IF (BP0='0' AND BP1='0' AND BP2='0') THEN + ESTART <= '1', '0' AFTER 5 ns; + ESUSP <= '0'; + ERES <= '0'; + INITIAL_CONFIG <= '1'; + WIP := '1'; + ELSE + --The Bulk Erase command will not set E_ERR if a + --protected sector is found during the command + --execution. + WEL := '0'; + END IF; + ELSIF Instruct = PASSP AND WEL = '1' THEN + IF not(PWDMLB='0' AND PSTMLB='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + REPORT "Password programming is not allowed" & + " in Password Protection Mode." + SEVERITY warning; + END IF; + ELSIF Instruct = PASSU AND WEL= '1' AND WIP= '0' THEN + PASSULCK_in <= '1'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + IF (P_ERR = '0' AND E_ERR = '0') THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = ASPP AND WEL = '1' THEN + IF not(ASPOTPFLAG) THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSE + WEL := '0'; + P_ERR := '1'; + REPORT "Once the Protection Mode is selected," & + "no further changes to the ASP register" & + "is allowed." + SEVERITY warning; + END IF; + ELSIF Instruct = ABWR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBP AND WEL = '1' THEN + sect := Address/(SecSize+1); + Addr := Address; + pgm_page := Address/PageSize; + + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PPBERS AND WEL = '1' THEN + IF PPBOTP = '1' THEN + PPBERASE_in <= '1'; + WIP := '1'; + ELSE + E_ERR := '1'; + END IF; + ELSIF Instruct = PLBWR AND WEL = '1' AND + RdPswdProtEnable = '0' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + sect := Address/(SecSize+1); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = PNVDLR AND WEL = '1' THEN + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = WVDLR AND WEL = '1' THEN + VDLR_reg := VDLR_reg_in; + WEL := '0'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 OR + Instruct = RES OR Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES OR + DummyBytes_act='1') AND VDLR_reg/="00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRFR OR Instruct = DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + dlp_act := FALSE; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + + IF Mem(read_addr) /= -1 THEN + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + ELSE + SOut_zd <= 'U'; + END IF; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct = DDRDIOR OR Instruct = DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF ((Instruct = DDRQIOR OR Instruct = DDRQIOR4) AND + QUAD = '1') THEN + IF EHP THEN + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + read_addr_tmp := read_addr; + SecAddr := ReturnSectorID(read_addr); + Sec_addr := read_addr - SecAddr*(SecSize+1); + SecAddr := ReturnSectorIDRdPswdMd(TBPROT); + read_addr := Sec_addr + SecAddr*(SecSize+1); + IF RdPswdProtMode = '0' THEN + read_addr := read_addr_tmp; + END IF; + + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct = OTPR THEN + IF (read_addr>=OTPLoAddr) AND + (read_addr<=OTPHiAddr) AND RdPswdProtMode = '0' THEN + --Read OTP Memory array + fast_rd <= true; + rd <= false; + data_out := to_slv(OTPMem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSIF (read_addr > OTPHiAddr) + OR RdPswdProtMode = '1' THEN + --OTP Read operation will not wrap to the + --starting address after the OTP address is at + --its maximum or Read Password Protection Mode + --is selected; instead, the data beyond the + --maximum OTP address will be undefined. + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF Instruct = REMS THEN + --Read Manufacturer and Device ID + IF read_addr MOD 2 = 0 THEN + data_out := to_slv(Manuf_ID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + data_out := to_slv(DeviceID,8); + SOut_zd <= data_out(7 - read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := 0; + END IF; + END IF; + ELSIF Instruct = RDID THEN + ident_out := CFI_array_tmp; + IF read_cnt < 648 THEN + SOut_zd <= ident_out(647-read_cnt); + read_cnt := read_cnt + 1; + ELSE + --Continued shifting of output beyond the end of + --the defined ID-CFI address space will provide + --undefined data. + SOut_zd <= 'U'; + END IF; + ELSIF Instruct = RES THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + data_out := to_slv(ESignature,8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DLPRD THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + SOut_zd <= VDLR_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ABRD THEN + --Read AutoBoot register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= AutoBoot_reg(31-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 32 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = ASPRD THEN + --Read ASP Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= ASP_reg(15-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 16 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PASSRD THEN + --Read Password Register + IF not (PWDMLB='0' AND PSTMLB='1') THEN + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Password_reg((8*byte_cnt-1)-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + byte_cnt := byte_cnt + 1; + IF byte_cnt = 9 THEN + byte_cnt := 1; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 64 THEN + read_cnt := 0; + END IF; + IF read_cnt = 0 THEN + ASSERT false + REPORT "Verification of password is not " & + " allowed in Password Protection Mode." + SEVERITY warning; + END IF; + END IF; + ELSIF Instruct = PLBRD THEN + --Read PPB Lock Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= PPBL(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + DYBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + + WHEN AUTOBOOT => + IF start_autoboot = '1' THEN + IF (oe) THEN + any_read <= true; + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + read_addr := read_addr + 1; + END IF; + END IF; + ELSIF oe_z THEN + IF QUAD = '1' THEN + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= false; --max SCK frequency is 104MHz + rd <= false; + dual <= true; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + ELSE + IF ABSD > 0 THEN --If ABSD > 0, + fast_rd <= true; --max SCK frequency is 133MHz + rd <= false; + dual <= false; + ddr <= false; + ELSE -- If ABSD = 0, max SCK frequency is 50 MHz + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + END IF; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + END IF; + + WHEN WRITE_SR => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF WDONE = '1' THEN + WIP := '0'; + WEL := '0'; + SRWD := Status_reg1_in(7);--MSB first + + IF LOCK='0' THEN + IF FREEZE='0' THEN + --The Freeze Bit, when set to 1, locks the current + --state of the BP2-0 bits in Status Register and + --the TBPROT bit in the Config Register + --As long as the FREEZE bit remains cleared to logic + --'0', the other bits of the Configuration register + --including FREEZE are writeable. + BP2 := Status_reg1_in(4); + BP1 := Status_reg1_in(3); + BP0 := Status_reg1_in(2); + + BP_bits := BP2 & BP1 & BP0; + + IF TBPROT = '0' AND INITIAL_CONFIG = '0' THEN + TBPROT := Config_reg1_in(5); + END IF; + + change_BP <= '1', '0' AFTER 1 ns; + + LC1 := Config_reg1_in(7); + LC0 := Config_reg1_in(6); + QUAD := Config_reg1_in(1); + + IF FREEZE = '0' THEN + FREEZE := Config_reg1_in(0); + END IF; + + IF WRLOCKENABLE AND LOCK = '0' THEN + LOCK := Config_reg1_in(4); + WRLOCKENABLE <= false; + END IF; + + IF BPNV = '0' THEN + BPNV := Config_reg1_in(3); + END IF; + END IF; + END IF; + END IF; + + WHEN PAGE_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(PDONE) THEN + IF (Instruct = QPP OR Instruct = QPP4) THEN + QPP_page(pgm_page) := '1'; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + Mem(Addr + i - cnt) := -1; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + IF RES_TO_SUSP_MIN_TIME = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + ELSE + ASSERT FALSE + REPORT "Minimum for tPRS is not satisfied! " & + "PGSP command is ignored" + SEVERITY warning; + END IF; + END IF; + + WHEN PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF pgm_page /= read_addr/PageSize THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF pgm_page /= read_addr/PageSize THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF pgm_page /= read_addr/PageSize THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF falling_edge(write) THEN + IF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF PRGSUSP_out = '1' AND PRGSUSP_in = '1' THEN + PRGSUSP_in <= '0'; + --The RDY/BSY bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + --The Program Suspend (PS) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --program operation has been suspended. + PS := '1'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1) AND + pgm_page /= read_addr/PageSize) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1) AND + pgm_page /= read_addr/PageSize) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF (SectorSuspend /= read_addr/(SecSize+1) AND + pgm_page /= read_addr/PageSize) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + ELSIF falling_edge(write) THEN + IF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = PGRS THEN + PGRES <= '1', '0' AFTER 5 ns; + PS := '0'; + WIP := '1'; + RES_TO_SUSP_MIN_TIME <= '1', '0' AFTER 60 ns; + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN OTP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF Address + wr_cnt <= OTPHiAddr THEN + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := OTPMem(Addr + i); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + OTPMem(Addr + i) := -1; + END LOOP; + ELSE + ASSERT false + REPORT "Programming will reach over address limit"& + " of OTP array" + SEVERITY warning; + END IF; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + OTPMem(Addr_tmp + i) := WData(i); + END LOOP; + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + END IF; + + WHEN SECTOR_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := -1; + END LOOP; + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN AddrLo TO AddrHi LOOP + Mem(i) := MaxData; + END LOOP; + ELSIF Instruct = ERSP AND ERSSUSP_in = '0' THEN + ESUSP <= '1', '0' AFTER 10 ns; + ERSSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + END IF; + + WHEN BULK_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(EDONE) THEN + FOR i IN 0 TO AddrRANGE LOOP + sect := i/(SecSize+1); + IF PPB_bits(sect) = '1' AND DYB_bits(sect) = '1' THEN + Mem(i) := -1; + END IF; + END LOOP; + END IF; + + IF EDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO AddrRANGE LOOP + sect := i/(SecSize+1); + IF PPB_bits(sect) = '1' AND DYB_bits(sect) = '1' THEN + Mem(i) := MaxData; + END IF; + END LOOP; + END IF; + + WHEN ERS_SUSP => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF ERSSUSP_out = '1' THEN + ERSSUSP_in <= '0'; + --The Erase Suspend (ES) bit in the Status Register will + --be set to the logical “1” state to indicate that the + --erase operation has been suspended. + ES := '1'; + --The WIP bit in the Status Register will indicate that + --the device is ready for another operation. + WIP := '0'; + END IF; + + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = DYBRD THEN + --Read DYB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF DYB_bits(sect) = '1' THEN + DYBAR(7 downto 0) := "11111111"; + ELSE + DYBAR(7 downto 0) := "00000000"; + END IF; + SOut_zd <= DYBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = BRRD THEN + --Read Bank Address Register + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + SOut_zd <= Bank_Addr_reg(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = PPBRD THEN + --Read PPB Access Register + sect := Address/(SecSize+1); + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + PPBAR(7 downto 0) := "UUUUUUUU"; + IF RdPswdProtMode = '0' THEN + IF PPB_bits(sect) = '1' THEN + PPBAR(7 downto 0) := "11111111"; + ELSE + PPBAR(7 downto 0) := "00000000"; + END IF; + END IF; + SOut_zd <= PPBAR(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + --Read Array Operations + ELSIF Instruct = READ OR Instruct = RD4 OR + Instruct = FSTRD OR Instruct = FSTRD4 OR + Instruct = DDRFR OR Instruct = DDRFR4 THEN + --Read Memory array + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + IF SectorSuspend /= read_addr/(SecSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRFR OR Instruct=DDRFR4) THEN + IF EHP THEN + IF Latency_code = 1 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3 OR + Latency_code = 0) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:= VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + read_cnt:=read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) is + -- enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + --Read Memory array + IF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF SectorSuspend /= read_addr/(SecSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF (Instruct=DDRDIOR OR Instruct=DDRDIOR4) THEN + IF EHP THEN + IF Latency_code = 0 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 1) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency"& + " is set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out:=VDLR_reg; + SOut_zd <=data_out(7-read_cnt); + SIOut_zd<=data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF Latency_code = 3 THEN + dlp_act := TRUE; + ELSIF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + END IF; + -- Data Learning Pattern (DLP) + -- is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND + dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + SOut_zd <= data_out(7-2*read_cnt); + SIOut_zd <= data_out(6-2*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 4 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSIF (Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 OR + Instruct = DDRQIOR OR Instruct= DDRQIOR4) + AND QUAD = '1' THEN + --Read Memory array + IF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + END IF; + IF SectorSuspend /= read_addr/(SecSize+1) THEN + IF ((bus_cycle_state = DUMMY_BYTES + OR DummyBytes_act = '1') + AND VDLR_reg /= "00000000") THEN + DummyBytes_act := '0'; + IF EHP THEN + IF (Latency_code=0 + AND dummy_cnt_act>=2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSE + IF (Latency_code = 0 AND + dummy_cnt_act >= 2) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 1 AND + dummy_cnt_act >= 3) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 2 AND + dummy_cnt_act >= 4) THEN + dlp_act := TRUE; + ELSIF (Latency_code = 3) THEN + dlp_act := FALSE; + REPORT "Inappropriate latency is"& + " set during DPL mode" + SEVERITY WARNING; + END IF; + -- Data Learning Pattern (DLP) is enabled + -- Optional DLP + IF (VDLR_reg/="00000000" AND dlp_act) THEN + dlp_act := FALSE; + data_out := VDLR_reg; + HOLDNegOut_zd <= data_out(7-read_cnt); + WPNegOut_zd <= data_out(7-read_cnt); + SOut_zd <= data_out(7-read_cnt); + SIOut_zd <= data_out(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + END IF; + ELSE + data_out := to_slv(Mem(read_addr),8); + HOLDNegOut_zd <= data_out(7-4*read_cnt); + WPNegOut_zd <= data_out(6-4*read_cnt); + SOut_zd <= data_out(5-4*read_cnt); + SIOut_zd <= data_out(4-4*read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + END IF; + ELSE + HOLDNegOut_zd <= 'U'; + WPNegOut_zd <= 'U'; + SOut_zd <= 'U'; + SIOut_zd <= 'U'; + read_cnt := read_cnt + 1; + IF read_cnt = 2 THEN + read_cnt := 0; + IF read_addr = AddrRANGE THEN + read_addr := 0; + ELSE + read_addr := read_addr + 1; + END IF; + END IF; + + END IF; + END IF; + ELSIF oe_z THEN + IF Instruct = READ OR Instruct = RD4 THEN + fast_rd <= false; + rd <= true; + dual <= false; + ddr <= false; + ELSIF Instruct = DDRFR OR Instruct = DDRFR4 THEN + fast_rd <= false; + rd <= false; + dual <= false; + ddr <= true; + ELSIF Instruct = DDRDIOR OR Instruct = DDRDIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSIF Instruct =DOR OR Instruct=DOR4 OR + Instruct = DIOR OR Instruct = DIOR4 OR + Instruct = QOR OR Instruct=QOR4 OR + Instruct = QIOR OR Instruct= QIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= false; + ELSIF Instruct = DDRQIOR OR Instruct = DDRQIOR4 THEN + fast_rd <= false; + rd <= false; + dual <= true; + ddr <= true; + ELSE + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + END IF; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF falling_edge(write) THEN + IF (Instruct = PP OR Instruct = PP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF SectorSuspend /= sect THEN + IF (Sec_Prot(sect) = '0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF (Instruct = QPP OR Instruct = QPP4) AND WEL = '1' THEN + sect := Address/(SecSize+1); + pgm_page := Address/PageSize; + IF SectorSuspend /= sect THEN + IF (Sec_Prot(sect)='0' AND + PPB_bits(sect)='1' AND DYB_bits(sect)='1') THEN + PSTART <= '1', '0' AFTER 5 ns; + PGSUSP <= '0'; + PGRES <= '0'; + WIP := '1' ; + SA <= sect; + Addr := Address; + Addr_tmp := Address; + wr_cnt := Byte_number; + FOR I IN wr_cnt DOWNTO 0 LOOP + IF Viol /= '0' THEN + WData(i) := -1; + ELSE + WData(i) := WByte(i); + END IF; + END LOOP; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSE + WEL := '0'; + P_ERR := '1'; + END IF; + ELSIF Instruct = WREN THEN + WEL := '1'; + ELSIF Instruct = CLSR THEN + --The Clear Status Register Command resets bit SR1[5] + --(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + E_ERR := '0'; + P_ERR := '0'; + ELSIF Instruct = BRWR THEN + Bank_Addr_reg(7) := Bank_Addr_reg_in(7); + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + ELSIF Instruct = WRR AND BAR_ACC = '1' THEN + -- Write to the lower address bits of the BAR + IF (P_ERR = '0' AND E_ERR = '0')THEN + Bank_Addr_reg(1) := Bank_Addr_reg_in(1); + Bank_Addr_reg(0) := Bank_Addr_reg_in(0); + END IF; + ELSIF Instruct = DYBWR AND WEL = '1' THEN + sect := Address/(SecSize+1); + PSTART <= '1', '0' AFTER 5 ns; + WIP := '1'; + ELSIF Instruct = ERRS THEN + ERES <= '1', '0' AFTER 5 ns; + ES := '0'; + WIP := '1'; + Addr := SectorSuspend*(SecSize+1); + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + RES_TO_SUSP_TYP_TIME <= '1', '0' AFTER 100 us; + END IF; + + IF Instruct = BRAC AND P_ERR = '0' AND E_ERR = '0' AND + RdPswdProtMode = '0' THEN + BAR_ACC <= '1'; + ELSE + BAR_ACC <= '0'; + END IF; + END IF; + + WHEN ERS_SUSP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF (Instruct = QPP OR Instruct = QPP4) THEN + QPP_page(pgm_page) := '1'; + END IF; + + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt := 0; + + FOR i IN 0 TO wr_cnt LOOP + new_int := WData(i); + old_int := Mem(Addr + i - cnt); + IF new_int > -1 THEN + new_bit := to_slv(new_int,8); + IF old_int > -1 THEN + old_bit := to_slv(old_int,8); + FOR j IN 0 TO 7 LOOP + IF old_bit(j) = '0' THEN + new_bit(j) := '0'; + END IF; + END LOOP; + new_int := to_nat(new_bit); + END IF; + WData(i) := new_int; + ELSE + WData(i) := -1; + END IF; + + IF (Addr + i) = AddrHi THEN + Addr := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + cnt :=0; + + IF PDONE = '1' THEN + WIP := '0'; + WEL := '0'; + FOR i IN 0 TO wr_cnt LOOP + Mem(Addr_tmp + i - cnt) := WData(i); + IF (Addr_tmp + i) = AddrHi THEN + Addr_tmp := AddrLo; + cnt := i + 1; + END IF; + END LOOP; + ELSIF Instruct = PGSP AND PRGSUSP_in = '0' THEN + IF RES_TO_SUSP_MIN_TIME = '0' THEN + PGSUSP <= '1', '0' AFTER 1 ns; + PRGSUSP_in <= '1'; + ASSERT RES_TO_SUSP_TYP_TIME = '0' + REPORT "Typical periods are needed for " & + "Program to progress to completion" + SEVERITY warning; + ELSE + ASSERT FALSE + REPORT "Minimum for tPRS is not satisfied! " & + "PGSP command is ignored" + SEVERITY warning; + END IF; + END IF; + + WHEN PASS_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + new_pass := Password_reg_in; + old_pass := Password_reg; + FOR j IN 0 TO 63 LOOP + IF old_pass(j) = '0' THEN + new_pass(j) := '0'; + END IF; + END LOOP; + + IF PDONE = '1' THEN + Password_reg := new_pass; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PASS_UNLOCK => + WIP := '1'; + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PASS_TEMP = Password_reg THEN + PASS_UNLOCKED <= TRUE; + ELSE + PASS_UNLOCKED <= FALSE; + END IF; + + IF PASSULCK_out = '1' THEN + IF PASS_UNLOCKED AND PWDMLB = '0' THEN + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + WIP := '0'; + ELSE + P_ERR := '1'; + REPORT "Incorrect Password!" + SEVERITY warning; + PASSACC_in <= '1'; + END IF; + WEL := '0'; + PASSULCK_in <= '0'; + END IF; + + WHEN PPB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF PPB_LOCK /= '0' THEN + PPB_bits(sect):= '0'; + WIP := '0'; + WEL := '0'; + ELSE + P_ERR := '0'; + WIP := '0'; + WEL := '0'; + END IF; + END IF; + + WHEN PPB_ERS => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PPBERASE_out = '1' THEN + IF PPB_LOCK /= '0' AND PPBOTP = '1' THEN + PPB_bits:= (OTHERS => '1'); + ELSE + E_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + PPBERASE_in <= '0'; + END IF; + + WHEN AUTOBOOT_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + AutoBoot_reg := AutoBoot_reg_in; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN PLB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN DYB_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + DYBAR := DYBAR_in; + IF DYBAR = "11111111" THEN + DYB_bits(sect):= '1'; + ELSIF DYBAR = "00000000" THEN + DYB_bits(sect):= '0'; + ELSE + P_ERR := '1'; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN ASP_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + + IF (RPME = '0' AND ASP_reg_in(5) = '1') THEN + P_ERR := '1'; + REPORT "RPME bit is allready programmed" + SEVERITY warning; + ELSE + RPME := ASP_reg_in(5); + END IF; + + IF (PPBOTP = '0' AND ASP_reg_in(3) ='1') THEN + P_ERR := '1'; + REPORT "PPBOTP bit is allready programmed" + SEVERITY warning; + ELSE + PPBOTP := ASP_reg_in(3); + END IF; + + IF (PWDMLB = '1' AND PSTMLB = '1') THEN + IF (ASP_reg_in(2) = '0' AND ASP_reg_in(1) = '0') THEN + REPORT "ASPR[2:1] = 00 Illegal condition" + SEVERITY warning; + P_ERR := '1'; + ELSE + IF (ASP_reg_in(2) /= '1' OR + ASP_reg_in(1) /= '1') THEN + ASPOTPFLAG <= TRUE; + END IF; + PWDMLB := ASP_reg_in(2); + PSTMLB := ASP_reg_in(1); + END IF; + END IF; + WIP := '0'; + WEL := '0'; + END IF; + + WHEN NVDLR_PG => + fast_rd <= true; + rd <= false; + dual <= false; + ddr <= false; + IF oe THEN + any_read <= true; + IF Instruct = RDSR THEN + --Read Status Register 1 + SOut_zd <= Status_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDSR2 THEN + --Read Status Register 2 + SOut_zd <= Status_reg2(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + ELSIF Instruct = RDCR THEN + --Read Configuration Register 1 + SOut_zd <= Config_reg1(7-read_cnt); + read_cnt := read_cnt + 1; + IF read_cnt = 8 THEN + read_cnt := 0; + END IF; + END IF; + ELSIF oe_z THEN + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + SIOut_zd <= 'Z'; + END IF; + + IF PDONE = '1' THEN + IF NVDLR_reg = "00000000" THEN + NVDLR_reg :=NVDLR_reg_in; + VDLR_reg := NVDLR_reg_in; + WIP := '0'; + WEL := '0'; + ELSE + WIP := '0'; + WEL := '0'; + P_ERR := '1'; + REPORT "NVDLR is allready programmed" + SEVERITY warning; + END IF; + END IF; + + WHEN RESET_STATE => + --the default condition hardware reset + --The Bank Address Register is loaded to all zeroes + Bank_Addr_reg := (others => '0'); + IF BPNV = '1' AND LOCK='0' AND FREEZE = '0' THEN + BP0 := '1'; + BP1 := '1'; + BP2 := '1'; + BP_bits := BP2 & BP1 & BP0; + change_BP <= '1', '0' AFTER 1 ns; + END IF; + --Resets the Status register 1 + P_ERR := '0'; + E_ERR := '0'; + WEL := '0'; + WIP := '0'; + --Resets the Status register 2 + ES := '0'; + PS := '0'; + --Resets the Configuration register 1 + FREEZE := '0'; + --On reset cycles the data pattern reverts back + --to what is in the NVDLR + VDLR_reg := NVDLR_reg; + dlp_act := FALSE; + --Loads the Program Buffer with all ones + WData := (OTHERS => MaxData); + + IF PWDMLB = '0' THEN + PPB_LOCK := '0'; + PPB_LOCK_temp <= '0'; + ELSE + PPB_LOCK := '1'; + PPB_LOCK_temp <= '1'; + END IF; + + END CASE; + + --Output Disable Control + IF (CSNeg_ipd = '1') THEN + SIOut_zd <= 'Z'; + HOLDNegOut_zd <= 'Z'; + WPNegOut_zd <= 'Z'; + SOut_zd <= 'Z'; + END IF; + + END PROCESS Functional; + + --------------------------------------------------------------------------- + -- CFI Process + --------------------------------------------------------------------------- + CFIPreload: PROCESS + + BEGIN + ------------------------------------------------------------------------ + --CFI array data + ------------------------------------------------------------------------ + -- Manufacturer and Device ID + CFI_array(16#00#) := 16#01#; + CFI_array(16#01#) := 16#02#; + CFI_array(16#02#) := 16#20#; + CFI_array(16#03#) := 16#00#; + CFI_array(16#04#) := 16#00#;--Uniform 256KB sectors + CFI_array(16#05#) := 16#80#; + CFI_array(16#06#) := 16#00#; + CFI_array(16#07#) := 16#00#; + CFI_array(16#08#) := 16#00#; + CFI_array(16#09#) := 16#00#; + CFI_array(16#0A#) := 16#00#; + CFI_array(16#0B#) := 16#00#; + CFI_array(16#0C#) := 16#00#; + CFI_array(16#0D#) := 16#00#; + CFI_array(16#0E#) := 16#00#; + CFI_array(16#0F#) := 16#00#; + --CFI Query Identification String + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#53#; + CFI_array(16#18#) := 16#46#; + CFI_array(16#19#) := 16#51#; + CFI_array(16#1A#) := 16#00#; + --CFI system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#06#; + CFI_array(16#20#) := 16#09#;-- 512B page + CFI_array(16#21#) := 16#09#;-- 256KB + CFI_array(16#22#) := 16#11#; + CFI_array(16#23#) := 16#02#; + CFI_array(16#24#) := 16#02#; + CFI_array(16#25#) := 16#03#; + CFI_array(16#26#) := 16#03#; + -- Device Geometry Definition + CFI_array(16#27#) := 16#1A#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#01#; + CFI_array(16#2A#) := 16#09#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#FF#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#04#; + CFI_array(16#31#) := 16#FF#; + CFI_array(16#32#) := 16#FF#; + CFI_array(16#33#) := 16#FF#; + CFI_array(16#34#) := 16#FF#; + CFI_array(16#35#) := 16#FF#; + CFI_array(16#36#) := 16#FF#; + CFI_array(16#37#) := 16#FF#; + CFI_array(16#38#) := 16#FF#; + CFI_array(16#39#) := 16#FF#; + CFI_array(16#3A#) := 16#FF#; + CFI_array(16#3B#) := 16#FF#; + CFI_array(16#3C#) := 16#FF#; + CFI_array(16#3D#) := 16#FF#; + CFI_array(16#3E#) := 16#FF#; + CFI_array(16#3F#) := 16#FF#; + -- CFI Primary Vendor-Specific Extended Query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#21#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#00#; + CFI_array(16#49#) := 16#08#; + + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#01#; + CFI_array(16#4C#) := 16#04#; + CFI_array(16#4D#) := 16#00#; + CFI_array(16#4E#) := 16#00#; + CFI_array(16#4F#) := 16#07#; + CFI_array(16#50#) := 16#01#; + + CFI_array_tmp :=to_slv(CFI_array(16#00#), 8) & + to_slv(CFI_array(16#01#), 8) & + to_slv(CFI_array(16#02#), 8) & + to_slv(CFI_array(16#03#), 8) & + to_slv(CFI_array(16#04#), 8) & + to_slv(CFI_array(16#05#), 8) & + to_slv(CFI_array(16#06#), 8) & + to_slv(CFI_array(16#07#), 8) & + to_slv(CFI_array(16#08#), 8) & + to_slv(CFI_array(16#09#), 8) & + to_slv(CFI_array(16#0A#), 8) & + to_slv(CFI_array(16#0B#), 8) & + to_slv(CFI_array(16#0C#), 8) & + to_slv(CFI_array(16#0D#), 8) & + to_slv(CFI_array(16#0E#), 8) & + to_slv(CFI_array(16#0F#), 8) & + to_slv(CFI_array(16#10#), 8) & + to_slv(CFI_array(16#11#), 8) & + to_slv(CFI_array(16#12#), 8) & + to_slv(CFI_array(16#13#), 8) & + to_slv(CFI_array(16#14#), 8) & + to_slv(CFI_array(16#15#), 8) & + to_slv(CFI_array(16#16#), 8) & + to_slv(CFI_array(16#17#), 8) & + to_slv(CFI_array(16#18#), 8) & + to_slv(CFI_array(16#19#), 8) & + to_slv(CFI_array(16#1A#), 8) & + to_slv(CFI_array(16#1B#), 8) & + to_slv(CFI_array(16#1C#), 8) & + to_slv(CFI_array(16#1D#), 8) & + to_slv(CFI_array(16#1E#), 8) & + to_slv(CFI_array(16#1F#), 8) & + to_slv(CFI_array(16#20#), 8) & + to_slv(CFI_array(16#21#), 8) & + to_slv(CFI_array(16#22#), 8) & + to_slv(CFI_array(16#23#), 8) & + to_slv(CFI_array(16#24#), 8) & + to_slv(CFI_array(16#25#), 8) & + to_slv(CFI_array(16#26#), 8) & + to_slv(CFI_array(16#27#), 8) & + to_slv(CFI_array(16#28#), 8) & + to_slv(CFI_array(16#29#), 8) & + to_slv(CFI_array(16#2A#), 8) & + to_slv(CFI_array(16#2B#), 8) & + to_slv(CFI_array(16#2C#), 8) & + to_slv(CFI_array(16#2D#), 8) & + to_slv(CFI_array(16#2E#), 8) & + to_slv(CFI_array(16#2F#), 8) & + to_slv(CFI_array(16#30#), 8) & + to_slv(CFI_array(16#31#), 8) & + to_slv(CFI_array(16#32#), 8) & + to_slv(CFI_array(16#33#), 8) & + to_slv(CFI_array(16#34#), 8) & + to_slv(CFI_array(16#35#), 8) & + to_slv(CFI_array(16#36#), 8) & + to_slv(CFI_array(16#37#), 8) & + to_slv(CFI_array(16#38#), 8) & + to_slv(CFI_array(16#39#), 8) & + to_slv(CFI_array(16#3A#), 8) & + to_slv(CFI_array(16#3B#), 8) & + to_slv(CFI_array(16#3C#), 8) & + to_slv(CFI_array(16#3D#), 8) & + to_slv(CFI_array(16#3E#), 8) & + to_slv(CFI_array(16#3F#), 8) & + to_slv(CFI_array(16#40#), 8) & + to_slv(CFI_array(16#41#), 8) & + to_slv(CFI_array(16#42#), 8) & + to_slv(CFI_array(16#43#), 8) & + to_slv(CFI_array(16#44#), 8) & + to_slv(CFI_array(16#45#), 8) & + to_slv(CFI_array(16#46#), 8) & + to_slv(CFI_array(16#47#), 8) & + to_slv(CFI_array(16#48#), 8) & + to_slv(CFI_array(16#49#), 8) & + to_slv(CFI_array(16#4A#), 8) & + to_slv(CFI_array(16#4B#), 8) & + to_slv(CFI_array(16#4C#), 8) & + to_slv(CFI_array(16#4D#), 8) & + to_slv(CFI_array(16#4E#), 8) & + to_slv(CFI_array(16#4F#), 8) & + to_slv(CFI_array(16#50#), 8); + + WAIT; + + END PROCESS CFIPreload; + + AspRegInit: PROCESS(ASP_INIT) + BEGIN + IF ASP_INIT = 0 THEN + ASP_reg := to_slv(16#FE4F#,16); + ELSE + ASP_reg := to_slv(16#FE7F#,16); + END IF; + END PROCESS AspRegInit; + + Protect : PROCESS(change_BP) + BEGIN + IF rising_edge(change_BP) THEN + + CASE BP_bits IS + WHEN "000" => + Sec_Prot := (OTHERS => '0'); + WHEN "001" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*63/64) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*63/64 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/64 - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/64) + := (OTHERS => '0'); + END IF; + WHEN "010" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*31/32) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*31/32 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/32 - 1 downto 0) + := (others => '1'); + Sec_Prot(SecNum downto (SecNum+1)/32) + := (OTHERS => '0'); + END IF; + WHEN "011" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*15/16) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*15/16 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/16 - 1 downto 0) + := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/16) + := (OTHERS => '0'); + END IF; + WHEN "100" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*7/8) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*7/8 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/8 - 1 downto 0) := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/8):= (OTHERS => '0'); + END IF; + WHEN "101" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)*3/4) + := (OTHERS => '1'); + Sec_Prot((SecNum+1)*3/4 - 1 downto 0) + := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/4 - 1 downto 0) := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/4):= (OTHERS => '0'); + END IF; + + WHEN "110" => + IF TBPROT = '0' THEN + Sec_Prot(SecNum downto (SecNum+1)/2):= (OTHERS => '1'); + Sec_Prot((SecNum+1)/2 - 1 downto 0) := (OTHERS => '0'); + ELSE + Sec_Prot((SecNum+1)/2 - 1 downto 0) := (OTHERS => '1'); + Sec_Prot(SecNum downto (SecNum+1)/2):= (OTHERS => '0'); + END IF; + + WHEN OTHERS => + Sec_Prot := (OTHERS => '1'); + END CASE; + END IF; + END PROCESS Protect; + + HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNeg_pullup) + BEGIN + IF (HOLDNeg_pullup = '0' AND QUAD /= '1') THEN + hold_mode := TRUE; + SIOut_z <= 'Z'; + SOut_z <= 'Z'; + ELSE + IF hold_mode THEN + SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0); + SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0); + hold_mode := FALSE; + ELSE + SIOut_z <= SIOut_zd; + SOut_z <= SOut_zd; + hold_mode := FALSE; + END IF; + END IF; + END PROCESS HOLD_FRAME_ON_PO_ZD; + + HOLD_PULL_UP : PROCESS(HOLDNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (HOLDNegIn = 'Z') THEN + HOLDNeg_pullup <= '1'; + ELSE + HOLDNeg_pullup <= HOLDNegIn; + END IF; + END IF; + END PROCESS HOLD_PULL_UP; + + WP_PULL_UP : PROCESS(WPNegIn) + BEGIN + IF (QUAD = '0') THEN + IF (WPNegIn = 'Z') THEN + WPNeg_pullup <= '1'; + ELSE + WPNeg_pullup <= WPNegIn; + END IF; + END IF; + END PROCESS WP_PULL_UP; + + RST_PULL_UP : PROCESS(RSTNeg) + BEGIN + IF (RSTNeg = 'Z') THEN + RSTNeg_pullup <= '1'; + ELSE + RSTNeg_pullup <= RSTNeg; + END IF; + END PROCESS RST_PULL_UP; + + --------------------------------------------------------------------------- + ---- File Read Section - Preload Control + --------------------------------------------------------------------------- + MemPreload : PROCESS + + -- text file input variables + FILE mem_file : text is mem_file_name; + FILE otp_file : text is otp_file_name; + VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0; + VARIABLE otp_ind : NATURAL RANGE 16#000# TO 16#3FF# := 16#000#; + VARIABLE buf : line; + + BEGIN + --------------------------------------------------------------------------- + --s25fl512s memory preload file format +----------------------------------- + --------------------------------------------------------------------------- + -- / - comment + -- @aaaaaa - stands for address + -- dd -
is byte to be written at Mem(aaaaaa++) + -- (aaaaaa is incremented at every load) + -- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (mem_file_name /= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF ind > AddrRANGE THEN + ASSERT false + REPORT "Given preload address is out of" & + "memory address range" + SEVERITY warning; + ELSE + ind := h(buf(2 to 8)); --address + END IF; + ELSE + Mem(ind) := h(buf(1 to 2)); + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --------------------------------------------------------------------------- + --s25fl512s_otp memory preload file format + --------------------------------------------------------------------------- + -- / - comment + -- @aaa - stands for address + -- dd -
is byte to be written at OTPMem(aaa++) + -- (aaa is incremented at every load) + -- only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (otp_file_name /= "none" AND UserPreload) THEN + otp_ind := 16#000#; + OTPMem := (OTHERS => MaxData); + WHILE (not ENDFILE (otp_file)) LOOP + READLINE (otp_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + IF otp_ind > 16#3FF# OR otp_ind < 16#000# THEN + ASSERT false + REPORT "Given preload address is out of" & + "OTP address range" + SEVERITY warning; + ELSE + otp_ind := h(buf(2 to 4)); --address + END IF; + ELSE + OTPMem(otp_ind) := h(buf(1 to 2)); + otp_ind := otp_ind + 1; + END IF; + END LOOP; + END IF; + + LOCK_BYTE1 := to_slv(OTPMem(16#10#),8); + LOCK_BYTE2 := to_slv(OTPMem(16#11#),8); + LOCK_BYTE3 := to_slv(OTPMem(16#12#),8); + LOCK_BYTE4 := to_slv(OTPMem(16#13#),8); + + WAIT; + END PROCESS MemPreload; + + ---------------------------------------------------------------------------- + -- Path Delay Section + ---------------------------------------------------------------------------- + + S_Out_PathDelay_Gen : PROCESS(SOut_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SOut, + OutSignalName => "SO", + OutTemp => SOut_z, + Mode => VitalTransport, + GlitchData => SO_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => (ddr OR fast_rd)), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => QUAD = '0') + ) + ); + END PROCESS; + + SI_Out_PathDelay : PROCESS(SIOut_z) + + VARIABLE SI_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SIOut, + OutSignalName => "SI", + OutTemp => SIOut_z, + Mode => VitalTransport, + GlitchData => SI_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND NOT(ddr)), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => dual AND ddr), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 3 => (InputChangeTime => HOLDNegIn'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => dual AND QUAD = '0') + ) + ); + END PROCESS; + + HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd) + + VARIABLE HOLD_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => HOLDNegOut, + OutSignalName => "HOLDNeg", + OutTemp => HOLDNegOut_zd, + Mode => VitalTransport, + GlitchData => HOLD_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + HOLDNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + WP_Out_PathDelay : PROCESS(WPNegOut_zd) + + VARIABLE WP_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => WPNegOut, + OutSignalName => "WPNeg", + OutTemp => WPNegOut_zd, + Mode => VitalTransport, + GlitchData => WP_GlitchData, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_normal), + PathCondition => dual AND not(ddr) AND QUAD = '1'), + 1 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_DDR), + PathCondition => ddr AND QUAD = '1'), + 2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1' AND + WPNegOut_zd = 'Z' AND QUAD = '1') + ) + ); + END PROCESS; + + END BLOCK behavior; +END vhdl_behavioral_static_memory_allocation; \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_ver.ftm b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_ver.ftm new file mode 100644 index 0000000..fbc6513 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_ver.ftm @@ -0,0 +1,511 @@ + +FMF Timing for s25fl512s Parts + + +version: | author: | mod date: | changes made: + V1.0 R. Prokopovic 09 Nov 27 Initial release + V1.1 V.Mancev 10 Oct 20 Latest datasheet aligned + V1.2 B.Colakovic 11 July 11 Latest datasheet aligned + V1.3 V.Mancev 11 Nov 17 Time tHO is changed to 1 ns + +1ns +s25fl512s + +S25FL512SAGMFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for VIO=VCC=2.7V to 3.6V, CL=30pF + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL512SAGMFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL512SAGMFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (3)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (2)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (3)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (4.8)) + (WIDTH (COND dual_rd (negedge SCK)) (4.8)) + (WIDTH (COND fast_rd (negedge SCK)) (3.75)) + (WIDTH (COND fast_rd (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL512SDPMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for Vcc range VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (5)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (4)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (7.5)) + (WIDTH (COND dual_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND ddrd SCK) (15)) +) + + + +S25FL512SDPMFIR10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR11_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI210_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI213_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI310_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI313_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for Vcc range VCC=2.7V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND ~ddr (IOPATH SCK SO (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND (ddr || rd_fast) (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && dual (IOPATH SCK SI (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && dual (IOPATH SCK SI (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND ~ddr && QUAD (IOPATH SCK HOLDNeg (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && QUAD (IOPATH SCK HOLDNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (COND ~ddr && QUAD (IOPATH SCK WPNeg (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND ddr && QUAD (IOPATH SCK WPNeg (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && dual (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + (COND CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~QUAD (IOPATH HOLDNeg SO () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + (COND ~QUAD && dual (IOPATH HOLDNeg SI () () (7:10.5:14) (7:10.5:14) (7:10.5:14) (7:10.5:14))) + + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP CSNeg (COND sdr_rd SCK) (3)) + (SETUP CSNeg (COND ddr_rd SCK) (3)) + (SETUP SI (COND deg_sin(posedge SCK)) (5)) + (SETUP SI (COND ddro(posedge SCK)) (2)) + (SETUP SI (COND ddro(negedge SCK)) (2)) + (SETUP WPNeg (COND wr_prot(negedge CSNeg)) (20)) + (SETUP HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (SETUP RSTNeg CSNeg (50)) + + (HOLD CSNeg (COND sdr_rd SCK) (3)) + (HOLD CSNeg (COND ddr_rd SCK) (3)) + (HOLD SI (COND deg_sin (posedge SCK)) (4)) + (HOLD SI (COND ddro (posedge SCK)) (2)) + (HOLD SI (COND ddro (negedge SCK)) (2)) + (HOLD WPNeg (COND wr_prot (posedge CSNeg)) (100)) + (HOLD HOLDNeg (COND quad_rd (posedge SCK)) (5)) + (HOLD CSNeg RSTNeg (35000)) + + (WIDTH (COND rd (posedge SCK)) (10)) + (WIDTH (COND rd (negedge SCK)) (10)) + (WIDTH (COND dual_rd (posedge SCK)) (7.5)) + (WIDTH (COND dual_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (negedge SCK)) (7.5)) + (WIDTH (COND fast_rd (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND ddrd (posedge SCK)) (7.5)) + (WIDTH (COND ddrd (negedge SCK)) (7.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND ddrd SCK) (15)) +) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_vhd.ftm b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_vhd.ftm new file mode 100644 index 0000000..4bef23a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/model/s25fl512s_vhd.ftm @@ -0,0 +1,547 @@ + +FMF Timing for s25fl512s Parts + + +version: | author: | mod date: | changes made: + V1.0 V.Mancev 09 Nov 26 Initial release + V1.1 V.Mancev 11 July 11 Latest datasheet aligned + V1.2 V.Mancev 11 Nov 17 Time tHO is changed to 1 ns + +1ns +s25fl512s + +S25FL512SAGMFI010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV010_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV011_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV013_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) (1) (5.4:6.7:8) (1) (5.4:6.7:8))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(200e3:340e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(100e3:150e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(200e6:400e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:103e9:460e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL512SAGMFI010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV010_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV011_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV013_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR11_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV210_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV213_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV310_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV313_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL10_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL13_R_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (4.3:6.0:7.65) (4.3:6.0:7.65) (1) (4.3:6.0:7.65) (1) (4.3:6.0:7.65))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(200e3:340e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(100e3:150e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(200e6:400e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:103e9:460e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL512SAGMFI010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFI013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFIR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV010_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV011_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFV013_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR11_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGMFVR13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHI313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHID13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV210_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV213_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV310_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHV313_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVA13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVB13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVC13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHVD13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIY13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIZ13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIS13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIT13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIK13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL10_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SAGBHIL13_R_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) (1) (4.5:5.5:6.5) (1) (4.5:5.5:6.5))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (3)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (3)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (2)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (3)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (4.8)) + (WIDTH (COND dual (negedge SCK)) (4.8)) + (WIDTH (COND fast (negedge SCK)) (3.75)) + (WIDTH (COND fast (posedge SCK)) (3.75)) + (WIDTH (COND quadpg (posedge SCK)) (6.25)) + (WIDTH (COND quadpg (negedge SCK)) (6.25)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (7.52)) + (PERIOD (COND dual_rd SCK) (9.6)) + (PERIOD (COND quadpg SCK) (12.5)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(200e3:340e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(100e3:150e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(200e6:400e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:103e9:460e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL512SDPMFIR10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR11_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI210_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI213_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI310_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI313_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID10_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID13_F_30pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (1.5:8:14.5) (1.5:8:14.5) (1) (1.5:8:14.5) (1) (1.5:8:14.5))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (10:12:14) (10:12:14) (10:12:14) (10:12:14)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (5)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (5)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (4)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (5)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (7.5)) + (WIDTH (COND dual (negedge SCK)) (7.5)) + (WIDTH (COND fast (negedge SCK)) (7.5)) + (WIDTH (COND fast (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(200e3:340e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(100e3:150e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(200e6:400e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:103e9:460e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + + +S25FL512SDPMFIR10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR11_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPMFIR13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI210_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI213_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI310_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHI313_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHIC13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID10_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +S25FL512SDPBHID13_F_15pF Spansion, FL-S_PPD_2.0 April 1, 2011 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (COND normal (IOPATH SCK SO (2:7:12) (2:7:12) (1) (2:7:12) (1) (2:7:12))) + (COND DDR (IOPATH SCK SO (1.5:4:6.5) (1.5:4:6.5) (1) (1.5:4:6.5) (1) (1.5:4:6.5))) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + (IOPATH HOLDNeg SO () () (10:12:14) (10:12:14) (10:12:14) (10:12:14)) + (IOPATH RSTNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + )) + (TIMINGCHECK + (SETUP (COND normal CSNeg) (posedge SCK) (3)) + (SETUP (COND DDR CSNeg) (posedge SCK) (3)) + (SETUP (COND normal SI) (posedge SCK) (5)) + (SETUP WPNeg CSNeg (20)) + (SETUP HOLDNeg SCK (5)) + (SETUP RSTNeg CSNeg (50)) + (SETUP (COND DDR SI) (posedge SCK) (2)) + (SETUP (COND DDR SI) (negedge SCK) (2)) + + (HOLD (COND normal CSNeg) (posedge SCK) (3)) + (HOLD (COND DDR CSNeg) (posedge SCK) (3)) + (HOLD (COND normal SI) (posedge SCK) (4)) + (HOLD WPNeg CSNeg (100)) + (HOLD HOLDNeg SCK (5)) + (HOLD CSNeg RSTNeg (35000)) + (HOLD (COND DDR SI) (posedge SCK) (2)) + (HOLD (COND DDR SI) (negedge SCK) (2)) + + (WIDTH (COND serial (posedge SCK)) (10)) + (WIDTH (COND serial (negedge SCK)) (10)) + (WIDTH (COND dual (posedge SCK)) (7.5)) + (WIDTH (COND dual (negedge SCK)) (7.5)) + (WIDTH (COND fast (negedge SCK)) (7.5)) + (WIDTH (COND fast (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (posedge SCK)) (7.5)) + (WIDTH (COND quadpg (negedge SCK)) (7.5)) + (WIDTH (COND DDR (posedge SCK)) (7.5)) + (WIDTH (COND DDR (negedge SCK)) (7.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgers (posedge CSNeg)) (50)) + (WIDTH (negedge RSTNeg) (200)) + (WIDTH (posedge RSTNeg) (50)) + (PERIOD (COND serial_rd SCK) (20)) + (PERIOD (COND fast_rd SCK) (15)) + (PERIOD (COND dual_rd SCK) (15)) + (PERIOD (COND quadpg SCK) (15)) + (PERIOD (COND DDR_rd SCK) (15)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(200e3:340e3:750e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BP) (DELAY (ABSOLUTE (DEVICE(100e3:150e3:400e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(200e6:400e6:1875e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(55e9:103e9:460e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WRR) (DELAY (ABSOLUTE(DEVICE(200e6:200e6:200e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300e3:300e3:300e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PRGSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/ERSSUSP) (DELAY (ABSOLUTE (DEVICE(40e3:40e3:40e3) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PPBERASE) (DELAY (ABSOLUTE (DEVICE(15e6:15e6:15e6) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSULCK) (DELAY (ABSOLUTE (DEVICE(1000:1000:1000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PASSACC) (DELAY (ABSOLUTE (DEVICE(100e3:100e3:100e3) ) ) ) + + \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl512s/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl512s/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl512s/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl512s/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/sdram/mt48lc16m16a2/dumpdata.txt b/lib/models/memory/sdram/mt48lc16m16a2/dumpdata.txt new file mode 100644 index 0000000..26790d8 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/dumpdata.txt @@ -0,0 +1,47 @@ +# Micron Technology, Inc. (FILE DUMP / MEMORY DUMP) +# BA ROWS COLS DQ +# -- ------------- --------- ---------------- + 00 0000000000000 000000000 0000000001100100 + 00 0000000000000 000000001 0000000001100101 + 00 0000000000000 000000010 0000000001100110 + 00 0000000000000 000000011 0000000001100111 + 00 0000000000000 000000100 0000000001101000 + 00 0000000000000 000000101 0000000001101001 + 00 0000000000000 000000110 0000000001101010 + 00 0000000000000 000000111 0000000001101011 + 00 0000000000000 000001000 0011111111111110 + 00 0000000000000 000001001 0011111111111110 + 00 0000000000000 000001010 0011111111111110 + 01 0000000000000 000000000 0000000011001000 + 01 0000000000000 000000001 0000000011001001 + 01 0000000000000 000000010 0000000011001010 + 01 0000000000000 000000011 0000000011001011 + 01 0000000000000 000000100 0000000011001100 + 01 0000000000000 000000101 0000000011001101 + 01 0000000000000 000000110 0000000011001110 + 01 0000000000000 000000111 0000000011001111 + 01 0000000000000 000001000 0111111111111101 + 01 0000000000000 000001001 0111111111111101 + 01 0000000000000 000001010 0111111111111101 + 10 0000000000000 000000000 0000000100101100 + 10 0000000000000 000000001 0000000100101101 + 10 0000000000000 000000010 0000000100101110 + 10 0000000000000 000000011 0000000100101111 + 10 0000000000000 000000100 0000000100110000 + 10 0000000000000 000000101 0000000100110001 + 10 0000000000000 000000110 0000000100110010 + 10 0000000000000 000000111 0000000100110011 + 10 0000000000000 000001000 1011111111111011 + 10 0000000000000 000001001 1011111111111011 + 10 0000000000000 000001010 1011111111111011 + 11 0000000000000 000000000 0000000110010000 + 11 0000000000000 000000001 0000000110010001 + 11 0000000000000 000000010 0000000110010010 + 11 0000000000000 000000011 0000000110010011 + 11 0000000000000 000000100 0000000110010100 + 11 0000000000000 000000101 0000000110010101 + 11 0000000000000 000000110 0000000110010110 + 11 0000000000000 000000111 0000000110010111 + 11 0000000000000 000001000 1111111111110111 + 11 0000000000000 000001001 1111111111110111 + 11 0000000000000 000001010 1111111111110111 diff --git a/lib/models/memory/sdram/mt48lc16m16a2/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc16m16a2/ed_comnd.vhd new file mode 100644 index 0000000..d449df6 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/ed_comnd.vhd @@ -0,0 +1,349 @@ +--------------------------------------------------------------------------------- +--COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit_vector), first data(integer), dqm(bit), cke(bit));-- +-- read(column address(integer), bank(bit_vector), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit_vector), data bus (integer), dqm(bit), cke(bit));-- +-- precharge(bank(bit_vector), address (integer), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit), cs(bit)); -- +-- burst_term(data bus(integer), dqm(bit_vector), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit_vector)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +--------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, "00", '1', '1'); --Always begin with one nop when using Micron's testbench + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +load_array; + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +precharge("00", 1024, Z, "00", '1'); + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +load_mode_reg(51, '1'); -- 19 / 35 / 51 -> lat=3,bl=8,mode=seq + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +-- Write Section + +next_cycle(clk); +active(0, "00", Z, "00", '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); -- Write Bank 0 +write(0, "00", 100, "00", '1'); + +next_cycle(clk); +nop(101, "00", '1', '1'); + +next_cycle(clk); +active(0, "01", 102, "00", '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(103, "00", '1', '1'); + +next_cycle(clk); +nop(104, "00", '1', '1'); + +next_cycle(clk); +nop(105, "00", '1', '1'); + +next_cycle(clk); +nop(106, "00", '1', '1'); + +next_cycle(clk); +nop(107, "00", '1', '1'); + +next_cycle(clk); +write(0, "01", 200, "00", '1'); -- Write Bank 1 + +next_cycle(clk); +precharge("00", 0, 201, "00", '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", 202, "00", '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(203, "00", '1', '1'); + +next_cycle(clk); +nop(204, "00", '1', '1'); + +next_cycle(clk); +nop(205, "00", '1', '1'); + +next_cycle(clk); +nop(206, "00", '1', '1'); + +next_cycle(clk); +nop(207, "00", '1', '1'); + +next_cycle(clk); +write(0, "10", 300, "00", '1'); -- Write Bank 2 + +next_cycle(clk); +precharge("01", 0, 301, "00", '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", 302, "00", '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(303, "00", '1', '1'); + +next_cycle(clk); +nop(304, "00", '1', '1'); + +next_cycle(clk); +nop(305, "00", '1', '1'); + +next_cycle(clk); +nop(306, "00", '1', '1'); + +next_cycle(clk); +nop(307, "00", '1', '1'); + +next_cycle(clk); +write(0, "11", 400, "00", '1'); -- Write Bank 3 + +next_cycle(clk); +precharge("10", 0, 401, "00", '1'); -- Precharge Bank 2 + +next_cycle(clk); +active(0, "00", 402, "00", '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(403, "00", '1', '1'); + +next_cycle(clk); +nop(404, "00", '1', '1'); + +next_cycle(clk); +nop(405, "00", '1', '1'); + +next_cycle(clk); +nop(406, "00", '1', '1'); + +next_cycle(clk); +nop(407, "00", '1', '1'); + +-- Read Section + +next_cycle(clk); +read(0, "00", "00", '1'); -- Read Bank 0 + +next_cycle(clk); +precharge("11", 0, Z, "00", '1'); -- Precharge Bank 3 + +next_cycle(clk); +active(0, "01", Z, "00", '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +read(0, "01", "00", '1'); -- Read Bank 1 + +next_cycle(clk); +precharge("00", 0, Z, "00", '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", Z, "00", '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +read(0, "10", "00", '1'); -- Read Bank 2 + +next_cycle(clk); +precharge("01", 0, Z, "00", '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", Z, "00", '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +read(0, "11", "00", '1'); -- Read Bank 3 + +next_cycle(clk); +precharge("10", 0, Z, "00", '1'); -- Precharge Bank 2 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +precharge("11", 0, Z, "00", '1'); -- Precharge Bank 3 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +unload_array; + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc16m16a2/loaddata.txt b/lib/models/memory/sdram/mt48lc16m16a2/loaddata.txt new file mode 100644 index 0000000..bee89c0 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/loaddata.txt @@ -0,0 +1,50 @@ +# Micron Technology, Inc. (FILE LOAD / MEMORY INITIALIZE) +# BA ROWS COLS DQ +# -- ------------- --------- ---------------- + 00 0000000000000 000000000 0011111111111110 + 00 0000000000000 000000001 0011111111111110 + 00 0000000000000 000000010 0011111111111110 + 00 0000000000000 000000011 0011111111111110 + 00 0000000000000 000000100 0011111111111110 + 00 0000000000000 000000101 0011111111111110 + 00 0000000000000 000000110 0011111111111110 + 00 0000000000000 000000111 0011111111111110 + 00 0000000000000 000001000 0011111111111110 + 00 0000000000000 000001001 0011111111111110 + 00 0000000000000 000001010 0011111111111110 + + 01 0000000000000 000000000 0111111111111101 + 01 0000000000000 000000001 0111111111111101 + 01 0000000000000 000000010 0111111111111101 + 01 0000000000000 000000011 0111111111111101 + 01 0000000000000 000000100 0111111111111101 + 01 0000000000000 000000101 0111111111111101 + 01 0000000000000 000000110 0111111111111101 + 01 0000000000000 000000111 0111111111111101 + 01 0000000000000 000001000 0111111111111101 + 01 0000000000000 000001001 0111111111111101 + 01 0000000000000 000001010 0111111111111101 + + 10 0000000000000 000000000 1011111111111011 + 10 0000000000000 000000001 1011111111111011 + 10 0000000000000 000000010 1011111111111011 + 10 0000000000000 000000011 1011111111111011 + 10 0000000000000 000000100 1011111111111011 + 10 0000000000000 000000101 1011111111111011 + 10 0000000000000 000000110 1011111111111011 + 10 0000000000000 000000111 1011111111111011 + 10 0000000000000 000001000 1011111111111011 + 10 0000000000000 000001001 1011111111111011 + 10 0000000000000 000001010 1011111111111011 + + 11 0000000000000 000000000 1111111111110111 + 11 0000000000000 000000001 1111111111110111 + 11 0000000000000 000000010 1111111111110111 + 11 0000000000000 000000011 1111111111110111 + 11 0000000000000 000000100 1111111111110111 + 11 0000000000000 000000101 1111111111110111 + 11 0000000000000 000000110 1111111111110111 + 11 0000000000000 000000111 1111111111110111 + 11 0000000000000 000001000 1111111111110111 + 11 0000000000000 000001001 1111111111110111 + 11 0000000000000 000001010 1111111111110111 diff --git a/lib/models/memory/sdram/mt48lc16m16a2/mt48lc16m16a2.vhd b/lib/models/memory/sdram/mt48lc16m16a2/mt48lc16m16a2.vhd new file mode 100644 index 0000000..fac375d --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/mt48lc16m16a2.vhd @@ -0,0 +1,1319 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC16M16A2.VHD +-- Version: 0.0g +-- Date: June 29th, 2000 +-- Model: Behavioral +-- Simulator: Model Technology (PC version 5.3 PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC16M16A2 (4Mb x 16 x 4 Banks) +-- +-- Description: Micron 256Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0g Son Huynh 208-368-3825 06/29/2000 Add Load/Dump memory array +-- Micron Technology Inc. Modify tWR + tRAS timing check +-- +-- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) +-- Micron Technology Inc. Fix tWR = 15 ns (Manual) +-- Fix tRP (Autoprecharge to AutoRefresh) +-- +-- 0.0c Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP +-- Micron Technology Inc. Fix tRC check in Load Mode Register +-- +-- 0.0b Son P. Huynh 208-368-3825 01/06/1998 Derive from 64Mb SDRAM model +-- Micron Technology Inc. +-- +----------------------------------------------------------------------------------------- + +LIBRARY STD; + USE STD.TEXTIO.ALL; +LIBRARY IEEE; + USE IEEE.STD_LOGIC_1164.ALL; + USE IEEE.STD_LOGIC_ARITH.ALL; +LIBRARY WORK; + USE WORK.MTI_PKG.ALL; + +ENTITY mt48lc16m16a2 IS + GENERIC ( + -- Timing Parameters for -75 (PC133) and CAS Latency = 2 + tAC : TIME := 6.0 ns; + tHZ : TIME := 7.0 ns; + tOH : TIME := 2.7 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 44.0 ns; + tRC : TIME := 66.0 ns; + tRCD : TIME := 20.0 ns; + tRP : TIME := 20.0 ns; + tRRD : TIME := 15.0 ns; + tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) + tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 10.0 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 13; + data_bits : INTEGER := 16; + col_bits : INTEGER := 9 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Load : IN STD_LOGIC := '0'; -- FOR LOADING MEMORY ARRAY + Dump : IN STD_LOGIC := '0' -- FOR DUMPING MEMORY ARRAY + ); +END mt48lc16m16a2; + +ARCHITECTURE behave OF mt48lc16m16a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, LOAD_FILE, DUMP_FILE); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL RAS_clk, Sys_clk, CkeZ : BIT := '0'; + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + +BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- RAS Clock for checking tWR and tRP + PROCESS + variable Clk0, Clk1 : integer := 0; + begin + RAS_clk <= '1'; + wait for 0.5 ns; + RAS_clk <= '0'; + wait for 0.5 ns; + if Clk0 > 100 or Clk1 > 100 then + wait; + else + if Clk = '1' and Cke = '1' then + Clk0 := 0; + Clk1 := Clk1 + 1; + elsif Clk = '0' and Cke = '1' then + Clk0 := Clk0 + 1; + Clk1 := 0; + end if; + end if; + END PROCESS; + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + -- NOTE: The extra bits in RAM_TYPE is for checking memory access. A logic 1 means + -- the location is in use. This will be checked when doing memory DUMP. + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg0, Dqm_reg1 : BIT_VECTOR (1 DOWNTO 0) := "00"; + + VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Load and Dumb variables + FILE file_load : TEXT IS IN "loaddata.txt"; -- Data load + FILE file_dump : TEXT IS OUT "dumpdata.txt"; -- Data dump + VARIABLE bank_load : BIT_VECTOR ( 1 DOWNTO 0); + VARIABLE rows_load : BIT_VECTOR (12 DOWNTO 0); + VARIABLE cols_load : BIT_VECTOR ( 8 DOWNTO 0); + VARIABLE data_load : BIT_VECTOR (15 DOWNTO 0); + VARIABLE i, j : INTEGER; + VARIABLE good_load : BOOLEAN; + VARIABLE l : LINE; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, RAS_clk; + IF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '0' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg0 := Dqm_reg1; + Dqm_reg1 := TO_BITVECTOR(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Precharge Timer for tWR + if (Burst_length_1 = '1' OR Write_burst_mode = '1') then + if (Count_precharge(0) = 1) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 1) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 1) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 1) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_2 = '1') then + if (Count_precharge(0) = 2) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 2) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 2) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 2) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_4 = '1') then + if (Count_precharge(0) = 4) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 4) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 4) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 4) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_8 = '1') then + if (Count_precharge(0) = 8) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 8) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 8) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 8) then + Count_time(3) := NOW; + end if; + end if; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) := WR_counter(0) + 1; + WR_counter(1) := WR_counter(1) + 1; + WR_counter(2) := WR_counter(2) + 1; + WR_counter(3) := WR_counter(3) + 1; + + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := TO_BITVECTOR (Addr); + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := TO_BITVECTOR (Addr); + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := TO_BITVECTOR (Ba); + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR + (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BITVECTOR (Ba); + A10_precharge(2) := TO_BIT(Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BITVECTOR (Ba); + A10_precharge(1) := TO_BIT(Addr(10)); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba="00" AND Pc_b0='1') OR (Ba="01" AND Pc_b1='1') OR (Ba="10" AND Pc_b2='1') OR (Ba="11" AND Pc_b3='1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (2) := TO_BITVECTOR (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (1) := TO_BITVECTOR (Ba); + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (0) := TO_BITVECTOR (Ba); + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Write_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN + RW_interrupt_write(TO_INTEGER(RW_Interrupt_Bank)) := '1'; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Read_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN + RW_interrupt_read(TO_INTEGER(RW_Interrupt_Bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + RW_Interrupt_Bank := TO_BitVector(Ba); + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank0 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank1 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank2 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank3 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); + END IF; + WR_chkp(TO_INTEGER(Bank)) := NOW; + WR_counter(TO_INTEGER(Bank)) := 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg0 /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '1' AND Dump = '0' THEN + Operation <= LOAD_FILE; + ASSERT (FALSE) REPORT "Reading memory array from file. This operation may take several minutes. Please wait..." + SEVERITY NOTE; + WHILE NOT endfile(file_load) LOOP + readline(file_load, l); + -- skip the line if it doesn't start with a number + read(l, bank_load, good => good_load); + NEXT WHEN NOT good_load; + read(l, rows_load); + read(l, cols_load); + read(l, data_load); + Init_Mem (Bank_Load, To_Integer(Rows_Load)); + IF Bank_Load = "00" THEN + Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)) := ('1' & Data_Load); + ELSIF Bank_Load = "01" THEN + Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)) := ('1' & Data_Load); + ELSIF Bank_Load = "10" THEN + Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)) := ('1' & Data_Load); + ELSIF Bank_Load = "11" THEN + Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)) := ('1' & Data_Load); + END IF; + END LOOP; + ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '1' THEN + Operation <= DUMP_FILE; + ASSERT (FALSE) REPORT "Writing memory array to file. This operation may take several minutes. Please wait..." + SEVERITY NOTE; + WRITE (l, string'("# Micron Technology, Inc. (FILE DUMP / MEMORY DUMP)")); + WRITELINE (file_dump, l); + WRITE (l, string'("# BA ROWS COLS DQ")); + WRITELINE (file_dump, l); + WRITE (l, string'("# -- ------------- --------- ----------------")); + WRITELINE (file_dump, l); + -- Dumping Bank 0 + FOR i IN 0 TO 2**addr_bits -1 LOOP + -- Check if ROW is NULL + IF Bank0 (i) /= NULL THEN + For j IN 0 TO 2**col_bits - 1 LOOP + -- Check if COL is NULL + NEXT WHEN Bank0 (i) (j) (data_bits) = '0'; + WRITE (l, string'("00"), right, 4); + WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); + WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); + WRITE (l, Bank0 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); + WRITELINE (file_dump, l); + END LOOP; + END IF; + END LOOP; + -- Dumping Bank 1 + FOR i IN 0 TO 2**addr_bits -1 LOOP + -- Check if ROW is NULL + IF Bank1 (i) /= NULL THEN + For j IN 0 TO 2**col_bits - 1 LOOP + -- Check if COL is NULL + NEXT WHEN Bank1 (i) (j) (data_bits) = '0'; + WRITE (l, string'("01"), right, 4); + WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); + WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); + WRITE (l, Bank1 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); + WRITELINE (file_dump, l); + END LOOP; + END IF; + END LOOP; + -- Dumping Bank 2 + FOR i IN 0 TO 2**addr_bits -1 LOOP + -- Check if ROW is NULL + IF Bank2 (i) /= NULL THEN + For j IN 0 TO 2**col_bits - 1 LOOP + -- Check if COL is NULL + NEXT WHEN Bank2 (i) (j) (data_bits) = '0'; + WRITE (l, string'("10"), right, 4); + WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); + WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); + WRITE (l, Bank2 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); + WRITELINE (file_dump, l); + END LOOP; + END IF; + END LOOP; + -- Dumping Bank 3 + FOR i IN 0 TO 2**addr_bits -1 LOOP + -- Check if ROW is NULL + IF Bank3 (i) /= NULL THEN + For j IN 0 TO 2**col_bits - 1 LOOP + -- Check if COL is NULL + NEXT WHEN Bank3 (i) (j) (data_bits) = '0'; + WRITE (l, string'("11"), right, 4); + WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); + WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); + WRITE (l, Bank3 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); + WRITELINE (file_dump, l); + END LOOP; + END IF; + END LOOP; + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + + -- Checking internal wires (Optional for debug purpose) + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Pre_chk (2) <= Pc_b2; + Pre_chk (3) <= Pc_b3; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Act_chk (2) <= Act_b2; + Act_chk (3) <= Act_b3; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "Dq Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc16m16a2/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc16m16a2/mti_pkg.vhd new file mode 100644 index 0000000..80a9639 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/mti_pkg.vhd @@ -0,0 +1,139 @@ +--***************************************************************************** +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +--***************************************************************************** + +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC; + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + -- Convert BIT to STD_LOGIC + FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC IS + BEGIN + CASE s IS + WHEN '0' => RETURN ('0'); + WHEN '1' => RETURN ('1'); + WHEN OTHERS => RETURN ('0'); + END CASE; + END; + + -- Convert STD_LOGIC to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert BIT_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Conver INTEGER to BIT_VECTOR + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc16m16a2/test.do b/lib/models/memory/sdram/mt48lc16m16a2/test.do new file mode 100644 index 0000000..c7e958c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/test.do @@ -0,0 +1,57 @@ +# Macro for running Micron SDRAM VHDL model +# +# Compile Package Library (Require) +vcom mti_pkg.vhd + +# Compile Micron Test Vector Generator (optional or use your own test) +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all + +# Compile Micron SDRAM +vcom mt48lc16m16a2.vhd + +# Compile Micron Testbench (optional or use your own test bench) +vcom test.vhd + +# Simulate Test +vsim tb + +# Display waveform +onerror {resume} +add wave -logic /tb/u1/clk +add wave -logic /tb/u1/cke +add wave -logic /tb/u1/cs_n +add wave -logic /tb/u1/ras_n +add wave -logic /tb/u1/cas_n +add wave -logic /tb/u1/we_n +add wave -literal -decimal /tb/u1/addr +add wave -literal -unsigned /tb/u1/ba +add wave -literal -decimal /tb/u1/dq +add wave -literal /tb/u1/dqm +add wave -literal /tb/u1/operation +add wave -literal -decimal /tb/u1/mode_reg +add wave -logic /tb/u1/active_enable +add wave -logic /tb/u1/aref_enable +add wave -logic /tb/u1/burst_term +add wave -logic /tb/u1/mode_reg_enable +add wave -logic /tb/u1/prech_enable +add wave -logic /tb/u1/read_enable +add wave -logic /tb/u1/write_enable +add wave -logic /tb/u1/burst_length_1 +add wave -logic /tb/u1/burst_length_2 +add wave -logic /tb/u1/burst_length_4 +add wave -logic /tb/u1/burst_length_8 +add wave -logic /tb/u1/cas_latency_2 +add wave -logic /tb/u1/cas_latency_3 +add wave -literal /tb/u1/pre_chk +add wave -literal /tb/u1/act_chk +add wave -literal /tb/u1/bank_chk +add wave -literal -decimal /tb/u1/row_chk +add wave -literal -decimal /tb/u1/col_chk +add wave -logic /tb/u1/dq_in_chk +add wave -logic /tb/u1/dq_out_chk + +# Run all test +run -all diff --git a/lib/models/memory/sdram/mt48lc16m16a2/test.txt b/lib/models/memory/sdram/mt48lc16m16a2/test.txt new file mode 100644 index 0000000..37330c0 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/test.txt @@ -0,0 +1,101 @@ +0 ns 1 1 1 1 1 00 00 0 -100 0 0 +22 ns 1 1 1 1 1 00 00 0 -100 0 0 +32 ns 1 0 1 1 1 00 00 0 -100 1 0 +42 ns 1 1 1 1 1 00 00 0 -100 0 0 +52 ns 1 1 1 1 1 00 00 0 -100 0 0 +62 ns 1 1 1 1 1 00 00 0 -100 0 0 +72 ns 1 1 1 1 1 00 00 0 -100 0 0 +82 ns 1 0 0 1 0 00 00 1024 -100 0 0 +92 ns 1 1 1 1 1 00 00 0 -100 0 0 +102 ns 1 1 1 1 1 00 00 0 -100 0 0 +112 ns 1 0 0 0 1 00 00 0 -100 0 0 +122 ns 1 1 1 1 1 00 00 0 -100 0 0 +132 ns 1 1 1 1 1 00 00 0 -100 0 0 +142 ns 1 1 1 1 1 00 00 0 -100 0 0 +152 ns 1 1 1 1 1 00 00 0 -100 0 0 +162 ns 1 1 1 1 1 00 00 0 -100 0 0 +172 ns 1 1 1 1 1 00 00 0 -100 0 0 +182 ns 1 1 1 1 1 00 00 0 -100 0 0 +192 ns 1 1 1 1 1 00 00 0 -100 0 0 +202 ns 1 0 0 0 1 00 00 0 -100 0 0 +212 ns 1 1 1 1 1 00 00 0 -100 0 0 +222 ns 1 1 1 1 1 00 00 0 -100 0 0 +232 ns 1 1 1 1 1 00 00 0 -100 0 0 +242 ns 1 1 1 1 1 00 00 0 -100 0 0 +252 ns 1 1 1 1 1 00 00 0 -100 0 0 +262 ns 1 1 1 1 1 00 00 0 -100 0 0 +272 ns 1 1 1 1 1 00 00 0 -100 0 0 +282 ns 1 1 1 1 1 00 00 0 -100 0 0 +292 ns 1 0 0 0 0 00 00 51 -100 0 0 +302 ns 1 1 1 1 1 00 00 0 -100 0 0 +312 ns 1 0 0 1 1 00 00 0 -100 0 0 +322 ns 1 1 1 1 1 00 00 0 -100 0 0 +332 ns 1 0 1 0 0 00 00 0 100 0 0 +342 ns 1 1 1 1 1 00 00 0 101 0 0 +352 ns 1 0 0 1 1 00 01 0 102 0 0 +362 ns 1 1 1 1 1 00 00 0 103 0 0 +372 ns 1 1 1 1 1 00 00 0 104 0 0 +382 ns 1 1 1 1 1 00 00 0 105 0 0 +392 ns 1 1 1 1 1 00 00 0 106 0 0 +402 ns 1 1 1 1 1 00 00 0 107 0 0 +412 ns 1 0 1 0 0 00 01 0 200 0 0 +422 ns 1 0 0 1 0 00 00 0 201 0 0 +432 ns 1 0 0 1 1 00 10 0 202 0 0 +442 ns 1 1 1 1 1 00 00 0 203 0 0 +452 ns 1 1 1 1 1 00 00 0 204 0 0 +462 ns 1 1 1 1 1 00 00 0 205 0 0 +472 ns 1 1 1 1 1 00 00 0 206 0 0 +482 ns 1 1 1 1 1 00 00 0 207 0 0 +492 ns 1 0 1 0 0 00 10 0 300 0 0 +502 ns 1 0 0 1 0 00 01 0 301 0 0 +512 ns 1 0 0 1 1 00 11 0 302 0 0 +522 ns 1 1 1 1 1 00 00 0 303 0 0 +532 ns 1 1 1 1 1 00 00 0 304 0 0 +542 ns 1 1 1 1 1 00 00 0 305 0 0 +552 ns 1 1 1 1 1 00 00 0 306 0 0 +562 ns 1 1 1 1 1 00 00 0 307 0 0 +572 ns 1 0 1 0 0 00 11 0 400 0 0 +582 ns 1 0 0 1 0 00 10 0 401 0 0 +592 ns 1 0 0 1 1 00 00 0 402 0 0 +602 ns 1 1 1 1 1 00 00 0 403 0 0 +612 ns 1 1 1 1 1 00 00 0 404 0 0 +622 ns 1 1 1 1 1 00 00 0 405 0 0 +632 ns 1 1 1 1 1 00 00 0 406 0 0 +642 ns 1 1 1 1 1 00 00 0 407 0 0 +652 ns 1 0 1 0 1 00 00 0 -100 0 0 +662 ns 1 0 0 1 0 00 11 0 -100 0 0 +672 ns 1 0 0 1 1 00 01 0 -100 0 0 +682 ns 1 1 1 1 1 00 00 0 -100 0 0 +692 ns 1 1 1 1 1 00 00 0 -100 0 0 +702 ns 1 1 1 1 1 00 00 0 -100 0 0 +712 ns 1 1 1 1 1 00 00 0 -100 0 0 +722 ns 1 1 1 1 1 00 00 0 -100 0 0 +732 ns 1 0 1 0 1 00 01 0 -100 0 0 +742 ns 1 0 0 1 0 00 00 0 -100 0 0 +752 ns 1 0 0 1 1 00 10 0 -100 0 0 +762 ns 1 1 1 1 1 00 00 0 -100 0 0 +772 ns 1 1 1 1 1 00 00 0 -100 0 0 +782 ns 1 1 1 1 1 00 00 0 -100 0 0 +792 ns 1 1 1 1 1 00 00 0 -100 0 0 +802 ns 1 1 1 1 1 00 00 0 -100 0 0 +812 ns 1 0 1 0 1 00 10 0 -100 0 0 +822 ns 1 0 0 1 0 00 01 0 -100 0 0 +832 ns 1 0 0 1 1 00 11 0 -100 0 0 +842 ns 1 1 1 1 1 00 00 0 -100 0 0 +852 ns 1 1 1 1 1 00 00 0 -100 0 0 +862 ns 1 1 1 1 1 00 00 0 -100 0 0 +872 ns 1 1 1 1 1 00 00 0 -100 0 0 +882 ns 1 1 1 1 1 00 00 0 -100 0 0 +892 ns 1 0 1 0 1 00 11 0 -100 0 0 +902 ns 1 0 0 1 0 00 10 0 -100 0 0 +912 ns 1 1 1 1 1 00 00 0 -100 0 0 +922 ns 1 1 1 1 1 00 00 0 -100 0 0 +932 ns 1 1 1 1 1 00 00 0 -100 0 0 +942 ns 1 1 1 1 1 00 00 0 -100 0 0 +952 ns 1 1 1 1 1 00 00 0 -100 0 0 +962 ns 1 1 1 1 1 00 00 0 -100 0 0 +972 ns 1 0 0 1 0 00 11 0 -100 0 0 +982 ns 1 1 1 1 1 00 00 0 -100 0 0 +992 ns 1 1 1 1 1 00 00 0 -100 0 0 +1002 ns 1 0 1 1 1 00 00 0 -100 0 1 +1012 ns 1 1 1 1 1 00 00 0 -100 0 0 diff --git a/lib/models/memory/sdram/mt48lc16m16a2/test.vhd b/lib/models/memory/sdram/mt48lc16m16a2/test.vhd new file mode 100644 index 0000000..d5de6f8 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/test.vhd @@ -0,0 +1,164 @@ +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + USE ieee.std_logic_arith.ALL; +LIBRARY STD; + USE std.textio.ALL; +LIBRARY work; + USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 13; + CONSTANT data_bits : INTEGER := 16; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + + COMPONENT mt48lc16m16a2 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := (OTHERS => '0'); + Load : IN STD_LOGIC := '0'; -- FOR LOADING MEMORY ARRAY + Dump : IN STD_LOGIC := '0' -- FOR DUMPING MEMORY ARRAY + ); + END COMPONENT; + + FOR ALL : mt48lc16m16a2 USE ENTITY work.mt48lc16m16a2 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pLoad : STD_LOGIC; + SIGNAL pDump : STD_LOGIC; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc16m16a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm, + Load => pLoad, + Dump => pDump + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : bit; + VARIABLE pCs_var : bit; + VARIABLE pRas_var : bit; + VARIABLE PCas_var : bit; + VARIABLE pWe_var : bit; + VARIABLE pDqm_var : bit_vector (1 DOWNTO 0); + VARIABLE pBa_var : bit_vector (1 DOWNTO 0); + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE PLoad_var : bit; + VARIABLE pDump_var : bit; + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read(l, time_var); + read(l, pCke_var); + read(l, pCs_var); + read(l, pRas_var); + read(l, pCas_var); + read(l, pWe_var); + read(l, pDqm_var); + read(l, pBa_var); + read(l, pAddr_var); + read(l, pDq_var); + read(l, PLoad_var); + read(l, pDump_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + pCke <= TO_StdLogic(pCke_var); + pCs <= TO_StdLogic(pCs_var); + pRas <= TO_StdLogic(pRas_var); + pCas <= TO_StdLogic(pCas_var); + pWe <= TO_StdLogic(pWe_var); + pDqm <= TO_StdLogicVector(pDqm_var); + pBa <= TO_StdLogicVector(pBa_var); + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= TO_StdLogic(PLoad_var); + pDump <= TO_StdLogic(pDump_var); + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc16m16a2/vec_gen.vhd b/lib/models/memory/sdram/mt48lc16m16a2/vec_gen.vhd new file mode 100644 index 0000000..633fb8d --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/vec_gen.vhd @@ -0,0 +1,353 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY ieee; + USE ieee.std_logic_1164.all; +LIBRARY STD; + USE std.textio.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); + first_data : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT; cs : IN BIT); + PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle(SIGNAL clk : IN BIT); + PROCEDURE load_array; + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array; + +END generate_vectors; + + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; + dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, first_data, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, row_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT; cs : IN BIT) IS + + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, cs, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS + +BEGIN + +WAIT UNTIL clk = '1'; + +END; + +PROCEDURE load_array IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 1, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE unload_array IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 1, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, op_code, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +writeline(output_file,l); --write vector to file + +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc16m16a2/wave.do b/lib/models/memory/sdram/mt48lc16m16a2/wave.do new file mode 100644 index 0000000..0e59196 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m16a2/wave.do @@ -0,0 +1,33 @@ +onerror {resume} +add wave -logic /tb/u1/clk +add wave -logic /tb/u1/cke +add wave -logic /tb/u1/cs_n +add wave -logic /tb/u1/ras_n +add wave -logic /tb/u1/cas_n +add wave -logic /tb/u1/we_n +add wave -literal -decimal /tb/u1/addr +add wave -literal -unsigned /tb/u1/ba +add wave -literal -decimal /tb/u1/dq +add wave -literal /tb/u1/dqm +add wave -literal /tb/u1/operation +add wave -literal -decimal /tb/u1/mode_reg +add wave -logic /tb/u1/active_enable +add wave -logic /tb/u1/aref_enable +add wave -logic /tb/u1/burst_term +add wave -logic /tb/u1/mode_reg_enable +add wave -logic /tb/u1/prech_enable +add wave -logic /tb/u1/read_enable +add wave -logic /tb/u1/write_enable +add wave -logic /tb/u1/burst_length_1 +add wave -logic /tb/u1/burst_length_2 +add wave -logic /tb/u1/burst_length_4 +add wave -logic /tb/u1/burst_length_8 +add wave -logic /tb/u1/cas_latency_2 +add wave -logic /tb/u1/cas_latency_3 +add wave -literal /tb/u1/pre_chk +add wave -literal /tb/u1/act_chk +add wave -literal /tb/u1/bank_chk +add wave -literal -decimal /tb/u1/row_chk +add wave -literal -decimal /tb/u1/col_chk +add wave -logic /tb/u1/dq_in_chk +add wave -logic /tb/u1/dq_out_chk diff --git a/lib/models/memory/sdram/mt48lc16m8a2/mt48lc16m8a2.vhd b/lib/models/memory/sdram/mt48lc16m8a2/mt48lc16m8a2.vhd new file mode 100644 index 0000000..562a4cc --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m8a2/mt48lc16m8a2.vhd @@ -0,0 +1,1069 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC16M8A2.VHD +-- Version: 1.0a +-- Date: January 26th, 2000 +-- Model: Behavioral +-- Simulator: Model Technology +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC16M8A2 (4Mb x 8 x 4 Banks) +-- +-- Description: Micron 128Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 1.0a Son P. Huynh 208-368-3825 12/02/1999 Second Release +-- Micron Technology Inc. - Simple testbench included +-- +----------------------------------------------------------------------------------------- + +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + USE ieee.std_logic_unsigned.conv_integer; + USE ieee.std_logic_arith.conv_std_logic_vector; + +ENTITY mt48lc16m8a2 IS + GENERIC ( + -- Timing Parameters for -75 (133 MHz @ CL2) + tAC : TIME := 6.0 ns; + tHZ : TIME := 6.0 ns; + tOH : TIME := 2.7 ns; + tMRD : TIME := 20.0 ns; -- 2 * tCK + tRAS : TIME := 44.0 ns; + tRC : TIME := 66.0 ns; + tRCD : TIME := 20.0 ns; + tRP : TIME := 20.0 ns; + tRRD : TIME := 15.0 ns; + tWRa : TIME := 17.5 ns; -- Auto precharge = tCK + 7.5 ns + tWRm : TIME := 15.0 ns; -- Manual Precharge = 15 ns + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 10.0 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 12; + data_bits : INTEGER := 8; + col_bits : INTEGER := 10 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC := '0' + ); +END mt48lc16m8a2; + +ARCHITECTURE behave OF mt48lc16m8a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, FILE_LOAD, FILE_UNLOAD); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xSL IS ARRAY (3 DOWNTO 0) OF STD_LOGIC; + TYPE Array4x2SLV IS ARRAY (3 DOWNTO 0) OF STD_LOGIC_VECTOR (1 DOWNTO 0); -- For Bank Pipeline + TYPE Array2x4SLV IS ARRAY (1 DOWNTO 0) OF STD_LOGIC_VECTOR (3 DOWNTO 0); -- For Dqm Pipeline + TYPE Array4xCSLV IS ARRAY (4 DOWNTO 0) OF STD_LOGIC_VECTOR (Col_bits - 1 DOWNTO 0); -- For Column Pipeline + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : STD_LOGIC := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : STD_LOGIC := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : STD_LOGIC := '0'; + SIGNAL Cas_latency_1, Cas_latency_2, Cas_latency_3 : STD_LOGIC := '0'; + SIGNAL Cs_in, Ras_in, Cas_in, We_in : STD_LOGIC := '0'; + SIGNAL Write_burst_mode : STD_LOGIC := '0'; + SIGNAL RAS_clk, Sys_clk, CkeZ : STD_LOGIC := '0'; + + -- The following signals are for debug purpose only + SIGNAL Act_chk : STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Din_chk : STD_LOGIC := '0'; + SIGNAL Dout_chk : STD_LOGIC := '0'; + +BEGIN + -- Strip the strength + Cs_in <= To_X01 (Cs_n); + Ras_in <= To_X01 (Ras_n); + Cas_in <= To_X01 (Cas_n); + We_in <= To_X01 (We_n); + + -- Commands Decode + Active_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= NOT(Cs_in) AND Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_1 <= NOT(Mode_reg(6)) AND NOT(Mode_reg(5)) AND Mode_reg(4); + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- RAS Clock for checking tWR and tRP + PROCESS + variable Clk0, Clk1 : integer := 0; + begin + RAS_clk <= '1'; + wait for 0.5 ns; + RAS_clk <= '0'; + wait for 0.5 ns; + END PROCESS; + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= Cke; + END IF; + Sys_clk <= CkeZ AND Clk; + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCSLV; + VARIABLE Bank_addr : Array4x2SLV; + VARIABLE Dqm_reg0, Dqm_reg1 : STD_LOGIC := '0'; + + VARIABLE Bank, Previous_bank : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_pipe_precharge : Array4x2SLV; + VARIABLE A10_pipe_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Bank_precharge : INTEGER := 0; + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : STD_LOGIC := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : STD_LOGIC := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : STD_LOGIC := '0'; + + -- Timing Check + VARIABLE MRD_chk : TIME := 0 ns; + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chka : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkm : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : STD_LOGIC_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := conv_integer(Col) + 1; + Col_temp := CONV_STD_LOGIC_VECTOR(Col_int, col_bits); + ELSIF Mode_reg (3) = '1' THEN + Col_vec := CONV_STD_LOGIC_VECTOR(Burst_counter, col_bits); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + IF Write_precharge (CONV_INTEGER(Bank)) = '1' THEN + WR_chka (CONV_INTEGER(Bank)) := NOW; + END IF; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + IF Write_precharge (CONV_INTEGER(Bank)) = '1' THEN + WR_chka (CONV_INTEGER(Bank)) := NOW; + END IF; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + IF Write_precharge (CONV_INTEGER(Bank)) = '1' THEN + WR_chka (CONV_INTEGER(Bank)) := NOW; + END IF; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + IF Write_precharge (CONV_INTEGER(Bank)) = '1' THEN + WR_chka (CONV_INTEGER(Bank)) := NOW; + END IF; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, RAS_clk; + IF Sys_clk'event AND Sys_clk = '1' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + -- Internal Precharge Pipeline + Bank_pipe_precharge(0) := Bank_pipe_precharge(1); + Bank_pipe_precharge(1) := Bank_pipe_precharge(2); + Bank_pipe_precharge(2) := Bank_pipe_precharge(3); + Bank_pipe_precharge(3) := "00"; + + A10_pipe_precharge(0) := A10_pipe_precharge(1); + A10_pipe_precharge(1) := A10_pipe_precharge(2); + A10_pipe_precharge(2) := A10_pipe_precharge(3); + A10_pipe_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg0 := Dqm_reg1; + Dqm_reg1 := Dqm; + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= Addr; + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (NOW - MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := NOW; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := Addr; + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := Addr; + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := Addr; + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := Addr; + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= Ba) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := Ba; + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkm(0) < tWRm) OR (NOW - WR_chkm(1) < tWRm) OR + (NOW - WR_chkm(2) < tWRm) OR (NOW - WR_chkm(3) < tWRm)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkm(CONV_INTEGER(Ba)) >= tWRm) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = Ba OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_pipe_precharge(2) := Ba; + A10_pipe_precharge(2) := Addr(10); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_pipe_precharge(1) := Ba; + A10_pipe_precharge(1) := Addr(10); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR + (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_1 = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := READ_A; + ELSE + Command(0) := READ; + END IF; + Col_addr (0) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (0) := Ba; + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (1) := Ba; + ELSIF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (2) := Ba; + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + -- Interrupt a write with autoprecharge + IF (Auto_precharge (Bank_precharge) = '1' AND + Write_precharge (Bank_precharge) = '1') THEN + RW_interrupt_write (Bank_precharge) := '1'; + WR_time (Bank_precharge) := NOW; + END IF; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (0) := Ba; + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + -- Interrupt a Write with Auto Precharge + IF (Auto_precharge(Bank_precharge) = '1' AND + Write_precharge(Bank_precharge) = '1') THEN + RW_interrupt_write(Bank_precharge) := '1'; + WR_time (Bank_precharge) := NOW; + END IF; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(Bank_precharge) = '1' AND + Read_precharge(Bank_precharge) = '1' THEN + RW_interrupt_read(Bank_precharge) := '1'; + END IF; + END IF; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (CONV_INTEGER(Ba)) := '1'; + Count_precharge (CONV_INTEGER(Ba)) := 0; + Bank_precharge := (CONV_INTEGER(Ba)); + IF Read_enable = '1' THEN + Read_precharge (CONV_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (CONV_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_pipe_precharge(0) = Bank OR A10_pipe_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Turn off databus + IF (Data_out_enable = '0') THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := CONV_INTEGER (Row); + Col_index := CONV_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm = '0' THEN + -- Initialize memory + Init_mem (Bank, Row_index); + -- Write to memory + IF Bank = "00" THEN + Bank0 (Row_index) (Col_index) := Dq; + ELSIF Bank = "01" THEN + Bank1 (Row_index) (Col_index) := Dq; + ELSIF Bank = "10" THEN + Bank2 (Row_index) (Col_index) := Dq; + ELSIF Bank = "11" THEN + Bank3 (Row_index) (Col_index) := Dq; + END IF; + -- Reset tWR counter + WR_chkm(CONV_INTEGER(Bank)) := NOW; + END IF; + -- Decode next burst address + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg0 = '0' THEN + -- Initialize memory + Init_mem (Bank, Row_index); + -- Load memory into buffer + IF Bank = "00" THEN + Dq <= TRANSPORT Bank0 (Row_index) (Col_index) AFTER tAC; + ELSIF Bank = "01" THEN + Dq <= TRANSPORT Bank1 (Row_index) (Col_index) AFTER tAC; + ELSIF Bank = "10" THEN + Dq <= TRANSPORT Bank2 (Row_index) (Col_index) AFTER tAC; + ELSIF Bank = "11" THEN + Dq <= TRANSPORT Bank3 (Row_index) (Col_index) AFTER tAC; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - WR_chka(0) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - WR_chka(0) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - WR_chka(0) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - WR_chka(0) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND NOW - WR_time(0) >= tWRa)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + ASSERT FALSE REPORT "WRITE: Start Internal Precharge Bank 0" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - WR_chka(1) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - WR_chka(1) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - WR_chka(1) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - WR_chka(1) >= tWRa))) OR + (RW_interrupt_write(1) = '1' AND NOW - WR_time(1) >= tWRa)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + ASSERT FALSE REPORT "WRITE: Start Internal Precharge Bank 1" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - WR_chka(2) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - WR_chka(2) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - WR_chka(2) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - WR_chka(2) >= tWRa))) OR + (RW_interrupt_write(2) = '1' AND NOW - WR_time(2) >= tWRa)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + ASSERT FALSE REPORT "WRITE: Start Internal Precharge Bank 2" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - WR_chka(3) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - WR_chka(3) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - WR_chka(3) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - WR_chka(3) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND NOW - WR_time(3) >= tWRa)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + ASSERT FALSE REPORT "WRITE: Start Internal Precharge Bank 3" SEVERITY NOTE; + END IF; + END IF; + + -- DEBUG STUFF + Act_chk <= (Act_b3 & Act_b2 & Act_b1 & Act_b0); + Din_chk <= Data_in_enable; + Dout_chk <= Data_out_enable; + END PROCESS; + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "DQ Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc16m8a2/test.do b/lib/models/memory/sdram/mt48lc16m8a2/test.do new file mode 100644 index 0000000..56933bb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m8a2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc16m8a2.vhd +vcom test.vhd +vsim -t ps tb +do wave.do +run 800 ns diff --git a/lib/models/memory/sdram/mt48lc16m8a2/test.vhd b/lib/models/memory/sdram/mt48lc16m8a2/test.vhd new file mode 100644 index 0000000..77b42ce --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m8a2/test.vhd @@ -0,0 +1,313 @@ +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + +ENTITY tb IS +END tb; + +ARCHITECTURE test OF tb IS + COMPONENT mt48lc16m8a2 + GENERIC ( + tCK : TIME := 10 ns; + addr_bits : INTEGER := 12; + data_bits : INTEGER := 8 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '0'; + Ras_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC := '0' + ); + END COMPONENT; + + FOR ALL : mt48lc16m8a2 USE ENTITY work.mt48lc16m8a2 (behave); + + CONSTANT tCK : TIME := 10 ns; + CONSTANT addr_bits : INTEGER := 12; + CONSTANT data_bits : INTEGER := 8; + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs_n : STD_LOGIC; + SIGNAL pCas_n : STD_LOGIC; + SIGNAL pRas_n : STD_LOGIC; + SIGNAL pWe_n : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc16m8a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs_n, + Ras_n => pRas_n, + Cas_n => pCas_n, + We_n => pWe_n, + Dqm => pDqm + ); + + stimulator : PROCESS + PROCEDURE ACTIVE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '1'; + pWe_n <= '1'; + pDqm <= '0'; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE AUTO_REFRESH IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '0'; + pWe_n <= '1'; + pDqm <= '0'; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE BURST_TERM IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '1'; + pWe_n <= '0'; + pDqm <= '0'; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE LOAD_MODE_REG (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '0'; + pWe_n <= '0'; + pDqm <= '0'; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE NOP (Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '1'; + pWe_n <= '1'; + pDqm <= '0'; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE PRECHARGE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '1'; + pWe_n <= '0'; + pDqm <= '0'; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE READ (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '0'; + pWe_n <= '1'; + pDqm <= '0'; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + -- Write + PROCEDURE WRITE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '0'; + pWe_n <= '0'; + pDqm <= '0'; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + BEGIN + -- COMMAND BA ADDR DQ + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + -- We need 100 us power up sequence. I use 10 NOPs here as a required example. + PRECHARGE ("00", "010000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + AUTO_REFRESH; + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + AUTO_REFRESH; + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + LOAD_MODE_REG ("00", "000000100010"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + ACTIVE ("00", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + ACTIVE ("01", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + ACTIVE ("10", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + ACTIVE ("11", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + WRITE ("00", "000000000000", "00000000"); + NOP ( "00000001"); + NOP ( "00000010"); + NOP ( "00000011"); + + WRITE ("01", "000000000000", "00000100"); + NOP ( "00000101"); + NOP ( "00000110"); + NOP ( "00000111"); + + WRITE ("10", "000000000000", "00001000"); + NOP ( "00001001"); + NOP ( "00001010"); + NOP ( "00001011"); + + WRITE ("11", "000000000000", "00001100"); + NOP ( "00001101"); + NOP ( "00001110"); + NOP ( "00001111"); + + READ ("00", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + READ ("01", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + READ ("10", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + READ ("11", "000000000000", "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + NOP ( "ZZZZZZZZ"); + NOP ( "ZZZZZZZZ"); + + ASSERT false + REPORT "End of Stimulation Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for tCK/2; + WHILE not stim_done loop + pclk <= '1'; + WAIT for tCK/2; + pclk <= '0'; + WAIT for tCK/2; + END LOOP; + done_time := now + tCK; + WHILE now < done_time LOOP -- one last clock to finish last command + pclk <= '1'; + WAIT for tCK/2; + pclk <= '0'; + WAIT for tCK/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; +END test; diff --git a/lib/models/memory/sdram/mt48lc16m8a2/wave.do b/lib/models/memory/sdram/mt48lc16m8a2/wave.do new file mode 100644 index 0000000..14a4520 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc16m8a2/wave.do @@ -0,0 +1,39 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -format Logic /tb/u1/clk +add wave -noupdate -format Logic /tb/u1/cke +add wave -noupdate -format Logic /tb/u1/cs_n +add wave -noupdate -format Logic /tb/u1/ras_n +add wave -noupdate -format Logic /tb/u1/cas_n +add wave -noupdate -format Logic /tb/u1/we_n +add wave -noupdate -format Literal -radix decimal /tb/u1/addr +add wave -noupdate -format Literal -radix unsigned /tb/u1/ba +add wave -noupdate -format Literal -radix decimal /tb/u1/dq +add wave -noupdate -format Logic /tb/u1/dqm +add wave -noupdate -format Literal -radix decimal /tb/u1/operation +add wave -noupdate -format Literal -radix decimal /tb/u1/mode_reg +add wave -noupdate -format Logic /tb/u1/active_enable +add wave -noupdate -format Logic /tb/u1/aref_enable +add wave -noupdate -format Logic /tb/u1/burst_term +add wave -noupdate -format Logic /tb/u1/mode_reg_enable +add wave -noupdate -format Logic /tb/u1/prech_enable +add wave -noupdate -format Logic /tb/u1/read_enable +add wave -noupdate -format Logic /tb/u1/write_enable +add wave -noupdate -format Logic /tb/u1/burst_length_1 +add wave -noupdate -format Logic /tb/u1/burst_length_2 +add wave -noupdate -format Logic /tb/u1/burst_length_4 +add wave -noupdate -format Logic /tb/u1/burst_length_8 +add wave -noupdate -format Logic /tb/u1/cas_latency_2 +add wave -noupdate -format Logic /tb/u1/cas_latency_3 +add wave -noupdate -format Literal /tb/u1/act_chk +add wave -noupdate -format Logic /tb/u1/din_chk +add wave -noupdate -format Logic /tb/u1/dout_chk +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {320 ns} +WaveRestoreZoom {139586 ps} {454431 ps} +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 0 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 diff --git a/lib/models/memory/sdram/mt48lc1m16a1/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc1m16a1/ed_comnd.vhd new file mode 100644 index 0000000..7273327 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/ed_comnd.vhd @@ -0,0 +1,242 @@ +--------------------------------------------------------------------------------- +--COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit), first data(integer), dqm(bit), cke(bit));-- +-- read(column address(integer), bank(bit), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit), data bus (integer), dqm(bit), cke(bit));-- +-- precharge(bank(bit), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit), cs(bit)); -- +-- burst_term(data bus(integer), dqm(bit_vector), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +--------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, "00", '1', '1'); -- Always begin with one nop when using Micron's testbench + +FOR i IN 1 to 5 LOOP -- You will need 100 us for powerup. + next_cycle(clk); -- I used 5 here just for an example. + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +precharge('0', 1024, Z, "00", '1'); -- Precharge all banks + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; -- First auto refresh + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; -- Second auto refresh + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +load_mode_reg(51, '1'); -- Load mode register (lat=3, bl=8, mode=seq) + +FOR i IN 1 TO 2 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +-- Alternate bank write access + +next_cycle(clk); +active(0, '0', Z, "00", '1'); -- Activate Bank 0, Row 0 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +write(1024, '0', 100, "00", '1'); -- Write Bank 0, Col 0, Data 100 (auto precharge) + +next_cycle(clk); +nop (101, "00", '1', '1'); + +next_cycle(clk); +nop (102, "00", '1', '1'); + +next_cycle(clk); +nop (103, "00", '1', '1'); + +next_cycle(clk); +nop (104, "00", '1', '1'); + +next_cycle(clk); +active(0, '1', 105, "00", '1'); -- Activate Bank 1, Row 0 + +next_cycle(clk); +nop (106, "00", '1', '1'); + +next_cycle(clk); +nop (107, "00", '1', '1'); + +next_cycle(clk); +write(1024, '1', 200, "00", '1'); -- Write Bank 1, Col 0, Data 200 (auto precharge) + +next_cycle(clk); +nop (201, "00", '1', '1'); + +next_cycle(clk); +nop (202, "00", '1', '1'); + +next_cycle(clk); +nop (203, "00", '1', '1'); + +next_cycle(clk); +nop (204, "00", '1', '1'); + +next_cycle(clk); +active(0, '0', 205, "00", '1'); -- Activate Bank 0, Row 0 + +next_cycle(clk); +nop (206, "00", '1', '1'); + +next_cycle(clk); +nop (207, "00", '1', '1'); + +-- Alternate bank read access + +next_cycle(clk); +read(1024, '0', "00", '1'); -- Read Bank 0, Col 0 (auto precharge) + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +active(0, '1', Z, "00", '1'); -- Activate Bank 1, Row 0 + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +read(1024, '1', "00", '1'); -- Read Bank 1, Col 0 (auto precharge) + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop (Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc1m16a1/io_utils.vhd b/lib/models/memory/sdram/mt48lc1m16a1/io_utils.vhd new file mode 100644 index 0000000..dfcb84a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/io_utils.vhd @@ -0,0 +1,266 @@ +LIBRARY ieee; +USE std.textio.ALL; +USE ieee.std_logic_1164.ALL; + +PACKAGE io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0); + + TYPE radix IS (binary, octal, decimal, hex); + + -- read a number from the line + -- use this if you have hex numbers that are not in VHDL pound-sign format + PROCEDURE read(l : INOUT line; value : OUT integer; radix : IN positive); + + -- read a number that might be in VHDL pound-sign format + PROCEDURE read_based(l : INOUT line; value : OUT integer); + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); +END io_utils; + +PACKAGE BODY io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0) + IS + BEGIN + write(l, value, justified, field); + END; + + PROCEDURE shrink_line(l : INOUT line; pos : integer) IS + VARIABLE tmpl : line; + BEGIN + tmpl := l; + l := NEW string'(tmpl(pos TO tmpl'high)); + deallocate(tmpl); + END; + + PROCEDURE read(l : INOUT line; + value : OUT integer; + radix : IN positive) + IS + CONSTANT not_digit : integer := -999; + + -- convert a character to a value from 0 to 15 + FUNCTION digit_value(c : character) RETURN integer IS + BEGIN + IF (c >= '0') AND (c <= '9') THEN + RETURN (character'pos(c) - character'pos('0')); + ELSIF (c >= 'a') AND (c <= 'f') THEN + RETURN (character'pos(c) - character'pos('a') + 10); + ELSIF (c >= 'A') AND (c <= 'F') THEN + RETURN (character'pos(c) - character'pos('A') + 10); + ELSE + RETURN not_digit; + END IF; + END; + + -- skip leading white space in the line + PROCEDURE skip_white(VARIABLE l : IN line; pos : OUT integer) IS + BEGIN + pos := l'low; + FOR i IN l'low TO l'high LOOP + CASE l(i) IS + WHEN ' ' | ht => + pos := i + 1; + WHEN OTHERS => + EXIT; + END CASE; + END LOOP; + END; + + VARIABLE digit : integer; + VARIABLE result : integer := 0; + VARIABLE pos : integer; + BEGIN + -- skip white space + skip_white(l, pos); + + -- calculate the value + FOR i IN pos TO l'right LOOP + digit := digit_value(l(i)); + EXIT WHEN (digit = not_digit) OR (digit >= radix); + result := result * radix + digit; + pos := i + 1; + END LOOP; + value := result; + + -- remove the "used" characters from the line + shrink_line(l, pos); + END; + + PROCEDURE read_based(l : INOUT line; value : OUT integer) IS + VARIABLE digit : integer; + VARIABLE num : integer; + VARIABLE base : integer; + BEGIN + read(l, num, 10); + IF (l'length > 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + base := num; + read(l, num, base); + IF (l'length >= 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + END IF; + END IF; + value := num; + END; + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_int(bv : std_logic_vector) RETURN integer + IS + VARIABLE result : integer := 0; + BEGIN + FOR i IN bv'RANGE LOOP + result := result * 2; + IF (bv(i) = '1') THEN + result := result + 1; + END IF; + END LOOP; + RETURN result; + END; + + TYPE array_of_widths IS ARRAY(radix) OF natural; + CONSTANT nibble_widths : array_of_widths := ( + binary => 1, + octal => 3, + hex => 4, + decimal=> 32); + CONSTANT hex_digit : string(1 TO 16) := "0123456789ABCDEF"; + + ALIAS input_val : std_logic_vector(value'length DOWNTO 1) IS value; + CONSTANT nibble_width : natural := nibble_widths(base); + CONSTANT result_width : natural := (value'length + nibble_width - 1)/nibble_width; + + VARIABLE result : string(1 TO result_width); -- longest possible value + VARIABLE result_pos : positive := 1; + VARIABLE nibble_val : integer; + VARIABLE bitcnt : integer; + BEGIN + IF base = decimal THEN + write(l, to_int(value), justified, field, base, use_pound); + RETURN; + END IF; + + bitcnt := value'length MOD nibble_width; + IF (bitcnt = 0) THEN + bitcnt := nibble_width; + END IF; + FOR i IN input_val'RANGE LOOP + nibble_val := nibble_val * 2; + IF (input_val(i) = '1') THEN + nibble_val := nibble_val + 1; + END IF; + bitcnt := bitcnt - 1; + IF (bitcnt = 0) THEN + result(result_pos) := hex_digit(nibble_val + 1); + result_pos := result_pos + 1; + nibble_val := 0; + bitcnt := nibble_width; + END IF; + END LOOP; + write(l, result, justified, field); + END; + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_bv(int : integer) RETURN std_logic_vector + IS + VARIABLE bv : std_logic_vector(32 DOWNTO 1) := (OTHERS => '0'); + VARIABLE pos : integer := 0; + VARIABLE tmpval : integer := int; + BEGIN + FOR i IN 1 TO 32 LOOP + pos := pos + 1; + IF (tmpval MOD 2) = 1 THEN + bv(i) := '1'; + END IF; + tmpval := tmpval / 2; + EXIT WHEN tmpval = 0; + END LOOP; + RETURN bv(pos DOWNTO 1); + END; + + VARIABLE tmp : line; + BEGIN + IF (base = decimal) THEN + IF (use_pound) THEN + write_string(tmp, "10#"); + END IF; + write(tmp, value); + IF (use_pound) THEN + write_string(tmp, "#"); + END IF; + write(l, tmp.ALL, justified, field); + deallocate(tmp); + ELSE + write(l, to_bv(value), justified, field, base, use_pound); + END IF; + END; + +END io_utils; + + + +-- test the hex number reader +--ENTITY test IS END; + +--USE std.textio.ALL; +--USE work.io_utils.ALL; +--ARCHITECTURE hex_test OF test IS +--BEGIN +-- PROCESS +-- VARIABLE val : integer; +-- FILE myfile : text IS IN "values"; +-- VARIABLE inline : line; +-- VARIABLE outline : line; +-- BEGIN +-- WHILE NOT endfile(myfile) LOOP +-- readline(myfile, inline); + +-- write(outline, inline.ALL); +-- +-- read_based(inline, val); + -- write_string(outline, " binary: "); + -- write(outline, val, base => binary); + -- write_string(outline, " octal: "); + -- write(outline, val, base => octal); + -- write_string(outline, " decimal: "); + -- write(outline, val, base => decimal); +-- write_string(outline, " hex: "); +-- write(outline, val, base => hex); +-- writeline(output, outline); +-- END LOOP; +-- WAIT; +-- END PROCESS; +--END; + + diff --git a/lib/models/memory/sdram/mt48lc1m16a1/mt48lc1m16a1.vhd b/lib/models/memory/sdram/mt48lc1m16a1/mt48lc1m16a1.vhd new file mode 100644 index 0000000..6b7b1f1 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/mt48lc1m16a1.vhd @@ -0,0 +1,907 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC1M18A1.VHD +-- Version: 0.0c +-- Date: April 20th, 1999 +-- Model: Behavioral +-- Simulator: Model Technology VLOG (PC version 5.2e PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC1M16A1 (512k x 16 x 2 Banks) +-- +-- Description: Micron 16Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0c Son P. Huynh 208-368-3825 04/20/1999 Fix precharge to different bank +-- Micron Technology Inc. terminate current bank +-- +-- 0.0b Son P. Huynh 208-368-3825 12/09/1998 Fix some timing check problem +-- Micron Technology Inc. - Improve model functionality +-- +-- 0.0a Son P. Huynh 208-368-3825 08/10/1998 First Release +-- Micron Technology Inc. - Simple testbench included +----------------------------------------------------------------------------------------- + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; +USE WORK.mti_pkg.ALL; + +ENTITY mt48lc1m16a1 IS + GENERIC ( + tAC : TIME := 6.0 ns; -- Timing parameter for -10 device + tAH : TIME := 1.0 ns; + tAS : TIME := 3.0 ns; + tCH : TIME := 3.5 ns; + tCL : TIME := 3.5 ns; + tCK : TIME := 10.0 ns; + tDH : TIME := 1.0 ns; + tDS : TIME := 3.0 ns; + tCKH : TIME := 1.0 ns; + tCKS : TIME := 3.0 ns; + tCMH : TIME := 1.0 ns; + tCMS : TIME := 3.0 ns; + tOH : TIME := 2.5 ns; + tHZ : TIME := 6.0 ns; + tMRD : INTEGER := 2; + tRAS : TIME := 60.0 ns; + tRC : TIME := 90.0 ns; + tRCD : TIME := 30.0 ns; + tRP : TIME := 30.0 ns; + tRRD : TIME := 20.0 ns; + tWR : INTEGER := 1; + addr_bits : INTEGER := 11; + data_bits : INTEGER := 16; + col_bits : INTEGER := 8 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC := '0'; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00" + ); +END mt48lc1m16a1; + +ARCHITECTURE behave OF mt48lc1m16a1 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A); + TYPE Array2xI IS ARRAY (1 DOWNTO 0) OF INTEGER; + TYPE Array2xB IS ARRAY (1 DOWNTO 0) OF BIT; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array2x2BV IS ARRAY (1 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array4xCBV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (3 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_1, Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL Sys_clk, CkeZ : BIT := '0'; + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Act_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT := '0'; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_1 <= NOT(Mode_reg(6)) AND NOT(Mode_reg(5)) AND Mode_reg(4); + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4xB; + VARIABLE Dqm_reg : Array2x2BV; + + VARIABLE Bank, Previous_bank : BIT := '0'; + VARIABLE B0_row_addr, B1_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE A10_precharge, Bank_precharge : Array4xB; + VARIABLE Auto_precharge, Read_precharge, Write_precharge : Array2xB; + VARIABLE Count_precharge : Array2xI; + VARIABLE RW_interrupt_write : BIT := '0'; + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1 : BIT := '0'; + VARIABLE Act_b0, Act_b1 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1 : TIME := 0 ns; + VARIABLE RP_chk, RP_chk0, RP_chk1 : TIME := 0 ns; + VARIABLE WR_chk : Array2xI := (0 & 0); + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT; Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = '0' THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = '1' THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk; + IF Sys_clk = '1' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := '0'; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := '0'; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg(0) := Dqm_reg(1); + Dqm_reg(1) := TO_BITVECTOR(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_chk(0) := WR_chk(0) + 1; + WR_chk(1) := WR_chk(1) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- Banks must be idle before Refresh + IF Pc_b1 = '0' OR Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b0 /= '1' OR Pc_b1 /= '1') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = '0' AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = '1' AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = '0' AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = '1' AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF (Previous_bank /= TO_BIT(Ba)) AND (NOW - RRD_chk < tRRD) THEN + ASSERT (FALSE) + REPORT "tRRD violation during activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record current Bank and RRD_chk + Previous_bank := TO_BIT(Ba); + RRD_chk := NOW; + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((WR_chk(0) < tWR) AND (WR_chk(1) < tWR)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge all banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = '0' THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = '1' THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + IF (WR_chk(TO_INTEGER(Ba)) < tWR) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + END IF; + + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BIT(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BIT (Ba); + A10_precharge(2) := TO_BIT (Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BIT (Ba); + A10_precharge(1) := TO_BIT (Addr(10)); + ELSIF CAS_latency_1 = '1' THEN + Command(0) := PRECH; + Bank_precharge(0) := TO_BIT (Ba); + A10_precharge(0) := TO_BIT (Addr(10)); + END IF; + -- Record Precharge Bank and Current tRP time + RP_chk := NOW; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + ELSIF CAS_latency_1 = '1' THEN + Command(0) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = '0' AND Pc_b0 = '1') OR (Ba = '1' AND Pc_b1 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = '0' THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = '1' THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- Read Terminate a Write Immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + RW_interrupt_write := '1'; + END IF; + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (2) := TO_BIT (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (1) := TO_BIT (Ba); + ELSIF Cas_latency_1 = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := READ_A; + ELSE + Command(0) := READ; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (0) := TO_BIT (Ba); + END IF; + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (0) := TO_BIT (Ba); + IF Data_in_enable = '1' THEN + RW_interrupt_write := '1'; + END IF; + END IF; + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + ((Read_enable = '1' OR Write_enable = '1') AND Count_precharge(0) >= 1)) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + Write_precharge(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + ((Read_enable = '1' OR Write_enable = '1') AND Count_precharge(1) >= 1)) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + Write_precharge(1) := '0'; + END IF; + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_write = '1' AND WR_chk(0) >= 1)) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_write = '1' AND WR_chk(1) >= 1)) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = '0' THEN + Row := B0_row_addr; + ELSE + Row := B1_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = '0' THEN + Row := B0_row_addr; + ELSE + Row := B1_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = '0' THEN + Dq_temp := Bank0 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank0 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = '1' THEN + Dq_temp := Bank1 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank1 (Row_index) (Col_index) := Dq_temp; + END IF; + WR_chk(TO_INTEGER(Bank)) := 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + Init_mem (Bank, Row_index); + IF Bank = '0' THEN + Dq_temp (15 DOWNTO 0) := Bank0 (Row_index) (Col_index); + IF Dqm_reg(0) = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg(0) = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg(0) = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + ELSIF Bank = '1' THEN + Dq_temp (15 DOWNTO 0) := Bank1 (Row_index) (Col_index); + IF Dqm_reg(0) = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg(0) = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg(0) = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + END IF; + Burst_decode; + END IF; + + -- Checking internal wires + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END IF; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "DQ Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc1m16a1/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc1m16a1/mti_pkg.vhd new file mode 100644 index 0000000..58cbbcd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/mti_pkg.vhd @@ -0,0 +1,143 @@ +--***************************************************************************** +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +--***************************************************************************** + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION TO_INTEGER (input : BIT) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + -- Convert BIT to INTEGER + FUNCTION TO_INTEGER (input : BIT) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert BIT_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Conver integer to bit_vector + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc1m16a1/readme.txt b/lib/models/memory/sdram/mt48lc1m16a1/readme.txt new file mode 100644 index 0000000..141be5c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/readme.txt @@ -0,0 +1,14 @@ +To operate the test bench for the Micron SDRAM VHDL model, follow the directions +given below: + +1. Be sure all supporting files for the SDRAM are compiled into your library: + + util1164.vhd + stdlogar.vhd + io_utils.vhd + mti_pkg.vhd + +2. Next, compile the mt48lc1m16a1.vhd file and the test.vhd file. + +3. Simulate the "tb" architecture. This is the testbench for the SDRAM. + diff --git a/lib/models/memory/sdram/mt48lc1m16a1/stdlogar.vhd b/lib/models/memory/sdram/mt48lc1m16a1/stdlogar.vhd new file mode 100644 index 0000000..e435ea2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/stdlogar.vhd @@ -0,0 +1,2247 @@ +-------------------------------------------------------------------------- +-- -- +-- Copyright (c) 1990,1991,1992 by Synopsys, Inc. All rights reserved. -- +-- -- +-- This source file may be used and distributed without restriction -- +-- provided that this copyright statement is not removed from the file -- +-- and that any derivative work contains this copyright notice. -- +-- -- +-- Package name: STD_LOGIC_ARITH -- +-- -- +-- Purpose: -- +-- A set of arithemtic, conversion, and comparison functions -- +-- for SIGNED, UNSIGNED, SMALL_INT, INTEGER, -- +-- STD_ULOGIC, STD_LOGIC, and STD_LOGIC_VECTOR. -- +-- -- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; + +package std_logic_arith is + + type UNSIGNED is array (NATURAL range <>) of STD_LOGIC; + type SIGNED is array (NATURAL range <>) of STD_LOGIC; + subtype SMALL_INT is INTEGER range 0 to 1; + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: INTEGER) return SIGNED; + function "+"(L: INTEGER; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: INTEGER) return SIGNED; + function "-"(L: INTEGER; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "+"(L: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED) return SIGNED; + function "-"(L: SIGNED) return SIGNED; + function "ABS"(L: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED) return STD_LOGIC_VECTOR; + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "*"(L: SIGNED; R: SIGNED) return SIGNED; + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + + function CONV_INTEGER(ARG: INTEGER) return INTEGER; + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER; + function CONV_INTEGER(ARG: SIGNED) return INTEGER; + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT; + + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED; + + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED; + + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + -- zero extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- returns STD_LOGIC_VECTOR(SIZE-1 downto 0) + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + + -- sign extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- return STD_LOGIC_VECTOR(SIZE-1 downto 0) + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + +end Std_logic_arith; + + + +library IEEE; +use IEEE.std_logic_1164.all; + +package body std_logic_arith is + + function max(L, R: INTEGER) return INTEGER is + begin + if L > R then + return L; + else + return R; + end if; + end; + + + function min(L, R: INTEGER) return INTEGER is + begin + if L < R then + return L; + else + return R; + end if; + end; + + -- synopsys synthesis_off + type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; + constant tbl_BINARY : tbl_type := + ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); + -- synopsys synthesis_on + + -- synopsys synthesis_off + type tbl_mvl9_boolean is array (STD_ULOGIC) of boolean; + constant IS_X : tbl_mvl9_boolean := + (true, true, false, false, true, true, false, false, true); + -- synopsys synthesis_on + + + + function MAKE_BINARY(A : STD_ULOGIC) return STD_ULOGIC is + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + if (IS_X(A)) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + return ('X'); + end if; + return tbl_BINARY(A); + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + + + -- Type propagation function which returns a signed type with the + -- size of the left arg. + function LEFT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the left arg. + function LEFT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns a signed type with the + -- size of the result of a signed multiplication + function MULT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the result of a unsigned multiplication + function MULT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + + + function mult(A,B: SIGNED) return SIGNED is + + variable BA: SIGNED((A'length+B'length-1) downto 0); + variable PA: SIGNED((A'length+B'length-1) downto 0); + variable AA: SIGNED(A'length downto 0); + variable neg: STD_ULOGIC; + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_TC_OP + -- pragma type_function MULT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + neg := B(B'left) xor A(A'left); + BA := CONV_SIGNED(('0' & ABS(B)),(A'length+B'length)); + AA := '0' & ABS(A); + for i in 0 to A'length-1 loop + if AA(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + if (neg= '1') then + return(-PA); + else + return(PA); + end if; + end; + + function mult(A,B: UNSIGNED) return UNSIGNED is + + variable BA: UNSIGNED((A'length+B'length-1) downto 0); + variable PA: UNSIGNED((A'length+B'length-1) downto 0); + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_UNS_OP + -- pragma type_function MULT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + BA := CONV_UNSIGNED(B,(A'length+B'length)); + for i in 0 to A'length-1 loop + if A(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + return(PA); + end; + + -- subtract two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function minus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_TC_OP + + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function plus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_TC_OP + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + -- subtract two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_minus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + + function "*"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1)); -- pragma label mult + end; + + + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1))); -- pragma label mult + end; + + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + + + function "+"(L: UNSIGNED) return UNSIGNED is + begin + return L; + end; + + + function "+"(L: SIGNED) return SIGNED is + begin + return L; + end; + + + function "-"(L: SIGNED) return SIGNED is + -- pragma label_applies_to minus + begin + return 0 - L; -- pragma label minus + end; + + + function "ABS"(L: SIGNED) return SIGNED is + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return L; + else + return 0 - L; + end if; + end; + + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "+"(L: SIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "-"(L: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + variable tmp: SIGNED(L'length-1 downto 0); + begin + tmp := 0 - L; -- pragma label minus + return STD_LOGIC_VECTOR (tmp); + end; + + + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR is + variable tmp: SIGNED(L'length-1 downto 0); + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return STD_LOGIC_VECTOR (L); + else + tmp := 0 - L; + return STD_LOGIC_VECTOR (tmp); + end if; + end; + + + -- Type propagation function which returns the type BOOLEAN + function UNSIGNED_RETURN_BOOLEAN(A,B: UNSIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns the type BOOLEAN + function SIGNED_RETURN_BOOLEAN(A,B: SIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := FALSE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less_or_equal(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := TRUE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := FALSE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less_or_equal(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := TRUE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_eql(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_EQL + begin + for i in L'range loop + if L(i) /= R(i) then + return FALSE; + end if; + end loop; + return TRUE; + end; + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_neq(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_NEQ + begin + for i in L'range loop + if L(i) /= R(i) then + return TRUE; + end if; + end loop; + return FALSE; + end; + + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + variable sign_bit: STD_ULOGIC; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + sign_bit := ARG(ARG'left); + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => sign_bit); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + + + function CONV_INTEGER(ARG: INTEGER) return INTEGER is + begin + return ARG; + end; + + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_UNSIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 31 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: SIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_SIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 32 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + if i /= ARG'left then + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end if; + end loop; + tmp := MAKE_BINARY(ARG(ARG'left)); + if tmp = '1' then + if ARG'length = 32 then + result := (result - 2**30) - 2**30; + else + result := result - (2 ** (ARG'length-1)); + end if; + end if; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT is + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + tmp := tbl_BINARY(ARG); + if tmp = '1' then + return 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + return 0; + else + return 0; + end if; + -- synopsys synthesis_on + end; + + + -- convert an integer to a unsigned STD_ULOGIC_VECTOR + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED is + variable result: UNSIGNED(SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_UNSIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED is + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to a 2's complement STD_ULOGIC_VECTOR + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED is + variable result: SIGNED (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED is + subtype rtype is SIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to an STD_LOGIC_VECTOR + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is + variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) return STD_LOGIC_VECTOR is + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) + return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds: STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + +end std_logic_arith; diff --git a/lib/models/memory/sdram/mt48lc1m16a1/test.txt b/lib/models/memory/sdram/mt48lc1m16a1/test.txt new file mode 100644 index 0000000..75ed4c6 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/test.txt @@ -0,0 +1,69 @@ +0 ns 1 1 1 1 1 00 0 0 -100 +22 ns 1 1 1 1 1 00 0 0 -100 +32 ns 1 1 1 1 1 00 0 0 -100 +42 ns 1 1 1 1 1 00 0 0 -100 +52 ns 1 1 1 1 1 00 0 0 -100 +62 ns 1 1 1 1 1 00 0 0 -100 +72 ns 1 0 0 1 0 00 0 1024 -100 +82 ns 1 1 1 1 1 00 0 0 -100 +92 ns 1 1 1 1 1 00 0 0 -100 +102 ns 1 0 0 0 1 00 0 0 -100 +112 ns 1 1 1 1 1 00 0 0 -100 +122 ns 1 1 1 1 1 00 0 0 -100 +132 ns 1 1 1 1 1 00 0 0 -100 +142 ns 1 1 1 1 1 00 0 0 -100 +152 ns 1 1 1 1 1 00 0 0 -100 +162 ns 1 1 1 1 1 00 0 0 -100 +172 ns 1 1 1 1 1 00 0 0 -100 +182 ns 1 1 1 1 1 00 0 0 -100 +192 ns 1 0 0 0 1 00 0 0 -100 +202 ns 1 1 1 1 1 00 0 0 -100 +212 ns 1 1 1 1 1 00 0 0 -100 +222 ns 1 1 1 1 1 00 0 0 -100 +232 ns 1 1 1 1 1 00 0 0 -100 +242 ns 1 1 1 1 1 00 0 0 -100 +252 ns 1 1 1 1 1 00 0 0 -100 +262 ns 1 1 1 1 1 00 0 0 -100 +272 ns 1 1 1 1 1 00 0 0 -100 +282 ns 1 0 0 0 0 00 0 51 -100 +292 ns 1 1 1 1 1 00 0 0 -100 +302 ns 1 1 1 1 1 00 0 0 -100 +312 ns 1 0 0 1 1 00 0 0 -100 +322 ns 1 1 1 1 1 00 0 0 -100 +332 ns 1 1 1 1 1 00 0 0 -100 +342 ns 1 0 1 0 0 00 0 1024 100 +352 ns 1 1 1 1 1 00 0 0 101 +362 ns 1 1 1 1 1 00 0 0 102 +372 ns 1 1 1 1 1 00 0 0 103 +382 ns 1 1 1 1 1 00 0 0 104 +392 ns 1 0 0 1 1 00 1 0 105 +402 ns 1 1 1 1 1 00 0 0 106 +412 ns 1 1 1 1 1 00 0 0 107 +422 ns 1 0 1 0 0 00 1 1024 200 +432 ns 1 1 1 1 1 00 0 0 201 +442 ns 1 1 1 1 1 00 0 0 202 +452 ns 1 1 1 1 1 00 0 0 203 +462 ns 1 1 1 1 1 00 0 0 204 +472 ns 1 0 0 1 1 00 0 0 205 +482 ns 1 1 1 1 1 00 0 0 206 +492 ns 1 1 1 1 1 00 0 0 207 +502 ns 1 0 1 0 1 00 0 1024 -100 +512 ns 1 1 1 1 1 00 0 0 -100 +522 ns 1 1 1 1 1 00 0 0 -100 +532 ns 1 1 1 1 1 00 0 0 -100 +542 ns 1 1 1 1 1 00 0 0 -100 +552 ns 1 0 0 1 1 00 1 0 -100 +562 ns 1 1 1 1 1 00 0 0 -100 +572 ns 1 1 1 1 1 00 0 0 -100 +582 ns 1 0 1 0 1 00 1 1024 -100 +592 ns 1 1 1 1 1 00 0 0 -100 +602 ns 1 1 1 1 1 00 0 0 -100 +612 ns 1 1 1 1 1 00 0 0 -100 +622 ns 1 1 1 1 1 00 0 0 -100 +632 ns 1 1 1 1 1 00 0 0 -100 +642 ns 1 1 1 1 1 00 0 0 -100 +652 ns 1 1 1 1 1 00 0 0 -100 +662 ns 1 1 1 1 1 00 0 0 -100 +672 ns 1 1 1 1 1 00 0 0 -100 +682 ns 1 1 1 1 1 00 0 0 -100 +692 ns 1 1 1 1 1 00 0 0 -100 diff --git a/lib/models/memory/sdram/mt48lc1m16a1/test.vhd b/lib/models/memory/sdram/mt48lc1m16a1/test.vhd new file mode 100644 index 0000000..53a8a7a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/test.vhd @@ -0,0 +1,168 @@ +LIBRARY ieee; +LIBRARY work; +USE ieee.std_logic_1164.ALL; +USE work.std_logic_arith.ALL; +USE work.util_1164.ALL; +USE std.textio.ALL; +USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 11; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + CONSTANT data_bits : INTEGER := 16; + + COMPONENT mt48lc1m16a1 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC := '0'; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '0'; + Ras_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00" + ); + END COMPONENT; + + FOR ALL : mt48lc1m16a1 USE ENTITY work.mt48lc1m16a1 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC; + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + +BEGIN + u1: mt48lc1m16a1 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : STD_LOGIC; + VARIABLE pCs_var : STD_LOGIC; + VARIABLE pRas_var : STD_LOGIC; + VARIABLE PCas_var : STD_LOGIC; + VARIABLE pWe_var : STD_LOGIC; + VARIABLE pDqm_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pBa_var : STD_LOGIC; + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read(l, time_var); + read(l, pCke_var); + read(l, pCs_var); + read(l, pRas_var); + read(l, pCas_var); + read(l, pWe_var); + read(l, pDqm_var); + read(l, pBa_var); + read(l, pAddr_var); + read(l, pDq_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + IF pWe_var='1' THEN + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + ELSE + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + END IF; + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc1m16a1/util1164.vhd b/lib/models/memory/sdram/mt48lc1m16a1/util1164.vhd new file mode 100644 index 0000000..bb4b5dd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/util1164.vhd @@ -0,0 +1,124 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE STD.textio.ALL; + +PACKAGE util_1164 IS + PROCEDURE read(l: INOUT line; value: OUT std_logic); + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector); + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0); + PROCEDURE Grow_line(L : inout LINE; incr : in integer); +END util_1164; + + + +PACKAGE BODY util_1164 IS + + FUNCTION white_space(value:character) RETURN boolean IS + VARIABLE result:boolean; + BEGIN + IF (value = ' ') OR (value = HT) THEN + RETURN true; + ELSE + RETURN false; + END IF; + END white_space; + + PROCEDURE read(l: INOUT line; value: OUT std_logic) IS + VARIABLE char_var: character:= ' '; + BEGIN + WHILE l'LENGTH > 0 LOOP + read(l,char_var); + IF NOT white_space(char_var) THEN + EXIT; + END IF; + END LOOP; + IF white_space(char_var) THEN + ASSERT false REPORT "No std_logic value found in file" + SEVERITY error; + value := 'X'; + RETURN; + END IF; + + CASE char_var IS + WHEN 'U'|'u' => value := 'U'; + WHEN '0' => value := '0'; + WHEN '1' => value := '1'; + WHEN 'X'|'x' => value := 'X'; + WHEN 'L'|'l' => value := 'L'; + WHEN 'H'|'h' => value := 'H'; + WHEN 'W'|'w' => value := 'W'; + WHEN 'Z'|'z' => value := 'Z'; + WHEN '-' => value := '-'; + WHEN OTHERS => + ASSERT false REPORT "Unrecognized value read for std_logic" + SEVERITY error; + value := 'X'; + END CASE; + END read; + + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector) IS + BEGIN + FOR i IN value'HIGH DOWNTO value'LOW LOOP + IF l'LENGTH > 0 THEN + read(l,value(i)); + ELSE + ASSERT false REPORT "Not enough values for std_logic_vector in file" + SEVERITY error; + RETURN; + END IF; + END LOOP; + END read; + + procedure Grow_line(L : inout LINE; incr : in integer) + is + variable old_L : LINE := L; + variable bfp: integer; -- Blank fill pointer. + begin + assert incr > 0 + report "Textio: Grow_line called with zero increment." + severity error; + + if L = null then + bfp := 0; + L := new string(1 to incr); + else + bfp := old_L'high; + L := new string(old_L'low to old_L'high + incr); + L(old_L'low to old_L'high) := old_L.all; + Deallocate(old_L); + end if; + for i in 1 to incr loop + L(bfp + i) := ' '; + end loop; + end; + + + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0) IS + variable fw: integer := VALUE'length; + variable bp: integer; + variable offset: integer := 0; + alias normal : std_logic_vector(0 to value'length - 1) is value; + begin + if L /= null then + bp := L'high + 1; + else bp := 1; + end if; + if FIELD > VALUE'length then + fw := FIELD; + if JUSTIFIED = right then + offset := fw - VALUE'length; + end if; + end if; + Grow_line(L, fw); + for i in normal'range loop + L(bp + i + offset) := character'val( + std_logic'pos(normal(i)) + character'pos('0')); + end loop; + end; + + +END util_1164; diff --git a/lib/models/memory/sdram/mt48lc1m16a1/vec_gen.vhd b/lib/models/memory/sdram/mt48lc1m16a1/vec_gen.vhd new file mode 100644 index 0000000..784fe26 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc1m16a1/vec_gen.vhd @@ -0,0 +1,369 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.io_utils.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write(col_address : IN INTEGER; bank : IN BIT; + first_data : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE read(col_address : IN INTEGER; bank : IN BIT; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE active(row_address : IN INTEGER; bank : IN BIT; data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE precharge(bank : IN BIT; address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT; cs : IN BIT); + PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle(SIGNAL clk : IN BIT); + PROCEDURE load_array(load : IN BIT); + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT); + +END generate_vectors; + + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT; first_data : IN INTEGER; + dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, first_data, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT; data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, row_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE precharge(bank : IN BIT; address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT; cs : IN BIT) IS + + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT := '0'; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, cs, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, 0, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, 0, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + --write(l, 0, right, 4); --load + --write(l, 0, right, 4); --unload + --write(l, 0, right, 6); --row_address_start + --write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS + +BEGIN + +WAIT UNTIL clk = '1'; + +END; + +PROCEDURE load_array(load : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, 0, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 1, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 1, right, 4); --unload +--write(l, row_start, right, 6); --row_address_start +--write(l, row_end, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, 0, right, 4); --Ba +write(l, op_code, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc32m4a2/base.do b/lib/models/memory/sdram/mt48lc32m4a2/base.do new file mode 100644 index 0000000..d2afbcb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/base.do @@ -0,0 +1,5 @@ +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd + diff --git a/lib/models/memory/sdram/mt48lc32m4a2/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc32m4a2/ed_comnd.vhd new file mode 100644 index 0000000..bd59d3c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/ed_comnd.vhd @@ -0,0 +1,345 @@ +--------------------------------------------------------------------------------- +--COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit_vector), first data(integer), dqm(bit), cke(bit));-- +-- read(column address(integer), bank(bit_vector), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit_vector), data bus (integer), dqm(bit), cke(bit));-- +-- precharge(bank(bit_vector), address (integer), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit), cs(bit)); -- +-- burst_term(data bus(integer), dqm(bit), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit_vector)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +--------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, '0', '1', '1'); --Always begin with one nop when using Micron's testbench + +--next_cycle(clk); +--load_array('1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +precharge("00", 1024, Z, '0', '1'); + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, '0', '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, '0', '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, '0', '1', '1'); +END LOOP; + +next_cycle(clk); +load_mode_reg(51, '1'); -- 19 / 35 / 51 -> lat=3,bl=8,mode=seq + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +-- Write Section + +next_cycle(clk); +active(0, "00", Z, '0', '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); -- Write Bank 0 +write(10, "00", 0, '0', '1'); + +next_cycle(clk); +nop(1, '0', '1', '1'); + +next_cycle(clk); +active(0, "01", 2, '0', '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(3, '0', '1', '1'); + +next_cycle(clk); +nop(4, '0', '1', '1'); + +next_cycle(clk); +nop(5, '0', '1', '1'); + +next_cycle(clk); +nop(6, '0', '1', '1'); + +next_cycle(clk); +nop(7, '0', '1', '1'); + +next_cycle(clk); +write(20, "01", 8, '0', '1'); -- Write Bank 1 + +next_cycle(clk); +precharge("00", 0, 9, '0', '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", 10, '0', '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(11, '0', '1', '1'); + +next_cycle(clk); +nop(12, '0', '1', '1'); + +next_cycle(clk); +nop(13, '0', '1', '1'); + +next_cycle(clk); +nop(14, '0', '1', '1'); + +next_cycle(clk); +nop(15, '0', '1', '1'); + +next_cycle(clk); +write(30, "10", 0, '0', '1'); -- Write Bank 2 + +next_cycle(clk); +precharge("01", 0, 1, '0', '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", 2, '0', '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(3, '0', '1', '1'); + +next_cycle(clk); +nop(4, '0', '1', '1'); + +next_cycle(clk); +nop(5, '0', '1', '1'); + +next_cycle(clk); +nop(6, '0', '1', '1'); + +next_cycle(clk); +nop(7, '0', '1', '1'); + +next_cycle(clk); +write(40, "11", 8, '0', '1'); -- Write Bank 3 + +next_cycle(clk); +precharge("10", 0, 9, '0', '1'); -- Precharge Bank 2 + +next_cycle(clk); +active(0, "00", 10, '0', '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(11, '0', '1', '1'); + +next_cycle(clk); +nop(12, '0', '1', '1'); + +next_cycle(clk); +nop(13, '0', '1', '1'); + +next_cycle(clk); +nop(14, '0', '1', '1'); + +next_cycle(clk); +nop(15, '0', '1', '1'); + +-- Read Section + +next_cycle(clk); +read(10, "00", '0', '1'); -- Read Bank 0 + +next_cycle(clk); +precharge("11", 0, Z, '0', '1'); -- Precharge Bank 3 + +next_cycle(clk); +active(0, "01", Z, '0', '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +read(20, "01", '0', '1'); -- Read Bank 1 + +next_cycle(clk); +precharge("00", 0, Z, '0', '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", Z, '0', '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +read(30, "10", '0', '1'); -- Read Bank 2 + +next_cycle(clk); +precharge("01", 0, Z, '0', '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", Z, '0', '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +read(40, "11", '0', '1'); -- Read Bank 3 + +next_cycle(clk); +precharge("10", 0, Z, '0', '1'); -- Precharge Bank 2 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +precharge("11", 0, Z, '0', '1'); -- Precharge Bank 3 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +--next_cycle(clk); +--unload_array(0, 0, '0'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc32m4a2/io_utils.vhd b/lib/models/memory/sdram/mt48lc32m4a2/io_utils.vhd new file mode 100644 index 0000000..dfcb84a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/io_utils.vhd @@ -0,0 +1,266 @@ +LIBRARY ieee; +USE std.textio.ALL; +USE ieee.std_logic_1164.ALL; + +PACKAGE io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0); + + TYPE radix IS (binary, octal, decimal, hex); + + -- read a number from the line + -- use this if you have hex numbers that are not in VHDL pound-sign format + PROCEDURE read(l : INOUT line; value : OUT integer; radix : IN positive); + + -- read a number that might be in VHDL pound-sign format + PROCEDURE read_based(l : INOUT line; value : OUT integer); + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); +END io_utils; + +PACKAGE BODY io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0) + IS + BEGIN + write(l, value, justified, field); + END; + + PROCEDURE shrink_line(l : INOUT line; pos : integer) IS + VARIABLE tmpl : line; + BEGIN + tmpl := l; + l := NEW string'(tmpl(pos TO tmpl'high)); + deallocate(tmpl); + END; + + PROCEDURE read(l : INOUT line; + value : OUT integer; + radix : IN positive) + IS + CONSTANT not_digit : integer := -999; + + -- convert a character to a value from 0 to 15 + FUNCTION digit_value(c : character) RETURN integer IS + BEGIN + IF (c >= '0') AND (c <= '9') THEN + RETURN (character'pos(c) - character'pos('0')); + ELSIF (c >= 'a') AND (c <= 'f') THEN + RETURN (character'pos(c) - character'pos('a') + 10); + ELSIF (c >= 'A') AND (c <= 'F') THEN + RETURN (character'pos(c) - character'pos('A') + 10); + ELSE + RETURN not_digit; + END IF; + END; + + -- skip leading white space in the line + PROCEDURE skip_white(VARIABLE l : IN line; pos : OUT integer) IS + BEGIN + pos := l'low; + FOR i IN l'low TO l'high LOOP + CASE l(i) IS + WHEN ' ' | ht => + pos := i + 1; + WHEN OTHERS => + EXIT; + END CASE; + END LOOP; + END; + + VARIABLE digit : integer; + VARIABLE result : integer := 0; + VARIABLE pos : integer; + BEGIN + -- skip white space + skip_white(l, pos); + + -- calculate the value + FOR i IN pos TO l'right LOOP + digit := digit_value(l(i)); + EXIT WHEN (digit = not_digit) OR (digit >= radix); + result := result * radix + digit; + pos := i + 1; + END LOOP; + value := result; + + -- remove the "used" characters from the line + shrink_line(l, pos); + END; + + PROCEDURE read_based(l : INOUT line; value : OUT integer) IS + VARIABLE digit : integer; + VARIABLE num : integer; + VARIABLE base : integer; + BEGIN + read(l, num, 10); + IF (l'length > 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + base := num; + read(l, num, base); + IF (l'length >= 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + END IF; + END IF; + value := num; + END; + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_int(bv : std_logic_vector) RETURN integer + IS + VARIABLE result : integer := 0; + BEGIN + FOR i IN bv'RANGE LOOP + result := result * 2; + IF (bv(i) = '1') THEN + result := result + 1; + END IF; + END LOOP; + RETURN result; + END; + + TYPE array_of_widths IS ARRAY(radix) OF natural; + CONSTANT nibble_widths : array_of_widths := ( + binary => 1, + octal => 3, + hex => 4, + decimal=> 32); + CONSTANT hex_digit : string(1 TO 16) := "0123456789ABCDEF"; + + ALIAS input_val : std_logic_vector(value'length DOWNTO 1) IS value; + CONSTANT nibble_width : natural := nibble_widths(base); + CONSTANT result_width : natural := (value'length + nibble_width - 1)/nibble_width; + + VARIABLE result : string(1 TO result_width); -- longest possible value + VARIABLE result_pos : positive := 1; + VARIABLE nibble_val : integer; + VARIABLE bitcnt : integer; + BEGIN + IF base = decimal THEN + write(l, to_int(value), justified, field, base, use_pound); + RETURN; + END IF; + + bitcnt := value'length MOD nibble_width; + IF (bitcnt = 0) THEN + bitcnt := nibble_width; + END IF; + FOR i IN input_val'RANGE LOOP + nibble_val := nibble_val * 2; + IF (input_val(i) = '1') THEN + nibble_val := nibble_val + 1; + END IF; + bitcnt := bitcnt - 1; + IF (bitcnt = 0) THEN + result(result_pos) := hex_digit(nibble_val + 1); + result_pos := result_pos + 1; + nibble_val := 0; + bitcnt := nibble_width; + END IF; + END LOOP; + write(l, result, justified, field); + END; + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_bv(int : integer) RETURN std_logic_vector + IS + VARIABLE bv : std_logic_vector(32 DOWNTO 1) := (OTHERS => '0'); + VARIABLE pos : integer := 0; + VARIABLE tmpval : integer := int; + BEGIN + FOR i IN 1 TO 32 LOOP + pos := pos + 1; + IF (tmpval MOD 2) = 1 THEN + bv(i) := '1'; + END IF; + tmpval := tmpval / 2; + EXIT WHEN tmpval = 0; + END LOOP; + RETURN bv(pos DOWNTO 1); + END; + + VARIABLE tmp : line; + BEGIN + IF (base = decimal) THEN + IF (use_pound) THEN + write_string(tmp, "10#"); + END IF; + write(tmp, value); + IF (use_pound) THEN + write_string(tmp, "#"); + END IF; + write(l, tmp.ALL, justified, field); + deallocate(tmp); + ELSE + write(l, to_bv(value), justified, field, base, use_pound); + END IF; + END; + +END io_utils; + + + +-- test the hex number reader +--ENTITY test IS END; + +--USE std.textio.ALL; +--USE work.io_utils.ALL; +--ARCHITECTURE hex_test OF test IS +--BEGIN +-- PROCESS +-- VARIABLE val : integer; +-- FILE myfile : text IS IN "values"; +-- VARIABLE inline : line; +-- VARIABLE outline : line; +-- BEGIN +-- WHILE NOT endfile(myfile) LOOP +-- readline(myfile, inline); + +-- write(outline, inline.ALL); +-- +-- read_based(inline, val); + -- write_string(outline, " binary: "); + -- write(outline, val, base => binary); + -- write_string(outline, " octal: "); + -- write(outline, val, base => octal); + -- write_string(outline, " decimal: "); + -- write(outline, val, base => decimal); +-- write_string(outline, " hex: "); +-- write(outline, val, base => hex); +-- writeline(output, outline); +-- END LOOP; +-- WAIT; +-- END PROCESS; +--END; + + diff --git a/lib/models/memory/sdram/mt48lc32m4a2/mt48lc32m4a2.vhd b/lib/models/memory/sdram/mt48lc32m4a2/mt48lc32m4a2.vhd new file mode 100644 index 0000000..fc22f7f --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/mt48lc32m4a2.vhd @@ -0,0 +1,1140 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC32M4A2.VHD +-- Version: 0.0g +-- Date: May 15th, 1999 +-- Model: Behavioral +-- Simulator: Model Technology (PC version 5.3 PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC32M4A2 (8Mb x 4 x 4 Banks) +-- +-- Description: Micron 128Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0g Son Huynh 208-368-3825 05/15/2000 Fix tWR + tRP timing +-- Micron Technology Inc. +-- +-- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) +-- Micron Technology Inc. Fix tWR = 15 ns (Manual) +-- Fix tRP (Autoprecharge to AutoRefresh) +-- +-- 0.0c Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP +-- Micron Technology Inc. Fix tRC check in Load Mode Register +-- +-- 0.0b Son P. Huynh 208-368-3825 12/29/1998 Derive from 64Mb SDRAM model +-- Micron Technology Inc. +-- +----------------------------------------------------------------------------------------- + +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; +LIBRARY work; + USE work.mti_pkg.ALL; + +ENTITY mt48lc32m4a2 IS + GENERIC ( + -- Timing Parameters for -7E and CAS Latency = 2 + tAC : TIME := 5.4 ns; + tHZ : TIME := 4.5 ns; + tOH : TIME := 2.7 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 37.0 ns; + tRC : TIME := 60.0 ns; + tRCD : TIME := 15.0 ns; + tRP : TIME := 15.0 ns; + tRRD : TIME := 14.0 ns; + tWRa : TIME := 7.0 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7 ns) + tWRp : TIME := 14.0 ns; -- A2 Version - Precharge mode only (14 ns) + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 7.5 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 12; + data_bits : INTEGER := 4; + col_bits : INTEGER := 11 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC := '0' + ); +END mt48lc32m4a2; + +ARCHITECTURE behave OF mt48lc32m4a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array2xB IS ARRAY (1 DOWNTO 0) OF BIT; + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL RAS_clk, Sys_clk, CkeZ : BIT := '0'; + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- RAS Clock for checking tWR and tRP + PROCESS + variable Clk0, Clk1 : integer := 0; + begin + RAS_clk <= '1'; + wait for 0.5 ns; + RAS_clk <= '0'; + wait for 0.5 ns; + if Clk0 > 100 or Clk1 > 100 then + wait; + else + if Clk = '1' then + Clk0 := 0; + Clk1 := Clk1 + 1; + else + Clk0 := Clk0 + 1; + Clk1 := 0; + end if; + end if; + END PROCESS; + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg : Array2xB; + + VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, RAS_clk; + IF Sys_clk'event and Sys_clk = '1' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg(0) := Dqm_reg(1); + Dqm_reg(1) := TO_BIT(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Precharge Timer for tWR + if (Burst_length_1 = '1' OR Write_burst_mode = '1') then + if (Count_precharge(0) = 1) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 1) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 1) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 1) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_2 = '1') then + if (Count_precharge(0) = 2) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 2) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 2) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 2) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_4 = '1') then + if (Count_precharge(0) = 4) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 4) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 4) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 4) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_8 = '1') then + if (Count_precharge(0) = 8) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 8) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 8) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 8) then + Count_time(3) := NOW; + end if; + end if; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) := WR_counter(0) + 1; + WR_counter(1) := WR_counter(1) + 1; + WR_counter(2) := WR_counter(2) + 1; + WR_counter(3) := WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := TO_BITVECTOR (Addr); + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := TO_BITVECTOR (Addr); + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := TO_BITVECTOR (Ba); + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR + (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BITVECTOR (Ba); + A10_precharge(2) := TO_BIT(Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BITVECTOR (Ba); + A10_precharge(1) := TO_BIT(Addr(10)); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(11) & Addr(9 DOWNTO 0)); + Bank_addr (2) := TO_BITVECTOR (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(11) & Addr(9 DOWNTO 0)); + Bank_addr (1) := TO_BITVECTOR (Ba); + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(11) & Addr(9 DOWNTO 0)); + Bank_addr (0) := TO_BITVECTOR (Ba); + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' AND Write_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_write(TO_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' AND Read_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_read(TO_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + RW_interrupt_bank := TO_BITVECTOR (Ba); + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm = '0' THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Bank0 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "01" THEN + Bank1 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "10" THEN + Bank2 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "11" THEN + Bank3 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + END IF; + WR_chkp(TO_INTEGER(Bank)) := NOW; + WR_counter(TO_INTEGER(Bank)) := 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg(0) = '0' THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank0 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "01" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank1 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "10" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank2 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "11" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank3 (Row_index) (Col_index)) AFTER tAC; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + + -- Checking internal variables (Optional for debug purpose) + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Pre_chk (2) <= Pc_b2; + Pre_chk (3) <= Pc_b3; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Act_chk (2) <= Act_b2; + Act_chk (3) <= Act_b3; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "Dq Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc32m4a2/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc32m4a2/mti_pkg.vhd new file mode 100644 index 0000000..9e4f824 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/mti_pkg.vhd @@ -0,0 +1,129 @@ +--***************************************************************************** +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +--***************************************************************************** + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + -- Convert BIT to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert BIT_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Conver integer to bit_vector + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc32m4a2/readme.txt b/lib/models/memory/sdram/mt48lc32m4a2/readme.txt new file mode 100644 index 0000000..5728ae8 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/readme.txt @@ -0,0 +1,14 @@ +To operate the test bench for the Micron SDRAM VHDL model, follow the directions +given below: + +1. Be sure all supporting files for the SDRAM are compiled into your library: + + util1164.vhd + stdlogar.vhd + io_utils.vhd + mti_pkg.vhd + +2. Next, compile the mt48lc32m4a2.vhd file and the test.vhd file. + +3. Simulate the "tb" architecture. This is the testbench for the 128Mb SDRAM. + diff --git a/lib/models/memory/sdram/mt48lc32m4a2/stdlogar.vhd b/lib/models/memory/sdram/mt48lc32m4a2/stdlogar.vhd new file mode 100644 index 0000000..e435ea2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/stdlogar.vhd @@ -0,0 +1,2247 @@ +-------------------------------------------------------------------------- +-- -- +-- Copyright (c) 1990,1991,1992 by Synopsys, Inc. All rights reserved. -- +-- -- +-- This source file may be used and distributed without restriction -- +-- provided that this copyright statement is not removed from the file -- +-- and that any derivative work contains this copyright notice. -- +-- -- +-- Package name: STD_LOGIC_ARITH -- +-- -- +-- Purpose: -- +-- A set of arithemtic, conversion, and comparison functions -- +-- for SIGNED, UNSIGNED, SMALL_INT, INTEGER, -- +-- STD_ULOGIC, STD_LOGIC, and STD_LOGIC_VECTOR. -- +-- -- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; + +package std_logic_arith is + + type UNSIGNED is array (NATURAL range <>) of STD_LOGIC; + type SIGNED is array (NATURAL range <>) of STD_LOGIC; + subtype SMALL_INT is INTEGER range 0 to 1; + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: INTEGER) return SIGNED; + function "+"(L: INTEGER; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: INTEGER) return SIGNED; + function "-"(L: INTEGER; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "+"(L: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED) return SIGNED; + function "-"(L: SIGNED) return SIGNED; + function "ABS"(L: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED) return STD_LOGIC_VECTOR; + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "*"(L: SIGNED; R: SIGNED) return SIGNED; + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + + function CONV_INTEGER(ARG: INTEGER) return INTEGER; + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER; + function CONV_INTEGER(ARG: SIGNED) return INTEGER; + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT; + + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED; + + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED; + + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + -- zero extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- returns STD_LOGIC_VECTOR(SIZE-1 downto 0) + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + + -- sign extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- return STD_LOGIC_VECTOR(SIZE-1 downto 0) + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + +end Std_logic_arith; + + + +library IEEE; +use IEEE.std_logic_1164.all; + +package body std_logic_arith is + + function max(L, R: INTEGER) return INTEGER is + begin + if L > R then + return L; + else + return R; + end if; + end; + + + function min(L, R: INTEGER) return INTEGER is + begin + if L < R then + return L; + else + return R; + end if; + end; + + -- synopsys synthesis_off + type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; + constant tbl_BINARY : tbl_type := + ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); + -- synopsys synthesis_on + + -- synopsys synthesis_off + type tbl_mvl9_boolean is array (STD_ULOGIC) of boolean; + constant IS_X : tbl_mvl9_boolean := + (true, true, false, false, true, true, false, false, true); + -- synopsys synthesis_on + + + + function MAKE_BINARY(A : STD_ULOGIC) return STD_ULOGIC is + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + if (IS_X(A)) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + return ('X'); + end if; + return tbl_BINARY(A); + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + + + -- Type propagation function which returns a signed type with the + -- size of the left arg. + function LEFT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the left arg. + function LEFT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns a signed type with the + -- size of the result of a signed multiplication + function MULT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the result of a unsigned multiplication + function MULT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + + + function mult(A,B: SIGNED) return SIGNED is + + variable BA: SIGNED((A'length+B'length-1) downto 0); + variable PA: SIGNED((A'length+B'length-1) downto 0); + variable AA: SIGNED(A'length downto 0); + variable neg: STD_ULOGIC; + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_TC_OP + -- pragma type_function MULT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + neg := B(B'left) xor A(A'left); + BA := CONV_SIGNED(('0' & ABS(B)),(A'length+B'length)); + AA := '0' & ABS(A); + for i in 0 to A'length-1 loop + if AA(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + if (neg= '1') then + return(-PA); + else + return(PA); + end if; + end; + + function mult(A,B: UNSIGNED) return UNSIGNED is + + variable BA: UNSIGNED((A'length+B'length-1) downto 0); + variable PA: UNSIGNED((A'length+B'length-1) downto 0); + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_UNS_OP + -- pragma type_function MULT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + BA := CONV_UNSIGNED(B,(A'length+B'length)); + for i in 0 to A'length-1 loop + if A(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + return(PA); + end; + + -- subtract two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function minus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_TC_OP + + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function plus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_TC_OP + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + -- subtract two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_minus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + + function "*"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1)); -- pragma label mult + end; + + + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1))); -- pragma label mult + end; + + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + + + function "+"(L: UNSIGNED) return UNSIGNED is + begin + return L; + end; + + + function "+"(L: SIGNED) return SIGNED is + begin + return L; + end; + + + function "-"(L: SIGNED) return SIGNED is + -- pragma label_applies_to minus + begin + return 0 - L; -- pragma label minus + end; + + + function "ABS"(L: SIGNED) return SIGNED is + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return L; + else + return 0 - L; + end if; + end; + + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "+"(L: SIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "-"(L: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + variable tmp: SIGNED(L'length-1 downto 0); + begin + tmp := 0 - L; -- pragma label minus + return STD_LOGIC_VECTOR (tmp); + end; + + + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR is + variable tmp: SIGNED(L'length-1 downto 0); + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return STD_LOGIC_VECTOR (L); + else + tmp := 0 - L; + return STD_LOGIC_VECTOR (tmp); + end if; + end; + + + -- Type propagation function which returns the type BOOLEAN + function UNSIGNED_RETURN_BOOLEAN(A,B: UNSIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns the type BOOLEAN + function SIGNED_RETURN_BOOLEAN(A,B: SIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := FALSE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less_or_equal(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := TRUE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := FALSE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less_or_equal(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := TRUE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_eql(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_EQL + begin + for i in L'range loop + if L(i) /= R(i) then + return FALSE; + end if; + end loop; + return TRUE; + end; + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_neq(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_NEQ + begin + for i in L'range loop + if L(i) /= R(i) then + return TRUE; + end if; + end loop; + return FALSE; + end; + + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + variable sign_bit: STD_ULOGIC; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + sign_bit := ARG(ARG'left); + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => sign_bit); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + + + function CONV_INTEGER(ARG: INTEGER) return INTEGER is + begin + return ARG; + end; + + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_UNSIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 31 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: SIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_SIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 32 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + if i /= ARG'left then + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end if; + end loop; + tmp := MAKE_BINARY(ARG(ARG'left)); + if tmp = '1' then + if ARG'length = 32 then + result := (result - 2**30) - 2**30; + else + result := result - (2 ** (ARG'length-1)); + end if; + end if; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT is + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + tmp := tbl_BINARY(ARG); + if tmp = '1' then + return 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + return 0; + else + return 0; + end if; + -- synopsys synthesis_on + end; + + + -- convert an integer to a unsigned STD_ULOGIC_VECTOR + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED is + variable result: UNSIGNED(SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_UNSIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED is + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to a 2's complement STD_ULOGIC_VECTOR + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED is + variable result: SIGNED (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED is + subtype rtype is SIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to an STD_LOGIC_VECTOR + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is + variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) return STD_LOGIC_VECTOR is + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) + return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds: STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + +end std_logic_arith; diff --git a/lib/models/memory/sdram/mt48lc32m4a2/test.do b/lib/models/memory/sdram/mt48lc32m4a2/test.do new file mode 100644 index 0000000..83a6f3b --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc32m4a2.vhd +vcom test.vhd +vsim tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48lc32m4a2/test.txt b/lib/models/memory/sdram/mt48lc32m4a2/test.txt new file mode 100644 index 0000000..ad4a459 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/test.txt @@ -0,0 +1,98 @@ +0 ns 1 1 1 1 1 0 00 0 -100 +22 ns 1 1 1 1 1 0 00 0 -100 +32 ns 1 1 1 1 1 0 00 0 -100 +42 ns 1 1 1 1 1 0 00 0 -100 +52 ns 1 1 1 1 1 0 00 0 -100 +62 ns 1 0 0 1 0 0 00 1024 -100 +72 ns 1 1 1 1 1 0 00 0 -100 +82 ns 1 1 1 1 1 0 00 0 -100 +92 ns 1 0 0 0 1 0 00 0 -100 +102 ns 1 1 1 1 1 0 00 0 -100 +112 ns 1 1 1 1 1 0 00 0 -100 +122 ns 1 1 1 1 1 0 00 0 -100 +132 ns 1 1 1 1 1 0 00 0 -100 +142 ns 1 1 1 1 1 0 00 0 -100 +152 ns 1 1 1 1 1 0 00 0 -100 +162 ns 1 1 1 1 1 0 00 0 -100 +172 ns 1 1 1 1 1 0 00 0 -100 +182 ns 1 0 0 0 1 0 00 0 -100 +192 ns 1 1 1 1 1 0 00 0 -100 +202 ns 1 1 1 1 1 0 00 0 -100 +212 ns 1 1 1 1 1 0 00 0 -100 +222 ns 1 1 1 1 1 0 00 0 -100 +232 ns 1 1 1 1 1 0 00 0 -100 +242 ns 1 1 1 1 1 0 00 0 -100 +252 ns 1 1 1 1 1 0 00 0 -100 +262 ns 1 1 1 1 1 0 00 0 -100 +272 ns 1 0 0 0 0 0 00 51 -100 +282 ns 1 1 1 1 1 0 00 0 -100 +292 ns 1 0 0 1 1 0 00 0 -100 +302 ns 1 1 1 1 1 0 00 0 -100 +312 ns 1 0 1 0 0 0 00 10 0 +322 ns 1 1 1 1 1 0 00 0 1 +332 ns 1 0 0 1 1 0 01 0 2 +342 ns 1 1 1 1 1 0 00 0 3 +352 ns 1 1 1 1 1 0 00 0 4 +362 ns 1 1 1 1 1 0 00 0 5 +372 ns 1 1 1 1 1 0 00 0 6 +382 ns 1 1 1 1 1 0 00 0 7 +392 ns 1 0 1 0 0 0 01 20 8 +402 ns 1 0 0 1 0 0 00 0 9 +412 ns 1 0 0 1 1 0 10 0 10 +422 ns 1 1 1 1 1 0 00 0 11 +432 ns 1 1 1 1 1 0 00 0 12 +442 ns 1 1 1 1 1 0 00 0 13 +452 ns 1 1 1 1 1 0 00 0 14 +462 ns 1 1 1 1 1 0 00 0 15 +472 ns 1 0 1 0 0 0 10 30 0 +482 ns 1 0 0 1 0 0 01 0 1 +492 ns 1 0 0 1 1 0 11 0 2 +502 ns 1 1 1 1 1 0 00 0 3 +512 ns 1 1 1 1 1 0 00 0 4 +522 ns 1 1 1 1 1 0 00 0 5 +532 ns 1 1 1 1 1 0 00 0 6 +542 ns 1 1 1 1 1 0 00 0 7 +552 ns 1 0 1 0 0 0 11 40 8 +562 ns 1 0 0 1 0 0 10 0 9 +572 ns 1 0 0 1 1 0 00 0 10 +582 ns 1 1 1 1 1 0 00 0 11 +592 ns 1 1 1 1 1 0 00 0 12 +602 ns 1 1 1 1 1 0 00 0 13 +612 ns 1 1 1 1 1 0 00 0 14 +622 ns 1 1 1 1 1 0 00 0 15 +632 ns 1 0 1 0 1 0 00 10 -100 +642 ns 1 0 0 1 0 0 11 0 -100 +652 ns 1 0 0 1 1 0 01 0 -100 +662 ns 1 1 1 1 1 0 00 0 -100 +672 ns 1 1 1 1 1 0 00 0 -100 +682 ns 1 1 1 1 1 0 00 0 -100 +692 ns 1 1 1 1 1 0 00 0 -100 +702 ns 1 1 1 1 1 0 00 0 -100 +712 ns 1 0 1 0 1 0 01 20 -100 +722 ns 1 0 0 1 0 0 00 0 -100 +732 ns 1 0 0 1 1 0 10 0 -100 +742 ns 1 1 1 1 1 0 00 0 -100 +752 ns 1 1 1 1 1 0 00 0 -100 +762 ns 1 1 1 1 1 0 00 0 -100 +772 ns 1 1 1 1 1 0 00 0 -100 +782 ns 1 1 1 1 1 0 00 0 -100 +792 ns 1 0 1 0 1 0 10 30 -100 +802 ns 1 0 0 1 0 0 01 0 -100 +812 ns 1 0 0 1 1 0 11 0 -100 +822 ns 1 1 1 1 1 0 00 0 -100 +832 ns 1 1 1 1 1 0 00 0 -100 +842 ns 1 1 1 1 1 0 00 0 -100 +852 ns 1 1 1 1 1 0 00 0 -100 +862 ns 1 1 1 1 1 0 00 0 -100 +872 ns 1 0 1 0 1 0 11 40 -100 +882 ns 1 0 0 1 0 0 10 0 -100 +892 ns 1 1 1 1 1 0 00 0 -100 +902 ns 1 1 1 1 1 0 00 0 -100 +912 ns 1 1 1 1 1 0 00 0 -100 +922 ns 1 1 1 1 1 0 00 0 -100 +932 ns 1 1 1 1 1 0 00 0 -100 +942 ns 1 1 1 1 1 0 00 0 -100 +952 ns 1 0 0 1 0 0 11 0 -100 +962 ns 1 1 1 1 1 0 00 0 -100 +972 ns 1 1 1 1 1 0 00 0 -100 +982 ns 1 1 1 1 1 0 00 0 -100 diff --git a/lib/models/memory/sdram/mt48lc32m4a2/test.vhd b/lib/models/memory/sdram/mt48lc32m4a2/test.vhd new file mode 100644 index 0000000..0d173f3 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/test.vhd @@ -0,0 +1,169 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE std.textio.ALL; +USE work.std_logic_arith.ALL; +USE work.util_1164.ALL; +USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 12; + CONSTANT data_bits : INTEGER := 4; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + + COMPONENT mt48lc32m4a2 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC := '0' + ); + END COMPONENT; + + FOR ALL : mt48lc32m4a2 USE ENTITY work.mt48lc32m4a2 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc32m4a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + --FILE stim_file:text IS IN "test1.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : STD_LOGIC; + VARIABLE pCs_var : STD_LOGIC; + VARIABLE pRas_var : STD_LOGIC; + VARIABLE PCas_var : STD_LOGIC; + VARIABLE pWe_var : STD_LOGIC; + VARIABLE pDqm_var : STD_LOGIC; + VARIABLE pBa_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read(l, time_var); + read(l, pCke_var); + read(l, pCs_var); + read(l, pRas_var); + read(l, pCas_var); + read(l, pWe_var); + read(l, pDqm_var); + read(l, pBa_var); + read(l, pAddr_var); + read(l, pDq_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + IF pWe_var='1' THEN + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + ELSE + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + END IF; + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc32m4a2/util1164.vhd b/lib/models/memory/sdram/mt48lc32m4a2/util1164.vhd new file mode 100644 index 0000000..bb4b5dd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/util1164.vhd @@ -0,0 +1,124 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE STD.textio.ALL; + +PACKAGE util_1164 IS + PROCEDURE read(l: INOUT line; value: OUT std_logic); + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector); + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0); + PROCEDURE Grow_line(L : inout LINE; incr : in integer); +END util_1164; + + + +PACKAGE BODY util_1164 IS + + FUNCTION white_space(value:character) RETURN boolean IS + VARIABLE result:boolean; + BEGIN + IF (value = ' ') OR (value = HT) THEN + RETURN true; + ELSE + RETURN false; + END IF; + END white_space; + + PROCEDURE read(l: INOUT line; value: OUT std_logic) IS + VARIABLE char_var: character:= ' '; + BEGIN + WHILE l'LENGTH > 0 LOOP + read(l,char_var); + IF NOT white_space(char_var) THEN + EXIT; + END IF; + END LOOP; + IF white_space(char_var) THEN + ASSERT false REPORT "No std_logic value found in file" + SEVERITY error; + value := 'X'; + RETURN; + END IF; + + CASE char_var IS + WHEN 'U'|'u' => value := 'U'; + WHEN '0' => value := '0'; + WHEN '1' => value := '1'; + WHEN 'X'|'x' => value := 'X'; + WHEN 'L'|'l' => value := 'L'; + WHEN 'H'|'h' => value := 'H'; + WHEN 'W'|'w' => value := 'W'; + WHEN 'Z'|'z' => value := 'Z'; + WHEN '-' => value := '-'; + WHEN OTHERS => + ASSERT false REPORT "Unrecognized value read for std_logic" + SEVERITY error; + value := 'X'; + END CASE; + END read; + + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector) IS + BEGIN + FOR i IN value'HIGH DOWNTO value'LOW LOOP + IF l'LENGTH > 0 THEN + read(l,value(i)); + ELSE + ASSERT false REPORT "Not enough values for std_logic_vector in file" + SEVERITY error; + RETURN; + END IF; + END LOOP; + END read; + + procedure Grow_line(L : inout LINE; incr : in integer) + is + variable old_L : LINE := L; + variable bfp: integer; -- Blank fill pointer. + begin + assert incr > 0 + report "Textio: Grow_line called with zero increment." + severity error; + + if L = null then + bfp := 0; + L := new string(1 to incr); + else + bfp := old_L'high; + L := new string(old_L'low to old_L'high + incr); + L(old_L'low to old_L'high) := old_L.all; + Deallocate(old_L); + end if; + for i in 1 to incr loop + L(bfp + i) := ' '; + end loop; + end; + + + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0) IS + variable fw: integer := VALUE'length; + variable bp: integer; + variable offset: integer := 0; + alias normal : std_logic_vector(0 to value'length - 1) is value; + begin + if L /= null then + bp := L'high + 1; + else bp := 1; + end if; + if FIELD > VALUE'length then + fw := FIELD; + if JUSTIFIED = right then + offset := fw - VALUE'length; + end if; + end if; + Grow_line(L, fw); + for i in normal'range loop + L(bp + i + offset) := character'val( + std_logic'pos(normal(i)) + character'pos('0')); + end loop; + end; + + +END util_1164; diff --git a/lib/models/memory/sdram/mt48lc32m4a2/vec_gen.vhd b/lib/models/memory/sdram/mt48lc32m4a2/vec_gen.vhd new file mode 100644 index 0000000..821d321 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/vec_gen.vhd @@ -0,0 +1,372 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.io_utils.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); + first_data : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT; cke : IN BIT); + PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT; cs : IN BIT); + PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle(SIGNAL clk : IN BIT); + PROCEDURE load_array(load : IN BIT); + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)); + +END generate_vectors; + + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; + dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, first_data, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, row_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT; cs : IN BIT) IS + + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, cs, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT := '0'; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + --write(l, 0, right, 4); --load + --write(l, 0, right, 4); --unload + --write(l, 0, right, 6); --row_address_start + --write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS + +BEGIN + +WAIT UNTIL clk = '1'; + +END; + +PROCEDURE load_array(load : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT := '0'; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 1, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT := '0'; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 1, right, 4); --unload +--write(l, row_start, right, 6); --row_address_start +--write(l, row_end, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT := '0'; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, op_code, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc32m4a2/vector.do b/lib/models/memory/sdram/mt48lc32m4a2/vector.do new file mode 100644 index 0000000..7480359 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/vector.do @@ -0,0 +1,4 @@ +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all diff --git a/lib/models/memory/sdram/mt48lc32m4a2/wave.do b/lib/models/memory/sdram/mt48lc32m4a2/wave.do new file mode 100644 index 0000000..168e846 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc32m4a2/wave.do @@ -0,0 +1,31 @@ +onerror {resume} +add wave -logic -height 20 /tb/u1/clk +add wave -logic -height 20 /tb/u1/cke +add wave -logic -height 20 /tb/u1/cs_n +add wave -logic -height 20 /tb/u1/ras_n +add wave -logic -height 20 /tb/u1/cas_n +add wave -logic -height 20 /tb/u1/we_n +add wave -logic -unsigned -height 20 /tb/u1/addr +add wave -logic -height 20 /tb/u1/ba +add wave -logic -unsigned -height 20 /tb/u1/dq +add wave -logic -height 20 /tb/u1/dqm +add wave -literal -ascii -height 20 /tb/u1/operation +add wave -logic -unsigned -height 20 /tb/u1/mode_reg +add wave -logic -height 20 /tb/u1/active_enable +add wave -logic -height 20 /tb/u1/aref_enable +add wave -logic -height 20 /tb/u1/burst_term +add wave -logic -height 20 /tb/u1/mode_reg_enable +add wave -logic -height 20 /tb/u1/prech_enable +add wave -logic -height 20 /tb/u1/read_enable +add wave -logic -height 20 /tb/u1/write_enable +add wave -logic -height 20 /tb/u1/burst_length_1 +add wave -logic -height 20 /tb/u1/burst_length_2 +add wave -logic -height 20 /tb/u1/burst_length_4 +add wave -logic -height 20 /tb/u1/burst_length_8 +add wave -logic -height 20 /tb/u1/cas_latency_2 +add wave -logic -height 20 /tb/u1/cas_latency_3 +add wave -logic -height 20 /tb/u1/pre_chk +add wave -logic -height 20 /tb/u1/act_chk +add wave -logic -height 20 /tb/u1/bank_chk +add wave -logic -unsigned -height 20 /tb/u1/row_chk +add wave -logic -unsigned -height 20 /tb/u1/col_chk diff --git a/lib/models/memory/sdram/mt48lc4m16a2/base.do b/lib/models/memory/sdram/mt48lc4m16a2/base.do new file mode 100644 index 0000000..d2afbcb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/base.do @@ -0,0 +1,5 @@ +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd + diff --git a/lib/models/memory/sdram/mt48lc4m16a2/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc4m16a2/ed_comnd.vhd new file mode 100644 index 0000000..489311e --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/ed_comnd.vhd @@ -0,0 +1,357 @@ +--------------------------------------------------------------------------------- +--COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit_vector), first data(integer), dqm(bit), cke(bit));-- +-- read(column address(integer), bank(bit_vector), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit_vector), data bus (integer), dqm(bit), cke(bit));-- +-- precharge(bank(bit_vector), address (integer), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit)); -- +-- burst_term(data bus(integer), dqm(bit_vector), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit_vector)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +--------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, "00", '1'); -- Always begin with one nop when using Micron's testbench + +next_cycle(clk); -- Load Memory Array +load_array('1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); -- Precharge All Banks +precharge("00", 1024, Z, "00", '1'); + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, "00", '1'); +END LOOP; + +next_cycle(clk); -- First Auto Refresh +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1'); +END LOOP; + +next_cycle(clk); -- Second Auto Refresh +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1'); +END LOOP; + +next_cycle(clk); -- Load Mode Register (CAS Latency = 3, Burst Length = 8) +load_mode_reg(51, '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +-- Write Section + +next_cycle(clk); +active(0, "00", Z, "00", '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); -- Write Bank 0 +write(0, "00", 10, "00", '1'); + +next_cycle(clk); +nop(11, "00", '1'); + +next_cycle(clk); +active(0, "01", 12, "00", '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(13, "00", '1'); + +next_cycle(clk); +nop(14, "00", '1'); + +next_cycle(clk); +nop(15, "00", '1'); + +next_cycle(clk); +nop(16, "00", '1'); + +next_cycle(clk); +nop(17, "00", '1'); + +next_cycle(clk); +write(0, "01", 20, "00", '1'); -- Write Bank 1 + +next_cycle(clk); +precharge("00", 0, 21, "00", '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", 22, "00", '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(23, "00", '1'); + +next_cycle(clk); +nop(24, "00", '1'); + +next_cycle(clk); +nop(25, "00", '1'); + +next_cycle(clk); +nop(26, "00", '1'); + +next_cycle(clk); +nop(27, "00", '1'); + +next_cycle(clk); +write(0, "10", 30, "00", '1'); -- Write Bank 2 + +next_cycle(clk); +precharge("01", 0, 31, "00", '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", 32, "00", '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(33, "00", '1'); + +next_cycle(clk); +nop(34, "00", '1'); + +next_cycle(clk); +nop(35, "00", '1'); + +next_cycle(clk); +nop(36, "00", '1'); + +next_cycle(clk); +nop(37, "00", '1'); + +next_cycle(clk); +write(0, "11", 40, "00", '1'); -- Write Bank 3 + +next_cycle(clk); +precharge("10", 0, 41, "00", '1'); -- Precharge Bank 2 + +next_cycle(clk); +active(0, "00", 42, "00", '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(43, "00", '1'); + +next_cycle(clk); +nop(44, "00", '1'); + +next_cycle(clk); +nop(45, "00", '1'); + +next_cycle(clk); +nop(46, "00", '1'); + +next_cycle(clk); +nop(47, "00", '1'); + +-- Read Section + +next_cycle(clk); +read(0, "00", "00", '1'); -- Read Bank 0 + +next_cycle(clk); +precharge("11", 0, Z, "00", '1'); -- Precharge Bank 3 + +next_cycle(clk); +active(0, "01", Z, "00", '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +read(0, "01", "00", '1'); -- Read Bank 1 + +next_cycle(clk); +precharge("00", 0, Z, "00", '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", Z, "00", '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +read(0, "10", "00", '1'); -- Read Bank 2 + +next_cycle(clk); +precharge("01", 0, Z, "00", '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", Z, "00", '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +read(0, "11", "00", '1'); -- Read Bank 3 + +next_cycle(clk); +precharge("10", 0, Z, "00", '1'); -- Precharge Bank 2 + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +precharge("11", 0, Z, "00", '1'); -- Precharge Bank 3 + +next_cycle(clk); +nop(Z, "00", '1'); + +next_cycle(clk); +nop(Z, "00", '1'); + +--next_cycle(clk); -- Unload Bank 0 Memory Array +--unload_array(0, 3, "00"); + +--next_cycle(clk); -- Unload Bank 1 Memory Array +--unload_array(0, 3, "01"); + +--next_cycle(clk); -- Unload Bank 2 Memory Array +--unload_array(0, 3, "10"); + +--next_cycle(clk); -- Unload Bank 3 Memory Array +--unload_array(0, 3, "11"); + +next_cycle(clk); +nop(Z, "00", '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + + + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc4m16a2/io_utils.vhd b/lib/models/memory/sdram/mt48lc4m16a2/io_utils.vhd new file mode 100644 index 0000000..dfcb84a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/io_utils.vhd @@ -0,0 +1,266 @@ +LIBRARY ieee; +USE std.textio.ALL; +USE ieee.std_logic_1164.ALL; + +PACKAGE io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0); + + TYPE radix IS (binary, octal, decimal, hex); + + -- read a number from the line + -- use this if you have hex numbers that are not in VHDL pound-sign format + PROCEDURE read(l : INOUT line; value : OUT integer; radix : IN positive); + + -- read a number that might be in VHDL pound-sign format + PROCEDURE read_based(l : INOUT line; value : OUT integer); + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); +END io_utils; + +PACKAGE BODY io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0) + IS + BEGIN + write(l, value, justified, field); + END; + + PROCEDURE shrink_line(l : INOUT line; pos : integer) IS + VARIABLE tmpl : line; + BEGIN + tmpl := l; + l := NEW string'(tmpl(pos TO tmpl'high)); + deallocate(tmpl); + END; + + PROCEDURE read(l : INOUT line; + value : OUT integer; + radix : IN positive) + IS + CONSTANT not_digit : integer := -999; + + -- convert a character to a value from 0 to 15 + FUNCTION digit_value(c : character) RETURN integer IS + BEGIN + IF (c >= '0') AND (c <= '9') THEN + RETURN (character'pos(c) - character'pos('0')); + ELSIF (c >= 'a') AND (c <= 'f') THEN + RETURN (character'pos(c) - character'pos('a') + 10); + ELSIF (c >= 'A') AND (c <= 'F') THEN + RETURN (character'pos(c) - character'pos('A') + 10); + ELSE + RETURN not_digit; + END IF; + END; + + -- skip leading white space in the line + PROCEDURE skip_white(VARIABLE l : IN line; pos : OUT integer) IS + BEGIN + pos := l'low; + FOR i IN l'low TO l'high LOOP + CASE l(i) IS + WHEN ' ' | ht => + pos := i + 1; + WHEN OTHERS => + EXIT; + END CASE; + END LOOP; + END; + + VARIABLE digit : integer; + VARIABLE result : integer := 0; + VARIABLE pos : integer; + BEGIN + -- skip white space + skip_white(l, pos); + + -- calculate the value + FOR i IN pos TO l'right LOOP + digit := digit_value(l(i)); + EXIT WHEN (digit = not_digit) OR (digit >= radix); + result := result * radix + digit; + pos := i + 1; + END LOOP; + value := result; + + -- remove the "used" characters from the line + shrink_line(l, pos); + END; + + PROCEDURE read_based(l : INOUT line; value : OUT integer) IS + VARIABLE digit : integer; + VARIABLE num : integer; + VARIABLE base : integer; + BEGIN + read(l, num, 10); + IF (l'length > 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + base := num; + read(l, num, base); + IF (l'length >= 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + END IF; + END IF; + value := num; + END; + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_int(bv : std_logic_vector) RETURN integer + IS + VARIABLE result : integer := 0; + BEGIN + FOR i IN bv'RANGE LOOP + result := result * 2; + IF (bv(i) = '1') THEN + result := result + 1; + END IF; + END LOOP; + RETURN result; + END; + + TYPE array_of_widths IS ARRAY(radix) OF natural; + CONSTANT nibble_widths : array_of_widths := ( + binary => 1, + octal => 3, + hex => 4, + decimal=> 32); + CONSTANT hex_digit : string(1 TO 16) := "0123456789ABCDEF"; + + ALIAS input_val : std_logic_vector(value'length DOWNTO 1) IS value; + CONSTANT nibble_width : natural := nibble_widths(base); + CONSTANT result_width : natural := (value'length + nibble_width - 1)/nibble_width; + + VARIABLE result : string(1 TO result_width); -- longest possible value + VARIABLE result_pos : positive := 1; + VARIABLE nibble_val : integer; + VARIABLE bitcnt : integer; + BEGIN + IF base = decimal THEN + write(l, to_int(value), justified, field, base, use_pound); + RETURN; + END IF; + + bitcnt := value'length MOD nibble_width; + IF (bitcnt = 0) THEN + bitcnt := nibble_width; + END IF; + FOR i IN input_val'RANGE LOOP + nibble_val := nibble_val * 2; + IF (input_val(i) = '1') THEN + nibble_val := nibble_val + 1; + END IF; + bitcnt := bitcnt - 1; + IF (bitcnt = 0) THEN + result(result_pos) := hex_digit(nibble_val + 1); + result_pos := result_pos + 1; + nibble_val := 0; + bitcnt := nibble_width; + END IF; + END LOOP; + write(l, result, justified, field); + END; + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_bv(int : integer) RETURN std_logic_vector + IS + VARIABLE bv : std_logic_vector(32 DOWNTO 1) := (OTHERS => '0'); + VARIABLE pos : integer := 0; + VARIABLE tmpval : integer := int; + BEGIN + FOR i IN 1 TO 32 LOOP + pos := pos + 1; + IF (tmpval MOD 2) = 1 THEN + bv(i) := '1'; + END IF; + tmpval := tmpval / 2; + EXIT WHEN tmpval = 0; + END LOOP; + RETURN bv(pos DOWNTO 1); + END; + + VARIABLE tmp : line; + BEGIN + IF (base = decimal) THEN + IF (use_pound) THEN + write_string(tmp, "10#"); + END IF; + write(tmp, value); + IF (use_pound) THEN + write_string(tmp, "#"); + END IF; + write(l, tmp.ALL, justified, field); + deallocate(tmp); + ELSE + write(l, to_bv(value), justified, field, base, use_pound); + END IF; + END; + +END io_utils; + + + +-- test the hex number reader +--ENTITY test IS END; + +--USE std.textio.ALL; +--USE work.io_utils.ALL; +--ARCHITECTURE hex_test OF test IS +--BEGIN +-- PROCESS +-- VARIABLE val : integer; +-- FILE myfile : text IS IN "values"; +-- VARIABLE inline : line; +-- VARIABLE outline : line; +-- BEGIN +-- WHILE NOT endfile(myfile) LOOP +-- readline(myfile, inline); + +-- write(outline, inline.ALL); +-- +-- read_based(inline, val); + -- write_string(outline, " binary: "); + -- write(outline, val, base => binary); + -- write_string(outline, " octal: "); + -- write(outline, val, base => octal); + -- write_string(outline, " decimal: "); + -- write(outline, val, base => decimal); +-- write_string(outline, " hex: "); +-- write(outline, val, base => hex); +-- writeline(output, outline); +-- END LOOP; +-- WAIT; +-- END PROCESS; +--END; + + diff --git a/lib/models/memory/sdram/mt48lc4m16a2/loaddata.txt b/lib/models/memory/sdram/mt48lc4m16a2/loaddata.txt new file mode 100644 index 0000000..c7599a9 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/loaddata.txt @@ -0,0 +1,40 @@ +0 0 00 0 -- ROW (HEX), COL (HEX), BANK (BIN), DATA (HEX) +0 1 00 1 +0 2 00 2 +0 3 00 3 +0 4 00 4 +0 5 00 5 +0 6 00 6 +0 7 00 7 +0 8 00 8 +0 9 00 9 +0 0 01 10 +0 1 01 11 +0 2 01 12 +0 3 01 13 +0 4 01 14 +0 5 01 15 +0 6 01 16 +0 7 01 17 +0 8 01 18 +0 9 01 19 +0 0 10 20 +0 1 10 21 +0 2 10 22 +0 3 10 23 +0 4 10 24 +0 5 10 25 +0 6 10 26 +0 7 10 27 +0 8 10 28 +0 9 10 29 +0 0 11 30 +0 1 11 31 +0 2 11 32 +0 3 11 33 +0 4 11 34 +0 5 11 35 +0 6 11 36 +0 7 11 37 +0 8 11 38 +0 9 11 39 diff --git a/lib/models/memory/sdram/mt48lc4m16a2/mt48lc4m16a2.vhd b/lib/models/memory/sdram/mt48lc4m16a2/mt48lc4m16a2.vhd new file mode 100644 index 0000000..45df8d2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/mt48lc4m16a2.vhd @@ -0,0 +1,1356 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC4M16A2.VHD +-- Version: 0.0f +-- Date: July 8th, 1999 +-- Model: Behavioral +-- Simulator: Model Technology (PC version 5.2e PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC4M16A2 (1Mb x 16 x 4 Banks) +-- +-- Description: Micron 64Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) +-- Micron Technology Inc. Fix tWR = 15 ns (Manual) +-- Fix tRP (Autoprecharge to AutoRefresh) +-- +-- 0.0e Son P. Huynh 208-368-3825 05/25/1999 Fix R/W Interrupting R/W with AP +-- Micron Technology Inc. +-- +-- 0.0d Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP +-- Micron Technology Inc. +-- +-- 0.0c Son P. Huynh 208-368-3825 01/14/1998 Add Load / Unload memory array +-- Micron Technology Inc. +-- +-- 0.0b Son P. Huynh 208-368-3825 12/09/1998 Fix some timing check problem +-- Micron Technology Inc. - Improve model functionality +-- +-- 0.0a Son P. Huynh 208-368-3825 08/10/1998 First Release +-- Micron Technology Inc. - Simple testbench included +----------------------------------------------------------------------------------------- + +LIBRARY std; + USE std.textio.ALL; +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; +LIBRARY work; + USE work.io_utils.ALL; + USE work.mti_pkg.ALL; + +ENTITY mt48lc4m16a2 IS + GENERIC ( + -- Timing Parameters for -75 (PC133) and CAS Latency = 2 + tAC : TIME := 6.0 ns; + tHZ : TIME := 7.0 ns; + tOH : TIME := 2.7 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 44.0 ns; + tRC : TIME := 66.0 ns; + tRCD : TIME := 20.0 ns; + tRP : TIME := 20.0 ns; + tRRD : TIME := 15.0 ns; + tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) + tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 10.0 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 12; + data_bits : INTEGER := 16; + col_bits : INTEGER := 8 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Load : IN STD_LOGIC := '0'; + Unload : IN STD_LOGIC := '0'; + Row_start : IN INTEGER := 0; + Row_end : IN INTEGER := 0 + ); +END mt48lc4m16a2; + +ARCHITECTURE behave OF mt48lc4m16a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, FILE_LOAD, FILE_UNLOAD); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL Sys_clk, CkeZ : BIT := '0'; + SIGNAL WR_counter : Array4xI := (0 & 0 & 0 & 0); + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg0, Dqm_reg1 : BIT_VECTOR (1 DOWNTO 0) := "00"; + + VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + VARIABLE WR_chk : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + + -- Load and Unload variables + FILE load_file : TEXT IS IN "loaddata.txt"; -- Data load + FILE out_file0 : TEXT IS OUT "outdata0.txt"; -- Data dump for bank 0 + FILE out_file1 : TEXT IS OUT "outdata1.txt"; -- Data dump for bank 1 + FILE out_file2 : TEXT IS OUT "outdata2.txt"; -- Data dump for bank 2 + FILE out_file3 : TEXT IS OUT "outdata3.txt"; -- Data dump for bank 3 + VARIABLE l_in, l_out0, l_out1, l_out2, l_out3 : LINE; + VARIABLE array_buffer : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE write_data_var : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE row_load, col_load, dq_load : INTEGER; + VARIABLE ba_load : BIT_VECTOR (1 DOWNTO 0); + VARIABLE dq_vec : BIT_VECTOR (data_bits - 1 DOWNTO 0); + VARIABLE i, j, k : INTEGER; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, WR_counter(0), WR_counter(1), WR_counter(2), WR_counter(3); + IF Sys_clk'event and Sys_clk = '1' AND Load = '0' AND Unload = '0' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg0 := Dqm_reg1; + Dqm_reg1 := TO_BITVECTOR(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) <= WR_counter(0) + 1; + WR_counter(1) <= WR_counter(1) + 1; + WR_counter(2) <= WR_counter(2) + 1; + WR_counter(3) <= WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := TO_BITVECTOR (Addr); + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := TO_BITVECTOR (Addr); + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := TO_BITVECTOR (Ba); + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chk(0) < tWRp) OR (NOW - WR_chk(1) < tWRp) OR + (NOW - WR_chk(2) < tWRp) OR (NOW - WR_chk(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chk(TO_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BITVECTOR (Ba); + A10_precharge(2) := TO_BIT(Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BITVECTOR (Ba); + A10_precharge(1) := TO_BIT(Addr(10)); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (2) := TO_BITVECTOR (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (1) := TO_BITVECTOR (Ba); + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (0) := TO_BITVECTOR (Ba); + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(TO_INTEGER(Bank)) = '1' AND Write_precharge(TO_INTEGER(Bank)) = '1' THEN + RW_interrupt_write(TO_INTEGER(Bank)) := '1'; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(TO_INTEGER(Bank)) = '1' AND Read_precharge(TO_INTEGER(Bank)) = '1' THEN + RW_interrupt_read(TO_INTEGER(Bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank0 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank1 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank2 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank3 (Row_index) (Col_index) := Dq_temp; + END IF; + WR_chk(TO_INTEGER(Bank)) := NOW; + WR_counter(TO_INTEGER(Bank)) <= 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg0 /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq_temp (15 DOWNTO 0) := Bank0 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "01" THEN + Dq_temp (15 DOWNTO 0) := Bank1 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "10" THEN + Dq_temp (15 DOWNTO 0) := Bank2 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "11" THEN + Dq_temp (15 DOWNTO 0) := Bank3 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + ELSIF Sys_clk'event and Sys_clk = '1' AND Load = '1' AND Unload = '0' THEN + Operation <= FILE_LOAD; + WHILE NOT ENDFILE (load_file) LOOP + READLINE (load_file, l_in); + IF l_in'LENGTH > 0 THEN + read (l_in, row_load, 16); -- Load from HEX to INTEGER + read (l_in, col_load, 16); -- Load from HEX to INTEGER + read (l_in, ba_load); + read (l_in, dq_load, 16); -- Load from HEX to INTEGER + + TO_BITVECTOR (dq_load, dq_vec); + + IF ba_load = "00" THEN + IF Bank0(row_load) = NULL THEN --initialize new memory block + Bank0(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank0(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank0(row_load)(col_load) := dq_vec; + ELSIF ba_load = "01" THEN + IF Bank1(row_load) = NULL THEN --initialize new memory block + Bank1(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank1(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank1(row_load)(col_load) := dq_vec; + ELSIF ba_load = "10" THEN + IF Bank2(row_load) = NULL THEN --initialize new memory block + Bank2(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank2(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank2(row_load)(col_load) := dq_vec; + ELSIF ba_load = "11" THEN + IF Bank3(row_load) = NULL THEN --initialize new memory block + Bank3(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank3(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank3(row_load)(col_load) := dq_vec; + END IF; + END IF; + END LOOP; + ELSIF Sys_clk'event and Sys_clk = '1' AND Load = '0' AND Unload = '1' THEN + Operation <= FILE_UNLOAD; + ASSERT (Row_start < 2**(Addr'HIGH + 1)) + REPORT "Row_start is out of range for device" + SEVERITY ERROR; + ASSERT (Row_end < 2**(Addr'HIGH + 1)) + REPORT "Row_end is out of range for device" + SEVERITY ERROR; + ASSERT ((Row_end - Row_start) >= 0) + REPORT "The Row ranges for Unload is invalid!" + SEVERITY ERROR; + IF ((Row_end - Row_start) >= 0) THEN + FOR i IN Row_start TO Row_end LOOP + j := 1; + IF (Ba = "00") THEN -- Unload Bank 0 + WRITE (l_out0, STRING'("Micron Technology Inc. - Unload Data Array - Bank 0 Row ")); + WRITE (l_out0, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file0, l_out0); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP -- Display Row and Column + IF (j = 1) THEN + WRITE (l_out0, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out0, STRING'(" : ")); + WRITE (l_out0, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out0, STRING'(" : ")); + END IF; + + IF (Bank0 (i) = NULL) THEN -- Row is empty, write message and exit + WRITE (l_out0, STRING'(" Row ")); + WRITE (l_out0, i); + WRITE (l_out0, STRING'(" is empty.")); + WRITELINE (out_file0, l_out0); + EXIT; + ELSE -- Buffering + array_buffer := Bank0 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); -- Convert to STD_LOGIC_VECTOR + WRITE (l_out0, write_data_var, RIGHT, 6, HEX, FALSE); -- Write message + IF (j = 16) then + WRITELINE (out_file0, l_out0); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "01") THEN + WRITE (l_out1, STRING'("Micron Technology Inc. - Unload Data Array - Bank 1 Row ")); + WRITE (l_out1, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file1, l_out1); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out1, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out1, STRING'(" : ")); + WRITE (l_out1, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out1, STRING'(" : ")); + END IF; + + IF (Bank1 (i) = NULL) THEN + WRITE (l_out1, STRING'(" Row ")); + WRITE (l_out1, i); + WRITE (l_out1, STRING'(" is empty.")); + WRITELINE (out_file1, l_out1); + EXIT; + ELSE + array_buffer := Bank1 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out1, write_data_var, RIGHT, 6, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file1, l_out1); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "10") THEN + WRITE (l_out2, STRING'("Micron Technology Inc. - Unload Data Array - Bank 2 Row ")); + WRITE (l_out2, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file2, l_out2); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out2, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out2, STRING'(" : ")); + WRITE (l_out2, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out2, STRING'(" : ")); + END IF; + + IF (Bank2 (i) = NULL) THEN + WRITE (l_out2, STRING'(" Row ")); + WRITE (l_out2, i); + WRITE (l_out2, STRING'(" is empty.")); + WRITELINE (out_file2, l_out2); + EXIT; + ELSE + array_buffer := Bank2 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out2, write_data_var, RIGHT, 6, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file2, l_out2); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "11") THEN + WRITE (l_out3, STRING'("Micron Technology Inc. - Unload Data Array - Bank 3 Row ")); + WRITE (l_out3, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file3, l_out3); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out3, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out3, STRING'(" : ")); + WRITE (l_out3, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out3, STRING'(" : ")); + END IF; + + IF (Bank3 (i) = NULL) THEN + WRITE (l_out3, STRING'(" Row ")); + WRITE (l_out3, i); + WRITE (l_out3, STRING'(" is empty.")); + WRITELINE (out_file3, l_out3); + EXIT; + ELSE + array_buffer := Bank3 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out3, write_data_var, RIGHT, 6, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file3, l_out3); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + END IF; + END LOOP; + END IF; + + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 2)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + WAIT FOR tWRa; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 2)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + WAIT FOR tWRa; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 2)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + WAIT FOR tWRa; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_write(3) = '1' AND WR_counter(3) >= 2)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + WAIT FOR tWRa; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + + -- Checking internal wires (Optional for debug purpose) + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Pre_chk (2) <= Pc_b2; + Pre_chk (3) <= Pc_b3; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Act_chk (2) <= Act_b2; + Act_chk (3) <= Act_b3; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "Dq Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc4m16a2/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc4m16a2/mti_pkg.vhd new file mode 100644 index 0000000..7ab90da --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/mti_pkg.vhd @@ -0,0 +1,128 @@ +-- ---------------------------------------------------------------------------- +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +-- ---------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION TO_INTEGER (input : BIT) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + FUNCTION TO_INTEGER (input : BIT) RETURN INTEGER IS + BEGIN + CASE input IS + WHEN '0' => RETURN 0; + WHEN '1' => RETURN 1; + WHEN OTHERS => RETURN 0; + END CASE; + END TO_INTEGER; + + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + BEGIN + CASE input IS + WHEN '0' | 'L' => RETURN 0; + WHEN '1' | 'H' => RETURN 1; + WHEN OTHERS => RETURN 0; + END CASE; + END TO_INTEGER; + + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' OR input(i) = 'H' THEN + result := result + weight; + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc4m16a2/outdata0.txt b/lib/models/memory/sdram/mt48lc4m16a2/outdata0.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc4m16a2/outdata1.txt b/lib/models/memory/sdram/mt48lc4m16a2/outdata1.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc4m16a2/outdata2.txt b/lib/models/memory/sdram/mt48lc4m16a2/outdata2.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc4m16a2/outdata3.txt b/lib/models/memory/sdram/mt48lc4m16a2/outdata3.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc4m16a2/readme.txt b/lib/models/memory/sdram/mt48lc4m16a2/readme.txt new file mode 100644 index 0000000..df7ad5c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/readme.txt @@ -0,0 +1,14 @@ +To operate the test bench for the Micron SDRAM VHDL model, follow the directions +given below: + +1. Be sure all supporting files for the SDRAM are compiled into your library: + + util1164.vhd + stdlogar.vhd + io_utils.vhd + mti_pkg.vhd + +2. Next, compile the mt48lc4m16a2.vhd file and the test.vhd file. + +3. Simulate the "tb" architecture. This is the testbench for the 64Mb SDRAM. + diff --git a/lib/models/memory/sdram/mt48lc4m16a2/runall.do b/lib/models/memory/sdram/mt48lc4m16a2/runall.do new file mode 100644 index 0000000..0cde4e3 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/runall.do @@ -0,0 +1,42 @@ +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all +vcom mt48lc4m16a2.vhd +vcom test.vhd +vsim tb +add wave -logic /u1/clk +add wave -logic /u1/cke +add wave -logic /u1/cs_n +add wave -logic /u1/ras_n +add wave -logic /u1/cas_n +add wave -logic /u1/we_n +add wave -literal -dec /u1/addr +add wave -literal -dec /u1/ba +add wave -literal -dec /u1/dq +add wave -literal /u1/dqm +add wave -literal /u1/operation +add wave -literal -dec /u1/mode_reg +add wave -logic /u1/active_enable +add wave -logic /u1/aref_enable +add wave -logic /u1/burst_term +add wave -logic /u1/mode_reg_enable +add wave -logic /u1/prech_enable +add wave -logic /u1/read_enable +add wave -logic /u1/write_enable +add wave -logic /u1/burst_length_1 +add wave -logic /u1/burst_length_2 +add wave -logic /u1/burst_length_4 +add wave -logic /u1/burst_length_8 +add wave -logic /u1/cas_latency_2 +add wave -logic /u1/cas_latency_3 +add wave -literal /u1/pre_chk +add wave -literal /u1/act_chk +add wave -literal /u1/bank_chk +add wave -literal -dec /u1/row_chk +add wave -literal -dec /u1/col_chk +run -all diff --git a/lib/models/memory/sdram/mt48lc4m16a2/stdlogar.vhd b/lib/models/memory/sdram/mt48lc4m16a2/stdlogar.vhd new file mode 100644 index 0000000..e435ea2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/stdlogar.vhd @@ -0,0 +1,2247 @@ +-------------------------------------------------------------------------- +-- -- +-- Copyright (c) 1990,1991,1992 by Synopsys, Inc. All rights reserved. -- +-- -- +-- This source file may be used and distributed without restriction -- +-- provided that this copyright statement is not removed from the file -- +-- and that any derivative work contains this copyright notice. -- +-- -- +-- Package name: STD_LOGIC_ARITH -- +-- -- +-- Purpose: -- +-- A set of arithemtic, conversion, and comparison functions -- +-- for SIGNED, UNSIGNED, SMALL_INT, INTEGER, -- +-- STD_ULOGIC, STD_LOGIC, and STD_LOGIC_VECTOR. -- +-- -- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; + +package std_logic_arith is + + type UNSIGNED is array (NATURAL range <>) of STD_LOGIC; + type SIGNED is array (NATURAL range <>) of STD_LOGIC; + subtype SMALL_INT is INTEGER range 0 to 1; + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: INTEGER) return SIGNED; + function "+"(L: INTEGER; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: INTEGER) return SIGNED; + function "-"(L: INTEGER; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "+"(L: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED) return SIGNED; + function "-"(L: SIGNED) return SIGNED; + function "ABS"(L: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED) return STD_LOGIC_VECTOR; + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "*"(L: SIGNED; R: SIGNED) return SIGNED; + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + + function CONV_INTEGER(ARG: INTEGER) return INTEGER; + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER; + function CONV_INTEGER(ARG: SIGNED) return INTEGER; + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT; + + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED; + + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED; + + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + -- zero extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- returns STD_LOGIC_VECTOR(SIZE-1 downto 0) + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + + -- sign extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- return STD_LOGIC_VECTOR(SIZE-1 downto 0) + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + +end Std_logic_arith; + + + +library IEEE; +use IEEE.std_logic_1164.all; + +package body std_logic_arith is + + function max(L, R: INTEGER) return INTEGER is + begin + if L > R then + return L; + else + return R; + end if; + end; + + + function min(L, R: INTEGER) return INTEGER is + begin + if L < R then + return L; + else + return R; + end if; + end; + + -- synopsys synthesis_off + type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; + constant tbl_BINARY : tbl_type := + ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); + -- synopsys synthesis_on + + -- synopsys synthesis_off + type tbl_mvl9_boolean is array (STD_ULOGIC) of boolean; + constant IS_X : tbl_mvl9_boolean := + (true, true, false, false, true, true, false, false, true); + -- synopsys synthesis_on + + + + function MAKE_BINARY(A : STD_ULOGIC) return STD_ULOGIC is + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + if (IS_X(A)) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + return ('X'); + end if; + return tbl_BINARY(A); + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + + + -- Type propagation function which returns a signed type with the + -- size of the left arg. + function LEFT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the left arg. + function LEFT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns a signed type with the + -- size of the result of a signed multiplication + function MULT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the result of a unsigned multiplication + function MULT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + + + function mult(A,B: SIGNED) return SIGNED is + + variable BA: SIGNED((A'length+B'length-1) downto 0); + variable PA: SIGNED((A'length+B'length-1) downto 0); + variable AA: SIGNED(A'length downto 0); + variable neg: STD_ULOGIC; + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_TC_OP + -- pragma type_function MULT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + neg := B(B'left) xor A(A'left); + BA := CONV_SIGNED(('0' & ABS(B)),(A'length+B'length)); + AA := '0' & ABS(A); + for i in 0 to A'length-1 loop + if AA(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + if (neg= '1') then + return(-PA); + else + return(PA); + end if; + end; + + function mult(A,B: UNSIGNED) return UNSIGNED is + + variable BA: UNSIGNED((A'length+B'length-1) downto 0); + variable PA: UNSIGNED((A'length+B'length-1) downto 0); + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_UNS_OP + -- pragma type_function MULT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + BA := CONV_UNSIGNED(B,(A'length+B'length)); + for i in 0 to A'length-1 loop + if A(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + return(PA); + end; + + -- subtract two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function minus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_TC_OP + + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function plus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_TC_OP + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + -- subtract two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_minus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + + function "*"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1)); -- pragma label mult + end; + + + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1))); -- pragma label mult + end; + + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + + + function "+"(L: UNSIGNED) return UNSIGNED is + begin + return L; + end; + + + function "+"(L: SIGNED) return SIGNED is + begin + return L; + end; + + + function "-"(L: SIGNED) return SIGNED is + -- pragma label_applies_to minus + begin + return 0 - L; -- pragma label minus + end; + + + function "ABS"(L: SIGNED) return SIGNED is + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return L; + else + return 0 - L; + end if; + end; + + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "+"(L: SIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "-"(L: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + variable tmp: SIGNED(L'length-1 downto 0); + begin + tmp := 0 - L; -- pragma label minus + return STD_LOGIC_VECTOR (tmp); + end; + + + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR is + variable tmp: SIGNED(L'length-1 downto 0); + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return STD_LOGIC_VECTOR (L); + else + tmp := 0 - L; + return STD_LOGIC_VECTOR (tmp); + end if; + end; + + + -- Type propagation function which returns the type BOOLEAN + function UNSIGNED_RETURN_BOOLEAN(A,B: UNSIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns the type BOOLEAN + function SIGNED_RETURN_BOOLEAN(A,B: SIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := FALSE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less_or_equal(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := TRUE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := FALSE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less_or_equal(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := TRUE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_eql(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_EQL + begin + for i in L'range loop + if L(i) /= R(i) then + return FALSE; + end if; + end loop; + return TRUE; + end; + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_neq(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_NEQ + begin + for i in L'range loop + if L(i) /= R(i) then + return TRUE; + end if; + end loop; + return FALSE; + end; + + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + variable sign_bit: STD_ULOGIC; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + sign_bit := ARG(ARG'left); + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => sign_bit); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + + + function CONV_INTEGER(ARG: INTEGER) return INTEGER is + begin + return ARG; + end; + + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_UNSIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 31 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: SIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_SIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 32 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + if i /= ARG'left then + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end if; + end loop; + tmp := MAKE_BINARY(ARG(ARG'left)); + if tmp = '1' then + if ARG'length = 32 then + result := (result - 2**30) - 2**30; + else + result := result - (2 ** (ARG'length-1)); + end if; + end if; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT is + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + tmp := tbl_BINARY(ARG); + if tmp = '1' then + return 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + return 0; + else + return 0; + end if; + -- synopsys synthesis_on + end; + + + -- convert an integer to a unsigned STD_ULOGIC_VECTOR + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED is + variable result: UNSIGNED(SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_UNSIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED is + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to a 2's complement STD_ULOGIC_VECTOR + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED is + variable result: SIGNED (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED is + subtype rtype is SIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to an STD_LOGIC_VECTOR + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is + variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) return STD_LOGIC_VECTOR is + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) + return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds: STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + +end std_logic_arith; diff --git a/lib/models/memory/sdram/mt48lc4m16a2/test.do b/lib/models/memory/sdram/mt48lc4m16a2/test.do new file mode 100644 index 0000000..80696c2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc4m16a2.vhd +vcom test.vhd +vsim tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48lc4m16a2/test.txt b/lib/models/memory/sdram/mt48lc4m16a2/test.txt new file mode 100644 index 0000000..78207b0 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/test.txt @@ -0,0 +1,99 @@ +0 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +22 ns 1 1 1 1 1 00 00 0 -100 1 0 0 0 +32 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +42 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +52 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +62 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +72 ns 1 0 0 1 0 00 00 1024 -100 0 0 0 0 +82 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +92 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +102 ns 1 0 0 0 1 00 00 0 -100 0 0 0 0 +112 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +122 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +132 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +142 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +152 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +162 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +172 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +182 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +192 ns 1 0 0 0 1 00 00 0 -100 0 0 0 0 +202 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +212 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +222 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +232 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +242 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +252 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +262 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +272 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +282 ns 1 0 0 0 0 00 00 51 -100 0 0 0 0 +292 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +302 ns 1 0 0 1 1 00 00 0 -100 0 0 0 0 +312 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +322 ns 1 0 1 0 0 00 00 0 10 0 0 0 0 +332 ns 1 1 1 1 1 00 00 0 11 0 0 0 0 +342 ns 1 0 0 1 1 00 01 0 12 0 0 0 0 +352 ns 1 1 1 1 1 00 00 0 13 0 0 0 0 +362 ns 1 1 1 1 1 00 00 0 14 0 0 0 0 +372 ns 1 1 1 1 1 00 00 0 15 0 0 0 0 +382 ns 1 1 1 1 1 00 00 0 16 0 0 0 0 +392 ns 1 1 1 1 1 00 00 0 17 0 0 0 0 +402 ns 1 0 1 0 0 00 01 0 20 0 0 0 0 +412 ns 1 0 0 1 0 00 00 0 21 0 0 0 0 +422 ns 1 0 0 1 1 00 10 0 22 0 0 0 0 +432 ns 1 1 1 1 1 00 00 0 23 0 0 0 0 +442 ns 1 1 1 1 1 00 00 0 24 0 0 0 0 +452 ns 1 1 1 1 1 00 00 0 25 0 0 0 0 +462 ns 1 1 1 1 1 00 00 0 26 0 0 0 0 +472 ns 1 1 1 1 1 00 00 0 27 0 0 0 0 +482 ns 1 0 1 0 0 00 10 0 30 0 0 0 0 +492 ns 1 0 0 1 0 00 01 0 31 0 0 0 0 +502 ns 1 0 0 1 1 00 11 0 32 0 0 0 0 +512 ns 1 1 1 1 1 00 00 0 33 0 0 0 0 +522 ns 1 1 1 1 1 00 00 0 34 0 0 0 0 +532 ns 1 1 1 1 1 00 00 0 35 0 0 0 0 +542 ns 1 1 1 1 1 00 00 0 36 0 0 0 0 +552 ns 1 1 1 1 1 00 00 0 37 0 0 0 0 +562 ns 1 0 1 0 0 00 11 0 40 0 0 0 0 +572 ns 1 0 0 1 0 00 10 0 41 0 0 0 0 +582 ns 1 0 0 1 1 00 00 0 42 0 0 0 0 +592 ns 1 1 1 1 1 00 00 0 43 0 0 0 0 +602 ns 1 1 1 1 1 00 00 0 44 0 0 0 0 +612 ns 1 1 1 1 1 00 00 0 45 0 0 0 0 +622 ns 1 1 1 1 1 00 00 0 46 0 0 0 0 +632 ns 1 1 1 1 1 00 00 0 47 0 0 0 0 +642 ns 1 0 1 0 1 00 00 0 -100 0 0 0 0 +652 ns 1 0 0 1 0 00 11 0 -100 0 0 0 0 +662 ns 1 0 0 1 1 00 01 0 -100 0 0 0 0 +672 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +682 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +692 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +702 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +712 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +722 ns 1 0 1 0 1 00 01 0 -100 0 0 0 0 +732 ns 1 0 0 1 0 00 00 0 -100 0 0 0 0 +742 ns 1 0 0 1 1 00 10 0 -100 0 0 0 0 +752 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +762 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +772 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +782 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +792 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +802 ns 1 0 1 0 1 00 10 0 -100 0 0 0 0 +812 ns 1 0 0 1 0 00 01 0 -100 0 0 0 0 +822 ns 1 0 0 1 1 00 11 0 -100 0 0 0 0 +832 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +842 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +852 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +862 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +872 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +882 ns 1 0 1 0 1 00 11 0 -100 0 0 0 0 +892 ns 1 0 0 1 0 00 10 0 -100 0 0 0 0 +902 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +912 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +922 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +932 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +942 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +952 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +962 ns 1 0 0 1 0 00 11 0 -100 0 0 0 0 +972 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +982 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +992 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 diff --git a/lib/models/memory/sdram/mt48lc4m16a2/test.vhd b/lib/models/memory/sdram/mt48lc4m16a2/test.vhd new file mode 100644 index 0000000..8c24d28 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/test.vhd @@ -0,0 +1,196 @@ +LIBRARY ieee; +LIBRARY work; +USE ieee.std_logic_1164.ALL; +USE work.std_logic_arith.ALL; +USE work.util_1164.ALL; +USE std.textio.ALL; +USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 12; + CONSTANT data_bits : INTEGER := 16; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + + COMPONENT mt48lc4m16a2 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := (OTHERS => '0'); + Load : IN STD_LOGIC := '0'; + Unload : IN STD_LOGIC := '0'; + Row_start : IN INTEGER := 0; + Row_end : IN INTEGER := 0 + ); + END COMPONENT; + + FOR ALL : mt48lc4m16a2 USE ENTITY work.mt48lc4m16a2 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL PLoad : STD_LOGIC; + SIGNAL PUnload : STD_LOGIC; + SIGNAL PRow_start : INTEGER; + SIGNAL PRow_end : INTEGER; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + +BEGIN + u1: mt48lc4m16a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm, + Load => pLoad, + Unload => pUnload, + Row_start => PRow_start, + Row_end => PRow_end + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : STD_LOGIC; + VARIABLE pCs_var : STD_LOGIC; + VARIABLE pRas_var : STD_LOGIC; + VARIABLE PCas_var : STD_LOGIC; + VARIABLE pWe_var : STD_LOGIC; + VARIABLE pDqm_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pBa_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE pLoad_var : STD_LOGIC; + VARIABLE pUnload_var : STD_LOGIC; + VARIABLE pRow_start_var : INTEGER; + VARIABLE pRow_end_var : INTEGER; + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read (l, time_var); + read (l, pCke_var); + read (l, pCs_var); + read (l, pRas_var); + read (l, pCas_var); + read (l, pWe_var); + read (l, pDqm_var); + read (l, pBa_var); + read (l, pAddr_var); + read (l, pDq_var); + read (l, pLoad_var); + read (l, pUnload_var); + read (l, pRow_start_var); + read (l, pRow_end_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + IF pWe_var='1' THEN + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= pLoad_var; + pUnload <= pUnload_var; + pRow_start <= pRow_start_var; + pRow_end <= pRow_end_var; + ELSE + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= pLoad_var; + pUnload <= pUnload_var; + pRow_start <= pRow_start_var; + pRow_end <= pRow_end_var; + END IF; + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc4m16a2/util1164.vhd b/lib/models/memory/sdram/mt48lc4m16a2/util1164.vhd new file mode 100644 index 0000000..bb4b5dd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/util1164.vhd @@ -0,0 +1,124 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE STD.textio.ALL; + +PACKAGE util_1164 IS + PROCEDURE read(l: INOUT line; value: OUT std_logic); + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector); + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0); + PROCEDURE Grow_line(L : inout LINE; incr : in integer); +END util_1164; + + + +PACKAGE BODY util_1164 IS + + FUNCTION white_space(value:character) RETURN boolean IS + VARIABLE result:boolean; + BEGIN + IF (value = ' ') OR (value = HT) THEN + RETURN true; + ELSE + RETURN false; + END IF; + END white_space; + + PROCEDURE read(l: INOUT line; value: OUT std_logic) IS + VARIABLE char_var: character:= ' '; + BEGIN + WHILE l'LENGTH > 0 LOOP + read(l,char_var); + IF NOT white_space(char_var) THEN + EXIT; + END IF; + END LOOP; + IF white_space(char_var) THEN + ASSERT false REPORT "No std_logic value found in file" + SEVERITY error; + value := 'X'; + RETURN; + END IF; + + CASE char_var IS + WHEN 'U'|'u' => value := 'U'; + WHEN '0' => value := '0'; + WHEN '1' => value := '1'; + WHEN 'X'|'x' => value := 'X'; + WHEN 'L'|'l' => value := 'L'; + WHEN 'H'|'h' => value := 'H'; + WHEN 'W'|'w' => value := 'W'; + WHEN 'Z'|'z' => value := 'Z'; + WHEN '-' => value := '-'; + WHEN OTHERS => + ASSERT false REPORT "Unrecognized value read for std_logic" + SEVERITY error; + value := 'X'; + END CASE; + END read; + + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector) IS + BEGIN + FOR i IN value'HIGH DOWNTO value'LOW LOOP + IF l'LENGTH > 0 THEN + read(l,value(i)); + ELSE + ASSERT false REPORT "Not enough values for std_logic_vector in file" + SEVERITY error; + RETURN; + END IF; + END LOOP; + END read; + + procedure Grow_line(L : inout LINE; incr : in integer) + is + variable old_L : LINE := L; + variable bfp: integer; -- Blank fill pointer. + begin + assert incr > 0 + report "Textio: Grow_line called with zero increment." + severity error; + + if L = null then + bfp := 0; + L := new string(1 to incr); + else + bfp := old_L'high; + L := new string(old_L'low to old_L'high + incr); + L(old_L'low to old_L'high) := old_L.all; + Deallocate(old_L); + end if; + for i in 1 to incr loop + L(bfp + i) := ' '; + end loop; + end; + + + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0) IS + variable fw: integer := VALUE'length; + variable bp: integer; + variable offset: integer := 0; + alias normal : std_logic_vector(0 to value'length - 1) is value; + begin + if L /= null then + bp := L'high + 1; + else bp := 1; + end if; + if FIELD > VALUE'length then + fw := FIELD; + if JUSTIFIED = right then + offset := fw - VALUE'length; + end if; + end if; + Grow_line(L, fw); + for i in normal'range loop + L(bp + i + offset) := character'val( + std_logic'pos(normal(i)) + character'pos('0')); + end loop; + end; + + +END util_1164; diff --git a/lib/models/memory/sdram/mt48lc4m16a2/vec_gen.vhd b/lib/models/memory/sdram/mt48lc4m16a2/vec_gen.vhd new file mode 100644 index 0000000..e036644 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/vec_gen.vhd @@ -0,0 +1,373 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.io_utils.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); + first_data : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle(SIGNAL clk : IN BIT); + PROCEDURE load_array(load : IN BIT); + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)); + +END generate_vectors; + + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; + dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, first_data, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, row_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 1, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS + +BEGIN + +WAIT UNTIL clk = '1'; + +END; + +PROCEDURE load_array(load : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 1, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 1, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 1, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 1, right, 4); --unload +write(l, row_start, right, 6); --row_address_start +write(l, row_end, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, op_code, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc4m16a2/vector.do b/lib/models/memory/sdram/mt48lc4m16a2/vector.do new file mode 100644 index 0000000..7480359 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/vector.do @@ -0,0 +1,4 @@ +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all diff --git a/lib/models/memory/sdram/mt48lc4m16a2/wave.do b/lib/models/memory/sdram/mt48lc4m16a2/wave.do new file mode 100644 index 0000000..ea73676 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m16a2/wave.do @@ -0,0 +1,34 @@ +onerror {resume} +add wave -logic /tb/u1/clk +add wave -logic /tb/u1/cke +add wave -logic /tb/u1/cs_n +add wave -logic /tb/u1/ras_n +add wave -logic /tb/u1/cas_n +add wave -logic /tb/u1/we_n +add wave -literal -decimal /tb/u1/addr +add wave -literal -binary /tb/u1/ba +add wave -literal -hexadecimal /tb/u1/dq +add wave -literal /tb/u1/dqm +add wave -literal /tb/u1/operation +add wave -literal -decimal /tb/u1/mode_reg +add wave -logic /tb/u1/active_enable +add wave -logic /tb/u1/aref_enable +add wave -logic /tb/u1/burst_term +add wave -logic /tb/u1/mode_reg_enable +add wave -logic /tb/u1/prech_enable +add wave -logic /tb/u1/read_enable +add wave -logic /tb/u1/write_enable +add wave -logic /tb/u1/burst_length_1 +add wave -logic /tb/u1/burst_length_2 +add wave -logic /tb/u1/burst_length_4 +add wave -logic /tb/u1/burst_length_8 +add wave -logic /tb/u1/cas_latency_2 +add wave -logic /tb/u1/cas_latency_3 +add wave -literal /tb/u1/pre_chk +add wave -literal /tb/u1/act_chk +add wave -literal /tb/u1/bank_chk +add wave -literal -decimal /tb/u1/row_chk +add wave -literal -decimal /tb/u1/col_chk +add wave -logic /tb/u1/dq_in_chk +add wave -logic /tb/u1/dq_out_chk +add wave -literal -decimal /tb/u1/rw_bank_chk diff --git a/lib/models/memory/sdram/mt48lc4m32b2/mt48lc4m32b2.vhd b/lib/models/memory/sdram/mt48lc4m32b2/mt48lc4m32b2.vhd new file mode 100644 index 0000000..ddb8820 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m32b2/mt48lc4m32b2.vhd @@ -0,0 +1,1148 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC4M32B2.VHD +-- Version: 0.0g +-- Date: May 19th, 2000 +-- Model: Behavioral +-- Simulator: Model Technology VLOG (PC version 5.3 PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC4M32B2 (1Mb x 32 x 4 Banks) +-- +-- Description: Micron 64Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0g Son Huynh 208-368-3825 05/19/2000 Fix tWR + tRP timing +-- Micron Technology Inc. +-- +-- 0.0a Son P. Huynh 208-368-3825 12/02/1999 First Release +-- Micron Technology Inc. - Simple testbench included +----------------------------------------------------------------------------------------- + +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + USE ieee.std_logic_unsigned.conv_integer; + USE ieee.std_logic_arith.conv_std_logic_vector; + +ENTITY mt48lc4m32b2 IS + GENERIC ( + -- Timing Parameters for -6 and CAS Latency = 2 + tAC : TIME := 7.5 ns; + tHZ : TIME := 7.5 ns; + tOH : TIME := 2.0 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 42.0 ns; + tRC : TIME := 60.0 ns; + tRCD : TIME := 18.0 ns; + tRP : TIME := 18.0 ns; + tRRD : TIME := 12.0 ns; + tWRa : TIME := 6.0 ns; -- A2 Version - Auto precharge mode only (1 Clk + 6 ns) + tWRp : TIME := 12.0 ns; -- A2 Version - Precharge mode only (12 ns) + + tAH : TIME := 1.0 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 7.5 ns; + tDH : TIME := 1.0 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 1.0 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 1.0 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 12; + data_bits : INTEGER := 32; + col_bits : INTEGER := 8 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC_VECTOR (3 DOWNTO 0) := (OTHERS => '0') + ); +END mt48lc4m32b2; + +ARCHITECTURE behave OF mt48lc4m32b2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, FILE_LOAD, FILE_UNLOAD); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF STD_LOGIC; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF STD_LOGIC_VECTOR (1 DOWNTO 0); -- For Bank Pipeline + TYPE Array2x4BV IS ARRAY (1 DOWNTO 0) OF STD_LOGIC_VECTOR (3 DOWNTO 0); -- For Dqm Pipeline + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF STD_LOGIC_VECTOR (Col_bits - 1 DOWNTO 0); -- For Column Pipeline + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : STD_LOGIC := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : STD_LOGIC := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : STD_LOGIC := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : STD_LOGIC := '0'; + SIGNAL Cs_in, Ras_in, Cas_in, We_in : STD_LOGIC := '0'; + SIGNAL Write_burst_mode : STD_LOGIC := '0'; + SIGNAL RAS_clk, Sys_clk, CkeZ : STD_LOGIC := '0'; + +BEGIN + -- Strip the strength + Cs_in <= To_X01 (Cs_n); + Ras_in <= To_X01 (Ras_n); + Cas_in <= To_X01 (Cas_n); + We_in <= To_X01 (We_n); + + -- Commands Decode + Active_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= NOT(Cs_in) AND Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- RAS Clock for checking tWR and tRP + PROCESS + variable Clk0, Clk1 : integer := 0; + begin + RAS_clk <= '1'; + wait for 0.5 ns; + RAS_clk <= '0'; + wait for 0.5 ns; + if Clk0 > 100 or Clk1 > 100 then + wait; + else + if Clk = '1' then + Clk0 := 0; + Clk1 := Clk1 + 1; + else + Clk0 := Clk0 + 1; + Clk1 := 0; + end if; + end if; + END PROCESS; + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= Cke; + END IF; + Sys_clk <= CkeZ AND Clk; + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg0, Dqm_reg1 : STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000"; + + VARIABLE Bank, Previous_bank : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_bank : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : STD_LOGIC := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : STD_LOGIC := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : STD_LOGIC := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : STD_LOGIC_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := conv_integer(Col) + 1; + Col_temp := CONV_STD_LOGIC_VECTOR(Col_int, col_bits); + ELSIF Mode_reg (3) = '1' THEN + Col_vec := CONV_STD_LOGIC_VECTOR(Burst_counter, col_bits); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, RAS_clk; + IF Sys_clk'event AND Sys_clk = '1' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg0 := Dqm_reg1; + Dqm_reg1 := Dqm; + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Precharge Timer for tWR + if (Burst_length_1 = '1' OR Write_burst_mode = '1') then + if (Count_precharge(0) = 1) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 1) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 1) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 1) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_2 = '1') then + if (Count_precharge(0) = 2) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 2) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 2) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 2) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_4 = '1') then + if (Count_precharge(0) = 4) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 4) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 4) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 4) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_8 = '1') then + if (Count_precharge(0) = 8) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 8) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 8) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 8) then + Count_time(3) := NOW; + end if; + end if; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) := WR_counter(0) + 1; + WR_counter(1) := WR_counter(1) + 1; + WR_counter(2) := WR_counter(2) + 1; + WR_counter(3) := WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= Addr; + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := Addr; + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := Addr; + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := Addr; + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := Addr; + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= Ba) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := Ba; + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR + (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkp(CONV_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = Ba OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := Ba; + A10_precharge(2) := Addr(10); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := Ba; + A10_precharge(1) := Addr(10); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (2) := Ba; + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (1) := Ba; + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (0) := Ba; + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' AND Write_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_write(CONV_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' AND Read_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_read(CONV_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (CONV_INTEGER(Ba)) := '1'; + Count_precharge (CONV_INTEGER(Ba)) := 0; + RW_interrupt_bank := Ba; + IF Read_enable = '1' THEN + Read_precharge (CONV_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (CONV_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := CONV_INTEGER (Row); + Col_index := CONV_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm /= "1111" THEN + -- Initialize memory + Init_mem (Bank, Row_index); + -- Load memory into buffer + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + END IF; + -- Dqm operation + IF Dqm (0) = '0' THEN + Dq_temp (7 DOWNTO 0) := Dq (7 DOWNTO 0); + END IF; + IF Dqm (1) = '0' THEN + Dq_temp (15 DOWNTO 8) := Dq (15 DOWNTO 8); + END IF; + IF Dqm (2) = '0' THEN + Dq_temp (23 DOWNTO 16) := Dq (23 DOWNTO 16); + END IF; + IF Dqm (3) = '0' THEN + Dq_temp (31 DOWNTO 24) := Dq (31 DOWNTO 24); + END IF; + -- Write back to memory + IF Bank = "00" THEN + Bank0 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "01" THEN + Bank1 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "10" THEN + Bank2 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "11" THEN + Bank3 (Row_index) (Col_index) := Dq_temp; + END IF; + -- Reset tWR counter + WR_chkp(CONV_INTEGER(Bank)) := NOW; + WR_counter(CONV_INTEGER(Bank)) := 0; + END IF; + -- Decode next burst address + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg0 /= "1111" THEN + -- Initialize memory + Init_mem (Bank, Row_index); + -- Load memory into buffer + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + END IF; + -- Dqm operation + IF Dqm_reg0 (0) = '0' THEN + Dq (7 DOWNTO 0) <= TRANSPORT Dq_temp(7 DOWNTO 0) AFTER tAC; + ELSE + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + IF Dqm_reg0 (1) = '0' THEN + Dq (15 DOWNTO 8) <= TRANSPORT Dq_temp(15 DOWNTO 8) AFTER tAC; + ELSE + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + IF Dqm_reg0 (2) = '0' THEN + Dq (23 DOWNTO 16) <= TRANSPORT Dq_temp(23 DOWNTO 16) AFTER tAC; + ELSE + Dq (23 DOWNTO 16) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + IF Dqm_reg0 (3) = '0' THEN + Dq (31 DOWNTO 24) <= TRANSPORT Dq_temp(31 DOWNTO 24) AFTER tAC; + ELSE + Dq (31 DOWNTO 24) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + END IF; + END PROCESS; + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "DQ Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc4m32b2/test.do b/lib/models/memory/sdram/mt48lc4m32b2/test.do new file mode 100644 index 0000000..532c7c2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m32b2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc4m32b2.vhd +vcom test.vhd +vsim -t ps tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48lc4m32b2/test.vhd b/lib/models/memory/sdram/mt48lc4m32b2/test.vhd new file mode 100644 index 0000000..473dccb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m32b2/test.vhd @@ -0,0 +1,309 @@ +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + +ENTITY tb IS +END tb; + +ARCHITECTURE test OF tb IS + COMPONENT mt48lc4m32b2 + GENERIC ( -- Timing for -7 CL2 + tCK : TIME := 7.500 ns; + addr_bits : INTEGER := 12; + data_bits : INTEGER := 32 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000" + ); + END COMPONENT; + + FOR ALL : mt48lc4m32b2 USE ENTITY work.mt48lc4m32b2 (behave); + + CONSTANT tCK : TIME := 7.500 ns; + CONSTANT addr_bits : INTEGER := 12; + CONSTANT data_bits : INTEGER := 32; + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs_n : STD_LOGIC; + SIGNAL pCas_n : STD_LOGIC; + SIGNAL pRas_n : STD_LOGIC; + SIGNAL pWe_n : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC_VECTOR (3 DOWNTO 0); + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc4m32b2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs_n, + Ras_n => pRas_n, + Cas_n => pCas_n, + We_n => pWe_n, + Dqm => pDqm + ); + + stimulator : PROCESS + PROCEDURE ACTIVE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '1'; + pWe_n <= '1'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE AUTO_REFRESH IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '0'; + pWe_n <= '1'; + pDqm <= "0000"; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE BURST_TERM IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '1'; + pWe_n <= '0'; + pDqm <= "0000"; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE LOAD_MODE_REG (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '0'; + pWe_n <= '0'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE NOP (Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '1'; + pWe_n <= '1'; + pDqm <= "0000"; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE PRECHARGE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '1'; + pWe_n <= '0'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE READ (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '0'; + pWe_n <= '1'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + -- Write + PROCEDURE WRITE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '0'; + pWe_n <= '0'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + BEGIN + -- COMMAND BA ADDR DQ + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + -- We need 100 us power up sequence. I use 10 NOPs here as a required example. + PRECHARGE ("00", "010000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + AUTO_REFRESH; + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + AUTO_REFRESH; + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + LOAD_MODE_REG ("00", "000000100010"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("00", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("01", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("10", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("11", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + WRITE ("00", "000000000000", "00000000000000000000000000000000"); + NOP ( "00000000000000000000000000000001"); + NOP ( "00000000000000000000000000000010"); + NOP ( "00000000000000000000000000000011"); + + WRITE ("01", "000000000000", "00000000000000000000000000000100"); + NOP ( "00000000000000000000000000000101"); + NOP ( "00000000000000000000000000000110"); + NOP ( "00000000000000000000000000000111"); + + WRITE ("10", "000000000000", "00000000000000000000000000001000"); + NOP ( "00000000000000000000000000001001"); + NOP ( "00000000000000000000000000001010"); + NOP ( "00000000000000000000000000001011"); + + WRITE ("11", "000000000000", "00000000000000000000000000001100"); + NOP ( "00000000000000000000000000001101"); + NOP ( "00000000000000000000000000001110"); + NOP ( "00000000000000000000000000001111"); + + READ ("00", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + READ ("01", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + READ ("10", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + READ ("11", "000000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for tCK/2; + WHILE not stim_done loop + pclk <= '1'; + WAIT for tCK/2; + pclk <= '0'; + WAIT for tCK/2; + END LOOP; + done_time := now + tCK; + WHILE now < done_time LOOP -- one last clock to finish last command + pclk <= '1'; + WAIT for tCK/2; + pclk <= '0'; + WAIT for tCK/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; +END test; diff --git a/lib/models/memory/sdram/mt48lc4m32b2/wave.do b/lib/models/memory/sdram/mt48lc4m32b2/wave.do new file mode 100644 index 0000000..26de1d2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc4m32b2/wave.do @@ -0,0 +1,26 @@ +add wave -noupdate -radix default -format Logic /tb/u1/clk +add wave -noupdate -radix default -format Logic /tb/u1/cke +add wave -noupdate -radix default -format Logic /tb/u1/cs_n +add wave -noupdate -radix default -format Logic /tb/u1/ras_n +add wave -noupdate -radix default -format Logic /tb/u1/cas_n +add wave -noupdate -radix default -format Logic /tb/u1/we_n +add wave -noupdate -radix decimal /tb/u1/addr +add wave -noupdate -radix unsigned /tb/u1/ba +add wave -noupdate -radix decimal /tb/u1/dq +add wave -noupdate -radix default -format Logic /tb/u1/dqm +add wave -noupdate -radix decimal /tb/u1/operation +add wave -noupdate -radix decimal /tb/u1/mode_reg +add wave -noupdate -radix default -format Logic /tb/u1/active_enable +add wave -noupdate -radix default -format Logic /tb/u1/aref_enable +add wave -noupdate -radix default -format Logic /tb/u1/burst_term +add wave -noupdate -radix default -format Logic /tb/u1/mode_reg_enable +add wave -noupdate -radix default -format Logic /tb/u1/prech_enable +add wave -noupdate -radix default -format Logic /tb/u1/read_enable +add wave -noupdate -radix default -format Logic /tb/u1/write_enable +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_1 +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_2 +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_4 +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_8 +add wave -noupdate -radix default -format Logic /tb/u1/cas_latency_2 +add wave -noupdate -radix default -format Logic /tb/u1/cas_latency_3 + diff --git a/lib/models/memory/sdram/mt48lc64m4a2/base.do b/lib/models/memory/sdram/mt48lc64m4a2/base.do new file mode 100644 index 0000000..d2afbcb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/base.do @@ -0,0 +1,5 @@ +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd + diff --git a/lib/models/memory/sdram/mt48lc64m4a2/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc64m4a2/ed_comnd.vhd new file mode 100644 index 0000000..bd59d3c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/ed_comnd.vhd @@ -0,0 +1,345 @@ +--------------------------------------------------------------------------------- +--COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit_vector), first data(integer), dqm(bit), cke(bit));-- +-- read(column address(integer), bank(bit_vector), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit_vector), data bus (integer), dqm(bit), cke(bit));-- +-- precharge(bank(bit_vector), address (integer), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit), cs(bit)); -- +-- burst_term(data bus(integer), dqm(bit), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit_vector)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +--------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, '0', '1', '1'); --Always begin with one nop when using Micron's testbench + +--next_cycle(clk); +--load_array('1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +precharge("00", 1024, Z, '0', '1'); + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, '0', '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, '0', '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, '0', '1', '1'); +END LOOP; + +next_cycle(clk); +load_mode_reg(51, '1'); -- 19 / 35 / 51 -> lat=3,bl=8,mode=seq + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +-- Write Section + +next_cycle(clk); +active(0, "00", Z, '0', '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); -- Write Bank 0 +write(10, "00", 0, '0', '1'); + +next_cycle(clk); +nop(1, '0', '1', '1'); + +next_cycle(clk); +active(0, "01", 2, '0', '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(3, '0', '1', '1'); + +next_cycle(clk); +nop(4, '0', '1', '1'); + +next_cycle(clk); +nop(5, '0', '1', '1'); + +next_cycle(clk); +nop(6, '0', '1', '1'); + +next_cycle(clk); +nop(7, '0', '1', '1'); + +next_cycle(clk); +write(20, "01", 8, '0', '1'); -- Write Bank 1 + +next_cycle(clk); +precharge("00", 0, 9, '0', '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", 10, '0', '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(11, '0', '1', '1'); + +next_cycle(clk); +nop(12, '0', '1', '1'); + +next_cycle(clk); +nop(13, '0', '1', '1'); + +next_cycle(clk); +nop(14, '0', '1', '1'); + +next_cycle(clk); +nop(15, '0', '1', '1'); + +next_cycle(clk); +write(30, "10", 0, '0', '1'); -- Write Bank 2 + +next_cycle(clk); +precharge("01", 0, 1, '0', '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", 2, '0', '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(3, '0', '1', '1'); + +next_cycle(clk); +nop(4, '0', '1', '1'); + +next_cycle(clk); +nop(5, '0', '1', '1'); + +next_cycle(clk); +nop(6, '0', '1', '1'); + +next_cycle(clk); +nop(7, '0', '1', '1'); + +next_cycle(clk); +write(40, "11", 8, '0', '1'); -- Write Bank 3 + +next_cycle(clk); +precharge("10", 0, 9, '0', '1'); -- Precharge Bank 2 + +next_cycle(clk); +active(0, "00", 10, '0', '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(11, '0', '1', '1'); + +next_cycle(clk); +nop(12, '0', '1', '1'); + +next_cycle(clk); +nop(13, '0', '1', '1'); + +next_cycle(clk); +nop(14, '0', '1', '1'); + +next_cycle(clk); +nop(15, '0', '1', '1'); + +-- Read Section + +next_cycle(clk); +read(10, "00", '0', '1'); -- Read Bank 0 + +next_cycle(clk); +precharge("11", 0, Z, '0', '1'); -- Precharge Bank 3 + +next_cycle(clk); +active(0, "01", Z, '0', '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +read(20, "01", '0', '1'); -- Read Bank 1 + +next_cycle(clk); +precharge("00", 0, Z, '0', '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", Z, '0', '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +read(30, "10", '0', '1'); -- Read Bank 2 + +next_cycle(clk); +precharge("01", 0, Z, '0', '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", Z, '0', '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +read(40, "11", '0', '1'); -- Read Bank 3 + +next_cycle(clk); +precharge("10", 0, Z, '0', '1'); -- Precharge Bank 2 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +precharge("11", 0, Z, '0', '1'); -- Precharge Bank 3 + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +--next_cycle(clk); +--unload_array(0, 0, '0'); + +next_cycle(clk); +nop(Z, '0', '1', '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc64m4a2/io_utils.vhd b/lib/models/memory/sdram/mt48lc64m4a2/io_utils.vhd new file mode 100644 index 0000000..dfcb84a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/io_utils.vhd @@ -0,0 +1,266 @@ +LIBRARY ieee; +USE std.textio.ALL; +USE ieee.std_logic_1164.ALL; + +PACKAGE io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0); + + TYPE radix IS (binary, octal, decimal, hex); + + -- read a number from the line + -- use this if you have hex numbers that are not in VHDL pound-sign format + PROCEDURE read(l : INOUT line; value : OUT integer; radix : IN positive); + + -- read a number that might be in VHDL pound-sign format + PROCEDURE read_based(l : INOUT line; value : OUT integer); + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); +END io_utils; + +PACKAGE BODY io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0) + IS + BEGIN + write(l, value, justified, field); + END; + + PROCEDURE shrink_line(l : INOUT line; pos : integer) IS + VARIABLE tmpl : line; + BEGIN + tmpl := l; + l := NEW string'(tmpl(pos TO tmpl'high)); + deallocate(tmpl); + END; + + PROCEDURE read(l : INOUT line; + value : OUT integer; + radix : IN positive) + IS + CONSTANT not_digit : integer := -999; + + -- convert a character to a value from 0 to 15 + FUNCTION digit_value(c : character) RETURN integer IS + BEGIN + IF (c >= '0') AND (c <= '9') THEN + RETURN (character'pos(c) - character'pos('0')); + ELSIF (c >= 'a') AND (c <= 'f') THEN + RETURN (character'pos(c) - character'pos('a') + 10); + ELSIF (c >= 'A') AND (c <= 'F') THEN + RETURN (character'pos(c) - character'pos('A') + 10); + ELSE + RETURN not_digit; + END IF; + END; + + -- skip leading white space in the line + PROCEDURE skip_white(VARIABLE l : IN line; pos : OUT integer) IS + BEGIN + pos := l'low; + FOR i IN l'low TO l'high LOOP + CASE l(i) IS + WHEN ' ' | ht => + pos := i + 1; + WHEN OTHERS => + EXIT; + END CASE; + END LOOP; + END; + + VARIABLE digit : integer; + VARIABLE result : integer := 0; + VARIABLE pos : integer; + BEGIN + -- skip white space + skip_white(l, pos); + + -- calculate the value + FOR i IN pos TO l'right LOOP + digit := digit_value(l(i)); + EXIT WHEN (digit = not_digit) OR (digit >= radix); + result := result * radix + digit; + pos := i + 1; + END LOOP; + value := result; + + -- remove the "used" characters from the line + shrink_line(l, pos); + END; + + PROCEDURE read_based(l : INOUT line; value : OUT integer) IS + VARIABLE digit : integer; + VARIABLE num : integer; + VARIABLE base : integer; + BEGIN + read(l, num, 10); + IF (l'length > 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + base := num; + read(l, num, base); + IF (l'length >= 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + END IF; + END IF; + value := num; + END; + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_int(bv : std_logic_vector) RETURN integer + IS + VARIABLE result : integer := 0; + BEGIN + FOR i IN bv'RANGE LOOP + result := result * 2; + IF (bv(i) = '1') THEN + result := result + 1; + END IF; + END LOOP; + RETURN result; + END; + + TYPE array_of_widths IS ARRAY(radix) OF natural; + CONSTANT nibble_widths : array_of_widths := ( + binary => 1, + octal => 3, + hex => 4, + decimal=> 32); + CONSTANT hex_digit : string(1 TO 16) := "0123456789ABCDEF"; + + ALIAS input_val : std_logic_vector(value'length DOWNTO 1) IS value; + CONSTANT nibble_width : natural := nibble_widths(base); + CONSTANT result_width : natural := (value'length + nibble_width - 1)/nibble_width; + + VARIABLE result : string(1 TO result_width); -- longest possible value + VARIABLE result_pos : positive := 1; + VARIABLE nibble_val : integer; + VARIABLE bitcnt : integer; + BEGIN + IF base = decimal THEN + write(l, to_int(value), justified, field, base, use_pound); + RETURN; + END IF; + + bitcnt := value'length MOD nibble_width; + IF (bitcnt = 0) THEN + bitcnt := nibble_width; + END IF; + FOR i IN input_val'RANGE LOOP + nibble_val := nibble_val * 2; + IF (input_val(i) = '1') THEN + nibble_val := nibble_val + 1; + END IF; + bitcnt := bitcnt - 1; + IF (bitcnt = 0) THEN + result(result_pos) := hex_digit(nibble_val + 1); + result_pos := result_pos + 1; + nibble_val := 0; + bitcnt := nibble_width; + END IF; + END LOOP; + write(l, result, justified, field); + END; + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_bv(int : integer) RETURN std_logic_vector + IS + VARIABLE bv : std_logic_vector(32 DOWNTO 1) := (OTHERS => '0'); + VARIABLE pos : integer := 0; + VARIABLE tmpval : integer := int; + BEGIN + FOR i IN 1 TO 32 LOOP + pos := pos + 1; + IF (tmpval MOD 2) = 1 THEN + bv(i) := '1'; + END IF; + tmpval := tmpval / 2; + EXIT WHEN tmpval = 0; + END LOOP; + RETURN bv(pos DOWNTO 1); + END; + + VARIABLE tmp : line; + BEGIN + IF (base = decimal) THEN + IF (use_pound) THEN + write_string(tmp, "10#"); + END IF; + write(tmp, value); + IF (use_pound) THEN + write_string(tmp, "#"); + END IF; + write(l, tmp.ALL, justified, field); + deallocate(tmp); + ELSE + write(l, to_bv(value), justified, field, base, use_pound); + END IF; + END; + +END io_utils; + + + +-- test the hex number reader +--ENTITY test IS END; + +--USE std.textio.ALL; +--USE work.io_utils.ALL; +--ARCHITECTURE hex_test OF test IS +--BEGIN +-- PROCESS +-- VARIABLE val : integer; +-- FILE myfile : text IS IN "values"; +-- VARIABLE inline : line; +-- VARIABLE outline : line; +-- BEGIN +-- WHILE NOT endfile(myfile) LOOP +-- readline(myfile, inline); + +-- write(outline, inline.ALL); +-- +-- read_based(inline, val); + -- write_string(outline, " binary: "); + -- write(outline, val, base => binary); + -- write_string(outline, " octal: "); + -- write(outline, val, base => octal); + -- write_string(outline, " decimal: "); + -- write(outline, val, base => decimal); +-- write_string(outline, " hex: "); +-- write(outline, val, base => hex); +-- writeline(output, outline); +-- END LOOP; +-- WAIT; +-- END PROCESS; +--END; + + diff --git a/lib/models/memory/sdram/mt48lc64m4a2/mt48lc64m4a2.vhd b/lib/models/memory/sdram/mt48lc64m4a2/mt48lc64m4a2.vhd new file mode 100644 index 0000000..f0ae0e9 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/mt48lc64m4a2.vhd @@ -0,0 +1,1055 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC64M4A2.VHD +-- Version: 0.0f +-- Date: July 8th, 1999 +-- Model: Behavioral +-- Simulator: Model Technology (PC version 5.2e PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC64M4A2 (16Mb x 4 x 4 Banks) +-- +-- Description: Micron 256Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0f Son Huynh 208-368-3825 07/08/1999 Initial Release (from 128Mb) +-- Micron Technology Inc. +-- +----------------------------------------------------------------------------------------- + +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; +LIBRARY work; + USE work.mti_pkg.ALL; + +ENTITY mt48lc64m4a2 IS + GENERIC ( + -- Timing Parameters for -75 (PC133) and CAS Latency = 2 + tAC : TIME := 6.0 ns; + tHZ : TIME := 7.0 ns; + tOH : TIME := 2.7 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 44.0 ns; + tRC : TIME := 66.0 ns; + tRCD : TIME := 20.0 ns; + tRP : TIME := 20.0 ns; + tRRD : TIME := 15.0 ns; + tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) + tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 10.0 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + addr_bits : INTEGER := 13; + data_bits : INTEGER := 4; + col_bits : INTEGER := 11 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC := '0' + ); +END mt48lc64m4a2; + +ARCHITECTURE behave OF mt48lc64m4a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array2xB IS ARRAY (1 DOWNTO 0) OF BIT; + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL Sys_clk, CkeZ : BIT := '0'; + SIGNAL WR_counter : Array4xI := (0 & 0 & 0 & 0); + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg : Array2xB; + + VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + VARIABLE WR_chk : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, WR_counter(0), WR_counter(1), WR_counter(2), WR_counter(3); + IF Sys_clk'event and Sys_clk = '1' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg(0) := Dqm_reg(1); + Dqm_reg(1) := TO_BIT(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) <= WR_counter(0) + 1; + WR_counter(1) <= WR_counter(1) + 1; + WR_counter(2) <= WR_counter(2) + 1; + WR_counter(3) <= WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := TO_BITVECTOR (Addr); + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := TO_BITVECTOR (Addr); + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := TO_BITVECTOR (Ba); + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chk(0) < tWRp) OR (NOW - WR_chk(1) < tWRp) OR + (NOW - WR_chk(2) < tWRp) OR (NOW - WR_chk(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chk(TO_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BITVECTOR (Ba); + A10_precharge(2) := TO_BIT(Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BITVECTOR (Ba); + A10_precharge(1) := TO_BIT(Addr(10)); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(11) & Addr(9 DOWNTO 0)); + Bank_addr (2) := TO_BITVECTOR (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(11) & Addr(9 DOWNTO 0)); + Bank_addr (1) := TO_BITVECTOR (Ba); + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(11) & Addr(9 DOWNTO 0)); + Bank_addr (0) := TO_BITVECTOR (Ba); + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(TO_INTEGER(Bank)) = '1' AND Write_precharge(TO_INTEGER(Bank)) = '1' THEN + RW_interrupt_write(TO_INTEGER(Bank)) := '1'; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(TO_INTEGER(Bank)) = '1' AND Read_precharge(TO_INTEGER(Bank)) = '1' THEN + RW_interrupt_read(TO_INTEGER(Bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm = '0' THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Bank0 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "01" THEN + Bank1 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "10" THEN + Bank2 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "11" THEN + Bank3 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + END IF; + WR_chk(TO_INTEGER(Bank)) := NOW; + WR_counter(TO_INTEGER(Bank)) <= 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg(0) = '0' THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank0 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "01" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank1 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "10" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank2 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "11" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank3 (Row_index) (Col_index)) AFTER tAC; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 2)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + WAIT FOR tWRa; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 2)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + WAIT FOR tWRa; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 2)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + WAIT FOR tWRa; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_write(3) = '1' AND WR_counter(3) >= 2)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + WAIT FOR tWRa; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + + -- Checking internal wires (Optional for debug purpose) + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Pre_chk (2) <= Pc_b2; + Pre_chk (3) <= Pc_b3; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Act_chk (2) <= Act_b2; + Act_chk (3) <= Act_b3; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "Dq Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc64m4a2/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc64m4a2/mti_pkg.vhd new file mode 100644 index 0000000..9e4f824 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/mti_pkg.vhd @@ -0,0 +1,129 @@ +--***************************************************************************** +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +--***************************************************************************** + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + -- Convert BIT to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert BIT_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Conver integer to bit_vector + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc64m4a2/readme.txt b/lib/models/memory/sdram/mt48lc64m4a2/readme.txt new file mode 100644 index 0000000..b208964 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/readme.txt @@ -0,0 +1,14 @@ +To operate the test bench for the Micron SDRAM VHDL model, follow the directions +given below: + +1. Be sure all supporting files for the SDRAM are compiled into your library: + + util1164.vhd + stdlogar.vhd + io_utils.vhd + mti_pkg.vhd + +2. Next, compile the mt48lc64m4a2.vhd file and the test.vhd file. + +3. Simulate the "tb" architecture. This is the testbench for the 256Mb SDRAM. + diff --git a/lib/models/memory/sdram/mt48lc64m4a2/stdlogar.vhd b/lib/models/memory/sdram/mt48lc64m4a2/stdlogar.vhd new file mode 100644 index 0000000..e435ea2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/stdlogar.vhd @@ -0,0 +1,2247 @@ +-------------------------------------------------------------------------- +-- -- +-- Copyright (c) 1990,1991,1992 by Synopsys, Inc. All rights reserved. -- +-- -- +-- This source file may be used and distributed without restriction -- +-- provided that this copyright statement is not removed from the file -- +-- and that any derivative work contains this copyright notice. -- +-- -- +-- Package name: STD_LOGIC_ARITH -- +-- -- +-- Purpose: -- +-- A set of arithemtic, conversion, and comparison functions -- +-- for SIGNED, UNSIGNED, SMALL_INT, INTEGER, -- +-- STD_ULOGIC, STD_LOGIC, and STD_LOGIC_VECTOR. -- +-- -- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; + +package std_logic_arith is + + type UNSIGNED is array (NATURAL range <>) of STD_LOGIC; + type SIGNED is array (NATURAL range <>) of STD_LOGIC; + subtype SMALL_INT is INTEGER range 0 to 1; + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: INTEGER) return SIGNED; + function "+"(L: INTEGER; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: INTEGER) return SIGNED; + function "-"(L: INTEGER; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "+"(L: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED) return SIGNED; + function "-"(L: SIGNED) return SIGNED; + function "ABS"(L: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED) return STD_LOGIC_VECTOR; + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "*"(L: SIGNED; R: SIGNED) return SIGNED; + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + + function CONV_INTEGER(ARG: INTEGER) return INTEGER; + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER; + function CONV_INTEGER(ARG: SIGNED) return INTEGER; + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT; + + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED; + + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED; + + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + -- zero extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- returns STD_LOGIC_VECTOR(SIZE-1 downto 0) + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + + -- sign extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- return STD_LOGIC_VECTOR(SIZE-1 downto 0) + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + +end Std_logic_arith; + + + +library IEEE; +use IEEE.std_logic_1164.all; + +package body std_logic_arith is + + function max(L, R: INTEGER) return INTEGER is + begin + if L > R then + return L; + else + return R; + end if; + end; + + + function min(L, R: INTEGER) return INTEGER is + begin + if L < R then + return L; + else + return R; + end if; + end; + + -- synopsys synthesis_off + type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; + constant tbl_BINARY : tbl_type := + ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); + -- synopsys synthesis_on + + -- synopsys synthesis_off + type tbl_mvl9_boolean is array (STD_ULOGIC) of boolean; + constant IS_X : tbl_mvl9_boolean := + (true, true, false, false, true, true, false, false, true); + -- synopsys synthesis_on + + + + function MAKE_BINARY(A : STD_ULOGIC) return STD_ULOGIC is + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + if (IS_X(A)) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + return ('X'); + end if; + return tbl_BINARY(A); + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + + + -- Type propagation function which returns a signed type with the + -- size of the left arg. + function LEFT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the left arg. + function LEFT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns a signed type with the + -- size of the result of a signed multiplication + function MULT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the result of a unsigned multiplication + function MULT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + + + function mult(A,B: SIGNED) return SIGNED is + + variable BA: SIGNED((A'length+B'length-1) downto 0); + variable PA: SIGNED((A'length+B'length-1) downto 0); + variable AA: SIGNED(A'length downto 0); + variable neg: STD_ULOGIC; + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_TC_OP + -- pragma type_function MULT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + neg := B(B'left) xor A(A'left); + BA := CONV_SIGNED(('0' & ABS(B)),(A'length+B'length)); + AA := '0' & ABS(A); + for i in 0 to A'length-1 loop + if AA(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + if (neg= '1') then + return(-PA); + else + return(PA); + end if; + end; + + function mult(A,B: UNSIGNED) return UNSIGNED is + + variable BA: UNSIGNED((A'length+B'length-1) downto 0); + variable PA: UNSIGNED((A'length+B'length-1) downto 0); + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_UNS_OP + -- pragma type_function MULT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + BA := CONV_UNSIGNED(B,(A'length+B'length)); + for i in 0 to A'length-1 loop + if A(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + return(PA); + end; + + -- subtract two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function minus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_TC_OP + + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function plus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_TC_OP + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + -- subtract two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_minus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + + function "*"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1)); -- pragma label mult + end; + + + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1))); -- pragma label mult + end; + + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + + + function "+"(L: UNSIGNED) return UNSIGNED is + begin + return L; + end; + + + function "+"(L: SIGNED) return SIGNED is + begin + return L; + end; + + + function "-"(L: SIGNED) return SIGNED is + -- pragma label_applies_to minus + begin + return 0 - L; -- pragma label minus + end; + + + function "ABS"(L: SIGNED) return SIGNED is + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return L; + else + return 0 - L; + end if; + end; + + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "+"(L: SIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "-"(L: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + variable tmp: SIGNED(L'length-1 downto 0); + begin + tmp := 0 - L; -- pragma label minus + return STD_LOGIC_VECTOR (tmp); + end; + + + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR is + variable tmp: SIGNED(L'length-1 downto 0); + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return STD_LOGIC_VECTOR (L); + else + tmp := 0 - L; + return STD_LOGIC_VECTOR (tmp); + end if; + end; + + + -- Type propagation function which returns the type BOOLEAN + function UNSIGNED_RETURN_BOOLEAN(A,B: UNSIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns the type BOOLEAN + function SIGNED_RETURN_BOOLEAN(A,B: SIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := FALSE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less_or_equal(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := TRUE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := FALSE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less_or_equal(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := TRUE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_eql(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_EQL + begin + for i in L'range loop + if L(i) /= R(i) then + return FALSE; + end if; + end loop; + return TRUE; + end; + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_neq(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_NEQ + begin + for i in L'range loop + if L(i) /= R(i) then + return TRUE; + end if; + end loop; + return FALSE; + end; + + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + variable sign_bit: STD_ULOGIC; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + sign_bit := ARG(ARG'left); + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => sign_bit); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + + + function CONV_INTEGER(ARG: INTEGER) return INTEGER is + begin + return ARG; + end; + + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_UNSIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 31 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: SIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_SIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 32 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + if i /= ARG'left then + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end if; + end loop; + tmp := MAKE_BINARY(ARG(ARG'left)); + if tmp = '1' then + if ARG'length = 32 then + result := (result - 2**30) - 2**30; + else + result := result - (2 ** (ARG'length-1)); + end if; + end if; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT is + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + tmp := tbl_BINARY(ARG); + if tmp = '1' then + return 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + return 0; + else + return 0; + end if; + -- synopsys synthesis_on + end; + + + -- convert an integer to a unsigned STD_ULOGIC_VECTOR + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED is + variable result: UNSIGNED(SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_UNSIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED is + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to a 2's complement STD_ULOGIC_VECTOR + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED is + variable result: SIGNED (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED is + subtype rtype is SIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to an STD_LOGIC_VECTOR + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is + variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) return STD_LOGIC_VECTOR is + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) + return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds: STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + +end std_logic_arith; diff --git a/lib/models/memory/sdram/mt48lc64m4a2/test.do b/lib/models/memory/sdram/mt48lc64m4a2/test.do new file mode 100644 index 0000000..d0c6ff0 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc64m4a2.vhd +vcom test.vhd +vsim tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48lc64m4a2/test.txt b/lib/models/memory/sdram/mt48lc64m4a2/test.txt new file mode 100644 index 0000000..ad4a459 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/test.txt @@ -0,0 +1,98 @@ +0 ns 1 1 1 1 1 0 00 0 -100 +22 ns 1 1 1 1 1 0 00 0 -100 +32 ns 1 1 1 1 1 0 00 0 -100 +42 ns 1 1 1 1 1 0 00 0 -100 +52 ns 1 1 1 1 1 0 00 0 -100 +62 ns 1 0 0 1 0 0 00 1024 -100 +72 ns 1 1 1 1 1 0 00 0 -100 +82 ns 1 1 1 1 1 0 00 0 -100 +92 ns 1 0 0 0 1 0 00 0 -100 +102 ns 1 1 1 1 1 0 00 0 -100 +112 ns 1 1 1 1 1 0 00 0 -100 +122 ns 1 1 1 1 1 0 00 0 -100 +132 ns 1 1 1 1 1 0 00 0 -100 +142 ns 1 1 1 1 1 0 00 0 -100 +152 ns 1 1 1 1 1 0 00 0 -100 +162 ns 1 1 1 1 1 0 00 0 -100 +172 ns 1 1 1 1 1 0 00 0 -100 +182 ns 1 0 0 0 1 0 00 0 -100 +192 ns 1 1 1 1 1 0 00 0 -100 +202 ns 1 1 1 1 1 0 00 0 -100 +212 ns 1 1 1 1 1 0 00 0 -100 +222 ns 1 1 1 1 1 0 00 0 -100 +232 ns 1 1 1 1 1 0 00 0 -100 +242 ns 1 1 1 1 1 0 00 0 -100 +252 ns 1 1 1 1 1 0 00 0 -100 +262 ns 1 1 1 1 1 0 00 0 -100 +272 ns 1 0 0 0 0 0 00 51 -100 +282 ns 1 1 1 1 1 0 00 0 -100 +292 ns 1 0 0 1 1 0 00 0 -100 +302 ns 1 1 1 1 1 0 00 0 -100 +312 ns 1 0 1 0 0 0 00 10 0 +322 ns 1 1 1 1 1 0 00 0 1 +332 ns 1 0 0 1 1 0 01 0 2 +342 ns 1 1 1 1 1 0 00 0 3 +352 ns 1 1 1 1 1 0 00 0 4 +362 ns 1 1 1 1 1 0 00 0 5 +372 ns 1 1 1 1 1 0 00 0 6 +382 ns 1 1 1 1 1 0 00 0 7 +392 ns 1 0 1 0 0 0 01 20 8 +402 ns 1 0 0 1 0 0 00 0 9 +412 ns 1 0 0 1 1 0 10 0 10 +422 ns 1 1 1 1 1 0 00 0 11 +432 ns 1 1 1 1 1 0 00 0 12 +442 ns 1 1 1 1 1 0 00 0 13 +452 ns 1 1 1 1 1 0 00 0 14 +462 ns 1 1 1 1 1 0 00 0 15 +472 ns 1 0 1 0 0 0 10 30 0 +482 ns 1 0 0 1 0 0 01 0 1 +492 ns 1 0 0 1 1 0 11 0 2 +502 ns 1 1 1 1 1 0 00 0 3 +512 ns 1 1 1 1 1 0 00 0 4 +522 ns 1 1 1 1 1 0 00 0 5 +532 ns 1 1 1 1 1 0 00 0 6 +542 ns 1 1 1 1 1 0 00 0 7 +552 ns 1 0 1 0 0 0 11 40 8 +562 ns 1 0 0 1 0 0 10 0 9 +572 ns 1 0 0 1 1 0 00 0 10 +582 ns 1 1 1 1 1 0 00 0 11 +592 ns 1 1 1 1 1 0 00 0 12 +602 ns 1 1 1 1 1 0 00 0 13 +612 ns 1 1 1 1 1 0 00 0 14 +622 ns 1 1 1 1 1 0 00 0 15 +632 ns 1 0 1 0 1 0 00 10 -100 +642 ns 1 0 0 1 0 0 11 0 -100 +652 ns 1 0 0 1 1 0 01 0 -100 +662 ns 1 1 1 1 1 0 00 0 -100 +672 ns 1 1 1 1 1 0 00 0 -100 +682 ns 1 1 1 1 1 0 00 0 -100 +692 ns 1 1 1 1 1 0 00 0 -100 +702 ns 1 1 1 1 1 0 00 0 -100 +712 ns 1 0 1 0 1 0 01 20 -100 +722 ns 1 0 0 1 0 0 00 0 -100 +732 ns 1 0 0 1 1 0 10 0 -100 +742 ns 1 1 1 1 1 0 00 0 -100 +752 ns 1 1 1 1 1 0 00 0 -100 +762 ns 1 1 1 1 1 0 00 0 -100 +772 ns 1 1 1 1 1 0 00 0 -100 +782 ns 1 1 1 1 1 0 00 0 -100 +792 ns 1 0 1 0 1 0 10 30 -100 +802 ns 1 0 0 1 0 0 01 0 -100 +812 ns 1 0 0 1 1 0 11 0 -100 +822 ns 1 1 1 1 1 0 00 0 -100 +832 ns 1 1 1 1 1 0 00 0 -100 +842 ns 1 1 1 1 1 0 00 0 -100 +852 ns 1 1 1 1 1 0 00 0 -100 +862 ns 1 1 1 1 1 0 00 0 -100 +872 ns 1 0 1 0 1 0 11 40 -100 +882 ns 1 0 0 1 0 0 10 0 -100 +892 ns 1 1 1 1 1 0 00 0 -100 +902 ns 1 1 1 1 1 0 00 0 -100 +912 ns 1 1 1 1 1 0 00 0 -100 +922 ns 1 1 1 1 1 0 00 0 -100 +932 ns 1 1 1 1 1 0 00 0 -100 +942 ns 1 1 1 1 1 0 00 0 -100 +952 ns 1 0 0 1 0 0 11 0 -100 +962 ns 1 1 1 1 1 0 00 0 -100 +972 ns 1 1 1 1 1 0 00 0 -100 +982 ns 1 1 1 1 1 0 00 0 -100 diff --git a/lib/models/memory/sdram/mt48lc64m4a2/test.vhd b/lib/models/memory/sdram/mt48lc64m4a2/test.vhd new file mode 100644 index 0000000..a99a225 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/test.vhd @@ -0,0 +1,168 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE std.textio.ALL; +USE work.std_logic_arith.ALL; +USE work.util_1164.ALL; +USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 13; + CONSTANT data_bits : INTEGER := 4; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + + COMPONENT mt48lc64m4a2 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC := '0' + ); + END COMPONENT; + + FOR ALL : mt48lc64m4a2 USE ENTITY work.mt48lc64m4a2 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc64m4a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : STD_LOGIC; + VARIABLE pCs_var : STD_LOGIC; + VARIABLE pRas_var : STD_LOGIC; + VARIABLE PCas_var : STD_LOGIC; + VARIABLE pWe_var : STD_LOGIC; + VARIABLE pDqm_var : STD_LOGIC; + VARIABLE pBa_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read(l, time_var); + read(l, pCke_var); + read(l, pCs_var); + read(l, pRas_var); + read(l, pCas_var); + read(l, pWe_var); + read(l, pDqm_var); + read(l, pBa_var); + read(l, pAddr_var); + read(l, pDq_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + IF pWe_var='1' THEN + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + ELSE + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + END IF; + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc64m4a2/util1164.vhd b/lib/models/memory/sdram/mt48lc64m4a2/util1164.vhd new file mode 100644 index 0000000..bb4b5dd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/util1164.vhd @@ -0,0 +1,124 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE STD.textio.ALL; + +PACKAGE util_1164 IS + PROCEDURE read(l: INOUT line; value: OUT std_logic); + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector); + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0); + PROCEDURE Grow_line(L : inout LINE; incr : in integer); +END util_1164; + + + +PACKAGE BODY util_1164 IS + + FUNCTION white_space(value:character) RETURN boolean IS + VARIABLE result:boolean; + BEGIN + IF (value = ' ') OR (value = HT) THEN + RETURN true; + ELSE + RETURN false; + END IF; + END white_space; + + PROCEDURE read(l: INOUT line; value: OUT std_logic) IS + VARIABLE char_var: character:= ' '; + BEGIN + WHILE l'LENGTH > 0 LOOP + read(l,char_var); + IF NOT white_space(char_var) THEN + EXIT; + END IF; + END LOOP; + IF white_space(char_var) THEN + ASSERT false REPORT "No std_logic value found in file" + SEVERITY error; + value := 'X'; + RETURN; + END IF; + + CASE char_var IS + WHEN 'U'|'u' => value := 'U'; + WHEN '0' => value := '0'; + WHEN '1' => value := '1'; + WHEN 'X'|'x' => value := 'X'; + WHEN 'L'|'l' => value := 'L'; + WHEN 'H'|'h' => value := 'H'; + WHEN 'W'|'w' => value := 'W'; + WHEN 'Z'|'z' => value := 'Z'; + WHEN '-' => value := '-'; + WHEN OTHERS => + ASSERT false REPORT "Unrecognized value read for std_logic" + SEVERITY error; + value := 'X'; + END CASE; + END read; + + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector) IS + BEGIN + FOR i IN value'HIGH DOWNTO value'LOW LOOP + IF l'LENGTH > 0 THEN + read(l,value(i)); + ELSE + ASSERT false REPORT "Not enough values for std_logic_vector in file" + SEVERITY error; + RETURN; + END IF; + END LOOP; + END read; + + procedure Grow_line(L : inout LINE; incr : in integer) + is + variable old_L : LINE := L; + variable bfp: integer; -- Blank fill pointer. + begin + assert incr > 0 + report "Textio: Grow_line called with zero increment." + severity error; + + if L = null then + bfp := 0; + L := new string(1 to incr); + else + bfp := old_L'high; + L := new string(old_L'low to old_L'high + incr); + L(old_L'low to old_L'high) := old_L.all; + Deallocate(old_L); + end if; + for i in 1 to incr loop + L(bfp + i) := ' '; + end loop; + end; + + + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0) IS + variable fw: integer := VALUE'length; + variable bp: integer; + variable offset: integer := 0; + alias normal : std_logic_vector(0 to value'length - 1) is value; + begin + if L /= null then + bp := L'high + 1; + else bp := 1; + end if; + if FIELD > VALUE'length then + fw := FIELD; + if JUSTIFIED = right then + offset := fw - VALUE'length; + end if; + end if; + Grow_line(L, fw); + for i in normal'range loop + L(bp + i + offset) := character'val( + std_logic'pos(normal(i)) + character'pos('0')); + end loop; + end; + + +END util_1164; diff --git a/lib/models/memory/sdram/mt48lc64m4a2/vec_gen.vhd b/lib/models/memory/sdram/mt48lc64m4a2/vec_gen.vhd new file mode 100644 index 0000000..821d321 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/vec_gen.vhd @@ -0,0 +1,372 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.io_utils.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); + first_data : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT; cke : IN BIT); + PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT; cs : IN BIT); + PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle(SIGNAL clk : IN BIT); + PROCEDURE load_array(load : IN BIT); + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)); + +END generate_vectors; + + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; + dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, first_data, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, row_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT; cs : IN BIT) IS + + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, cs, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT := '0'; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + --write(l, 0, right, 4); --load + --write(l, 0, right, 4); --unload + --write(l, 0, right, 6); --row_address_start + --write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS + +BEGIN + +WAIT UNTIL clk = '1'; + +END; + +PROCEDURE load_array(load : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT := '0'; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 1, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT := '0'; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 1, right, 4); --unload +--write(l, row_start, right, 6); --row_address_start +--write(l, row_end, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT := '0'; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, op_code, right, 6); --address +write(l, -100, right, 6); --first data location +--write(l, 0, right, 4); --load +--write(l, 0, right, 4); --unload +--write(l, 0, right, 6); --row_address_start +--write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc64m4a2/vector.do b/lib/models/memory/sdram/mt48lc64m4a2/vector.do new file mode 100644 index 0000000..7480359 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/vector.do @@ -0,0 +1,4 @@ +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all diff --git a/lib/models/memory/sdram/mt48lc64m4a2/wave.do b/lib/models/memory/sdram/mt48lc64m4a2/wave.do new file mode 100644 index 0000000..168e846 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc64m4a2/wave.do @@ -0,0 +1,31 @@ +onerror {resume} +add wave -logic -height 20 /tb/u1/clk +add wave -logic -height 20 /tb/u1/cke +add wave -logic -height 20 /tb/u1/cs_n +add wave -logic -height 20 /tb/u1/ras_n +add wave -logic -height 20 /tb/u1/cas_n +add wave -logic -height 20 /tb/u1/we_n +add wave -logic -unsigned -height 20 /tb/u1/addr +add wave -logic -height 20 /tb/u1/ba +add wave -logic -unsigned -height 20 /tb/u1/dq +add wave -logic -height 20 /tb/u1/dqm +add wave -literal -ascii -height 20 /tb/u1/operation +add wave -logic -unsigned -height 20 /tb/u1/mode_reg +add wave -logic -height 20 /tb/u1/active_enable +add wave -logic -height 20 /tb/u1/aref_enable +add wave -logic -height 20 /tb/u1/burst_term +add wave -logic -height 20 /tb/u1/mode_reg_enable +add wave -logic -height 20 /tb/u1/prech_enable +add wave -logic -height 20 /tb/u1/read_enable +add wave -logic -height 20 /tb/u1/write_enable +add wave -logic -height 20 /tb/u1/burst_length_1 +add wave -logic -height 20 /tb/u1/burst_length_2 +add wave -logic -height 20 /tb/u1/burst_length_4 +add wave -logic -height 20 /tb/u1/burst_length_8 +add wave -logic -height 20 /tb/u1/cas_latency_2 +add wave -logic -height 20 /tb/u1/cas_latency_3 +add wave -logic -height 20 /tb/u1/pre_chk +add wave -logic -height 20 /tb/u1/act_chk +add wave -logic -height 20 /tb/u1/bank_chk +add wave -logic -unsigned -height 20 /tb/u1/row_chk +add wave -logic -unsigned -height 20 /tb/u1/col_chk diff --git a/lib/models/memory/sdram/mt48lc8m16a2/base.do b/lib/models/memory/sdram/mt48lc8m16a2/base.do new file mode 100644 index 0000000..d2afbcb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/base.do @@ -0,0 +1,5 @@ +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd + diff --git a/lib/models/memory/sdram/mt48lc8m16a2/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc8m16a2/ed_comnd.vhd new file mode 100644 index 0000000..3d7fb12 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/ed_comnd.vhd @@ -0,0 +1,349 @@ +--------------------------------------------------------------------------------- +--COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit_vector), first data(integer), dqm(bit), cke(bit));-- +-- read(column address(integer), bank(bit_vector), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit_vector), data bus (integer), dqm(bit), cke(bit));-- +-- precharge(bank(bit_vector), address (integer), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit), cs(bit)); -- +-- burst_term(data bus(integer), dqm(bit_vector), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit_vector)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +--------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, "00", '1', '1'); --Always begin with one nop when using Micron's testbench + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +load_array('1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +precharge("00", 1024, Z, "00", '1'); + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, "00", '1', '1'); +END LOOP; + +next_cycle(clk); +load_mode_reg(51, '1'); -- 19 / 35 / 51 -> lat=3,bl=8,mode=seq + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +-- Write Section + +next_cycle(clk); +active(0, "00", Z, "00", '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); -- Write Bank 0 +write(0, "00", 100, "00", '1'); + +next_cycle(clk); +nop(101, "00", '1', '1'); + +next_cycle(clk); +active(0, "01", 102, "00", '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(103, "00", '1', '1'); + +next_cycle(clk); +nop(104, "00", '1', '1'); + +next_cycle(clk); +nop(105, "00", '1', '1'); + +next_cycle(clk); +nop(106, "00", '1', '1'); + +next_cycle(clk); +nop(107, "00", '1', '1'); + +next_cycle(clk); +write(0, "01", 200, "00", '1'); -- Write Bank 1 + +next_cycle(clk); +precharge("00", 0, 201, "00", '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", 202, "00", '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(203, "00", '1', '1'); + +next_cycle(clk); +nop(204, "00", '1', '1'); + +next_cycle(clk); +nop(205, "00", '1', '1'); + +next_cycle(clk); +nop(206, "00", '1', '1'); + +next_cycle(clk); +nop(207, "00", '1', '1'); + +next_cycle(clk); +write(0, "10", 300, "00", '1'); -- Write Bank 2 + +next_cycle(clk); +precharge("01", 0, 301, "00", '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", 302, "00", '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(303, "00", '1', '1'); + +next_cycle(clk); +nop(304, "00", '1', '1'); + +next_cycle(clk); +nop(305, "00", '1', '1'); + +next_cycle(clk); +nop(306, "00", '1', '1'); + +next_cycle(clk); +nop(307, "00", '1', '1'); + +next_cycle(clk); +write(0, "11", 400, "00", '1'); -- Write Bank 3 + +next_cycle(clk); +precharge("10", 0, 401, "00", '1'); -- Precharge Bank 2 + +next_cycle(clk); +active(0, "00", 402, "00", '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(403, "00", '1', '1'); + +next_cycle(clk); +nop(404, "00", '1', '1'); + +next_cycle(clk); +nop(405, "00", '1', '1'); + +next_cycle(clk); +nop(406, "00", '1', '1'); + +next_cycle(clk); +nop(407, "00", '1', '1'); + +-- Read Section + +next_cycle(clk); +read(0, "00", "00", '1'); -- Read Bank 0 + +next_cycle(clk); +precharge("11", 0, Z, "00", '1'); -- Precharge Bank 3 + +next_cycle(clk); +active(0, "01", Z, "00", '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +read(0, "01", "00", '1'); -- Read Bank 1 + +next_cycle(clk); +precharge("00", 0, Z, "00", '1'); -- Precharge Bank 0 + +next_cycle(clk); +active(0, "10", Z, "00", '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +read(0, "10", "00", '1'); -- Read Bank 2 + +next_cycle(clk); +precharge("01", 0, Z, "00", '1'); -- Precharge Bank 1 + +next_cycle(clk); +active(0, "11", Z, "00", '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +read(0, "11", "00", '1'); -- Read Bank 3 + +next_cycle(clk); +precharge("10", 0, Z, "00", '1'); -- Precharge Bank 2 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +precharge("11", 0, Z, "00", '1'); -- Precharge Bank 3 + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +next_cycle(clk); +unload_array(0, 0, "00"); + +next_cycle(clk); +nop(Z, "00", '1', '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc8m16a2/io_utils.vhd b/lib/models/memory/sdram/mt48lc8m16a2/io_utils.vhd new file mode 100644 index 0000000..dfcb84a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/io_utils.vhd @@ -0,0 +1,266 @@ +LIBRARY ieee; +USE std.textio.ALL; +USE ieee.std_logic_1164.ALL; + +PACKAGE io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0); + + TYPE radix IS (binary, octal, decimal, hex); + + -- read a number from the line + -- use this if you have hex numbers that are not in VHDL pound-sign format + PROCEDURE read(l : INOUT line; value : OUT integer; radix : IN positive); + + -- read a number that might be in VHDL pound-sign format + PROCEDURE read_based(l : INOUT line; value : OUT integer); + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); +END io_utils; + +PACKAGE BODY io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0) + IS + BEGIN + write(l, value, justified, field); + END; + + PROCEDURE shrink_line(l : INOUT line; pos : integer) IS + VARIABLE tmpl : line; + BEGIN + tmpl := l; + l := NEW string'(tmpl(pos TO tmpl'high)); + deallocate(tmpl); + END; + + PROCEDURE read(l : INOUT line; + value : OUT integer; + radix : IN positive) + IS + CONSTANT not_digit : integer := -999; + + -- convert a character to a value from 0 to 15 + FUNCTION digit_value(c : character) RETURN integer IS + BEGIN + IF (c >= '0') AND (c <= '9') THEN + RETURN (character'pos(c) - character'pos('0')); + ELSIF (c >= 'a') AND (c <= 'f') THEN + RETURN (character'pos(c) - character'pos('a') + 10); + ELSIF (c >= 'A') AND (c <= 'F') THEN + RETURN (character'pos(c) - character'pos('A') + 10); + ELSE + RETURN not_digit; + END IF; + END; + + -- skip leading white space in the line + PROCEDURE skip_white(VARIABLE l : IN line; pos : OUT integer) IS + BEGIN + pos := l'low; + FOR i IN l'low TO l'high LOOP + CASE l(i) IS + WHEN ' ' | ht => + pos := i + 1; + WHEN OTHERS => + EXIT; + END CASE; + END LOOP; + END; + + VARIABLE digit : integer; + VARIABLE result : integer := 0; + VARIABLE pos : integer; + BEGIN + -- skip white space + skip_white(l, pos); + + -- calculate the value + FOR i IN pos TO l'right LOOP + digit := digit_value(l(i)); + EXIT WHEN (digit = not_digit) OR (digit >= radix); + result := result * radix + digit; + pos := i + 1; + END LOOP; + value := result; + + -- remove the "used" characters from the line + shrink_line(l, pos); + END; + + PROCEDURE read_based(l : INOUT line; value : OUT integer) IS + VARIABLE digit : integer; + VARIABLE num : integer; + VARIABLE base : integer; + BEGIN + read(l, num, 10); + IF (l'length > 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + base := num; + read(l, num, base); + IF (l'length >= 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + END IF; + END IF; + value := num; + END; + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_int(bv : std_logic_vector) RETURN integer + IS + VARIABLE result : integer := 0; + BEGIN + FOR i IN bv'RANGE LOOP + result := result * 2; + IF (bv(i) = '1') THEN + result := result + 1; + END IF; + END LOOP; + RETURN result; + END; + + TYPE array_of_widths IS ARRAY(radix) OF natural; + CONSTANT nibble_widths : array_of_widths := ( + binary => 1, + octal => 3, + hex => 4, + decimal=> 32); + CONSTANT hex_digit : string(1 TO 16) := "0123456789ABCDEF"; + + ALIAS input_val : std_logic_vector(value'length DOWNTO 1) IS value; + CONSTANT nibble_width : natural := nibble_widths(base); + CONSTANT result_width : natural := (value'length + nibble_width - 1)/nibble_width; + + VARIABLE result : string(1 TO result_width); -- longest possible value + VARIABLE result_pos : positive := 1; + VARIABLE nibble_val : integer; + VARIABLE bitcnt : integer; + BEGIN + IF base = decimal THEN + write(l, to_int(value), justified, field, base, use_pound); + RETURN; + END IF; + + bitcnt := value'length MOD nibble_width; + IF (bitcnt = 0) THEN + bitcnt := nibble_width; + END IF; + FOR i IN input_val'RANGE LOOP + nibble_val := nibble_val * 2; + IF (input_val(i) = '1') THEN + nibble_val := nibble_val + 1; + END IF; + bitcnt := bitcnt - 1; + IF (bitcnt = 0) THEN + result(result_pos) := hex_digit(nibble_val + 1); + result_pos := result_pos + 1; + nibble_val := 0; + bitcnt := nibble_width; + END IF; + END LOOP; + write(l, result, justified, field); + END; + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_bv(int : integer) RETURN std_logic_vector + IS + VARIABLE bv : std_logic_vector(32 DOWNTO 1) := (OTHERS => '0'); + VARIABLE pos : integer := 0; + VARIABLE tmpval : integer := int; + BEGIN + FOR i IN 1 TO 32 LOOP + pos := pos + 1; + IF (tmpval MOD 2) = 1 THEN + bv(i) := '1'; + END IF; + tmpval := tmpval / 2; + EXIT WHEN tmpval = 0; + END LOOP; + RETURN bv(pos DOWNTO 1); + END; + + VARIABLE tmp : line; + BEGIN + IF (base = decimal) THEN + IF (use_pound) THEN + write_string(tmp, "10#"); + END IF; + write(tmp, value); + IF (use_pound) THEN + write_string(tmp, "#"); + END IF; + write(l, tmp.ALL, justified, field); + deallocate(tmp); + ELSE + write(l, to_bv(value), justified, field, base, use_pound); + END IF; + END; + +END io_utils; + + + +-- test the hex number reader +--ENTITY test IS END; + +--USE std.textio.ALL; +--USE work.io_utils.ALL; +--ARCHITECTURE hex_test OF test IS +--BEGIN +-- PROCESS +-- VARIABLE val : integer; +-- FILE myfile : text IS IN "values"; +-- VARIABLE inline : line; +-- VARIABLE outline : line; +-- BEGIN +-- WHILE NOT endfile(myfile) LOOP +-- readline(myfile, inline); + +-- write(outline, inline.ALL); +-- +-- read_based(inline, val); + -- write_string(outline, " binary: "); + -- write(outline, val, base => binary); + -- write_string(outline, " octal: "); + -- write(outline, val, base => octal); + -- write_string(outline, " decimal: "); + -- write(outline, val, base => decimal); +-- write_string(outline, " hex: "); +-- write(outline, val, base => hex); +-- writeline(output, outline); +-- END LOOP; +-- WAIT; +-- END PROCESS; +--END; + + diff --git a/lib/models/memory/sdram/mt48lc8m16a2/loaddata.txt b/lib/models/memory/sdram/mt48lc8m16a2/loaddata.txt new file mode 100644 index 0000000..c7599a9 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/loaddata.txt @@ -0,0 +1,40 @@ +0 0 00 0 -- ROW (HEX), COL (HEX), BANK (BIN), DATA (HEX) +0 1 00 1 +0 2 00 2 +0 3 00 3 +0 4 00 4 +0 5 00 5 +0 6 00 6 +0 7 00 7 +0 8 00 8 +0 9 00 9 +0 0 01 10 +0 1 01 11 +0 2 01 12 +0 3 01 13 +0 4 01 14 +0 5 01 15 +0 6 01 16 +0 7 01 17 +0 8 01 18 +0 9 01 19 +0 0 10 20 +0 1 10 21 +0 2 10 22 +0 3 10 23 +0 4 10 24 +0 5 10 25 +0 6 10 26 +0 7 10 27 +0 8 10 28 +0 9 10 29 +0 0 11 30 +0 1 11 31 +0 2 11 32 +0 3 11 33 +0 4 11 34 +0 5 11 35 +0 6 11 36 +0 7 11 37 +0 8 11 38 +0 9 11 39 diff --git a/lib/models/memory/sdram/mt48lc8m16a2/mt48lc8m16a2.vhd b/lib/models/memory/sdram/mt48lc8m16a2/mt48lc8m16a2.vhd new file mode 100644 index 0000000..3093c8c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/mt48lc8m16a2.vhd @@ -0,0 +1,1426 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC8M16A2.VHD +-- Version: 0.0g +-- Date: May 11th, 1999 +-- Model: Behavioral +-- Simulator: Model Technology (PC version 5.3 PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC8M16A2 (2Mb x 16 x 4 Banks) +-- +-- Description: Micron 128Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0g Son Huynh 208-368-3825 05/11/2000 Fix tWR + tRP timing +-- Micron Technology Inc. +-- +-- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) +-- Micron Technology Inc. Fix tWR = 15 ns (Manual) +-- Fix tRP (Autoprecharge to AutoRefresh) +-- +-- 0.0c Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP +-- Micron Technology Inc. Fix tRC check in Load Mode Register +-- +-- 0.0b Son P. Huynh 208-368-3825 01/06/1998 Derive from 64Mb SDRAM model +-- Micron Technology Inc. +-- +----------------------------------------------------------------------------------------- + +LIBRARY std; + USE std.textio.ALL; +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; +LIBRARY work; + USE work.io_utils.ALL; + USE work.mti_pkg.ALL; + +ENTITY mt48lc8m16a2 IS + GENERIC ( + -- Timing Parameters for -7E and CAS Latency = 2 + tAC : TIME := 5.4 ns; + tHZ : TIME := 5.4 ns; + tOH : TIME := 2.7 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 37.0 ns; + tRC : TIME := 60.0 ns; + tRCD : TIME := 15.0 ns; + tRP : TIME := 15.0 ns; + tRRD : TIME := 14.0 ns; + tWRa : TIME := 7.0 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7 ns) + tWRp : TIME := 14.0 ns; -- A2 Version - Precharge mode only (14 ns) + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 7.5 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 12; + data_bits : INTEGER := 16; + col_bits : INTEGER := 9 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Load : IN STD_LOGIC := '0'; + Unload : IN STD_LOGIC := '0'; + Row_start : IN INTEGER := 0; + Row_end : IN INTEGER := 0 + ); +END mt48lc8m16a2; + +ARCHITECTURE behave OF mt48lc8m16a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, FILE_LOAD, FILE_UNLOAD); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL RAS_clk, Sys_clk, CkeZ : BIT := '0'; + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- RAS Clock for checking tWR and tRP + PROCESS + variable Clk0, Clk1 : integer := 0; + begin + RAS_clk <= '1'; + wait for 0.5 ns; + RAS_clk <= '0'; + wait for 0.5 ns; + if Clk0 > 100 or Clk1 > 100 then + wait; + else + if Clk = '1' then + Clk0 := 0; + Clk1 := Clk1 + 1; + else + Clk0 := Clk0 + 1; + Clk1 := 0; + end if; + end if; + END PROCESS; + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg0, Dqm_reg1 : BIT_VECTOR (1 DOWNTO 0) := "00"; + + VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Load and Unload variables + FILE load_file : TEXT IS IN "loaddata.txt"; -- Data load + FILE out_file0 : TEXT IS OUT "outdata0.txt"; -- Data dump for bank 0 + FILE out_file1 : TEXT IS OUT "outdata1.txt"; -- Data dump for bank 1 + FILE out_file2 : TEXT IS OUT "outdata2.txt"; -- Data dump for bank 2 + FILE out_file3 : TEXT IS OUT "outdata3.txt"; -- Data dump for bank 3 + VARIABLE l_in, l_out0, l_out1, l_out2, l_out3 : LINE; + VARIABLE array_buffer : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE write_data_var : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE row_load, col_load, dq_load : INTEGER; + VARIABLE ba_load : BIT_VECTOR (1 DOWNTO 0); + VARIABLE dq_vec : BIT_VECTOR (data_bits - 1 DOWNTO 0); + VARIABLE i, j, k : INTEGER; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, RAS_clk; + IF Sys_clk'event and Sys_clk = '1' AND Load = '0' AND Unload = '0' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg0 := Dqm_reg1; + Dqm_reg1 := TO_BITVECTOR(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Precharge Timer for tWR + if (Burst_length_1 = '1' OR Write_burst_mode = '1') then + if (Count_precharge(0) = 1) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 1) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 1) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 1) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_2 = '1') then + if (Count_precharge(0) = 2) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 2) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 2) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 2) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_4 = '1') then + if (Count_precharge(0) = 4) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 4) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 4) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 4) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_8 = '1') then + if (Count_precharge(0) = 8) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 8) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 8) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 8) then + Count_time(3) := NOW; + end if; + end if; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) := WR_counter(0) + 1; + WR_counter(1) := WR_counter(1) + 1; + WR_counter(2) := WR_counter(2) + 1; + WR_counter(3) := WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := TO_BITVECTOR (Addr); + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := TO_BITVECTOR (Addr); + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := TO_BITVECTOR (Ba); + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR + (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BITVECTOR (Ba); + A10_precharge(2) := TO_BIT(Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BITVECTOR (Ba); + A10_precharge(1) := TO_BIT(Addr(10)); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (2) := TO_BITVECTOR (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (1) := TO_BITVECTOR (Ba); + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (0) := TO_BITVECTOR (Ba); + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' AND Write_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_write(TO_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' AND Read_precharge(TO_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_read(TO_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + RW_interrupt_bank := TO_BITVECTOR (Ba); + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank0 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank1 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank2 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + IF Dqm = "01" THEN + Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); + ELSIF Dqm = "10" THEN + Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); + ELSE + Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); + END IF; + Bank3 (Row_index) (Col_index) := Dq_temp; + END IF; + WR_chkp(TO_INTEGER(Bank)) := NOW; + WR_counter(TO_INTEGER(Bank)) := 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg0 /= "11" THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq_temp (15 DOWNTO 0) := Bank0 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "01" THEN + Dq_temp (15 DOWNTO 0) := Bank1 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "10" THEN + Dq_temp (15 DOWNTO 0) := Bank2 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + ELSIF Bank = "11" THEN + Dq_temp (15 DOWNTO 0) := Bank3 (Row_index) (Col_index); + IF Dqm_reg0 = "00" THEN + Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; + ELSIF Dqm_reg0 = "01" THEN + Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + ELSIF Dqm_reg0 = "10" THEN + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; + END IF; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + ELSIF Sys_clk'event and Sys_clk = '1' AND Load = '1' AND Unload = '0' THEN + Operation <= FILE_LOAD; + WHILE NOT ENDFILE (load_file) LOOP + READLINE (load_file, l_in); + IF l_in'LENGTH > 0 THEN + read (l_in, row_load, 16); -- Load from HEX to INTEGER + read (l_in, col_load, 16); -- Load from HEX to INTEGER + read (l_in, ba_load); + read (l_in, dq_load, 16); -- Load from HEX to INTEGER + + TO_BITVECTOR (dq_load, dq_vec); + + IF ba_load = "00" THEN + IF Bank0(row_load) = NULL THEN --initialize new memory block + Bank0(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank0(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank0(row_load)(col_load) := dq_vec; + ELSIF ba_load = "01" THEN + IF Bank1(row_load) = NULL THEN --initialize new memory block + Bank1(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank1(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank1(row_load)(col_load) := dq_vec; + ELSIF ba_load = "10" THEN + IF Bank2(row_load) = NULL THEN --initialize new memory block + Bank2(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank2(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank2(row_load)(col_load) := dq_vec; + ELSIF ba_load = "11" THEN + IF Bank3(row_load) = NULL THEN --initialize new memory block + Bank3(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank3(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank3(row_load)(col_load) := dq_vec; + END IF; + END IF; + END LOOP; + ELSIF Sys_clk'event and Sys_clk = '1' AND Load = '0' AND Unload = '1' THEN + Operation <= FILE_UNLOAD; + ASSERT (Row_start < 2**(Addr'HIGH + 1)) + REPORT "Row_start is out of range for device" + SEVERITY ERROR; + ASSERT (Row_end < 2**(Addr'HIGH + 1)) + REPORT "Row_end is out of range for device" + SEVERITY ERROR; + ASSERT ((Row_end - Row_start) >= 0) + REPORT "The Row ranges for Unload is invalid!" + SEVERITY ERROR; + IF ((Row_end - Row_start) >= 0) THEN + FOR i IN Row_start TO Row_end LOOP + j := 1; + IF (Ba = "00") THEN -- Unload Bank 0 + WRITE (l_out0, STRING'("Micron Technology Inc. - Unload Data Array - Bank 0 Row ")); + WRITE (l_out0, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file0, l_out0); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP -- Display Row and Column + IF (j = 1) THEN + WRITE (l_out0, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out0, STRING'(" : ")); + WRITE (l_out0, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out0, STRING'(" : ")); + END IF; + + IF (Bank0 (i) = NULL) THEN -- Row is empty, write message and exit + WRITE (l_out0, STRING'(" Row ")); + WRITE (l_out0, i); + WRITE (l_out0, STRING'(" is empty.")); + WRITELINE (out_file0, l_out0); + EXIT; + ELSE -- Buffering + array_buffer := Bank0 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); -- Convert to STD_LOGIC_VECTOR + WRITE (l_out0, write_data_var, RIGHT, 6, HEX, FALSE); -- Write message + IF (j = 16) then + WRITELINE (out_file0, l_out0); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "01") THEN + WRITE (l_out1, STRING'("Micron Technology Inc. - Unload Data Array - Bank 1 Row ")); + WRITE (l_out1, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file1, l_out1); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out1, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out1, STRING'(" : ")); + WRITE (l_out1, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out1, STRING'(" : ")); + END IF; + + IF (Bank1 (i) = NULL) THEN + WRITE (l_out1, STRING'(" Row ")); + WRITE (l_out1, i); + WRITE (l_out1, STRING'(" is empty.")); + WRITELINE (out_file1, l_out1); + EXIT; + ELSE + array_buffer := Bank1 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out1, write_data_var, RIGHT, 6, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file1, l_out1); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "10") THEN + WRITE (l_out2, STRING'("Micron Technology Inc. - Unload Data Array - Bank 2 Row ")); + WRITE (l_out2, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file2, l_out2); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out2, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out2, STRING'(" : ")); + WRITE (l_out2, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out2, STRING'(" : ")); + END IF; + + IF (Bank2 (i) = NULL) THEN + WRITE (l_out2, STRING'(" Row ")); + WRITE (l_out2, i); + WRITE (l_out2, STRING'(" is empty.")); + WRITELINE (out_file2, l_out2); + EXIT; + ELSE + array_buffer := Bank2 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out2, write_data_var, RIGHT, 6, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file2, l_out2); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "11") THEN + WRITE (l_out3, STRING'("Micron Technology Inc. - Unload Data Array - Bank 3 Row ")); + WRITE (l_out3, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file3, l_out3); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out3, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out3, STRING'(" : ")); + WRITE (l_out3, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out3, STRING'(" : ")); + END IF; + + IF (Bank3 (i) = NULL) THEN + WRITE (l_out3, STRING'(" Row ")); + WRITE (l_out3, i); + WRITE (l_out3, STRING'(" is empty.")); + WRITELINE (out_file3, l_out3); + EXIT; + ELSE + array_buffer := Bank3 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out3, write_data_var, RIGHT, 6, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file3, l_out3); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + END IF; + END LOOP; + END IF; + + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + + -- Checking internal wires (Optional for debug purpose) + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Pre_chk (2) <= Pc_b2; + Pre_chk (3) <= Pc_b3; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Act_chk (2) <= Act_b2; + Act_chk (3) <= Act_b3; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "Dq Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc8m16a2/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc8m16a2/mti_pkg.vhd new file mode 100644 index 0000000..9e4f824 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/mti_pkg.vhd @@ -0,0 +1,129 @@ +--***************************************************************************** +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +--***************************************************************************** + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + -- Convert BIT to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert BIT_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Conver integer to bit_vector + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc8m16a2/outdata0.txt b/lib/models/memory/sdram/mt48lc8m16a2/outdata0.txt new file mode 100644 index 0000000..0e12acc --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/outdata0.txt @@ -0,0 +1,33 @@ +Micron Technology Inc. - Unload Data Array - Bank 0 Row 0 + 0 : 0 : 0064 0065 0066 0067 0068 0069 006A 006B 0074 0075 006E 006F 0070 0071 0072 0073 + 0 : 10 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 20 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 30 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 40 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 50 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 60 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 70 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 80 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 90 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : A0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : B0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : C0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : D0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : E0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : F0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 100 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 110 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 120 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 130 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 140 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 150 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 160 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 170 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 180 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 190 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 1A0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 1B0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 1C0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 1D0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 1E0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 + 0 : 1F0 : 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 diff --git a/lib/models/memory/sdram/mt48lc8m16a2/outdata1.txt b/lib/models/memory/sdram/mt48lc8m16a2/outdata1.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc8m16a2/outdata2.txt b/lib/models/memory/sdram/mt48lc8m16a2/outdata2.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc8m16a2/outdata3.txt b/lib/models/memory/sdram/mt48lc8m16a2/outdata3.txt new file mode 100644 index 0000000..e69de29 diff --git a/lib/models/memory/sdram/mt48lc8m16a2/readme.txt b/lib/models/memory/sdram/mt48lc8m16a2/readme.txt new file mode 100644 index 0000000..9804585 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/readme.txt @@ -0,0 +1,14 @@ +To operate the test bench for the Micron SDRAM VHDL model, follow the directions +given below: + +1. Be sure all supporting files for the SDRAM are compiled into your library: + + util1164.vhd + stdlogar.vhd + io_utils.vhd + mti_pkg.vhd + +2. Next, compile the mt48lc8m16a2.vhd file and the test.vhd file. + +3. Simulate the "tb" architecture. This is the testbench for the 128Mb SDRAM. + diff --git a/lib/models/memory/sdram/mt48lc8m16a2/runall.do b/lib/models/memory/sdram/mt48lc8m16a2/runall.do new file mode 100644 index 0000000..36da31c --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/runall.do @@ -0,0 +1,49 @@ +# Compile base libraries +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd +# Compile test vectors +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all +# Compile Micron SDRAM model and testbench +vcom mt48lc8m16a2.vhd +vcom test.vhd +vsim -t ps tb +# Add waveform +add wave -logic /tb/u1/clk +add wave -logic /tb/u1/cke +add wave -logic /tb/u1/cs_n +add wave -logic /tb/u1/ras_n +add wave -logic /tb/u1/cas_n +add wave -logic /tb/u1/we_n +add wave -literal -decimal /tb/u1/addr +add wave -literal -unsigned /tb/u1/ba +add wave -literal -decimal /tb/u1/dq +add wave -literal /tb/u1/dqm +add wave -literal /tb/u1/operation +add wave -literal -decimal /tb/u1/mode_reg +add wave -logic /tb/u1/active_enable +add wave -logic /tb/u1/aref_enable +add wave -logic /tb/u1/burst_term +add wave -logic /tb/u1/mode_reg_enable +add wave -logic /tb/u1/prech_enable +add wave -logic /tb/u1/read_enable +add wave -logic /tb/u1/write_enable +add wave -logic /tb/u1/burst_length_1 +add wave -logic /tb/u1/burst_length_2 +add wave -logic /tb/u1/burst_length_4 +add wave -logic /tb/u1/burst_length_8 +add wave -logic /tb/u1/cas_latency_2 +add wave -logic /tb/u1/cas_latency_3 +add wave -literal /tb/u1/pre_chk +add wave -literal /tb/u1/act_chk +add wave -literal /tb/u1/bank_chk +add wave -literal -decimal /tb/u1/row_chk +add wave -literal -decimal /tb/u1/col_chk +add wave -logic /tb/u1/dq_in_chk +add wave -logic /tb/u1/dq_out_chk +# run all test vectors +run -all diff --git a/lib/models/memory/sdram/mt48lc8m16a2/stdlogar.vhd b/lib/models/memory/sdram/mt48lc8m16a2/stdlogar.vhd new file mode 100644 index 0000000..e435ea2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/stdlogar.vhd @@ -0,0 +1,2247 @@ +-------------------------------------------------------------------------- +-- -- +-- Copyright (c) 1990,1991,1992 by Synopsys, Inc. All rights reserved. -- +-- -- +-- This source file may be used and distributed without restriction -- +-- provided that this copyright statement is not removed from the file -- +-- and that any derivative work contains this copyright notice. -- +-- -- +-- Package name: STD_LOGIC_ARITH -- +-- -- +-- Purpose: -- +-- A set of arithemtic, conversion, and comparison functions -- +-- for SIGNED, UNSIGNED, SMALL_INT, INTEGER, -- +-- STD_ULOGIC, STD_LOGIC, and STD_LOGIC_VECTOR. -- +-- -- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; + +package std_logic_arith is + + type UNSIGNED is array (NATURAL range <>) of STD_LOGIC; + type SIGNED is array (NATURAL range <>) of STD_LOGIC; + subtype SMALL_INT is INTEGER range 0 to 1; + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: INTEGER) return SIGNED; + function "+"(L: INTEGER; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: INTEGER) return SIGNED; + function "-"(L: INTEGER; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "+"(L: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED) return SIGNED; + function "-"(L: SIGNED) return SIGNED; + function "ABS"(L: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED) return STD_LOGIC_VECTOR; + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "*"(L: SIGNED; R: SIGNED) return SIGNED; + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + + function CONV_INTEGER(ARG: INTEGER) return INTEGER; + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER; + function CONV_INTEGER(ARG: SIGNED) return INTEGER; + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT; + + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED; + + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED; + + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + -- zero extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- returns STD_LOGIC_VECTOR(SIZE-1 downto 0) + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + + -- sign extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- return STD_LOGIC_VECTOR(SIZE-1 downto 0) + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + +end Std_logic_arith; + + + +library IEEE; +use IEEE.std_logic_1164.all; + +package body std_logic_arith is + + function max(L, R: INTEGER) return INTEGER is + begin + if L > R then + return L; + else + return R; + end if; + end; + + + function min(L, R: INTEGER) return INTEGER is + begin + if L < R then + return L; + else + return R; + end if; + end; + + -- synopsys synthesis_off + type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; + constant tbl_BINARY : tbl_type := + ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); + -- synopsys synthesis_on + + -- synopsys synthesis_off + type tbl_mvl9_boolean is array (STD_ULOGIC) of boolean; + constant IS_X : tbl_mvl9_boolean := + (true, true, false, false, true, true, false, false, true); + -- synopsys synthesis_on + + + + function MAKE_BINARY(A : STD_ULOGIC) return STD_ULOGIC is + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + if (IS_X(A)) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + return ('X'); + end if; + return tbl_BINARY(A); + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + + + -- Type propagation function which returns a signed type with the + -- size of the left arg. + function LEFT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the left arg. + function LEFT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns a signed type with the + -- size of the result of a signed multiplication + function MULT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the result of a unsigned multiplication + function MULT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + + + function mult(A,B: SIGNED) return SIGNED is + + variable BA: SIGNED((A'length+B'length-1) downto 0); + variable PA: SIGNED((A'length+B'length-1) downto 0); + variable AA: SIGNED(A'length downto 0); + variable neg: STD_ULOGIC; + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_TC_OP + -- pragma type_function MULT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + neg := B(B'left) xor A(A'left); + BA := CONV_SIGNED(('0' & ABS(B)),(A'length+B'length)); + AA := '0' & ABS(A); + for i in 0 to A'length-1 loop + if AA(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + if (neg= '1') then + return(-PA); + else + return(PA); + end if; + end; + + function mult(A,B: UNSIGNED) return UNSIGNED is + + variable BA: UNSIGNED((A'length+B'length-1) downto 0); + variable PA: UNSIGNED((A'length+B'length-1) downto 0); + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_UNS_OP + -- pragma type_function MULT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + BA := CONV_UNSIGNED(B,(A'length+B'length)); + for i in 0 to A'length-1 loop + if A(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + return(PA); + end; + + -- subtract two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function minus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_TC_OP + + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function plus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_TC_OP + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + -- subtract two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_minus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + + function "*"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1)); -- pragma label mult + end; + + + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1))); -- pragma label mult + end; + + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + + + function "+"(L: UNSIGNED) return UNSIGNED is + begin + return L; + end; + + + function "+"(L: SIGNED) return SIGNED is + begin + return L; + end; + + + function "-"(L: SIGNED) return SIGNED is + -- pragma label_applies_to minus + begin + return 0 - L; -- pragma label minus + end; + + + function "ABS"(L: SIGNED) return SIGNED is + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return L; + else + return 0 - L; + end if; + end; + + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "+"(L: SIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "-"(L: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + variable tmp: SIGNED(L'length-1 downto 0); + begin + tmp := 0 - L; -- pragma label minus + return STD_LOGIC_VECTOR (tmp); + end; + + + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR is + variable tmp: SIGNED(L'length-1 downto 0); + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return STD_LOGIC_VECTOR (L); + else + tmp := 0 - L; + return STD_LOGIC_VECTOR (tmp); + end if; + end; + + + -- Type propagation function which returns the type BOOLEAN + function UNSIGNED_RETURN_BOOLEAN(A,B: UNSIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns the type BOOLEAN + function SIGNED_RETURN_BOOLEAN(A,B: SIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := FALSE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less_or_equal(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := TRUE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := FALSE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less_or_equal(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := TRUE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_eql(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_EQL + begin + for i in L'range loop + if L(i) /= R(i) then + return FALSE; + end if; + end loop; + return TRUE; + end; + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_neq(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_NEQ + begin + for i in L'range loop + if L(i) /= R(i) then + return TRUE; + end if; + end loop; + return FALSE; + end; + + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + variable sign_bit: STD_ULOGIC; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + sign_bit := ARG(ARG'left); + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => sign_bit); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + + + function CONV_INTEGER(ARG: INTEGER) return INTEGER is + begin + return ARG; + end; + + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_UNSIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 31 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: SIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_SIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 32 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + if i /= ARG'left then + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end if; + end loop; + tmp := MAKE_BINARY(ARG(ARG'left)); + if tmp = '1' then + if ARG'length = 32 then + result := (result - 2**30) - 2**30; + else + result := result - (2 ** (ARG'length-1)); + end if; + end if; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT is + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + tmp := tbl_BINARY(ARG); + if tmp = '1' then + return 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + return 0; + else + return 0; + end if; + -- synopsys synthesis_on + end; + + + -- convert an integer to a unsigned STD_ULOGIC_VECTOR + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED is + variable result: UNSIGNED(SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_UNSIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED is + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to a 2's complement STD_ULOGIC_VECTOR + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED is + variable result: SIGNED (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED is + subtype rtype is SIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to an STD_LOGIC_VECTOR + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is + variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) return STD_LOGIC_VECTOR is + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) + return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds: STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + +end std_logic_arith; diff --git a/lib/models/memory/sdram/mt48lc8m16a2/test.do b/lib/models/memory/sdram/mt48lc8m16a2/test.do new file mode 100644 index 0000000..e1f75c3 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc8m16a2.vhd +vcom test.vhd +vsim tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48lc8m16a2/test.txt b/lib/models/memory/sdram/mt48lc8m16a2/test.txt new file mode 100644 index 0000000..36bc0ea --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/test.txt @@ -0,0 +1,115 @@ +0 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +22 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +32 ns 1 0 1 1 1 00 00 0 -100 1 0 0 0 +42 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +52 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +62 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +72 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +82 ns 1 0 0 1 0 00 00 1024 -100 0 0 0 0 +92 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +102 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +112 ns 1 0 0 0 1 00 00 0 -100 0 0 0 0 +122 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +132 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +142 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +152 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +162 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +172 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +182 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +192 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +202 ns 1 0 0 0 1 00 00 0 -100 0 0 0 0 +212 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +222 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +232 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +242 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +252 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +262 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +272 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +282 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +292 ns 1 0 0 0 0 00 00 51 -100 0 0 0 0 +302 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +312 ns 1 0 0 1 1 00 00 0 -100 0 0 0 0 +322 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +332 ns 1 0 1 0 0 00 00 0 100 0 0 0 0 +342 ns 1 1 1 1 1 00 00 0 101 0 0 0 0 +352 ns 1 0 0 1 1 00 01 0 102 0 0 0 0 +362 ns 1 1 1 1 1 00 00 0 103 0 0 0 0 +372 ns 1 1 1 1 1 00 00 0 104 0 0 0 0 +382 ns 1 1 1 1 1 00 00 0 105 0 0 0 0 +392 ns 1 1 1 1 1 00 00 0 106 0 0 0 0 +402 ns 1 1 1 1 1 00 00 0 107 0 0 0 0 +412 ns 1 0 1 0 0 00 01 0 200 0 0 0 0 +422 ns 1 0 0 1 0 00 00 0 201 0 0 0 0 +432 ns 1 0 0 1 1 00 10 0 202 0 0 0 0 +442 ns 1 1 1 1 1 00 00 0 203 0 0 0 0 +452 ns 1 1 1 1 1 00 00 0 204 0 0 0 0 +462 ns 1 1 1 1 1 00 00 0 205 0 0 0 0 +472 ns 1 1 1 1 1 00 00 0 206 0 0 0 0 +482 ns 1 1 1 1 1 00 00 0 207 0 0 0 0 +492 ns 1 0 1 0 0 00 10 0 300 0 0 0 0 +502 ns 1 0 0 1 0 00 01 0 301 0 0 0 0 +512 ns 1 0 0 1 1 00 11 0 302 0 0 0 0 +522 ns 1 1 1 1 1 00 00 0 303 0 0 0 0 +532 ns 1 1 1 1 1 00 00 0 304 0 0 0 0 +542 ns 1 1 1 1 1 00 00 0 305 0 0 0 0 +552 ns 1 1 1 1 1 00 00 0 306 0 0 0 0 +562 ns 1 1 1 1 1 00 00 0 307 0 0 0 0 +572 ns 1 0 1 0 0 00 11 0 400 0 0 0 0 +582 ns 1 0 0 1 0 00 10 0 401 0 0 0 0 +592 ns 1 0 0 1 1 00 00 0 402 0 0 0 0 +602 ns 1 1 1 1 1 00 00 0 403 0 0 0 0 +612 ns 1 1 1 1 1 00 00 0 404 0 0 0 0 +622 ns 1 1 1 1 1 00 00 0 405 0 0 0 0 +632 ns 1 1 1 1 1 00 00 0 406 0 0 0 0 +642 ns 1 1 1 1 1 00 00 0 407 0 0 0 0 +652 ns 1 0 1 0 1 00 00 0 -100 0 0 0 0 +662 ns 1 0 0 1 0 00 11 0 -100 0 0 0 0 +672 ns 1 0 0 1 1 00 01 0 -100 0 0 0 0 +682 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +692 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +702 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +712 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +722 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +732 ns 1 0 1 0 1 00 01 0 -100 0 0 0 0 +742 ns 1 0 0 1 0 00 00 0 -100 0 0 0 0 +752 ns 1 0 0 1 1 00 10 0 -100 0 0 0 0 +762 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +772 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +782 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +792 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +802 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +812 ns 1 0 1 0 1 00 10 0 -100 0 0 0 0 +822 ns 1 0 0 1 0 00 01 0 -100 0 0 0 0 +832 ns 1 0 0 1 1 00 11 0 -100 0 0 0 0 +842 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +852 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +862 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +872 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +882 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +892 ns 1 0 1 0 1 00 11 0 -100 0 0 0 0 +902 ns 1 0 0 1 0 00 10 0 -100 0 0 0 0 +912 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +922 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +932 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +942 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +952 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +962 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +972 ns 1 0 0 1 0 00 11 0 -100 0 0 0 0 +982 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +992 ns 1 0 0 1 1 00 00 0 -100 0 0 0 0 +1002 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +1012 ns 1 0 1 0 0 00 00 1034 110 0 0 0 0 +1022 ns 1 1 1 1 1 00 00 0 111 0 0 0 0 +1032 ns 1 1 1 1 1 00 00 0 112 0 0 0 0 +1042 ns 1 1 1 1 1 00 00 0 113 0 0 0 0 +1052 ns 1 1 1 1 1 00 00 0 114 0 0 0 0 +1062 ns 1 1 1 1 1 00 00 0 115 0 0 0 0 +1072 ns 1 1 1 1 1 00 00 0 116 0 0 0 0 +1082 ns 1 1 1 1 1 00 00 0 117 0 0 0 0 +1092 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +1102 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +1112 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +1122 ns 1 0 0 1 1 00 00 0 -100 0 0 0 0 +1132 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 +1142 ns 1 0 1 1 1 00 00 0 -100 0 1 0 0 +1152 ns 1 1 1 1 1 00 00 0 -100 0 0 0 0 diff --git a/lib/models/memory/sdram/mt48lc8m16a2/test.vhd b/lib/models/memory/sdram/mt48lc8m16a2/test.vhd new file mode 100644 index 0000000..b16346f --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/test.vhd @@ -0,0 +1,197 @@ +LIBRARY ieee; +LIBRARY work; +USE ieee.std_logic_1164.ALL; +USE work.std_logic_arith.ALL; +USE work.util_1164.ALL; +USE std.textio.ALL; +USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 12; + CONSTANT data_bits : INTEGER := 16; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + + COMPONENT mt48lc8m16a2 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := (OTHERS => '0'); + Load : IN STD_LOGIC := '0'; + Unload : IN STD_LOGIC := '0'; + Row_start : IN INTEGER := 0; + Row_end : IN INTEGER := 0 + ); + END COMPONENT; + + FOR ALL : mt48lc8m16a2 USE ENTITY work.mt48lc8m16a2 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL PLoad : STD_LOGIC; + SIGNAL PUnload : STD_LOGIC; + SIGNAL PRow_start : INTEGER; + SIGNAL PRow_end : INTEGER; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc8m16a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm, + Load => pLoad, + Unload => pUnload, + Row_start => PRow_start, + Row_end => PRow_end + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : STD_LOGIC; + VARIABLE pCs_var : STD_LOGIC; + VARIABLE pRas_var : STD_LOGIC; + VARIABLE PCas_var : STD_LOGIC; + VARIABLE pWe_var : STD_LOGIC; + VARIABLE pDqm_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pBa_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE pLoad_var : STD_LOGIC; + VARIABLE pUnload_var : STD_LOGIC; + VARIABLE pRow_start_var : INTEGER; + VARIABLE pRow_end_var : INTEGER; + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read(l, time_var); + read(l, pCke_var); + read(l, pCs_var); + read(l, pRas_var); + read(l, pCas_var); + read(l, pWe_var); + read(l, pDqm_var); + read(l, pBa_var); + read(l, pAddr_var); + read(l, pDq_var); + read (l, pLoad_var); + read (l, pUnload_var); + read (l, pRow_start_var); + read (l, pRow_end_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + IF pWe_var='1' THEN + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= pLoad_var; + pUnload <= pUnload_var; + pRow_start <= pRow_start_var; + pRow_end <= pRow_end_var; + ELSE + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= pLoad_var; + pUnload <= pUnload_var; + pRow_start <= pRow_start_var; + pRow_end <= pRow_end_var; + END IF; + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc8m16a2/util1164.vhd b/lib/models/memory/sdram/mt48lc8m16a2/util1164.vhd new file mode 100644 index 0000000..bb4b5dd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/util1164.vhd @@ -0,0 +1,124 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE STD.textio.ALL; + +PACKAGE util_1164 IS + PROCEDURE read(l: INOUT line; value: OUT std_logic); + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector); + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0); + PROCEDURE Grow_line(L : inout LINE; incr : in integer); +END util_1164; + + + +PACKAGE BODY util_1164 IS + + FUNCTION white_space(value:character) RETURN boolean IS + VARIABLE result:boolean; + BEGIN + IF (value = ' ') OR (value = HT) THEN + RETURN true; + ELSE + RETURN false; + END IF; + END white_space; + + PROCEDURE read(l: INOUT line; value: OUT std_logic) IS + VARIABLE char_var: character:= ' '; + BEGIN + WHILE l'LENGTH > 0 LOOP + read(l,char_var); + IF NOT white_space(char_var) THEN + EXIT; + END IF; + END LOOP; + IF white_space(char_var) THEN + ASSERT false REPORT "No std_logic value found in file" + SEVERITY error; + value := 'X'; + RETURN; + END IF; + + CASE char_var IS + WHEN 'U'|'u' => value := 'U'; + WHEN '0' => value := '0'; + WHEN '1' => value := '1'; + WHEN 'X'|'x' => value := 'X'; + WHEN 'L'|'l' => value := 'L'; + WHEN 'H'|'h' => value := 'H'; + WHEN 'W'|'w' => value := 'W'; + WHEN 'Z'|'z' => value := 'Z'; + WHEN '-' => value := '-'; + WHEN OTHERS => + ASSERT false REPORT "Unrecognized value read for std_logic" + SEVERITY error; + value := 'X'; + END CASE; + END read; + + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector) IS + BEGIN + FOR i IN value'HIGH DOWNTO value'LOW LOOP + IF l'LENGTH > 0 THEN + read(l,value(i)); + ELSE + ASSERT false REPORT "Not enough values for std_logic_vector in file" + SEVERITY error; + RETURN; + END IF; + END LOOP; + END read; + + procedure Grow_line(L : inout LINE; incr : in integer) + is + variable old_L : LINE := L; + variable bfp: integer; -- Blank fill pointer. + begin + assert incr > 0 + report "Textio: Grow_line called with zero increment." + severity error; + + if L = null then + bfp := 0; + L := new string(1 to incr); + else + bfp := old_L'high; + L := new string(old_L'low to old_L'high + incr); + L(old_L'low to old_L'high) := old_L.all; + Deallocate(old_L); + end if; + for i in 1 to incr loop + L(bfp + i) := ' '; + end loop; + end; + + + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0) IS + variable fw: integer := VALUE'length; + variable bp: integer; + variable offset: integer := 0; + alias normal : std_logic_vector(0 to value'length - 1) is value; + begin + if L /= null then + bp := L'high + 1; + else bp := 1; + end if; + if FIELD > VALUE'length then + fw := FIELD; + if JUSTIFIED = right then + offset := fw - VALUE'length; + end if; + end if; + Grow_line(L, fw); + for i in normal'range loop + L(bp + i + offset) := character'val( + std_logic'pos(normal(i)) + character'pos('0')); + end loop; + end; + + +END util_1164; diff --git a/lib/models/memory/sdram/mt48lc8m16a2/vec_gen.vhd b/lib/models/memory/sdram/mt48lc8m16a2/vec_gen.vhd new file mode 100644 index 0000000..cc7f9d6 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/vec_gen.vhd @@ -0,0 +1,364 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.io_utils.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); + first_data : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT; cs : IN BIT); + PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle(SIGNAL clk : IN BIT); + PROCEDURE load_array(load : IN BIT); + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)); + +END generate_vectors; + + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; + dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, first_data, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, row_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, Cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT; cs : IN BIT) IS + + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, cs, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT_VECTOR(1 DOWNTO 0); cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE col_address : INTEGER := 0; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, col_address, right, 6); --address +write(l, data_bus, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS +BEGIN + WAIT UNTIL clk = '1'; +END; + +PROCEDURE load_array(load : IN BIT) IS + VARIABLE l : LINE; + VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 1, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)) IS + VARIABLE l : LINE; + VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, 1, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 1, right, 4); --Ras +write(l, 1, right, 4); --Cas +write(l, 1, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, 0, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 1, right, 4); --unload +write(l, row_start, right, 6); --row_address_start +write(l, row_end, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + +VARIABLE l : LINE; +VARIABLE dqm : BIT_VECTOR(1 DOWNTO 0) := "00"; +VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; + +BEGIN + +IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); +ELSE + write(l, now-set_up, left, 4, ns); +END IF; + +write(l, cke, right, 4); --Cke +write(l, 0, right, 4); --Cs +write(l, 0, right, 4); --Ras +write(l, 0, right, 4); --Cas +write(l, 0, right, 4); --We +write(l, dqm, right, 4); --Dqm +write(l, bank, right, 4); --Ba +write(l, op_code, right, 6); --address +write(l, -100, right, 6); --first data location +write(l, 0, right, 4); --load +write(l, 0, right, 4); --unload +write(l, 0, right, 6); --row_address_start +write(l, 0, right, 6); --row_address_end +writeline(output_file,l); --write vector to file + +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc8m16a2/vector.do b/lib/models/memory/sdram/mt48lc8m16a2/vector.do new file mode 100644 index 0000000..7480359 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/vector.do @@ -0,0 +1,4 @@ +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all diff --git a/lib/models/memory/sdram/mt48lc8m16a2/wave.do b/lib/models/memory/sdram/mt48lc8m16a2/wave.do new file mode 100644 index 0000000..0e59196 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m16a2/wave.do @@ -0,0 +1,33 @@ +onerror {resume} +add wave -logic /tb/u1/clk +add wave -logic /tb/u1/cke +add wave -logic /tb/u1/cs_n +add wave -logic /tb/u1/ras_n +add wave -logic /tb/u1/cas_n +add wave -logic /tb/u1/we_n +add wave -literal -decimal /tb/u1/addr +add wave -literal -unsigned /tb/u1/ba +add wave -literal -decimal /tb/u1/dq +add wave -literal /tb/u1/dqm +add wave -literal /tb/u1/operation +add wave -literal -decimal /tb/u1/mode_reg +add wave -logic /tb/u1/active_enable +add wave -logic /tb/u1/aref_enable +add wave -logic /tb/u1/burst_term +add wave -logic /tb/u1/mode_reg_enable +add wave -logic /tb/u1/prech_enable +add wave -logic /tb/u1/read_enable +add wave -logic /tb/u1/write_enable +add wave -logic /tb/u1/burst_length_1 +add wave -logic /tb/u1/burst_length_2 +add wave -logic /tb/u1/burst_length_4 +add wave -logic /tb/u1/burst_length_8 +add wave -logic /tb/u1/cas_latency_2 +add wave -logic /tb/u1/cas_latency_3 +add wave -literal /tb/u1/pre_chk +add wave -literal /tb/u1/act_chk +add wave -literal /tb/u1/bank_chk +add wave -literal -decimal /tb/u1/row_chk +add wave -literal -decimal /tb/u1/col_chk +add wave -logic /tb/u1/dq_in_chk +add wave -logic /tb/u1/dq_out_chk diff --git a/lib/models/memory/sdram/mt48lc8m8a2/base.do b/lib/models/memory/sdram/mt48lc8m8a2/base.do new file mode 100644 index 0000000..d2afbcb --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/base.do @@ -0,0 +1,5 @@ +vcom util1164.vhd +vcom stdlogar.vhd +vcom io_utils.vhd +vcom mti_pkg.vhd + diff --git a/lib/models/memory/sdram/mt48lc8m8a2/ed_comnd.vhd b/lib/models/memory/sdram/mt48lc8m8a2/ed_comnd.vhd new file mode 100644 index 0000000..523da89 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/ed_comnd.vhd @@ -0,0 +1,370 @@ +-------------------------------------------------------------------------------------------------- +-- COMMAND FORMAT -- +-- -- +-- write(column address(integer), bank(bit_vector), first data(integer), dqm(bit), cke(bit)); -- +-- read(column address(integer), bank(bit_vector), dqm(bit), cke(bit)); -- +-- active(row address(integer), bank(bit_vector), data bus (integer), dqm(bit), cke(bit)); -- +-- precharge(bank(bit_vector), address (integer), data bus(integer), dqm(bit), cke(bit)); -- +-- nop(data bus(integer), dqm(bit), cke(bit)); -- +-- burst_term(data bus(integer), dqm(bit), cke(bit)); -- +-- load_array('1'); -- +-- load_mode_reg(register(integer), cke(bit)); -- +-- next_cycle(clk); This is used after every command(incl. nop) to clock -- +-- at the correct clock frequency entered in the clock -- +-- period constant below -- +-- unload_array(row_start(integer), row_end(integer), bank(bit_vector)) -- +-- load_mode_reg(op_code(integer)) -- +-- -- +-------------------------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.generate_vectors.all; + +ENTITY vector_generate IS +END vector_generate; + +ARCHITECTURE vector_generate OF vector_generate IS + + SIGNAL stim_done : BOOLEAN := FALSE; + SIGNAL clk : BIT := '0'; + CONSTANT clk_start : time := 15 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT Z : INTEGER := -100; + +BEGIN + +PROCESS + +BEGIN + +WAIT UNTIL clk = '1' AND clk'EVENT; + +--------------------ENTER COMMANDS BELOW THIS LINE----------------------------- +--******************DO NOT USE -100 FOR A DQ VALUE*************************---- +--*******************Z WILL PLACE HI-Z ON THE BUS**************************---- +--*******USE next_cycle(clk) FOR ADVANCING TO NEXT CLOCK CYCLE*************---- + +nop(Z, '0', '1'); --Always begin with one nop when using Micron's testbench + +next_cycle(clk); +load_array; + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +precharge("00", 1024, Z, '0', '1'); + +FOR i IN 1 to 2 LOOP + next_cycle(clk); + nop(Z, '0', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, '0', '1'); +END LOOP; + +next_cycle(clk); +auto_refresh; + +FOR i IN 1 TO 8 LOOP + next_cycle(clk); + nop(Z, '0', '1'); +END LOOP; + +next_cycle(clk); +load_mode_reg(49, '1'); -- 19 / 35 / 51 -> lat=3,bl=8,mode=seq + +next_cycle(clk); +nop(Z, '0', '1'); + +-- Write Section + +next_cycle(clk); +active(0, "00", Z, '0', '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +--write(0, "00", 10, '0', '1'); -- Write Bank 0 +write(1024, "00", 10, '0', '1'); -- Write Bank 0 Auto Precharge + +next_cycle(clk); +nop(11, '0', '1'); + +next_cycle(clk); +active(0, "01", 12, '0', '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(13, '0', '1'); + +next_cycle(clk); +nop(14, '0', '1'); + +next_cycle(clk); +nop(15, '0', '1'); + +next_cycle(clk); +nop(16, '0', '1'); + +next_cycle(clk); +nop(17, '0', '1'); + +next_cycle(clk); +--write(0, "01", 20, '0', '1'); -- Write Bank 1 +write(1024, "01", 20, '0', '1'); -- Write Bank 1 Auto Precharge + +next_cycle(clk); +--precharge("00", 0, 21, '0', '1'); -- Precharge Bank 0 +nop(21, '0', '1'); + +next_cycle(clk); +active(0, "10", 22, '0', '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(23, '0', '1'); + +next_cycle(clk); +nop(24, '0', '1'); + +next_cycle(clk); +nop(25, '0', '1'); + +next_cycle(clk); +nop(26, '0', '1'); + +next_cycle(clk); +nop(27, '0', '1'); + +next_cycle(clk); +--write(0, "10", 30, '0', '1'); -- Write Bank 2 +write(1024, "10", 30, '0', '1'); -- Write Bank 2 Auto Precharge + +next_cycle(clk); +--precharge("01", 0, 31, '0', '1'); -- Precharge Bank 1 +nop(31, '0', '1'); + +next_cycle(clk); +active(0, "11", 32, '0', '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(33, '0', '1'); + +next_cycle(clk); +nop(34, '0', '1'); + +next_cycle(clk); +nop(35, '0', '1'); + +next_cycle(clk); +nop(36, '0', '1'); + +next_cycle(clk); +nop(37, '0', '1'); + +next_cycle(clk); +--write(0, "11", 40, '0', '1'); -- Write Bank 3 +write(1024, "11", 40, '0', '1'); -- Write Bank 3 Auto Precharge + +next_cycle(clk); +--precharge("10", 0, 41, '0', '1'); -- Precharge Bank 2 +nop(41, '0', '1'); + +next_cycle(clk); +active(0, "00", 42, '0', '1'); -- Activate Bank 0 + +next_cycle(clk); +nop(43, '0', '1'); + +next_cycle(clk); +nop(44, '0', '1'); + +next_cycle(clk); +nop(45, '0', '1'); + +next_cycle(clk); +nop(46, '0', '1'); + +next_cycle(clk); +nop(47, '0', '1'); + +-- Read Section + +next_cycle(clk); +--read(0, "00", '0', '1'); -- Read Bank 0 +read(1024, "00", '0', '1'); -- Read Bank 0 Auto Precharge + +next_cycle(clk); +--precharge("11", 0, Z, '0', '1'); -- Precharge Bank 3 +nop(Z, '0', '1'); + +next_cycle(clk); +active(0, "01", Z, '0', '1'); -- Activate Bank 1 + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +--read(0, "01", '0', '1'); -- Read Bank 1 +read(1024, "01", '0', '1'); -- Read Bank 1 Auto Precharge + +next_cycle(clk); +--precharge("00", 0, Z, '0', '1'); -- Precharge Bank 0 +nop(Z, '0', '1'); + +next_cycle(clk); +active(0, "10", Z, '0', '1'); -- Activate Bank 2 + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +--read(0, "10", '0', '1'); -- Read Bank 2 +read(1024, "10", '0', '1'); -- Read Bank 2 Auto Precharge + +next_cycle(clk); +--precharge("01", 0, Z, '0', '1'); -- Precharge Bank 1 +nop(Z, '0', '1'); + +next_cycle(clk); +active(0, "11", Z, '0', '1'); -- Activate Bank 3 + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +--read(0, "11", '0', '1'); -- Read Bank 3 +read(1024, "11", '0', '1'); -- Read Bank 3 Auto Precharge + +next_cycle(clk); +--precharge("10", 0, Z, '0', '1'); -- Precharge Bank 2 +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +--precharge("11", 0, Z, '0', '1'); -- Precharge Bank 3 +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +nop(Z, '0', '1'); + +next_cycle(clk); +unload_array(0, 1, "00"); -- Unload From Row 0-1, Bank 00 + +next_cycle(clk); +unload_array(0, 1, "01"); -- Unload From Row 0-1, Bank 10 + +next_cycle(clk); +unload_array(0, 1, "10"); -- Unload From Row 0-1, Bank 01 + +next_cycle(clk); +unload_array(0, 1, "11"); -- Unload From Row 0-1, Bank 11 + +next_cycle(clk); +nop(Z, '0', '1'); + +stim_done <= TRUE; --always include this line at the end of your stimulus + +------------------------------------------------------------------------------- +--*************************************************************************---- +END PROCESS; + + +clock: + PROCESS + VARIABLE done_time : time; + VARIABLE cycle_var : integer := 0; + BEGIN + cycle <= 0; + clk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + clk <= '1'; + cycle <= cycle_var; + WAIT for clk_period/2; + cycle_var := cycle_var + 1; + clk <= '0'; + WAIT for clk_period/2; + END LOOP; + + ASSERT (FALSE) + REPORT "Test Vectors Generated" + SEVERITY note; + + WAIT; + END PROCESS; + + +END; diff --git a/lib/models/memory/sdram/mt48lc8m8a2/io_utils.vhd b/lib/models/memory/sdram/mt48lc8m8a2/io_utils.vhd new file mode 100644 index 0000000..dfcb84a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/io_utils.vhd @@ -0,0 +1,266 @@ +LIBRARY ieee; +USE std.textio.ALL; +USE ieee.std_logic_1164.ALL; + +PACKAGE io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0); + + TYPE radix IS (binary, octal, decimal, hex); + + -- read a number from the line + -- use this if you have hex numbers that are not in VHDL pound-sign format + PROCEDURE read(l : INOUT line; value : OUT integer; radix : IN positive); + + -- read a number that might be in VHDL pound-sign format + PROCEDURE read_based(l : INOUT line; value : OUT integer); + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false); +END io_utils; + +PACKAGE BODY io_utils IS + + PROCEDURE write_string(l : INOUT line; + value : IN string; + justified : IN side := right; + field : IN width := 0) + IS + BEGIN + write(l, value, justified, field); + END; + + PROCEDURE shrink_line(l : INOUT line; pos : integer) IS + VARIABLE tmpl : line; + BEGIN + tmpl := l; + l := NEW string'(tmpl(pos TO tmpl'high)); + deallocate(tmpl); + END; + + PROCEDURE read(l : INOUT line; + value : OUT integer; + radix : IN positive) + IS + CONSTANT not_digit : integer := -999; + + -- convert a character to a value from 0 to 15 + FUNCTION digit_value(c : character) RETURN integer IS + BEGIN + IF (c >= '0') AND (c <= '9') THEN + RETURN (character'pos(c) - character'pos('0')); + ELSIF (c >= 'a') AND (c <= 'f') THEN + RETURN (character'pos(c) - character'pos('a') + 10); + ELSIF (c >= 'A') AND (c <= 'F') THEN + RETURN (character'pos(c) - character'pos('A') + 10); + ELSE + RETURN not_digit; + END IF; + END; + + -- skip leading white space in the line + PROCEDURE skip_white(VARIABLE l : IN line; pos : OUT integer) IS + BEGIN + pos := l'low; + FOR i IN l'low TO l'high LOOP + CASE l(i) IS + WHEN ' ' | ht => + pos := i + 1; + WHEN OTHERS => + EXIT; + END CASE; + END LOOP; + END; + + VARIABLE digit : integer; + VARIABLE result : integer := 0; + VARIABLE pos : integer; + BEGIN + -- skip white space + skip_white(l, pos); + + -- calculate the value + FOR i IN pos TO l'right LOOP + digit := digit_value(l(i)); + EXIT WHEN (digit = not_digit) OR (digit >= radix); + result := result * radix + digit; + pos := i + 1; + END LOOP; + value := result; + + -- remove the "used" characters from the line + shrink_line(l, pos); + END; + + PROCEDURE read_based(l : INOUT line; value : OUT integer) IS + VARIABLE digit : integer; + VARIABLE num : integer; + VARIABLE base : integer; + BEGIN + read(l, num, 10); + IF (l'length > 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + base := num; + read(l, num, base); + IF (l'length >= 1) AND (l(l'left) = '#') THEN + shrink_line(l, l'left+1); + END IF; + END IF; + value := num; + END; + + PROCEDURE write(l : INOUT line; + value : IN std_logic_vector; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_int(bv : std_logic_vector) RETURN integer + IS + VARIABLE result : integer := 0; + BEGIN + FOR i IN bv'RANGE LOOP + result := result * 2; + IF (bv(i) = '1') THEN + result := result + 1; + END IF; + END LOOP; + RETURN result; + END; + + TYPE array_of_widths IS ARRAY(radix) OF natural; + CONSTANT nibble_widths : array_of_widths := ( + binary => 1, + octal => 3, + hex => 4, + decimal=> 32); + CONSTANT hex_digit : string(1 TO 16) := "0123456789ABCDEF"; + + ALIAS input_val : std_logic_vector(value'length DOWNTO 1) IS value; + CONSTANT nibble_width : natural := nibble_widths(base); + CONSTANT result_width : natural := (value'length + nibble_width - 1)/nibble_width; + + VARIABLE result : string(1 TO result_width); -- longest possible value + VARIABLE result_pos : positive := 1; + VARIABLE nibble_val : integer; + VARIABLE bitcnt : integer; + BEGIN + IF base = decimal THEN + write(l, to_int(value), justified, field, base, use_pound); + RETURN; + END IF; + + bitcnt := value'length MOD nibble_width; + IF (bitcnt = 0) THEN + bitcnt := nibble_width; + END IF; + FOR i IN input_val'RANGE LOOP + nibble_val := nibble_val * 2; + IF (input_val(i) = '1') THEN + nibble_val := nibble_val + 1; + END IF; + bitcnt := bitcnt - 1; + IF (bitcnt = 0) THEN + result(result_pos) := hex_digit(nibble_val + 1); + result_pos := result_pos + 1; + nibble_val := 0; + bitcnt := nibble_width; + END IF; + END LOOP; + write(l, result, justified, field); + END; + + PROCEDURE write(l : INOUT line; + value : IN integer; + justified : IN side := right; + field : IN width := 0; + base : IN radix; + use_pound : boolean := false) + IS + FUNCTION to_bv(int : integer) RETURN std_logic_vector + IS + VARIABLE bv : std_logic_vector(32 DOWNTO 1) := (OTHERS => '0'); + VARIABLE pos : integer := 0; + VARIABLE tmpval : integer := int; + BEGIN + FOR i IN 1 TO 32 LOOP + pos := pos + 1; + IF (tmpval MOD 2) = 1 THEN + bv(i) := '1'; + END IF; + tmpval := tmpval / 2; + EXIT WHEN tmpval = 0; + END LOOP; + RETURN bv(pos DOWNTO 1); + END; + + VARIABLE tmp : line; + BEGIN + IF (base = decimal) THEN + IF (use_pound) THEN + write_string(tmp, "10#"); + END IF; + write(tmp, value); + IF (use_pound) THEN + write_string(tmp, "#"); + END IF; + write(l, tmp.ALL, justified, field); + deallocate(tmp); + ELSE + write(l, to_bv(value), justified, field, base, use_pound); + END IF; + END; + +END io_utils; + + + +-- test the hex number reader +--ENTITY test IS END; + +--USE std.textio.ALL; +--USE work.io_utils.ALL; +--ARCHITECTURE hex_test OF test IS +--BEGIN +-- PROCESS +-- VARIABLE val : integer; +-- FILE myfile : text IS IN "values"; +-- VARIABLE inline : line; +-- VARIABLE outline : line; +-- BEGIN +-- WHILE NOT endfile(myfile) LOOP +-- readline(myfile, inline); + +-- write(outline, inline.ALL); +-- +-- read_based(inline, val); + -- write_string(outline, " binary: "); + -- write(outline, val, base => binary); + -- write_string(outline, " octal: "); + -- write(outline, val, base => octal); + -- write_string(outline, " decimal: "); + -- write(outline, val, base => decimal); +-- write_string(outline, " hex: "); +-- write(outline, val, base => hex); +-- writeline(output, outline); +-- END LOOP; +-- WAIT; +-- END PROCESS; +--END; + + diff --git a/lib/models/memory/sdram/mt48lc8m8a2/loaddata.txt b/lib/models/memory/sdram/mt48lc8m8a2/loaddata.txt new file mode 100644 index 0000000..0a69592 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/loaddata.txt @@ -0,0 +1,41 @@ +0 0 00 0 -- ROW (HEX), COL (HEX), BANK (BIN), DATA (HEX) +0 1 00 1 +0 2 00 2 +0 3 00 3 +0 4 00 4 +0 5 00 5 +0 6 00 6 +0 7 00 7 +0 8 00 8 +0 9 00 9 +0 0 01 10 +0 1 01 11 +0 2 01 12 +0 3 01 13 +0 4 01 14 +0 5 01 15 +0 6 01 16 +0 7 01 17 +0 8 01 18 +0 9 01 19 +0 0 10 20 +0 1 10 21 +0 2 10 22 +0 3 10 23 +0 4 10 24 +0 5 10 25 +0 6 10 26 +0 7 10 27 +0 8 10 28 +0 9 10 29 +0 0 11 30 +0 1 11 31 +0 2 11 32 +0 3 11 33 +0 4 11 34 +0 5 11 35 +0 6 11 36 +0 7 11 37 +0 8 11 38 +0 9 11 39 + diff --git a/lib/models/memory/sdram/mt48lc8m8a2/mt48lc8m8a2.vhd b/lib/models/memory/sdram/mt48lc8m8a2/mt48lc8m8a2.vhd new file mode 100644 index 0000000..3d8ec4d --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/mt48lc8m8a2.vhd @@ -0,0 +1,1351 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC8M8A2.VHD +-- Version: 0.0f +-- Date: July 8th, 1999 +-- Model: Behavioral +-- Simulator: Model Technology (PC version 5.2e PE) +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC8M8A2 (2Mb x 8 x 4 Banks) +-- +-- Description: Micron 64Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- ---- ---------------------------- ---------- ------------------------------------- +-- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) +-- Micron Technology Inc. Fix tWR = 15 ns (Manual) +-- Fix tRP (Autoprecharge to AutoRefresh) +-- +-- 0.0e Son P. Huynh 208-368-3825 05/25/1999 Fix R/W Interrupting R/W with AP +-- Micron Technology Inc. +-- +-- 0.0d Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP +-- Micron Technology Inc. +-- +-- 0.0c Son P. Huynh 208-368-3825 01/18/1998 Add Load / Unload memory array +-- Micron Technology Inc. +-- +-- 0.0b Son P. Huynh 208-368-3825 12/09/1998 Fix some timing check problem +-- Micron Technology Inc. - Improve model functionality +-- +-- 0.0a Son P. Huynh 208-368-3825 08/10/1998 First Release +-- Micron Technology Inc. - Simple testbench included +----------------------------------------------------------------------------------------- + +LIBRARY STD; + USE STD.TEXTIO.ALL; +LIBRARY IEEE; + USE IEEE.STD_LOGIC_1164.ALL; +LIBRARY WORK; + USE WORK.IO_UTILS.ALL; + USE WORK.MTI_PKG.ALL; + +ENTITY mt48lc8m8a2 IS + GENERIC ( + -- Timing Parameters for -75 (PC133) and CAS Latency = 2 + tAC : TIME := 6.0 ns; + tHZ : TIME := 7.0 ns; + tOH : TIME := 2.7 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 44.0 ns; + tRC : TIME := 66.0 ns; + tRCD : TIME := 20.0 ns; + tRP : TIME := 20.0 ns; + tRRD : TIME := 15.0 ns; + tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) + tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) + + tAH : TIME := 0.8 ns; + tAS : TIME := 1.5 ns; + tCH : TIME := 2.5 ns; + tCL : TIME := 2.5 ns; + tCK : TIME := 10.0 ns; + tDH : TIME := 0.8 ns; + tDS : TIME := 1.5 ns; + tCKH : TIME := 0.8 ns; + tCKS : TIME := 1.5 ns; + tCMH : TIME := 0.8 ns; + tCMS : TIME := 1.5 ns; + + addr_bits : INTEGER := 12; + data_bits : INTEGER := 8; + col_bits : INTEGER := 9 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC := '0'; + Load : IN STD_LOGIC := '0'; + Unload : IN STD_LOGIC := '0'; + Row_start : IN INTEGER := 0; + Row_end : IN INTEGER := 0 + ); +END mt48lc8m8a2; + +ARCHITECTURE behave OF mt48lc8m8a2 IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, FILE_LOAD, FILE_UNLOAD); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; + TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); + TYPE Array2xB IS ARRAY (1 DOWNTO 0) OF BIT; + TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; + SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; + SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; + SIGNAL Write_burst_mode : BIT := '0'; + SIGNAL Sys_clk, CkeZ : BIT := '0'; + + -- Checking internal wires + SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; + SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; + SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; + SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + BEGIN + -- CS# Decode + WITH Cs_n SELECT + Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + WITH Cs_n SELECT + We_in <= TO_BIT (We_n, '1') WHEN '0', + '1' WHEN '1', + '1' WHEN OTHERS; + + -- Commands Decode + Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= TO_BIT(Cke, '1'); + END IF; + Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCBV; + VARIABLE Bank_addr : Array4x2BV; + VARIABLE Dqm_reg : Array2xB; + + VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2BV; + VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0); + VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Load and Unload variables + FILE load_file : TEXT IS IN "loaddata.txt"; -- Data load + FILE out_file0 : TEXT IS OUT "outdata0.txt"; -- Data dump for bank 0 + FILE out_file1 : TEXT IS OUT "outdata1.txt"; -- Data dump for bank 1 + FILE out_file2 : TEXT IS OUT "outdata2.txt"; -- Data dump for bank 2 + FILE out_file3 : TEXT IS OUT "outdata3.txt"; -- Data dump for bank 3 + VARIABLE l_in, l_out0, l_out1, l_out2, l_out3 : LINE; + VARIABLE array_buffer : BIT_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE write_data_var : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE row_load, col_load, dq_load : INTEGER; + VARIABLE ba_load : BIT_VECTOR (1 DOWNTO 0); + VARIABLE dq_vec : BIT_VECTOR (data_bits - 1 DOWNTO 0); + VARIABLE i, j, k : INTEGER; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : BIT_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := TO_INTEGER(Col); + Col_int := Col_int + 1; + TO_BITVECTOR (Col_int, Col_temp); + ELSIF Mode_reg (3) = '1' THEN + TO_BITVECTOR (Burst_counter, Col_vec); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk; + IF Sys_clk'EVENT AND Sys_clk = '1' AND Load = '0' AND Unload = '0' THEN + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Dqm pipeline for Read + Dqm_reg(0) := Dqm_reg(1); + Dqm_reg(1) := TO_BIT(Dqm); + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Precharge Timer for tWR + IF (Burst_Length_1 = '1' OR Write_Burst_Mode = '1') THEN + IF (Count_Precharge(0) = 1) THEN + Count_time(0) := NOW; + END IF; + IF (Count_Precharge(1) = 1) THEN + Count_time(1) := NOW; + END IF; + IF (Count_Precharge(2) = 1) THEN + Count_time(2) := NOW; + END IF; + IF (Count_Precharge(3) = 1) THEN + Count_time(3) := NOW; + END IF; + ELSIF (Burst_Length_2 = '1') THEN + IF (Count_Precharge(0) = 2) THEN + Count_time(0) := NOW; + END IF; + IF (Count_Precharge(1) = 2) THEN + Count_time(1) := NOW; + END IF; + IF (Count_Precharge(2) = 2) THEN + Count_time(2) := NOW; + END IF; + IF (Count_Precharge(3) = 2) THEN + Count_time(3) := NOW; + END IF; + ELSIF (Burst_Length_4 = '1') THEN + IF (Count_Precharge(0) = 4) THEN + Count_time(0) := NOW; + END IF; + IF (Count_Precharge(1) = 4) THEN + Count_time(1) := NOW; + END IF; + IF (Count_Precharge(2) = 4) THEN + Count_time(2) := NOW; + END IF; + IF (Count_Precharge(3) = 4) THEN + Count_time(3) := NOW; + END IF; + ELSIF (Burst_Length_8 = '1') THEN + IF (Count_Precharge(0) = 8) THEN + Count_time(0) := NOW; + END IF; + IF (Count_Precharge(1) = 8) THEN + Count_time(1) := NOW; + END IF; + IF (Count_Precharge(2) = 8) THEN + Count_time(2) := NOW; + END IF; + IF (Count_Precharge(3) = 8) THEN + Count_time(3) := NOW; + END IF; + END IF; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) := WR_counter(0) + 1; + WR_counter(1) := WR_counter(1) + 1; + WR_counter(2) := WR_counter(2) + 1; + WR_counter(3) := WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= TO_BITVECTOR (Addr); + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := TO_BITVECTOR (Addr); + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := TO_BITVECTOR (Addr); + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := TO_BITVECTOR (Addr); + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := TO_BITVECTOR (Addr); + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := TO_BITVECTOR (Ba); + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR + (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := TO_BITVECTOR (Ba); + A10_precharge(2) := TO_BIT(Addr(10)); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := TO_BITVECTOR (Ba); + A10_precharge(1) := TO_BIT(Addr(10)); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (2) := TO_BITVECTOR (Ba); + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (1) := TO_BITVECTOR (Ba); + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); + Bank_addr (0) := TO_BITVECTOR (Ba); + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Interrupt a Write with Auto Precharge + IF Auto_precharge(TO_INTEGER (RW_interrupt_bank)) = '1' AND Write_precharge(TO_INTEGER (RW_interrupt_bank)) = '1' THEN + RW_interrupt_write(TO_INTEGER (RW_interrupt_bank)) := '1'; + WR_time(TO_INTEGER (RW_interrupt_bank)) := NOW; + END IF; + + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(TO_INTEGER (RW_interrupt_bank)) = '1' AND Read_precharge(TO_INTEGER (RW_interrupt_bank)) = '1' THEN + RW_interrupt_read(TO_INTEGER (RW_interrupt_bank)) := '1'; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (TO_INTEGER(Ba)) := '1'; + Count_precharge (TO_INTEGER(Ba)) := 0; + RW_interrupt_bank := TO_BITVECTOR(Ba); + IF Read_enable = '1' THEN + Read_precharge (TO_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (TO_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + IF Data_out_enable = '0' THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := TO_INTEGER (Row); + Col_index := TO_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm = '0' THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Bank0 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "01" THEN + Bank1 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "10" THEN + Bank2 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + ELSIF Bank = "11" THEN + Bank3 (Row_index) (Col_index) := TO_BITVECTOR(Dq); + END IF; + WR_chkp(TO_INTEGER(Bank)) := NOW; + WR_counter(TO_INTEGER(Bank)) := 0; + END IF; + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg(0) = '0' THEN + Init_mem (Bank, Row_index); + IF Bank = "00" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank0 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "01" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank1 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "10" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank2 (Row_index) (Col_index)) AFTER tAC; + ELSIF Bank = "11" THEN + Dq <= TRANSPORT TO_STDLOGICVECTOR(Bank3 (Row_index) (Col_index)) AFTER tAC; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + ELSIF Sys_clk'EVENT AND Sys_clk = '1' AND Load = '1' AND Unload = '0' THEN + Operation <= FILE_LOAD; + WHILE NOT ENDFILE (load_file) LOOP + READLINE (load_file, l_in); + IF l_in'LENGTH > 0 THEN + read (l_in, row_load, 16); -- Load from HEX to INTEGER + read (l_in, col_load, 16); -- Load from HEX to INTEGER + read (l_in, ba_load); + read (l_in, dq_load, 16); -- Load from HEX to INTEGER + + TO_BITVECTOR (dq_load, dq_vec); + + IF ba_load = "00" THEN + IF Bank0(row_load) = NULL THEN --initialize new memory block + Bank0(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank0(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank0(row_load)(col_load) := dq_vec; + ELSIF ba_load = "01" THEN + IF Bank1(row_load) = NULL THEN --initialize new memory block + Bank1(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank1(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank1(row_load)(col_load) := dq_vec; + ELSIF ba_load = "10" THEN + IF Bank2(row_load) = NULL THEN --initialize new memory block + Bank2(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank2(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank2(row_load)(col_load) := dq_vec; + ELSIF ba_load = "11" THEN + IF Bank3(row_load) = NULL THEN --initialize new memory block + Bank3(row_load) := new ram_type; + FOR i IN (2**(col_bits))-1 DOWNTO 0 LOOP + FOR k IN data_bits - 1 DOWNTO 0 LOOP + Bank3(row_load) (i) (k) := '0'; + END LOOP; + END LOOP; + END IF; + Bank3(row_load)(col_load) := dq_vec; + END IF; + END IF; + END LOOP; + + ELSIF Sys_clk'EVENT AND Sys_clk = '1' AND Load = '0' AND Unload = '1' THEN + Operation <= FILE_UNLOAD; + ASSERT (Row_start < 2**(Addr'HIGH + 1)) + REPORT "Row_start is out of range for device" + SEVERITY ERROR; + ASSERT (Row_end < 2**(Addr'HIGH + 1)) + REPORT "Row_end is out of range for device" + SEVERITY ERROR; + ASSERT ((Row_end - Row_start) >= 0) + REPORT "The Row ranges for Unload is invalid!" + SEVERITY ERROR; + IF ((Row_end - Row_start) >= 0) THEN + FOR i IN Row_start TO Row_end LOOP + j := 1; + IF (Ba = "00") THEN -- Unload Bank 0 + WRITE (l_out0, STRING'("Micron Technology Inc. - Unload Data Array - Bank 0 Row ")); + WRITE (l_out0, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file0, l_out0); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP -- Display Row and Column + IF (j = 1) THEN + WRITE (l_out0, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out0, STRING'(" : ")); + WRITE (l_out0, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out0, STRING'(" : ")); + END IF; + + IF (Bank0 (i) = NULL) THEN -- Row is empty, write message and exit + WRITE (l_out0, STRING'(" Row ")); + WRITE (l_out0, i); + WRITE (l_out0, STRING'(" is empty.")); + WRITELINE (out_file0, l_out0); + EXIT; + ELSE -- Buffering + array_buffer := Bank0 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); -- Convert to STD_LOGIC_VECTOR + WRITE (l_out0, write_data_var, RIGHT, 3, HEX, FALSE); -- Write message + IF (j = 16) then + WRITELINE (out_file0, l_out0); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "01") THEN + WRITE (l_out1, STRING'("Micron Technology Inc. - Unload Data Array - Bank 1 Row ")); + WRITE (l_out1, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file1, l_out1); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out1, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out1, STRING'(" : ")); + WRITE (l_out1, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out1, STRING'(" : ")); + END IF; + + IF (Bank1 (i) = NULL) THEN + WRITE (l_out1, STRING'(" Row ")); + WRITE (l_out1, i); + WRITE (l_out1, STRING'(" is empty.")); + WRITELINE (out_file1, l_out1); + EXIT; + ELSE + array_buffer := Bank1 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out1, write_data_var, RIGHT, 3, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file1, l_out1); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "10") THEN + WRITE (l_out2, STRING'("Micron Technology Inc. - Unload Data Array - Bank 2 Row ")); + WRITE (l_out2, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file2, l_out2); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out2, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out2, STRING'(" : ")); + WRITE (l_out2, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out2, STRING'(" : ")); + END IF; + + IF (Bank2 (i) = NULL) THEN + WRITE (l_out2, STRING'(" Row ")); + WRITE (l_out2, i); + WRITE (l_out2, STRING'(" is empty.")); + WRITELINE (out_file2, l_out2); + EXIT; + ELSE + array_buffer := Bank2 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out2, write_data_var, RIGHT, 3, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file2, l_out2); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + ELSIF (Ba = "11") THEN + WRITE (l_out3, STRING'("Micron Technology Inc. - Unload Data Array - Bank 3 Row ")); + WRITE (l_out3, i, RIGHT, 3, HEX, FALSE); + WRITELINE (out_file3, l_out3); + FOR k IN 0 TO ((2**Col_bits) - 1) LOOP + IF (j = 1) THEN + WRITE (l_out3, i, RIGHT, 3, HEX, FALSE); + WRITE (l_out3, STRING'(" : ")); + WRITE (l_out3, k, RIGHT, 3, HEX, FALSE); + WRITE (l_out3, STRING'(" : ")); + END IF; + + IF (Bank3 (i) = NULL) THEN + WRITE (l_out3, STRING'(" Row ")); + WRITE (l_out3, i); + WRITE (l_out3, STRING'(" is empty.")); + WRITELINE (out_file3, l_out3); + EXIT; + ELSE + array_buffer := Bank3 (i) (k); + END IF; + + write_data_var := TO_STDLOGICVECTOR(array_buffer); + WRITE (l_out3, write_data_var, RIGHT, 3, HEX, FALSE); + IF (j = 16) then + WRITELINE (out_file3, l_out3); + j := 1; + ELSE + j := j + 1; + END IF; + END LOOP; + END IF; + END LOOP; + END IF; + + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 2)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + WAIT FOR tWRa; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 2)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + WAIT FOR tWRa; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 2)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + WAIT FOR tWRa; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_write(3) = '1' AND WR_counter(3) >= 2)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + WAIT FOR tWRa; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + + -- Checking internal wires (Optional for debug purpose) + Pre_chk (0) <= Pc_b0; + Pre_chk (1) <= Pc_b1; + Pre_chk (2) <= Pc_b2; + Pre_chk (3) <= Pc_b3; + Act_chk (0) <= Act_b0; + Act_chk (1) <= Act_b1; + Act_chk (2) <= Act_b2; + Act_chk (3) <= Act_b3; + Dq_in_chk <= Data_in_enable; + Dq_out_chk <= Data_out_enable; + Bank_chk <= Bank; + Row_chk <= Row; + Col_chk <= Col; + END PROCESS; + + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "Dq Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48lc8m8a2/mti_pkg.vhd b/lib/models/memory/sdram/mt48lc8m8a2/mti_pkg.vhd new file mode 100644 index 0000000..9e4f824 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/mti_pkg.vhd @@ -0,0 +1,129 @@ +--***************************************************************************** +-- +-- Micron Semiconductor Products, Inc. +-- +-- Copyright 1997, Micron Semiconductor Products, Inc. +-- All rights reserved. +-- +--***************************************************************************** + +LIBRARY work; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; + +PACKAGE mti_pkg IS + + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); + +END mti_pkg; + +PACKAGE BODY mti_pkg IS + + -- Convert BIT to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + IF input = '1' THEN + result := weight; + ELSE + result := 0; -- if unknowns, default to logic 0 + END IF; + RETURN result; + END TO_INTEGER; + + -- Convert BIT_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Convert STD_LOGIC_VECTOR to INTEGER + FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS + VARIABLE result : INTEGER := 0; + VARIABLE weight : INTEGER := 1; + BEGIN + FOR i IN input'LOW TO input'HIGH LOOP + IF input(i) = '1' THEN + result := result + weight; + ELSE + result := result + 0; -- if unknowns, default to logic 0 + END IF; + weight := weight * 2; + END LOOP; + RETURN result; + END TO_INTEGER; + + -- Conver integer to bit_vector + PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS + VARIABLE work,offset,outputlen,j : INTEGER := 0; + BEGIN + --length of vector + IF output'LENGTH > 32 THEN + outputlen := 32; + offset := output'LENGTH - 32; + IF input >= 0 THEN + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '0'; + END LOOP; + ELSE + FOR i IN offset-1 DOWNTO 0 LOOP + output(output'HIGH - i) := '1'; + END LOOP; + END IF; + ELSE + outputlen := output'LENGTH; + END IF; + --positive value + IF (input >= 0) THEN + work := input; + j := outputlen - 1; + FOR i IN 1 to 32 LOOP + IF j >= 0 then + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '0'; + ELSE + output(output'HIGH-j-offset) := '1'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '0'; + END IF; + --negative value + ELSE + work := (-input) - 1; + j := outputlen - 1; + FOR i IN 1 TO 32 LOOP + IF j>= 0 THEN + IF (work MOD 2) = 0 THEN + output(output'HIGH-j-offset) := '1'; + ELSE + output(output'HIGH-j-offset) := '0'; + END IF; + END IF; + work := work / 2; + j := j - 1; + END LOOP; + IF outputlen = 32 THEN + output(output'HIGH) := '1'; + END IF; + END IF; + END TO_BITVECTOR; + +END mti_pkg; diff --git a/lib/models/memory/sdram/mt48lc8m8a2/outdata0.txt b/lib/models/memory/sdram/mt48lc8m8a2/outdata0.txt new file mode 100644 index 0000000..fe40f95 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/outdata0.txt @@ -0,0 +1,35 @@ +Micron Technology Inc. - Unload Data Array - Bank 0 Row 0 + 0 : 0 : 0A 0B 02 03 04 05 06 07 08 09 00 00 00 00 00 00 + 0 : 10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 100 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 110 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 120 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 130 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 140 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 150 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 160 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 170 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 180 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 190 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Micron Technology Inc. - Unload Data Array - Bank 0 Row 1 + 1 : 0 : Row 1 is empty. diff --git a/lib/models/memory/sdram/mt48lc8m8a2/outdata1.txt b/lib/models/memory/sdram/mt48lc8m8a2/outdata1.txt new file mode 100644 index 0000000..ae9d17a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/outdata1.txt @@ -0,0 +1,35 @@ +Micron Technology Inc. - Unload Data Array - Bank 1 Row 0 + 0 : 0 : 14 15 12 13 14 15 16 17 18 19 00 00 00 00 00 00 + 0 : 10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 100 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 110 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 120 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 130 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 140 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 150 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 160 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 170 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 180 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 190 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Micron Technology Inc. - Unload Data Array - Bank 1 Row 1 + 1 : 0 : Row 1 is empty. diff --git a/lib/models/memory/sdram/mt48lc8m8a2/outdata2.txt b/lib/models/memory/sdram/mt48lc8m8a2/outdata2.txt new file mode 100644 index 0000000..d67f6e4 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/outdata2.txt @@ -0,0 +1,35 @@ +Micron Technology Inc. - Unload Data Array - Bank 2 Row 0 + 0 : 0 : 1E 1F 22 23 24 25 26 27 28 29 00 00 00 00 00 00 + 0 : 10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 100 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 110 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 120 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 130 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 140 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 150 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 160 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 170 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 180 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 190 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Micron Technology Inc. - Unload Data Array - Bank 2 Row 1 + 1 : 0 : Row 1 is empty. diff --git a/lib/models/memory/sdram/mt48lc8m8a2/outdata3.txt b/lib/models/memory/sdram/mt48lc8m8a2/outdata3.txt new file mode 100644 index 0000000..1d4e144 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/outdata3.txt @@ -0,0 +1,35 @@ +Micron Technology Inc. - Unload Data Array - Bank 3 Row 0 + 0 : 0 : 28 29 32 33 34 35 36 37 38 39 00 00 00 00 00 00 + 0 : 10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 100 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 110 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 120 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 130 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 140 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 150 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 160 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 170 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 180 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 190 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 0 : 1F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +Micron Technology Inc. - Unload Data Array - Bank 3 Row 1 + 1 : 0 : Row 1 is empty. diff --git a/lib/models/memory/sdram/mt48lc8m8a2/readme.txt b/lib/models/memory/sdram/mt48lc8m8a2/readme.txt new file mode 100644 index 0000000..c594a7e --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/readme.txt @@ -0,0 +1,14 @@ +To operate the test bench for the Micron SDRAM VHDL model, follow the directions +given below: + +1. Be sure all supporting files for the SDRAM are compiled into your library: + + util1164.vhd + stdlogar.vhd + io_utils.vhd + mti_pkg.vhd + +2. Next, compile the mt48lc8m8a2.vhd file and the test.vhd file. + +3. Simulate the "tb" architecture. This is the testbench for the 64Mb SDRAM. + diff --git a/lib/models/memory/sdram/mt48lc8m8a2/stdlogar.vhd b/lib/models/memory/sdram/mt48lc8m8a2/stdlogar.vhd new file mode 100644 index 0000000..e435ea2 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/stdlogar.vhd @@ -0,0 +1,2247 @@ +-------------------------------------------------------------------------- +-- -- +-- Copyright (c) 1990,1991,1992 by Synopsys, Inc. All rights reserved. -- +-- -- +-- This source file may be used and distributed without restriction -- +-- provided that this copyright statement is not removed from the file -- +-- and that any derivative work contains this copyright notice. -- +-- -- +-- Package name: STD_LOGIC_ARITH -- +-- -- +-- Purpose: -- +-- A set of arithemtic, conversion, and comparison functions -- +-- for SIGNED, UNSIGNED, SMALL_INT, INTEGER, -- +-- STD_ULOGIC, STD_LOGIC, and STD_LOGIC_VECTOR. -- +-- -- +-------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; + +package std_logic_arith is + + type UNSIGNED is array (NATURAL range <>) of STD_LOGIC; + type SIGNED is array (NATURAL range <>) of STD_LOGIC; + subtype SMALL_INT is INTEGER range 0 to 1; + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: INTEGER) return SIGNED; + function "+"(L: INTEGER; R: SIGNED) return SIGNED; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED; + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED; + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: INTEGER) return SIGNED; + function "-"(L: INTEGER; R: SIGNED) return SIGNED; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED; + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED; + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED; + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR; + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR; + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR; + + function "+"(L: UNSIGNED) return UNSIGNED; + function "+"(L: SIGNED) return SIGNED; + function "-"(L: SIGNED) return SIGNED; + function "ABS"(L: SIGNED) return SIGNED; + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR; + function "+"(L: SIGNED) return STD_LOGIC_VECTOR; + function "-"(L: SIGNED) return STD_LOGIC_VECTOR; + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED; + function "*"(L: SIGNED; R: SIGNED) return SIGNED; + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED; + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR; + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR; + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN; + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN; + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN; + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN; + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN; + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN; + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED; + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED; + + function CONV_INTEGER(ARG: INTEGER) return INTEGER; + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER; + function CONV_INTEGER(ARG: SIGNED) return INTEGER; + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT; + + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED; + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED; + + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED; + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED; + + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) + return STD_LOGIC_VECTOR; + -- zero extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- returns STD_LOGIC_VECTOR(SIZE-1 downto 0) + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + + -- sign extend STD_LOGIC_VECTOR (ARG) to SIZE, + -- SIZE < 0 is same as SIZE = 0 + -- return STD_LOGIC_VECTOR(SIZE-1 downto 0) + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR; + +end Std_logic_arith; + + + +library IEEE; +use IEEE.std_logic_1164.all; + +package body std_logic_arith is + + function max(L, R: INTEGER) return INTEGER is + begin + if L > R then + return L; + else + return R; + end if; + end; + + + function min(L, R: INTEGER) return INTEGER is + begin + if L < R then + return L; + else + return R; + end if; + end; + + -- synopsys synthesis_off + type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; + constant tbl_BINARY : tbl_type := + ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); + -- synopsys synthesis_on + + -- synopsys synthesis_off + type tbl_mvl9_boolean is array (STD_ULOGIC) of boolean; + constant IS_X : tbl_mvl9_boolean := + (true, true, false, false, true, true, false, false, true); + -- synopsys synthesis_on + + + + function MAKE_BINARY(A : STD_ULOGIC) return STD_ULOGIC is + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + if (IS_X(A)) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + return ('X'); + end if; + return tbl_BINARY(A); + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return UNSIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : UNSIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return SIGNED is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : SIGNED (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : STD_LOGIC_VECTOR) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + function MAKE_BINARY(A : SIGNED) return STD_LOGIC_VECTOR is + -- synopsys built_in SYN_FEED_THRU + variable one_bit : STD_ULOGIC; + variable result : STD_LOGIC_VECTOR (A'range); + begin + -- synopsys synthesis_off + for i in A'range loop + if (IS_X(A(i))) then + assert false + report "There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)." + severity warning; + result := (others => 'X'); + return result; + end if; + result(i) := tbl_BINARY(A(i)); + end loop; + return result; + -- synopsys synthesis_on + end; + + + + -- Type propagation function which returns a signed type with the + -- size of the left arg. + function LEFT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the left arg. + function LEFT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED (A'left downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns a signed type with the + -- size of the result of a signed multiplication + function MULT_SIGNED_ARG(A,B: SIGNED) return SIGNED is + variable Z: SIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns an unsigned type with the + -- size of the result of a unsigned multiplication + function MULT_UNSIGNED_ARG(A,B: UNSIGNED) return UNSIGNED is + variable Z: UNSIGNED ((A'length+B'length-1) downto 0); + -- pragma return_port_name Z + begin + return(Z); + end; + + + + function mult(A,B: SIGNED) return SIGNED is + + variable BA: SIGNED((A'length+B'length-1) downto 0); + variable PA: SIGNED((A'length+B'length-1) downto 0); + variable AA: SIGNED(A'length downto 0); + variable neg: STD_ULOGIC; + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_TC_OP + -- pragma type_function MULT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + neg := B(B'left) xor A(A'left); + BA := CONV_SIGNED(('0' & ABS(B)),(A'length+B'length)); + AA := '0' & ABS(A); + for i in 0 to A'length-1 loop + if AA(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + if (neg= '1') then + return(-PA); + else + return(PA); + end if; + end; + + function mult(A,B: UNSIGNED) return UNSIGNED is + + variable BA: UNSIGNED((A'length+B'length-1) downto 0); + variable PA: UNSIGNED((A'length+B'length-1) downto 0); + constant one : UNSIGNED(1 downto 0) := "01"; + + -- pragma map_to_operator MULT_UNS_OP + -- pragma type_function MULT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + PA := (others => 'X'); + return(PA); + end if; + PA := (others => '0'); + BA := CONV_UNSIGNED(B,(A'length+B'length)); + for i in 0 to A'length-1 loop + if A(i) = '1' then + PA := PA+BA; + end if; + BA := SHL(BA,one); + end loop; + return(PA); + end; + + -- subtract two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function minus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_TC_OP + + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function plus(A, B: SIGNED) return SIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: SIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_TC_OP + -- pragma type_function LEFT_SIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + -- subtract two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_minus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV: STD_ULOGIC_VECTOR (A'left downto 0); + variable sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator SUB_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '1'; + BV := not STD_ULOGIC_VECTOR(B); + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + -- add two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_plus(A, B: UNSIGNED) return UNSIGNED is + variable carry: STD_ULOGIC; + variable BV, sum: UNSIGNED (A'left downto 0); + + -- pragma map_to_operator ADD_UNS_OP + -- pragma type_function LEFT_UNSIGNED_ARG + -- pragma return_port_name Z + + begin + if (A(A'left) = 'X' or B(B'left) = 'X') then + sum := (others => 'X'); + return(sum); + end if; + carry := '0'; + BV := B; + + for i in 0 to A'left loop + sum(i) := A(i) xor BV(i) xor carry; + carry := (A(i) and BV(i)) or + (A(i) and carry) or + (carry and BV(i)); + end loop; + return sum; + end; + + + + function "*"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to mult + begin + return mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length)); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + begin + return mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1)); -- pragma label mult + end; + + + function "*"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to mult + begin + return STD_LOGIC_VECTOR (mult(CONV_UNSIGNED(L, L'length), + CONV_UNSIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length+1), + CONV_SIGNED(R, R'length))); -- pragma label mult + end; + + function "*"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + begin + return STD_LOGIC_VECTOR (mult(CONV_SIGNED(L, L'length), + CONV_SIGNED(R, R'length+1))); -- pragma label mult + end; + + + function "+"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "+"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label plus + end; + + + + function "+"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + plus( -- pragma label plus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "+"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))) ; -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (unsigned_plus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + function "+"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to plus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (plus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label plus + end; + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: INTEGER) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return UNSIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return SIGNED is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label minus + end; + + + + + function "-"(L: UNSIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (unsigned_minus(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length + 1, R'length); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: SIGNED; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := max(L'length, R'length + 1); + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: INTEGER; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: INTEGER) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: INTEGER; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: UNSIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: STD_ULOGIC; R: UNSIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length + 1; + begin + return STD_LOGIC_VECTOR (CONV_UNSIGNED( + minus( -- pragma label minus + CONV_SIGNED(L, length), + CONV_SIGNED(R, length)), + length-1)); + end; + + + function "-"(L: SIGNED; R: STD_ULOGIC) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := L'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + function "-"(L: STD_ULOGIC; R: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + constant length: INTEGER := R'length; + begin + return STD_LOGIC_VECTOR (minus(CONV_SIGNED(L, length), + CONV_SIGNED(R, length))); -- pragma label minus + end; + + + + + function "+"(L: UNSIGNED) return UNSIGNED is + begin + return L; + end; + + + function "+"(L: SIGNED) return SIGNED is + begin + return L; + end; + + + function "-"(L: SIGNED) return SIGNED is + -- pragma label_applies_to minus + begin + return 0 - L; -- pragma label minus + end; + + + function "ABS"(L: SIGNED) return SIGNED is + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return L; + else + return 0 - L; + end if; + end; + + + function "+"(L: UNSIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "+"(L: SIGNED) return STD_LOGIC_VECTOR is + begin + return STD_LOGIC_VECTOR (L); + end; + + + function "-"(L: SIGNED) return STD_LOGIC_VECTOR is + -- pragma label_applies_to minus + variable tmp: SIGNED(L'length-1 downto 0); + begin + tmp := 0 - L; -- pragma label minus + return STD_LOGIC_VECTOR (tmp); + end; + + + function "ABS"(L: SIGNED) return STD_LOGIC_VECTOR is + variable tmp: SIGNED(L'length-1 downto 0); + begin + if (L(L'left) = '0' or L(L'left) = 'L') then + return STD_LOGIC_VECTOR (L); + else + tmp := 0 - L; + return STD_LOGIC_VECTOR (tmp); + end if; + end; + + + -- Type propagation function which returns the type BOOLEAN + function UNSIGNED_RETURN_BOOLEAN(A,B: UNSIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + -- Type propagation function which returns the type BOOLEAN + function SIGNED_RETURN_BOOLEAN(A,B: SIGNED) return BOOLEAN is + variable Z: BOOLEAN; + -- pragma return_port_name Z + begin + return(Z); + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := FALSE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + -- compare two signed numbers of the same length + -- both arrays must have range (msb downto 0) + function is_less_or_equal(A, B: SIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_TC_OP + -- pragma type_function SIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + if A(sign) /= B(sign) then + result := A(sign) = '1'; + else + result := TRUE; + for i in 0 to sign-1 loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + end if; + return result; + end; + + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LT_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := FALSE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + -- compare two unsigned numbers of the same length + -- both arrays must have range (msb downto 0) + function unsigned_is_less_or_equal(A, B: UNSIGNED) return BOOLEAN is + constant sign: INTEGER := A'left; + variable a_is_0, b_is_1, result : boolean; + + -- pragma map_to_operator LEQ_UNS_OP + -- pragma type_function UNSIGNED_RETURN_BOOLEAN + -- pragma return_port_name Z + + begin + result := TRUE; + for i in 0 to sign loop + a_is_0 := A(i) = '0'; + b_is_1 := B(i) = '1'; + result := (a_is_0 and b_is_1) or + (a_is_0 and result) or + (b_is_1 and result); + end loop; + return result; + end; + + + + + function "<"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + function "<"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to lt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label lt + end; + + + + + function "<="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(L, length), + CONV_UNSIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + function "<="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to leq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(L, length), + CONV_SIGNED(R, length)); -- pragma label leq + end; + + + + + function ">"(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length + 1; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := L'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + function ">"(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to gt + constant length: INTEGER := R'length; + begin + return is_less(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label gt + end; + + + + + function ">="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return unsigned_is_less_or_equal(CONV_UNSIGNED(R, length), + CONV_UNSIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length + 1, R'length); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := max(L'length, R'length + 1); + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length + 1; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: SIGNED; R: INTEGER) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := L'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + function ">="(L: INTEGER; R: SIGNED) return BOOLEAN is + -- pragma label_applies_to geq + constant length: INTEGER := R'length; + begin + return is_less_or_equal(CONV_SIGNED(R, length), + CONV_SIGNED(L, length)); -- pragma label geq + end; + + + + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_eql(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_EQL + begin + for i in L'range loop + if L(i) /= R(i) then + return FALSE; + end if; + end loop; + return TRUE; + end; + + -- for internal use only. Assumes SIGNED arguments of equal length. + function bitwise_neq(L: STD_ULOGIC_VECTOR; R: STD_ULOGIC_VECTOR) + return BOOLEAN is + -- pragma built_in SYN_NEQ + begin + for i in L'range loop + if L(i) /= R(i) then + return TRUE; + end if; + end loop; + return FALSE; + end; + + + function "="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_eql( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + + function "/="(L: UNSIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_UNSIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_UNSIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: SIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length + 1, R'length); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := max(L'length, R'length + 1); + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: UNSIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: UNSIGNED) return BOOLEAN is + constant length: INTEGER := R'length + 1; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: SIGNED; R: INTEGER) return BOOLEAN is + constant length: INTEGER := L'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + function "/="(L: INTEGER; R: SIGNED) return BOOLEAN is + constant length: INTEGER := R'length; + begin + return bitwise_neq( STD_ULOGIC_VECTOR( CONV_SIGNED(L, length) ), + STD_ULOGIC_VECTOR( CONV_SIGNED(R, length) ) ); + end; + + + + function SHL(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHL(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb downto 2**i) := + result(result_msb - 2**i downto 0); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + function SHR(ARG: UNSIGNED; COUNT: UNSIGNED) return UNSIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is UNSIGNED (result_msb downto 0); + variable result, temp: rtype; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => '0'); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + function SHR(ARG: SIGNED; COUNT: UNSIGNED) return SIGNED is + constant control_msb: INTEGER := COUNT'length - 1; + variable control: UNSIGNED (control_msb downto 0); + constant result_msb: INTEGER := ARG'length-1; + subtype rtype is SIGNED (result_msb downto 0); + variable result, temp: rtype; + variable sign_bit: STD_ULOGIC; + begin + control := MAKE_BINARY(COUNT); + if (control(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := ARG; + sign_bit := ARG(ARG'left); + for i in 0 to control_msb loop + if control(i) = '1' then + temp := rtype'(others => sign_bit); + if 2**i <= result_msb then + temp(result_msb - 2**i downto 0) := + result(result_msb downto 2**i); + end if; + result := temp; + end if; + end loop; + return result; + end; + + + + + function CONV_INTEGER(ARG: INTEGER) return INTEGER is + begin + return ARG; + end; + + function CONV_INTEGER(ARG: UNSIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_UNSIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 31 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: SIGNED) return INTEGER is + variable result: INTEGER; + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_SIGNED_TO_INTEGER + begin + -- synopsys synthesis_off + assert ARG'length <= 32 + report "ARG is too large in CONV_INTEGER" + severity FAILURE; + result := 0; + for i in ARG'range loop + if i /= ARG'left then + result := result * 2; + tmp := tbl_BINARY(ARG(i)); + if tmp = '1' then + result := result + 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + end if; + end if; + end loop; + tmp := MAKE_BINARY(ARG(ARG'left)); + if tmp = '1' then + if ARG'length = 32 then + result := (result - 2**30) - 2**30; + else + result := result - (2 ** (ARG'length-1)); + end if; + end if; + return result; + -- synopsys synthesis_on + end; + + + function CONV_INTEGER(ARG: STD_ULOGIC) return SMALL_INT is + variable tmp: STD_ULOGIC; + -- synopsys built_in SYN_FEED_THRU + begin + -- synopsys synthesis_off + tmp := tbl_BINARY(ARG); + if tmp = '1' then + return 1; + elsif tmp = 'X' then + assert false + report "CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0." + severity WARNING; + return 0; + else + return 0; + end if; + -- synopsys synthesis_on + end; + + + -- convert an integer to a unsigned STD_ULOGIC_VECTOR + function CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) return UNSIGNED is + variable result: UNSIGNED(SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_UNSIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: UNSIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: SIGNED; SIZE: INTEGER) return UNSIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable new_bounds: UNSIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_UNSIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return UNSIGNED is + subtype rtype is UNSIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to a 2's complement STD_ULOGIC_VECTOR + function CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) return SIGNED is + variable result: SIGNED (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: UNSIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_SIGNED(ARG: SIGNED; SIZE: INTEGER) return SIGNED is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is SIGNED (SIZE-1 downto 0); + variable new_bounds : SIGNED (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_SIGNED(ARG: STD_ULOGIC; SIZE: INTEGER) return SIGNED is + subtype rtype is SIGNED (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + + -- convert an integer to an STD_LOGIC_VECTOR + function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is + variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable temp: integer; + -- synopsys built_in SYN_INTEGER_TO_SIGNED + begin + -- synopsys synthesis_off + temp := ARG; + for i in 0 to SIZE-1 loop + if (temp mod 2) = 1 then + result(i) := '1'; + else + result(i) := '0'; + end if; + if temp > 0 then + temp := temp / 2; + else + temp := (temp - 1) / 2; -- simulate ASR + end if; + end loop; + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: UNSIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + function CONV_STD_LOGIC_VECTOR(ARG: SIGNED; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function CONV_STD_LOGIC_VECTOR(ARG: STD_ULOGIC; SIZE: INTEGER) return STD_LOGIC_VECTOR is + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + result := rtype'(others => '0'); + result(0) := MAKE_BINARY(ARG); + if (result(0) = 'X') then + result := rtype'(others => 'X'); + end if; + return result; + -- synopsys synthesis_on + end; + + function EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) + return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds: STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_ZERO_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => '0'); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + + function SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) return STD_LOGIC_VECTOR is + constant msb: INTEGER := min(ARG'length, SIZE) - 1; + subtype rtype is STD_LOGIC_VECTOR (SIZE-1 downto 0); + variable new_bounds : STD_LOGIC_VECTOR (ARG'length-1 downto 0); + variable result: rtype; + -- synopsys built_in SYN_SIGN_EXTEND + begin + -- synopsys synthesis_off + new_bounds := MAKE_BINARY(ARG); + if (new_bounds(0) = 'X') then + result := rtype'(others => 'X'); + return result; + end if; + result := rtype'(others => new_bounds(new_bounds'left)); + result(msb downto 0) := new_bounds(msb downto 0); + return result; + -- synopsys synthesis_on + end; + + +end std_logic_arith; diff --git a/lib/models/memory/sdram/mt48lc8m8a2/test.do b/lib/models/memory/sdram/mt48lc8m8a2/test.do new file mode 100644 index 0000000..ea4831f --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/test.do @@ -0,0 +1,5 @@ +vcom mt48lc8m8a2.vhd +vcom test.vhd +vsim tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48lc8m8a2/test.txt b/lib/models/memory/sdram/mt48lc8m8a2/test.txt new file mode 100644 index 0000000..9f8367a --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/test.txt @@ -0,0 +1,103 @@ +0 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +22 ns 1 0 1 1 1 0 00 0 -100 1 0 0 0 +32 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +42 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +52 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +62 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +72 ns 1 0 0 1 0 0 00 1024 -100 0 0 0 0 +82 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +92 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +102 ns 1 0 0 0 1 0 00 0 -100 0 0 0 0 +112 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +122 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +132 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +142 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +152 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +162 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +172 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +182 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +192 ns 1 0 0 0 1 0 00 0 -100 0 0 0 0 +202 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +212 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +222 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +232 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +242 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +252 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +262 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +272 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +282 ns 1 0 0 0 0 0 00 49 -100 0 0 0 0 +292 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +302 ns 1 0 0 1 1 0 00 0 -100 0 0 0 0 +312 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +322 ns 1 0 1 0 0 0 00 1024 10 0 0 0 0 +332 ns 1 0 1 1 1 0 00 0 11 0 0 0 0 +342 ns 1 0 0 1 1 0 01 0 12 0 0 0 0 +352 ns 1 0 1 1 1 0 00 0 13 0 0 0 0 +362 ns 1 0 1 1 1 0 00 0 14 0 0 0 0 +372 ns 1 0 1 1 1 0 00 0 15 0 0 0 0 +382 ns 1 0 1 1 1 0 00 0 16 0 0 0 0 +392 ns 1 0 1 1 1 0 00 0 17 0 0 0 0 +402 ns 1 0 1 0 0 0 01 1024 20 0 0 0 0 +412 ns 1 0 1 1 1 0 00 0 21 0 0 0 0 +422 ns 1 0 0 1 1 0 10 0 22 0 0 0 0 +432 ns 1 0 1 1 1 0 00 0 23 0 0 0 0 +442 ns 1 0 1 1 1 0 00 0 24 0 0 0 0 +452 ns 1 0 1 1 1 0 00 0 25 0 0 0 0 +462 ns 1 0 1 1 1 0 00 0 26 0 0 0 0 +472 ns 1 0 1 1 1 0 00 0 27 0 0 0 0 +482 ns 1 0 1 0 0 0 10 1024 30 0 0 0 0 +492 ns 1 0 1 1 1 0 00 0 31 0 0 0 0 +502 ns 1 0 0 1 1 0 11 0 32 0 0 0 0 +512 ns 1 0 1 1 1 0 00 0 33 0 0 0 0 +522 ns 1 0 1 1 1 0 00 0 34 0 0 0 0 +532 ns 1 0 1 1 1 0 00 0 35 0 0 0 0 +542 ns 1 0 1 1 1 0 00 0 36 0 0 0 0 +552 ns 1 0 1 1 1 0 00 0 37 0 0 0 0 +562 ns 1 0 1 0 0 0 11 1024 40 0 0 0 0 +572 ns 1 0 1 1 1 0 00 0 41 0 0 0 0 +582 ns 1 0 0 1 1 0 00 0 42 0 0 0 0 +592 ns 1 0 1 1 1 0 00 0 43 0 0 0 0 +602 ns 1 0 1 1 1 0 00 0 44 0 0 0 0 +612 ns 1 0 1 1 1 0 00 0 45 0 0 0 0 +622 ns 1 0 1 1 1 0 00 0 46 0 0 0 0 +632 ns 1 0 1 1 1 0 00 0 47 0 0 0 0 +642 ns 1 0 1 0 1 0 00 1024 -100 0 0 0 0 +652 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +662 ns 1 0 0 1 1 0 01 0 -100 0 0 0 0 +672 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +682 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +692 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +702 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +712 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +722 ns 1 0 1 0 1 0 01 1024 -100 0 0 0 0 +732 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +742 ns 1 0 0 1 1 0 10 0 -100 0 0 0 0 +752 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +762 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +772 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +782 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +792 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +802 ns 1 0 1 0 1 0 10 1024 -100 0 0 0 0 +812 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +822 ns 1 0 0 1 1 0 11 0 -100 0 0 0 0 +832 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +842 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +852 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +862 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +872 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +882 ns 1 0 1 0 1 0 11 1024 -100 0 0 0 0 +892 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +902 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +912 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +922 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +932 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +942 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +952 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +962 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +972 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +982 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 +992 ns 1 0 1 1 1 0 00 0 -100 0 1 0 1 +1002 ns 1 0 1 1 1 0 01 0 -100 0 1 0 1 +1012 ns 1 0 1 1 1 0 10 0 -100 0 1 0 1 +1022 ns 1 0 1 1 1 0 11 0 -100 0 1 0 1 +1032 ns 1 0 1 1 1 0 00 0 -100 0 0 0 0 diff --git a/lib/models/memory/sdram/mt48lc8m8a2/test.vhd b/lib/models/memory/sdram/mt48lc8m8a2/test.vhd new file mode 100644 index 0000000..a88b117 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/test.vhd @@ -0,0 +1,196 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE std.textio.ALL; +USE work.std_logic_arith.ALL; +USE work.util_1164.ALL; +USE work.mti_pkg.ALL; + +ENTITY tb IS +END tb; + + +ARCHITECTURE test OF tb IS + CONSTANT addr_bits : INTEGER := 12; + CONSTANT data_bits : INTEGER := 8; + CONSTANT clk_start : time := 5 ns; + CONSTANT clk_period : time := 10 ns; + CONSTANT continue_time : time := 10 ns; + + COMPONENT mt48lc8m8a2 + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC := '0'; + Load : IN STD_LOGIC := '0'; + Unload : IN STD_LOGIC := '0'; + Row_start : IN INTEGER := 0; + Row_end : IN INTEGER := 0 + ); + END COMPONENT; + + FOR ALL : mt48lc8m8a2 USE ENTITY work.mt48lc8m8a2 (behave); + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs : STD_LOGIC; + SIGNAL pCas : STD_LOGIC; + SIGNAL pRas : STD_LOGIC; + SIGNAL pWe : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC; + SIGNAL PLoad : STD_LOGIC; + SIGNAL PUnload : STD_LOGIC; + SIGNAL PRow_start : INTEGER; + SIGNAL PRow_end : INTEGER; + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48lc8m8a2 + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs, + Ras_n => pRas, + Cas_n => pCas, + We_n => pWe, + Dqm => pDqm, + Load => pLoad, + Unload => pUnload, + Row_start => PRow_start, + Row_end => PRow_end + ); + + stimulator : PROCESS + FILE stim_file:text IS IN "test.txt"; + VARIABLE l : line; + VARIABLE time_var : TIME; + VARIABLE pCke_var : STD_LOGIC; + VARIABLE pCs_var : STD_LOGIC; + VARIABLE pRas_var : STD_LOGIC; + VARIABLE PCas_var : STD_LOGIC; + VARIABLE pWe_var : STD_LOGIC; + VARIABLE pDqm_var : STD_LOGIC; + VARIABLE pBa_var : STD_LOGIC_VECTOR (1 DOWNTO 0); + VARIABLE pAddr_var : INTEGER; + VARIABLE pDq_var : INTEGER; -- -100 is converted to hi-Z state + VARIABLE pLoad_var : STD_LOGIC; + VARIABLE pUnload_var : STD_LOGIC; + VARIABLE pRow_start_var : INTEGER; + VARIABLE pRow_end_var : INTEGER; + VARIABLE pMa_var_vect : STD_LOGIC_VECTOR(addr_bits - 1 DOWNTO 0); + CONSTANT HiZ : STD_LOGIC_VECTOR(data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + BEGIN + WHILE not ENDFILE(stim_file) LOOP + readline(stim_file,l); + IF l'length > 0 THEN + read (l, time_var); + read (l, pCke_var); + read (l, pCs_var); + read (l, pRas_var); + read (l, pCas_var); + read (l, pWe_var); + read (l, pDqm_var); + read (l, pBa_var); + read (l, pAddr_var); + read (l, pDq_var); + read (l, pLoad_var); + read (l, pUnload_var); + read (l, pRow_start_var); + read (l, pRow_end_var); + IF now > time_var THEN + ASSERT false + REPORT "Detected a time in the stim file that is in the past" + SEVERITY error; + ELSE + WAIT FOR time_var-now; + IF pWe_var='1' THEN + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= pLoad_var; + pUnload <= pUnload_var; + pRow_start <= pRow_start_var; + pRow_end <= pRow_end_var; + ELSE + pCke <= pCke_var; + pCs <= pCs_var; + pRas <= pRas_var; + pCas <= pCas_var; + pWe <= pWe_var; + pDqm <= pDqm_var; + pBa <= pBa_var; + pMa_var_vect := CONV_STD_LOGIC_VECTOR(pAddr_var, addr_bits); + pAddr <= pMa_var_vect; + IF pDq_var = -100 THEN + pDq <= HiZ; + ELSE + pDq <= CONV_STD_LOGIC_VECTOR(pDq_var, data_bits); + END IF; + pLoad <= pLoad_var; + pUnload <= pUnload_var; + pRow_start <= pRow_start_var; + pRow_end <= pRow_end_var; + END IF; + END IF; + END IF; + END LOOP; + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for clk_start; + WHILE not stim_done loop + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + done_time := now+continue_time; + WHILE now < done_time LOOP --one last clock to finish last command + pclk <= '1'; + WAIT for clk_period/2; + pclk <= '0'; + WAIT for clk_period/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; + +END test; + + diff --git a/lib/models/memory/sdram/mt48lc8m8a2/util1164.vhd b/lib/models/memory/sdram/mt48lc8m8a2/util1164.vhd new file mode 100644 index 0000000..bb4b5dd --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/util1164.vhd @@ -0,0 +1,124 @@ +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE STD.textio.ALL; + +PACKAGE util_1164 IS + PROCEDURE read(l: INOUT line; value: OUT std_logic); + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector); + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0); + PROCEDURE Grow_line(L : inout LINE; incr : in integer); +END util_1164; + + + +PACKAGE BODY util_1164 IS + + FUNCTION white_space(value:character) RETURN boolean IS + VARIABLE result:boolean; + BEGIN + IF (value = ' ') OR (value = HT) THEN + RETURN true; + ELSE + RETURN false; + END IF; + END white_space; + + PROCEDURE read(l: INOUT line; value: OUT std_logic) IS + VARIABLE char_var: character:= ' '; + BEGIN + WHILE l'LENGTH > 0 LOOP + read(l,char_var); + IF NOT white_space(char_var) THEN + EXIT; + END IF; + END LOOP; + IF white_space(char_var) THEN + ASSERT false REPORT "No std_logic value found in file" + SEVERITY error; + value := 'X'; + RETURN; + END IF; + + CASE char_var IS + WHEN 'U'|'u' => value := 'U'; + WHEN '0' => value := '0'; + WHEN '1' => value := '1'; + WHEN 'X'|'x' => value := 'X'; + WHEN 'L'|'l' => value := 'L'; + WHEN 'H'|'h' => value := 'H'; + WHEN 'W'|'w' => value := 'W'; + WHEN 'Z'|'z' => value := 'Z'; + WHEN '-' => value := '-'; + WHEN OTHERS => + ASSERT false REPORT "Unrecognized value read for std_logic" + SEVERITY error; + value := 'X'; + END CASE; + END read; + + PROCEDURE read(l: INOUT line; value: OUT std_logic_vector) IS + BEGIN + FOR i IN value'HIGH DOWNTO value'LOW LOOP + IF l'LENGTH > 0 THEN + read(l,value(i)); + ELSE + ASSERT false REPORT "Not enough values for std_logic_vector in file" + SEVERITY error; + RETURN; + END IF; + END LOOP; + END read; + + procedure Grow_line(L : inout LINE; incr : in integer) + is + variable old_L : LINE := L; + variable bfp: integer; -- Blank fill pointer. + begin + assert incr > 0 + report "Textio: Grow_line called with zero increment." + severity error; + + if L = null then + bfp := 0; + L := new string(1 to incr); + else + bfp := old_L'high; + L := new string(old_L'low to old_L'high + incr); + L(old_L'low to old_L'high) := old_L.all; + Deallocate(old_L); + end if; + for i in 1 to incr loop + L(bfp + i) := ' '; + end loop; + end; + + + PROCEDURE write(l: INOUT line; value: IN std_logic_vector; + JUSTIFIED: IN SIDE := right; + FIELD: IN WIDTH := 0) IS + variable fw: integer := VALUE'length; + variable bp: integer; + variable offset: integer := 0; + alias normal : std_logic_vector(0 to value'length - 1) is value; + begin + if L /= null then + bp := L'high + 1; + else bp := 1; + end if; + if FIELD > VALUE'length then + fw := FIELD; + if JUSTIFIED = right then + offset := fw - VALUE'length; + end if; + end if; + Grow_line(L, fw); + for i in normal'range loop + L(bp + i + offset) := character'val( + std_logic'pos(normal(i)) + character'pos('0')); + end loop; + end; + + +END util_1164; diff --git a/lib/models/memory/sdram/mt48lc8m8a2/vec_gen.vhd b/lib/models/memory/sdram/mt48lc8m8a2/vec_gen.vhd new file mode 100644 index 0000000..82b2277 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/vec_gen.vhd @@ -0,0 +1,319 @@ +------------------------------------------------------------------------------- +-- -- +-- This is a data generator for the testbench for Micron's Synchronous -- +-- DRAM. This generator reads a text file line-by-line and generates -- +-- a file of test vectors that is then read by the testbench and -- +-- applied to the part. -- +-- -- +-- This VHDL program creates a text file of test vectors that is used by the -- +-- test bench. Place your commands in a file (a copy of VEC_GEN.VHD) and run -- +-- VEC_GEN.VHD in your VHDL simulator (make sure you have compiled this -- +-- package prior to running the program VEC_GEN.VHD). This will produce the -- +-- vectors that are required to run the included testbench. Change the name -- +-- of the vector file to save your vectors in separate files. The default -- +-- file name for the output vectors generated from this pacakage is -- +-- "test.txt." -- +-- -- +-- Now compile and run the testbench program embedtb.vhd. The testbench uses -- +-- the default test.txt as input vectors. -- +-- -- +-- -- +-- Copyright 1997 Micron Technology, Inc. -- +-- -- +------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.all; +USE std.textio.all; +USE work.io_utils.all; + + +PACKAGE generate_vectors IS + + CONSTANT set_up : TIME; + CONSTANT hold : TIME; + CONSTANT cycle_start : TIME; + + SIGNAL cycle : INTEGER := 0; + SIGNAL sim_time : TIME := 0 ns; + FILE output_file:TEXT IS OUT "test.txt"; + PROCEDURE write (col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE read (col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT; cke : IN BIT); + PROCEDURE active (row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE precharge (bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE nop (data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE burst_term (data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT); + PROCEDURE auto_refresh; + PROCEDURE next_cycle (SIGNAL clk : IN BIT); + PROCEDURE load_array; + PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT); + PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)); + +END generate_vectors; + +PACKAGE BODY generate_vectors IS + + CONSTANT set_up : TIME := 3 ns; + CONSTANT hold : TIME := 1 ns; + CONSTANT cycle_start : TIME := 0 ns; + +PROCEDURE write(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); first_data : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + VARIABLE l : LINE; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, Cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 0, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, col_address, right, 6); --address + write(l, first_data, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE read(col_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); dqm : IN BIT; cke : IN BIT) IS + VARIABLE l : LINE; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, Cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, col_address, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE active(row_address : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0); data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + VARIABLE l : LINE; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, Cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, row_address, right, 6); --address + write(l, data_bus, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE precharge(bank : IN BIT_VECTOR(1 DOWNTO 0); address : IN INTEGER; data_bus: IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + VARIABLE l : LINE; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, Cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 0, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, address, right, 6); --address + write(l, data_bus, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE nop(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + VARIABLE l : LINE; + VARIABLE col_address : INTEGER := 0; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, col_address, right, 6); --address + write(l, data_bus, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE burst_term(data_bus : IN INTEGER; dqm : IN BIT; cke : IN BIT) IS + VARIABLE l : LINE; + VARIABLE col_address : INTEGER := 0; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 0, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, col_address, right, 6); --address + write(l, data_bus, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE auto_refresh IS + VARIABLE l : LINE; + VARIABLE dqm : BIT := '0'; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + + +PROCEDURE next_cycle(SIGNAL clk : IN BIT) IS +BEGIN + WAIT UNTIL clk = '1'; +END; + +PROCEDURE load_array IS + VARIABLE l : LINE; + VARIABLE dqm : BIT := '0'; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 1, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE unload_array(row_start : IN INTEGER; row_end : IN INTEGER; bank : IN BIT_VECTOR(1 DOWNTO 0)) IS + VARIABLE l : LINE; + VARIABLE dqm : BIT := '0'; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, 1, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 1, right, 4); --Ras + write(l, 1, right, 4); --Cas + write(l, 1, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, 0, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 1, right, 4); --unload + write(l, row_start, right, 6); --row_address_start + write(l, row_end, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +PROCEDURE load_mode_reg(op_code : IN INTEGER; cke : IN BIT) IS + VARIABLE l : LINE; + VARIABLE dqm : BIT := '0'; + VARIABLE bank : BIT_VECTOR(1 DOWNTO 0) := "00"; +BEGIN + IF cycle = 0 THEN + write(l, cycle_start, left, 4, ns); + ELSE + write(l, now-set_up, left, 4, ns); + END IF; + write(l, cke, right, 4); --Cke + write(l, 0, right, 4); --Cs + write(l, 0, right, 4); --Ras + write(l, 0, right, 4); --Cas + write(l, 0, right, 4); --We + write(l, dqm, right, 4); --Dqm + write(l, bank, right, 4); --Ba + write(l, op_code, right, 6); --address + write(l, -100, right, 6); --first data location + write(l, 0, right, 4); --load + write(l, 0, right, 4); --unload + write(l, 0, right, 6); --row_address_start + write(l, 0, right, 6); --row_address_end + writeline(output_file,l); --write vector to file +END; + +END generate_vectors; + diff --git a/lib/models/memory/sdram/mt48lc8m8a2/vector.do b/lib/models/memory/sdram/mt48lc8m8a2/vector.do new file mode 100644 index 0000000..7480359 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/vector.do @@ -0,0 +1,4 @@ +vcom vec_gen.vhd +vcom ed_comnd.vhd +vsim vector_generate +run -all diff --git a/lib/models/memory/sdram/mt48lc8m8a2/wave.do b/lib/models/memory/sdram/mt48lc8m8a2/wave.do new file mode 100644 index 0000000..f414a82 --- /dev/null +++ b/lib/models/memory/sdram/mt48lc8m8a2/wave.do @@ -0,0 +1,31 @@ +onerror {resume} +add wave -logic /tb/u1/clk +add wave -logic /tb/u1/cke +add wave -logic /tb/u1/cs_n +add wave -logic /tb/u1/ras_n +add wave -logic /tb/u1/cas_n +add wave -logic /tb/u1/we_n +add wave -literal -decimal /tb/u1/addr +add wave -literal -unsigned /tb/u1/ba +add wave -literal -decimal /tb/u1/dq +add wave -logic /tb/u1/dqm +add wave -literal -decimal /tb/u1/operation +add wave -literal -decimal /tb/u1/mode_reg +add wave -logic /tb/u1/active_enable +add wave -logic /tb/u1/aref_enable +add wave -logic /tb/u1/burst_term +add wave -logic /tb/u1/mode_reg_enable +add wave -logic /tb/u1/prech_enable +add wave -logic /tb/u1/read_enable +add wave -logic /tb/u1/write_enable +add wave -logic /tb/u1/burst_length_1 +add wave -logic /tb/u1/burst_length_2 +add wave -logic /tb/u1/burst_length_4 +add wave -logic /tb/u1/burst_length_8 +add wave -logic /tb/u1/cas_latency_2 +add wave -logic /tb/u1/cas_latency_3 +add wave -literal -binary /tb/u1/pre_chk +add wave -literal -binary /tb/u1/act_chk +add wave -literal -unsigned /tb/u1/bank_chk +add wave -literal -decimal /tb/u1/row_chk +add wave -literal -decimal /tb/u1/col_chk diff --git a/lib/models/memory/sdram/mt48v2m32lffc/mt48v2m32lffc.vhd b/lib/models/memory/sdram/mt48v2m32lffc/mt48v2m32lffc.vhd new file mode 100644 index 0000000..e857bd2 --- /dev/null +++ b/lib/models/memory/sdram/mt48v2m32lffc/mt48v2m32lffc.vhd @@ -0,0 +1,1163 @@ +----------------------------------------------------------------------------------------- +-- +-- File Name: MT48LC2M32LFFC.VHD +-- Version: 0.0 +-- Date: June 4th, 2001 +-- Model: Behavioral +-- Simulator: Model Technology +-- +-- Dependencies: None +-- +-- Author: Son P. Huynh +-- Email: sphuynh@micron.com +-- Phone: (208) 368-3825 +-- Company: Micron Technology, Inc. +-- Part Number: MT48LC2M32LFFC (1Mb x 32 x 4 Banks) +-- +-- Description: Micron 64Mb SDRAM +-- +-- Limitation: - Doesn't check for 4096-cycle refresh +-- +-- Note: - Set simulator resolution to "ps" accuracy +-- +-- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +-- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +-- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +-- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +-- +-- Copyright (c) 1998 Micron Semiconductor Products, Inc. +-- All rights researved +-- +-- Rev Author Phone Date Changes +-- --- ---------------------------- ---------- ------------------------------------- +-- 0.0 Son P. Huynh 208-368-3825 06/04/2001 First Release +-- Micron Technology Inc. - Simple testbench included +----------------------------------------------------------------------------------------- + +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + USE ieee.std_logic_unsigned.conv_integer; + USE ieee.std_logic_arith.conv_std_logic_vector; + +ENTITY mt48v2m32lffc IS + GENERIC ( + -- Timing Parameters for -8 and CAS Latency = 2 + tAC : TIME := 8.0 ns; + tHZ : TIME := 8.0 ns; + tOH : TIME := 2.5 ns; + tMRD : INTEGER := 2; -- 2 Clk Cycles + tRAS : TIME := 48.0 ns; + tRC : TIME := 80.0 ns; + tRCD : TIME := 20.0 ns; + tRFC : TIME := 80.0 ns; + tRP : TIME := 20.0 ns; + tRRD : TIME := 20.0 ns; + tWRa : TIME := 7.0 ns; -- A2 Version - Auto precharge mode only (1 Clk + 6 ns) + tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (12 ns) + + tAH : TIME := 1.0 ns; + tAS : TIME := 2.5 ns; + tCH : TIME := 3.0 ns; + tCL : TIME := 3.0 ns; + tCK : TIME := 13.0 ns; + tDH : TIME := 1.0 ns; + tDS : TIME := 2.5 ns; + tCKH : TIME := 1.0 ns; + tCKS : TIME := 2.5 ns; + tCMH : TIME := 1.0 ns; + tCMS : TIME := 2.5 ns; + + addr_bits : INTEGER := 11; + data_bits : INTEGER := 32; + col_bits : INTEGER := 8 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '0'; + Cs_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '0'; + Cas_n : IN STD_LOGIC := '0'; + We_n : IN STD_LOGIC := '0'; + Dqm : IN STD_LOGIC_VECTOR (3 DOWNTO 0) := (OTHERS => '0') + ); +END mt48v2m32lffc; + +ARCHITECTURE behave OF mt48v2m32lffc IS + TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, FILE_LOAD, FILE_UNLOAD); + TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; + TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; + TYPE Array4xSL IS ARRAY (3 DOWNTO 0) OF STD_LOGIC; + TYPE Array4x2SLV IS ARRAY (3 DOWNTO 0) OF STD_LOGIC_VECTOR (1 DOWNTO 0); -- For Bank Pipeline + TYPE Array2x4SLV IS ARRAY (1 DOWNTO 0) OF STD_LOGIC_VECTOR (3 DOWNTO 0); -- For Dqm Pipeline + TYPE Array4xCSLV IS ARRAY (4 DOWNTO 0) OF STD_LOGIC_VECTOR (Col_bits - 1 DOWNTO 0); -- For Column Pipeline + TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; + SIGNAL Operation : State := NOP; + SIGNAL Mode_reg : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL Active_enable, Aref_enable, Burst_term : STD_LOGIC := '0'; + SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : STD_LOGIC := '0'; + SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : STD_LOGIC := '0'; + SIGNAL Cas_latency_1, Cas_latency_2, Cas_latency_3 : STD_LOGIC := '0'; + SIGNAL Cs_in, Ras_in, Cas_in, We_in : STD_LOGIC := '0'; + SIGNAL Write_burst_mode : STD_LOGIC := '0'; + SIGNAL RAS_clk, Sys_clk, CkeZ : STD_LOGIC := '0'; + +BEGIN + -- Strip the strength + Cs_in <= To_X01 (Cs_n); + Ras_in <= To_X01 (Ras_n); + Cas_in <= To_X01 (Cas_n); + We_in <= To_X01 (We_n); + + -- Commands Decode + Active_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND We_in; + Aref_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND We_in; + Burst_term <= NOT(Cs_in) AND Ras_in AND Cas_in AND NOT(We_in); + Mode_reg_enable <= NOT(Cs_in) AND NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); + Prech_enable <= NOT(Cs_in) AND NOT(Ras_in) AND Cas_in AND NOT(We_in); + Read_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND We_in; + Write_enable <= NOT(Cs_in) AND Ras_in AND NOT(Cas_in) AND NOT(We_in); + + -- Burst Length Decode + Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); + Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); + Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); + Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); + + -- CAS Latency Decode + Cas_latency_1 <= NOT(Mode_reg(6)) AND NOT(Mode_reg(5)) AND Mode_reg(4); + Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); + Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); + + -- Write Burst Mode + Write_burst_mode <= Mode_reg(9); + + -- RAS Clock for checking tWR and tRP + PROCESS + variable Clk0, Clk1 : integer := 0; + begin + RAS_clk <= '1'; + wait for 0.5 ns; + RAS_clk <= '0'; + wait for 0.5 ns; + if Clk0 > 100 or Clk1 > 100 then + wait; + else + if Clk = '1' then + Clk0 := 0; + Clk1 := Clk1 + 1; + else + Clk0 := Clk0 + 1; + Clk1 := 0; + end if; + end if; + END PROCESS; + + -- System Clock + int_clk : PROCESS (Clk) + begin + IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN + CkeZ <= Cke; + END IF; + Sys_clk <= CkeZ AND Clk; + END PROCESS; + + state_register : PROCESS + TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + TYPE ram_pntr IS ACCESS ram_type; + TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; + VARIABLE Bank0 : ram_stor; + VARIABLE Bank1 : ram_stor; + VARIABLE Bank2 : ram_stor; + VARIABLE Bank3 : ram_stor; + VARIABLE Row_index, Col_index : INTEGER := 0; + VARIABLE Dq_temp : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => '0'); + + VARIABLE Col_addr : Array4xCSLV; + VARIABLE Bank_addr : Array4x2SLV; + VARIABLE Dqm_reg0, Dqm_reg1 : STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000"; + + VARIABLE Bank, Previous_bank : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col_brst : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Row : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Col : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + VARIABLE Burst_counter : INTEGER := 0; + + VARIABLE Command : Array_state; + VARIABLE Bank_precharge : Array4x2SLV; + VARIABLE A10_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Auto_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Read_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE Write_precharge : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_write : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_read : Array4xSL := ('0' & '0' & '0' & '0'); + VARIABLE RW_interrupt_bank : STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); + + VARIABLE Data_in_enable, Data_out_enable : STD_LOGIC := '0'; + VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : STD_LOGIC := '0'; + VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : STD_LOGIC := '0'; + + -- Timing Check + VARIABLE MRD_chk : INTEGER := 0; + VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); + VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); + VARIABLE RC_chk, RRD_chk : TIME := 0 ns; + VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; + VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; + VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; + + -- Initialize empty rows + PROCEDURE Init_mem (Bank : STD_LOGIC_VECTOR (1 DOWNTO 0); Row_index : INTEGER) IS + VARIABLE i, j : INTEGER := 0; + BEGIN + IF Bank = "00" THEN + IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty + Bank0 (Row_index) := NEW ram_type; -- Open new row for access + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank0 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "01" THEN + IF Bank1 (Row_index) = NULL THEN + Bank1 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank1 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "10" THEN + IF Bank2 (Row_index) = NULL THEN + Bank2 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank2 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + ELSIF Bank = "11" THEN + IF Bank3 (Row_index) = NULL THEN + Bank3 (Row_index) := NEW ram_type; + FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP + FOR j IN (data_bits - 1) DOWNTO 0 LOOP + Bank3 (Row_index) (i) (j) := '0'; + END LOOP; + END LOOP; + END IF; + END IF; + END; + + -- Burst Counter + PROCEDURE Burst_decode IS + VARIABLE Col_int : INTEGER := 0; + VARIABLE Col_vec, Col_temp : STD_LOGIC_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); + BEGIN + -- Advance Burst Counter + Burst_counter := Burst_counter + 1; + + -- Burst Type + IF Mode_reg (3) = '0' THEN + Col_int := conv_integer(Col) + 1; + Col_temp := CONV_STD_LOGIC_VECTOR(Col_int, col_bits); + ELSIF Mode_reg (3) = '1' THEN + Col_vec := CONV_STD_LOGIC_VECTOR(Burst_counter, col_bits); + Col_temp (2) := Col_vec (2) XOR Col_brst (2); + Col_temp (1) := Col_vec (1) XOR Col_brst (1); + Col_temp (0) := Col_vec (0) XOR Col_brst (0); + END IF; + + -- Burst Length + IF Burst_length_2 = '1' THEN + Col (0) := Col_temp (0); + ELSIF Burst_length_4 = '1' THEN + Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); + ELSIF Burst_length_8 = '1' THEN + Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); + ELSE + Col := Col_temp; + END IF; + + -- Burst Read Single Write + IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + + -- Data counter + IF Burst_length_1 = '1' THEN + IF Burst_counter >= 1 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_2 = '1' THEN + IF Burst_counter >= 2 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_4 = '1' THEN + IF Burst_counter >= 4 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Burst_length_8 = '1' THEN + IF Burst_counter >= 8 THEN + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + ELSIF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + END IF; + END; + + BEGIN + WAIT ON Sys_clk, RAS_clk; + IF Sys_clk'event AND Sys_clk = '1' THEN + -- Internal Command Pipeline + Command(0) := Command(1); + Command(1) := Command(2); + Command(2) := Command(3); + Command(3) := NOP; + + Col_addr(0) := Col_addr(1); + Col_addr(1) := Col_addr(2); + Col_addr(2) := Col_addr(3); + Col_addr(3) := (OTHERS => '0'); + + Bank_addr(0) := Bank_addr(1); + Bank_addr(1) := Bank_addr(2); + Bank_addr(2) := Bank_addr(3); + Bank_addr(3) := "00"; + + Bank_precharge(0) := Bank_precharge(1); + Bank_precharge(1) := Bank_precharge(2); + Bank_precharge(2) := Bank_precharge(3); + Bank_precharge(3) := "00"; + + A10_precharge(0) := A10_precharge(1); + A10_precharge(1) := A10_precharge(2); + A10_precharge(2) := A10_precharge(3); + A10_precharge(3) := '0'; + + -- Operation Decode (Optional for showing current command on posedge clock / debug feature) + IF Active_enable = '1' THEN + Operation <= ACT; + ELSIF Aref_enable = '1' THEN + Operation <= A_REF; + ELSIF Burst_term = '1' THEN + Operation <= BST; + ELSIF Mode_reg_enable = '1' THEN + Operation <= LMR; + ELSIF Prech_enable = '1' THEN + Operation <= PRECH; + ELSIF Read_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= READ; + ELSE + Operation <= READ_A; + END IF; + ELSIF Write_enable = '1' THEN + IF Addr(10) = '0' THEN + Operation <= WRITE; + ELSE + Operation <= WRITE_A; + END IF; + ELSE + Operation <= NOP; + END IF; + + -- Dqm pipeline for Read + Dqm_reg0 := Dqm_reg1; + Dqm_reg1 := Dqm; + + -- Read or Write with Auto Precharge Counter + IF Auto_precharge (0) = '1' THEN + Count_precharge (0) := Count_precharge (0) + 1; + END IF; + IF Auto_precharge (1) = '1' THEN + Count_precharge (1) := Count_precharge (1) + 1; + END IF; + IF Auto_precharge (2) = '1' THEN + Count_precharge (2) := Count_precharge (2) + 1; + END IF; + IF Auto_precharge (3) = '1' THEN + Count_precharge (3) := Count_precharge (3) + 1; + END IF; + + -- Auto Precharge Timer for tWR + if (Burst_length_1 = '1' OR Write_burst_mode = '1') then + if (Count_precharge(0) = 1) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 1) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 1) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 1) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_2 = '1') then + if (Count_precharge(0) = 2) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 2) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 2) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 2) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_4 = '1') then + if (Count_precharge(0) = 4) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 4) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 4) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 4) then + Count_time(3) := NOW; + end if; + elsif (Burst_length_8 = '1') then + if (Count_precharge(0) = 8) then + Count_time(0) := NOW; + end if; + if (Count_precharge(1) = 8) then + Count_time(1) := NOW; + end if; + if (Count_precharge(2) = 8) then + Count_time(2) := NOW; + end if; + if (Count_precharge(3) = 8) then + Count_time(3) := NOW; + end if; + end if; + + -- tMRD Counter + MRD_chk := MRD_chk + 1; + + -- tWR Counter + WR_counter(0) := WR_counter(0) + 1; + WR_counter(1) := WR_counter(1) + 1; + WR_counter(2) := WR_counter(2) + 1; + WR_counter(3) := WR_counter(3) + 1; + + -- Auto Refresh + IF Aref_enable = '1' THEN + -- Auto Refresh to Auto Refresh + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Auto Refresh" + SEVERITY WARNING; + -- Precharge to Auto Refresh + ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Auto Refresh" + SEVERITY WARNING; + -- All banks must be idle before refresh + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All banks must be Precharge before Auto Refresh" + SEVERITY WARNING; + END IF; + -- Record current tRC time + RC_chk := NOW; + END IF; + + -- Load Mode Register + IF Mode_reg_enable = '1' THEN + Mode_reg <= Addr; + IF (Pc_b3 = '0' OR Pc_b2 = '0' OR Pc_b1 = '0' OR Pc_b0 = '0') THEN + ASSERT (FALSE) + REPORT "All bank must be Precharge before Load Mode Register" + SEVERITY WARNING; + END IF; + -- REF to LMR + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Load Mode Register" + SEVERITY WARNING; + -- LMR to LMR + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Load Mode Register" + SEVERITY WARNING; + -- Record current tMRD time + MRD_chk := 0; + END IF; + + -- Active Block (latch Bank and Row Address) + IF Active_enable = '1' THEN + IF Ba = "00" AND Pc_b0 = '1' THEN + Act_b0 := '1'; + Pc_b0 := '0'; + B0_row_addr := Addr; + RCD_chk0 := NOW; + RAS_chk0 := NOW; + -- Precharge to Active Bank 0 + ASSERT (NOW - RP_chk0 >= tRP) + REPORT "tRP violation during Activate Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '1' THEN + Act_b1 := '1'; + Pc_b1 := '0'; + B1_row_addr := Addr; + RCD_chk1 := NOW; + RAS_chk1 := NOW; + -- Precharge to Active Bank 1 + ASSERT (NOW - RP_chk1 >= tRP) + REPORT "tRP violation during Activate Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '1' THEN + Act_b2 := '1'; + Pc_b2 := '0'; + B2_row_addr := Addr; + RCD_chk2 := NOW; + RAS_chk2 := NOW; + -- Precharge to Active Bank 2 + ASSERT (NOW - RP_chk2 >= tRP) + REPORT "tRP violation during Activate Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '1' THEN + Act_b3 := '1'; + Pc_b3 := '0'; + B3_row_addr := Addr; + RCD_chk3 := NOW; + RAS_chk3 := NOW; + -- Precharge to Active Bank 3 + ASSERT (NOW - RP_chk3 >= tRP) + REPORT "tRP violation during Activate Bank 3" + SEVERITY WARNING; + ELSIF Ba = "00" AND Pc_b0 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 0 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "01" AND Pc_b1 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 1 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "10" AND Pc_b2 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 2 is not Precharged" + SEVERITY WARNING; + ELSIF Ba = "11" AND Pc_b3 = '0' THEN + ASSERT (FALSE) + REPORT "Bank 3 is not Precharged" + SEVERITY WARNING; + END IF; + -- Active Bank A to Active Bank B + IF ((Previous_bank /= Ba) AND (NOW - RRD_chk < tRRD)) THEN + ASSERT (FALSE) + REPORT "tRRD violation during Activate" + SEVERITY WARNING; + END IF; + -- LMR to ACT + ASSERT (MRD_chk >= tMRD) + REPORT "tMRD violation during Activate" + SEVERITY WARNING; + -- AutoRefresh to Activate + ASSERT (NOW - RC_chk >= tRC) + REPORT "tRC violation during Activate" + SEVERITY WARNING; + -- Record variable for checking violation + RRD_chk := NOW; + Previous_bank := Ba; + END IF; + + -- Precharge Block + IF Prech_enable = '1' THEN + IF Addr(10) = '1' THEN + Pc_b0 := '1'; + Pc_b1 := '1'; + Pc_b2 := '1'; + Pc_b3 := '1'; + Act_b0 := '0'; + Act_b1 := '0'; + Act_b2 := '0'; + Act_b3 := '0'; + RP_chk0 := NOW; + RP_chk1 := NOW; + RP_chk2 := NOW; + RP_chk3 := NOW; + -- Activate to Precharge all banks + ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) + REPORT "tRAS violation during Precharge all banks" + SEVERITY WARNING; + -- tWR violation check for Write + IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR + (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN + ASSERT (FALSE) + REPORT "tWR violation during Precharge ALL banks" + SEVERITY WARNING; + END IF; + ELSIF Addr(10) = '0' THEN + IF Ba = "00" THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + -- Activate to Precharge bank 0 + ASSERT (NOW - RAS_chk0 >= tRAS) + REPORT "tRAS violation during Precharge bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + -- Activate to Precharge bank 1 + ASSERT (NOW - RAS_chk1 >= tRAS) + REPORT "tRAS violation during Precharge bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + -- Activate to Precharge bank 2 + ASSERT (NOW - RAS_chk2 >= tRAS) + REPORT "tRAS violation during Precharge bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + -- Activate to Precharge bank 3 + ASSERT (NOW - RAS_chk3 >= tRAS) + REPORT "tRAS violation during Precharge bank 3" + SEVERITY WARNING; + END IF; + -- tWR violation check for Write + ASSERT (NOW - WR_chkp(CONV_INTEGER(Ba)) >= tWRp) + REPORT "tWR violation during Precharge" + SEVERITY WARNING; + END IF; + -- Terminate a Write Immediately (if same bank or all banks) + IF (Data_in_enable = '1' AND (Bank = Ba OR Addr(10) = '1')) THEN + Data_in_enable := '0'; + END IF; + -- Precharge Command Pipeline for READ + IF CAS_latency_3 = '1' THEN + Command(2) := PRECH; + Bank_precharge(2) := Ba; + A10_precharge(2) := Addr(10); + ELSIF CAS_latency_2 = '1' THEN + Command(1) := PRECH; + Bank_precharge(1) := Ba; + A10_precharge(1) := Addr(10); + END IF; + END IF; + + -- Burst Terminate + IF Burst_term = '1' THEN + -- Terminate a Write immediately + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + END IF; + -- Terminate a Read depend on CAS Latency + IF CAS_latency_3 = '1' THEN + Command(2) := BST; + ELSIF CAS_latency_2 = '1' THEN + Command(1) := BST; + END IF; + END IF; + + -- Read, Write, Column Latch + IF Read_enable = '1' OR Write_enable = '1' THEN + -- Check to see if bank is open (ACT) for Read or Write + IF ((Ba = "00" AND Pc_b0 = '1') OR (Ba = "01" AND Pc_b1 = '1') OR + (Ba = "10" AND Pc_b2 = '1') OR (Ba = "11" AND Pc_b3 = '1')) THEN + ASSERT (FALSE) + REPORT "Cannot Read or Write - Bank is not Activated" + SEVERITY WARNING; + END IF; + -- Activate to Read or Write + IF Ba = "00" THEN + ASSERT (NOW - RCD_chk0 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 0" + SEVERITY WARNING; + ELSIF Ba = "01" THEN + ASSERT (NOW - RCD_chk1 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 1" + SEVERITY WARNING; + ELSIF Ba = "10" THEN + ASSERT (NOW - RCD_chk2 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 2" + SEVERITY WARNING; + ELSIF Ba = "11" THEN + ASSERT (NOW - RCD_chk3 >= tRCD) + REPORT "tRCD violation during Read or Write to Bank 3" + SEVERITY WARNING; + END IF; + -- Read Command + IF Read_enable = '1' THEN + -- CAS Latency Pipeline + IF Cas_latency_1 = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := READ_A; + ELSE + Command(0) := READ; + END IF; + Col_addr (0) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (0) := Ba; + ELSIF Cas_latency_2 = '1' THEN + IF Addr(10) = '1' THEN + Command(1) := READ_A; + ELSE + Command(1) := READ; + END IF; + Col_addr (1) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (1) := Ba; + ELSIF Cas_latency_3 = '1' THEN + IF Addr(10) = '1' THEN + Command(2) := READ_A; + ELSE + Command(2) := READ; + END IF; + Col_addr (2) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (2) := Ba; + END IF; + + -- Read intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + -- Interrupt a write with autoprecharge + IF (Auto_precharge (CONV_INTEGER(RW_interrupt_bank)) = '1' AND + Write_precharge (CONV_INTEGER(RW_interrupt_bank)) = '1') THEN + RW_interrupt_write (CONV_INTEGER(RW_interrupt_bank)) := '1'; + WR_time (CONV_INTEGER(RW_interrupt_bank)) := NOW; + END IF; + END IF; + + -- Write Command + ELSIF Write_enable = '1' THEN + IF Addr(10) = '1' THEN + Command(0) := WRITE_A; + ELSE + Command(0) := WRITE; + END IF; + Col_addr (0) := Addr(col_bits - 1 DOWNTO 0); + Bank_addr (0) := Ba; + + -- Write intterupt a Write (terminate Write immediately) + IF Data_in_enable = '1' THEN + Data_in_enable := '0'; + -- Interrupt a Write with Auto Precharge + IF (Auto_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' AND + Write_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1') THEN + RW_interrupt_write(CONV_INTEGER(RW_interrupt_bank)) := '1'; + WR_time (CONV_INTEGER(RW_interrupt_bank)) := NOW; + END IF; + END IF; + + -- Write interrupt a Read (terminate Read immediately) + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + -- Interrupt a Read with Auto Precharge + IF Auto_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' AND Read_precharge(CONV_INTEGER(RW_interrupt_bank)) = '1' THEN + RW_interrupt_read(CONV_INTEGER(RW_interrupt_bank)) := '1'; + END IF; + END IF; + END IF; + + -- Read or Write with Auto Precharge + IF Addr(10) = '1' THEN + Auto_precharge (CONV_INTEGER(Ba)) := '1'; + Count_precharge (CONV_INTEGER(Ba)) := 0; + RW_interrupt_bank := Ba; + IF Read_enable = '1' THEN + Read_precharge (CONV_INTEGER(Ba)) := '1'; + ELSIF Write_enable = '1' THEN + Write_precharge (CONV_INTEGER(Ba)) := '1'; + END IF; + END IF; + END IF; + + -- Read with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. BL/2 cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR + (RW_interrupt_read(0) = '1')) THEN + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + Auto_precharge(0) := '0'; + Read_precharge(0) := '0'; + RW_interrupt_read(0) := '0'; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR + (RW_interrupt_read(1) = '1')) THEN + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + Auto_precharge(1) := '0'; + Read_precharge(1) := '0'; + RW_interrupt_read(1) := '0'; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR + (RW_interrupt_read(2) = '1')) THEN + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + Auto_precharge(2) := '0'; + Read_precharge(2) := '0'; + RW_interrupt_read(2) := '0'; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR + (RW_interrupt_read(3) = '1')) THEN + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + Auto_precharge(3) := '0'; + Read_precharge(3) := '0'; + RW_interrupt_read(3) := '0'; + END IF; + END IF; + + -- Internal Precharge or Bst + IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks + IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank + IF Data_out_enable = '1' THEN + Data_out_enable := '0'; + END IF; + END IF; + + -- Turn off databus + IF (Data_out_enable = '0') THEN + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + + -- Detect Read or Write Command + IF Command(0) = READ OR Command(0) = READ_A THEN + Bank := Bank_addr (0); + Col := Col_addr (0); + Col_brst := Col_addr (0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '0'; + Data_out_enable := '1'; + ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN + Bank := Bank_addr(0); + Col := Col_addr(0); + Col_brst := Col_addr(0); + IF Bank_addr (0) = "00" THEN + Row := B0_row_addr; + ELSIF Bank_addr (0) = "01" THEN + Row := B1_row_addr; + ELSIF Bank_addr (0) = "10" THEN + Row := B2_row_addr; + ELSE + Row := B3_row_addr; + END IF; + Burst_counter := 0; + Data_in_enable := '1'; + Data_out_enable := '0'; + END IF; + + -- DQ (Driver / Receiver) + Row_index := CONV_INTEGER (Row); + Col_index := CONV_INTEGER (Col); + IF Data_in_enable = '1' THEN + IF Dqm /= "1111" THEN + -- Initialize memory + Init_mem (Bank, Row_index); + -- Load memory into buffer + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + END IF; + -- Dqm operation + IF Dqm (0) = '0' THEN + Dq_temp (7 DOWNTO 0) := Dq (7 DOWNTO 0); + END IF; + IF Dqm (1) = '0' THEN + Dq_temp (15 DOWNTO 8) := Dq (15 DOWNTO 8); + END IF; + IF Dqm (2) = '0' THEN + Dq_temp (23 DOWNTO 16) := Dq (23 DOWNTO 16); + END IF; + IF Dqm (3) = '0' THEN + Dq_temp (31 DOWNTO 24) := Dq (31 DOWNTO 24); + END IF; + -- Write back to memory + IF Bank = "00" THEN + Bank0 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "01" THEN + Bank1 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "10" THEN + Bank2 (Row_index) (Col_index) := Dq_temp; + ELSIF Bank = "11" THEN + Bank3 (Row_index) (Col_index) := Dq_temp; + END IF; + -- Reset tWR counter + WR_chkp(CONV_INTEGER(Bank)) := NOW; + WR_counter(CONV_INTEGER(Bank)) := 0; + END IF; + -- Decode next burst address + Burst_decode; + ELSIF Data_out_enable = '1' THEN + IF Dqm_reg0 /= "1111" THEN + -- Initialize memory + Init_mem (Bank, Row_index); + -- Load memory into buffer + IF Bank = "00" THEN + Dq_temp := Bank0 (Row_index) (Col_index); + ELSIF Bank = "01" THEN + Dq_temp := Bank1 (Row_index) (Col_index); + ELSIF Bank = "10" THEN + Dq_temp := Bank2 (Row_index) (Col_index); + ELSIF Bank = "11" THEN + Dq_temp := Bank3 (Row_index) (Col_index); + END IF; + -- Dqm operation + IF Dqm_reg0 (0) = '0' THEN + Dq (7 DOWNTO 0) <= TRANSPORT Dq_temp(7 DOWNTO 0) AFTER tAC; + ELSE + Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + IF Dqm_reg0 (1) = '0' THEN + Dq (15 DOWNTO 8) <= TRANSPORT Dq_temp(15 DOWNTO 8) AFTER tAC; + ELSE + Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + IF Dqm_reg0 (2) = '0' THEN + Dq (23 DOWNTO 16) <= TRANSPORT Dq_temp(23 DOWNTO 16) AFTER tAC; + ELSE + Dq (23 DOWNTO 16) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + IF Dqm_reg0 (3) = '0' THEN + Dq (31 DOWNTO 24) <= TRANSPORT Dq_temp(31 DOWNTO 24) AFTER tAC; + ELSE + Dq (31 DOWNTO 24) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; + END IF; + ELSE + Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; + END IF; + Burst_decode; + END IF; + + -- Write with AutoPrecharge Calculation + -- The device start internal precharge when: + -- 1. tWR cycles after command + -- and 2. Meet tRAS requirement + -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) + IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN + IF (((NOW - RAS_chk0 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN + Auto_precharge(0) := '0'; + Write_precharge(0) := '0'; + RW_interrupt_write(0) := '0'; + Pc_b0 := '1'; + Act_b0 := '0'; + RP_chk0 := NOW; + ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; + END IF; + END IF; + IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN + IF (((NOW - RAS_chk1 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR + (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN + Auto_precharge(1) := '0'; + Write_precharge(1) := '0'; + RW_interrupt_write(1) := '0'; + Pc_b1 := '1'; + Act_b1 := '0'; + RP_chk1 := NOW; + END IF; + END IF; + IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN + IF (((NOW - RAS_chk2 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR + (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN + Auto_precharge(2) := '0'; + Write_precharge(2) := '0'; + RW_interrupt_write(2) := '0'; + Pc_b2 := '1'; + Act_b2 := '0'; + RP_chk2 := NOW; + END IF; + END IF; + IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN + IF (((NOW - RAS_chk3 >= tRAS) AND + (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR + (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR + (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN + Auto_precharge(3) := '0'; + Write_precharge(3) := '0'; + RW_interrupt_write(3) := '0'; + Pc_b3 := '1'; + Act_b3 := '0'; + RP_chk3 := NOW; + END IF; + END IF; + END IF; + END PROCESS; + + -- Clock timing checks + Clock_check : PROCESS + VARIABLE Clk_low, Clk_high : TIME := 0 ns; + BEGIN + WAIT ON Clk; + IF (Clk = '1' AND NOW >= 10 ns) THEN + ASSERT (NOW - Clk_low >= tCL) + REPORT "tCL violation" + SEVERITY WARNING; + ASSERT (NOW - Clk_high >= tCK) + REPORT "tCK violation" + SEVERITY WARNING; + Clk_high := NOW; + ELSIF (Clk = '0' AND NOW /= 0 ns) THEN + ASSERT (NOW - Clk_high >= tCH) + REPORT "tCH violation" + SEVERITY WARNING; + Clk_low := NOW; + END IF; + END PROCESS; + + -- Setup timing checks + Setup_check : PROCESS + BEGIN + WAIT ON Clk; + IF Clk = '1' THEN + ASSERT(Cke'LAST_EVENT >= tCKS) + REPORT "CKE Setup time violation -- tCKS" + SEVERITY WARNING; + ASSERT(Cs_n'LAST_EVENT >= tCMS) + REPORT "CS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT >= tCMS) + REPORT "CAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT >= tCMS) + REPORT "RAS# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT >= tCMS) + REPORT "WE# Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT >= tCMS) + REPORT "Dqm Setup time violation -- tCMS" + SEVERITY WARNING; + ASSERT(Addr'LAST_EVENT >= tAS) + REPORT "ADDR Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT >= tAS) + REPORT "BA Setup time violation -- tAS" + SEVERITY WARNING; + ASSERT(Dq'LAST_EVENT >= tDS) + REPORT "Dq Setup time violation -- tDS" + SEVERITY WARNING; + END IF; + END PROCESS; + + -- Hold timing checks + Hold_check : PROCESS + BEGIN + WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); + IF Clk'DELAYED (tCKH) = '1' THEN + ASSERT(Cke'LAST_EVENT > tCKH) + REPORT "CKE Hold time violation -- tCKH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tCMH) = '1' THEN + ASSERT(Cs_n'LAST_EVENT > tCMH) + REPORT "CS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Cas_n'LAST_EVENT > tCMH) + REPORT "CAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Ras_n'LAST_EVENT > tCMH) + REPORT "RAS# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(We_n'LAST_EVENT > tCMH) + REPORT "WE# Hold time violation -- tCMH" + SEVERITY WARNING; + ASSERT(Dqm'LAST_EVENT > tCMH) + REPORT "Dqm Hold time violation -- tCMH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tAH) = '1' THEN + ASSERT(Addr'LAST_EVENT > tAH) + REPORT "ADDR Hold time violation -- tAH" + SEVERITY WARNING; + ASSERT(Ba'LAST_EVENT > tAH) + REPORT "BA Hold time violation -- tAH" + SEVERITY WARNING; + END IF; + IF Clk'DELAYED (tDH) = '1' THEN + ASSERT(Dq'LAST_EVENT > tDH) + REPORT "DQ Hold time violation -- tDH" + SEVERITY WARNING; + END IF; + END PROCESS; + +END behave; diff --git a/lib/models/memory/sdram/mt48v2m32lffc/test.do b/lib/models/memory/sdram/mt48v2m32lffc/test.do new file mode 100644 index 0000000..7a7cc2b --- /dev/null +++ b/lib/models/memory/sdram/mt48v2m32lffc/test.do @@ -0,0 +1,5 @@ +vcom mt48v2m32lffc.vhd +vcom test.vhd +vsim -t ps tb +do wave.do +run -all diff --git a/lib/models/memory/sdram/mt48v2m32lffc/test.vhd b/lib/models/memory/sdram/mt48v2m32lffc/test.vhd new file mode 100644 index 0000000..1c37500 --- /dev/null +++ b/lib/models/memory/sdram/mt48v2m32lffc/test.vhd @@ -0,0 +1,309 @@ +LIBRARY ieee; + USE ieee.std_logic_1164.ALL; + +ENTITY tb IS +END tb; + +ARCHITECTURE test OF tb IS + COMPONENT mt48v2m32lffc + GENERIC ( -- Timing for -7 CL2 + tCK : TIME := 13 ns; + addr_bits : INTEGER := 11; + data_bits : INTEGER := 32 + ); + PORT ( + Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); + Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); + Ba : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; + Clk : IN STD_LOGIC := '0'; + Cke : IN STD_LOGIC := '1'; + Cs_n : IN STD_LOGIC := '1'; + Cas_n : IN STD_LOGIC := '1'; + Ras_n : IN STD_LOGIC := '1'; + We_n : IN STD_LOGIC := '1'; + Dqm : IN STD_LOGIC_VECTOR (3 DOWNTO 0) := "0000" + ); + END COMPONENT; + + FOR ALL : mt48v2m32lffc USE ENTITY work.mt48v2m32lffc (behave); + + CONSTANT tCK : TIME := 13 ns; + CONSTANT addr_bits : INTEGER := 11; + CONSTANT data_bits : INTEGER := 32; + + SIGNAL pDq : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0); + SIGNAL pAddr : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + SIGNAL pBa : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL pClk : STD_LOGIC; + SIGNAL pCke : STD_LOGIC; + SIGNAL pCs_n : STD_LOGIC; + SIGNAL pCas_n : STD_LOGIC; + SIGNAL pRas_n : STD_LOGIC; + SIGNAL pWe_n : STD_LOGIC; + SIGNAL pDqm : STD_LOGIC_VECTOR (3 DOWNTO 0); + SIGNAL stim_done : boolean := false; + SIGNAL clk_done : boolean := false; + + +BEGIN + u1: mt48v2m32lffc + PORT MAP( + Dq => pDq, + Addr => pAddr, + Ba => pBa, + Clk => pClk, + Cke => pCke, + Cs_n => pCs_n, + Ras_n => pRas_n, + Cas_n => pCas_n, + We_n => pWe_n, + Dqm => pDqm + ); + + stimulator : PROCESS + PROCEDURE ACTIVE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '1'; + pWe_n <= '1'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE AUTO_REFRESH IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '0'; + pWe_n <= '1'; + pDqm <= "0000"; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE BURST_TERM IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '1'; + pWe_n <= '0'; + pDqm <= "0000"; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE LOAD_MODE_REG (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '0'; + pWe_n <= '0'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= (OTHERS => 'Z'); + WAIT FOR tCK; + END; + + PROCEDURE NOP (Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '1'; + pWe_n <= '1'; + pDqm <= "0000"; + --pBa <= "00"; + --pAddr <= (OTHERS => '0'); + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE PRECHARGE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '0'; + pCas_n <= '1'; + pWe_n <= '0'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + PROCEDURE READ (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '0'; + pWe_n <= '1'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + + -- Write + PROCEDURE WRITE (Ba_in : STD_LOGIC_VECTOR (1 DOWNTO 0); + Addr_in : STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0); + Dq_in : STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0)) IS + BEGIN + pCke <= '1'; + pCs_n <= '0'; + pRas_n <= '1'; + pCas_n <= '0'; + pWe_n <= '0'; + pDqm <= "0000"; + pBa <= Ba_in; + pAddr <= Addr_in; + pDq <= Dq_in; + WAIT FOR tCK; + END; + BEGIN + -- COMMAND BA ADDR DQ + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + -- We need 100 us power up sequence. I use 10 NOPs here as a required example. + PRECHARGE ("00", "10000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + AUTO_REFRESH; + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + AUTO_REFRESH; + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + LOAD_MODE_REG ("00", "00000100010"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("00", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("01", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("10", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ACTIVE ("11", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + WRITE ("00", "00000000000", "00000000000000000000000000000000"); + NOP ( "00000000000000000000000000000001"); + NOP ( "00000000000000000000000000000010"); + NOP ( "00000000000000000000000000000011"); + + WRITE ("01", "00000000000", "00000000000000000000000000000100"); + NOP ( "00000000000000000000000000000101"); + NOP ( "00000000000000000000000000000110"); + NOP ( "00000000000000000000000000000111"); + + WRITE ("10", "00000000000", "00000000000000000000000000001000"); + NOP ( "00000000000000000000000000001001"); + NOP ( "00000000000000000000000000001010"); + NOP ( "00000000000000000000000000001011"); + + WRITE ("11", "00000000000", "00000000000000000000000000001100"); + NOP ( "00000000000000000000000000001101"); + NOP ( "00000000000000000000000000001110"); + NOP ( "00000000000000000000000000001111"); + + READ ("00", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + READ ("01", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + READ ("10", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + READ ("11", "00000000000", "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + NOP ( "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); + + ASSERT false + REPORT "End of Stimulation File Detected!" + SEVERITY note; + stim_done <= true; + WAIT; + END PROCESS; + + clock : PROCESS + VARIABLE done_time : time; + BEGIN + pclk <= '0'; + WAIT for tCK/2; + WHILE not stim_done loop + pclk <= '1'; + WAIT for tCK/2; + pclk <= '0'; + WAIT for tCK/2; + END LOOP; + done_time := now + tCK; + WHILE now < done_time LOOP -- one last clock to finish last command + pclk <= '1'; + WAIT for tCK/2; + pclk <= '0'; + WAIT for tCK/2; + END LOOP; + ASSERT false + REPORT "Suspending clock activity" + SEVERITY note; + clk_done <= true; + WAIT; + END PROCESS; +END test; diff --git a/lib/models/memory/sdram/mt48v2m32lffc/wave.do b/lib/models/memory/sdram/mt48v2m32lffc/wave.do new file mode 100644 index 0000000..26de1d2 --- /dev/null +++ b/lib/models/memory/sdram/mt48v2m32lffc/wave.do @@ -0,0 +1,26 @@ +add wave -noupdate -radix default -format Logic /tb/u1/clk +add wave -noupdate -radix default -format Logic /tb/u1/cke +add wave -noupdate -radix default -format Logic /tb/u1/cs_n +add wave -noupdate -radix default -format Logic /tb/u1/ras_n +add wave -noupdate -radix default -format Logic /tb/u1/cas_n +add wave -noupdate -radix default -format Logic /tb/u1/we_n +add wave -noupdate -radix decimal /tb/u1/addr +add wave -noupdate -radix unsigned /tb/u1/ba +add wave -noupdate -radix decimal /tb/u1/dq +add wave -noupdate -radix default -format Logic /tb/u1/dqm +add wave -noupdate -radix decimal /tb/u1/operation +add wave -noupdate -radix decimal /tb/u1/mode_reg +add wave -noupdate -radix default -format Logic /tb/u1/active_enable +add wave -noupdate -radix default -format Logic /tb/u1/aref_enable +add wave -noupdate -radix default -format Logic /tb/u1/burst_term +add wave -noupdate -radix default -format Logic /tb/u1/mode_reg_enable +add wave -noupdate -radix default -format Logic /tb/u1/prech_enable +add wave -noupdate -radix default -format Logic /tb/u1/read_enable +add wave -noupdate -radix default -format Logic /tb/u1/write_enable +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_1 +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_2 +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_4 +add wave -noupdate -radix default -format Logic /tb/u1/burst_length_8 +add wave -noupdate -radix default -format Logic /tb/u1/cas_latency_2 +add wave -noupdate -radix default -format Logic /tb/u1/cas_latency_3 +
is byte to be written at Mem(aaaaaa++) + -- (aaaaaa is incremented at every load) + -- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + --------------------------------------------------------------------------- + + -- memory preload + IF (mem_file_name /= "none" AND UserPreload) THEN + ind := 0; + Mem := (OTHERS => MaxData); + WHILE (not ENDFILE (mem_file)) LOOP + READLINE (mem_file, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 7)); --address + IF ind > AddrRANGE THEN + ASSERT false + REPORT "Given preload address is out of" & + "memory address range" + SEVERITY warning; + END IF; + ELSE + IF ind <= AddrRANGE THEN + Mem(ind) := h(buf(1 to 2)); + END IF; + IF ind < AddrRANGE THEN + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + WAIT; + END PROCESS MemPreload; + + SO_OUT: PROCESS(SO_z) + + VARIABLE SO_GlitchData : VitalGlitchDataType; + BEGIN + VitalPathDelay01Z ( + OutSignal => SO, + OutSignalName => "SO", + OutTemp => SO_z, + GlitchData => SO_GlitchData, + XOn => XOn, + MsgOn => MsgOn, + Paths => ( + 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, + PathDelay => VitalExtendtofillDelay(tpd_SCK_SO), + PathCondition => SO_z /= 'Z'), + 1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, + PathDelay => tpd_CSNeg_SO, + PathCondition => CSNeg_ipd = '1'), + 2 => (InputChangeTime => HOLDNeg_ipd'LAST_EVENT, + PathDelay => tpd_HOLDNeg_SO, + PathCondition => TRUE) + ) + ); + END PROCESS SO_OUT; + + END BLOCK behavior; +END vhdl_behavioral; diff --git a/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_verilog.ftm b/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_verilog.ftm new file mode 100644 index 0000000..d1fe8c7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_verilog.ftm @@ -0,0 +1,52 @@ + +FMF Timing for s25fl064a Parts + + +version: | author: | mod date: | changes made: + V1.0 G.Gojanovic 05 May 13 Initial release + +1ns +s25fl064a + +S25Fl064A0LMAI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMFI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNAI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNFI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMAI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMFI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNAI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNFI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMAI003 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMFI003 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNAI003 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNFI003 s25fl064a_00_a0 April 26, 2005 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius +Comercial Ta=0 to +70 Celsius + + (DELAY (ABSOLUTE + + (IOPATH SCK SO (3:6:9) (3:6:9) () (3:6:9) () (3:6:9)) + (IOPATH HOLDNeg SO () () (4:7:10) (4:7:10) (4:7:10) (4:7:10)) + (IOPATH CSNeg SO () () (4:7:10) () (4:7:10) ()) +)) +(TIMINGCHECK + + (SETUP CSNeg SCK (5)) + (SETUP HOLDNeg SCK (5)) + (SETUP SI SCK (5)) + (SETUP WNeg CSNeg (15)) + + (HOLD CSNeg SCK (5)) + (HOLD HOLDNeg SCK (5)) + (HOLD SI SCK (5)) + (HOLD WNeg CSNeg (15)) + + (WIDTH (negedge SCK) (9)) + (WIDTH (posedge SCK) (9)) + (WIDTH (posedge CSNeg) (100)) + (PERIOD (COND fast_rd SCK) (20.0)) + (PERIOD (COND rd SCK) (40.0)) +) + + diff --git a/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_vhd.ftm b/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_vhd.ftm new file mode 100644 index 0000000..0cab2e7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/model/s25fl064a_vhd.ftm @@ -0,0 +1,65 @@ + +FMF Timing for s25fl064a Parts + + +version: | author: | mod date: | changes made: + V1.0 G.Gojanovic 05 May 11 Initial release + +1ns +s25fl064a + +S25Fl064A0LMAI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMFI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNAI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNFI000 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMAI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMFI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNAI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNFI001 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMAI003 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LMFI003 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNAI003 s25fl064a_00_a0 April 26, 2005 +S25Fl064A0LNFI003 s25fl064a_00_a0 April 26, 2005 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius +Comercial Ta=0 to +70 Celsius + + + (DELAY (ABSOLUTE + (IOPATH SCK SO (3:6:9) (3:6:9) () (3:6:9) () (3:6:9)) + (IOPATH HOLDNeg SO () () (4:7:10) (4:7:10) (4:7:10) (4:7:10)) + (IOPATH CSNeg SO () () (4:7:10) () (4:7:10) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (5)) + (SETUP HOLDNeg SCK (5)) + (SETUP SI SCK (5)) + (SETUP WNeg CSNeg (15)) + + (HOLD CSNeg SCK (5)) + (HOLD HOLDNeg SCK (5)) + (HOLD SI SCK (5)) + (HOLD WNeg CSNeg (15)) + + (WIDTH (negedge SCK) (9)) + (WIDTH (posedge SCK) (9)) + (WIDTH (posedge CSNeg) (100)) + (PERIOD (COND fast_rd SCK) (20.0)) + (PERIOD (COND rd SCK) (40.0)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1000000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(1e9:15e8:3e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(128e9:192e9:384e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE (DEVICE(60000000:60000000:60000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(10000000:10000000:10000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(3000:3000:3000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --CFI query identification string + CFI_array(16#10#) := 16#51#; + CFI_array(16#11#) := 16#52#; + CFI_array(16#12#) := 16#59#; + CFI_array(16#13#) := 16#02#; + CFI_array(16#14#) := 16#00#; + CFI_array(16#15#) := 16#40#; + CFI_array(16#16#) := 16#00#; + CFI_array(16#17#) := 16#00#; + CFI_array(16#18#) := 16#00#; + CFI_array(16#19#) := 16#00#; + CFI_array(16#1A#) := 16#00#; + --system interface string + CFI_array(16#1B#) := 16#27#; + CFI_array(16#1C#) := 16#36#; + CFI_array(16#1D#) := 16#00#; + CFI_array(16#1E#) := 16#00#; + CFI_array(16#1F#) := 16#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + CFI_array(16#35#) := 16#00#; + CFI_array(16#36#) := 16#00#; + CFI_array(16#37#) := 16#00#; + CFI_array(16#38#) := 16#00#; + CFI_array(16#39#) := 16#00#; + CFI_array(16#3A#) := 16#00#; + CFI_array(16#3B#) := 16#00#; + CFI_array(16#3C#) := 16#00#; + --primary vendor-specific extended query + CFI_array(16#40#) := 16#50#; + CFI_array(16#41#) := 16#52#; + CFI_array(16#42#) := 16#49#; + CFI_array(16#43#) := 16#31#; + CFI_array(16#44#) := 16#33#; + CFI_array(16#45#) := 16#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl064a/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl064a/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl064a/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064a/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils; diff --git a/lib/models/memory/flash/serial/S25fl064k/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl064k/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl064k/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl064k/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 vital-amd-serial-s25fl-REL-s25fl064k-2010-09-07-1.tar.gz +# Release Date (DD/MM/YYYY) => 07/09/2010 +# Release Version => 1.0 + +########################################## +VITAL model author - Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl064k-2010-09-08-2.tar.gz +# Release Date (DD/MM/YYYY) => 08/09/2010 +# Release Version => 1.1 + +# Corrections: +# Documentation added. +# Write Enable for Volatile Status register Instruction implemented. +# Test for Write Enable for Volatile Status register instruction. + +# Files modified +-s25fl064.v +-testbench_s25fl064k_verilog.vhd +-spansion_tc_pkg.vhd +########################################## +VITAL model author - Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl064k-2010-09-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/09/2010 +# Release Version => 1.2 + +# Corrections: +# VHDL model added +# Read ID instruciton (ABh) also can be issued when device is not in deep power down mode +# bus_cycle section for WRR command is changed +# path delay conditions modified + +# Files modified +-s25fl064.v +-testbench_s25fl064k_verilog.vhd +-spansion_tc_pkg.vhd +-s25fl064k.ftmv +-s25fl064k_verilog.sdf +########################################## +VITAL model author - Ranko Prokopovic + r-prokopovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl064k-2010-09-17-1.tar.gz +# Release Date (DD/MM/YYYY) => 17/09/2010 +# Release Version => 1.3 + +# Corrections: +# Line "define SPEEDSIM" in Verilog model was left commented, and testbench had parameter +# 'LongTimming' set on FALSE +# some unnecessary lines were removed + +# Files modified +-s25fl064.v +-testbench_s25fl064k_verilog.vhd +-s25fl064k.vhd +-testbench_s25fl064k_vhdl.vhd +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +# Release Label => vital-amd-serial-s25fl-REL-s25fl064k-2012-06-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/06/2012 +# Release Version => 1.4 + +# Corrections: +# Corrected functionality for sector and block erase and page program operation + +# Files modified +-s25fl064k.vhd +########################################## \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.v b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.v new file mode 100644 index 0000000..4d54f4c --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl064k/model/s25fl064k.v @@ -0,0 +1,4219 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl064k.v +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2010 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 R.Prokopovic 03 Aug 10 Initial +// +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL064K +// +// Description: 64 Megabit Serial Flash Memory +// +/////////////////////////////////////////////////////////////////////////////// +// Comments : +// +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl064k + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + HOLDNeg, + WPNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + inout SI ; + inout SO ; + input SCK ; + input CSNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + // ***** internal delays ********************* + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGRES_out ; + reg ERSRES_out ; + reg PRGRES_in ; + reg ERSRES_in ; + reg WRR_in ; + reg WRR_out ; + reg DP_in ; + reg DP_out ; + reg RES_in ; + reg RES_out ; + // ******* event control registers ************ + reg PRGSUSP_out_event; + reg PRGRES_out_event; + reg ERSSUSP_out_event; + reg ERSRES_out_event; + reg PGSUSP_event; + reg PGRES_event; + reg ESUSP_event; + reg ERES_event; + reg next_state_event; + + reg rising_edge_PoweredUp; + reg rising_edge_RES_out; + reg rising_edge_PRGRES_out; + reg rising_edge_PSTART; + reg rising_edge_WSTART; + reg rising_edge_VLTSTART; + reg rising_edge_ESTART; + reg rising_edge_prot_bits; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl064k.mem"; + parameter screg_file_name = "s25fl064kscreg.mem";//"none"; + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl064k"; + parameter MaxData = 255; + parameter AddrRANGE = 24'h7FFFFF; + parameter PageNum = 16'h7FFF; + parameter SecSize_4 = 12'hFFF; + parameter SecSize_32 = 16'h7FFF; + parameter SecSize_64 = 16'hFFFF; + parameter Blk_4_Num = 2047; + parameter Blk_64_Num = 127; + parameter Blk_32_Num = 255; + parameter SFDP_HiAddr = 8'hFF; + parameter SFDP_LoAddr = 8'h00; + parameter SecReg_HiAddr = 8'hFF; + parameter SecReg_LoAddr = 8'h00; + parameter SCREG_LoAddr = 12'h000; + parameter SCREG_HiAddr = 12'h2FF; + parameter BYTE = 8; + + // Manufacturer Identification and Device Identification + parameter Manuf_ID = 8'hEF; + parameter Device_ID1 = 8'h16; + parameter Device_ID2 = 8'h40; + parameter Device_ID3 = 8'h17; + parameter unique_id = 64'h000000000000ABAB; + + // If speedsimulation is needed uncomment following line + + `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; +// reg ERSRES ; + + reg WDONE ; + reg WSTART ; + reg VLTSTART ; + reg VLTDONE ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + + // Programming buffer + integer WByte[0:255]; + + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRP0; + wire SEC; + wire TB; + wire BP2; + wire BP1; + wire BP0; + wire WEL; + wire BUSY; + assign SRP0 = Status_reg1[7]; + assign SEC = Status_reg1[6]; + assign TB = Status_reg1[5]; + assign BP2 = Status_reg1[4]; + assign BP1 = Status_reg1[3]; + assign BP0 = Status_reg1[2]; + assign WEL = Status_reg1[1]; + assign BUSY = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire SUS; + wire CMP; +// wire LB3; +// wire LB2; +// wire LB1; + wire [2:0]LB; + wire QE; + wire SRP1; + assign SUS = Status_reg2[7]; + assign CMP = Status_reg2[6]; + assign LB = Status_reg2[5:3]; +// assign LB2 = Status_reg2[4]; +// assign LB1 = Status_reg2[3]; + assign QE = Status_reg2[1]; + assign SRP1 = Status_reg2[0]; + + reg[15:0] Status_reg; // Status_reg2 & Status_reg1 + reg[15:0] Status_reg_in; // Status_reg2 & Status_reg1 + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [Blk_4_Num:0] Sec_Prot = {2048{1'b0}}; + + // Security registers array + integer Security_Reg[SCREG_LoAddr:SCREG_HiAddr]; + integer Security_Reg1[SecReg_LoAddr:SecReg_HiAddr]; + integer Security_Reg2[SecReg_LoAddr:SecReg_HiAddr]; + integer Security_Reg3[SecReg_LoAddr:SecReg_HiAddr]; + + // SFDP register array + integer SFDP_array[SFDP_LoAddr:SFDP_HiAddr]; + + /////////////////////////////////////////////////////////////////////////// + // Command Register + reg write; + reg read_out; + reg slow_read; + reg dual_read; + reg fast_read; + reg quad_read; + reg pp_quad; + reg oe = 1'b0; + event oe_event; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + integer wr_cnt; + integer cnt; + integer Byte_number = 0; + integer read_cnt = 0; + integer read_addr = 0; + reg[7:0] data_out; + reg[23:0] ident_out; + reg[15:0] ident_out2; + integer AddrLo; + integer AddrHi; + integer AddrLo_ers; + integer AddrHi_ers; + integer AddrLo_wrap; + integer AddrHi_wrap; + + reg change_prot_bits = 0; + + //Address + integer Address = 0; // 0 - AddrRANGE + reg change_addr; + + //Sector and subsector addresses + integer SA = 0; + integer sect; + integer sect_tmp_pg; + integer sect_tmp_ers; + integer sfdp_addr; + integer w_size; +// integer w_size; + + reg hold_mode = 1'b0; + + // Flag for release from deep power down, read ID or not + reg res_flag; + reg pg_screg_flag = 1'b0; + reg ers_screg_flag = 1'b0; + reg wren_vlt_flag = 1'b0; + reg susp_flag = 1'b0; + // timing check violation + reg Viol = 1'b0; + reg sr_read = 1'b0; + reg read_id = 1'b0; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + //VHDL VITAL CheckEnable equivalents + wire rd_slow; + assign rd_slow = slow_read; + wire rd_fast; + assign rd_fast = fast_read; + wire quad_rd; + assign quad_rd = deg_holdin && QE && ~dual_read && (SIOut_z != 1'bz); + wire quad_pg; + assign quad_pg = QE && WEL && pp_quad; + wire wr_prot; + assign wr_prot = SRP0 && WEL; + wire dual_rd; + assign dual_rd = dual_read ; + wire power; + assign power = PoweredUp; + wire hold_cond; + assign hold_cond = PoweredUp && ~QE; + wire any_read; + assign any_read = (dual_read || quad_read || slow_read || fast_read) + && ~WEL && ~sr_read; + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SIOut_z !== 1'bZ) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + assign deg_sin = deq_sin; /*&& (~any_read);*/ + + wire pg_ers; + assign pg_ers = PSTART || ESTART || sr_read; + +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_1 =1; // tCLQV1 + specparam tpd_SCK_SO_2 =1; // tCLQV2 -for read ID instructions + specparam tpd_CSNeg_SO =1; // tSHQZ (tDIS) + specparam tpd_HOLDNeg_SO =1; // tHLQZ, tHHQX + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; // tSLCH, tSHCH + specparam tsetup_SI_SCK =1; // tDVCH + specparam tsetup_HOLDNeg_SCK =1; // tHLCH, tHHCH + specparam tsetup_WPNeg_CSNeg =1; // tWHSL + + //thold values: hold times + specparam thold_CSNeg_SCK =1; // tCHSL, tCHSH + specparam thold_SI_SCK =1; // tCHDX + specparam thold_HOLDNeg_SCK =1; // tCHHL, tCHHH + specparam thold_WPNeg_CSNeg =1; // tSHWL + + // tpw values: pulse width + specparam tpw_SCK_slow_posedge =1; // tCH + specparam tpw_SCK_slow_negedge =1; // tCL + specparam tpw_SCK_fast_posedge =1; // tCH + specparam tpw_SCK_fast_negedge =1; // tCL + specparam tpw_CSNeg_read_posedge =1; // tSHSL1 + specparam tpw_CSNeg_pger_posedge =1; // tSHSL2 + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_slow =1; + specparam tperiod_SCK_fast =1; + + // tdevice values: values for internal delays + + // VCC (min) to CS# Low + specparam tdevice_PU = 1e7; // 10 us + // CS# High to Power Down Mode -- tDP + specparam tdevice_DP = 3e6; // 3 us + // CS# High to StandBy mode without Electronic Signature read + specparam tdevice_RES1 = 3e6; // 3 us + // CS# High to StandBy mode with Electronic Signature read + specparam tdevice_RES2 = 18e5; // 1.8 us + // CS# High to next Instruction after Suspend + specparam tdevice_SUS = 2e7; // 20 us + // Resume Suspend to Program/Erase time + specparam tdevice_PRGSUSP = 2e5; // 200 ns + + `ifdef SPEEDSIM + // Page Program Time + specparam tdevice_PP = 3e8; // 30 us + // Byte Program Time (First Byte) + specparam tdevice_BP1 = 5e5; // 0.5 us + // Additional Byte Program Time (After First Byte) + specparam tdevice_BP2 = 12e4; // 120 ns + // Sector Erase Time (4KB) + specparam tdevice_SE = 4e9; // 4 ms + // Block Erase Time (32KB) + specparam tdevice_BE1 = 8e9; // 8 ms + // Block Erase Time (64KB) + specparam tdevice_BE2 = 1e10; // 10 ms + // Chip Erase Time + specparam tdevice_CE = 3e11; // 300 ms + // Write Status Register Time + specparam tdevice_WRR = 15e7; // 150 us + // Write Volatile Status Register Time + specparam tdevice_VRR = 5e4; // 50 ns + `else + // Page Program Time + specparam tdevice_PP = 3e9; // 3 ms + // Byte Program Time (First Byte) + specparam tdevice_BP1 = 5e7; // 50 us + // Additional Byte Program Time (After First Byte) + specparam tdevice_BP2 = 12e6; // 12 us + // Sector Erase Time (4KB) + specparam tdevice_SE = 4e11; // 400 ms + // Block Erase Time (32KB) + specparam tdevice_BE1 = 8e11; // 800 ms + // Block Erase Time (64KB) + specparam tdevice_BE2 = 1e12; // 1000 ms + // Chip Erase Time + specparam tdevice_CE = 3e13; // 30 s + // Write Status Register Time + specparam tdevice_WRR = 15e9; // 15 ms + // Write Volatile Status Register Time + specparam tdevice_VRR = 5e4; // 50 ns + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~read_id) (SCK => SO) = tpd_SCK_SO_1; + if (read_id) (SCK => SO) = tpd_SCK_SO_2; + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (~quad_read) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (dual_read || quad_read) (SCK => SI) = tpd_SCK_SO_1; + if (CSNeg && ~deg_sin) (CSNeg => SI) = tpd_CSNeg_SO; + if (~quad_read && dual_read) (HOLDNeg => SI) = tpd_HOLDNeg_SO; +// if (QE) (SCK => SI) = tpd_SCK_SO_1; + if (quad_read) (SCK => WPNeg) = tpd_SCK_SO_1; + if (quad_read) (SCK => HOLDNeg) = tpd_SCK_SO_1; + if (CSNeg && QE) (CSNeg => SI) = tpd_CSNeg_SO; + if (CSNeg && QE) (CSNeg => WPNeg) = tpd_CSNeg_SO; + if (CSNeg && QE) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& power, + tsetup_CSNeg_SCK , Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK , Viol); + $setup ( SO , posedge SCK &&& quad_pg, + tsetup_SI_SCK , Viol); + $setup ( WPNeg , posedge SCK &&& quad_pg, + tsetup_SI_SCK , Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_pg, + tsetup_SI_SCK , Viol); + $setup ( HOLDNeg , posedge SCK &&& hold_cond, + tsetup_HOLDNeg_SCK , Viol); + $setup ( WPNeg , negedge CSNeg &&& WPNeg, + tsetup_WPNeg_CSNeg , Viol); + + $hold ( posedge SCK &&& power, CSNeg, + thold_CSNeg_SCK , Viol); + $hold ( posedge SCK &&& deg_sin, SI , + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& quad_pg, SO , + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& quad_pg, WPNeg, + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& quad_pg, HOLDNeg, + thold_SI_SCK , Viol); + $hold ( posedge SCK &&& hold_cond, HOLDNeg, + thold_HOLDNeg_SCK, Viol); + $hold ( posedge CSNeg &&& wr_prot, WPNeg, + thold_WPNeg_CSNeg, Viol); + + $width ( posedge SCK &&& rd_slow , tpw_SCK_slow_posedge); + $width ( negedge SCK &&& rd_slow , tpw_SCK_slow_negedge); + $width ( posedge SCK &&& rd_fast , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& rd_fast , tpw_SCK_fast_negedge); + $width ( posedge CSNeg &&& any_read , tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& pg_ers , tpw_CSNeg_pger_posedge); + + $period ( posedge SCK &&& rd_slow , tperiod_SCK_slow); + $period ( posedge SCK &&& rd_fast , tperiod_SCK_fast); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 4'd0; + parameter WRITE_SR = 4'd1; + parameter PAGE_PG = 4'd2; + parameter PG_SUSP = 4'd3; + parameter SECTOR_ERS = 4'd4; + parameter BULK_ERS = 4'd5; + parameter ERS_SUSP = 4'd6; + parameter ERS_SUSP_PG = 4'd7; + parameter PG_SUSP_ERS = 4'd8; + parameter DP_DOWN = 4'd9; + parameter WRITE_SR_V = 4'd10; + + reg [3:0] current_state; + reg [3:0] next_state; + +// Instruction type + parameter NONE = 6'd0; + parameter WREN = 6'd1; // 06h + parameter WRENV = 6'd2; // 50h + parameter WRDI = 6'd3; // 04h + parameter RDSR = 6'd4; // 05h + parameter RDSR2 = 6'd5; // 35h + parameter WRR = 6'd6; // 01h + parameter READ = 6'd7; // 03h + parameter FAST_READ = 6'd8; // 0Bh + parameter FAST_DREAD = 6'd9; // 3Bh + parameter FAST_QREAD = 6'd10; // 6Bh + parameter FAST_DREAD_2 = 6'd11; // BBh + parameter FAST_QREAD_4 = 6'd12; // EBh + parameter W_QREAD = 6'd13; // E7h + parameter WOCT_QREAD = 6'd14; // E3h + parameter SET_BURST_WRAP = 6'd15; // 77h + parameter CONT_RD_RST = 6'd16; // FFh or FFFFH + parameter PP = 6'd17; // 02h + parameter QPP = 6'd18; // 32h + parameter SE = 6'd19; // 20h + parameter BE_32 = 6'd20; // 52h + parameter BE_64 = 6'd21; // D8h + parameter CE = 6'd22; // C7h or 60h + parameter ERS_PG_SUSP = 6'd23; // 75h + parameter ERS_PG_RES = 6'd24; // 7Ah + parameter DP = 6'd25; // B9h + parameter RES_RD_ID = 6'd26; // ABh + parameter RDID = 6'd27; // 90h + parameter RDID_DUAL = 6'd28; // 92h + parameter RDID_QUAD = 6'd29; // 94h + parameter RD_UNIQ_ID = 6'd30; // 4Bh + parameter RDIDJ = 6'd31; // 9Fh + parameter RD_SFDP = 6'd32; // 5Ah + parameter ERS_SCREG = 6'd33; // 44h + parameter PG_SCREG = 6'd34; // 42h + parameter RD_SCREG = 6'd35; // 48h + + reg [5:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + always @(PoweredUp or falling_edge_CSNeg_ipd) + begin:CheckCEOnPowerUP + if ((~PoweredUp) && falling_edge_CSNeg_ipd) + $display ("Device is selected during Power Up"); + end + + initial + begin : Init + write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; +// cnt = 0; + PGSUSP = 1'b0; + PGRES = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + PDONE = 1'b1; + PSTART = 1'b0; + EDONE = 1'b1; + ESTART = 1'b0; + WDONE = 1'b1; + WSTART = 1'b0; + VLTDONE = 1'b1; + VLTSTART = 1'b0; + + DP_in = 1'b0; + DP_out = 1'b0; + RES_in = 1'b0; + RES_out = 1'b0; + PRGRES_in = 1'b0; + ERSRES_in = 1'b0; + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl064k.mem, memory preload file + // @aaaaaa - stands for address + // dd -