-- -------------------------------------------------------------------------- -- -- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- -- -------------------------------------------------------------------------- -- -- TODO -- -------------------------------------------------------------------------- -- -- Author : Markus Koch -- Contributors : None -- License : Mozilla Public License (MPL) Version 2 -- -------------------------------------------------------------------------- -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use std.textio.all; entity aps6404l is generic( SIZE : natural := 1024; LOG_EN : boolean := true; MEMFILE : string := "" ); port( ce_n : in std_logic; sclk : in std_logic; sio : inout std_logic_vector(3 downto 0) ); end entity aps6404l; architecture bench of aps6404l is procedure print(text : string) is variable buf : line; begin if not LOG_EN then return; end if; write(buf, string'("aps6404l: ")); write(buf, text); WriteLine(OUTPUT, buf); end procedure print; begin test : process is type rx_state_t is (COMMAND, READ, WRITE, COMPLETE); type byte_vector is array (natural range <>) of std_logic_vector(7 downto 0); subtype mem_t is byte_vector(0 to SIZE - 1); impure function init_ram_hex return mem_t is file text_file : text; variable text_line : line; variable ram_content : mem_t := (others => x"5A"); begin if MEMFILE /= "" then file_open(text_file, MEMFILE, read_mode); for i in 0 to SIZE - 1 loop exit when endfile(text_file); readline(text_file, text_line); hread(text_line, ram_content(i)); end loop; end if; return ram_content; end function; variable mem : mem_t := init_ram_hex; variable bytes : byte_vector(0 to 32); variable cnt, bytecnt : integer; variable state : rx_state_t; variable mode : integer := 0; variable wrap_boundary : boolean := false; variable dout : std_logic_vector(7 downto 0); variable addr : integer; variable sio_temp : std_logic_vector(sio'range); procedure handle(command_edge : boolean) is begin if command_edge then case state is when COMMAND => case bytes(0) is when x"66" => print(" SPI reset enter"); state := COMPLETE; when x"99" => print(" SPI reset execute"); mode := 0; wrap_boundary := false; state := COMPLETE; when x"35" => print(" QPI enter"); mode := 1; state := COMPLETE; when x"F5" => print(" QPI exit"); mode := 0; state := COMPLETE; when x"C0" => print(" Wrap Boundary Toggle"); wrap_boundary := not wrap_boundary; state := COMPLETE; when x"0B" => print(" QPI Read Slow"); state := READ; when x"EB" => print(" QPI Read Fast"); state := READ; when x"02" => print(" QPI Write (1)"); state := WRITE; when x"38" => print(" QPI Write (2)"); state := WRITE; when others => print(" Unknown command: 0x" & to_hstring(bytes(0))); state := COMPLETE; end case; when READ => if bytecnt = 3 then print(" Addr: " & to_hstring(bytes(1)) & to_hstring(bytes(2)) & to_hstring(bytes(3))); addr := to_integer(unsigned(std_logic_vector'(bytes(1), bytes(2), bytes(3)))); elsif bytecnt > 4 then if addr < SIZE then dout := mem(addr); print(" Read " & integer'image(addr) & ": " & to_hstring(mem(addr))); else dout := (others => 'X'); print(" Read " & integer'image(addr) & ": OUT-OF-BOUNDS"); end if; addr := addr + 1; end if; when WRITE => if bytecnt = 3 then print(" Addr: " & to_hstring(bytes(1)) & to_hstring(bytes(2)) & to_hstring(bytes(3))); addr := to_integer(unsigned(std_logic_vector'(bytes(1), bytes(2), bytes(3)))); elsif bytecnt > 3 then print(" Write " & integer'image(addr) & ": " & to_hstring(bytes(bytecnt))); if (addr < SIZE) then mem(addr) := bytes(bytecnt); else print(" Error: OUT OF BOUNDS access! Ignoring write."); end if; addr := addr + 1; end if; when COMPLETE => null; end case; bytecnt := bytecnt + 1; end if; if state = READ and bytecnt > 4 then sio_temp := dout(7 downto 4) when command_edge else dout(3 downto 0); sio <= sio_temp after 5 ns; end if; end procedure handle; begin sio <= (others => 'Z'); wait until ce_n = '0'; print("Selected."); bytes := (others => (others => 'U')); cnt := 0; bytecnt := 0; state := COMMAND; loop wait on sclk, ce_n; if mode = 0 then -- SPI if falling_edge(sclk) then bytes(cnt / 8)(7 - (cnt mod 8)) := sio(0); cnt := cnt + 1; if cnt mod 4 = 0 then handle(cnt mod 8 = 0); end if; end if; else -- QPI if falling_edge(sclk) then bytes(cnt / 2)((1 - (cnt mod 2) + 1) * 4 - 1 downto (1 - (cnt mod 2)) * 4) := sio; cnt := cnt + 1; end if; if falling_edge(sclk) then handle(cnt mod 2 = 0); end if; end if; exit when ce_n = '1'; end loop; print("Deselected."); end process test; end architecture bench;