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( 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; 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; 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 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 = 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 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 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); 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 => data <= directionBuf(15 downto 8); when REG_ADDR_DIRECTION_1_LOWER_BYTE => 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 => data <= memory(conv_integer(channelBuf))(15 downto 8); when REG_ADDR_TIMING_LOWER_BYTE => data <= memory(conv_integer(channelBuf))(7 downto 0); 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 => data <= controlBuf(15 downto 8); when REG_ADDR_CONTROL_LOWER_BYTE => data <= controlBuf(7 downto 0); when others => data <= (others => 'Z'); -- Запретить запись на шину end case; if addr /= REG_ADDR_CONTROL_UPPER_BYTE then enableWriteControlBuf <= '1'; else enableWriteControlBuf <= '0'; end if; 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; 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 => directionBuf(15 downto 8) <= data; when REG_ADDR_DIRECTION_1_LOWER_BYTE => 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 => memory(conv_integer(channelBuf))(15 downto 8) <= data; when REG_ADDR_TIMING_LOWER_BYTE => memory(conv_integer(channelBuf))(7 downto 0) <= data; when REG_ADDR_CMD_UPPER_BYTE => cmdBuf(15 downto 8) <= data; when REG_ADDR_CMD_LOWER_BYTE => cmdBuf(7 downto 0) <= data; -- when REG_ADDR_CONTROL_UPPER_BYTE => -- controlBuf(15 downto 8) <= data; -- when REG_ADDR_CONTROL_LOWER_BYTE => -- 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;