2008/12/10

Spartan3 PCIバス付きFPGA評価ボード(8)

まだまだ作成途上なので汚いですが、pciコアのソースコードです。

  • PCIコア部分です。RAMを読む部分とPCIコアを分けていて、appcore_start、appcore_doneという信号で同期をとっています(その割には分離性が高くないですが)。このあたりをきちんと考えて設計しないと、バースト転送で速度を上げるのは難しそう。


----------------------------------------------------------------------------------
-- Company:
-- Engineer: taipapa
--
-- Create Date: 21:40:28 11/22/2008
-- Design Name:
-- Module Name: pci1 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------

-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.


---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity pcicore is
Port (PCI_CLK : in STD_LOGIC;
N_INTA : out STD_LOGIC;
N_RST_I : in STD_LOGIC;
N_FRAME_IO : inout STD_LOGIC;
N_TRDY_IO : inout STD_LOGIC;
N_GNT_I : in STD_LOGIC;
N_STOP_IO : inout STD_LOGIC;
PAR_IO : inout STD_LOGIC;
IDSEL_I : in STD_LOGIC;
N_IRDY_IO : inout STD_LOGIC;
N_DEVSEL_IO : inout STD_LOGIC;
N_PERR_IO : inout STD_LOGIC;
N_SERR_IO : inout STD_LOGIC;
N_REQ_Q : inout STD_LOGIC;
N_CBE_IO : inout STD_LOGIC_VECTOR(3 downto 0);
AD_IO : inout STD_LOGIC_VECTOR(31 downto 0);

-- 7 Segments
SEG_LED_SELECT : out STD_LOGIC_VECTOR(4 downto 0);
SEG_LED_DATA : out STD_LOGIC_VECTOR(7 downto 0);

-- LEDs
LED_2 : out STD_LOGIC;
LED_3 : out STD_LOGIC;
LED_4 : out STD_LOGIC;
LED_5 : out STD_LOGIC);
end pcicore;

architecture Behavioral of pcicore is

component SEGDISP
Port (PCI_CLK : in STD_LOGIC;
RESET: in STD_LOGIC;
SEL : out STD_LOGIC_VECTOR(4 downto 0);
DAT : out STD_LOGIC_VECTOR(7 downto 0);
DIGIT0: in std_logic_vector (3 downto 0);
DIGIT1: in std_logic_vector (3 downto 0);
DIGIT2: in std_logic_vector (3 downto 0);
DIGIT3: in std_logic_vector (3 downto 0));
end component;

component ram
port (
clka: IN std_logic;
dina: IN std_logic_VECTOR(31 downto 0);
addra: IN std_logic_VECTOR(8 downto 0);
wea: IN std_logic_vector(0 downto 0);
douta: OUT std_logic_VECTOR(31 downto 0));
end component;

-- PCI signals
signal AD_PORT: std_logic_vector(31 downto 0);
signal DEVSEL_PORT: std_logic;
signal TRDY_PORT: std_logic;
signal STOP_PORT: std_logic;
signal SERR_PORT : std_logic := 'Z';
signal PERR_PORT : std_logic := 'Z';
signal PAR_PORT : std_logic := 'Z';

-- Latched signals
signal buscommand : std_logic_vector(3 downto 0);
signal address : std_logic_vector(31 downto 0);
signal idsel : std_logic;

-- Address decoder
signal Hit_device : std_logic;
signal Hit_Memory0 : std_logic;
signal Hit_Memory1 : std_logic;
signal Hit_Config : std_logic;

-- State machine
signal curstate: std_logic_vector(3 downto 0);
signal nxtstate: std_logic_vector(3 downto 0);
constant IDLE : std_logic_vector(3 downto 0) := "0000";
constant ADDR : std_logic_vector(3 downto 0) := "0001";
constant BUSY : std_logic_vector(3 downto 0) := "0010";
constant IRDY : std_logic_vector(3 downto 0) := "0011";
constant LOCALWAIT : std_logic_vector(3 downto 0) := "0100";
constant COMP : std_logic_vector(3 downto 0) := "0101";
constant COMP2 : std_logic_vector(3 downto 0) := "0110";
constant DISCON : std_logic_vector(3 downto 0) := "0111";
constant INIT : std_logic_vector(3 downto 0) := "1000";
constant ERR : std_logic_vector(3 downto 0) := "1111";

