Чтобы изучить VHDL, я реализую свой собственный CPU с VHDL.
Я реализую IO с отображением в памяти, который одинаково обращается к традиционной оперативной памяти и различным периферийным устройствам ввода-вывода с точки зрения пользовательского кода.
Это реализация "корня" адресного пространства данных:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity data_memory_controller is
port (
clock: in std_logic;
addr: in std_logic_vector(31 downto 0);
rq: out std_logic_vector(31 downto 0);
wq: in std_logic_vector(31 downto 0);
re: in std_logic;
we: in std_logic;
ledr: out std_logic_vector(9 downto 0);
sw: in std_logic_vector(9 downto 0)
);
end;
architecture rtl of data_memory_controller is
component onchip_ram
generic (
addr_width: integer;
data_width: integer
);
port (
clock: in std_logic;
addr: in std_logic_vector(addr_width-1 downto 0);
rq: out std_logic_vector(data_width-1 downto 0);
wq: in std_logic_vector(data_width-1 downto 0);
re: in std_logic;
we: in std_logic
);
end component;
component ledr_controller
port (
clock: in std_logic;
rq: out std_logic_vector(31 downto 0);
wq: in std_logic_vector(31 downto 0);
re: in std_logic;
we: in std_logic;
ledr: out std_logic_vector(9 downto 0)
);
end component;
component sw_controller
port (
clock: in std_logic;
rq: out std_logic_vector(31 downto 0);
re: in std_logic;
sw: in std_logic_vector(9 downto 0)
);
end component;
signal c0, c1, c2: std_logic;
signal rq_tri: std_logic_vector(31 downto 0);
begin
c0 <= '1' when std_match(addr, "000000000000000000000000--------") else '0';
c1 <= '1' when std_match(addr, "10000000000000000000000000000000") else '0';
c2 <= '1' when std_match(addr, "10000000000000000000000000000001") else '0';
onchip_ram_c: onchip_ram generic map(
addr_width => 8,
data_width => 32
) port map (
clock => clock,
addr => addr(7 downto 0),
rq => rq_tri,
wq => wq,
re => re and c0,
we => we and c0
);
ledr_controller_c: ledr_controller port map(
clock => clock,
rq => rq_tri,
wq => wq,
re => re and c1,
we => we and c1,
ledr => ledr
);
sw_controller_c: sw_controller port map(
clock => clock,
rq => rq_tri,
re => re and c2,
sw => sw
);
rq <= rq_tri; -- line 90
rq <= (others => 'L'); -- line 91
end;
Это реализация одного из периферийных устройств ввода / вывода:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sw_controller is
port (
clock: in std_logic;
rq: out std_logic_vector(31 downto 0);
re: in std_logic;
sw: in std_logic_vector(9 downto 0)
);
end;
architecture rtl of sw_controller is
begin
process(clock)
begin
if rising_edge(clock) then
if std_match(re, '1') then
rq <= "0000000000000000000000" & sw;
else
rq <= (others => 'Z');
end if;
end if;
end process;
end;
Каждое периферийное устройство принимает сигнал разрешения чтения. если разрешение на чтение становится высоким, это приводит к rq
линии; в противном случае задается высокий импеданс, чтобы другие периферийные устройства могли двигаться.
Назначение строки 90 и строки 91 data_memory_controller
состоит в том, что состояние с высоким импедансом не распространяется за пределы этой сущности; для реального оборудования это может быть реализовано понижающим резистором.
Насколько я знаю, из-за правила разрешения std_logic
, rq
из data_memory_controller
становятся 'L', если нет периферийных устройств, которые управляют выходом (= rq_tri
- это 'Z'); в противном случае rq
копирует содержимое rq_tri
.
Однако на этапе анализа и синтеза возвращается следующая ошибка:
Error (10028): Can't resolve multiple constant drivers for net "rq[31]" at data_memory_controller.vhd(90)
Error (10029): Constant driver at data_memory_controller.vhd(91)
Error (10028): Can't resolve multiple constant drivers for net "rq[30]" at data_memory_controller.vhd(90)
Error (10028): Can't resolve multiple constant drivers for net "rq[29]" at data_memory_controller.vhd(90)
...... [similar Error (10028) messages] ......
Да, я "управляю" несколькими сигналами на одной линии, но я подумал, что для этой ситуации есть четко определенные правила, и эту программу следует принять.
Если что-то не так, пожалуйста, поправьте меня. Более того, я хочу найти альтернативные способы
- каждая периферия может управлять выходом, или 'Z' зависит от сигнала разрешения чтения, а
- не распространять 'Z' снаружи
data_memory_controller
Я использую Quartus Prime Lite Edition версии 18.0, и эта реализация будет загружена на микросхему FPGA серии Intel MAX 10.