Worldmaster 0 29 февраля Опубликовано 29 февраля · Жалоба В 29.02.2024 в 15:38, _4afc_ сказал: Вот так выглядит написанное Вами текстовое описания аппаратуры. Покажите пожалуйста хороший вариант? У меня в архитектуре несколько процессов которые заведуют разными вещами. То есть логичнее каждый процесс вытащить в отдельный entity/module так чтоли?? Тогда на диаграмме будут модули блоками показаны или это не принципиально? В 29.02.2024 в 15:38, _4afc_ сказал: //исходные LUT8+LUT8+LUT8+R = 1.627+1.627+1.627+0.380=5.261nS - 1 такт 190МГц always @( posedge C ) if( CE & A[3:0] & B[1:0] & Z[13:0]) Q<=X; А почему тут именно LUT8?? Как я понимаю: CE & A[3:0] = на вход подаем CE и A[3:0] то есть 5 сигналов. значит используем LUT5?? & B[1:0] = один выход с первого условия и 2 сигнала отсюда = LUT4 & Z[13:0] = один с предыдущего и 14 тут = LUT8*2 Q<=X; = R тогда LUT5 + LUT4 + ( LUT8*2 ) + R. Правильно или нет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Yuri124 1 29 февраля Опубликовано 29 февраля · Жалоба On 2/29/2024 at 3:50 PM, Worldmaster said: CE & A[3:0] = на вход подаем CE и A[3:0] то есть 5 сигналов. значит используем LUT5?? & B[1:0] = один выход с первого условия и 2 сигнала отсюда = LUT4 А можно и по-другому CE & A[3:0]& B[1:0] в один LUT, например... Ну и - я не в курсе, как там ресурсы распределены физически в кристалле, синтезатор сам должен оптимизировать исходя из заданных условий оптимизации (скорость или размер, к примеру). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 29 февраля Опубликовано 29 февраля · Жалоба 1 hour ago, Worldmaster said: Что значит умирают? https://nandland.com/variables-vs-signals/ variable не будут видны в другом процессе если нужен фифо опишите его отдельно - разбейте Вашу логику на более простые и понятные модули Двухклоковый фифо я выкладывал... Посмотрите как переходите через клоковые домены - правильно? sdc or xdc для логики написаны которая отвечает за коректный переход между клоковыми доменами Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 29 февраля Опубликовано 29 февраля · Жалоба 1 hour ago, Worldmaster said: У меня в архитектуре несколько процессов которые заведуют разными вещами. То есть логичнее каждый процесс вытащить в отдельный entity/module так чтоли?? Если будет отдельный модуль, а его выходы будут внутри подключены к регистрам - вы начнёте понимать как писать на ПЛИС. 1 hour ago, Worldmaster said: Покажите пожалуйста хороший вариант? Например модуль останавливающий работу FSM на 600/3600/36000/900000 тактов займёт 36 регистров, 44 LUT, с максимальной частотой 306МГц и 2 уровнями логики для GW2A GW5A_ES и будет выглядеть так: Spoiler Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 29 февраля Опубликовано 29 февраля · Жалоба 25 minutes ago, _4afc_ said: Если будет отдельный модуль, а его выходы будут внутри подключены к регистрам - вы начнёте понимать как писать на ПЛИС. Например модуль останавливающий работу FSM на 600/3600/36000/900000 тактов например library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity PauseCounter is generic ( COUNT_WIDTH : integer := 16 ); port ( clk : in std_logic; rst : in std_logic; load : in std_logic; pause_value : in unsigned(COUNT_WIDTH - 1 downto 0); done : out std_logic ); end entity PauseCounter; architecture Behavioral of PauseCounter is signal count : unsigned(COUNT_WIDTH - 1 downto 0) := (others => '0'); signal counting : std_logic; signal shift_counting : std_logic; signal reg_strob : std_logic; signal reg_ready : std_logic; begin process (clk, rst) begin if rst = '1' then count <= (others => '0'); counting <= '0'; reg_ready <= '0'; shift_counting <= '0'; elsif rising_edge(clk) then shift_counting <= counting; if load = '1' then count <= pause_value; counting <= '1'; reg_ready <= '0'; elsif counting = '1' then if count = 0 then counting <= '0'; reg_ready <= '1'; count <= count; else count <= count - 1; reg_ready <= '0'; counting <= '1'; end if; end if; end if; end process; reg_strob <= shift_counting and not(counting); --done <= reg_ready; done <= reg_strob; end Behavioral; пример использования library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity spi_config is generic( N : integer := 24; -- number of bit to serialize CLK_DIV : integer := 1 ); -- input clock divider to generate output serial clock; o_sclk frequency = i_clk/(2*CLK_DIV) port ( clk : in std_logic; rst : in std_logic; start : in std_logic; ready : out std_logic; busy_spi : out std_logic; -- spi o_sclk : out std_logic; o_ss : out std_logic; o_mosi : out std_logic; i_miso : in std_logic ); end spi_config; architecture rtl of spi_config is COMPONENT power_on_start is Port ( clk : in std_logic; rst : in std_logic; start_up : out std_logic ); end COMPONENT; COMPONENT spi_controller is generic( N : integer := 24; -- number of bit to serialize CLK_DIV : integer := 1 ); -- input clock divider to generate output serial clock; o_sclk frequency = i_clk/(2*CLK_DIV) port ( i_clk : in std_logic; i_rstb : in std_logic; i_tx_start : in std_logic; -- start TX on serial line o_tx_end : out std_logic; -- TX data completed; o_data_parallel available i_data_parallel : in std_logic_vector(N-1 downto 0); -- data to sent o_data_parallel : out std_logic_vector(N-1 downto 0); -- received data o_sclk : out std_logic; o_ss : out std_logic; o_mosi : out std_logic; i_miso : in std_logic); end COMPONENT; COMPONENT PauseCounter is generic ( COUNT_WIDTH : integer := 16 ); port ( clk : in std_logic; rst : in std_logic; load : in std_logic; pause_value : in unsigned(COUNT_WIDTH - 1 downto 0); done : out std_logic ); end COMPONENT; type state_type is ( idle_st , pause_st , send_config_data , pause2_st, send_config_data2 ); -- Declare current and next state signals SIGNAL current_state, nxt_state : state_type; signal reg_tx_start : std_logic; signal reg_tx_end : std_logic; signal reg_indata_parallel : std_logic_vector(N-1 downto 0); signal reg_outndata_parallel : std_logic_vector(N-1 downto 0); signal reg_start_pause : std_logic; signal reg_end_pause : std_logic; signal reg_value_pause : unsigned(15 downto 0); signal reg_busy : std_logic; signal reg_start_up : std_logic; signal reg_start : std_logic; begin busy_spi <= reg_busy; reg_start <= reg_start_up or start; start_up_inst : power_on_start Port map( clk => clk, rst => rst, start_up => reg_start_up ); spi_controller_inst: spi_controller generic map( N => N, -- number of bit to serialize CLK_DIV => CLK_DIV -- input clock divider to generate output serial clock; o_sclk frequency = i_clk/(2*CLK_DIV) ) port map( i_clk => clk, i_rstb => not(rst), i_tx_start => reg_tx_start, -- start TX on serial line o_tx_end => reg_tx_end, -- TX data completed; o_data_parallel available i_data_parallel => reg_indata_parallel, -- data to sent o_data_parallel => reg_outndata_parallel, -- received data o_sclk => o_sclk, o_ss => o_ss, o_mosi => o_mosi, i_miso => o_mosi --i_miso ); PauseCounter_inst: PauseCounter generic map( COUNT_WIDTH => 16 ) port map( clk => clk, rst => rst, load => reg_start_pause, pause_value => reg_value_pause, done => reg_end_pause ); -------------------------------------------------------------------------- clocked_proc : PROCESS (all) -------------------------------------------------------------------------- BEGIN IF (rst = '1') THEN current_state <= idle_st; -- Default Reset Values reg_tx_start <= '0'; reg_indata_parallel <= (others => '0'); ready <= '0'; reg_start_pause <= '0'; reg_value_pause <= (others => '0'); reg_busy <= '0'; ELSIF (clk'EVENT AND clk = '1') THEN current_state <= nxt_state; -- Combined Actions CASE current_state IS WHEN idle_st => ready <= '0'; if reg_start = '1' THEN reg_start_pause <= '1'; reg_value_pause <= to_unsigned(CLK_DIV*2, reg_value_pause'length); else reg_start_pause <= '0'; --reg_indata_parallel <= (others => '0'); end if; WHEN pause_st => reg_start_pause <= '0'; if reg_end_pause = '1' THEN reg_tx_start <= '1'; reg_busy <= '1'; reg_indata_parallel <= '0' & "10" & "0000000010100" & "00000010"; -- R_W & W1_W0 & A12-A0 & D7-D0 -- Data can be sent in either MSB-first mode --std_logic_vector(to_unsigned(170, reg_indata_parallel'length)); else reg_tx_start <= '0'; reg_indata_parallel <= std_logic_vector(to_unsigned(0, reg_indata_parallel'length)); end if; WHEN send_config_data => reg_tx_start <= '0'; if reg_tx_end = '1' THEN reg_start_pause <= '1'; reg_value_pause <= to_unsigned(CLK_DIV*2, reg_value_pause'length); reg_indata_parallel <= std_logic_vector(to_unsigned(0, reg_indata_parallel'length)); else reg_start_pause <= '0'; end if; WHEN pause2_st => reg_start_pause <= '0'; if reg_end_pause = '1' THEN reg_tx_start <= '1'; reg_indata_parallel <= '0' & "10" & "1111111111111" & "00000001"; -- R_W & W1_W0 & A12-A0 & D7-D0 -- Data can be sent in either MSB-first mode --std_logic_vector(to_unsigned(85, reg_indata_parallel'length)); else reg_tx_start <= '0'; --reg_indata_parallel <= std_logic_vector(to_unsigned(0, reg_indata_parallel'length)); end if; WHEN send_config_data2 => reg_tx_start <= '0'; if reg_tx_end = '1' THEN ready <= '1'; reg_busy <= '0'; reg_indata_parallel <= std_logic_vector(to_unsigned(0, reg_indata_parallel'length)); else ready <= '0'; --reg_indata_parallel <= (others => '0'); end if; WHEN OTHERS => NULL; END CASE; END IF; END PROCESS clocked_proc; -------------------------------------------------------------------------- nextstate_proc : PROCESS ( all ) -------------------------------------------------------------------------- BEGIN CASE current_state IS WHEN idle_st => IF (reg_start = '1') THEN nxt_state <= pause_st; ELSE nxt_state <= idle_st; END IF; WHEN pause_st => if reg_end_pause = '1' THEN nxt_state <= send_config_data; else nxt_state <= pause_st; end if; WHEN send_config_data => if reg_tx_end = '1' THEN nxt_state <= pause2_st; else nxt_state <= send_config_data; end if; WHEN pause2_st => if reg_end_pause = '1' THEN nxt_state <= send_config_data2; else nxt_state <= pause2_st; end if; WHEN send_config_data2 => if reg_tx_end = '1' THEN nxt_state <= idle_st; else nxt_state <= send_config_data2; end if; WHEN OTHERS => nxt_state <= idle_st; END CASE; END PROCESS nextstate_proc; end rtl; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 29 февраля Опубликовано 29 февраля · Жалоба 32 minutes ago, Maverick_ said: например COUNT_WIDTH : integer := 16 Для 900000 вероятно 24 бита. Как ваш пример: выглядит в схематике любого IDE? сколько занимает Reg/LUT? сколько слоёв логики? на какой максимальной частоте может работать? В приведённом мной примере для решения задачи достаточно было 4 фиксированных варианта паузы, поэтому они задаются 2 битами, ваш более общий на любую величину. PS: Посмотрел ваш вариант, получилось: займёт 26 регистров, 54 LUT, с максимальной частотой 146МГц и 5 уровнями логики для GW5A_ES и будет выглядеть так: PauseCounter.pdf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 29 февраля Опубликовано 29 февраля · Жалоба если хотите увеличить частоту можно применить конвеерний счетчик - вместо встроенного в модуль PauseCounter сигнала count library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity PipelinedCounter is generic ( width_g: natural := 64; -- Must be divisible by parts_g. parts_g: natural := 4 ); port ( clk: in std_logic; rst: in std_logic; clear: in std_logic; enable: in std_logic; count: out std_logic_vector(width_g - 1 downto 0); tick: out std_logic ); end entity; architecture rtl of PipelinedCounter is constant part_width_c: natural := width_g / parts_g; signal almost_tick_r: std_logic_vector(parts_g - 1 downto 0); signal count_r: std_logic_vector(width_g - 1 downto 0); begin count <= count_r; process (all) variable part_v: unsigned(part_width_c - 1 downto 0); variable tick_v: std_logic; begin if rst = '1' then count_r <= (others => '0'); almost_tick_r <= (others => '0'); tick <= '0'; elsif rising_edge(clk) then tick_v := enable; for i in 0 to parts_g - 1 loop part_v := unsigned(count_r((i + 1) * part_width_c - 1 downto i * part_width_c)); if tick_v = '1' then -- Value is max - 1? if part_v = to_unsigned(2**part_width_c - 2, part_width_c) then almost_tick_r(i) <= '1'; else almost_tick_r(i) <= '0'; end if; part_v := part_v + 1; end if; count_r((i + 1) * part_width_c - 1 downto i * part_width_c) <= std_logic_vector(part_v); tick_v := tick_v and almost_tick_r(i); end loop; tick <= tick_v; if clear = '1' then count_r <= (others => '0'); almost_tick_r <= (others => '0'); tick <= '0'; end if; end if; end process; end architecture; он разбит по 4 бита 1 hour ago, _4afc_ said: Для 900000 вероятно 24 бита. Как ваш пример: выглядит в схематике любого IDE? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Worldmaster 0 1 марта Опубликовано 1 марта (изменено) · Жалоба В 29.02.2024 в 16:41, Maverick_ сказал: variable не будут видны в другом процессе А зачем мне видеть их в других процессах. Это локальные переменные можно сказать и используются только внутри одного процесса. В 29.02.2024 в 16:41, Maverick_ сказал: если нужен фифо опишите его отдельно Так и сделано. Есть модуль FIFO, SDRAM, i2c. Но в основной архитектуре добавились процессы которые координируют потоки данных между ними. Нужно и с камер снимать данные укладывая их в оперативу и если прилетел запрос с FIFO то отрабатывать его и одновременно выкидывать в него данные из оперативы, а еще не забыть i2c и с периферии снимать показания. Просто я так понял что вы склоняете к тому что все управляющие процессы вынести тоже в отдельные компоненты, тогда видимо и диаграмма будет более понятная. А потом просто связать сигналы всех этих блоков в топовой архитектуре. Так ведь? В 29.02.2024 в 16:41, Maverick_ сказал: Двухклоковый фифо я выкладывал... Я смотрел ваш пример но так и не нашел варианта как его встроить к себе. А возможно что у себя я и сделал нечто такое же. У меня есть процесс который закладывает данные в RAM по нужному адресу но когда приходит запрос с FIFO он производит передачу блоков из RAM в буфер отправки FIFO. Пока освобождается один буфер, процесс закидывает данные из камер в RAM, потом если буфер пуст то производит чтения из рамы. В 29.02.2024 в 16:55, _4afc_ сказал: Например модуль останавливающий работу FSM на 600/3600/36000/900000 тактов Линий маловато. А есть чтонибудь большое большое. Камеры например какие нибудь или что нибудь из периферии .. Мне кажется что тоже будет такая же каша на диаграмме как и у меня. ну либо с самого маленького кирпича собирать блоки, блоки объединять опять в блоки пока не получится один суперблок который в архитектуре будет просто соединять сигналы с железки и передавать их внутрь. Изменено 1 марта пользователем Worldmaster Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Worldmaster 0 1 марта Опубликовано 1 марта · Жалоба Ну и все равно не понятно что делать с коркой MIPI. component mipi_rx port ( reset_n: in std_logic; HS_CLK_P: in std_logic; HS_CLK_N: in std_logic; clk_byte_out: out std_logic; HS_DATA1_P: in std_logic; HS_DATA1_N: in std_logic; data_out1: out std_logic_vector(7 downto 0); HS_DATA0_P: in std_logic; HS_DATA0_N: in std_logic; data_out0: out std_logic_vector(7 downto 0); hs_en: in std_logic; clk_term_en: in std_logic; data_term_en: in std_logic; ready: out std_logic ); end component; MyMIPI1: mipi_rx port map ( reset_n => Mipi_Rst_N, HS_CLK_P => CAM1_CLK_P, HS_CLK_N => CAM1_CLK_N, HS_DATA1_P => CAM1_DATA_P, HS_DATA1_N => CAM1_DATA_N, HS_DATA0_P => CAM1_DATA_2_P, HS_DATA0_N => CAM1_DATA_2_N, ready => Cam1_Mipi_Ready, clk_byte_out => Cam1_Mipi_Data_Read_Clk, data_out1 => CAM1_MIPI_DATA_OUT1, data_out0 => CAM1_MIPI_DATA_OUT0, hs_en => Mipi_EN_N, clk_term_en => '1', data_term_en => '1' ); А процесс примитивный до нельзя. function rMod(value: integer; maxSize: integer) return integer is begin if value >= maxSize then return value - maxSize; else return value; end if; end function; Cam1_Read_Process: process (buffer_pointers_reset, Cam1_Mipi_Data_Read_Clk) begin if buffer_pointers_reset = '0' then cam1_write_ptr <= 0; elsif rising_edge(Cam1_Mipi_Data_Read_Clk) then cam1_data_buffer(cam1_write_ptr) <= Cam1_Mipi_Data_Out0 & Cam1_Mipi_Data_Out1; cam1_write_ptr <= rMod(cam1_write_ptr + 1, MAX_BUF_CNT); end if; end process Cam1_Read_Process; И все равно он показывает недобор частоты по CAM1_CLK. С этим то что делать? Почему корка такая медленная? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 1 марта Опубликовано 1 марта · Жалоба cam1_data_buffer - организация памяти какая - блочная память или регистровая или srl? как синтезатор реализовал? расскажите что физически процесс делает: Cam1_Read_Process: process (buffer_pointers_reset, Cam1_Mipi_Data_Read_Clk) begin if buffer_pointers_reset = '0' then cam1_write_ptr <= 0; elsif rising_edge(Cam1_Mipi_Data_Read_Clk) then cam1_data_buffer(cam1_write_ptr) <= Cam1_Mipi_Data_Out0 & Cam1_Mipi_Data_Out1; cam1_write_ptr <= rMod(cam1_write_ptr + 1, MAX_BUF_CNT); end if; end process Cam1_Read_Process; то что пишет и читает вижу, точно нужно одновременность? почему Вы не хотите написать подмодули с такторовой частатой clk и ресетом rst в топ модуле соеденить все модули подав нужные частоты от PLL не хотите сделать память отдельным модулем: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use IEEE.NUMERIC_STD.ALL; entity bram_tdp is generic ( DATA : integer := 32; ADDR : integer := 12 ); port ( -- Port A a_clk : in std_logic; --ena : in std_logic; a_wr : in std_logic; a_addr : in std_logic_vector(ADDR-1 downto 0); a_din : in std_logic_vector(DATA-1 downto 0); a_dout : out std_logic_vector(DATA-1 downto 0); -- Port B b_clk : in std_logic; --enb : in std_logic; b_wr : in std_logic; b_addr : in std_logic_vector(ADDR-1 downto 0); b_din : in std_logic_vector(DATA-1 downto 0); b_dout : out std_logic_vector(DATA-1 downto 0) ); end bram_tdp; architecture rtl of bram_tdp is -- Shared memory type mem_type is array ( (2**ADDR)-1 downto 0 ) of std_logic_vector(DATA-1 downto 0); FUNCTION initialize_ram return mem_type is variable result : mem_type; BEGIN FOR i IN ((2**ADDR)-1) DOWNTO 0 LOOP result(i) := std_logic_vector( to_unsigned(natural(i), natural'((DATA)))); END LOOP; RETURN result; END initialize_ram; -- shared variable mem : mem_type := initialize_ram; shared variable mem : mem_type := (others => (others => '0')); -- := initialize_ram; begin -- Port A process(a_clk) begin if(a_clk'event and a_clk='1') then -- if ena = '1' then if(a_wr='1') then mem(conv_integer(a_addr)) := a_din; end if; a_dout <= mem(conv_integer(a_addr)); -- end if; end if; end process; -- Port B process(b_clk) begin if(b_clk'event and b_clk='1') then --- if enb = '1' then if(b_wr='1') then mem(conv_integer(b_addr)) := b_din; end if; b_dout <= mem(conv_integer(b_addr)); -- end if; end if; end process; end rtl; каждый подмодуль проверить на максимальную частоту (отдельный проект) - надо бы такое сделать и за одно посмотреть как синтезатор Вас понимает - блочная память, DSP - схемотехника по RTL просматровщику написать тестбенч - промоделировать - с коркой и без например MIPI Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Worldmaster 0 1 марта Опубликовано 1 марта (изменено) · Жалоба В 01.03.2024 в 10:23, Maverick_ сказал: как синтезатор реализовал? Если я правильно понял что вот так: constant MAX_BUF_CNT : integer :=128; type MEMBuffer is array (0 to MAX_BUF_CNT-1) of std_logic_vector(15 downto 0); signal cam1_data_buffer: MEMBuffer := (others=>(others=>'0')); Если надо по другому то покажите пожалуйста как. В 01.03.2024 в 10:23, Maverick_ сказал: расскажите что физически процесс делает: Камера подключена к линиям mipi_rx. Корка получает данные и преобразует их в байты. Когда они готовы генерит сигнал Cam1_Mipi_Data_Read_Clk и процесс объединяет два байта в один блок и пишет в буфер. В 01.03.2024 в 10:23, Maverick_ сказал: то что пишет и читает вижу, точно нужно одновременность? В чем одновременность? В 01.03.2024 в 10:23, Maverick_ сказал: почему Вы не хотите написать подмодули с такторовой частатой clk и ресетом rst в топ модуле соеденить все модули подав нужные частоты от PLL Ну в данном случае для сбора данных нужен был всего один процесс. Поэтому и не стал городить надстройку. Вы хотите сказать что если сделать отдельный модуль MIPI_CTRL и туда перенести этот процесс то это радикально изменит ситуацию? Для MIPI передачу данных определяет сама камера же. ЗАчем этому модулю еще какое то тактирование? Изменено 1 марта пользователем Worldmaster Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 1 марта Опубликовано 1 марта · Жалоба что значит "Когда они готовы генерит сигнал Cam1_Mipi_Data_Read_Clk " ? счетчики cam1_data_buffer(cam1_write_ptr) <= Cam1_Mipi_Data_Out0 & Cam1_Mipi_Data_Out1; cam1_write_ptr <= rMod(cam1_write_ptr + 1, MAX_BUF_CNT); работают паралельно т.е. одновременно - пишиут и читают из одной ячейки памяти, судя по Вашему процессу Тактовая частота на модулях должна быть постоянно - работает модуль в данный момент времени или нет определяет сигнал разрешения valid для данных или enable для модуля - например library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity modulo_cnt is port ( clk : in std_logic; rst : in std_logic; -- inputs max_cnt : in std_logic_vector; en : in std_logic; -- outputs zero : out std_logic ); end modulo_cnt; architecture rtl of modulo_cnt is -- normalize the unconstrained input alias max_cnt_norm : std_logic_vector(max_cnt'length - 1 downto 0) is max_cnt; -- normalized unconstrained input signal cnt : unsigned(max_cnt_norm'left downto 0); begin counter_pr : process (clk) begin if (rising_edge(clk)) then if (rst = '1') then cnt <= unsigned(max_cnt_norm) - 1; zero <= '0'; elsif (en = '1') then -- is counting enabled? if (cnt = 1) then -- use pipeline to assert zero zero <= '1'; -- together with cnt=0 else zero <= '0'; end if; if (zero = '1') then -- check if counter reached zero cnt <= unsigned(max_cnt_norm) - 1; -- reload with modulo_value-1 else cnt <= cnt - 1; -- decrement counter end if; end if; end if; end process counter_pr; end rtl; попробуйте промоделировать - разберитесь с enable для модуля valid/ready для данных модуль принимает данные по valid выдает модуль обработанные данные по сигналу ready Для следующего модуля ready превращается в сигнал valid промоделируйте двухклоковое фифо ... чаще всего FSM работает с сигналами valid/ready - т.е. дает разрешения работы или запрещает модуля или процесса Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 25 1 марта Опубликовано 1 марта · Жалоба 1 hour ago, Worldmaster said: Линий маловато. А есть чтонибудь большое большое. Камеры например какие нибудь или что нибудь из периферии .. Мне кажется что тоже будет такая же каша на диаграмме как и у меня. ну либо с самого маленького кирпича собирать блоки, блоки объединять опять в блоки пока не получится один суперблок который в архитектуре будет просто соединять сигналы с железки и передавать их внутрь. Да. Мне так удобнее. Написать универсальный (лучше параметризируемый) модуль с "always" внутри. Отсимулировать его во всех режимах. И далее использовать уже эту абстракцию в своих модулях. Практически мои проекты состоят из модулей состоящих из модулей которые состоят из модулей... Все модули содержат комментарий описывающий их назначение. Только самый нижний уровень, в моём идеале, содержит "always". Дело в том, что описание ПЛИС на Verilog отличается от программы на C++ под CPU. И основное отличие от CPU в том, что нельзя создать "глобальную переменную", которая будет менять своё значение от 5 разных подпрограмм. В ПЛИС все переменные (REG) каждый такт меняются одновременно в зависимости от локальных условий (LUT). Кратко: на заводе с менеджментом CPU - рабочему (АЛУ) постоянно поступают приказы от любого количества руководителей, причём устно, по громкой связи, на личный телефон, по мылу, телеге, видеосвязи... меняют приоритеты и прерывают работу новыми заданиями, на стол кто-то притаскивает болванки, ставит станки, забирает детали... на заводе с менеджментом ПЛИС - рабочий (REG) каждый такт смотрит в отрывной календарь (LUT), выполняет заданное там действие, передаёт результат далее по конвейеру в календари (LUT) других работников и свой на завтра, текущий лист отрывает и выбрасывает. Соответственно архитектурно просится описывать алгоритм как изменение конкретного REG от условий LUT находящегося в неком ограниченном по функционалу модуле (CLB). 1 hour ago, Worldmaster said: И все равно он показывает недобор частоты по CAM1_CLK. С этим то что делать? Если проект разбит на модули - вы можите посмотреть Fmax на любое кол-во конкретных подмодулей сразу в отчёте, добавив это требование в sdc файл мышкой или редактором. 38 minutes ago, Maverick_ said: каждый подмодуль проверить на максимальную частоту (отдельный проект) - необязательно, в GoWin можно посмотреть Fmax любого модуля и его детей и найти паршивую овцу портящую семью. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Worldmaster 0 1 марта Опубликовано 1 марта · Жалоба В 01.03.2024 в 10:48, Maverick_ сказал: что значит "Когда они готовы генерит сигнал Cam1_Mipi_Data_Read_Clk " ? Gowin MIPI D-PHY RX TX Advance.pdf Вот документ на корку. В 01.03.2024 в 10:48, Maverick_ сказал: работают паралельно т.е. одновременно - пишиут и читают из одной ячейки памяти, судя по Вашему процессу Это плохо?? Выше вроде по советам сделал что используется значение прошлой переменной а потом изменяется на новое. Так как правильно то?? То что вы привели модуль памяти по сути ведь тоже самое. Также использован logic_vector variable mem : mem_type := (others => (others => '0')); Просто дополнительно добавлена надстройка в виде модуля. Какое преимущество в этом? Вместо простого присвоения счетчика вы добавляете еще больше LUT и логики. Разве это должно работать быстрее? Но я тут проверил и даже если в Cam1_Read_Process будет только мигание светодиодом все равно частота выше 30 не поднимается. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 1 марта Опубликовано 1 марта · Жалоба variable mem : mem_type := (others => (others => '0')); у меня строка используется для инициализации памяти - после того как плис будет запрограммипрвана, что должно быть в памяти и все ... с коркой MIPI я бы работал через двухклоковое фифо 1 частота работы модуля чаще она будет высокой 2 частота MIPI И смотрел (на логике) за сигналами фифо full/empty - для старта можно вывел их на светодиоды/лог анализатор - убедиться что нет потерь данных возможно лучше сделал бы пакетное фифо - мое на форуме как пример Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться