107 lines
3.6 KiB
VHDL
Raw Normal View History

2022-04-07 18:43:21 +02:00
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity LEDs is
port(
-- bus interface
clk : in std_logic;
reset_n : in std_logic;
cs : in std_logic;
read : in std_logic;
write : in std_logic;
address : in std_logic_vector(1 downto 0);
rddata : out std_logic_vector(31 downto 0);
wrdata : in std_logic_vector(31 downto 0);
-- external output
LEDs : out std_logic_vector(95 downto 0)
);
end LEDs;
architecture synth of LEDs is
constant REG_LED_0_31 : std_logic_vector(1 downto 0) := "00";
constant REG_LED_32_63 : std_logic_vector(1 downto 0) := "01";
constant REG_LED_64_95 : std_logic_vector(1 downto 0) := "10";
constant REG_DUTY_CYCLE : std_logic_vector(1 downto 0) := "11";
signal reg_read : std_logic;
signal reg_address : std_logic_vector(1 downto 0);
signal counter : std_logic_vector(7 downto 0);
signal LEDs_reg : std_logic_vector(95 downto 0);
signal LEDs_FPGA4U : std_logic_vector(95 downto 0);
signal duty_cycle : std_logic_vector(7 downto 0);
begin
LEDs_FPGA4U <= LEDs_reg when counter < duty_cycle else (others => '0');
-- On FPGA4U, LEDs were addressed by column, on GECKO by row and mirrored
-- Therefore, we need to transpose the indices and flip the indeces along x
process(LEDs_FPGA4U)
variable LEDs_before_transpose: std_logic_vector(95 downto 0);
begin
for i in 0 to 95 loop
LEDs_before_transpose(i / 8 + (i mod 8) * 12) := LEDs_FPGA4U(i);
LEDs(i) <= LEDs_before_transpose((i / 12 + 1) * 12 - 1 - (i mod 12));
end loop;
end process;
-- registers
process(clk, reset_n)
begin
if (reset_n = '0') then
reg_read <= '0';
reg_address <= (others => '0');
counter <= (others => '0');
elsif (rising_edge(clk)) then
reg_read <= cs and read;
reg_address <= address;
if address /= REG_DUTY_CYCLE then
counter <= std_logic_vector(unsigned(counter) + 1);
else
counter <= (others => '0');
end if;
end if;
end process;
-- read
process(reg_read, reg_address, LEDs_reg, duty_cycle)
begin
rddata <= (others => 'Z');
if (reg_read = '1') then
rddata <= (others => '0');
case reg_address is
when REG_LED_0_31 =>
rddata <= LEDs_reg(31 downto 0);
when REG_LED_32_63 =>
rddata <= LEDs_reg(63 downto 32);
when REG_LED_64_95 =>
rddata <= LEDs_reg(95 downto 64);
when REG_DUTY_CYCLE =>
rddata(7 downto 0) <= duty_cycle;
when others =>
end case;
end if;
end process;
-- write
process(clk, reset_n)
begin
if (reset_n = '0') then
LEDs_reg <= (others => '0');
duty_cycle <= X"0F";
elsif (rising_edge(clk)) then
if (cs = '1' and write = '1') then
case address is
when REG_LED_0_31 => LEDs_reg(31 downto 0) <= wrdata;
when REG_LED_32_63 => LEDs_reg(63 downto 32) <= wrdata;
when REG_LED_64_95 => LEDs_reg(95 downto 64) <= wrdata;
when REG_DUTY_CYCLE => duty_cycle <= wrdata(7 downto 0);
when others => null;
end case;
end if;
end if;
end process;
end synth;