Skip to content

Instantly share code, notes, and snippets.

@atnon
Created May 11, 2015 17:45
Show Gist options
  • Save atnon/891d0b79ec26b78c7451 to your computer and use it in GitHub Desktop.
Save atnon/891d0b79ec26b78c7451 to your computer and use it in GitHub Desktop.
APB Slave, just something random.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library grlib;
use grlib.amba.all;
use grlib.stdlib.all;
use grlib.devices.all;
library work;
entity lcd_apb is
generic(
pindex : integer := 0;
paddr : integer := 0;
pmask : integer := 16#fff#;
pirq : integer := 0;
cpu_freq : integer := 100000 -- CPU Frequency in kHz.
);
port(
clk : in std_logic;
rstn : in std_logic;
apbi : in apb_slv_in_type;
apbo : out apb_slv_out_type;
);
end entity lcd_apb;
architecture RTL of lcd_apb is
constant pconfig : apb_config_type := (
0 => ahb_device_reg(VENDOR_OPENCORES, GAISLER_GPREG, 0, 0, pirq),
1 => apb_iobar(paddr, pmask)
);
type stateType is (IDLE, HOLD);
signal state : stateType := IDLE;
begin
APB_Ctrl_Write : process(clk, rstn) is
begin
apbo.pirq(pirq) <= '0'; -- Interrupt is normally not triggered.
if rstn = '0' then
elsif rising_edge(clk) then
if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then -- triggers when new data.
-- APB is byte addressed, so we cannot use the two lower bits.
case apbi.paddr(4 downto 2) is
when "000" => -- Base address
SomeReg1 <= apbi.pwdata(31 downto 0); -- Latch data from bus.
when "001" => -- Base address + 0x4
SomeReg2 <= apbi.pwdata(31 downto 0); -- Latch data from bus.
when others =>
null;
end case;
end if;
apbo.pirq(pirq) <= '1'; -- Trigger interrupt
end if;
end process APB_Ctrl_Write;
-- APB read process, we need not worry about signals since the APB master
-- arbitrates what is read.
APB_Ctrl_Read : process(rstn, apbi) is
begin
if rstn = '0' then
apbo.prdata <= (others => '0');
elsif rising_edge(clk) then
case apbi.paddr(4 downto 2) is
when "000" =>
apbo.prdata <= SomeReg1;
when "001" =>
apbo.prdata <= SomeReg2;
when others =>
apbo.prdata <= (others => '0');
end case;
end if;
end process APB_Ctrl_Read;
-- IRQ implementation will probably differ a lot depending on what
-- triggers the IRQ. The important thing is that the IRQ is not high
-- longer than one clock cycle.
APB_Ctrl_IRQ : process(clk, rstn) is
begin
if rstn = '0' then
apbo.pirq(pirq) <= '0';
state <= IDLE;
elsif rising_edge(clk) then
apbo.pirq(pirq) <= '0';
case state is
when IDLE =>
-- Waiting for trigger signal to go high.
if triggerSignal = '1' then
state <= HOLD;
apbo.pirq(pirq) = '1';
end if;
when HOLD =>
-- Waiting for tigger signal to go low.
if triggerSignal = '0' then
state <= IDLE;
end if;
end case;
end if;
end process APB_Ctrl_IRQ;
-- Set APB bus signals.
apbo.pindex <= pindex; -- VHDL Generic
apbo.pconfig <= pconfig; -- VHDL Constant
--pragma translate_off
bootmsg : report_version
generic map("apbvgreport_versiona" & tost(pindex) & ": My APB Slave");
--pragma translate_on
end architecture RTL;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment