trashernet-soc/fpga/hdl/device_models/aps6404l.vhd

179 lines
4.7 KiB
VHDL

-- -------------------------------------------------------------------------- --
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
-- -------------------------------------------------------------------------- --
-- TODO
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- 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(
LOG_EN : boolean := true
);
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);
variable mem : byte_vector(0 to 1023);
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
dout := mem(addr);
print(" Read " & integer'image(addr) & ": " & to_hstring(mem(addr)));
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)));
mem(addr) := bytes(bytecnt);
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;