Jump to content

    

Создание энкодера для регистра сдвига

Здравствуйте, настал тут у меня момент отупения (всю неделю).

Нужно реализовать асинхронный энкодер для параметризируемого регистра сдвига. Нужно контролировать фронт сигнала - то есть перепад подряд идущих единиц, пока не встретится стабильный ноль.

Я написал такую функцию для преобразования входного потока, но она синтезируется в какую-то ерунду:

function logic my_encoder(
	input logic [6 : 0] i_encode
	);

casez (i_encode)				// приоритетный выбор "до первого ноля"
	7'b??????1: return 3'b000;
	7'b?????10: return 3'b001;
	7'b????100: return 3'b010;
	7'b???1000: return 3'b011;
	7'b??10000: return 3'b100;
	7'b?100000: return 3'b101;
	7'b1000000: return 3'b110;
	default:	return 3'b111;
endcase

Так как функции не параметризируются, а входной регистр может быть разной длинны, приходится по-рагульному встраивать в код:

parameter p_length = 3;				// анализ 3 бит данных
logic [3 : 0] r_data;				// иходной вектор
wire logic [1 : 0] r_data_encoded;	// выходные декодированные данные
assign {r_data_encoded} = my_encoder(r_data[p_length - 1 : 0]);

Приоритетный перебор "менял местами" - ничего не помогло (перечисление наоборот).

Подскажите возможное решение. А лучше почему данный Кейс финтезируется в какой-то бред (у меня всегда 1-й бит r_data_encoded подтянут на землю).

З.Ы. Так же пробовал абстрагироваться от остальных значений и детектировать только наиболее раннее значение фронта, результат таков же:

casez (i_encode)
	7'b??????1: return 3'b000;
	7'b?????10: return 3'b001;
	7'b????10?: return 3'b010;
	7'b???10??: return 3'b011;
	7'b??10???: return 3'b100;
	7'b?10????: return 3'b101;
	7'b10?????: return 3'b110;
	default:	return 3'b111;
endcase

 

Share this post


Link to post
Share on other sites
13 минут назад, Nick_K сказал:

Нужно контролировать фронт сигнала - то есть перепад подряд идущих единиц, пока не встретится стабильный ноль.

 

Делаем так. 

рисуем автомат, у которого две ветви. Одна из исходного влево - это если 0, другая - вправо,  это если 0. Тактируем все системными клоками, поскольку входные импульсы привязываем к ним на самом входе проекта. Чтобы не зависеть от частоты дребезга, даем еще сигнал "разрешения", который и определяет как часто будет срабатывать автомат... Ну и в каждой ветви делаем по 3-5 состояний. Скажем для ветви "0" - если 0, то переход в следующее, а если 1 - то в исходное... Получим фильтр дребезга по фронтам и по просечкам сигналов... Прохождение автомата по последнему состоянию в ветви и даст импульс длительностью в 1 клок, который может быть использован в более верхнем автомате....

Хотите подробнее - могу по скайпу голосом...

Share this post


Link to post
Share on other sites

Спасибо, как в схемотехнике это выглядит - я понимаю. Вопрос как это описать на умном SystemVerilog не используя кучу if-else. На VHDL знаю, а с SV достаточно недавно работаю

Share this post


Link to post
Share on other sites
2 минуты назад, Nick_K сказал:

Спасибо, как в схемотехнике это выглядит - я понимаю. Вопрос как это описать на умном SystemVerilog не используя кучу if-else. На VHDL знаю, а с SV достаточно недавно работаю

Как описать автомат? В этом проблема? И при чем тут именно SV? Регистровая часть автомата и комбинационная да еще таймер для выдержки времени... Дело то простейшее...

Share this post


Link to post
Share on other sites

Приветствую!

Для начала поставьте более конкретную задачу - какие комбинации вы хотите детектировать? Что считать фронтом в вашем понимании?  В широком регистре перепадов 1->0  может быть несколько -  нужны все или только первый? C какой стороны  регистра искать фронт? 

