+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity assert_pulsewidth is
- generic (
- LEVEL: std_logic := '1';
- T_MIN: time := time'low;
- T_MAX: time := time'high;
- NAME: string := "<sig>"
- );
- port (
- sig: in std_logic
- );
-end assert_pulsewidth;
-
-
-architecture behavioral of assert_pulsewidth is
-begin
-
- process (sig)
- variable width: time;
- begin
- -- Detect the end of a pulse of type LEVEL
- if sig /= LEVEL and sig'last_value = LEVEL then
- -- Delayed by a delta cycle since sig'last_event is now
- width := sig'delayed'last_event;
-
- assert width <= T_MAX
- report "Maximum " & std_logic'image(LEVEL) & " pulse width violation for '" & NAME &
- "' (width: " & time'image(width) & ", max: " & time'image(T_MAX) & ")"
- severity error;
-
- assert width >= T_MIN
- report "Minimum " & std_logic'image(LEVEL) & " pulse width violation for '" & NAME &
- "' (width: " & time'image(width) & ", min: " & time'image(T_MIN) & ")"
- severity error;
- end if;
- end process;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity assert_setuphold is
- generic (
- LEVEL: std_logic := '1';
- T_SETUP: time := time'low;
- T_HOLD: time := time'low;
- NAME_REF: string := "<ref>";
- NAME_SIG: string := "<sig>"
- );
- port (
- ref: in std_logic; -- Reference signal for setup/hold times, e.g. clock
- sig: in std_logic
- );
-end assert_setuphold;
-
-
-architecture behavioral of assert_setuphold is
-begin
-
- process (ref, sig)
- -- Absolute time of most recent edge-of-interest
- -- Initial value is negative so hold checks can be skipped if "sig" changes before "ref"
- variable last_edge: time := -1 ps;
-
- variable setup_time: time;
- variable hold_time: time;
- begin
- -- Detect edges where "ref" transitions to LEVEL
- if ref'event and ref = LEVEL then
- -- Keep track of the last edge for the hold time test
- -- Normally I hate that variables retain values between process invocations, but here it's useful!
- last_edge := now;
-
- -- If sig changed at same time as ref, assume its new value is not the value being referenced by the edge
- -- (Allow the hold-time constraint to catch problems there)
- setup_time := sig'last_event;
- if setup_time = 0 ns then
- setup_time := sig'delayed'last_event;
- end if;
-
- -- Check setup time constraint unless this is the beginning of the simulation
- if now > 0 ps then
- assert setup_time >= T_SETUP
- report "Setup time to '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
- " (actual: " & time'image(setup_time) & ", required: " & time'image(T_SETUP) & ")"
- severity error;
- end if;
- end if;
-
- -- Detect changes in "sig" but only if "ref" has had an edge before
- if sig'event and last_edge > 0 ps then
- -- Checking against ref'last_event is tempting, but it might catch the wrong kind of transition
- hold_time := now - last_edge;
-
- -- Check hold time constraint
- assert hold_time >= T_HOLD
- report "Hold time from '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
- " (actual: " & time'image(hold_time) & ", required: " & time'image(T_HOLD) & ")"
- severity error;
- end if;
- end process;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity assert_setuphold_vec is
- generic (
- LEVEL: std_logic := '1';
- T_SETUP: time := time'low;
- T_HOLD: time := time'low;
- NAME_REF: string := "<ref>";
- NAME_SIG: string := "<sig>"
- );
- port (
- ref: in std_logic; -- Reference signal for setup/hold times, e.g. clock
- sig: in std_logic_vector
- );
-end assert_setuphold_vec;
-
-
-architecture behavioral of assert_setuphold_vec is
-begin
-
- process (ref, sig)
- -- Absolute time of most recent edge-of-interest
- -- Initial value is negative so hold checks can be skipped if "sig" changes before "ref"
- variable last_edge: time := -1 ps;
-
- variable setup_time: time;
- variable hold_time: time;
- begin
- -- Detect edges where "ref" transitions to LEVEL
- if ref'event and ref = LEVEL then
- -- Keep track of the last edge for the hold time test
- -- Normally I hate that variables retain values between process invocations, but here it's useful!
- last_edge := now;
-
- -- If sig changed at same time as ref, assume its new value is not the value being referenced by the edge
- -- (Allow the hold-time constraint to catch problems there)
- setup_time := sig'last_event;
- if setup_time = 0 ns then
- setup_time := sig'delayed'last_event;
- end if;
-
- -- Check setup time constraint unless this is the beginning of the simulation
- if now > 0 ps then
- assert setup_time >= T_SETUP
- report "Setup time to '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
- " (actual: " & time'image(setup_time) & ", required: " & time'image(T_SETUP) & ")"
- severity error;
- end if;
- end if;
-
- -- Detect changes in "sig" but only if "ref" has had an edge before
- if sig'event and last_edge > 0 ps then
- -- Checking against ref'last_event is tempting, but it might catch the wrong kind of transition
- hold_time := now - last_edge;
-
- -- Check hold time constraint
- assert hold_time >= T_HOLD
- report "Hold time from '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
- " (actual: " & time'image(hold_time) & ", required: " & time'image(T_HOLD) & ")"
- severity error;
- end if;
- end process;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity changed_within_t is
- generic (
- T: time := 0 ns;
- T_HOLD: time := 0 ns
- );
- port (
- sig_in: in std_logic;
- sig_out: out std_logic
- );
-end changed_within_t;
-
-
-architecture behavioral of changed_within_t is
- signal sig: std_logic := '1';
-begin
-
- sig <= '1' after T_HOLD when not sig_in'stable(T - T_HOLD) else '0' after T_HOLD;
- sig_out <= sig;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity changed_within_t_vec is
- generic (
- T: time := 0 ns;
- T_HOLD: time := 0 ns
- );
- port (
- sig_in: in std_logic_vector;
- sig_out: out std_logic
- );
-end changed_within_t_vec;
-
-
-architecture behavioral of changed_within_t_vec is
- signal sig: std_logic := '1';
-begin
-
- sig <= '1' after T_HOLD when not sig_in'stable(T - T_HOLD) else '0' after T_HOLD;
- sig_out <= sig;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity delay_edges is
- generic (
- D_RISE: time := 0 ns;
- D_FALL: time := 0 ns
- );
- port (
- sig_in: in std_logic;
- sig_out: out std_logic
- );
-end delay_edges;
-
-architecture behavioral of delay_edges is
- signal mask: std_logic;
-begin
-
- process (sig_in)
- begin
- if mask = 'U' then
- mask <= sig_in;
- end if;
- if sig_in'event and sig_in = '1' then
- mask <= '1' after D_RISE;
- end if;
- if sig_in'event and sig_in = '0' then
- mask <= '0' after D_FALL;
- end if;
- end process;
- sig_out <= mask;
-
-end behavioral;
-
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+entity genericmem is
+ generic (
+ INIT: std_logic_vector(32*8-1 downto 0) := (others => '0')
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ cyc_i: in std_logic;
+ stb_i: in std_logic;
+ we_i: in std_logic;
+ ack_o: out std_logic;
+ adr_i: in std_logic_vector(4 downto 0);
+ dat_i: in std_logic_vector(7 downto 0);
+ dat_o: out std_logic_vector(7 downto 0)
+ );
+end genericmem;
+
+
+architecture behavioral of genericmem is
+
+ type mem_array_t is array(natural range <>) of std_logic_vector(7 downto 0);
+
+ signal mem_array: mem_array_t(31 downto 0);
+
+begin
+
+ process (rst_i, clk_i, cyc_i, stb_i, we_i, adr_i, dat_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ for i in 0 to 31 loop
+ mem_array(31-i) <= INIT((i+1)*8-1 downto i*8);
+ end loop;
+ elsif cyc_i = '1' and stb_i = '1' and we_i = '1' then
+ mem_array(to_integer(unsigned(adr_i))) <= dat_i;
+ end if;
+ end if;
+ end process;
+
+ ack_o <= '1';
+ dat_o <= mem_array(to_integer(unsigned(adr_i)));
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.sim_utility.all;
+
+
+entity js28f128j3d75 is
+ generic (
+ FILENAME: string := "";
+ BASEADDR: natural := 0
+ );
+ port (
+ a: in std_logic_vector(23 downto 0);
+ d: inout std_logic_vector(15 downto 0);
+ ce: in std_logic_vector(2 downto 0);
+ rp_n: in std_logic;
+ oe_n: in std_logic;
+ we_n: in std_logic;
+ sts: out std_logic; -- open drain
+ byte_n: in std_logic;
+ vpen: in std_logic
+ );
+end js28f128j3d75;
+
+
+architecture behavioral of js28f128j3d75 is
+ ----------------------------------------------------------------------------
+ -- Timings for 128Mbit, J3D-75 parts
+
+ -- Read timings
+ constant T_AVAV: time := 75 ns; -- R1, Read/Write Cycle Time
+ constant T_AVQV: time := 75 ns; -- R2, Address to Output Delay
+ constant T_ELQV: time := 75 ns; -- R3, CEx to Output Delay
+ constant T_GLQV_NA: time := 25 ns; -- R4, OE# to Non-Array Output Delay
+ constant T_PHQV: time := 210 ns; -- R5, RP# High to Output Delay
+ constant T_ELQX: time := 0 ns; -- R6, CEx to Output Low Z
+ constant T_GLQX: time := 0 ns; -- R7, OE# to Output Low Z
+ constant T_EHQZ: time := 25 ns; -- R8, CEx High to Output in High Z
+ constant T_GHQZ: time := 15 ns; -- R9, OE# High to Output in High Z
+ constant T_OH: time := 0 ns; -- R10, Output Hold from Address, CEx, or OE# change
+ constant T_ELFL: time := 10 ns; -- R11, CEx Low to BYTE# High or Low
+ constant T_ELFH: time := 10 ns; -- R11, (Same as Above)
+ constant T_FLQV: time := 1 us; -- R12, BYTE# to Output Delay
+ constant T_FHQV: time := 1 us; -- R12, (Same as Above)
+ constant T_FLQZ: time := 1 us; -- R13, BYTE# to Output in High Z
+ constant T_EHEL: time := 0 ns; -- R14, CEx High to CEx Low
+ constant T_APA: time := 25 ns; -- R15, Page Address Access Time
+ constant T_GLQV_A: time := 25 ns; -- R16, OE# to Array Output Delay
+
+ -- Write timings
+ constant T_PHWL: time := 210 ns; -- W1, RP# High Recovery to WE# (CEx) Going Low
+ constant T_PHEL: time := 210 ns; -- W1, (Same as Above)
+ constant T_ELWL: time := 0 ns; -- W2, CEx (WE#) Low to WE# (CEx) Going Low
+ constant T_WLEL: time := 0 ns; -- W2, (Same as Above)
+ constant T_WP: time := 60 ns; -- W3, Write Pulse Width
+ constant T_DVWH: time := 50 ns; -- W4, Data Setup to WE# (CEx) Going High
+ constant T_DVEH: time := 50 ns; -- W4, (Same as Above)
+ constant T_AVWH: time := 55 ns; -- W5, Address Setup to WE# (CEx) Going High
+ constant T_AVEH: time := 55 ns; -- W5, (Same as Above)
+ constant T_WHEH: time := 0 ns; -- W6, CEx (WE#) Hold from WE# (CEx) High
+ constant T_EHWH: time := 0 ns; -- W6, (Same as Above)
+ constant T_WHDX: time := 0 ns; -- W7, Data Hold from WE# (CEx) High
+ constant T_EHDX: time := 0 ns; -- W7, (Same as Above)
+ constant T_WHAX: time := 0 ns; -- W8, Address Hold from WE# (CEx) High
+ constant T_EHAX: time := 0 ns; -- W8, (Same as Above)
+ constant T_WPH: time := 30 ns; -- W9, Write Pulse Width High
+ constant T_VPWH: time := 0 ns; -- W11, Vpen Setup to WE# (CEx) Going High
+ constant T_VPEH: time := 0 ns; -- W11, (Same as Above)
+ constant T_WHGL: time := 35 ns; -- W12, Write Recovery before Read
+ constant T_EHGL: time := 35 ns; -- W12, (Same as Above)
+ constant T_WHRL: time := 500 ns; -- W13, WE# (CEx) High to STS Going Low
+ constant T_EHRL: time := 500 ns; -- W13, (Same as Above)
+ constant T_QVVL: time := 0 ns; -- W15, Vpen Hold from Valid SRD, STS Going High
+
+ -- Configuration timings
+ constant T_WHQV3: time := 175 us; -- W16, Byte Program Time (Using Word/Byte Program Command)
+ constant T_EHQV3: time := 175 us; -- W16, (Same as above)
+ constant T_WHQV4: time := 4 sec; -- W16, Block Erase Time
+ constant T_EHQV4: time := 4 sec; -- W16, (Same as above)
+ constant T_WHQV5: time := 60 us; -- W16, Set Lock-Bit Time
+ constant T_EHQV5: time := 60 us; -- W16, (Same as above)
+ constant T_WHQV6: time := 0.7 sec; -- W16, Clear Block Lock-Bits Time
+ constant T_EHQV6: time := 0.7 sec; -- W16, (Same as above)
+ constant T_WHRH1: time := 20 us; -- W16, Program Suspend Latency Time to Read
+ constant T_EHRH1: time := 20 us; -- W16, (Same as above)
+ constant T_WHRH: time := 20 us; -- W16, Erase Suspend Latency Time to Read
+ constant T_EHRH: time := 20 us; -- W16, (Same as above)
+ constant T_STS: time := 500 ns; -- WY, STS Pulse Width Low Time
+
+ -- Reset timings
+ constant T_PLPH: time := 25 us; -- P1, RP# Pulse Low Time
+ constant T_PHRH: time := 100 ns; -- P2, RP# High to Reset During Block-Erase, Program, or Lock-Bit Configuration
+ constant T_VCCPH: time := 60 us; -- P3, Vcc Power Valid to RP# de-assertion (high)
+
+ ----------------------------------------------------------------------------
+ -- Useful internal signals
+
+ signal internal_ce_n: std_logic;
+ signal internal_we_n: std_logic;
+
+ ----------------------------------------------------------------------------
+ -- Array value
+
+ shared variable flash_array: sparse_t;
+ signal array_word: std_logic_vector(15 downto 0);
+
+ ----------------------------------------------------------------------------
+ -- Device Information
+
+ signal id_word: std_logic_vector(15 downto 0);
+
+ ----------------------------------------------------------------------------
+ -- Status Register
+
+ signal sts_word: std_logic_vector(15 downto 0);
+
+ signal sts_ready: std_logic;
+ signal sts_susp_erase: std_logic;
+ signal sts_error_erase: std_logic;
+ signal sts_error_prog: std_logic;
+ signal sts_error_vpen: std_logic;
+ signal sts_susp_prog: std_logic;
+ signal sts_error_lock: std_logic;
+
+ ----------------------------------------------------------------------------
+ -- CFI Query
+
+ signal cfi_word: std_logic_vector(15 downto 0);
+
+ ----------------------------------------------------------------------------
+ -- Output value
+
+ type read_state_t is (R_ARRAY, R_ID, R_STATUS, R_CFI);
+ signal read_state_cur: read_state_t;
+
+ signal word: std_logic_vector(15 downto 0);
+ signal word_x: std_logic_vector(15 downto 0);
+ signal word_xz: std_logic_vector(15 downto 0);
+
+ signal xmask_rp: std_logic;
+ signal xmask_byte: std_logic;
+ signal xmask_ce: std_logic;
+ signal xmask_oe: std_logic;
+ signal xmask_addr_h: std_logic;
+ signal xmask_addr_l: std_logic;
+
+ signal zmask_ce: std_logic;
+ signal zmask_oe: std_logic;
+ signal zmask_byte: std_logic;
+
+ ----------------------------------------------------------------------------
+ -- Other registers
+
+ signal ecr_reg: std_logic_vector(23 downto 0);
+ signal sts_config_reg: std_logic_vector(7 downto 0);
+
+ ----------------------------------------------------------------------------
+ -- CUI state machine
+
+ type cui_state_t is (
+ C_IDLE,
+ C_PROG_STS,
+ C_PROG_OTP,
+ C_PROG_WORD,
+ C_PROG_BUF_COUNT,
+ C_PROG_BUF_DATA,
+ C_ERASE,
+ C_LOCK_OR_ECR
+ );
+
+ signal cui_state_cur: cui_state_t;
+
+ ----------------------------------------------------------------------------
+ -- Write state machine
+
+ type wsm_state_t is (
+ W_IDLE,
+ W_PROG_OTP,
+ W_PROG_WORD,
+ W_PROG_WORD_FINISH,
+ W_PROG_BUF,
+ W_ERASE,
+ W_ERASE_FINISH,
+ W_LOCK,
+ W_UNLOCK
+ );
+
+ signal wsm_state_cur: wsm_state_t;
+
+ signal trig_clrsts: std_logic;
+ signal trig_susp: std_logic;
+ signal trig_resume: std_logic;
+ signal trig_cmderr: std_logic;
+ signal trig_otp: std_logic;
+ signal trig_word: std_logic;
+ signal trig_buf: std_logic;
+ signal trig_erase: std_logic;
+ signal trig_lock: std_logic;
+ signal trig_unlock: std_logic;
+
+ signal prog_word: std_logic_vector(15 downto 0);
+ signal prog_addr: std_logic_vector(23 downto 0);
+ signal erase_addr: std_logic_vector(23 downto 0);
+ signal lock_addr: std_logic_vector(23 downto 0);
+ signal unlock_addr: std_logic_vector(23 downto 0);
+
+begin
+
+ ----------------------------------------------------------------------------
+ -- Useful internal signals composed from external signals
+
+ -- Decode multiple chip enable inputs into single chip enable signal
+ with ce select internal_ce_n <=
+ '0' when "000",
+ '1' when "001",
+ '1' when "010",
+ '1' when "011",
+ '0' when "100",
+ '0' when "101",
+ '0' when "110",
+ '1' when "111",
+ 'X' when others;
+
+ -- Write latch is triggered by either WEx or CEx going high, whichever is first
+ internal_we_n <= we_n or internal_ce_n;
+
+ -- STS signal represents the state of the WSM
+ sts <= 'H' when sts_ready = '1' else '0';
+
+
+ ----------------------------------------------------------------------------
+ -- Array value
+
+ process
+ begin
+ if FILENAME = "" then
+ flash_array := sparse_create(default => x"FF");
+ else
+ flash_array := sparse_create;
+ sparse_load(flash_array, FILENAME, BASEADDR);
+ end if;
+ wait;
+ end process;
+
+ process (a, sts_ready)
+ begin
+ -- sts_ready is in the sensitivity list because flash_array is a variable and cannot be
+ array_word <= sparse_get(flash_array, to_integer(unsigned(a(a'high downto 1) & '0'))) &
+ sparse_get(flash_array, to_integer(unsigned(a(a'high downto 1) & '1'))) after T_OH;
+ end process;
+
+
+ ----------------------------------------------------------------------------
+ -- Device Information
+
+ id_word <= (others => 'X');
+
+
+ ----------------------------------------------------------------------------
+ -- Status Register
+
+ sts_word <= "00000000" &
+ sts_ready &
+ sts_susp_erase &
+ sts_error_erase &
+ sts_error_prog &
+ sts_error_vpen &
+ sts_susp_prog &
+ sts_error_lock &
+ '0';
+
+
+ ----------------------------------------------------------------------------
+ -- CFI Query
+
+ cfi_word <= (others => 'X');
+
+
+ ----------------------------------------------------------------------------
+ -- Output value
+
+ with read_state_cur select word <=
+ array_word when R_ARRAY,
+ id_word when R_ID,
+ sts_word when R_STATUS,
+ cfi_word when R_CFI,
+ (others => 'X') when others;
+
+ e_xmask_rp: entity work.changed_within_t
+ generic map (T => T_PHQV)
+ port map (sig_in => rp_n, sig_out => xmask_rp);
+
+ e_xmask_byte: entity work.changed_within_t
+ generic map (T => T_FLQV)
+ port map (sig_in => byte_n, sig_out => xmask_byte);
+
+ e_xmask_ce: entity work.delay_edges
+ generic map (D_RISE => T_OH, D_FALL => T_ELQV)
+ port map (sig_in => internal_ce_n, sig_out => xmask_ce);
+
+ e_xmask_oe: entity work.delay_edges
+ generic map (D_RISE => T_OH, D_FALL => T_GLQV_A)
+ port map (sig_in => oe_n, sig_out => xmask_oe);
+
+ e_xmask_addr_h: entity work.changed_within_t_vec
+ generic map (T => T_AVQV, T_HOLD => T_OH)
+ port map (sig_in => a(a'high downto 3), sig_out => xmask_addr_h);
+
+ e_xmask_addr_l: entity work.changed_within_t_vec
+ generic map (T => T_APA, T_HOLD => T_OH)
+ port map (sig_in => a(2 downto 0), sig_out => xmask_addr_l);
+
+ word_x <= (others => 'X') when (xmask_rp or xmask_ce or xmask_oe or xmask_addr_h or xmask_addr_l) = '1' else word;
+
+ e_zmask_ce: entity work.delay_edges
+ generic map (D_RISE => T_EHQZ, D_FALL => T_ELQX)
+ port map (sig_in => internal_ce_n, sig_out => zmask_ce);
+
+ e_zmask_oe: entity work.delay_edges
+ generic map (D_RISE => T_GHQZ, D_FALL => T_GLQX)
+ port map (sig_in => oe_n, sig_out => zmask_oe);
+
+ word_xz <= (others => 'Z') when (zmask_ce or zmask_oe) = '1' else word_x;
+
+ zmask_byte <= not byte_n after T_FLQZ;
+
+ d(15 downto 8) <= (others => 'Z') when zmask_byte = '1' else word_xz(15 downto 8);
+ d( 7 downto 0) <= word_xz( 7 downto 0) when byte_n = '1' else
+ word_xz( 7 downto 0) when a(0) = '0' else
+ word_xz(15 downto 8);
+
+
+ ----------------------------------------------------------------------------
+ -- Command User Interface (CUI)
+
+ process (rp_n, internal_we_n, a, d)
+ begin
+ if rp_n = '0' then
+ cui_state_cur <= C_IDLE;
+ trig_clrsts <= '0';
+ trig_susp <= '0';
+ trig_resume <= '0';
+ trig_cmderr <= '0';
+ trig_otp <= '0';
+ trig_word <= '0';
+ trig_buf <= '0';
+ trig_erase <= '0';
+ trig_lock <= '0';
+ trig_unlock <= '0';
+ elsif falling_edge(internal_we_n) then
+ trig_clrsts <= '0';
+ trig_susp <= '0';
+ trig_resume <= '0';
+ trig_cmderr <= '0';
+ trig_otp <= '0';
+ trig_word <= '0';
+ trig_buf <= '0';
+ trig_erase <= '0';
+ trig_lock <= '0';
+ trig_unlock <= '0';
+ elsif rising_edge(internal_we_n) then
+ case cui_state_cur is
+ when C_IDLE =>
+ case d(7 downto 0) is
+ when x"FF" => -- Read Array
+ read_state_cur <= R_ARRAY;
+
+ when x"70" => -- Read Status Register
+ read_state_cur <= R_STATUS;
+
+ when x"90" => -- Read Identifier Codes/Device Information
+ report "TODO: Read identifier codes and device information" severity error;
+ read_state_cur <= R_ID;
+
+ when x"98" => -- CFI Query
+ report "TODO: CFI query" severity error;
+ read_state_cur <= R_CFI;
+
+ when x"50" => -- Clear Status Register
+ trig_clrsts <= '1';
+
+ when x"B8" => -- Program STS Configuration Register
+ cui_state_cur <= C_PROG_STS;
+
+ when x"c0" => -- Program OTP Register
+ cui_state_cur <= C_PROG_OTP;
+
+ when x"40" | x"10" => -- Word/Byte Program
+ cui_state_cur <= C_PROG_WORD;
+
+ when x"E8" => -- Buffered Program
+ read_state_cur <= R_STATUS;
+ cui_state_cur <= C_PROG_BUF_COUNT;
+
+ when x"20" => -- Block Erase
+ cui_state_cur <= C_ERASE;
+
+ when x"60" => -- Lock/Unlock Block or Program Enhanced Configuration Register
+ cui_state_cur <= C_LOCK_OR_ECR;
+
+ when x"B0" => -- Program/Erase Suspend
+ trig_susp <= '1';
+ read_state_cur <= R_STATUS;
+
+ when x"D0" => -- Program/Erase Resume
+ trig_resume <= '1';
+ read_state_cur <= R_STATUS;
+
+ when others =>
+ trig_cmderr <= '1';
+ end case;
+
+ when C_PROG_STS =>
+ assert d(7 downto 0) = x"00" report "TODO: STS pulse config" severity error;
+ sts_config_reg <= d(7 downto 0);
+ cui_state_cur <= C_IDLE;
+
+ when C_PROG_OTP =>
+ trig_otp <= '1';
+ read_state_cur <= R_STATUS;
+ cui_state_cur <= C_IDLE;
+
+ when C_PROG_WORD =>
+ prog_word <= d;
+ prog_addr <= a;
+ trig_word <= '1';
+ read_state_cur <= R_STATUS;
+ cui_state_cur <= C_IDLE;
+
+ when C_PROG_BUF_COUNT =>
+ report "TODO: buffered program" severity error;
+ cui_state_cur <= C_PROG_BUF_DATA;
+
+ when C_PROG_BUF_DATA =>
+ cui_state_cur <= C_IDLE;
+
+ when C_ERASE =>
+ case d(7 downto 0) is
+ when x"D0" => -- Erase Block
+ erase_addr <= a;
+ trig_erase <= '1';
+ read_state_cur <= R_STATUS;
+ cui_state_cur <= C_IDLE;
+
+ when others =>
+ trig_cmderr <= '1';
+ cui_state_cur <= C_IDLE;
+ end case;
+
+ when C_LOCK_OR_ECR =>
+ case d(7 downto 0) is
+ when x"04" => -- Program Enhanced Configuration Register
+ assert a = x"000000" report "TODO: ECR configuration" severity error;
+ ecr_reg <= a;
+ cui_state_cur <= C_IDLE;
+
+ when x"01" => -- Lock Block
+ lock_addr <= a;
+ trig_lock <= '1';
+ read_state_cur <= R_STATUS;
+ cui_state_cur <= C_IDLE;
+
+ when x"0D" => -- Unlock block
+ unlock_addr <= a;
+ trig_unlock <= '1';
+ read_state_cur <= R_STATUS;
+ cui_state_cur <= C_IDLE;
+
+ when others =>
+ trig_cmderr <= '1';
+ cui_state_cur <= C_IDLE;
+ end case;
+
+ when others =>
+ report "Unhandled CUI state" severity error;
+ end case;
+ end if;
+ end process;
+
+
+ ----------------------------------------------------------------------------
+ -- Write State Machine (WSM)
+
+ process (wsm_state_cur, rp_n, vpen,
+ trig_clrsts, trig_susp, trig_resume, trig_cmderr, trig_otp,
+ trig_word, trig_buf, trig_erase, trig_lock, trig_unlock)
+ begin
+ if rp_n = '0' then
+ wsm_state_cur <= W_IDLE;
+
+ -- Clear all error and status bits and initialize to ready
+ sts_ready <= '1';
+ sts_susp_erase <= '0';
+ sts_error_erase <= '0';
+ sts_error_prog <= '0';
+ sts_error_vpen <= '0';
+ sts_susp_prog <= '0';
+ sts_error_lock <= '0';
+ else
+ -- Clearing error status bits should probably be allowed in any WSM state
+ if rising_edge(trig_clrsts) then
+ sts_error_erase <= '0';
+ sts_error_prog <= '0';
+ sts_error_vpen <= '0';
+ sts_error_lock <= '0';
+ end if;
+
+ -- Command errors should probably be latched in any WSM state
+ if rising_edge(trig_cmderr) then
+ sts_error_erase <= '1';
+ sts_error_prog <= '1';
+ end if;
+
+ -- Handle each state's logic
+ -- Keep in mind this is not only run when wsm_state_cur changes,
+ -- but also rerun when vpen or any trigger signal change
+ sts_ready <= '0';
+ case wsm_state_cur is
+ when W_IDLE =>
+ sts_ready <= '1';
+
+ -- After these state transitions, this process will be rerun
+ -- in the next delta cycle with the new state
+ if rising_edge(trig_resume) then
+ report "TODO: resume program/erase operation" severity error;
+ elsif rising_edge(trig_otp) then
+ wsm_state_cur <= W_PROG_OTP;
+ elsif rising_edge(trig_word) then
+ wsm_state_cur <= W_PROG_WORD;
+ elsif rising_edge(trig_buf) then
+ wsm_state_cur <= W_PROG_BUF;
+ elsif rising_edge(trig_erase) then
+ wsm_state_cur <= W_ERASE;
+ elsif rising_edge(trig_lock) then
+ wsm_state_cur <= W_LOCK;
+ elsif rising_edge(trig_unlock) then
+ wsm_state_cur <= W_UNLOCK;
+ end if;
+
+ when W_PROG_OTP =>
+ report "TODO: program OTP" severity error;
+ wsm_state_cur <= W_IDLE;
+
+ when W_PROG_WORD =>
+ -- TODO: check lock bits
+
+ -- If vpen is low or drops during programming, halt with error
+ if vpen = '0' then
+ sts_error_prog <= '1';
+ sts_error_vpen <= '1';
+ wsm_state_cur <= W_IDLE;
+ end if;
+
+ -- If suspend command is sent, pause programming
+ if rising_edge(trig_susp) then
+ report "TODO: program suspend" severity error;
+ end if;
+
+ -- Invalidate the data and schedule programming completion
+ if byte_n = '0' then
+ sparse_set(flash_array, to_integer(unsigned(prog_addr)), "XXXXXXXX");
+ else
+ sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '0')), "XXXXXXXX");
+ sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '1')), "XXXXXXXX");
+ end if;
+ wsm_state_cur <= W_PROG_WORD_FINISH after T_WHQV3;
+
+ when W_PROG_WORD_FINISH =>
+ if byte_n = '0' then
+ sparse_set(flash_array, to_integer(unsigned(prog_addr)), prog_word(7 downto 0));
+ else
+ sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '0')), prog_word(15 downto 8));
+ sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '1')), prog_word( 7 downto 0));
+ end if;
+ wsm_state_cur <= W_IDLE;
+
+ when W_PROG_BUF =>
+ report "TODO: buffered program" severity error;
+ wsm_state_cur <= W_IDLE;
+
+ when W_ERASE =>
+ -- TODO: check lock bits
+
+ -- If vpen is low or drops during erase, halt with error
+ if vpen = '0' then
+ sts_error_erase <= '1';
+ sts_error_vpen <= '1';
+ wsm_state_cur <= W_IDLE;
+ end if;
+
+ -- If suspend command is sent, pause programming
+ if rising_edge(trig_susp) then
+ report "TODO: erase suspend" severity error;
+ end if;
+
+ -- Invalidate the data and schedule the erase completion
+ for i in 0 to 16#1ffff# loop
+ sparse_set(flash_array, to_integer(unsigned(erase_addr(erase_addr'high downto 16)) & to_unsigned(i, 17)), x"FF");
+ end loop;
+ wsm_state_cur <= W_ERASE_FINISH after T_WHQV4;
+
+ when W_ERASE_FINISH =>
+ for i in 0 to 16#1ffff# loop
+ sparse_set(flash_array, to_integer(unsigned(erase_addr(erase_addr'high downto 16)) & to_unsigned(i, 17)), x"FF");
+ end loop;
+ wsm_state_cur <= W_IDLE;
+
+ when W_LOCK =>
+ report "TODO: program lock bits" severity error;
+ wsm_state_cur <= W_IDLE;
+
+ when W_UNLOCK =>
+ report "TODO: erase lock bits" severity error;
+ wsm_state_cur <= W_IDLE;
+
+ when others =>
+ report "Unhandled WSM state" severity error;
+
+ end case;
+ end if;
+ end process;
+
+
+ ----------------------------------------------------------------------------
+ -- Check for erroneous usages
+
+ -- Should not try to read and write at the same time
+ process (oe_n, we_n)
+ begin
+ assert not (oe_n = '0' and we_n = '0')
+ report "OE# and WE# should never be enabled simultaneously."
+ severity error;
+ end process;
+
+ -- Address must be valid for a full read or write cycle
+ R1: process (oe_n, a(23 downto 4))
+ begin
+ -- FIXME: Check more address bits if in non-array or 4-word array modes
+ if a(23 downto 4)'event and oe_n = '0' then
+ assert a(23 downto 4)'last_event >= T_AVAV;
+ report "T_AVAV not met (Read/Write Cycle Time)"
+ severity error;
+ end if;
+ end process;
+
+ -- BYTE# cannot change more than T_ELFL/T_ELFH after CEx goes low
+ -- This might be another way of describing a negative setup time requirement
+ R11: process (byte_n, internal_ce_n)
+ begin
+ if byte_n'event and internal_ce_n = '0' then
+ assert internal_ce_n'last_event <= T_ELFL;
+ report "T_ELFL/H not met (CEx Low to BYTE# High or Low)"
+ severity error;
+ end if;
+ end process;
+
+ W1a: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_HOLD => T_PHWL, NAME_SIG => "WE#", NAME_REF => "RP#")
+ port map (sig => we_n, ref => rp_n);
+
+ W1b: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_HOLD => T_PHEL, NAME_SIG => "CEx", NAME_REF => "RP#")
+ port map (sig => internal_ce_n, ref => rp_n);
+
+ W2a: entity work.assert_setuphold
+ generic map (LEVEL => '0', T_SETUP => T_ELWL, NAME_SIG => "CEx", NAME_REF => "WE#")
+ port map (sig => internal_ce_n, ref => we_n);
+
+ W2b: entity work.assert_setuphold
+ generic map (LEVEL => '0', T_SETUP => T_WLEL, NAME_SIG => "WE#", NAME_REF => "CEx")
+ port map (sig => we_n, ref => internal_ce_n);
+
+ W3: entity work.assert_pulsewidth
+ generic map (LEVEL => '0', T_MIN => T_WP, NAME => "WE#")
+ port map (sig => we_n);
+
+ W4: entity work.assert_setuphold_vec
+ generic map (LEVEL => '1', T_SETUP => T_DVWH, NAME_SIG => "Data", NAME_REF => "WE#/CEx")
+ port map (sig => d, ref => internal_we_n);
+
+ W5: entity work.assert_setuphold_vec
+ generic map (LEVEL => '1', T_SETUP => T_AVWH, NAME_SIG => "Addr", NAME_REF => "WE#/CEx")
+ port map (sig => a, ref => internal_we_n);
+
+ W6a: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_HOLD => T_WHEH, NAME_SIG => "CEx", NAME_REF => "WE#")
+ port map (sig => internal_ce_n, ref => we_n);
+
+ W6b: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_HOLD => T_EHWH, NAME_SIG => "WE#", NAME_REF => "CEx")
+ port map (sig => we_n, ref => internal_ce_n);
+
+ W7: entity work.assert_setuphold_vec
+ generic map (LEVEL => '1', T_HOLD => T_WHDX, NAME_SIG => "Data", NAME_REF => "WE#/CEx")
+ port map (sig => d, ref => internal_we_n);
+
+ W8: entity work.assert_setuphold_vec
+ generic map (LEVEL => '1', T_HOLD => T_WHAX, NAME_SIG => "Addr", NAME_REF => "WE#/CEx")
+ port map (sig => a, ref => internal_we_n);
+
+ W9: entity work.assert_pulsewidth
+ generic map (LEVEL => '1', T_MIN => T_WPH, NAME => "WE#")
+ port map (sig => we_n);
+
+ W11: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_SETUP => T_VPWH, NAME_SIG => "Vpen", NAME_REF => "WE#/CEx")
+ port map (sig => vpen, ref => internal_we_n);
+
+ W12: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_HOLD => T_WHGL, NAME_SIG => "OE#", NAME_REF => "WE#/CEx")
+ port map (sig => oe_n, ref => internal_we_n);
+
+ W15: entity work.assert_setuphold
+ generic map (LEVEL => '1', T_HOLD => T_QVVL, NAME_SIG => "Vpen", NAME_REF => "sts")
+ port map (sig => vpen, ref => sts_ready);
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+
+entity mt45w8mw16bgx is
+ port (
+ a: in std_logic_vector(22 downto 0);
+ dq: inout std_logic_vector(15 downto 0);
+ clk: in std_logic;
+ adv_n: in std_logic;
+ cre: in std_logic;
+ ce_n: in std_logic;
+ oe_n: in std_logic;
+ we_n: in std_logic;
+ lb_n: in std_logic;
+ ub_n: in std_logic;
+ rwait: out std_logic
+ );
+end mt45w8mw16bgx;
+
+
+architecture behavioral of mt45w8mw16bgx is
+
+ -- Timings (-708/80MHz)
+ constant T_AA: time := 70 ns; -- Address access time
+ constant T_AADV: time := 70 ns; -- ADV# access time
+ constant T_ABA: time := 46.5 ns; --
+ constant T_ACLK: time := 9 ns; --
+ constant T_APA: time := 20 ns; -- Page access time
+ constant T_AS: time := 0 ns; --
+ constant T_AVH: time := 2 ns; -- Address hold from ADV# HIGH
+ constant T_AVS: time := 5 ns; -- Address setup to ADV# HIGH
+ constant T_AW: time := 70 ns; --
+ constant T_BA: time := 70 ns; -- LB#/UB# access time
+ constant T_BHZ: time := 8 ns; -- LB#/UB# disable to DQ High-Z output
+ constant T_BLZ: time := 10 ns; -- LB#/UB# enable to Low-Z output
+ constant T_BOE: time := 20 ns; --
+ constant T_BW: time := 70 ns; --
+ constant T_CBPH: time := 6 ns; --
+ constant T_CEM: time := 4 us; -- Maximum CE# pulse width
+ constant T_CEW: time := 7.5 ns; -- CE# LOW to WAIT valid
+ constant T_CLK: time := 12.5 ns; --
+ constant T_CO: time := 70 ns; -- Chip select access time
+ constant T_CPH: time := 5 ns; --
+ constant T_CSP: time := 4 ns; --
+ constant T_CVS: time := 7 ns; -- CE# LOW to ADV# HIGH
+ constant T_CW: time := 70 ns; --
+ constant T_DH: time := 0 ns; --
+ constant T_DPD: time := 10 us; --
+ constant T_DPDX: time := 10 us; --
+ constant T_DW: time := 20 ns; --
+ constant T_HD: time := 2 ns; --
+ constant T_HZ: time := 8 ns; -- Chip disable to DQ and WAIT High-Z output
+ constant T_KHKL: time := 1.8 ns; --
+ constant T_KHTL: time := 9 ns; --
+ constant T_KOH: time := 2 ns; --
+ constant T_KP: time := 4 ns; --
+ constant T_LZ: time := 10 ns; -- Chip enable to Low-Z output
+ constant T_OE: time := 20 ns; -- Output enable to valid output
+ constant T_OH: time := 5 ns; -- Output hold from address change
+ constant T_OHZ: time := 8 ns; -- Output disable to DQ High-Z output
+ constant T_OLZ: time := 3 ns; -- Output enable to Low-Z output
+ constant T_OW: time := 5 ns; --
+ constant T_PC: time := 20 ns; -- Page READ cycle time
+ constant T_PU: time := 150 us; --
+ constant T_RC: time := 70 ns; -- READ cycle time
+ constant T_SP: time := 3 ns; --
+ constant T_VP: time := 5 ns; -- ADV# pulse width LOW
+ constant T_VS: time := 70 ns; --
+ constant T_WC: time := 70 ns; --
+ constant T_WHZ: time := 8 ns; --
+ constant T_WP: time := 45 ns; --
+ constant T_WPH: time := 10 ns; --
+ constant T_WR: time := 0 ns; --
+
+ -- Internal types
+ type word_array is array(natural range <>) of std_logic_vector(15 downto 0);
+
+ -- Data array read signals
+ signal array_reg: word_array(15 downto 0) := (others => (others => '1'));
+ signal array_word: std_logic_vector(15 downto 0);
+ signal read_word: std_logic_vector(15 downto 0);
+ signal xmask_addr: std_logic;
+ signal xmask_ce_n: std_logic;
+ signal xmask_oe_n: std_logic;
+ signal xmask_ub_n: std_logic;
+ signal xmask_lb_n: std_logic;
+ signal xmask_hi: std_logic;
+ signal xmask_lo: std_logic;
+ signal zmask_ce_n: std_logic;
+ signal zmask_oe_n: std_logic;
+ signal zmask_ub_n: std_logic;
+ signal zmask_lb_n: std_logic;
+ signal zmask_hi: std_logic;
+ signal zmask_lo: std_logic;
+
+ -- Data array write signals
+ signal internal_we_ub_n: std_logic;
+ signal internal_we_lb_n: std_logic;
+
+ -- Configuration registers
+ signal bcr_reg: std_logic_vector(15 downto 0) := x"9d1f";
+ signal rcr_reg: std_logic_vector(15 downto 0) := x"0010";
+ signal didr_reg: std_logic_vector(15 downto 0) := x"0343";
+
+begin
+
+ ----------------------------------------------------------------------------
+ -- Asynchronous array reads
+
+ -- Look up value from memory array, delay to allow for hold time
+ array_word <= array_reg(to_integer(unsigned(a))) after T_HZ; -- T_OHZ, T_BHZ
+
+ -- Generate mask for periods of time with invalid data
+ -- FIXME: this may break hold time
+ xm_addr: entity work.changed_within_t_vec generic map (T => T_AA, T_HOLD => T_OH)
+ port map (sig_in => a, sig_out => xmask_addr);
+ xm_ce: entity work.changed_within_t generic map (T => T_CO, T_HOLD => T_HZ)
+ port map (sig_in => ce_n, sig_out => xmask_ce_n);
+ xm_oe: entity work.changed_within_t generic map (T => T_OE, T_HOLD => T_OHZ)
+ port map (sig_in => oe_n, sig_out => xmask_oe_n);
+ xm_ub: entity work.changed_within_t generic map (T => T_BA, T_HOLD => T_BHZ)
+ port map (sig_in => ub_n, sig_out => xmask_ub_n);
+ xm_lb: entity work.changed_within_t generic map (T => T_BA, T_HOLD => T_BHZ)
+ port map (sig_in => lb_n, sig_out => xmask_lb_n);
+ xmask_hi <= xmask_addr or xmask_ce_n or xmask_oe_n or xmask_ub_n;
+ xmask_lo <= xmask_addr or xmask_ce_n or xmask_oe_n or xmask_lb_n;
+
+ -- Invalidate data for some periods of time
+ read_word(15 downto 8) <= (others => 'X') when xmask_hi = '1' else array_word(15 downto 8);
+ read_word( 7 downto 0) <= (others => 'X') when xmask_lo = '1' else array_word( 7 downto 0);
+
+ -- Generate mask for periods of time where data bus is high-z
+ zm_ce: entity work.delay_edges generic map (D_RISE => T_HZ, D_FALL => T_LZ)
+ port map (sig_in => ce_n, sig_out => zmask_ce_n);
+ zm_oe: entity work.delay_edges generic map (D_RISE => T_OHZ, D_FALL => T_OLZ)
+ port map (sig_in => oe_n, sig_out => zmask_oe_n);
+ zm_ub: entity work.delay_edges generic map (D_RISE => T_BHZ, D_FALL => T_BLZ)
+ port map (sig_in => ub_n, sig_out => zmask_ub_n);
+ zm_lb: entity work.delay_edges generic map (D_RISE => T_BHZ, D_FALL => T_BLZ)
+ port map (sig_in => lb_n, sig_out => zmask_lb_n);
+ zmask_hi <= zmask_ce_n or zmask_oe_n or zmask_ub_n;
+ zmask_lo <= zmask_ce_n or zmask_oe_n or zmask_lb_n;
+
+ -- Generate output data signals
+ dq(15 downto 8) <= (others => 'Z') when zmask_hi = '1' or we_n = '0'
+ else read_word(15 downto 8);
+ dq( 7 downto 0) <= (others => 'Z') when zmask_lo = '1' or we_n = '0'
+ else read_word( 7 downto 0);
+
+
+ ----------------------------------------------------------------------------
+ -- Asynchronous array writes
+
+ -- Internal signals to trigger latching of data
+ internal_we_ub_n <= ce_n or we_n or ub_n;
+ internal_we_lb_n <= ce_n or we_n or lb_n;
+
+ -- Latch data on rising edge of write signal
+ process (internal_we_ub_n, internal_we_lb_n)
+ begin
+ -- Changing (or tristating) DQ at the same moment as the write rising-edge should
+ -- be allowed (T_DH, data hold time, = 0 ns), but this breaks in ISim 14.7, hence
+ -- the 1 ps delay.
+ if rising_edge(internal_we_ub_n) then
+ array_reg(to_integer(unsigned(a)))(15 downto 8) <= dq(15 downto 8)'delayed(1 ps);
+ end if;
+
+ if rising_edge(internal_we_lb_n) then
+ array_reg(to_integer(unsigned(a)))( 7 downto 0) <= dq( 7 downto 0)'delayed(1 ps);
+ end if;
+ end process;
+
+
+ ----------------------------------------------------------------------------
+ -- Check for erroneous usage
+
+ -- TODO: check T_AVH, T_AVS, T_CVS, T_VP, T_AS
+ assert adv_n = '0'
+ report "ADV# not yet supported"
+ severity error;
+
+ assert clk = '0'
+ report "Synchronous operation not yet supported"
+ severity error;
+
+
+ -- Should (probably) not assert oe_n and we_n at the same time
+ process (oe_n, we_n)
+ begin
+ assert not (oe_n = '0' and we_n = '0')
+ report "OE# and WE# are active simultaneously (write takes precedence)"
+ severity warning;
+ end process;
+
+ -- Maximum CE# pulse width (to allow internal refresh)
+ process (ce_n)
+ begin
+ if rising_edge(ce_n) then
+ assert ce_n'last_event < T_CEM
+ report "T_CEM not met (Maximum CE# pulse width)"
+ severity error;
+ end if;
+ end process;
+
+
+ -- Write recovery time (address hold time)
+ process (a, internal_we_ub_n, internal_we_lb_n)
+ begin
+ if a'event then
+ if internal_we_ub_n = '1' then
+ assert internal_we_ub_n'last_event >= T_WR
+ report "T_WR not met (Write recovery time)"
+ severity error;
+ end if;
+ if internal_we_lb_n = '1' then
+ assert internal_we_lb_n'last_event >= T_WR
+ report "T_WR not met (Write recovery time)"
+ severity error;
+ end if;
+ end if;
+ end process;
+
+ -- Address valid to end of WRITE
+ process (a, internal_we_ub_n, internal_we_lb_n)
+ begin
+ if rising_edge(internal_we_ub_n) then
+ assert a'last_event >= T_AW
+ report "T_AW not met (Address valid to end of WRITE)"
+ severity error;
+ end if;
+ if rising_edge(internal_we_lb_n) then
+ assert a'last_event >= T_AW
+ report "T_AW not met (Address valid to end of WRITE)"
+ severity error;
+ end if;
+ end process;
+
+ -- Chip enable to end of WRITE
+ process (ce_n, internal_we_ub_n, internal_we_lb_n)
+ begin
+ if rising_edge(internal_we_ub_n) then
+ assert ce_n'delayed'delayed'last_event >= T_CW
+ report "T_CW not met (Chip enable to end of WRITE)"
+ severity error;
+ end if;
+ if rising_edge(internal_we_lb_n) then
+ assert ce_n'delayed'delayed'last_event >= T_CW
+ report "T_CW not met (Chip enable to end of WRITE)"
+ severity error;
+ end if;
+ end process;
+
+ -- CE# HIGH between subsequent async operations
+ process (ce_n)
+ begin
+ if falling_edge(ce_n) then
+ assert ce_n'delayed'last_event >= T_CPH
+ report "T_CPH not met (CE# HIGH between subsequent async operations)"
+ severity error;
+ end if;
+ end process;
+
+ -- LB#/UB# select to end of WRITE
+ process (ub_n, lb_n, internal_we_ub_n, internal_we_lb_n)
+ begin
+ if rising_edge(internal_we_ub_n) then
+ assert ub_n'last_event >= T_BW
+ report "T_BW not met (UB# select to end of WRITE)"
+ severity error;
+ end if;
+ if rising_edge(internal_we_lb_n) then
+ assert lb_n'last_event >= T_BW
+ report "T_BW not met (LB# select to end of WRITE)"
+ severity error;
+ end if;
+ end process;
+
+ -- WRITE pulse width
+ process (we_n, internal_we_ub_n, internal_we_lb_n)
+ variable t: time;
+ begin
+ -- Datasheet specifies WE# HIGH pulse width strictly on WE# signal
+ -- FIXME: should this be strictly on internal we signals?
+ if falling_edge(we_n) then
+ assert we_n'delayed'last_event >= T_WPH
+ report "T_WPH not met (WRITE pulse width HIGH)"
+ severity error;
+ end if;
+ -- Datasheet specifies WE# LOW pulse width against whatever signal triggers write
+ -- FIXME: should this be strictly on internal we signals?
+ if rising_edge(internal_we_ub_n) then
+ assert we_n'delayed'delayed'last_event >= T_WP
+ report "T_WP not met (WRITE pulse width)"
+ severity error;
+ end if;
+ if rising_edge(internal_we_lb_n) then
+ t := we_n'delayed'delayed'last_event;
+ assert we_n'delayed'delayed'last_event >= T_WP
+ report "T_WP not met (WRITE pulse width)" & time'image(t)
+ severity error;
+ end if;
+ end process;
+
+ -- Data setup and hold times
+ process (dq, internal_we_ub_n, internal_we_lb_n)
+ begin
+ if rising_edge(internal_we_ub_n) then
+ assert dq(15 downto 8)'delayed'delayed'last_event >= T_DW
+ report "T_DW not met (Data upper byte WRITE setup time)"
+ severity error;
+ end if;
+ if rising_edge(internal_we_lb_n) then
+ assert dq(7 downto 0)'delayed'delayed'last_event >= T_DW
+ report "T_DW not met (Data lower byte WRITE setup time)"
+ severity error;
+ end if;
+ if dq(15 downto 8)'event then
+ assert internal_we_ub_n'last_event >= T_DH
+ report "T_DH not met (Data upper byte HOLD from WRITE time)"
+ severity error;
+ end if;
+ if dq(7 downto 0)'event then
+ assert internal_we_lb_n'last_event >= T_DH
+ report "T_DH not met (Data lower byte HOLD from WRITE time)"
+ severity error;
+ end if;
+ end process;
+
+end behavioral;
+++ /dev/null
---------------------------------------------------------------------------------
--- Notes:
---
--- In ISim 14.7, it appears that the 'stable attribute doesn't work
--- Checking if 'last_event >= T_x doesn't seem to work with no previous events
---------------------------------------------------------------------------------
-
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-
-entity js28f128j3d75 is
- port (
- a: in std_logic_vector(23 downto 0);
- d: inout std_logic_vector(15 downto 0);
- ce: in std_logic_vector(2 downto 0);
- rp_n: in std_logic;
- oe_n: in std_logic;
- we_n: in std_logic;
- sts: out std_logic; -- open drain
- byte_n: in std_logic;
- vpen: in std_logic
- );
-end js28f128j3d75;
-
-
-architecture behavioral of js28f128j3d75 is
-
- -- Timings for 128Mbit, J3D-75 parts
-
- -- Read timings
- constant T_AVAV: time := 75 ns; -- R1, Read/Write Cycle Time
- constant T_AVQV: time := 75 ns; -- R2, Address to Output Delay
- constant T_ELQV: time := 75 ns; -- R3, CEx to Output Delay
- constant T_GLQV_NA: time := 25 ns; -- R4, OE# to Non-Array Output Delay
- constant T_PHQV: time := 210 ns; -- R5, RP# High to Output Delay
- constant T_ELQX: time := 0 ns; -- R6, CEx to Output Low Z
- constant T_GLQX: time := 0 ns; -- R7, OE# to Output Low Z
- constant T_EHQZ: time := 25 ns; -- R8, CEx High to Output in High Z
- constant T_GHQZ: time := 15 ns; -- R9, OE# High to Output in High Z
- constant T_OH: time := 0 ns; -- R10, Output Hold from Address, CEx, or OE# change
- constant T_ELFL: time := 10 ns; -- R11, CEx Low to BYTE# High or Low
- constant T_ELFH: time := 10 ns; -- R11, (Same as Above)
- constant T_FLQV: time := 1 ns; -- R12, BYTE# to Output Delay
- constant T_FHQV: time := 1 ns; -- R12, (Same as Above)
- constant T_FLQZ: time := 1 ns; -- R13, BYTE# to Output in High Z
- constant T_EHEL: time := 0 ns; -- R14, CEx High to CEx Low
- constant T_APA: time := 25 ns; -- R15, Page Address Access Time
- constant T_GLQV_A: time := 25 ns; -- R16, OE# to Array Output Delay
-
- -- Write timings
- constant T_PHWL: time := 210 ns; -- W1, RP# High Recovery to WE# (CEx) Going Low
- constant T_PHEL: time := 210 ns; -- W1, (Same as Above)
- constant T_ELWL: time := 0 ns; -- W2, CEx (WE#) Low to WE# (CEx) Going Low
- constant T_WLEL: time := 0 ns; -- W2, (Same as Above)
- constant T_WP: time := 60 ns; -- W3, Write Pulse Width
- constant T_DVWH: time := 50 ns; -- W4, Data Setup to WE# (CEx) Going High
- constant T_DVEH: time := 50 ns; -- W4, (Same as Above)
- constant T_AVWH: time := 55 ns; -- W5, Address Setup to WE# (CEx) Going High
- constant T_AVEH: time := 55 ns; -- W5, (Same as Above)
- constant T_WHEH: time := 0 ns; -- W6, CEx (WE#) Hold from WE# (CEx) High
- constant T_EHWH: time := 0 ns; -- W6, (Same as Above)
- constant T_WHDX: time := 0 ns; -- W7, Data Hold from WE# (CEx) High
- constant T_EHDX: time := 0 ns; -- W7, (Same as Above)
- constant T_WHAX: time := 0 ns; -- W8, Address Hold from WE# (CEx) High
- constant T_EHAX: time := 0 ns; -- W8, (Same as Above)
- constant T_WPH: time := 30 ns; -- W9, Write Pulse Width High
- constant T_VPWH: time := 0 ns; -- W11, Vpen Setup to WE# (CEx) Going High
- constant T_VPEH: time := 0 ns; -- W11, (Same as Above)
- constant T_WHGL: time := 35 ns; -- W12, Write Recovery before Read
- constant T_EHGL: time := 35 ns; -- W12, (Same as Above)
- constant T_WHRL: time := 500 ns; -- W13, WE# (CEx) High to STS Going Low
- constant T_EHRL: time := 500 ns; -- W13, (Same as Above)
- constant T_QVVL: time := 0 ns; -- W15, Vpen Hold from Valid SRD, STS Going High
-
- -- Configuration timings
- constant T_WHQV3: time := 175 us; -- W16, Byte Program Time (Using Word/Byte Program Command)
- constant T_EHQV3: time := 175 us; -- W16, (Same as above)
- constant T_WHQV4: time := 4 sec; -- W16, Block Erase Time
- constant T_EHQV4: time := 4 sec; -- W16, (Same as above)
- constant T_WHQV5: time := 60 us; -- W16, Set Lock-Bit Time
- constant T_EHQV5: time := 60 us; -- W16, (Same as above)
- constant T_WHQV6: time := 0.7 sec; -- W16, Clear Block Lock-Bits Time
- constant T_EHQV6: time := 0.7 sec; -- W16, (Same as above)
- constant T_WHRH1: time := 20 us; -- W16, Program Suspend Latency Time to Read
- constant T_EHRH1: time := 20 us; -- W16, (Same as above)
- constant T_WHRH: time := 20 us; -- W16, Erase Suspend Latency Time to Read
- constant T_EHRH: time := 20 us; -- W16, (Same as above)
- constant T_STS: time := 500 ns; -- WY, STS Pulse Width Low Time
-
- -- Reset timings
- constant T_PLPH: time := 25 us; -- P1, RP# Pulse Low Time
- constant T_PHRH: time := 100 ns; -- P2, RP# High to Reset During Block-Erase, Program, or Lock-Bit Configuration
- constant T_VCCPH: time := 60 us; -- P3, Vcc Power Valid to RP# de-assertion (high)
-
- pure function block_index_of(address: std_logic_vector(a'high downto 0)) return integer is
- begin
- return to_integer(unsigned(address(address'high downto 17)));
- end function;
-
- pure function word_index_of(address: std_logic_vector(a'high downto 0)) return integer is
- begin
- return to_integer(unsigned(address(16 downto 1)));
- end function;
-
- -- Internal types
- type word_array is array(natural range <>) of std_logic_vector(15 downto 0);
- type block_array is array(natural range<>) of word_array(65535 downto 0);
-
- type cui_state is (
- C_IDLE,
- C_PECR,
- C_POTP,
- C_STSC,
- C_PROG,
- C_BUF_PROG_COUNT,
- C_BUF_PROG_DATA,
- C_BUF_PROG_CONF,
- C_ERASE,
- C_LOCK
- );
- type read_state is (R_ARRAY, R_ID, R_STATUS, R_CFI);
- type wsm_state is (W_READY, W_PROG, W_BUF_PROG, W_ERASE, W_LOCK_PROG, W_LOCK_ERASE, W_OTP_PROG, W_RESUME);
-
- -- Internal signals
- signal internal_ce_n: std_logic; -- Composite chip-enable from multiple CE input signals
- signal internal_we_n: std_logic; -- Composite write-latch from WE# and CEx
-
- signal array_pre_word: std_logic_vector(15 downto 0);
- signal array_word: std_logic_vector(15 downto 0);
- signal cfi_pre_word: std_logic_vector(15 downto 0);
- signal cfi_word: std_logic_vector(15 downto 0);
- signal id_pre_word: std_logic_vector(15 downto 0);
- signal id_word: std_logic_vector(15 downto 0);
- signal status_pre_word: std_logic_vector(15 downto 0);
- signal status_word: std_logic_vector(15 downto 0);
- signal read_pre_word: std_logic_vector(15 downto 0);
- signal read_word: std_logic_vector(15 downto 0);
- signal last_word: std_logic_vector(15 downto 0);
-
- -- Delay mask signals for array reads
- signal addr_hi_change_4: std_logic;
- signal addr_hi_change_8: std_logic;
- signal addr_hi_change: std_logic;
- signal is_sensing: std_logic;
- signal addr_lo_change_4: std_logic;
- signal addr_lo_change_8: std_logic;
- signal addr_lo_change: std_logic;
- signal oe_change_array: std_logic;
-
- -- Delay mask signals for non-array reads
- signal addr_change: std_logic;
- signal oe_change_nonarray: std_logic;
-
- -- Delay mask signals for all reads
- signal rp_change: std_logic;
- signal ce_change: std_logic;
- signal byte_change: std_logic;
-
- -- Delay mask signals for tristate logic
- signal ce_n_gate: std_logic;
- signal oe_n_gate: std_logic;
- signal final_oe_n: std_logic;
-
- signal cur_cui_state: cui_state;
- signal cur_read_state: read_state;
- signal cur_wsm_state: wsm_state;
- signal next_wsm_state: wsm_state;
- signal wsm_trigger: std_logic;
-
- -- Status signals
- signal sts_ready: std_logic := '1';
- signal sts_susp_erase: std_logic := '0';
- signal sts_error_code: std_logic_vector(1 downto 0) := "00";
- signal sts_error_volt: std_logic := '0';
- signal sts_susp_prog: std_logic := '0';
- signal sts_error_lock: std_logic := '0';
- signal sts_config: std_logic_vector(7 downto 0) := (others => '0');
-
- -- Flash array data
- -- Only two blocks to save the simulator
- signal flash_array: block_array(1 downto 0) := (others => (others => (others => '1')));
-
- -- Lock operation state
- signal lock_address: std_logic_vector(a'range);
- signal lock_reg: std_logic_vector(127 downto 0) := (others => '0');
-
- -- Program array operation state
- signal prog_count: integer;
- signal prog_address: std_logic_vector(a'range);
- signal prog_buf: word_array(31 downto 0);
- signal prog_word: std_logic_vector(15 downto 0);
-
- -- Erase operation state
- signal erase_address: std_logic_vector(a'range);
-
- -- Enhanced Configuration Register
- signal ecr_reg: std_logic_vector(16 downto 0);
- signal ecr_8word_page: std_logic;
-
- -- OTP Protection Register
- signal otp_prog_offset: std_logic_vector(a'range);
- signal otp_prog_data: std_logic_vector(15 downto 0);
- signal plr_reg: std_logic_vector(15 downto 0) := x"FFFE";
- signal otp_reg: word_array(7 downto 0) := (others => (others => '1'));
-
- -- Debug
- signal ce_stable: boolean;
-begin
-
- ----------------------------------------------------------------------------
- -- Useful internal signals composed from external signals
-
- -- Decode multiple chip enable inputs into single chip enable signal
- with ce select internal_ce_n <=
- '0' when "000",
- '1' when "001",
- '1' when "010",
- '1' when "011",
- '0' when "100",
- '0' when "101",
- '0' when "110",
- '1' when "111",
- 'X' when others;
-
- -- Write latch is triggered by either WEx or CEx going high, whichever is first
- internal_we_n <= we_n or internal_ce_n;
-
- -- STS signal represents the state of the WSM
- sts <= 'H' when sts_ready = '1' else '0';
-
-
- ----------------------------------------------------------------------------
- -- Reset logic
-
- reset: process (rp_n)
- begin
- if rp_n = '0' then
- -- reset all state machines
- -- cur_cui_state <= C_IDLE;
- -- cur_read_state <= R_ARRAY;
- -- cur_wsm_state <= W_READY;
-
- -- reset status register and status config
- --sts_ready <= '1';
- --sts_susp_erase <= '0';
- --sts_error_code <= "00";
- --sts_error_volt <= '0';
- --sts_susp_prog <= '0';
- --sts_error_lock <= '0';
- sts_config <= (others => '0');
-
- -- reset ECR to 4-word page mode
- ecr_reg <= (others => '0');
-
- -- abort all program, erase, lock-bit operations
- end if;
- end process;
-
-
- ----------------------------------------------------------------------------
- -- Read logic
-
- -- Look up value from flash array
- array_pre_word <= flash_array(block_index_of(a))(word_index_of(a));
-
- -- Generate mask signal representing sensing delay
- -- ce_change is incorporated here because the datasheet says ce falling triggers sensing,
- -- but the same delay also listed for all other reads, so it is incorporated again below.
- addr_hi_change_4 <= '1' when (a(a'high downto 3) /= a(a'high downto 3)'delayed(T_AVQV)) or
- (a(a'high downto 3)'last_event < T_AVQV)
- else '0';
- addr_hi_change_8 <= '1' when (a(a'high downto 4) /= a(a'high downto 4)'delayed(T_AVQV)) or
- (a(a'high downto 4)'last_event < T_AVQV)
- else '0';
- with ecr_8word_page select addr_hi_change <=
- addr_hi_change_8 when '1',
- addr_hi_change_4 when others;
- ce_change <= '1' when (internal_ce_n /= internal_ce_n'delayed(T_ELQV)) or
- (internal_ce_n'last_event < T_ELQV)
- else '0';
- is_sensing <= addr_hi_change or ce_change;
-
- -- Generate mask signal representing word select delay
- addr_lo_change_4 <= '1' when (a(2 downto 0) /= a(2 downto 0)'delayed(T_APA)) or
- (a(2 downto 0)'last_event < T_APA)
- else '0';
- addr_lo_change_8 <= '1' when (a(3 downto 0) /= a(3 downto 0)'delayed(T_APA)) or
- (a(3 downto 0)'last_event < T_APA)
- else '0';
- with ecr_8word_page select addr_lo_change <=
- addr_lo_change_8 when '1',
- addr_lo_change_4 when others;
-
- -- Generate mask signal representing OE# delay for array reads
- oe_change_array <= '1' when (oe_n /= oe_n'delayed(T_GLQV_A)) or
- (oe_n'last_event < T_GLQV_A)
- else '0';
-
- array_word <= (others => 'X') when is_sensing = '1' or
- addr_lo_change = '1' or
- oe_change_array = '1' else array_pre_word;
-
-
- -- Generate mask signals representing delays for non-array reads (and use ce_change from above)
- -- Not sure if T_AVAV applies to non-array reads, so apply it anyway just in case
- addr_change <= '1' when (a /= a'delayed(T_AVQV)) or
- (a'last_event < T_AVQV)
- else '0';
- oe_change_nonarray <= '1' when (oe_n /= oe_n'delayed(T_GLQV_NA)) or
- (oe_n'last_event < T_GLQV_NA)
- else '0';
-
- -- Look up CFI query value
- do_cfi_read: process (a)
- begin
- case a(8 downto 1) is
- when x"10" => cfi_pre_word <= x"0051";
- when x"11" => cfi_pre_word <= x"0052";
- when x"12" => cfi_pre_word <= x"0059";
- when others => cfi_pre_word <= (others => '0');
- end case;
- end process;
-
- cfi_word <= (others => 'X') when addr_change = '1' or
- oe_change_nonarray = '1' else cfi_pre_word;
-
- -- Look up ID register value
- do_id_read: process (a)
- begin
- case to_integer(unsigned(a(16 downto 1))) is
- -- Device ID
- when 16#0001# =>
- id_pre_word <= x"0018";
-
- -- Lock bit for this block
- when 16#0002# =>
- id_pre_word <= (others => '0');
- id_pre_word(0) <= lock_reg(to_integer(unsigned(a(a'high downto 17))));
-
- -- OTP protection lock register
- when 16#0080# => id_pre_word <= plr_reg;
-
- -- OTP register
- when 16#0081# to 16#88# =>
- id_pre_word <= otp_reg(to_integer(unsigned(a)) - 16#81#);
-
- when others => id_pre_word <= (others => 'X');
- end case;
- end process;
-
- id_word <= (others => 'X') when addr_change = '1' or
- oe_change_nonarray = '1' else id_pre_word;
-
- -- Compute status register value
- do_status: process (internal_ce_n, oe_n,
- sts_ready, sts_susp_erase, sts_error_code, sts_error_volt, sts_susp_prog, sts_error_lock)
- begin
- -- Status register value is latched on CEx or OE# going low
- if falling_edge(internal_ce_n) or (falling_edge(oe_n) and internal_ce_n = '0') then
- status_pre_word(15 downto 8) <= x"00";
- status_pre_word(7) <= sts_ready;
- status_pre_word(6) <= sts_susp_erase;
- status_pre_word(5 downto 4) <= sts_error_code;
- status_pre_word(3) <= sts_error_volt;
- status_pre_word(2) <= sts_susp_prog;
- status_pre_word(1) <= sts_error_lock;
- status_pre_word(0) <= '0';
- end if;
- end process;
-
- status_word <= (others => 'X') when addr_change = '1' or
- oe_change_nonarray = '1' else status_pre_word;
-
-
- -- Choose a value based on read mode
- do_read: process (cur_read_state, array_word, cfi_word, id_word, status_word)
- begin
- case cur_read_state is
- when R_ARRAY =>
- read_pre_word <= array_word;
- when R_ID =>
- read_pre_word <= id_word;
- when R_STATUS =>
- read_pre_word <= status_word;
- when R_CFI =>
- read_pre_word <= cfi_word;
- when others =>
- read_pre_word <= (others => 'X');
- end case;
- end process;
-
- -- Generate mask signals for delays that apply to any read
- rp_change <= '1' when (rp_n /= rp_n'delayed(T_PHQV)) or
- (rp_n'last_event < T_PHQV)
- else '0';
- byte_change <= '1' when (byte_n /= byte_n'delayed(T_FLQV)) or
- (byte_n'last_event < T_FLQV)
- else '0';
- -- ce_change from above
-
- -- Handle byte/word modes
- byte_select: process (read_pre_word, a(0), byte_n)
- begin
- if byte_n = '0' then
- -- Oops, extra tristating to handle here instead of in tristate logic
- -- Good thing is is sim-only!
- read_word(15 downto 8) <= (others => 'Z');
- if a(0) = '0' then
- read_word(7 downto 0) <= read_pre_word(7 downto 0);
- else
- read_word(7 downto 0) <= read_pre_word(15 downto 8);
- end if;
- else
- read_word <= read_pre_word;
- end if;
- end process;
-
- -- Equal parts gin, green chartreuse, maraschino liqueur, lime; shaken and served up
- last_word <= (others => 'X') when rp_change = '1' or
- byte_change = '1' else read_word;
-
-
- -- Handle delays between CEx/OE# and transitions between low/high-Z output
- -- The front and back porch have different delay specs, so to get the front porch
- -- with one delay and the back porch with the other we may need to either and or
- -- or the delayed signals depending on which delay is longer.
- delayed_ce_n_a: if T_ELQX > T_EHQZ generate
- ce_n_gate <= internal_ce_n'delayed(T_ELQX) or internal_ce_n'delayed(T_EHQZ);
- end generate;
- delayed_ce_n_b: if T_ELQX <= T_EHQZ generate
- ce_n_gate <= internal_ce_n'delayed(T_ELQX) and internal_ce_n'delayed(T_EHQZ);
- end generate;
- delayed_oe_n_a: if T_GLQX > T_GHQZ generate
- oe_n_gate <= oe_n'delayed(T_GLQX) or oe_n'delayed(T_GHQZ);
- end generate;
- delayed_oe_n_b: if T_GLQX <= T_GHQZ generate
- oe_n_gate <= oe_n'delayed(T_GLQX) and oe_n'delayed(T_GHQZ);
- end generate;
- final_oe_n <= ce_n_gate or oe_n_gate;
- d <= (others => 'Z') when rp_n = '0' or final_oe_n = '1' else last_word'delayed(T_OH);
-
-
- ecr_8word_page <= ecr_reg(13);
-
-
- ----------------------------------------------------------------------------
- -- Write logic
-
- -- Latch CUI on rising edge of we_n or ce_n
- -- CUI logic is responsible for:
- -- * checking sts_ready before triggering
- -- * checking sts_susp_prog/erase before triggering if relevant
- -- * setting sts_susp_prog/erase when suspending
- -- * setting next_wsm_state and wsm_trigger to begin operations
- cui: process (internal_we_n, a, d, rp_n,
- sts_ready, sts_susp_prog, sts_susp_erase, cur_wsm_state)
- variable prog_i: integer;
- begin
- if rp_n = '0' then
- cur_cui_state <= C_IDLE;
- cur_read_state <= R_ARRAY;
- wsm_trigger <= '0';
- elsif rising_edge(internal_we_n) then
- case cur_cui_state is
- when C_IDLE =>
- wsm_trigger <= '0';
-
- -- Idle, not waiting for data or confirmation commands
- case d(7 downto 0) is
- -- Program Enhanced Configuration Register (Setup)
- --when x"60" =>
- -- cur_cui_state <= C_PECR;
-
- -- Program OTP Register (Setup)
- when x"c0" =>
- cur_cui_state <= C_POTP;
-
- -- Clear Status Register
- when x"50" =>
- -- Only clear error flags, not status
- sts_error_code <= "00";
- sts_error_volt <= '0';
- sts_error_lock <= '0';
- cur_read_state <= R_STATUS;
-
- -- Program STS Configuration Register (Setup)
- when x"b8" =>
- -- FIXME: enter R_STATUS?
- cur_cui_state <= C_STSC;
-
- -- Read Array
- when x"ff" =>
- assert sts_ready = '1'
- report "Entering read-array mode while WSM is busy"
- severity warning;
- cur_read_state <= R_ARRAY;
-
- -- Read Status Register
- when x"70" =>
- cur_read_state <= R_STATUS;
-
- -- Read Identifier Codes
- when x"90" =>
- cur_read_state <= R_ID;
-
- -- CFI Query
- when x"98" =>
- cur_read_state <= R_CFI;
-
- -- Word/Byte Program (Setup)
- when x"40" | x"10" =>
- cur_cui_state <= C_PROG;
-
- -- Buffered Program (Setup)
- when x"e8" =>
- cur_read_state <= R_STATUS;
- if sts_ready = '1' then
- cur_cui_state <= C_BUF_PROG_COUNT;
- end if;
-
- -- BLock Erase (Setup)
- when x"20" =>
- cur_cui_state <= C_ERASE;
-
- -- Program/Erase Suspend
- when x"b0" =>
- if sts_ready = '1' then
- -- No-op
- null;
- elsif cur_wsm_state = W_PROG or cur_wsm_state = W_BUF_PROG then
- -- Suspend program operation
- sts_susp_prog <= '1';
- elsif cur_wsm_state = W_ERASE then
- -- Suspend erase operation
- sts_susp_erase <= '1';
- end if;
- -- Suspend does not change read mode
-
- -- Program/Erase Resume
- when x"d0" =>
- next_wsm_state <= W_RESUME;
- wsm_trigger <= '1';
- cur_read_state <= R_STATUS;
-
- -- Lock/Unlock Block (Setup) and Program Enhanced Configuration Register (Setup)
- when x"60" =>
- cur_read_state <= R_STATUS;
- cur_cui_state <= C_LOCK;
-
- when others =>
- sts_error_code <= "11";
- end case;
-
- -- Started Program Enhanced Configuration Register command
- when C_PECR =>
- case d(7 downto 0) is
- when x"04" =>
- ecr_reg <= a(ecr_reg'high downto 0);
- -- Datasheet says it returns to read-array mode...
- -- FIXME: Does it just not change the mode?
- cur_read_state <= R_ARRAY;
-
- when others =>
- sts_error_code <= "11";
- end case;
- cur_cui_state <= C_IDLE;
-
- -- Started Program OTP Register command
- when C_POTP =>
- if sts_ready = '0' then
- -- Not allowed while WSM is busy
- sts_error_code <= "11";
- elsif sts_susp_prog = '1' or sts_susp_erase = '1' then
- -- Not allowed while program/erase suspended
- sts_error_code <= "11";
- else
- -- Latch address and data and trigger WSM
- otp_prog_offset <= a;
- otp_prog_data <= d;
- next_wsm_state <= W_OTP_PROG;
- wsm_trigger <= '1';
- end if;
-
- cur_read_state <= R_STATUS;
- cur_cui_state <= C_IDLE;
-
- -- Started Program STS Configuration Register command
- when C_STSC =>
- if sts_ready = '0' then
- -- Not allowed while WSM is busy
- sts_error_code <= "11";
- elsif sts_susp_prog = '1' or sts_susp_erase = '1' then
- -- Not allowed while program/erase suspended
- sts_error_code <= "11";
- elsif (d and x"00fc") /= x"0000" then
- -- Invalid configuration value
- sts_error_code <= "11";
- else
- assert d(1) = '0' and d(0) = '0'
- report "TODO: STS pulse config"
- severity warning;
- sts_config <= d(7 downto 0);
- end if;
- cur_read_state <= R_STATUS;
- cur_cui_state <= C_IDLE;
-
- -- Started Word/Byte Program command
- when C_PROG =>
- if sts_ready = '0' then
- -- Not allowed while WSM is busy
- sts_error_code <= "11";
- elsif sts_susp_prog = '1' then
- -- Not allowed while program suspended
- sts_error_code <= "11";
- else
- -- Latch address and data and trigger WSM
- prog_address <= a;
- prog_word <= d;
- next_wsm_state <= W_PROG;
- wsm_trigger <= '1';
- end if;
- cur_read_state <= R_STATUS;
- cur_cui_state <= C_IDLE;
-
- -- Started Buffer Program command
- when C_BUF_PROG_COUNT =>
- if sts_ready = '0' then
- -- sts_ready already checked in previous state, but just in case
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- elsif sts_susp_prog = '1' then
- -- Do not allow while programming operation is suspended
- -- Should this check have been rolled into the status check in
- -- the previous state? Or should this check be done in the previous
- -- state? TODO: check on hardware
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- elsif (d(7 downto 0) and x"e0") /= x"0000" then
- -- Word count must be <= 31
- report "Buffer program sent with word count greater than 31" severity warning;
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- else
- -- Latch start address and word count
- prog_address <= a;
- prog_count <= to_integer(unsigned(d));
- prog_i := to_integer(unsigned(d));
- cur_cui_state <= C_BUF_PROG_DATA;
- end if;
-
- when C_BUF_PROG_DATA =>
- -- Latch data into buffer at address
- prog_buf(to_integer(unsigned(a(5 downto 1)))) <= d;
- if prog_i = 0 then
- cur_cui_state <= C_BUF_PROG_CONF;
- else
- prog_i := prog_i - 1;
- end if;
-
- when C_BUF_PROG_CONF =>
- if d(7 downto 0) /= x"d0" then
- -- Failed to confirm write, abort
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- else
- -- Trigger WSM
- next_wsm_state <= W_BUF_PROG;
- wsm_trigger <= '1';
- cur_cui_state <= C_IDLE;
- end if;
-
- -- Started Block Erase command
- when C_ERASE =>
- -- TODO: not allowed when erase or program suspended
- if sts_ready = '0' then
- -- Not allowed while WSM is busy
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- elsif sts_susp_prog = '1' or sts_susp_erase = '1' then
- -- Not allowed while program/erase suspended
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- elsif d(7 downto 0) /= x"d0" then
- -- Failed to confirm erase
- sts_error_code <= "11";
- cur_cui_state <= C_IDLE;
- else
- -- Latch block address and trigger WSM
- erase_address <= a;
- next_wsm_state <= W_ERASE;
- wsm_trigger <= '1';
- cur_cui_state <= C_IDLE;
- end if;
-
- -- Started Lock/Unlock Block command
- when C_LOCK =>
- -- Read state already set to R_STATUS in previous cycle
- case d(7 downto 0) is
- -- Program Enhanced Configuration Register
- when x"04" =>
- ecr_reg <= a(ecr_reg'high downto 0);
- -- Datasheet says it returns to read-array mode
- cur_read_state <= R_ARRAY;
-
- -- Lock Block
- when x"01" =>
- -- address in a
- if sts_ready = '0' then
- -- Cannot program when WSM is busy
- sts_error_code <= "11";
- elsif sts_susp_erase = '1' or sts_susp_prog = '1' then
- -- Cannot program when erase or program suspended
- sts_error_code <= "11";
- else
- lock_address <= a;
- next_wsm_state <= W_LOCK_PROG;
- wsm_trigger <= '1';
- end if;
-
- -- Unlock Blocks
- when x"d0" =>
- if sts_ready = '0' then
- -- Cannot erase when WSM is busy
- sts_error_code <= "11";
- elsif sts_susp_erase = '1' or sts_susp_prog = '1' then
- -- Cannot erase when erase or program suspended
- sts_error_code <= "11";
- else
- next_wsm_state <= W_LOCK_ERASE;
- wsm_trigger <= '1';
- end if;
-
- when others =>
- sts_error_code <= "11";
- end case;
- cur_cui_state <= C_IDLE;
-
- when others =>
- cur_cui_state <= C_IDLE;
- end case;
- end if;
- end process;
-
- -- Write state machine is responsible for checking:
- -- * Vpen state
- -- * valid offset/address
- -- * lock protection
- -- * checking wsm_trigger and next_wsm_state to begin operations
- -- * checking sts_susp_* state to suspend operations
- wsm: process (rp_n, vpen, sts_susp_erase, sts_susp_prog, wsm_trigger, cur_wsm_state, next_wsm_state)
- variable otp_prog_idx: integer;
- variable prog_buf_addr: integer;
- begin
- if rp_n = '0' then
- -- TODO: hold ready low for some time after reset
- cur_wsm_state <= W_READY;
- sts_ready <= '1';
- sts_susp_erase <= '0';
- sts_error_code <= "00";
- sts_error_volt <= '0';
- sts_susp_prog <= '0';
- sts_error_lock <= '0';
- end if;
-
- sts_ready <= '0'; -- Default to not-ready
-
- -- Process triggers from the CUI FSM
- if rising_edge(wsm_trigger) then
- cur_wsm_state <= next_wsm_state;
- end if;
-
- case cur_wsm_state is
- when W_READY =>
- sts_ready <= '1'; -- Ready status only in ready state
-
- when W_PROG =>
- -- Abort with voltage error if Vpen drops
- sts_ready <= '0';
- if vpen = '0' then
- sts_error_code(0) <= '1';
- sts_error_volt <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Suspend programming operation when signaled
- if sts_susp_prog = '1' then
- cur_wsm_state <= W_READY after T_WHRH1; -- T_EHRH1
- end if;
- -- Check lock protection bit for block
- if lock_reg(block_index_of(prog_address)) = '1' then
- sts_error_code(0) <= '1';
- sts_error_lock <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- flash_array(block_index_of(prog_address))(word_index_of(prog_address)) <=
- flash_array(block_index_of(prog_address))(word_index_of(prog_address))
- and prog_word;
- cur_wsm_state <= W_READY after T_WHQV3; -- T_EHQV3
-
- when W_BUF_PROG =>
- -- Abort with voltage error if Vpen drops
- if vpen = '0' then
- sts_error_code(0) <= '1';
- sts_error_volt <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Suspend programming operation when signaled
- if sts_susp_prog = '1' then
- cur_wsm_state <= W_READY after T_WHRH1; -- T_EHRH1
- end if;
- -- Check lock protection bit for block
- if lock_reg(block_index_of(prog_address)) = '1' then
- sts_error_code(0) <= '1';
- sts_error_lock <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- TODO: write zeroes
- prog_buf_addr := to_integer(unsigned(prog_address));
- for addr in prog_buf_addr to prog_buf_addr + prog_count + 1 loop
- flash_array(block_index_of(std_logic_vector(to_unsigned(addr, 24))))(word_index_of(std_logic_vector(to_unsigned(addr, 24)))) <=
- flash_array(block_index_of(std_logic_vector(to_unsigned(addr, 24))))(word_index_of(std_logic_vector(to_unsigned(addr, 24))))
- and prog_buf(addr mod 32);
- end loop;
- -- TODO: get correct timing
- cur_wsm_state <= W_READY after T_WHQV3; -- T_EHQV3
-
- when W_ERASE =>
- -- Abort with voltage error if Vpen drops
- if vpen = '0' then
- sts_error_code(1) <= '1';
- sts_error_volt <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Suspend erase operation when signaled
- if sts_susp_erase = '1' then
- cur_wsm_state <= W_READY after T_WHRH; -- T_EHRH
- end if;
- -- Check lock protection bit for block
- if lock_reg(block_index_of(erase_address)) = '1' then
- sts_error_code(1) <= '1';
- sts_error_lock <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Erase block and return to ready
- flash_array(block_index_of(erase_address)) <= (others => (others => '1'));
- cur_wsm_state <= W_READY after T_WHQV4; -- T_EHQV4
-
- when W_LOCK_PROG =>
- -- Abort with voltage error if Vpen drops
- if vpen = '0' then
- sts_error_code(0) <= '1';
- sts_error_volt <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Write lock bit and return to ready
- lock_reg(block_index_of(lock_address)) <= '1';
- cur_wsm_state <= W_READY after T_WHQV5; -- T_EHQV5
-
- when W_LOCK_ERASE =>
- -- Abort with voltage error if Vpen drops
- if vpen = '0' then
- sts_error_code(1) <= '1';
- sts_error_volt <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Erase all lock bits and return to ready
- lock_reg <= (others => '0');
- cur_wsm_state <= W_READY after T_WHQV6; -- T_EHQV6
-
- when W_OTP_PROG =>
- -- Abort with voltage error if Vpen drops
- if vpen = '0' then
- sts_error_code(0) <= '1';
- sts_error_volt <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Check for out-of-range address
- otp_prog_idx := to_integer(unsigned(otp_prog_offset(otp_prog_offset'high downto 1)));
- if otp_prog_idx < 16#80# or otp_prog_idx > 16#88# then
- sts_error_code(0) <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- -- Check for protection bits
- if otp_prog_idx >= 16#81# and otp_prog_idx <= 16#84# then
- if plr_reg(0) = '0' then
- sts_error_code(0) <= '1';
- sts_error_lock <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- end if;
- if otp_prog_idx >= 16#85# and otp_prog_idx <= 16#88# then
- if plr_reg(1) = '0' then
- sts_error_code(0) <= '1';
- sts_error_lock <= '1';
- cur_wsm_state <= W_READY after T_STS;
- end if;
- end if;
- -- Write zeroes and return to ready
- if otp_prog_idx = 16#80# then
- plr_reg <= plr_reg and otp_prog_data;
- else
- otp_prog_idx := otp_prog_idx - 16#81#;
- otp_reg(otp_prog_idx) <= otp_reg(otp_prog_idx) and otp_prog_data;
- end if;
- cur_wsm_state <= W_READY after T_WHQV5; -- Best guess for timing
-
- when W_RESUME =>
- if sts_susp_prog = '1' then
- -- Precedence goes to resuimg programming operation
- sts_susp_prog <= '0';
- cur_wsm_state <= W_PROG after T_STS;
- elsif sts_susp_erase = '1' then
- -- Resume erase operation if no programming operation pending
- sts_susp_erase <= '0';
- cur_wsm_state <= W_ERASE after T_STS;
- else
- -- Nothing to resume, return to ready
- cur_wsm_state <= W_READY after T_STS;
- end if;
-
- when others =>
- cur_wsm_state <= W_READY after T_STS;
- end case;
- end process;
-
-
- ----------------------------------------------------------------------------
- -- Check for erroneous usages
-
- -- Should not try to read and write at the same time
- process (oe_n, we_n)
- begin
- assert not (oe_n = '0' and we_n = '0')
- report "OE# and WE# should never be enabled simultaneously."
- severity error;
- end process;
-
- -- Address must be valid for a full read or write cycle
- R1: process (oe_n, a(23 downto 4))
- begin
- -- FIXME: Check more address bits if in non-array or 4-word array modes
- if a(23 downto 4)'event and oe_n = '0' then
- assert a(23 downto 4)'last_event >= T_AVAV;
- report "T_AVAV not met (Read/Write Cycle Time)"
- severity error;
- end if;
- end process;
-
- -- BYTE# cannot change more than T_ELFL/T_ELFH after CEx goes low
- R11: process (byte_n, internal_ce_n)
- begin
- if byte_n'event and internal_ce_n = '0' then
- assert internal_ce_n'last_event <= T_ELFL;
- report "T_ELFL/H not met (CEx Low to BYTE# High or Low)"
- severity error;
- end if;
- end process;
-
- -- WE# and CEx cannot become active less than T_PHWL/EL after RP# goes high
- W1: process (rp_n, we_n, internal_ce_n)
- begin
- if rp_n = '1' then
- if falling_edge(we_n) then
- assert rp_n'last_event >= T_PHWL
- report "T_PHWL not met (RP# High Recovery to WE# Going Low)"
- severity error;
- end if;
- if falling_edge(internal_ce_n) then
- assert rp_n'last_event >= T_PHEL
- report "T_PHEL not met (RP# High Recovery to CEx Going Low)"
- severity error;
- end if;
- end if;
- end process;
-
- -- CEx and WE# may have set-up timing constraints relative to each other
- W2: process (we_n, internal_ce_n)
- begin
- if falling_edge(we_n) and internal_ce_n = '0' then
- assert internal_ce_n'last_event >= T_ELWL
- report "T_ELWL not met (CEx Low to WE# Going Low)"
- severity error;
- end if;
- if falling_edge(internal_ce_n) and we_n = '0' then
- assert we_n'last_event >= T_WLEL
- report "T_WLEL not met (WE# Low to CEx Going Low)"
- severity error;
- end if;
- end process;
-
- -- WE# has a minimum low pulse width
- W3: process (we_n)
- begin
- if rising_edge(we_n) then
- --assert we_n'last_event >= T_WP
- assert we_n'delayed(T_WP) = '0'
- report "T_WP not met (Write Pulse Width)"
- severity error;
- end if;
- end process;
-
- -- Data-in set-up time (no need to use internal_we_n here)
- W4: process (internal_we_n, d)
- begin
- if rising_edge(internal_we_n) then
- -- T_DVEH and T_DVWH are the same in the datasheet, so they probably
- -- refer to the internal write-latch signal composed of CEx and WE#.
- -- Checking against the internal signal prevents us from checking
- -- timing between our own output and CEx during write cycles.
- assert d'delayed'last_event >= T_DVWH -- Also T_DVEH
- report "T_DVWH/T_DVEH not met (Data Setup to WE#/CEx Going High)" & time'image(d'last_event)
- severity error;
- end if;
- --if rising_edge(we_n) then
- -- assert d'last_event >= T_DVWH
- -- report "T_DVWH not met (Data Setup to WE# Going High)"
- -- severity error;
- --end if;
- --if rising_edge(internal_ce_n) then
- -- -- Have seen some false-positives where d'last_event = 0 ps, but d'event = False
- -- -- Delaying 1 ps will get past any event in the current simulation cycle
- -- assert d'delayed(1 ps)'last_event >= T_DVEH
- -- report "T_DVEH not met (Data Setup to CEx Going High)"
- -- severity error;
- --end if;
- end process;
-
- -- Address set-up time (no need to use internal_we_n here)
- W5: process (internal_we_n, a)
- begin
- if rising_edge(internal_we_n) then
- -- T_AVEH and T_AVWH are the same in the datasheet, so they probably
- -- refer to the internal write-latch signal composed of CEx and WE#.
- -- Checking against the internal signal prevents us from checking
- -- timing against CEx during read cycles.
- assert a'last_event >= T_AVWH -- Also T_DVEH
- report "T_AVWH/T_DVEH not met (Data Setup to WE#/CEx Going High)"
- severity error;
- end if;
- --if rising_edge(we_n) then
- -- assert a'last_event >= T_AVWH
- -- report "T_AVWH not met (Address Setup to WE# Going High)"
- -- severity error;
- --end if;
- --if rising_edge(internal_ce_n) then
- -- assert a'last_event >= T_AVEH
- -- report "T_AVEH not met (Address Setup to CEx Going High)"
- -- severity error;
- --end if;
- end process;
-
- -- CEx and WE# may have hold timing constraints relative to each other
- W6: process (we_n, internal_ce_n)
- begin
- if rising_edge(we_n) and internal_ce_n = '1' then
- assert internal_ce_n'last_event >= T_EHWH
- report "T_EHWH not met (WE# Hold from CEx High)"
- severity error;
- end if;
- if rising_edge(internal_ce_n) and we_n = '1' then
- assert we_n'last_event >= T_WHEH
- report "T_WHEH not met (CEx Hold from WE# High)"
- severity error;
- end if;
- end process;
-
- -- Data-in hold time
- W7: process (internal_we_n, d)
- begin
- if d'event and internal_we_n = '1' then
- assert internal_we_n'last_event >= T_WHDX -- T_EHDX
- report "T_W/EHDX not met (Data Hold from WE# (CEx) High)"
- severity error;
- end if;
- end process;
-
- -- Address hold time
- W8: process (internal_we_n, a)
- begin
- if a'event and internal_we_n = '1' then
- assert internal_we_n'last_event >= T_WHAX -- T_EHAX
- report "T_W/EHAX not met (Address Hold from WE# (CEx) High)"
- severity error;
- end if;
- end process;
-
- -- WE# has a minimum high pulse width
- W9: process (we_n)
- begin
- if falling_edge(we_n) then
- --assert we_n'last_event >= T_WPH
- assert we_n'delayed(T_WPH) = '1'
- report "T_WPH not met (Write Pulse Width High)"
- severity error;
- end if;
- end process;
-
- -- Vpen set-up time before write latch (don't need to use internal_we_n here)
- W11: process (we_n, internal_ce_n, vpen)
- begin
- if rising_edge(we_n) and vpen = '1' then
- assert vpen'last_event >= T_VPWH
- report "T_VPWH not met (Vpen Setup to WE# High)"
- severity error;
- end if;
- if rising_edge(internal_ce_n) and vpen = '1' then
- assert vpen'last_event >= T_VPEH
- report "T_VPEH not met (Vpen Setup to CEx High)"
- severity error;
- end if;
- end process;
-
- -- Write recovery before Read
- W12: process (internal_we_n, oe_n)
- begin
- if falling_edge(oe_n) and internal_we_n = '1' then
- assert internal_we_n'last_event >= T_WHGL -- T_EHGL
- report "T_W/EHGL not met (Write Recovery before Read)"
- severity error;
- end if;
- end process;
-
- -- Vpen hold time
- W15: process (vpen)
- begin
- -- TODO: T_QVVL never shown on any waveform diagrams
- end process;
-
- -- RP# pulse time
- P1: process (rp_n)
- begin
- if rising_edge(rp_n) then
- -- If the simulations tarts with rp_n = '0' then last_event won't work
- -- assert rp_n'last_event >= T_PLPH
- assert rp_n'delayed(T_PLPH) = '0'
- report "T_PLPH not met (RP# Pulse Low Time)"
- severity error;
- end if;
- end process;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library simulated;
-
-
-entity mt45w8mw16bgx is
- port (
- a: in std_logic_vector(22 downto 0);
- dq: inout std_logic_vector(15 downto 0);
- clk: in std_logic;
- adv_n: in std_logic;
- cre: in std_logic;
- ce_n: in std_logic;
- oe_n: in std_logic;
- we_n: in std_logic;
- lb_n: in std_logic;
- ub_n: in std_logic;
- rwait: out std_logic
- );
-end mt45w8mw16bgx;
-
-
-architecture behavioral of mt45w8mw16bgx is
-
- -- Timings (-708/80MHz)
- constant T_AA: time := 70 ns; -- Address access time
- constant T_AADV: time := 70 ns; -- ADV# access time
- constant T_ABA: time := 46.5 ns; --
- constant T_ACLK: time := 9 ns; --
- constant T_APA: time := 20 ns; -- Page access time
- constant T_AS: time := 0 ns; --
- constant T_AVH: time := 2 ns; -- Address hold from ADV# HIGH
- constant T_AVS: time := 5 ns; -- Address setup to ADV# HIGH
- constant T_AW: time := 70 ns; --
- constant T_BA: time := 70 ns; -- LB#/UB# access time
- constant T_BHZ: time := 8 ns; -- LB#/UB# disable to DQ High-Z output
- constant T_BLZ: time := 10 ns; -- LB#/UB# enable to Low-Z output
- constant T_BOE: time := 20 ns; --
- constant T_BW: time := 70 ns; --
- constant T_CBPH: time := 6 ns; --
- constant T_CEM: time := 4 us; -- Maximum CE# pulse width
- constant T_CEW: time := 7.5 ns; -- CE# LOW to WAIT valid
- constant T_CLK: time := 12.5 ns; --
- constant T_CO: time := 70 ns; -- Chip select access time
- constant T_CPH: time := 5 ns; --
- constant T_CSP: time := 4 ns; --
- constant T_CVS: time := 7 ns; -- CE# LOW to ADV# HIGH
- constant T_CW: time := 70 ns; --
- constant T_DH: time := 0 ns; --
- constant T_DPD: time := 10 us; --
- constant T_DPDX: time := 10 us; --
- constant T_DW: time := 20 ns; --
- constant T_HD: time := 2 ns; --
- constant T_HZ: time := 8 ns; -- Chip disable to DQ and WAIT High-Z output
- constant T_KHKL: time := 1.8 ns; --
- constant T_KHTL: time := 9 ns; --
- constant T_KOH: time := 2 ns; --
- constant T_KP: time := 4 ns; --
- constant T_LZ: time := 10 ns; -- Chip enable to Low-Z output
- constant T_OE: time := 20 ns; -- Output enable to valid output
- constant T_OH: time := 5 ns; -- Output hold from address change
- constant T_OHZ: time := 8 ns; -- Output disable to DQ High-Z output
- constant T_OLZ: time := 3 ns; -- Output enable to Low-Z output
- constant T_OW: time := 5 ns; --
- constant T_PC: time := 20 ns; -- Page READ cycle time
- constant T_PU: time := 150 us; --
- constant T_RC: time := 70 ns; -- READ cycle time
- constant T_SP: time := 3 ns; --
- constant T_VP: time := 5 ns; -- ADV# pulse width LOW
- constant T_VS: time := 70 ns; --
- constant T_WC: time := 70 ns; --
- constant T_WHZ: time := 8 ns; --
- constant T_WP: time := 45 ns; --
- constant T_WPH: time := 10 ns; --
- constant T_WR: time := 0 ns; --
-
- -- Internal types
- type word_array is array(natural range <>) of std_logic_vector(15 downto 0);
-
- -- Data array read signals
- signal array_reg: word_array(15 downto 0) := (others => (others => '1'));
- signal array_word: std_logic_vector(15 downto 0);
- signal read_word: std_logic_vector(15 downto 0);
- signal xmask_addr: std_logic;
- signal xmask_ce_n: std_logic;
- signal xmask_oe_n: std_logic;
- signal xmask_ub_n: std_logic;
- signal xmask_lb_n: std_logic;
- signal xmask_hi: std_logic;
- signal xmask_lo: std_logic;
- signal zmask_ce_n: std_logic;
- signal zmask_oe_n: std_logic;
- signal zmask_ub_n: std_logic;
- signal zmask_lb_n: std_logic;
- signal zmask_hi: std_logic;
- signal zmask_lo: std_logic;
-
- -- Data array write signals
- signal internal_we_ub_n: std_logic;
- signal internal_we_lb_n: std_logic;
-
- -- Configuration registers
- signal bcr_reg: std_logic_vector(15 downto 0) := x"9d1f";
- signal rcr_reg: std_logic_vector(15 downto 0) := x"0010";
- signal didr_reg: std_logic_vector(15 downto 0) := x"0343";
-
-begin
-
- ----------------------------------------------------------------------------
- -- Asynchronous array reads
-
- -- Look up value from memory array, delay to allow for hold time
- array_word <= array_reg(to_integer(unsigned(a))) after T_HZ; -- T_OHZ, T_BHZ
-
- -- Generate mask for periods of time with invalid data
- -- FIXME: this may break hold time
- xm_addr: entity simulated.changed_within_t_vec generic map (T => T_AA, T_HOLD => T_OH)
- port map (sig_in => a, sig_out => xmask_addr);
- xm_ce: entity simulated.changed_within_t generic map (T => T_CO, T_HOLD => T_HZ)
- port map (sig_in => ce_n, sig_out => xmask_ce_n);
- xm_oe: entity simulated.changed_within_t generic map (T => T_OE, T_HOLD => T_OHZ)
- port map (sig_in => oe_n, sig_out => xmask_oe_n);
- xm_ub: entity simulated.changed_within_t generic map (T => T_BA, T_HOLD => T_BHZ)
- port map (sig_in => ub_n, sig_out => xmask_ub_n);
- xm_lb: entity simulated.changed_within_t generic map (T => T_BA, T_HOLD => T_BHZ)
- port map (sig_in => lb_n, sig_out => xmask_lb_n);
- xmask_hi <= xmask_addr or xmask_ce_n or xmask_oe_n or xmask_ub_n;
- xmask_lo <= xmask_addr or xmask_ce_n or xmask_oe_n or xmask_lb_n;
-
- -- Invalidate data for some periods of time
- read_word(15 downto 8) <= (others => 'X') when xmask_hi = '1' else array_word(15 downto 8);
- read_word( 7 downto 0) <= (others => 'X') when xmask_lo = '1' else array_word( 7 downto 0);
-
- -- Generate mask for periods of time where data bus is high-z
- zm_ce: entity simulated.delay_edges generic map (D_RISE => T_HZ, D_FALL => T_LZ)
- port map (sig_in => ce_n, sig_out => zmask_ce_n);
- zm_oe: entity simulated.delay_edges generic map (D_RISE => T_OHZ, D_FALL => T_OLZ)
- port map (sig_in => oe_n, sig_out => zmask_oe_n);
- zm_ub: entity simulated.delay_edges generic map (D_RISE => T_BHZ, D_FALL => T_BLZ)
- port map (sig_in => ub_n, sig_out => zmask_ub_n);
- zm_lb: entity simulated.delay_edges generic map (D_RISE => T_BHZ, D_FALL => T_BLZ)
- port map (sig_in => lb_n, sig_out => zmask_lb_n);
- zmask_hi <= zmask_ce_n or zmask_oe_n or zmask_ub_n;
- zmask_lo <= zmask_ce_n or zmask_oe_n or zmask_lb_n;
-
- -- Generate output data signals
- dq(15 downto 8) <= (others => 'Z') when zmask_hi = '1' or we_n = '0'
- else read_word(15 downto 8);
- dq( 7 downto 0) <= (others => 'Z') when zmask_lo = '1' or we_n = '0'
- else read_word( 7 downto 0);
-
-
- ----------------------------------------------------------------------------
- -- Asynchronous array writes
-
- -- Internal signals to trigger latching of data
- internal_we_ub_n <= ce_n or we_n or ub_n;
- internal_we_lb_n <= ce_n or we_n or lb_n;
-
- -- Latch data on rising edge of write signal
- process (internal_we_ub_n, internal_we_lb_n)
- begin
- -- Changing (or tristating) DQ at the same moment as the write rising-edge should
- -- be allowed (T_DH, data hold time, = 0 ns), but this breaks in ISim 14.7, hence
- -- the 1 ps delay.
- if rising_edge(internal_we_ub_n) then
- array_reg(to_integer(unsigned(a)))(15 downto 8) <= dq(15 downto 8)'delayed(1 ps);
- end if;
-
- if rising_edge(internal_we_lb_n) then
- array_reg(to_integer(unsigned(a)))( 7 downto 0) <= dq( 7 downto 0)'delayed(1 ps);
- end if;
- end process;
-
-
- ----------------------------------------------------------------------------
- -- Check for erroneous usage
-
- -- TODO: check T_AVH, T_AVS, T_CVS, T_VP, T_AS
- assert adv_n = '0'
- report "ADV# not yet supported"
- severity error;
-
- assert clk = '0'
- report "Synchronous operation not yet supported"
- severity error;
-
-
- -- Should (probably) not assert oe_n and we_n at the same time
- process (oe_n, we_n)
- begin
- assert not (oe_n = '0' and we_n = '0')
- report "OE# and WE# are active simultaneously (write takes precedence)"
- severity warning;
- end process;
-
- -- Maximum CE# pulse width (to allow internal refresh)
- process (ce_n)
- begin
- if rising_edge(ce_n) then
- assert ce_n'last_event < T_CEM
- report "T_CEM not met (Maximum CE# pulse width)"
- severity error;
- end if;
- end process;
-
-
- -- Write recovery time (address hold time)
- process (a, internal_we_ub_n, internal_we_lb_n)
- begin
- if a'event then
- if internal_we_ub_n = '1' then
- assert internal_we_ub_n'last_event >= T_WR
- report "T_WR not met (Write recovery time)"
- severity error;
- end if;
- if internal_we_lb_n = '1' then
- assert internal_we_lb_n'last_event >= T_WR
- report "T_WR not met (Write recovery time)"
- severity error;
- end if;
- end if;
- end process;
-
- -- Address valid to end of WRITE
- process (a, internal_we_ub_n, internal_we_lb_n)
- begin
- if rising_edge(internal_we_ub_n) then
- assert a'last_event >= T_AW
- report "T_AW not met (Address valid to end of WRITE)"
- severity error;
- end if;
- if rising_edge(internal_we_lb_n) then
- assert a'last_event >= T_AW
- report "T_AW not met (Address valid to end of WRITE)"
- severity error;
- end if;
- end process;
-
- -- Chip enable to end of WRITE
- process (ce_n, internal_we_ub_n, internal_we_lb_n)
- begin
- if rising_edge(internal_we_ub_n) then
- assert ce_n'delayed'delayed'last_event >= T_CW
- report "T_CW not met (Chip enable to end of WRITE)"
- severity error;
- end if;
- if rising_edge(internal_we_lb_n) then
- assert ce_n'delayed'delayed'last_event >= T_CW
- report "T_CW not met (Chip enable to end of WRITE)"
- severity error;
- end if;
- end process;
-
- -- CE# HIGH between subsequent async operations
- process (ce_n)
- begin
- if falling_edge(ce_n) then
- assert ce_n'delayed'last_event >= T_CPH
- report "T_CPH not met (CE# HIGH between subsequent async operations)"
- severity error;
- end if;
- end process;
-
- -- LB#/UB# select to end of WRITE
- process (ub_n, lb_n, internal_we_ub_n, internal_we_lb_n)
- begin
- if rising_edge(internal_we_ub_n) then
- assert ub_n'last_event >= T_BW
- report "T_BW not met (UB# select to end of WRITE)"
- severity error;
- end if;
- if rising_edge(internal_we_lb_n) then
- assert lb_n'last_event >= T_BW
- report "T_BW not met (LB# select to end of WRITE)"
- severity error;
- end if;
- end process;
-
- -- WRITE pulse width
- process (we_n, internal_we_ub_n, internal_we_lb_n)
- variable t: time;
- begin
- -- Datasheet specifies WE# HIGH pulse width strictly on WE# signal
- -- FIXME: should this be strictly on internal we signals?
- if falling_edge(we_n) then
- assert we_n'delayed'last_event >= T_WPH
- report "T_WPH not met (WRITE pulse width HIGH)"
- severity error;
- end if;
- -- Datasheet specifies WE# LOW pulse width against whatever signal triggers write
- -- FIXME: should this be strictly on internal we signals?
- if rising_edge(internal_we_ub_n) then
- assert we_n'delayed'delayed'last_event >= T_WP
- report "T_WP not met (WRITE pulse width)"
- severity error;
- end if;
- if rising_edge(internal_we_lb_n) then
- t := we_n'delayed'delayed'last_event;
- assert we_n'delayed'delayed'last_event >= T_WP
- report "T_WP not met (WRITE pulse width)" & time'image(t)
- severity error;
- end if;
- end process;
-
- -- Data setup and hold times
- process (dq, internal_we_ub_n, internal_we_lb_n)
- begin
- if rising_edge(internal_we_ub_n) then
- assert dq(15 downto 8)'delayed'delayed'last_event >= T_DW
- report "T_DW not met (Data upper byte WRITE setup time)"
- severity error;
- end if;
- if rising_edge(internal_we_lb_n) then
- assert dq(7 downto 0)'delayed'delayed'last_event >= T_DW
- report "T_DW not met (Data lower byte WRITE setup time)"
- severity error;
- end if;
- if dq(15 downto 8)'event then
- assert internal_we_ub_n'last_event >= T_DH
- report "T_DH not met (Data upper byte HOLD from WRITE time)"
- severity error;
- end if;
- if dq(7 downto 0)'event then
- assert internal_we_lb_n'last_event >= T_DH
- report "T_DH not met (Data lower byte HOLD from WRITE time)"
- severity error;
- end if;
- end process;
-
-end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.std_logic_misc.all;
+
+
+entity proto_ps2 is
+ port (
+ tx_byte: in std_logic_vector(7 downto 0);
+
+ ps2_clk: inout std_logic;
+ ps2_data: inout std_logic
+ );
+end proto_ps2;
+
+
+architecture behavioral of proto_ps2 is
+
+ type state_t is (
+ S_IDLE, S_INHIBIT,
+ S_TX_BIT_L, S_TX_BIT_H, S_TX_STOP_L, S_TX_STOP_H,
+ S_RX_BIT_L, S_RX_BIT_H, S_RX_STOP_L
+ );
+
+ -- Timings from http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
+ -- Slowest timing:
+ --constant T1: time := 25 us; -- Time from DATA transition to falling edge of CLK
+ --constant T2: time := 45 us; -- Time from rising edge of CLK to DATA transition
+ --constant T3: time := 50 us; -- Duration of CLK inactive (Tx)
+ --constant T4: time := 50 us; -- Duration of CLK active (Tx)
+ --constant T5: time := 50 us;
+ --constant T7: time := 50 us; -- Duration of CLK inactive (Rx)
+ --constant T8: time := 50 us; -- Duration of CLK active (Rx)
+ --constant T9: time := 25 us; -- Time after CLK rise to sample
+
+ -- Fastest timing:
+ constant T1: time := 5 us; -- Time from DATA transition to falling edge of CLK
+ constant T2: time := 5 us; -- Time from rising edge of CLK to DATA transition
+ constant T3: time := 30 us; -- Duration of CLK inactive (Tx)
+ constant T4: time := 30 us; -- Duration of CLK active (Tx)
+ --constant T5: time := 0 us;
+ constant T7: time := 30 us; -- Duration of CLK inactive (Rx)
+ constant T8: time := 30 us; -- Duration of CLK active (Rx)
+ constant T9: time := 5 us; -- Time after CLK rise to sample
+
+ signal cur_state: state_t := S_IDLE;
+
+ signal tx_req: boolean;
+
+ -- CLK and DATA that the device is *trying* to drive, can be overridden by the host
+ signal dev_clk: std_logic := '1';
+ signal dev_data: std_logic := '1';
+
+ -- For detecting when the host overrides device's CLK and DATA
+ signal inhibit: std_logic;
+ signal host_tx: std_logic;
+
+ signal test_sample: std_logic;
+
+ signal data: std_logic_vector(10 downto 0);
+ signal i: integer;
+
+begin
+
+ test_sample <= ps2_data'delayed(T8 - T9);
+
+ process (cur_state, inhibit, host_tx, tx_req, tx_byte)
+ --variable data: std_logic_vector(10 downto 0);
+ --variable i: integer;
+ variable temp: std_logic;
+ begin
+ if inhibit'event then
+ if inhibit = '1' then
+ -- Abort any transmissions when inhibited
+ if cur_state /= S_IDLE then
+ report "PS2 device inhibited (transmission aborted)";
+ else
+ report "PS2 device inhibited";
+ end if;
+ if cur_state = S_TX_STOP_L or cur_state = S_TX_STOP_H then
+ -- FIXME: prevent inhibition during the stop bit, reporting is fine for now
+ report "PS2 device inhibited during stop bit" severity error;
+ end if;
+ cur_state <= S_INHIBIT;
+ else
+ report "PS2 device uninhibited";
+ if host_tx = '1' then
+ i <= 0;
+ data <= (others => '0');
+ cur_state <= S_RX_BIT_L after T8;
+ else
+ cur_state <= S_IDLE;
+ end if;
+ end if;
+ elsif tx_req'event and tx_req then
+ report "PS2 device beginning transmission";
+ data <= '1' & '1' & (not xor_reduce(tx_byte)) & tx_byte;
+ i <= 0;
+ dev_data <= '0';
+ cur_state <= S_TX_BIT_L after T1;
+ elsif host_tx'event and host_tx = '1' then
+ if not (cur_state = S_IDLE or cur_state = S_INHIBIT or
+ cur_state = S_RX_BIT_L or cur_state = S_RX_BIT_H or cur_state = S_RX_STOP_L) then
+ report "PS2 device saw unexpected drop in DATA line" severity error;
+ elsif cur_state = S_IDLE then
+ -- http://www.mcamafia.de/pdf/ibm_hitrc07.pdf *implies* that the
+ -- device should still receive data without the host pulling the
+ -- clock low first, but this is unusual and could cause problems
+ -- if the device is about to begin a transmission.
+ report "PS2 device saw drop in DATA line while not inhibited" severity warning;
+ i <= 0;
+ data <= (others => '0');
+ cur_state <= S_RX_BIT_L after T8;
+ end if;
+ elsif cur_state'event then
+ -- Self-driving state machine, can be pushed into states by the rest of the process
+ case cur_state is
+ when S_IDLE =>
+ dev_clk <= '1';
+ dev_data <= '1';
+
+ when S_TX_BIT_L =>
+ dev_clk <= '0';
+ if i < 9 then
+ cur_state <= S_TX_BIT_H after T3;
+ else
+ cur_state <= S_TX_STOP_H after T3;
+ end if;
+
+ when S_TX_BIT_H =>
+ dev_clk <= '1';
+ dev_data <= data(i) after T2;
+ i <= i + 1;
+ cur_state <= S_TX_BIT_L after T4;
+
+ when S_TX_STOP_H =>
+ dev_clk <= '1';
+ dev_data <= '1' after T2;
+ cur_state <= S_TX_STOP_L after T4;
+
+ when S_TX_STOP_L =>
+ dev_clk <= '0';
+ cur_state <= S_IDLE after T3;
+
+ when S_INHIBIT =>
+ dev_clk <= '1';
+ dev_data <= '1';
+
+ when S_RX_BIT_L =>
+ dev_clk <= '0';
+ data(i) <= ps2_data'delayed(T8 - T9); -- Reach back into the previous clock high period
+ i <= i + 1;
+ cur_state <= S_RX_BIT_H after T7;
+
+ when S_RX_BIT_H =>
+ dev_clk <= '1';
+ if i <= 9 then
+ cur_state <= S_RX_BIT_L after T8;
+ else
+ cur_state <= S_RX_STOP_L after T8;
+ end if;
+
+ when S_RX_STOP_L =>
+ dev_clk <= '0';
+ dev_data <= '0'; -- Pull DATA low to acknowledge
+ data(i) <= ps2_data'delayed(T8 - T9); -- Reach back into the previous clock high period
+ temp := ps2_data'delayed(T8 - T9);
+ report "PS2 device recieved " & integer'image(to_integer(unsigned(data(8 downto 1))));
+ -- Spec says device should continue clocking and request a
+ -- resend if it gets a zero stop bit, but that's already an
+ -- error condition so reporting is sufficient.
+ assert temp /= '0'
+ report "PS2 device got a 0 stop bit"
+ severity error;
+ assert xor_reduce(data(9 downto 1)) = '1'
+ report "PS2 device received wrong parity"
+ severity error;
+ cur_state <= S_IDLE after T7;
+
+ when others =>
+ cur_state <= S_IDLE;
+ end case;
+ end if;
+ end process;
+
+ -- Check for anything driving the CLK and DATA lines too hard
+ process (ps2_clk, ps2_data)
+ begin
+ if ps2_clk = '1' then
+ report "PS2 clock line driven harder than expected" severity error;
+ end if;
+ if ps2_data = '1' then
+ report "PS2 data line driven harder than expected" severity error;
+ end if;
+ end process;
+
+ -- Weaken clock and data high signals
+ ps2_clk <= '0' when dev_clk = '0' else 'H';
+ ps2_data <= '0' when dev_data = '0' else 'H';
+
+ -- Detect host signaling
+ -- Needs delayed dev_clk/data to account for "gate delay" from computing ps2_clk/data from dev_clk/data
+ inhibit <= '1' when ps2_clk = '0' and dev_clk'delayed = '1' else '0';
+ host_tx <= '1' when ps2_data = '0' and dev_data'delayed = '1' else '0';
+
+ -- Detect test process transmit request
+ tx_req <= not tx_byte'quiet;
+
+end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-use ieee.std_logic_misc.all;
-
-
-entity ps2_device is
- port (
- tx_byte: in std_logic_vector(7 downto 0);
-
- ps2_clk: inout std_logic;
- ps2_data: inout std_logic
- );
-end ps2_device;
-
-
-architecture behavioral of ps2_device is
-
- type state_t is (
- S_IDLE, S_INHIBIT,
- S_TX_BIT_L, S_TX_BIT_H, S_TX_STOP_L, S_TX_STOP_H,
- S_RX_BIT_L, S_RX_BIT_H, S_RX_STOP_L
- );
-
- -- Timings from http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
- -- Slowest timing:
- --constant T1: time := 25 us; -- Time from DATA transition to falling edge of CLK
- --constant T2: time := 45 us; -- Time from rising edge of CLK to DATA transition
- --constant T3: time := 50 us; -- Duration of CLK inactive (Tx)
- --constant T4: time := 50 us; -- Duration of CLK active (Tx)
- --constant T5: time := 50 us;
- --constant T7: time := 50 us; -- Duration of CLK inactive (Rx)
- --constant T8: time := 50 us; -- Duration of CLK active (Rx)
- --constant T9: time := 25 us; -- Time after CLK rise to sample
-
- -- Fastest timing:
- constant T1: time := 5 us; -- Time from DATA transition to falling edge of CLK
- constant T2: time := 5 us; -- Time from rising edge of CLK to DATA transition
- constant T3: time := 30 us; -- Duration of CLK inactive (Tx)
- constant T4: time := 30 us; -- Duration of CLK active (Tx)
- --constant T5: time := 0 us;
- constant T7: time := 30 us; -- Duration of CLK inactive (Rx)
- constant T8: time := 30 us; -- Duration of CLK active (Rx)
- constant T9: time := 5 us; -- Time after CLK rise to sample
-
- signal cur_state: state_t := S_IDLE;
-
- signal tx_req: boolean;
-
- -- CLK and DATA that the device is *trying* to drive, can be overridden by the host
- signal dev_clk: std_logic := '1';
- signal dev_data: std_logic := '1';
-
- -- For detecting when the host overrides device's CLK and DATA
- signal inhibit: std_logic;
- signal host_tx: std_logic;
-
- signal test_sample: std_logic;
-
- signal data: std_logic_vector(10 downto 0);
- signal i: integer;
-
-begin
-
- test_sample <= ps2_data'delayed(T8 - T9);
-
- process (cur_state, inhibit, host_tx, tx_req, tx_byte)
- --variable data: std_logic_vector(10 downto 0);
- --variable i: integer;
- variable temp: std_logic;
- begin
- if inhibit'event then
- if inhibit = '1' then
- -- Abort any transmissions when inhibited
- if cur_state /= S_IDLE then
- report "PS2 device inhibited (transmission aborted)";
- else
- report "PS2 device inhibited";
- end if;
- if cur_state = S_TX_STOP_L or cur_state = S_TX_STOP_H then
- -- FIXME: prevent inhibition during the stop bit, reporting is fine for now
- report "PS2 device inhibited during stop bit" severity error;
- end if;
- cur_state <= S_INHIBIT;
- else
- report "PS2 device uninhibited";
- if host_tx = '1' then
- i <= 0;
- data <= (others => '0');
- cur_state <= S_RX_BIT_L after T8;
- else
- cur_state <= S_IDLE;
- end if;
- end if;
- elsif tx_req'event and tx_req then
- report "PS2 device beginning transmission";
- data <= '1' & '1' & (not xor_reduce(tx_byte)) & tx_byte;
- i <= 0;
- dev_data <= '0';
- cur_state <= S_TX_BIT_L after T1;
- elsif host_tx'event and host_tx = '1' then
- if not (cur_state = S_IDLE or cur_state = S_INHIBIT or
- cur_state = S_RX_BIT_L or cur_state = S_RX_BIT_H or cur_state = S_RX_STOP_L) then
- report "PS2 device saw unexpected drop in DATA line" severity error;
- elsif cur_state = S_IDLE then
- -- http://www.mcamafia.de/pdf/ibm_hitrc07.pdf *implies* that the
- -- device should still receive data without the host pulling the
- -- clock low first, but this is unusual and could cause problems
- -- if the device is about to begin a transmission.
- report "PS2 device saw drop in DATA line while not inhibited" severity warning;
- i <= 0;
- data <= (others => '0');
- cur_state <= S_RX_BIT_L after T8;
- end if;
- elsif cur_state'event then
- -- Self-driving state machine, can be pushed into states by the rest of the process
- case cur_state is
- when S_IDLE =>
- dev_clk <= '1';
- dev_data <= '1';
-
- when S_TX_BIT_L =>
- dev_clk <= '0';
- if i < 9 then
- cur_state <= S_TX_BIT_H after T3;
- else
- cur_state <= S_TX_STOP_H after T3;
- end if;
-
- when S_TX_BIT_H =>
- dev_clk <= '1';
- dev_data <= data(i) after T2;
- i <= i + 1;
- cur_state <= S_TX_BIT_L after T4;
-
- when S_TX_STOP_H =>
- dev_clk <= '1';
- dev_data <= '1' after T2;
- cur_state <= S_TX_STOP_L after T4;
-
- when S_TX_STOP_L =>
- dev_clk <= '0';
- cur_state <= S_IDLE after T3;
-
- when S_INHIBIT =>
- dev_clk <= '1';
- dev_data <= '1';
-
- when S_RX_BIT_L =>
- dev_clk <= '0';
- data(i) <= ps2_data'delayed(T8 - T9); -- Reach back into the previous clock high period
- i <= i + 1;
- cur_state <= S_RX_BIT_H after T7;
-
- when S_RX_BIT_H =>
- dev_clk <= '1';
- if i <= 9 then
- cur_state <= S_RX_BIT_L after T8;
- else
- cur_state <= S_RX_STOP_L after T8;
- end if;
-
- when S_RX_STOP_L =>
- dev_clk <= '0';
- dev_data <= '0'; -- Pull DATA low to acknowledge
- data(i) <= ps2_data'delayed(T8 - T9); -- Reach back into the previous clock high period
- temp := ps2_data'delayed(T8 - T9);
- report "PS2 device recieved " & integer'image(to_integer(unsigned(data(8 downto 1))));
- -- Spec says device should continue clocking and request a
- -- resend if it gets a zero stop bit, but that's already an
- -- error condition so reporting is sufficient.
- assert temp /= '0'
- report "PS2 device got a 0 stop bit"
- severity error;
- assert xor_reduce(data(9 downto 1)) = '1'
- report "PS2 device received wrong parity"
- severity error;
- cur_state <= S_IDLE after T7;
-
- when others =>
- cur_state <= S_IDLE;
- end case;
- end if;
- end process;
-
- -- Check for anything driving the CLK and DATA lines too hard
- process (ps2_clk, ps2_data)
- begin
- if ps2_clk = '1' then
- report "PS2 clock line driven harder than expected" severity error;
- end if;
- if ps2_data = '1' then
- report "PS2 data line driven harder than expected" severity error;
- end if;
- end process;
-
- -- Weaken clock and data high signals
- ps2_clk <= '0' when dev_clk = '0' else 'H';
- ps2_data <= '0' when dev_data = '0' else 'H';
-
- -- Detect host signaling
- -- Needs delayed dev_clk/data to account for "gate delay" from computing ps2_clk/data from dev_clk/data
- inhibit <= '1' when ps2_clk = '0' and dev_clk'delayed = '1' else '0';
- host_tx <= '1' when ps2_data = '0' and dev_data'delayed = '1' else '0';
-
- -- Detect test process transmit request
- tx_req <= not tx_byte'quiet;
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library work;
-use work.sim_utility.all;
-
-
-entity sim_js28f128j3d75 is
- generic (
- FILENAME: string := "";
- BASEADDR: natural := 0
- );
- port (
- a: in std_logic_vector(23 downto 0);
- d: inout std_logic_vector(15 downto 0);
- ce: in std_logic_vector(2 downto 0);
- rp_n: in std_logic;
- oe_n: in std_logic;
- we_n: in std_logic;
- sts: out std_logic; -- open drain
- byte_n: in std_logic;
- vpen: in std_logic
- );
-end sim_js28f128j3d75;
-
-
-architecture behavioral of sim_js28f128j3d75 is
- ----------------------------------------------------------------------------
- -- Timings for 128Mbit, J3D-75 parts
-
- -- Read timings
- constant T_AVAV: time := 75 ns; -- R1, Read/Write Cycle Time
- constant T_AVQV: time := 75 ns; -- R2, Address to Output Delay
- constant T_ELQV: time := 75 ns; -- R3, CEx to Output Delay
- constant T_GLQV_NA: time := 25 ns; -- R4, OE# to Non-Array Output Delay
- constant T_PHQV: time := 210 ns; -- R5, RP# High to Output Delay
- constant T_ELQX: time := 0 ns; -- R6, CEx to Output Low Z
- constant T_GLQX: time := 0 ns; -- R7, OE# to Output Low Z
- constant T_EHQZ: time := 25 ns; -- R8, CEx High to Output in High Z
- constant T_GHQZ: time := 15 ns; -- R9, OE# High to Output in High Z
- constant T_OH: time := 0 ns; -- R10, Output Hold from Address, CEx, or OE# change
- constant T_ELFL: time := 10 ns; -- R11, CEx Low to BYTE# High or Low
- constant T_ELFH: time := 10 ns; -- R11, (Same as Above)
- constant T_FLQV: time := 1 us; -- R12, BYTE# to Output Delay
- constant T_FHQV: time := 1 us; -- R12, (Same as Above)
- constant T_FLQZ: time := 1 us; -- R13, BYTE# to Output in High Z
- constant T_EHEL: time := 0 ns; -- R14, CEx High to CEx Low
- constant T_APA: time := 25 ns; -- R15, Page Address Access Time
- constant T_GLQV_A: time := 25 ns; -- R16, OE# to Array Output Delay
-
- -- Write timings
- constant T_PHWL: time := 210 ns; -- W1, RP# High Recovery to WE# (CEx) Going Low
- constant T_PHEL: time := 210 ns; -- W1, (Same as Above)
- constant T_ELWL: time := 0 ns; -- W2, CEx (WE#) Low to WE# (CEx) Going Low
- constant T_WLEL: time := 0 ns; -- W2, (Same as Above)
- constant T_WP: time := 60 ns; -- W3, Write Pulse Width
- constant T_DVWH: time := 50 ns; -- W4, Data Setup to WE# (CEx) Going High
- constant T_DVEH: time := 50 ns; -- W4, (Same as Above)
- constant T_AVWH: time := 55 ns; -- W5, Address Setup to WE# (CEx) Going High
- constant T_AVEH: time := 55 ns; -- W5, (Same as Above)
- constant T_WHEH: time := 0 ns; -- W6, CEx (WE#) Hold from WE# (CEx) High
- constant T_EHWH: time := 0 ns; -- W6, (Same as Above)
- constant T_WHDX: time := 0 ns; -- W7, Data Hold from WE# (CEx) High
- constant T_EHDX: time := 0 ns; -- W7, (Same as Above)
- constant T_WHAX: time := 0 ns; -- W8, Address Hold from WE# (CEx) High
- constant T_EHAX: time := 0 ns; -- W8, (Same as Above)
- constant T_WPH: time := 30 ns; -- W9, Write Pulse Width High
- constant T_VPWH: time := 0 ns; -- W11, Vpen Setup to WE# (CEx) Going High
- constant T_VPEH: time := 0 ns; -- W11, (Same as Above)
- constant T_WHGL: time := 35 ns; -- W12, Write Recovery before Read
- constant T_EHGL: time := 35 ns; -- W12, (Same as Above)
- constant T_WHRL: time := 500 ns; -- W13, WE# (CEx) High to STS Going Low
- constant T_EHRL: time := 500 ns; -- W13, (Same as Above)
- constant T_QVVL: time := 0 ns; -- W15, Vpen Hold from Valid SRD, STS Going High
-
- -- Configuration timings
- constant T_WHQV3: time := 175 us; -- W16, Byte Program Time (Using Word/Byte Program Command)
- constant T_EHQV3: time := 175 us; -- W16, (Same as above)
- constant T_WHQV4: time := 4 sec; -- W16, Block Erase Time
- constant T_EHQV4: time := 4 sec; -- W16, (Same as above)
- constant T_WHQV5: time := 60 us; -- W16, Set Lock-Bit Time
- constant T_EHQV5: time := 60 us; -- W16, (Same as above)
- constant T_WHQV6: time := 0.7 sec; -- W16, Clear Block Lock-Bits Time
- constant T_EHQV6: time := 0.7 sec; -- W16, (Same as above)
- constant T_WHRH1: time := 20 us; -- W16, Program Suspend Latency Time to Read
- constant T_EHRH1: time := 20 us; -- W16, (Same as above)
- constant T_WHRH: time := 20 us; -- W16, Erase Suspend Latency Time to Read
- constant T_EHRH: time := 20 us; -- W16, (Same as above)
- constant T_STS: time := 500 ns; -- WY, STS Pulse Width Low Time
-
- -- Reset timings
- constant T_PLPH: time := 25 us; -- P1, RP# Pulse Low Time
- constant T_PHRH: time := 100 ns; -- P2, RP# High to Reset During Block-Erase, Program, or Lock-Bit Configuration
- constant T_VCCPH: time := 60 us; -- P3, Vcc Power Valid to RP# de-assertion (high)
-
- ----------------------------------------------------------------------------
- -- Useful internal signals
-
- signal internal_ce_n: std_logic;
- signal internal_we_n: std_logic;
-
- ----------------------------------------------------------------------------
- -- Array value
-
- shared variable flash_array: sparse_t;
- signal array_word: std_logic_vector(15 downto 0);
-
- ----------------------------------------------------------------------------
- -- Device Information
-
- signal id_word: std_logic_vector(15 downto 0);
-
- ----------------------------------------------------------------------------
- -- Status Register
-
- signal sts_word: std_logic_vector(15 downto 0);
-
- signal sts_ready: std_logic;
- signal sts_susp_erase: std_logic;
- signal sts_error_erase: std_logic;
- signal sts_error_prog: std_logic;
- signal sts_error_vpen: std_logic;
- signal sts_susp_prog: std_logic;
- signal sts_error_lock: std_logic;
-
- ----------------------------------------------------------------------------
- -- CFI Query
-
- signal cfi_word: std_logic_vector(15 downto 0);
-
- ----------------------------------------------------------------------------
- -- Output value
-
- type read_state_t is (R_ARRAY, R_ID, R_STATUS, R_CFI);
- signal read_state_cur: read_state_t;
-
- signal word: std_logic_vector(15 downto 0);
- signal word_x: std_logic_vector(15 downto 0);
- signal word_xz: std_logic_vector(15 downto 0);
-
- signal xmask_rp: std_logic;
- signal xmask_byte: std_logic;
- signal xmask_ce: std_logic;
- signal xmask_oe: std_logic;
- signal xmask_addr_h: std_logic;
- signal xmask_addr_l: std_logic;
-
- signal zmask_ce: std_logic;
- signal zmask_oe: std_logic;
- signal zmask_byte: std_logic;
-
- ----------------------------------------------------------------------------
- -- Other registers
-
- signal ecr_reg: std_logic_vector(23 downto 0);
- signal sts_config_reg: std_logic_vector(7 downto 0);
-
- ----------------------------------------------------------------------------
- -- CUI state machine
-
- type cui_state_t is (
- C_IDLE,
- C_PROG_STS,
- C_PROG_OTP,
- C_PROG_WORD,
- C_PROG_BUF_COUNT,
- C_PROG_BUF_DATA,
- C_ERASE,
- C_LOCK_OR_ECR
- );
-
- signal cui_state_cur: cui_state_t;
-
- ----------------------------------------------------------------------------
- -- Write state machine
-
- type wsm_state_t is (
- W_IDLE,
- W_PROG_OTP,
- W_PROG_WORD,
- W_PROG_WORD_FINISH,
- W_PROG_BUF,
- W_ERASE,
- W_ERASE_FINISH,
- W_LOCK,
- W_UNLOCK
- );
-
- signal wsm_state_cur: wsm_state_t;
-
- signal trig_clrsts: std_logic;
- signal trig_susp: std_logic;
- signal trig_resume: std_logic;
- signal trig_cmderr: std_logic;
- signal trig_otp: std_logic;
- signal trig_word: std_logic;
- signal trig_buf: std_logic;
- signal trig_erase: std_logic;
- signal trig_lock: std_logic;
- signal trig_unlock: std_logic;
-
- signal prog_word: std_logic_vector(15 downto 0);
- signal prog_addr: std_logic_vector(23 downto 0);
- signal erase_addr: std_logic_vector(23 downto 0);
- signal lock_addr: std_logic_vector(23 downto 0);
- signal unlock_addr: std_logic_vector(23 downto 0);
-
-begin
-
- ----------------------------------------------------------------------------
- -- Useful internal signals composed from external signals
-
- -- Decode multiple chip enable inputs into single chip enable signal
- with ce select internal_ce_n <=
- '0' when "000",
- '1' when "001",
- '1' when "010",
- '1' when "011",
- '0' when "100",
- '0' when "101",
- '0' when "110",
- '1' when "111",
- 'X' when others;
-
- -- Write latch is triggered by either WEx or CEx going high, whichever is first
- internal_we_n <= we_n or internal_ce_n;
-
- -- STS signal represents the state of the WSM
- sts <= 'H' when sts_ready = '1' else '0';
-
-
- ----------------------------------------------------------------------------
- -- Array value
-
- process
- begin
- if FILENAME = "" then
- flash_array := sparse_create(default => x"FF");
- else
- flash_array := sparse_create;
- sparse_load(flash_array, FILENAME, BASEADDR);
- end if;
- wait;
- end process;
-
- process (a, sts_ready)
- begin
- -- sts_ready is in the sensitivity list because flash_array is a variable and cannot be
- array_word <= sparse_get(flash_array, to_integer(unsigned(a(a'high downto 1) & '0'))) &
- sparse_get(flash_array, to_integer(unsigned(a(a'high downto 1) & '1'))) after T_OH;
- end process;
-
-
- ----------------------------------------------------------------------------
- -- Device Information
-
- id_word <= (others => 'X');
-
-
- ----------------------------------------------------------------------------
- -- Status Register
-
- sts_word <= "00000000" &
- sts_ready &
- sts_susp_erase &
- sts_error_erase &
- sts_error_prog &
- sts_error_vpen &
- sts_susp_prog &
- sts_error_lock &
- '0';
-
-
- ----------------------------------------------------------------------------
- -- CFI Query
-
- cfi_word <= (others => 'X');
-
-
- ----------------------------------------------------------------------------
- -- Output value
-
- with read_state_cur select word <=
- array_word when R_ARRAY,
- id_word when R_ID,
- sts_word when R_STATUS,
- cfi_word when R_CFI,
- (others => 'X') when others;
-
- e_xmask_rp: entity work.changed_within_t
- generic map (T => T_PHQV)
- port map (sig_in => rp_n, sig_out => xmask_rp);
-
- e_xmask_byte: entity work.changed_within_t
- generic map (T => T_FLQV)
- port map (sig_in => byte_n, sig_out => xmask_byte);
-
- e_xmask_ce: entity work.delay_edges
- generic map (D_RISE => T_OH, D_FALL => T_ELQV)
- port map (sig_in => internal_ce_n, sig_out => xmask_ce);
-
- e_xmask_oe: entity work.delay_edges
- generic map (D_RISE => T_OH, D_FALL => T_GLQV_A)
- port map (sig_in => oe_n, sig_out => xmask_oe);
-
- e_xmask_addr_h: entity work.changed_within_t_vec
- generic map (T => T_AVQV, T_HOLD => T_OH)
- port map (sig_in => a(a'high downto 3), sig_out => xmask_addr_h);
-
- e_xmask_addr_l: entity work.changed_within_t_vec
- generic map (T => T_APA, T_HOLD => T_OH)
- port map (sig_in => a(2 downto 0), sig_out => xmask_addr_l);
-
- word_x <= (others => 'X') when (xmask_rp or xmask_ce or xmask_oe or xmask_addr_h or xmask_addr_l) = '1' else word;
-
- e_zmask_ce: entity work.delay_edges
- generic map (D_RISE => T_EHQZ, D_FALL => T_ELQX)
- port map (sig_in => internal_ce_n, sig_out => zmask_ce);
-
- e_zmask_oe: entity work.delay_edges
- generic map (D_RISE => T_GHQZ, D_FALL => T_GLQX)
- port map (sig_in => oe_n, sig_out => zmask_oe);
-
- word_xz <= (others => 'Z') when (zmask_ce or zmask_oe) = '1' else word_x;
-
- zmask_byte <= not byte_n after T_FLQZ;
-
- d(15 downto 8) <= (others => 'Z') when zmask_byte = '1' else word_xz(15 downto 8);
- d( 7 downto 0) <= word_xz( 7 downto 0) when byte_n = '1' else
- word_xz( 7 downto 0) when a(0) = '0' else
- word_xz(15 downto 8);
-
-
- ----------------------------------------------------------------------------
- -- Command User Interface (CUI)
-
- process (rp_n, internal_we_n, a, d)
- begin
- if rp_n = '0' then
- cui_state_cur <= C_IDLE;
- trig_clrsts <= '0';
- trig_susp <= '0';
- trig_resume <= '0';
- trig_cmderr <= '0';
- trig_otp <= '0';
- trig_word <= '0';
- trig_buf <= '0';
- trig_erase <= '0';
- trig_lock <= '0';
- trig_unlock <= '0';
- elsif falling_edge(internal_we_n) then
- trig_clrsts <= '0';
- trig_susp <= '0';
- trig_resume <= '0';
- trig_cmderr <= '0';
- trig_otp <= '0';
- trig_word <= '0';
- trig_buf <= '0';
- trig_erase <= '0';
- trig_lock <= '0';
- trig_unlock <= '0';
- elsif rising_edge(internal_we_n) then
- case cui_state_cur is
- when C_IDLE =>
- case d(7 downto 0) is
- when x"FF" => -- Read Array
- read_state_cur <= R_ARRAY;
-
- when x"70" => -- Read Status Register
- read_state_cur <= R_STATUS;
-
- when x"90" => -- Read Identifier Codes/Device Information
- report "TODO: Read identifier codes and device information" severity error;
- read_state_cur <= R_ID;
-
- when x"98" => -- CFI Query
- report "TODO: CFI query" severity error;
- read_state_cur <= R_CFI;
-
- when x"50" => -- Clear Status Register
- trig_clrsts <= '1';
-
- when x"B8" => -- Program STS Configuration Register
- cui_state_cur <= C_PROG_STS;
-
- when x"c0" => -- Program OTP Register
- cui_state_cur <= C_PROG_OTP;
-
- when x"40" | x"10" => -- Word/Byte Program
- cui_state_cur <= C_PROG_WORD;
-
- when x"E8" => -- Buffered Program
- read_state_cur <= R_STATUS;
- cui_state_cur <= C_PROG_BUF_COUNT;
-
- when x"20" => -- Block Erase
- cui_state_cur <= C_ERASE;
-
- when x"60" => -- Lock/Unlock Block or Program Enhanced Configuration Register
- cui_state_cur <= C_LOCK_OR_ECR;
-
- when x"B0" => -- Program/Erase Suspend
- trig_susp <= '1';
- read_state_cur <= R_STATUS;
-
- when x"D0" => -- Program/Erase Resume
- trig_resume <= '1';
- read_state_cur <= R_STATUS;
-
- when others =>
- trig_cmderr <= '1';
- end case;
-
- when C_PROG_STS =>
- assert d(7 downto 0) = x"00" report "TODO: STS pulse config" severity error;
- sts_config_reg <= d(7 downto 0);
- cui_state_cur <= C_IDLE;
-
- when C_PROG_OTP =>
- trig_otp <= '1';
- read_state_cur <= R_STATUS;
- cui_state_cur <= C_IDLE;
-
- when C_PROG_WORD =>
- prog_word <= d;
- prog_addr <= a;
- trig_word <= '1';
- read_state_cur <= R_STATUS;
- cui_state_cur <= C_IDLE;
-
- when C_PROG_BUF_COUNT =>
- report "TODO: buffered program" severity error;
- cui_state_cur <= C_PROG_BUF_DATA;
-
- when C_PROG_BUF_DATA =>
- cui_state_cur <= C_IDLE;
-
- when C_ERASE =>
- case d(7 downto 0) is
- when x"D0" => -- Erase Block
- erase_addr <= a;
- trig_erase <= '1';
- read_state_cur <= R_STATUS;
- cui_state_cur <= C_IDLE;
-
- when others =>
- trig_cmderr <= '1';
- cui_state_cur <= C_IDLE;
- end case;
-
- when C_LOCK_OR_ECR =>
- case d(7 downto 0) is
- when x"04" => -- Program Enhanced Configuration Register
- assert a = x"000000" report "TODO: ECR configuration" severity error;
- ecr_reg <= a;
- cui_state_cur <= C_IDLE;
-
- when x"01" => -- Lock Block
- lock_addr <= a;
- trig_lock <= '1';
- read_state_cur <= R_STATUS;
- cui_state_cur <= C_IDLE;
-
- when x"0D" => -- Unlock block
- unlock_addr <= a;
- trig_unlock <= '1';
- read_state_cur <= R_STATUS;
- cui_state_cur <= C_IDLE;
-
- when others =>
- trig_cmderr <= '1';
- cui_state_cur <= C_IDLE;
- end case;
-
- when others =>
- report "Unhandled CUI state" severity error;
- end case;
- end if;
- end process;
-
-
- ----------------------------------------------------------------------------
- -- Write State Machine (WSM)
-
- process (wsm_state_cur, rp_n, vpen,
- trig_clrsts, trig_susp, trig_resume, trig_cmderr, trig_otp,
- trig_word, trig_buf, trig_erase, trig_lock, trig_unlock)
- begin
- if rp_n = '0' then
- wsm_state_cur <= W_IDLE;
-
- -- Clear all error and status bits and initialize to ready
- sts_ready <= '1';
- sts_susp_erase <= '0';
- sts_error_erase <= '0';
- sts_error_prog <= '0';
- sts_error_vpen <= '0';
- sts_susp_prog <= '0';
- sts_error_lock <= '0';
- else
- -- Clearing error status bits should probably be allowed in any WSM state
- if rising_edge(trig_clrsts) then
- sts_error_erase <= '0';
- sts_error_prog <= '0';
- sts_error_vpen <= '0';
- sts_error_lock <= '0';
- end if;
-
- -- Command errors should probably be latched in any WSM state
- if rising_edge(trig_cmderr) then
- sts_error_erase <= '1';
- sts_error_prog <= '1';
- end if;
-
- -- Handle each state's logic
- -- Keep in mind this is not only run when wsm_state_cur changes,
- -- but also rerun when vpen or any trigger signal change
- sts_ready <= '0';
- case wsm_state_cur is
- when W_IDLE =>
- sts_ready <= '1';
-
- -- After these state transitions, this process will be rerun
- -- in the next delta cycle with the new state
- if rising_edge(trig_resume) then
- report "TODO: resume program/erase operation" severity error;
- elsif rising_edge(trig_otp) then
- wsm_state_cur <= W_PROG_OTP;
- elsif rising_edge(trig_word) then
- wsm_state_cur <= W_PROG_WORD;
- elsif rising_edge(trig_buf) then
- wsm_state_cur <= W_PROG_BUF;
- elsif rising_edge(trig_erase) then
- wsm_state_cur <= W_ERASE;
- elsif rising_edge(trig_lock) then
- wsm_state_cur <= W_LOCK;
- elsif rising_edge(trig_unlock) then
- wsm_state_cur <= W_UNLOCK;
- end if;
-
- when W_PROG_OTP =>
- report "TODO: program OTP" severity error;
- wsm_state_cur <= W_IDLE;
-
- when W_PROG_WORD =>
- -- TODO: check lock bits
-
- -- If vpen is low or drops during programming, halt with error
- if vpen = '0' then
- sts_error_prog <= '1';
- sts_error_vpen <= '1';
- wsm_state_cur <= W_IDLE;
- end if;
-
- -- If suspend command is sent, pause programming
- if rising_edge(trig_susp) then
- report "TODO: program suspend" severity error;
- end if;
-
- -- Invalidate the data and schedule programming completion
- if byte_n = '0' then
- sparse_set(flash_array, to_integer(unsigned(prog_addr)), "XXXXXXXX");
- else
- sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '0')), "XXXXXXXX");
- sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '1')), "XXXXXXXX");
- end if;
- wsm_state_cur <= W_PROG_WORD_FINISH after T_WHQV3;
-
- when W_PROG_WORD_FINISH =>
- if byte_n = '0' then
- sparse_set(flash_array, to_integer(unsigned(prog_addr)), prog_word(7 downto 0));
- else
- sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '0')), prog_word(15 downto 8));
- sparse_set(flash_array, to_integer(unsigned(prog_addr(prog_addr'high downto 1) & '1')), prog_word( 7 downto 0));
- end if;
- wsm_state_cur <= W_IDLE;
-
- when W_PROG_BUF =>
- report "TODO: buffered program" severity error;
- wsm_state_cur <= W_IDLE;
-
- when W_ERASE =>
- -- TODO: check lock bits
-
- -- If vpen is low or drops during erase, halt with error
- if vpen = '0' then
- sts_error_erase <= '1';
- sts_error_vpen <= '1';
- wsm_state_cur <= W_IDLE;
- end if;
-
- -- If suspend command is sent, pause programming
- if rising_edge(trig_susp) then
- report "TODO: erase suspend" severity error;
- end if;
-
- -- Invalidate the data and schedule the erase completion
- for i in 0 to 16#1ffff# loop
- sparse_set(flash_array, to_integer(unsigned(erase_addr(erase_addr'high downto 16)) & to_unsigned(i, 17)), x"FF");
- end loop;
- wsm_state_cur <= W_ERASE_FINISH after T_WHQV4;
-
- when W_ERASE_FINISH =>
- for i in 0 to 16#1ffff# loop
- sparse_set(flash_array, to_integer(unsigned(erase_addr(erase_addr'high downto 16)) & to_unsigned(i, 17)), x"FF");
- end loop;
- wsm_state_cur <= W_IDLE;
-
- when W_LOCK =>
- report "TODO: program lock bits" severity error;
- wsm_state_cur <= W_IDLE;
-
- when W_UNLOCK =>
- report "TODO: erase lock bits" severity error;
- wsm_state_cur <= W_IDLE;
-
- when others =>
- report "Unhandled WSM state" severity error;
-
- end case;
- end if;
- end process;
-
-
- ----------------------------------------------------------------------------
- -- Check for erroneous usages
-
- -- Should not try to read and write at the same time
- process (oe_n, we_n)
- begin
- assert not (oe_n = '0' and we_n = '0')
- report "OE# and WE# should never be enabled simultaneously."
- severity error;
- end process;
-
- -- Address must be valid for a full read or write cycle
- R1: process (oe_n, a(23 downto 4))
- begin
- -- FIXME: Check more address bits if in non-array or 4-word array modes
- if a(23 downto 4)'event and oe_n = '0' then
- assert a(23 downto 4)'last_event >= T_AVAV;
- report "T_AVAV not met (Read/Write Cycle Time)"
- severity error;
- end if;
- end process;
-
- -- BYTE# cannot change more than T_ELFL/T_ELFH after CEx goes low
- -- This might be another way of describing a negative setup time requirement
- R11: process (byte_n, internal_ce_n)
- begin
- if byte_n'event and internal_ce_n = '0' then
- assert internal_ce_n'last_event <= T_ELFL;
- report "T_ELFL/H not met (CEx Low to BYTE# High or Low)"
- severity error;
- end if;
- end process;
-
- W1a: entity work.assert_setuphold
- generic map (LEVEL => '1', T_HOLD => T_PHWL, NAME_SIG => "WE#", NAME_REF => "RP#")
- port map (sig => we_n, ref => rp_n);
-
- W1b: entity work.assert_setuphold
- generic map (LEVEL => '1', T_HOLD => T_PHEL, NAME_SIG => "CEx", NAME_REF => "RP#")
- port map (sig => internal_ce_n, ref => rp_n);
-
- W2a: entity work.assert_setuphold
- generic map (LEVEL => '0', T_SETUP => T_ELWL, NAME_SIG => "CEx", NAME_REF => "WE#")
- port map (sig => internal_ce_n, ref => we_n);
-
- W2b: entity work.assert_setuphold
- generic map (LEVEL => '0', T_SETUP => T_WLEL, NAME_SIG => "WE#", NAME_REF => "CEx")
- port map (sig => we_n, ref => internal_ce_n);
-
- W3: entity work.assert_pulsewidth
- generic map (LEVEL => '0', T_MIN => T_WP, NAME => "WE#")
- port map (sig => we_n);
-
- W4: entity work.assert_setuphold_vec
- generic map (LEVEL => '1', T_SETUP => T_DVWH, NAME_SIG => "Data", NAME_REF => "WE#/CEx")
- port map (sig => d, ref => internal_we_n);
-
- W5: entity work.assert_setuphold_vec
- generic map (LEVEL => '1', T_SETUP => T_AVWH, NAME_SIG => "Addr", NAME_REF => "WE#/CEx")
- port map (sig => a, ref => internal_we_n);
-
- W6a: entity work.assert_setuphold
- generic map (LEVEL => '1', T_HOLD => T_WHEH, NAME_SIG => "CEx", NAME_REF => "WE#")
- port map (sig => internal_ce_n, ref => we_n);
-
- W6b: entity work.assert_setuphold
- generic map (LEVEL => '1', T_HOLD => T_EHWH, NAME_SIG => "WE#", NAME_REF => "CEx")
- port map (sig => we_n, ref => internal_ce_n);
-
- W7: entity work.assert_setuphold_vec
- generic map (LEVEL => '1', T_HOLD => T_WHDX, NAME_SIG => "Data", NAME_REF => "WE#/CEx")
- port map (sig => d, ref => internal_we_n);
-
- W8: entity work.assert_setuphold_vec
- generic map (LEVEL => '1', T_HOLD => T_WHAX, NAME_SIG => "Addr", NAME_REF => "WE#/CEx")
- port map (sig => a, ref => internal_we_n);
-
- W9: entity work.assert_pulsewidth
- generic map (LEVEL => '1', T_MIN => T_WPH, NAME => "WE#")
- port map (sig => we_n);
-
- W11: entity work.assert_setuphold
- generic map (LEVEL => '1', T_SETUP => T_VPWH, NAME_SIG => "Vpen", NAME_REF => "WE#/CEx")
- port map (sig => vpen, ref => internal_we_n);
-
- W12: entity work.assert_setuphold
- generic map (LEVEL => '1', T_HOLD => T_WHGL, NAME_SIG => "OE#", NAME_REF => "WE#/CEx")
- port map (sig => oe_n, ref => internal_we_n);
-
- W15: entity work.assert_setuphold
- generic map (LEVEL => '1', T_HOLD => T_QVVL, NAME_SIG => "Vpen", NAME_REF => "sts")
- port map (sig => vpen, ref => sts_ready);
-
-end behavioral;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-
-package sim_utility is
-
- ----------------------------------------------------------------------------
- -- String manipulation
-
- function str_endswith(str: string; suffix: string) return boolean;
-
-
- ----------------------------------------------------------------------------
- -- Sparse byte array for simulated memory devices
- --
- -- Looks like protected types aren't supported by ISE 14.7, so gotta do this
-
- subtype byte_t is std_logic_vector(7 downto 0);
- type byte_array_t is array(natural range <>) of byte_t;
- type p_byte_array_t is access byte_array_t;
- type item_t;
- type p_item_t is access item_t;
- type item_t is record
- base: integer;
- data: p_byte_array_t;
- next_item: p_item_t;
- end record;
-
- type sparse_t is record
- default: byte_t;
- page_size: natural;
- first: p_item_t;
- end record;
-
-
- function sparse_create (default: in byte_t := (others => 'U');
- page_size: in natural := 4096)
- return sparse_t;
-
-
- procedure sparse_load (sparse: inout sparse_t;
- filename: in string;
- base: in integer := 0);
-
-
- function sparse_get (sparse: in sparse_t;
- idx: in natural)
- return byte_t;
-
-
- procedure sparse_set (sparse: inout sparse_t;
- idx: in natural;
- val: in byte_t);
-
-
- procedure sparse_get_slice(sparse: in sparse_t;
- idx: in natural;
- val: out byte_array_t);
-
-
- procedure sparse_set_slice(sparse: inout sparse_t;
- idx: in natural;
- val: in byte_array_t);
-
-end sim_utility;
-
-
-package body sim_utility is
-
- ----------------------------------------------------------------------------
- -- String manipulation
-
- function str_endswith(str: string; suffix: string) return boolean is
- begin
- if str'length < suffix'length then
- return false;
- else
- return str(str'right - (suffix'length - 1) to str'right) = suffix;
- end if;
- end function;
-
-
- ----------------------------------------------------------------------------
- -- Sparse byte array for simulated memory devices
-
- -- Create a new sparse array
- function sparse_create(default: in byte_t := (others => 'U'); page_size: in natural := 4096) return sparse_t is
- begin
- return (
- default => default,
- page_size => page_size,
- first => null
- );
- end function;
-
- -- Load data from a file into a sparse byte array
- procedure sparse_load(sparse: inout sparse_t; filename: in string; base: in integer := 0) is
- type char_file_t is file of character;
- subtype ibyte_t is natural range 0 to 255;
-
- file f: char_file_t;
- variable fstatus: FILE_OPEN_STATUS;
-
- variable i: natural;
- variable c: character;
- variable b: ibyte_t;
- variable v: byte_t;
- begin
- -- Load data from file
- if str_endswith(FILENAME, ".bin") then
- -- Raw binary file
-
- file_open(fstatus, f, FILENAME, READ_MODE);
- assert fstatus = OPEN_OK report "Failed to open file '" & FILENAME & "'" severity failure;
-
- i := 0;
- while not endfile(f) loop
- read(f, c);
- b := character'pos(c);
- v := std_logic_vector(to_unsigned(b, 8));
- sparse_set(sparse, i+base, v);
- i := i + 1;
- end loop;
-
- file_close(f);
-
- elsif str_endswith(FILENAME, ".hex") then
- -- Intel HEX format
- assert false report "Intel HEX format not yet supported" severity failure;
- else
- assert false report "Filename suffix not recognized: '" & FILENAME & "'" severity failure;
- end if;
- end procedure;
-
- -- Get a value from a sparse array
- function sparse_get(sparse: in sparse_t; idx: in natural) return byte_t is
- variable base: natural;
- variable this: p_item_t;
- begin
- -- Find a page that contains idx
- base := idx - (idx mod sparse.page_size);
- this := sparse.first;
- while this /= null loop
- if this.base = base then
- -- Retrieve the value and exit
- return this.data(idx mod sparse.page_size);
- end if;
- this := this.next_item;
- end loop;
-
- -- No page containing idx, return the default value
- return sparse.default;
- end function;
-
- -- Set a value within a sparse array
- procedure sparse_set(sparse: inout sparse_t; idx: in natural; val: in byte_t) is
- variable base: natural;
- variable this: p_item_t;
- variable new_item: p_item_t;
- begin
- -- Find a page that contains idx
- base := idx - (idx mod sparse.page_size);
- this := sparse.first;
- while this /= null loop
- if this.base = base then
- -- Write the value and exit
- this.data(idx mod sparse.page_size) := val;
- return;
- end if;
- this := this.next_item;
- end loop;
-
- -- No page found containing idx, create one and add it
- new_item := new item_t;
-
- new_item.base := base;
- new_item.data := new byte_array_t(sparse.page_size-1 downto 0);
- new_item.next_item := sparse.first;
-
- sparse.first := new_item;
-
- for i in 0 to sparse.page_size-1 loop
- new_item.data(i) := sparse.default;
- end loop;
- new_item.data(idx mod sparse.page_size) := val;
- end procedure;
-
- -- Get a slice of bytes from a sparse array
- procedure sparse_get_slice(sparse: in sparse_t; idx: in natural; val: out byte_array_t) is
- begin
- for i in val'range loop
- val(i) := sparse_get(sparse, idx+i);
- end loop;
- end procedure;
-
- -- Set a slice of bytes within a sparse array
- procedure sparse_set_slice(sparse: inout sparse_t; idx: in natural; val: in byte_array_t) is
- begin
- for i in val'range loop
- sparse_set(sparse, idx+i, val(i));
- end loop;
- end procedure;
-
-end sim_utility;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity test_attrs is
-end test_attrs;
-
-
-architecture behavior of test_attrs is
-
- constant T: time := 10 ns;
-
- signal sig: std_logic;
- signal sig_delayed: std_logic;
- signal sig_stable: boolean;
- signal sig_quiet: boolean;
- signal sig_last_event: time;
- signal sig_last_active: time;
- signal sig_last_event_2: time;
- signal sig_last_active_2: time;
-
-begin
-
- test: process is
- begin
-
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
-
- sig <= '0';
-
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
- wait for 30 ns;
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
-
- sig <= '1';
-
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
- wait for 30 ns;
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
-
- sig <= '1';
-
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
- wait for 30 ns;
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
-
- sig <= '0';
-
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
- wait for 30 ns;
- sig_last_event_2 <= sig'last_event;
- sig_last_active_2 <= sig'last_active;
-
- wait;
-
- end process;
-
- sig_delayed <= sig'delayed(T);
- sig_stable <= sig'stable(T);
- sig_quiet <= sig'quiet(T);
-
- -- These don't work as expected!
- -- This also applies to equivalent processes with sensitivity lists
- sig_last_event <= sig'last_event;
- sig_last_active <= sig'last_active;
-
-end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+
+entity test_genericmem is
+end test_genericmem;
+
+
+architecture behavior of test_genericmem is
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+ signal cyc_i: std_logic;
+ signal stb_i: std_logic;
+ signal we_i: std_logic;
+ signal ack_o: std_logic;
+ signal adr_i: std_logic_vector(4 downto 0);
+ signal dat_i: std_logic_vector(7 downto 0);
+ signal dat_o: std_logic_vector(7 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ -- Initial values
+ cyc_i <= '0';
+ stb_i <= '0';
+ we_i <= '0';
+ adr_i <= (others => '0');
+ dat_i <= (others => '0');
+
+ -- Reset
+ rst_i <= '1';
+ wait for 40 ns;
+ rst_i <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+
+ e_uut: entity work.genericmem
+ generic map (
+ INIT => x"00112233445566778899aabbccddeeff0123456789abcdeffedcba9876543210"
+ )
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ cyc_i => cyc_i,
+ stb_i => stb_i,
+ we_i => we_i,
+ ack_o => ack_o,
+ adr_i => adr_i,
+ dat_i => dat_i,
+ dat_o => dat_o
+ );
+
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for 10 ns;
+ clk_i <= '1';
+ wait for 10 ns;
+ end process;
+
+end;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-library flash_js28f128;
+library work;
-entity testbench_j28f128j3d75 is
-end testbench_j28f128j3d75;
+entity test_js28f128j3d75 is
+end test_js28f128j3d75;
-architecture behavior of testbench_js28f128j3d75 is
+architecture behavior of test_js28f128j3d75 is
- type op is (O_NONE, O_READ_ARRAY, O_READ_STATUS, O_PROG_A, O_PROG_B, O_MODE_ARRAY);
-
- -- Flash signals
- signal a: std_logic_vector(23 downto 0);
- signal d: std_logic_vector(15 downto 0);
- signal ce: std_logic_vector(2 downto 0);
- signal rp_n: std_logic;
- signal oe_n: std_logic;
- signal we_n: std_logic;
- signal sts: std_logic;
+ signal a: std_logic_vector(23 downto 0);
+ signal d: std_logic_vector(15 downto 0);
+ signal ce: std_logic_vector(2 downto 0);
+ signal rp_n: std_logic := '0';
+ signal oe_n: std_logic;
+ signal we_n: std_logic;
+ signal sts: std_logic;
signal byte_n: std_logic;
- signal vpen: std_logic;
-
- -- Debug
- signal cur_op: op;
+ signal vpen: std_logic;
begin
- uut: entity flash_js28f128.js28f128j3d75 port map (
- a => a,
- d => d,
- ce => ce,
- rp_n => rp_n,
- oe_n => oe_n,
- we_n => we_n,
- sts => sts,
- byte_n => byte_n,
- vpen => vpen
- );
-
-
- tb: process
+ p_test: process
begin
- -- Initial values
- cur_op <= O_NONE;
- a <= (others => '0');
- d <= (others => 'Z');
- ce <= (others => '1');
- oe_n <= '1';
- we_n <= '1';
+ -- Initial values and reset
+ a <= x"000000";
+ d <= "ZZZZZZZZZZZZZZZZ";
+ ce <= "111";
+ rp_n <= '0';
+ oe_n <= '1';
+ we_n <= '1';
byte_n <= '1';
- vpen <= '1';
-
- -- Reset
- rp_n <= '1';
+ vpen <= '1';
+ wait for 10 ns;
+ rp_n <= '1';
wait for 1 us;
- rp_n <= '0';
- wait for 25 us;
- rp_n <= '1';
- wait for 210 ns;
-
- -- Wait for long BYTE# signal propagation time
- wait for 1 ms;
- -- Asynchronous array read
- cur_op <= O_READ_ARRAY;
- ce(0) <= '0';
- oe_n <= '0';
- a <= x"000000";
- wait for 100 ns;
- a <= x"000002";
- wait for 100 ns;
- a <= x"000004";
- wait for 100 ns;
- a <= x"000006";
- wait for 100 ns;
- a <= x"000008";
- wait for 100 ns;
- a <= x"00000a";
- wait for 100 ns;
- a <= x"00000c";
+ -- Test a page read
+ ce <= "000";
+ oe_n <= '0';
wait for 100 ns;
- a <= x"00000e";
- wait for 100 ns;
- ce(0) <= '1';
- oe_n <= '1';
- cur_op <= O_NONE;
+ a <= x"000002";
+ wait for 50 ns;
+ a <= x"000004";
+ wait for 50 ns;
+ a <= x"000006";
+ wait for 50 ns;
+ oe_n <= '1';
+ ce <= "111";
- wait for 25 ns;
-
- -- Program word
- ce(0) <= '0';
+ wait for 100 ns;
- cur_op <= O_PROG_A;
- a <= x"000000";
- d <= x"0040";
+ -- Send the write-word command
+ a <= x"000008";
+ d <= x"0040";
+ ce <= "000";
we_n <= '0';
- wait for 60 ns;
+ wait for 80 ns;
we_n <= '1';
- wait for 30 ns;
+ ce <= "111";
+ wait for 35 ns;
- cur_op <= O_PROG_B;
- a <= x"000000";
- d <= x"abcd";
+ -- Send the word to write
+ d <= x"1234";
+ ce <= "000";
we_n <= '0';
- wait for 60 ns;
+ wait for 80 ns;
we_n <= '1';
- wait for 30 ns;
-
- ce(0) <= '1';
- d <= (others => 'Z');
- cur_op <= O_NONE;
- wait for 100 us;
-
- -- Read status during program
- cur_op <= O_READ_STATUS;
- ce(0) <= '0';
- oe_n <= '0';
- a <= x"000000";
- wait for 100 ns;
- assert d = x"0000"
- report "Status read got wrong value: " & integer'image(to_integer(unsigned(d)))
- severity error;
- oe_n <= '1';
- ce(0) <= '1';
- cur_op <= O_NONE;
- wait for 25 ns;
+ ce <= "111";
+ wait for 35 ns;
- -- Wait for program to complete
+ -- Wait for the write to complete
wait until sts /= '0';
- wait for 25 ns;
+ wait for 50 ns;
- -- Read status after program
- cur_op <= O_READ_STATUS;
- ce(0) <= '0';
- oe_n <= '0';
- a <= x"000000";
- wait for 100 ns;
- assert d = x"0080"
- report "Status read got wrong value: " & integer'image(to_integer(unsigned(d)))
- severity error;
- oe_n <= '1';
- ce(0) <= '1';
- cur_op <= O_NONE;
- wait for 25 ns;
-
- -- Enter read-array mode
- cur_op <= O_MODE_ARRAY;
- a <= x"000000";
- d <= x"00ff";
- ce(0) <= '0';
+ -- Send the read-array command
+ d <= x"00ff";
+ ce <= "000";
we_n <= '0';
- wait for 60 ns;
+ wait for 80 ns;
we_n <= '1';
- wait for 30 ns;
- ce(0) <= '1';
- d <= (others => 'Z');
- cur_op <= O_NONE;
- wait for 25 ns;
-
- -- Read flash array value
- cur_op <= O_READ_ARRAY;
- ce(0) <= '0';
+ ce <= "111";
+ wait for 35 ns;
+
+ -- Read back the value we wrote
+ d <= "ZZZZZZZZZZZZZZZZ";
+ ce <= "000";
oe_n <= '0';
- a <= x"000000";
- wait for 100 ns;
- assert d = x"abcd"
- report "Array read got wrong value"
- severity error;
+ wait for 80 ns;
oe_n <= '1';
- ce(0) <= '1';
- cur_op <= O_NONE;
- wait for 25 ns;
+ ce <= "111";
+ wait for 35 ns;
wait;
end process;
-end architecture;
+ e_dut: entity work.js28f128j3d75
+ generic map (FILENAME => "/home/ryan/Dropbox/Projects/VHDL/libraries/simulated/tests/test.bin")
+ port map (
+ a => a,
+ d => d,
+ ce => ce,
+ rp_n => rp_n,
+ oe_n => oe_n,
+ we_n => we_n,
+ sts => sts,
+ byte_n => byte_n,
+ vpen => vpen
+ );
+end;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-library simulated;
+library work;
-entity testbench_ram is
-end testbench_ram;
+entity test_mt45w8mw16bgx is
+end test_mt45w8mw16bgx;
-architecture behavior of testbench_ram is
+architecture behavior of test_mt45w8mw16bgx is
signal addr: std_logic_vector(23 downto 0); -- Extra bit to allow hex literals
signal data: std_logic_vector(15 downto 0);
wait;
end process;
- uut: entity simulated.mt45w8mw16bgx
+ uut: entity work.mt45w8mw16bgx
port map (
a => addr(22 downto 0),
dq => data,
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity test_ps2 is
+end test_ps2;
+
+
+architecture behavior of test_ps2 is
+
+ signal tx_byte: std_logic_vector(7 downto 0) := x"00";
+ signal ps2_clk: std_logic;
+ signal ps2_data: std_logic;
+
+begin
+
+ ps2_clk <= 'H';
+ ps2_data <= 'H';
+
+ p_test: process
+ begin
+ ps2_clk <= 'Z';
+ ps2_data <= 'Z';
+
+ -- Receive bytes form device
+ wait for 100 ns;
+ tx_byte <= x"a5";
+ wait for 1 ms;
+ tx_byte <= x"a5";
+ wait for 400 us;
+ ps2_clk <= '0'; -- Cancel transmission from host
+ wait for 400 us;
+ ps2_clk <= 'Z';
+ wait for 200 us;
+ tx_byte <= x"c3";
+ wait for 1 ms;
+
+ -- Transmit byte to device
+ ps2_clk <= '0';
+ wait for 30 us;
+ ps2_data <= '0'; -- start
+ wait for 30 us;
+ ps2_clk <= 'Z';
+ wait until ps2_clk = '0';
+ ps2_data <= '0'; -- 0
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= 'Z'; -- 1
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= '0'; -- 2
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= 'Z'; -- 3
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= '0'; -- 4
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= '0'; -- 5
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= 'Z'; -- 6
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= 'Z'; -- 7
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= 'Z'; -- parity
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= '0'; -- stop
+ wait until ps2_clk /= '0';
+ wait until ps2_clk = '0';
+ ps2_data <= 'Z'; -- ack
+ assert ps2_data = '0'
+ report "NACK from device"
+ severity error;
+ wait until ps2_clk /= '0';
+ wait;
+ end process;
+
+ e_ps2_device: entity work.proto_ps2
+ port map (
+ tx_byte => tx_byte,
+
+ ps2_clk => ps2_clk,
+ ps2_data => ps2_data
+ );
+
+end;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-
-
-entity test_ps2_device is
-end test_ps2_device;
-
-
-architecture behavior of test_ps2_device is
-
- signal tx_byte: std_logic_vector(7 downto 0) := x"00";
- signal ps2_clk: std_logic;
- signal ps2_data: std_logic;
-
-begin
-
- ps2_clk <= 'H';
- ps2_data <= 'H';
-
- p_test: process
- begin
- ps2_clk <= 'Z';
- ps2_data <= 'Z';
-
- -- Receive bytes form device
- wait for 100 ns;
- tx_byte <= x"a5";
- wait for 1 ms;
- tx_byte <= x"a5";
- wait for 400 us;
- ps2_clk <= '0'; -- Cancel transmission from host
- wait for 400 us;
- ps2_clk <= 'Z';
- wait for 200 us;
- tx_byte <= x"c3";
- wait for 1 ms;
-
- -- Transmit byte to device
- ps2_clk <= '0';
- wait for 30 us;
- ps2_data <= '0'; -- start
- wait for 30 us;
- ps2_clk <= 'Z';
- wait until ps2_clk = '0';
- ps2_data <= '0'; -- 0
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= 'Z'; -- 1
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= '0'; -- 2
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= 'Z'; -- 3
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= '0'; -- 4
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= '0'; -- 5
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= 'Z'; -- 6
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= 'Z'; -- 7
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= 'Z'; -- parity
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= '0'; -- stop
- wait until ps2_clk /= '0';
- wait until ps2_clk = '0';
- ps2_data <= 'Z'; -- ack
- assert ps2_data = '0'
- report "NACK from device"
- severity error;
- wait until ps2_clk /= '0';
- wait;
- end process;
-
- e_ps2_device: entity work.ps2_device
- port map (
- fast => true,
-
- tx_byte => tx_byte,
-
- ps2_clk => ps2_clk,
- ps2_data => ps2_data
- );
-
-end;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library work;
-
-
-entity test_simflash is
-end test_simflash;
-
-
-architecture behavior of test_simflash is
-
- signal a: std_logic_vector(23 downto 0);
- signal d: std_logic_vector(15 downto 0);
- signal ce: std_logic_vector(2 downto 0);
- signal rp_n: std_logic := '0';
- signal oe_n: std_logic;
- signal we_n: std_logic;
- signal sts: std_logic;
- signal byte_n: std_logic;
- signal vpen: std_logic;
-
-begin
-
- p_test: process
- begin
- -- Initial values and reset
- a <= x"000000";
- d <= "ZZZZZZZZZZZZZZZZ";
- ce <= "111";
- rp_n <= '0';
- oe_n <= '1';
- we_n <= '1';
- byte_n <= '1';
- vpen <= '1';
- wait for 10 ns;
- rp_n <= '1';
- wait for 1 us;
-
- -- Test a page read
- ce <= "000";
- oe_n <= '0';
- wait for 100 ns;
- a <= x"000002";
- wait for 50 ns;
- a <= x"000004";
- wait for 50 ns;
- a <= x"000006";
- wait for 50 ns;
- oe_n <= '1';
- ce <= "111";
-
- wait for 100 ns;
-
- -- Send the write-word command
- a <= x"000008";
- d <= x"0040";
- ce <= "000";
- we_n <= '0';
- wait for 80 ns;
- we_n <= '1';
- ce <= "111";
- wait for 35 ns;
-
- -- Send the word to write
- d <= x"1234";
- ce <= "000";
- we_n <= '0';
- wait for 80 ns;
- we_n <= '1';
- ce <= "111";
- wait for 35 ns;
-
- -- Wait for the write to complete
- wait until sts /= '0';
- wait for 50 ns;
-
- -- Send the read-array command
- d <= x"00ff";
- ce <= "000";
- we_n <= '0';
- wait for 80 ns;
- we_n <= '1';
- ce <= "111";
- wait for 35 ns;
-
- -- Read back the value we wrote
- d <= "ZZZZZZZZZZZZZZZZ";
- ce <= "000";
- oe_n <= '0';
- wait for 80 ns;
- oe_n <= '1';
- ce <= "111";
- wait for 35 ns;
-
- wait;
- end process;
-
- e_dut: entity work.sim_js28f128j3d75
- generic map (FILENAME => "/home/ryan/Dropbox/Projects/VHDL/libraries/simulated/tests/test.bin")
- port map (
- a => a,
- d => d,
- ce => ce,
- rp_n => rp_n,
- oe_n => oe_n,
- we_n => we_n,
- sts => sts,
- byte_n => byte_n,
- vpen => vpen
- );
-end;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library work;
-
-
-entity test_simmem is
-end test_simmem;
-
-
-architecture behavior of test_simmem is
-
- signal rst_i: std_logic;
- signal clk_i: std_logic;
- signal cyc_i: std_logic;
- signal stb_i: std_logic;
- signal we_i: std_logic;
- signal ack_o: std_logic;
- signal adr_i: std_logic_vector(4 downto 0);
- signal dat_i: std_logic_vector(7 downto 0);
- signal dat_o: std_logic_vector(7 downto 0);
-
-begin
-
- p_test: process
- begin
- -- Initial values
- cyc_i <= '0';
- stb_i <= '0';
- we_i <= '0';
- adr_i <= (others => '0');
- dat_i <= (others => '0');
-
- -- Reset
- rst_i <= '1';
- wait for 40 ns;
- rst_i <= '0';
-
- -- Done
- wait;
- end process;
-
-
- e_uut: entity work.wb_memory
- generic map (
- INIT => x"00112233445566778899aabbccddeeff0123456789abcdeffedcba9876543210"
- )
- port map (
- rst_i => rst_i,
- clk_i => clk_i,
- cyc_i => cyc_i,
- stb_i => stb_i,
- we_i => we_i,
- ack_o => ack_o,
- adr_i => adr_i,
- dat_i => dat_i,
- dat_o => dat_o
- );
-
-
- p_clk: process
- begin
- clk_i <= '0';
- wait for 10 ns;
- clk_i <= '1';
- wait for 10 ns;
- end process;
-
-end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity assert_pulsewidth is
+ generic (
+ LEVEL: std_logic := '1';
+ T_MIN: time := time'low;
+ T_MAX: time := time'high;
+ NAME: string := "<sig>"
+ );
+ port (
+ sig: in std_logic
+ );
+end assert_pulsewidth;
+
+
+architecture behavioral of assert_pulsewidth is
+begin
+
+ process (sig)
+ variable width: time;
+ begin
+ -- Detect the end of a pulse of type LEVEL
+ if sig /= LEVEL and sig'last_value = LEVEL then
+ -- Delayed by a delta cycle since sig'last_event is now
+ width := sig'delayed'last_event;
+
+ assert width <= T_MAX
+ report "Maximum " & std_logic'image(LEVEL) & " pulse width violation for '" & NAME &
+ "' (width: " & time'image(width) & ", max: " & time'image(T_MAX) & ")"
+ severity error;
+
+ assert width >= T_MIN
+ report "Minimum " & std_logic'image(LEVEL) & " pulse width violation for '" & NAME &
+ "' (width: " & time'image(width) & ", min: " & time'image(T_MIN) & ")"
+ severity error;
+ end if;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity assert_setuphold is
+ generic (
+ LEVEL: std_logic := '1';
+ T_SETUP: time := time'low;
+ T_HOLD: time := time'low;
+ NAME_REF: string := "<ref>";
+ NAME_SIG: string := "<sig>"
+ );
+ port (
+ ref: in std_logic; -- Reference signal for setup/hold times, e.g. clock
+ sig: in std_logic
+ );
+end assert_setuphold;
+
+
+architecture behavioral of assert_setuphold is
+begin
+
+ process (ref, sig)
+ -- Absolute time of most recent edge-of-interest
+ -- Initial value is negative so hold checks can be skipped if "sig" changes before "ref"
+ variable last_edge: time := -1 ps;
+
+ variable setup_time: time;
+ variable hold_time: time;
+ begin
+ -- Detect edges where "ref" transitions to LEVEL
+ if ref'event and ref = LEVEL then
+ -- Keep track of the last edge for the hold time test
+ -- Normally I hate that variables retain values between process invocations, but here it's useful!
+ last_edge := now;
+
+ -- If sig changed at same time as ref, assume its new value is not the value being referenced by the edge
+ -- (Allow the hold-time constraint to catch problems there)
+ setup_time := sig'last_event;
+ if setup_time = 0 ns then
+ setup_time := sig'delayed'last_event;
+ end if;
+
+ -- Check setup time constraint unless this is the beginning of the simulation
+ if now > 0 ps then
+ assert setup_time >= T_SETUP
+ report "Setup time to '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
+ " (actual: " & time'image(setup_time) & ", required: " & time'image(T_SETUP) & ")"
+ severity error;
+ end if;
+ end if;
+
+ -- Detect changes in "sig" but only if "ref" has had an edge before
+ if sig'event and last_edge > 0 ps then
+ -- Checking against ref'last_event is tempting, but it might catch the wrong kind of transition
+ hold_time := now - last_edge;
+
+ -- Check hold time constraint
+ assert hold_time >= T_HOLD
+ report "Hold time from '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
+ " (actual: " & time'image(hold_time) & ", required: " & time'image(T_HOLD) & ")"
+ severity error;
+ end if;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity assert_setuphold_vec is
+ generic (
+ LEVEL: std_logic := '1';
+ T_SETUP: time := time'low;
+ T_HOLD: time := time'low;
+ NAME_REF: string := "<ref>";
+ NAME_SIG: string := "<sig>"
+ );
+ port (
+ ref: in std_logic; -- Reference signal for setup/hold times, e.g. clock
+ sig: in std_logic_vector
+ );
+end assert_setuphold_vec;
+
+
+architecture behavioral of assert_setuphold_vec is
+begin
+
+ process (ref, sig)
+ -- Absolute time of most recent edge-of-interest
+ -- Initial value is negative so hold checks can be skipped if "sig" changes before "ref"
+ variable last_edge: time := -1 ps;
+
+ variable setup_time: time;
+ variable hold_time: time;
+ begin
+ -- Detect edges where "ref" transitions to LEVEL
+ if ref'event and ref = LEVEL then
+ -- Keep track of the last edge for the hold time test
+ -- Normally I hate that variables retain values between process invocations, but here it's useful!
+ last_edge := now;
+
+ -- If sig changed at same time as ref, assume its new value is not the value being referenced by the edge
+ -- (Allow the hold-time constraint to catch problems there)
+ setup_time := sig'last_event;
+ if setup_time = 0 ns then
+ setup_time := sig'delayed'last_event;
+ end if;
+
+ -- Check setup time constraint unless this is the beginning of the simulation
+ if now > 0 ps then
+ assert setup_time >= T_SETUP
+ report "Setup time to '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
+ " (actual: " & time'image(setup_time) & ", required: " & time'image(T_SETUP) & ")"
+ severity error;
+ end if;
+ end if;
+
+ -- Detect changes in "sig" but only if "ref" has had an edge before
+ if sig'event and last_edge > 0 ps then
+ -- Checking against ref'last_event is tempting, but it might catch the wrong kind of transition
+ hold_time := now - last_edge;
+
+ -- Check hold time constraint
+ assert hold_time >= T_HOLD
+ report "Hold time from '" & NAME_REF & "' <= " & std_logic'image(LEVEL) & " violation for " & NAME_SIG &
+ " (actual: " & time'image(hold_time) & ", required: " & time'image(T_HOLD) & ")"
+ severity error;
+ end if;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity changed_within_t is
+ generic (
+ T: time := 0 ns;
+ T_HOLD: time := 0 ns
+ );
+ port (
+ sig_in: in std_logic;
+ sig_out: out std_logic
+ );
+end changed_within_t;
+
+
+architecture behavioral of changed_within_t is
+ signal sig: std_logic := '1';
+begin
+
+ sig <= '1' after T_HOLD when not sig_in'stable(T - T_HOLD) else '0' after T_HOLD;
+ sig_out <= sig;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity changed_within_t_vec is
+ generic (
+ T: time := 0 ns;
+ T_HOLD: time := 0 ns
+ );
+ port (
+ sig_in: in std_logic_vector;
+ sig_out: out std_logic
+ );
+end changed_within_t_vec;
+
+
+architecture behavioral of changed_within_t_vec is
+ signal sig: std_logic := '1';
+begin
+
+ sig <= '1' after T_HOLD when not sig_in'stable(T - T_HOLD) else '0' after T_HOLD;
+ sig_out <= sig;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity delay_edges is
+ generic (
+ D_RISE: time := 0 ns;
+ D_FALL: time := 0 ns
+ );
+ port (
+ sig_in: in std_logic;
+ sig_out: out std_logic
+ );
+end delay_edges;
+
+architecture behavioral of delay_edges is
+ signal mask: std_logic;
+begin
+
+ process (sig_in)
+ begin
+ if mask = 'U' then
+ mask <= sig_in;
+ end if;
+ if sig_in'event and sig_in = '1' then
+ mask <= '1' after D_RISE;
+ end if;
+ if sig_in'event and sig_in = '0' then
+ mask <= '0' after D_FALL;
+ end if;
+ end process;
+ sig_out <= mask;
+
+end behavioral;
+
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+package sim_utility is
+
+ ----------------------------------------------------------------------------
+ -- String manipulation
+
+ function str_endswith(str: string; suffix: string) return boolean;
+
+
+ ----------------------------------------------------------------------------
+ -- Sparse byte array for simulated memory devices
+ --
+ -- Looks like protected types aren't supported by ISE 14.7, so gotta do this
+
+ subtype byte_t is std_logic_vector(7 downto 0);
+ type byte_array_t is array(natural range <>) of byte_t;
+ type p_byte_array_t is access byte_array_t;
+ type item_t;
+ type p_item_t is access item_t;
+ type item_t is record
+ base: integer;
+ data: p_byte_array_t;
+ next_item: p_item_t;
+ end record;
+
+ type sparse_t is record
+ default: byte_t;
+ page_size: natural;
+ first: p_item_t;
+ end record;
+
+
+ function sparse_create (default: in byte_t := (others => 'U');
+ page_size: in natural := 4096)
+ return sparse_t;
+
+
+ procedure sparse_load (sparse: inout sparse_t;
+ filename: in string;
+ base: in integer := 0);
+
+
+ function sparse_get (sparse: in sparse_t;
+ idx: in natural)
+ return byte_t;
+
+
+ procedure sparse_set (sparse: inout sparse_t;
+ idx: in natural;
+ val: in byte_t);
+
+
+ procedure sparse_get_slice(sparse: in sparse_t;
+ idx: in natural;
+ val: out byte_array_t);
+
+
+ procedure sparse_set_slice(sparse: inout sparse_t;
+ idx: in natural;
+ val: in byte_array_t);
+
+end sim_utility;
+
+
+package body sim_utility is
+
+ ----------------------------------------------------------------------------
+ -- String manipulation
+
+ function str_endswith(str: string; suffix: string) return boolean is
+ begin
+ if str'length < suffix'length then
+ return false;
+ else
+ return str(str'right - (suffix'length - 1) to str'right) = suffix;
+ end if;
+ end function;
+
+
+ ----------------------------------------------------------------------------
+ -- Sparse byte array for simulated memory devices
+
+ -- Create a new sparse array
+ function sparse_create(default: in byte_t := (others => 'U'); page_size: in natural := 4096) return sparse_t is
+ begin
+ return (
+ default => default,
+ page_size => page_size,
+ first => null
+ );
+ end function;
+
+ -- Load data from a file into a sparse byte array
+ procedure sparse_load(sparse: inout sparse_t; filename: in string; base: in integer := 0) is
+ type char_file_t is file of character;
+ subtype ibyte_t is natural range 0 to 255;
+
+ file f: char_file_t;
+ variable fstatus: FILE_OPEN_STATUS;
+
+ variable i: natural;
+ variable c: character;
+ variable b: ibyte_t;
+ variable v: byte_t;
+ begin
+ -- Load data from file
+ if str_endswith(FILENAME, ".bin") then
+ -- Raw binary file
+
+ file_open(fstatus, f, FILENAME, READ_MODE);
+ assert fstatus = OPEN_OK report "Failed to open file '" & FILENAME & "'" severity failure;
+
+ i := 0;
+ while not endfile(f) loop
+ read(f, c);
+ b := character'pos(c);
+ v := std_logic_vector(to_unsigned(b, 8));
+ sparse_set(sparse, i+base, v);
+ i := i + 1;
+ end loop;
+
+ file_close(f);
+
+ elsif str_endswith(FILENAME, ".hex") then
+ -- Intel HEX format
+ assert false report "Intel HEX format not yet supported" severity failure;
+ else
+ assert false report "Filename suffix not recognized: '" & FILENAME & "'" severity failure;
+ end if;
+ end procedure;
+
+ -- Get a value from a sparse array
+ function sparse_get(sparse: in sparse_t; idx: in natural) return byte_t is
+ variable base: natural;
+ variable this: p_item_t;
+ begin
+ -- Find a page that contains idx
+ base := idx - (idx mod sparse.page_size);
+ this := sparse.first;
+ while this /= null loop
+ if this.base = base then
+ -- Retrieve the value and exit
+ return this.data(idx mod sparse.page_size);
+ end if;
+ this := this.next_item;
+ end loop;
+
+ -- No page containing idx, return the default value
+ return sparse.default;
+ end function;
+
+ -- Set a value within a sparse array
+ procedure sparse_set(sparse: inout sparse_t; idx: in natural; val: in byte_t) is
+ variable base: natural;
+ variable this: p_item_t;
+ variable new_item: p_item_t;
+ begin
+ -- Find a page that contains idx
+ base := idx - (idx mod sparse.page_size);
+ this := sparse.first;
+ while this /= null loop
+ if this.base = base then
+ -- Write the value and exit
+ this.data(idx mod sparse.page_size) := val;
+ return;
+ end if;
+ this := this.next_item;
+ end loop;
+
+ -- No page found containing idx, create one and add it
+ new_item := new item_t;
+
+ new_item.base := base;
+ new_item.data := new byte_array_t(sparse.page_size-1 downto 0);
+ new_item.next_item := sparse.first;
+
+ sparse.first := new_item;
+
+ for i in 0 to sparse.page_size-1 loop
+ new_item.data(i) := sparse.default;
+ end loop;
+ new_item.data(idx mod sparse.page_size) := val;
+ end procedure;
+
+ -- Get a slice of bytes from a sparse array
+ procedure sparse_get_slice(sparse: in sparse_t; idx: in natural; val: out byte_array_t) is
+ begin
+ for i in val'range loop
+ val(i) := sparse_get(sparse, idx+i);
+ end loop;
+ end procedure;
+
+ -- Set a slice of bytes within a sparse array
+ procedure sparse_set_slice(sparse: inout sparse_t; idx: in natural; val: in byte_array_t) is
+ begin
+ for i in val'range loop
+ sparse_set(sparse, idx+i, val(i));
+ end loop;
+ end procedure;
+
+end sim_utility;
+++ /dev/null
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-
-entity wb_memory is
- generic (
- INIT: std_logic_vector(32*8-1 downto 0) := (others => '0')
- );
- port (
- rst_i: in std_logic;
- clk_i: in std_logic;
-
- cyc_i: in std_logic;
- stb_i: in std_logic;
- we_i: in std_logic;
- ack_o: out std_logic;
- adr_i: in std_logic_vector(4 downto 0);
- dat_i: in std_logic_vector(7 downto 0);
- dat_o: out std_logic_vector(7 downto 0)
- );
-end wb_memory;
-
-
-architecture behavioral of wb_memory is
-
- type mem_array_t is array(natural range <>) of std_logic_vector(7 downto 0);
-
- signal mem_array: mem_array_t(31 downto 0);
-
-begin
-
- process (rst_i, clk_i, cyc_i, stb_i, we_i, adr_i, dat_i)
- begin
- if rising_edge(clk_i) then
- if rst_i = '1' then
- for i in 0 to 31 loop
- mem_array(31-i) <= INIT((i+1)*8-1 downto i*8);
- end loop;
- elsif cyc_i = '1' and stb_i = '1' and we_i = '1' then
- mem_array(to_integer(unsigned(adr_i))) <= dat_i;
- end if;
- end if;
- end process;
-
- ack_o <= '1';
- dat_o <= mem_array(to_integer(unsigned(adr_i)));
-
-end behavioral;