2024-04-01 18:52:02 +03:00
library ieee ;
use ieee.std_logic_1164. all ;
use ieee.std_logic_arith. all ;
use ieee.std_logic_unsigned. all ;
2024-03-28 18:35:51 +03:00
entity RAM9X8_PWM is
generic (
REG_ADDR_MODE_CONTROL_UPPER_BYTE : integer : = 14 ;
REG_ADDR_MODE_CONTROL_LOWER_BYTE : integer : = 15 ;
REG_ADDR_MASK_2_UPPER_BYTE : integer : = 16 ;
REG_ADDR_MASK_2_LOWER_BYTE : integer : = 17 ;
REG_ADDR_MASK_1_UPPER_BYTE : integer : = 18 ;
REG_ADDR_MASK_1_LOWER_BYTE : integer : = 19 ;
REG_ADDR_DIRECT_CONTROL_2_UPPER_BYTE : integer : = 20 ;
REG_ADDR_DIRECT_CONTROL_2_LOWER_BYTE : integer : = 21 ;
REG_ADDR_DIRECT_CONTROL_1_UPPER_BYTE : integer : = 22 ;
REG_ADDR_DIRECT_CONTROL_1_LOWER_BYTE : integer : = 23 ;
REG_ADDR_PERIOD_UPPER_BYTE : integer : = 24 ;
REG_ADDR_PERIOD_LOWER_BYTE : integer : = 25 ;
2024-04-01 18:52:02 +03:00
REG_ADDR_DIRECTION_2_UPPER_BYTE : integer : = 26 ;
REG_ADDR_DIRECTION_2_LOWER_BYTE : integer : = 27 ;
REG_ADDR_DIRECTION_1_UPPER_BYTE : integer : = 28 ;
REG_ADDR_DIRECTION_1_LOWER_BYTE : integer : = 29 ;
REG_ADDR_CHANNEL_UPPER_BYTE : integer : = 30 ;
REG_ADDR_CHANNEL_LOWER_BYTE : integer : = 31 ;
REG_ADDR_TIMING_UPPER_BYTE : integer : = 32 ;
REG_ADDR_TIMING_LOWER_BYTE : integer : = 33 ;
REG_ADDR_CMD_UPPER_BYTE : integer : = 34 ;
REG_ADDR_CMD_LOWER_BYTE : integer : = 35 ;
REG_ADDR_CONTROL_UPPER_BYTE : integer : = 36 ;
REG_ADDR_CONTROL_LOWER_BYTE : integer : = 37 ;
2024-03-28 18:35:51 +03:00
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' ;
2024-04-01 18:52:02 +03:00
pwm : in std_logic_vector ( 5 downto 0 ) ;
error : in std_logic
2024-03-28 18:35:51 +03:00
) ;
end entity ;
architecture behavorial of RAM9X8_PWM is
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' ) ;
2024-04-01 18:52:02 +03:00
signal directionBuf : std_logic_vector ( 31 downto 0 ) : = ( others = > '0' ) ;
2024-03-28 18:35:51 +03:00
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' ) ;
2024-04-01 18:52:02 +03:00
signal tkBuf : std_logic_vector ( 31 downto 0 ) : = ( others = > '1' ) ;
type mem is array ( 31 downto 0 ) of std_logic_vector ( 15 downto 0 ) ;
2024-03-28 18:35:51 +03:00
signal memory : mem ;
2024-04-01 18:52:02 +03:00
signal memoryBuf : mem ;
2024-03-28 18:35:51 +03:00
2024-04-01 18:52:02 +03:00
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' ;
2024-03-28 18:35:51 +03:00
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 = REG_ADDR_MODE_CONTROL_UPPER_BYTE or addr = REG_ADDR_MODE_CONTROL_LOWER_BYTE
or addr = REG_ADDR_MASK_2_UPPER_BYTE or addr = REG_ADDR_MASK_2_LOWER_BYTE or addr = REG_ADDR_MASK_1_UPPER_BYTE or addr = REG_ADDR_MASK_1_LOWER_BYTE
or addr = REG_ADDR_DIRECT_CONTROL_2_UPPER_BYTE or addr = REG_ADDR_DIRECT_CONTROL_2_LOWER_BYTE or addr = REG_ADDR_DIRECT_CONTROL_1_UPPER_BYTE or addr = REG_ADDR_DIRECT_CONTROL_1_LOWER_BYTE
2024-04-01 18:52:02 +03:00
or addr = REG_ADDR_PERIOD_UPPER_BYTE or addr = REG_ADDR_PERIOD_LOWER_BYTE
or addr = REG_ADDR_DIRECTION_2_UPPER_BYTE or addr = REG_ADDR_DIRECTION_2_LOWER_BYTE or addr = REG_ADDR_DIRECTION_1_UPPER_BYTE or addr = REG_ADDR_DIRECTION_1_LOWER_BYTE
2024-03-28 18:35:51 +03:00
or addr = REG_ADDR_CHANNEL_UPPER_BYTE or addr = REG_ADDR_CHANNEL_LOWER_BYTE or addr = REG_ADDR_TIMING_UPPER_BYTE or addr = REG_ADDR_TIMING_LOWER_BYTE
or addr = REG_ADDR_CMD_UPPER_BYTE or addr = REG_ADDR_CMD_LOWER_BYTE or addr = REG_ADDR_CONTROL_UPPER_BYTE or addr = REG_ADDR_CONTROL_LOWER_BYTE ) then
if ( oe = '0' and we = '1' ) then -- Если сигнал чтения активен, а записи нет
case addr is
when REG_ADDR_MODE_CONTROL_UPPER_BYTE = >
data < = modeBuf ( 15 downto 8 ) ;
when REG_ADDR_MODE_CONTROL_LOWER_BYTE = >
data < = modeBuf ( 7 downto 0 ) ;
when REG_ADDR_MASK_2_UPPER_BYTE = >
data < = maskBuf ( 31 downto 24 ) ;
when REG_ADDR_MASK_2_LOWER_BYTE = >
data < = maskBuf ( 23 downto 16 ) ;
when REG_ADDR_MASK_1_UPPER_BYTE = >
data < = maskBuf ( 15 downto 8 ) ;
when REG_ADDR_MASK_1_LOWER_BYTE = >
data < = maskBuf ( 7 downto 0 ) ;
when REG_ADDR_DIRECT_CONTROL_2_UPPER_BYTE = >
data < = directControlBuf ( 31 downto 24 ) ;
when REG_ADDR_DIRECT_CONTROL_2_LOWER_BYTE = >
data < = directControlBuf ( 23 downto 16 ) ;
when REG_ADDR_DIRECT_CONTROL_1_UPPER_BYTE = >
data < = directControlBuf ( 15 downto 8 ) ;
when REG_ADDR_DIRECT_CONTROL_1_LOWER_BYTE = >
data < = directControlBuf ( 7 downto 0 ) ;
when REG_ADDR_PERIOD_UPPER_BYTE = >
data < = periodBuf ( 15 downto 8 ) ;
when REG_ADDR_PERIOD_LOWER_BYTE = >
data < = periodBuf ( 7 downto 0 ) ;
2024-04-01 18:52:02 +03:00
when REG_ADDR_DIRECTION_2_UPPER_BYTE = >
data < = directionBuf ( 31 downto 24 ) ;
when REG_ADDR_DIRECTION_2_LOWER_BYTE = >
data < = directionBuf ( 23 downto 16 ) ;
when REG_ADDR_DIRECTION_1_UPPER_BYTE = >
2024-03-28 18:35:51 +03:00
data < = directionBuf ( 15 downto 8 ) ;
2024-04-01 18:52:02 +03:00
when REG_ADDR_DIRECTION_1_LOWER_BYTE = >
2024-03-28 18:35:51 +03:00
data < = directionBuf ( 7 downto 0 ) ;
when REG_ADDR_CHANNEL_UPPER_BYTE = >
data < = channelBuf ( 15 downto 8 ) ;
when REG_ADDR_CHANNEL_LOWER_BYTE = >
data < = channelBuf ( 7 downto 0 ) ;
when REG_ADDR_TIMING_UPPER_BYTE = >
2024-04-01 18:52:02 +03:00
data < = memory ( conv_integer ( channelBuf ) ) ( 15 downto 8 ) ;
2024-03-28 18:35:51 +03:00
when REG_ADDR_TIMING_LOWER_BYTE = >
2024-04-01 18:52:02 +03:00
data < = memory ( conv_integer ( channelBuf ) ) ( 7 downto 0 ) ;
2024-03-28 18:35:51 +03:00
when REG_ADDR_CMD_UPPER_BYTE = >
data < = cmdBuf ( 15 downto 8 ) ;
when REG_ADDR_CMD_LOWER_BYTE = >
data < = cmdBuf ( 7 downto 0 ) ;
when REG_ADDR_CONTROL_UPPER_BYTE = >
2024-04-01 18:52:02 +03:00
data < = controlBuf ( 15 downto 8 ) ;
2024-03-28 18:35:51 +03:00
when REG_ADDR_CONTROL_LOWER_BYTE = >
2024-04-01 18:52:02 +03:00
data < = controlBuf ( 7 downto 0 ) ;
2024-03-28 18:35:51 +03:00
when others = >
data < = ( others = > 'Z' ) ; -- Запретить запись на шину
2024-04-01 18:52:02 +03:00
end case ;
if addr / = REG_ADDR_CONTROL_UPPER_BYTE then
enableWriteControlBuf < = '1' ;
else
enableWriteControlBuf < = '0' ;
end if ;
2024-03-28 18:35:51 +03:00
elsif ( oe = '1' and we = '0' ) then -- Если сигнал записи активен, а чтения нет
case addr is
when REG_ADDR_MODE_CONTROL_UPPER_BYTE = >
modeBuf ( 15 downto 8 ) < = data ;
when REG_ADDR_MODE_CONTROL_LOWER_BYTE = >
modeBuf ( 7 downto 0 ) < = data ;
when REG_ADDR_MASK_2_UPPER_BYTE = >
maskBuf ( 31 downto 24 ) < = data ;
when REG_ADDR_MASK_2_LOWER_BYTE = >
maskBuf ( 23 downto 16 ) < = data ;
when REG_ADDR_MASK_1_UPPER_BYTE = >
maskBuf ( 15 downto 8 ) < = data ;
when REG_ADDR_MASK_1_LOWER_BYTE = >
maskBuf ( 7 downto 0 ) < = data ;
when REG_ADDR_DIRECT_CONTROL_2_UPPER_BYTE = >
directControlBuf ( 31 downto 24 ) < = data ;
when REG_ADDR_DIRECT_CONTROL_2_LOWER_BYTE = >
directControlBuf ( 23 downto 16 ) < = data ;
when REG_ADDR_DIRECT_CONTROL_1_UPPER_BYTE = >
directControlBuf ( 15 downto 8 ) < = data ;
when REG_ADDR_DIRECT_CONTROL_1_LOWER_BYTE = >
directControlBuf ( 7 downto 0 ) < = data ;
when REG_ADDR_PERIOD_UPPER_BYTE = >
periodBuf ( 15 downto 8 ) < = data ;
when REG_ADDR_PERIOD_LOWER_BYTE = >
periodBuf ( 7 downto 0 ) < = data ;
2024-04-01 18:52:02 +03:00
when REG_ADDR_DIRECTION_2_UPPER_BYTE = >
directionBuf ( 31 downto 24 ) < = data ;
when REG_ADDR_DIRECTION_2_LOWER_BYTE = >
directionBuf ( 23 downto 16 ) < = data ;
when REG_ADDR_DIRECTION_1_UPPER_BYTE = >
2024-03-28 18:35:51 +03:00
directionBuf ( 15 downto 8 ) < = data ;
2024-04-01 18:52:02 +03:00
when REG_ADDR_DIRECTION_1_LOWER_BYTE = >
2024-03-28 18:35:51 +03:00
directionBuf ( 7 downto 0 ) < = data ;
when REG_ADDR_CHANNEL_UPPER_BYTE = >
channelBuf ( 15 downto 8 ) < = data ;
when REG_ADDR_CHANNEL_LOWER_BYTE = >
channelBuf ( 7 downto 0 ) < = data ;
when REG_ADDR_TIMING_UPPER_BYTE = >
2024-04-01 18:52:02 +03:00
memory ( conv_integer ( channelBuf ) ) ( 15 downto 8 ) < = data ;
2024-03-28 18:35:51 +03:00
when REG_ADDR_TIMING_LOWER_BYTE = >
2024-04-01 18:52:02 +03:00
memory ( conv_integer ( channelBuf ) ) ( 7 downto 0 ) < = data ;
2024-03-28 18:35:51 +03:00
when REG_ADDR_CMD_UPPER_BYTE = >
cmdBuf ( 15 downto 8 ) < = data ;
when REG_ADDR_CMD_LOWER_BYTE = >
cmdBuf ( 7 downto 0 ) < = data ;
2024-04-01 18:52:02 +03:00
-- when REG_ADDR_CONTROL_UPPER_BYTE =>
-- controlBuf(15 downto 8) <= data;
-- when REG_ADDR_CONTROL_LOWER_BYTE =>
-- controlBuf(7 downto 0) <= data;
2024-03-28 18:35:51 +03:00
when others = >
data < = ( others = > 'Z' ) ; -- Запретить запись на шину
end case ;
else
data < = ( others = > 'Z' ) ; -- Запретить запись на шину
2024-04-01 18:52:02 +03:00
end if ;
2024-03-28 18:35:51 +03:00
else
data < = ( others = > 'Z' ) ; -- Запретить запись на шину
end if ;
else
data < = ( others = > 'Z' ) ; -- Запретить запись на шину
end if ;
end process ;
process ( clk ) is
begin
2024-04-01 18:52:02 +03:00
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' ;
2024-03-28 18:35:51 +03:00
else
2024-04-01 18:52:02 +03:00
if updown = '0' then
interrupt < = '1' ;
interruptBuf < = '1' ;
period < = periodBuf ; -- новый период грузится сразу во время начала подъема пилы
end if ;
2024-03-28 18:35:51 +03:00
end if ;
else
2024-04-01 18:52:02 +03:00
if count < 7 then
count : = count + 1 ;
2024-03-28 18:35:51 +03:00
else
2024-04-01 18:52:02 +03:00
interrupt < = '0' ;
interruptBuf < = '0' ;
2024-03-28 18:35:51 +03:00
end if ;
2024-04-01 18:52:02 +03:00
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 ;
2024-03-28 18:35:51 +03:00
2024-04-01 18:52:02 +03:00
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 ;
2024-03-28 18:35:51 +03:00
2024-04-01 18:52:02 +03:00
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 ;
2024-03-28 18:35:51 +03:00
end behavorial ;