-- Local State machine
signal l_curstate: std_logic_vector(3 downto 0) := "0000";
signal l_nxtstate: std_logic_vector(3 downto 0) := "0000";
constant L_IDLE : std_logic_vector(3 downto 0) := "0000";
constant L_CFG : std_logic_vector(3 downto 0) := "0001";
constant L_MEM0 : std_logic_vector(3 downto 0) := "0010";
constant L_MEM1 : std_logic_vector(3 downto 0) := "0011";
-- constant L_MEM2 : std_logic_vector(3 downto 0) := "0100";
constant L_COMP : std_logic_vector(3 downto 0) := "0101";
constant L_ERR : std_logic_vector(3 downto 0) := "1111";
signal appcore_start : std_logic;
signal appcore_done : std_logic;

-- PCI bus command
constant CMD_MemRead : std_logic_vector(3 downto 0) := ("0110");
constant CMD_MemWrite : std_logic_vector(3 downto 0) := ("0111");
constant CMD_ConfRead : std_logic_vector(3 downto 0) := ("1010");
constant CMD_ConfWrite : std_logic_vector(3 downto 0) := ("1011");

-- Config Regs
signal CFG_vendorID : std_logic_vector(15 downto 0) := (X"3449");
signal CFG_deviceID : std_logic_vector(15 downto 0) := (X"8000");
signal CFG_command : std_logic_vector(15 downto 0) := (X"0000");
signal CFG_status : std_logic_vector(15 downto 0) := (X"0200");
signal CFG_baseclass : std_logic_vector(7 downto 0) := (X"05");
signal CFG_subclass : std_logic_vector(7 downto 0) := (X"00");
signal CFG_programIF : std_logic_vector(7 downto 0) := (X"00");
signal CFG_revisionID : std_logic_vector(7 downto 0) := (X"01");
signal CFG_headertype : std_logic_vector(7 downto 0) := (X"00");

-- BAR
-- 16Bytes
signal CFG_BAR0 : std_logic_vector(31 downto 4);
-- 1MBytes
signal CFG_BAR1 : std_logic_vector(31 downto 20);

-- test registers accessed through memory space
signal regtest0 : std_logic_vector(31 downto 0) := (X"00100000");

-- ram
signal Ram_din : std_logic_vector(31 downto 0);
signal Ram_dout : std_logic_vector(31 downto 0);
signal Ram_addr : std_logic_vector(8 downto 0);
signal Ram_we : std_logic_vector(0 downto 0);

begin

-- LED connection
LED_2 <= N_FRAME_IO;
LED_3 <= N_DEVSEL_IO;
LED_4 <= N_IRDY_IO;
LED_5 <= DEVSEL_Port;

-- modules: Segment display
segs : SEGDISP port map(
PCI_CLK => PCI_CLK,
RESET => N_RST_I,
SEL => SEG_LED_SELECT,
DAT => SEG_LED_DATA,
DIGIT0 => curstate,
DIGIT1 => regtest0(23 downto 20),
DIGIT2 => regtest0(27 downto 24),
DIGIT3 => regtest0(31 downto 28));

-- the ram
raminst : ram
port map (
clka => PCI_CLK,
dina => Ram_din,
addra => Ram_addr,
wea => Ram_we,
douta => Ram_dout);

-- Address decoder
Hit_device <= Hit_memory0 or Hit_memory1 or Hit_config;
process(idsel, buscommand, address, CFG_BAR0, CFG_BAR1, CFG_command)
begin
-- Check memory space access
if ((buscommand = CMD_MemRead or buscommand = CMD_MemWrite) and
CFG_command(1) = '1') then
if (address(31 downto 4) = CFG_BAR0(31 downto 4)) then
Hit_memory0 <= '1';
Hit_memory1 <= '0';
elsif (address(31 downto 20) = CFG_BAR1(31 downto 20)) then
Hit_memory0 <= '0';
Hit_memory1 <= '1';
else
Hit_memory0 <= '0';
Hit_memory1 <= '0';
end if;
else
Hit_memory0 <= '0';
Hit_memory1 <= '0';
end if;

