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;