Ну а для "параметризация" функций с векторами можно пользоваться некими особенностями Verilog - автоматическим расширением/усечением разрядности при присвоении.  Например нахождение первой 1 справа

module test_1 (
  input  wire        clk  ,
  input  wire  [3:0] din_a,
  input  wire  [7:0] din_b,
  output logic [3:0] dou_a,
  output logic [4:0] dou_b
);

localparam MAX_POSSIBLE_WIDTH = 256;

function int first_one_from_right (input logic [MAX_POSSIBLE_WIDTH-1:0] din, int din_wh);
  for (int ii=0; ii<MAX_POSSIBLE_WIDTH; ++ii) begin
    if (din[ii]==1) begin
      return ii;
    end
  end
  return din_wh;
endfunction

always @(posedge clk) begin
  dou_a <= ($clog2($bits(din_a))+1)'(first_one_from_right(din_a, $bits(din_a)));
  dou_b <=                           first_one_from_right(din_b, $bits(din_b));
end
endmodule

Удачи! Rob. 

Share this post


Link to post
Share on other sites
44 minutes ago, RobFPGA said:

Для начала поставьте более конкретную задачу - какие комбинации вы хотите детектировать? 

Фронт в данной задаче - это когда слева единицы, а справа хотя бы один ноль. Что правее после ноля - не важно, для меня это дребезг, а если ноли слева от единиц - это обычная обрезка входного сигнала. К примеру:

00001111 - данных нет

00001110 - начало приёма

00001100 - продолжение

00001001 - дребезг

Если бы не необходимость отсеивания дребезга, то я бы просто сумму унарного кода вычислял. А так загвоздка.

За параметризацию входных сигналов я вкурсе, только мне это не сильно подходит, если говорить о функции case. Кстати было бы неплохо понять как параметризировать выходной сигнал (который после return), а также как передавать локальный параметр (или просто параметр) в пакет/package, т.к. функции обычно выношу в пакеты отдельные, для удобства редактирования.

Share this post


Link to post
Share on other sites

Приветствую!

Все одно не однозначные/неполные условия: 

  00001100 - продолжение

...

  00110011 - дребезг ?

  01100110 - Где фронт ? 

Увы - SV  язык с жесткой типизацией - требует чтобы типы  аргументов и возвращаемых значений были определённы на этапе компиляции.

Поэтому и приходится закладывать максимальные значения ширины векторов.

Ну или как вариант засунуть функции в interface :wink2:  Но это если синтезатор поддерживает такие извраты. 

interface if_func #(MAX_WH=8);

typedef logic       [MAX_WH-1:0] din_t;
typedef logic [$clog2(MAX_WH):0] dou_t;

  function dou_t first_one_from_rignt (input din_t din);
    for (int ii=0; ii<MAX_WH; ++ii) begin
      if (din[ii]==1) begin
        return ii;
      end
    end
    return MAX_WH;
  endfunction
    
endinterface
    
module ...

  if_func #(.MAX_WH($bits(din_a))) func_if_a ();
  if_func #(.MAX_WH($bits(din_b))) func_if_b ();
...
    dou_a <= func_if_a.first_one_from_rignt(din_a);
    dou_b <= func_if_b.first_one_from_rignt(din_b);
..

Удачи! Rob.

Share this post


Link to post
Share on other sites
17 hours ago, RobFPGA said:

00110011 - дребезг ? 

0011 - фронт, остальное мусор

 

17 hours ago, RobFPGA said:

01100110 - Где фронт ? 

011 - фронт

17 hours ago, RobFPGA said:

Увы - SV  язык с жесткой типизацией - требует чтобы типы  аргументов и возвращаемых значений были определённы на этапе компиляции.

Спасибо! именно это и навело меня на мысль/решение - я объявлял возвращаемое значение как logic без размеров. Поэтому у меня синтезировало только первый бит выходного значения. Поменял на logic [1:0] и пошло как тёща под лёд ... вобщем пошло :smile:

Share this post


Link to post
Share on other sites
On 7/25/2019 at 5:11 PM, Nick_K said:

...


wire logic [1 : 0] r_data_encoded;	// выходные декодированные данные
assign {r_data_encoded} = my_encoder(r_data[p_length - 1 : 0]);

...

почему данный Кейс финтезируется в какой-то бред (у меня всегда 1-й бит r_data_encoded подтянут на землю) ...

...


casez (i_encode)
	7'b??????1: return 3'b000;
	7'b?????10: return 3'b001;
	7'b????10?: return 3'b010;
	7'b???10??: return 3'b011;
	7'b??10???: return 3'b100;
	7'b?10????: return 3'b101;
	7'b10?????: return 3'b110;
	default:	return 3'b111;
endcase

 

Функция my_encode возвращает 3 битика (return 3'bXXX), а регистр, в который вы выкладываете этот результат (r_data_encoded) имеет разрядность [1:0] = 2 битика.

 

А если хочется параметризировать - над делать что-то вроде того, что показал @RobFPGA. Ну и все разрядности обязаны быть определены на этапе синтеза.

А еще, похоже, что вам просто надо посчитать количество нулей или единиц в слове - можно попробовать погуглить на эту тему, есть разные алгоритмы как для С так и для HDL.

Share this post


Link to post
Share on other sites
В 25.07.2019 в 13:11, Nick_K сказал:

Так как функции не параметризируются

Переходите на VHDL. Там с параметризацией никаких проблем.

Share this post


Link to post
Share on other sites
В 25.07.2019 в 14:48, Nick_K сказал:

Фронт в данной задаче - это когда слева единицы, а справа хотя бы один ноль. Что правее после ноля - не важно, для меня это дребезг, а если ноли слева от единиц - это обычная обрезка входного сигнала. К примеру:

00001111 - данных нет

00001110 - начало приёма

00001100 - продолжение

00001001 - дребезг

Если бы не необходимость отсеивания дребезга, то я бы просто сумму унарного кода вычислял. А так загвоздка.

За параметризацию входных сигналов я вкурсе, только мне это не сильно подходит, если говорить о функции case. Кстати было бы неплохо понять как параметризировать выходной сигнал (который после return), а также как передавать локальный параметр (или просто параметр) в пакет/package, т.к. функции обычно выношу в пакеты отдельные, для удобства редактирования.

На мой взгляд вы всё смешали в кучу. Мухи отдельно, котлеты отдельно - сначала удалите дребезг, а уж потом вылавливайте фронт.

Share this post


Link to post
Share on other sites
On 7/27/2019 at 7:00 AM, nice_vladi said:

Функция my_encode возвращает 3 битика (return 3'bXXX), а регистр, в который вы выкладываете этот результат (r_data_encoded) имеет разрядность [1:0] = 2 битика.

Я же написал уже, что проблема в объявлении функции:

function logic my_encoder(
	input logic [6 : 0] i_encode
	);

А должно быть:

function [2:0] logic my_encoder(
	input logic [6 : 0] i_encode
	);

тогда функция синтезирует правильную ширину выходного вектора на SV. В отличии от VHDL где как-раз размерность и нельзя указывать для функции.

On 7/27/2019 at 7:00 AM, nice_vladi said:

А еще, похоже, что вам просто надо посчитать количество нулей или единиц в слове - можно попробовать погуглить на эту тему, есть разные алгоритмы как для С так и для HDL.

Опять нет. Нужно к каждым двум битам сдвигового регистра прицепить XOR и повесить на чепочку мультиплексоров. Чтобы старший мультиплексор обрезал работу всем остальным. можно реализовать через приоритетный if-else но тогда это получится очень большой кусок кода, с 0 удобочитаемостью и реюзабелльностью. А так на Лутах обычный Энкодер вышел.

 

On 7/27/2019 at 7:20 AM, andrew_b said:

Переходите на VHDL. Там с параметризацией никаких проблем.

Я с него только слез :wink:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this