368 lines
12 KiB
VHDL
368 lines
12 KiB
VHDL
library ieee;
|
||
use ieee.std_logic_1164.all;
|
||
use ieee.std_logic_arith.all;
|
||
use ieee.std_logic_unsigned.all;
|
||
|
||
entity RAM9X8_PWM is
|
||
generic(
|
||
PWM_BASE_ADDRESS : integer := 16;
|
||
|
||
DATA_BUS_WIDTH : integer := 8;
|
||
ADDRESS_BUS_WIDTH : integer := 9
|
||
);
|
||
|
||
port(
|
||
clk : in std_logic;
|
||
|
||
data : inout std_logic_vector(DATA_BUS_WIDTH - 1 downto 0);
|
||
address : in std_logic_vector(ADDRESS_BUS_WIDTH - 1 downto 0);
|
||
we : in std_logic;
|
||
oe : in std_logic;
|
||
ce : in std_logic;
|
||
|
||
tk : out std_logic_vector(31 downto 0) := (others => '1');
|
||
interrupt : out std_logic := '1';
|
||
pwm : in std_logic_vector(5 downto 0);
|
||
error : in std_logic
|
||
);
|
||
end entity;
|
||
|
||
architecture behavorial of RAM9X8_PWM is
|
||
|
||
signal PWM_MODE_CONTROL_LOWER : integer := PWM_BASE_ADDRESS;
|
||
signal PWM_MODE_CONTROL_UPPER : integer := PWM_BASE_ADDRESS + 1;
|
||
signal PWM_MASK_2_LOWER : integer := PWM_BASE_ADDRESS + 2;
|
||
signal PWM_MASK_2_UPPER : integer := PWM_BASE_ADDRESS + 3;
|
||
signal PWM_MASK_1_LOWER : integer := PWM_BASE_ADDRESS + 4;
|
||
signal PWM_MASK_1_UPPER : integer := PWM_BASE_ADDRESS + 5;
|
||
signal PWM_DIRECT_CONTROL_2_LOWER : integer := PWM_BASE_ADDRESS + 6;
|
||
signal PWM_DIRECT_CONTROL_2_UPPER : integer := PWM_BASE_ADDRESS + 7;
|
||
signal PWM_DIRECT_CONTROL_1_LOWER : integer := PWM_BASE_ADDRESS + 8;
|
||
signal PWM_DIRECT_CONTROL_1_UPPER : integer := PWM_BASE_ADDRESS + 9;
|
||
signal PWM_PERIOD_LOWER : integer := PWM_BASE_ADDRESS + 10;
|
||
signal PWM_PERIOD_UPPER : integer := PWM_BASE_ADDRESS + 11;
|
||
signal PWM_DIRECTION_2_LOWER : integer := PWM_BASE_ADDRESS + 12;
|
||
signal PWM_DIRECTION_2_UPPER : integer := PWM_BASE_ADDRESS + 13;
|
||
signal PWM_DIRECTION_1_LOWER : integer := PWM_BASE_ADDRESS + 14;
|
||
signal PWM_DIRECTION_1_UPPER : integer := PWM_BASE_ADDRESS + 15;
|
||
signal PWM_CHANNEL_LOWER : integer := PWM_BASE_ADDRESS + 16;
|
||
signal PWM_CHANNEL_UPPER : integer := PWM_BASE_ADDRESS + 17;
|
||
signal PWM_TIMING_LOWER : integer := PWM_BASE_ADDRESS + 18;
|
||
signal PWM_TIMING_UPPER : integer := PWM_BASE_ADDRESS + 19;
|
||
signal PWM_CMD_LOWER : integer := PWM_BASE_ADDRESS + 20;
|
||
signal PWM_CMD_UPPER : integer := PWM_BASE_ADDRESS + 21;
|
||
signal PWM_CONTROL_LOWER : integer := PWM_BASE_ADDRESS + 22;
|
||
signal PWM_CONTROL_UPPER : integer := PWM_BASE_ADDRESS + 23;
|
||
|
||
signal modeBuf : std_logic_vector(15 downto 0) := (others => '0');
|
||
signal maskBuf : std_logic_vector(31 downto 0) := (others => '1');
|
||
signal directControlBuf : std_logic_vector(31 downto 0) := (others => '1');
|
||
signal periodBuf : std_logic_vector(15 downto 0) := (others => '0');
|
||
signal directionBuf : std_logic_vector(31 downto 0) := (others => '0');
|
||
signal channelBuf : std_logic_vector(15 downto 0) := (others => '0');
|
||
signal cmdBuf : std_logic_vector(15 downto 0) := (others => '0');
|
||
signal controlBuf : std_logic_vector(15 downto 0) := (others => '0');
|
||
|
||
signal tkBuf : std_logic_vector(31 downto 0) := (others => '1');
|
||
|
||
type mem is array (31 downto 0) of std_logic_vector(15 downto 0);
|
||
signal memory : mem;
|
||
signal memoryBuf : mem;
|
||
|
||
signal pwm3level : std_logic_vector(31 downto 0) := (others => '1');
|
||
signal upDown : std_logic := '0';
|
||
signal upDownPrev : std_logic := '0';
|
||
signal interruptBuf : std_logic := '0';
|
||
signal period : std_logic_vector(15 downto 0) := (others => '0');
|
||
signal counter : std_logic_vector(15 downto 0) := (others => '0');
|
||
|
||
signal enableWriteControlBuf : std_logic := '1';
|
||
|
||
begin
|
||
|
||
process (we, oe, ce)
|
||
variable addr : integer range 0 to 2**ADDRESS_BUS_WIDTH - 1 := 0;
|
||
begin
|
||
if (ce = '0') then -- Если микросхема выбрана
|
||
addr := conv_integer(address);
|
||
if (addr = PWM_MODE_CONTROL_UPPER or addr = PWM_MODE_CONTROL_LOWER
|
||
or addr = PWM_MASK_2_UPPER or addr = PWM_MASK_2_LOWER or addr = PWM_MASK_1_UPPER or addr = PWM_MASK_1_LOWER
|
||
or addr = PWM_DIRECT_CONTROL_2_UPPER or addr = PWM_DIRECT_CONTROL_2_LOWER or addr = PWM_DIRECT_CONTROL_1_UPPER or addr = PWM_DIRECT_CONTROL_1_LOWER
|
||
or addr = PWM_PERIOD_UPPER or addr = PWM_PERIOD_LOWER
|
||
or addr = PWM_DIRECTION_2_UPPER or addr = PWM_DIRECTION_2_LOWER or addr = PWM_DIRECTION_1_UPPER or addr = PWM_DIRECTION_1_LOWER
|
||
or addr = PWM_CHANNEL_UPPER or addr = PWM_CHANNEL_LOWER or addr = PWM_TIMING_UPPER or addr = PWM_TIMING_LOWER
|
||
or addr = PWM_CMD_UPPER or addr = PWM_CMD_LOWER or addr = PWM_CONTROL_UPPER or addr = PWM_CONTROL_LOWER) then
|
||
if (oe = '0' and we = '1') then -- Если сигнал чтения активен, а записи нет
|
||
case addr is
|
||
when PWM_MODE_CONTROL_UPPER =>
|
||
data <= modeBuf(15 downto 8);
|
||
when PWM_MODE_CONTROL_LOWER =>
|
||
data <= modeBuf(7 downto 0);
|
||
when PWM_MASK_2_UPPER =>
|
||
data <= maskBuf(31 downto 24);
|
||
when PWM_MASK_2_LOWER =>
|
||
data <= maskBuf(23 downto 16);
|
||
when PWM_MASK_1_UPPER =>
|
||
data <= maskBuf(15 downto 8);
|
||
when PWM_MASK_1_LOWER =>
|
||
data <= maskBuf(7 downto 0);
|
||
when PWM_DIRECT_CONTROL_2_UPPER =>
|
||
data <= directControlBuf(31 downto 24);
|
||
when PWM_DIRECT_CONTROL_2_LOWER =>
|
||
data <= directControlBuf(23 downto 16);
|
||
when PWM_DIRECT_CONTROL_1_UPPER =>
|
||
data <= directControlBuf(15 downto 8);
|
||
when PWM_DIRECT_CONTROL_1_LOWER =>
|
||
data <= directControlBuf(7 downto 0);
|
||
when PWM_PERIOD_UPPER =>
|
||
data <= periodBuf(15 downto 8);
|
||
when PWM_PERIOD_LOWER =>
|
||
data <= periodBuf(7 downto 0);
|
||
when PWM_DIRECTION_2_UPPER =>
|
||
data <= directionBuf(31 downto 24);
|
||
when PWM_DIRECTION_2_LOWER =>
|
||
data <= directionBuf(23 downto 16);
|
||
when PWM_DIRECTION_1_UPPER =>
|
||
data <= directionBuf(15 downto 8);
|
||
when PWM_DIRECTION_1_LOWER =>
|
||
data <= directionBuf(7 downto 0);
|
||
when PWM_CHANNEL_UPPER =>
|
||
data <= channelBuf(15 downto 8);
|
||
when PWM_CHANNEL_LOWER =>
|
||
data <= channelBuf(7 downto 0);
|
||
when PWM_TIMING_UPPER =>
|
||
data <= memory(conv_integer(channelBuf))(15 downto 8);
|
||
when PWM_TIMING_LOWER =>
|
||
data <= memory(conv_integer(channelBuf))(7 downto 0);
|
||
when PWM_CMD_UPPER =>
|
||
data <= cmdBuf(15 downto 8);
|
||
when PWM_CMD_LOWER =>
|
||
data <= cmdBuf(7 downto 0);
|
||
when PWM_CONTROL_UPPER =>
|
||
data <= controlBuf(15 downto 8);
|
||
when PWM_CONTROL_LOWER =>
|
||
data <= controlBuf(7 downto 0);
|
||
when others =>
|
||
data <= (others => 'Z'); -- Запретить запись на шину
|
||
end case;
|
||
|
||
if addr /= PWM_CONTROL_LOWER then
|
||
enableWriteControlBuf <= '1';
|
||
else
|
||
enableWriteControlBuf <= '0';
|
||
end if;
|
||
elsif (oe = '1' and we = '0') then -- Если сигнал записи активен, а чтения нет
|
||
case addr is
|
||
when PWM_MODE_CONTROL_UPPER =>
|
||
modeBuf(15 downto 8) <= data;
|
||
when PWM_MODE_CONTROL_LOWER =>
|
||
modeBuf(7 downto 0) <= data;
|
||
when PWM_MASK_2_UPPER =>
|
||
maskBuf(31 downto 24) <= data;
|
||
when PWM_MASK_2_LOWER =>
|
||
maskBuf(23 downto 16) <= data;
|
||
when PWM_MASK_1_UPPER =>
|
||
maskBuf(15 downto 8) <= data;
|
||
when PWM_MASK_1_LOWER =>
|
||
maskBuf(7 downto 0) <= data;
|
||
when PWM_DIRECT_CONTROL_2_UPPER =>
|
||
directControlBuf(31 downto 24) <= data;
|
||
when PWM_DIRECT_CONTROL_2_LOWER =>
|
||
directControlBuf(23 downto 16) <= data;
|
||
when PWM_DIRECT_CONTROL_1_UPPER =>
|
||
directControlBuf(15 downto 8) <= data;
|
||
when PWM_DIRECT_CONTROL_1_LOWER =>
|
||
directControlBuf(7 downto 0) <= data;
|
||
when PWM_PERIOD_UPPER =>
|
||
periodBuf(15 downto 8) <= data;
|
||
when PWM_PERIOD_LOWER =>
|
||
periodBuf(7 downto 0) <= data;
|
||
when PWM_DIRECTION_2_UPPER =>
|
||
directionBuf(31 downto 24) <= data;
|
||
when PWM_DIRECTION_2_LOWER =>
|
||
directionBuf(23 downto 16) <= data;
|
||
when PWM_DIRECTION_1_UPPER =>
|
||
directionBuf(15 downto 8) <= data;
|
||
when PWM_DIRECTION_1_LOWER =>
|
||
directionBuf(7 downto 0) <= data;
|
||
when PWM_CHANNEL_UPPER =>
|
||
channelBuf(15 downto 8) <= data;
|
||
when PWM_CHANNEL_LOWER =>
|
||
channelBuf(7 downto 0) <= data;
|
||
when PWM_TIMING_UPPER =>
|
||
memory(conv_integer(channelBuf))(15 downto 8) <= data;
|
||
when PWM_TIMING_LOWER =>
|
||
memory(conv_integer(channelBuf))(7 downto 0) <= data;
|
||
when PWM_CMD_UPPER =>
|
||
cmdBuf(15 downto 8) <= data;
|
||
when PWM_CMD_LOWER =>
|
||
cmdBuf(7 downto 0) <= data;
|
||
-- when PWM_CONTROL_UPPER =>
|
||
-- controlBuf(15 downto 8) <= data;
|
||
-- when PWM_CONTROL_LOWER =>
|
||
-- controlBuf(7 downto 0) <= data;
|
||
when others =>
|
||
data <= (others => 'Z'); -- Запретить запись на шину
|
||
end case;
|
||
else
|
||
data <= (others => 'Z'); -- Запретить запись на шину
|
||
end if;
|
||
else
|
||
data <= (others => 'Z'); -- Запретить запись на шину
|
||
end if;
|
||
else
|
||
data <= (others => 'Z'); -- Запретить запись на шину
|
||
end if;
|
||
end process;
|
||
|
||
process(clk) is
|
||
begin
|
||
if rising_edge(clk) then
|
||
if upDown = '0' then
|
||
if conv_integer(counter) < conv_integer(period) then
|
||
counter <= counter + 1;
|
||
else
|
||
counter <= period;
|
||
updown <= '1';
|
||
end if;
|
||
else
|
||
if conv_integer(counter) > 0 then
|
||
counter <= counter - 1;
|
||
else
|
||
counter <= (others => '0');
|
||
upDown <= '0';
|
||
end if;
|
||
end if;
|
||
upDownPrev <= upDown;
|
||
end if;
|
||
end process;
|
||
|
||
process(clk) is
|
||
variable count : integer range 0 to 7 := 0;
|
||
begin
|
||
if rising_edge(clk) then
|
||
if upDown /= upDownPrev then
|
||
count := 0;
|
||
if cmdBuf(14) = '0' then
|
||
interrupt <= '1';
|
||
else
|
||
if updown = '0' then
|
||
interrupt <= '1';
|
||
interruptBuf <= '1';
|
||
period <= periodBuf; -- новый период грузится сразу во время начала подъема пилы
|
||
end if;
|
||
end if;
|
||
else
|
||
if count < 7 then
|
||
count := count + 1;
|
||
else
|
||
interrupt <= '0';
|
||
interruptBuf <= '0';
|
||
end if;
|
||
end if;
|
||
end if;
|
||
end process;
|
||
|
||
process(interruptBuf) is
|
||
begin
|
||
if interruptBuf = '0' then
|
||
for i in 0 to 31 loop
|
||
memoryBuf(i) <= memory(i); -- а вот новые значения таймингов загрузяться только после счетчика. Но зато могут грузиться дважды за период, если выбран соответствующий тип формирования прерывания
|
||
end loop;
|
||
end if;
|
||
end process;
|
||
|
||
process(clk) is
|
||
begin
|
||
if rising_edge(clk) then
|
||
for i in 0 to 11 loop
|
||
if(conv_integer(memoryBuf(i)) > counter) then
|
||
if(directionBuf(i) = '0') then
|
||
pwm3level(i) <= '0';
|
||
else
|
||
pwm3level(i) <= '1';
|
||
end if;
|
||
else
|
||
if(directionBuf(i) = '0') then
|
||
pwm3level(i) <= '1';
|
||
else
|
||
pwm3level(i) <= '0';
|
||
end if;
|
||
end if;
|
||
end loop;
|
||
|
||
for i in 12 to 15 loop
|
||
if(conv_integer(memoryBuf(i)) > counter) then
|
||
pwm3level(i) <= '0';
|
||
else
|
||
pwm3level(i) <= '1';
|
||
end if;
|
||
end loop;
|
||
|
||
for i in 16 to 27 loop
|
||
if(conv_integer(memoryBuf(i)) > counter) then
|
||
if(directionBuf(i) = '0') then
|
||
pwm3level(i) <= '0';
|
||
else
|
||
pwm3level(i) <= '1';
|
||
end if;
|
||
else
|
||
if(directionBuf(i) = '0') then
|
||
pwm3level(i) <= '1';
|
||
else
|
||
pwm3level(i) <= '0';
|
||
end if;
|
||
end if;
|
||
end loop;
|
||
|
||
for i in 28 to 31 loop
|
||
if(conv_integer(memoryBuf(i)) > counter) then
|
||
pwm3level(i) <= '0';
|
||
else
|
||
pwm3level(i) <= '1';
|
||
end if;
|
||
end loop;
|
||
end if;
|
||
end process;
|
||
|
||
process(clk) is
|
||
begin
|
||
if rising_edge(clk) then
|
||
case modeBuf is
|
||
when x"0000" =>
|
||
tkBuf <= pwm3level;
|
||
when x"0001" =>
|
||
tkBuf <= (others => '1');
|
||
tkBuf(5 downto 0) <= pwm;
|
||
when x"0002" =>
|
||
tkBuf <= pwm3level;
|
||
when x"0003" =>
|
||
tkBuf <= directControlBuf;
|
||
when others =>
|
||
tkBuf <= (others => '1');
|
||
end case;
|
||
end if;
|
||
end process;
|
||
|
||
process(clk) is
|
||
begin
|
||
if rising_edge(clk) then
|
||
if cmdBuf(15) = '1' and error = '1' then
|
||
tk <= tkBuf or maskBuf;
|
||
else
|
||
tk <= (others => '1');
|
||
end if;
|
||
end if;
|
||
end process;
|
||
|
||
process(clk) is
|
||
begin
|
||
if rising_edge(clk) then
|
||
if enableWriteControlBuf = '1' then
|
||
controlBuf <= counter;
|
||
end if;
|
||
end if;
|
||
end process;
|
||
|
||
|
||
end behavorial; |