-- Check config space access
if ((buscommand = CMD_ConfRead or buscommand = CMD_ConfWrite) and
-- am I selected?
idsel = '1' and
-- function 0, type 0
address(10 downto 8) = "000" and address(1 downto 0) = "00")
then
Hit_config <= '1';
else
Hit_config <= '0';
end if;
end process;


-- Application core state machine

-- Higher bits are ignored
Ram_addr <= address(10 downto 2);

process(PCI_CLK, N_RST_I)
begin
if (N_RST_I = '0') then
-- Initialize state machine
l_curstate <= L_IDLE;
l_nxtstate <= L_IDLE;
appcore_done <= '0';

-- Initialize configuration registers
CFG_BAR0 <= (others => '0');
CFG_BAR1 <= (others => '0');
CFG_command <= (others => '0');

-- Ram initialize
Ram_we <= "0";

elsif (PCI_CLK'event and PCI_CLK='1') then

l_curstate <= l_nxtstate;

case l_curstate is
-- Local idle state
when L_IDLE =>
if (appcore_start = '1') then
if (Hit_config = '1') then
l_nxtstate <= L_CFG;
end if;
if (Hit_memory0 = '1') then
l_nxtstate <= L_MEM0;
end if;
if (Hit_memory1 = '1') then
l_nxtstate <= L_MEM1;
end if;
else
l_nxtstate <= L_IDLE;
end if;

-- Configuration space
when L_CFG =>
if (buscommand(0) = '1') then
-- Config Write
case address(7 downto 2) is
-- Command register
when "000001" =>
if (N_CBE_IO(0) = '0') then
-- Memory space bit
CFG_command(1) <= AD_IO(1);
end if;

-- Bar0
when "000100" =>
if (N_CBE_IO(3) = '0') then
CFG_BAR0(31 downto 24) <= AD_IO(31 downto 24);
end if;
if (N_CBE_IO(2) = '0') then
CFG_BAR0(23 downto 16) <= AD_IO(23 downto 16);
end if;
if (N_CBE_IO(1) = '0') then
CFG_BAR0(15 downto 8) <= AD_IO(15 downto 8);
end if;
if (N_CBE_IO(0) = '0') then
CFG_BAR0(7 downto 4) <= AD_IO(7 downto 4);
end if;

-- Bar1
when "000101" =>
if (N_CBE_IO(3) = '0') then
CFG_BAR1(31 downto 24) <= AD_IO(31 downto 24);
end if;
if (N_CBE_IO(2) = '0') then
CFG_BAR1(23 downto 20) <= AD_IO(23 downto 20);
end if;

when others =>
null;
end case;
else
-- Config Read
case address(7 downto 2) is
when "000000" => -- vendor ID/dev ID
AD_Port(31 downto 16) <= CFG_deviceID;
AD_Port(15 downto 0) <= CFG_vendorID;
when "000001" => -- status/command
AD_Port(31 downto 16) <= CFG_status;
AD_Port(15 downto 0) <= CFG_command;
when "000010" => -- class code
AD_Port(31 downto 24) <= CFG_baseclass;
AD_Port(23 downto 16) <= CFG_subclass;
AD_Port(15 downto 8) <= CFG_programIF;
AD_Port(7 downto 0) <= CFG_revisionID;
when "000011" => -- header types
AD_Port(31 downto 24) <= (others => '0');
AD_Port(23 downto 16) <= CFG_headertype;
AD_Port(15 downto 0) <= (others => '0');
when "000100" => -- BAR0
AD_Port(31 downto 4) <= CFG_BAR0(31 downto 4);
AD_Port(3 downto 0) <= (others => '0');
when "000101" => -- BAR1
AD_Port(31 downto 20) <= CFG_BAR1(31 downto 20);
AD_Port(19 downto 0) <= (others => '0');
when "001011" => -- subvendor ID/subsystem ID
AD_Port(31 downto 16) <= CFG_deviceID;
AD_Port(15 downto 0) <= CFG_vendorID;
when others =>
AD_Port(31 downto 0) <= (others => '0');
end case;
end if;
appcore_done <= '1';
l_nxtstate <= L_COMP;

-- BAR0 memory space
when L_MEM0 =>
if (buscommand(0) = '1') then
-- Memory Write
case address(7 downto 0) is
when "00000000" =>
if (N_CBE_IO(3) = '0') then
regtest0(31 downto 24) <= AD_IO(31 downto 24);
end if;
if (N_CBE_IO(2) = '0') then
regtest0(23 downto 16) <= AD_IO(23 downto 16);
end if;
if (N_CBE_IO(1) = '0') then
regtest0(15 downto 8) <= AD_IO(15 downto 8);
end if;
if (N_CBE_IO(0) = '0') then
regtest0(7 downto 0) <= AD_IO(7 downto 0);
end if;
when others =>
null;
end case;
else
-- Memory Read
case address(7 downto 0) is
when "00000000" =>
AD_Port <= regtest0;
when others =>
AD_Port <= (others => '0');
end case;
end if;

appcore_done <= '1';
l_nxtstate <= L_COMP;

-- BAR1 memory space
when L_MEM1 =>
if (buscommand(0) = '1') then
-- Memory Write
Ram_din <= AD_IO;
Ram_we <= "1";
else
-- Memory Read
Ram_we <= "0";
AD_Port <= Ram_dout;
end if;
appcore_done <= '1';
l_nxtstate <= L_COMP;

when L_COMP =>
-- Indicate we finished
appcore_done <= '0';

-- Stop driving AD
AD_Port <= (others => 'Z');

-- stop we
Ram_we <= "0";

l_nxtstate <= L_IDLE;

when L_ERR =>
l_nxtstate <= L_ERR;

when others =>
l_nxtstate <= L_ERR;

end case;
end if;
end process;

-- Main state machine
process(PCI_CLK, N_RST_I)
begin
if (N_RST_I = '0') then
-- Initialize state machine
curstate <= INIT;
nxtstate <= INIT;
elsif (PCI_CLK'event and PCI_CLK='1') then
curstate <= nxtstate;

case curstate is
when INIT =>
appcore_start <= '0';
-- Initialize internal registers
DEVSEL_PORT <= 'Z';
TRDY_PORT <= 'Z';
STOP_PORT <= 'Z';
AD_Port <= (others => 'Z');
nxtstate <= IDLE;

-- BUS idle
when IDLE =>
if (N_FRAME_IO = '0' and N_IRDY_IO = '1') then
buscommand <= N_CBE_IO;
address <= AD_IO;
idsel <= IDSEL_I;
nxtstate <= ADDR;
else
nxtstate <= IDLE;
end if;

-- Address decode
when ADDR =>
if (Hit_device = '1') then
DEVSEL_PORT <= '0';
TRDY_PORT <= '1';
-- deassert STOP#
STOP_PORT <= '1';
nxtstate <= IRDY;
else
nxtstate <= BUSY;
end if;

when BUSY =>
if (N_FRAME_IO = '1' and N_IRDY_IO = '1') then
nxtstate <= IDLE;
else
nxtstate <= BUSY;
end if;

when IRDY =>
if (N_IRDY_IO = '0') then
appcore_start <= '1';
nxtstate <= LOCALWAIT;
else
nxtstate <= IRDY;
end if;

when LOCALWAIT =>
appcore_start <= '0';
if (appcore_done = '1') then
TRDY_PORT <= '0';
-- assert STOP#
STOP_PORT <= '0';
nxtstate <= COMP;
else
nxtstate <= LOCALWAIT;
end if;

when COMP =>
TRDY_PORT <= '1';
AD_Port <= (others => 'Z');

if (N_FRAME_IO = '0') then
-- Burst Transfer
nxtstate <= DISCON;
else
DEVSEL_PORT <= '1';
STOP_PORT <= '1';
nxtstate <= COMP2;
end if;

when DISCON =>
if (N_FRAME_IO = '0') then
nxtstate <= DISCON;
else
DEVSEL_PORT <= '1';
STOP_PORT <= '1';
nxtstate <= COMP2;
end if;

when COMP2 =>
TRDY_PORT <= 'Z';
DEVSEL_PORT <= 'Z';
STOP_PORT <= 'Z';
nxtstate <= IDLE;

when ERR =>
nxtstate <= ERR;

when others =>
nxtstate <= ERR;

end case;
end if;
end process;

N_DEVSEL_IO <= DEVSEL_PORT;
N_TRDY_IO <= TRDY_PORT;
N_STOP_IO <= STOP_PORT;
AD_IO <= AD_Port;

N_SERR_IO <= SERR_PORT;
N_PERR_IO <= PERR_PORT;
PAR_IO <= PAR_PORT;

N_INTA <= '1';

end Behavioral;


  • 7セグメントx4のLEDのドライバです。


----------------------------------------------------------------------------------
-- Company:
-- Engineer: taipapa
--
-- Create Date: 21:40:28 11/22/2008
-- Design Name: 7 seg driver
-- Module Name: seg - Behavioral
-- Project Name: pci1
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------

-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity SEGDISP is
Port (PCI_CLK : in STD_LOGIC;
RESET: in STD_LOGIC;
SEL : out STD_LOGIC_VECTOR(4 downto 0);
DAT : out STD_LOGIC_VECTOR(7 downto 0);
DIGIT0: in std_logic_vector (3 downto 0);
DIGIT1: in std_logic_vector (3 downto 0);
DIGIT2: in std_logic_vector (3 downto 0);
DIGIT3: in std_logic_vector (3 downto 0));
end SEGDISP;

architecture rtl of SEGDISP is
signal cnt : std_logic_vector(15 downto 0);
signal SEG_curdigit : std_logic_vector(1 downto 0);
signal SEG_segval : std_logic_vector(3 downto 0);
type digits_t is array (3 downto 0) of std_logic_vector (3 downto 0);
signal SEG_digits : digits_t;
signal SEG_SEL: std_logic_vector(3 downto 0); -- do not use semicolon
signal SEG_DATA: std_logic_vector(6 downto 0);
begin
process(PCI_CLK, RESET)
begin
if (RESET = '0') then
cnt <= (others => '0');
SEG_curdigit <= "00";
elsif (PCI_CLK'event and PCI_CLK='1') then
SEG_digits(0) <= DIGIT0;
SEG_digits(1) <= DIGIT1;
SEG_digits(2) <= DIGIT2;
SEG_digits(3) <= DIGIT3;
cnt <= cnt + '1';
if (cnt = "0") then
SEG_curdigit <= SEG_curdigit + '1';
end if;
end if;
end process;

-- Selectors (digits bit, segment value)
SEG_segval <= SEG_digits((CONV_INTEGER(SEG_curdigit(1 downto 0))));
with SEG_curdigit select
SEG_SEL <=
"0001" when "00", -- 1
"0010" when "01", -- 10
"0100" when "10", -- 100
"1000" when "11", -- 1000
"1111" when others; -- ?

with SEG_segval select
SEG_DATA <=
"1111110" when "0000", -- 0
"0110000" when "0001", -- 1
"1101101" when "0010", -- 2
"1111001" when "0011", -- 3
"0110011" when "0100", -- 4
"1011011" when "0101", -- 5
"1011111" when "0110", -- 6
"1110000" when "0111", -- 7
"1111111" when "1000", -- 8
"1111011" when "1001", -- 9
"1110111" when "1010", -- A
"0011111" when "1011", -- B
"1001110" when "1100", -- C
"0111101" when "1101", -- D
"1001111" when "1110", -- E
"1000111" when "1111", -- F
"0110111" when others; -- 10-15, H mark

SEL <= '0' & SEG_SEL;
DAT <= not ('0' & SEG_DATA);

end rtl;

0 件のコメント: