Перейти к содержанию
    

Добрый день.

Пытаюсь воспроизвести алгоритм Бута по примеру из Википедии https://ru.wikipedia.org/wiki/%D0%90%D0%BB%....B8.D1.82.D0.BC

На листе всё выходит нормально, при написании алгоритма на verilog получается не настолько точно.

Вот листинг кода http://pastebin.com/BgSTGGdC

Помогите разобраться с ошибкой, пожалуйста.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день.

Пытаюсь воспроизвести алгоритм Бута по примеру из Википедии https://ru.wikipedia.org/wiki/%D0%90%D0%BB%....B8.D1.82.D0.BC

На листе всё выходит нормально, при написании алгоритма на verilog получается не настолько точно.

Вот листинг кода http://pastebin.com/BgSTGGdC

Помогите разобраться с ошибкой, пожалуйста.

зачем? есть встроенные умножители, если нету (в современных плис это редкость), то синтезатор сам синтезирует умножитель ...

Вам достаточно написать а = в*с

 

 

PS думаю Вы плохо "просили" гугл Вам найти пример описания

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

зачем? есть встроенные умножители, если нету (в современных плис это редкость), то синтезатор сам синтезирует умножитель ...

Вам достаточно написать а = в*с

Пишу диплом на тему "быстрый умножитель". Сравниваю между собой различные алгоритмы.

 

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

 

Я нашел реализации алгоритма Бута на verilog и vhdl, но мне больше интересно, в чем здесь ошибка.

 

Выяснилось, что суммирование и вычитание производятся нужное число раз, но всё равно результат неправильный.

Изменено пользователем Moses

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если вы пишите диплом, то зачем разбираться в том правильный результат или неправильный? B)

Помнится сам писал этого Бута, давно это было.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если вы пишите диплом, то зачем разбираться в том правильный результат или неправильный? B)

Конечно, вообще никто не будет запускать мой вериложный код, который указан в конце диплома, и можно так всё оставить, но самому интересно, где здесь ошибка.

 

Кстати, если вдруг кому-то нужно, то написал другой алгоритм для разрядностей 4x4, 8x8, 16x16.

По некой причине unsigned умножает нормально, signed только в том случае, если A положительное.

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

 

http://pastebin.com/jHsDkRJg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, если вдруг кому-то нужно, то написал другой алгоритм для разрядностей 4x4, 8x8, 16x16.

По некой причине unsigned умножает нормально, signed только в том случае, если A положительное.

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

1) этот алгоритм вообще должен работать для знаковых чисел?

Если да, то:

2) либо объявите все регистры/порты как знаковые, либо при работе с ними указывайте, что синтезатор должен интерпретировать их как знаковые, используя $signed()

3) у вас в одном месте используется арифметический сдвиг: X <<< 1, а в другом - обычный X << 2, так должно быть? Для беззнаковых это одно и тоже, для знаковых результат будет разным.

4) always@(*) проще, это не VHDL, зачем описывать все входящие переменные так дотошно, хотя в учебных целях может и надо )

5) используйте регистры, заведите клок и перенесите ваш always @ (A, B) в always@(posedge clock).

6)

3'b000:;
3'b111:;

это лучше описать через default. У вас там вообще походу latch нарисовывается. Перепишите через регистры или переделайте блокирующие операции как положено.

Поищите примеры реализации подобного кода на верилоге в нете, наверняка их немало, посмотрите как люди делают, может найдёте для себя что нибудь полезное, а вообще нужно книги почитать, что нибудь базовое по rtl design.

Но это всё если вы после диплома собираетесь на этом поприще трудиться, если нет, то смело забудьте, что я тут понаписал :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) этот алгоритм вообще должен работать для знаковых чисел?

Если да, то:

2) либо объявите все регистры/порты как знаковые, либо при работе с ними указывайте, что синтезатор должен интерпретировать их как знаковые, используя $signed()

3) у вас в одном месте используется арифметический сдвиг: X <<< 1, а в другом - обычный X << 2, так должно быть? Для беззнаковых это одно и тоже, для знаковых результат будет разным.

4) always@(*) проще, это не VHDL, зачем описывать все входящие переменные так дотошно, хотя в учебных целях может и надо )

5) используйте регистры, заведите клок и перенесите ваш always @ (A, B) в always@(posedge clock).

6)

3'b000:;
3'b111:;

это лучше описать через default. У вас там вообще походу latch нарисовывается. Перепишите через регистры или переделайте блокирующие операции как положено.

Поищите примеры реализации подобного кода на верилоге в нете, наверняка их немало, посмотрите как люди делают, может найдёте для себя что нибудь полезное, а вообще нужно книги почитать, что нибудь базовое по rtl design.

Но это всё если вы после диплома собираетесь на этом поприще трудиться, если нет, то смело забудьте, что я тут понаписал :rolleyes:

 

Спасибо за совет по поводу signed, действительно в этом дело.

По поводу сдвигов - в одном случае происходит умножение на два, в другом просто сдвиг на два бита. Думаю, при умножении имеет смысл сохранять знак.

Теперь всё работает правильно :)

 

Что посоветуете почитать по rtl design?

За семестр обучения верилога я научился описывать полусумматоры четырьмя способами, собирать из этого полный сумматор, а из полного сумматора - n-битный сумматор, но лишь недавно узнал про

assign {carry, summ} = A + B;

 

Вот правильная итоговая версия, если кому-то нужно.

http://pastebin.com/Y2fqX3dj

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я даже не знаю, что посоветовать. Для начала пробегитесь по нету, почитайте туториалы с самыми простейшими конструкциями, попутно реализуя каждую конструкцию в modelsim и смотря на waveview как это работает. После проверки в modelsim обязательно собирайте эту конструкцию в quartus/ise/vivado (что ближе будет, пока вам вендор не важен, quartus имеет самый дружественный интерфейс) и смотрите как ваша схема собирается в rtl viewer. Неплохой сайт например вот. Кое что разбирают на stack exchange ну и вообще гуглите ресурсы по выбранному вами языку. Ну и тут разумеется постоянно обсуждаются всяческие ньюансы, но это все таки форум а не учебник). Кстати в тех же quartus/ise есть темплейты языка на самые базовые конструкции, их тоже все надо бы проиграть. Вот книга, но за неё стоит браться, когда уже немного освоитесь с языком, поможет привести мысли в порядок. Удачи.

 

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

Изменено пользователем serjj

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А еще описание синтезируемых конструкций под конкретное семейство ПЛИС, поновее возьмите, типа всяких XST User Guide. Там очень дотошно перечислены как в конкретном ПЛИС описывается та или иная конструкция, так что чуть ли не перекрывает стандарт верилога.... Есть такой же обобщенный документ

 

Но я не уверен что надо учить описание элементов и собирать из них схему, я выступаю за поведенческий дизайн, а уже конкретику отдавать синтезатору. Это тратить больше ЛУТов, но зато экономит время. А оно нынче дороже ЛУТов. Все естественно ИМХО...

 

А на алгоритм бута в итоге все забили? или ошибку нашли и поправили?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день.

Пытаюсь воспроизвести алгоритм Бута по примеру из Википедии https://ru.wikipedia.org/wiki/%D0%90%D0%BB%....B8.D1.82.D0.BC

На листе всё выходит нормально, при написании алгоритма на verilog получается не настолько точно.

Вот листинг кода http://pastebin.com/BgSTGGdC

Помогите разобраться с ошибкой, пожалуйста.

посмотрите это

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот правильная итоговая версия, если кому-то нужно.

http://pastebin.com/Y2fqX3dj

1) Изучите как блокирующие присвоение (=) отличается от неблокирующего (<=) и почему для регистров используется неблокирующее

2) Неправильно в двух или более разных местах присваивать значение одному и тому же регистру; если регистру могут присваиваться разные значения, это должно быть описано в одном always блоке через конструкции if-else if-else или case-endcase. Присвоение в разных местах без условной связи даст вам неопределенный синтез, все равно что написать: Пете 10 лет, а через пол страницы - Пете 13 лет :rolleyes:

3) логика на MULT это какой-то кошмар, его нужно либо переделать, сделав нормальное дерево, либо вынести MULT в блок комбинаторной логики always@(*). Тогда по клоку захватываются входные данные, т.е. ваши M и Х и выходные данные, например MULTREG, а само вычисление будет комбинаторным

4) вообще почитайте что такое циклы for и while в verilog, очень похоже, что вы их тут пытаетесь использовать по аналогии с С

5) вы добавили в case default условие, но что будет по дефолту с MULT? Если case конструкция используется для блокирующего присвоения, вы должны описать все возможные ситуации иначе состояние неопределенности переменной синтезируется как латч, что неправильно. Подозреваю, что это еще одно наследие С

Вы рисовали схему вашего устройства умножителя в виде базовых блоков (сумматоры/логика/регистры) например для небольшой разрядности (4/8)? Я бы на вашем месте для начала расписал бы для случая 8, например, без использования for весь алгоритм. И например в двух вариантах - чисто комбинаторном и в виде дерева суммирования с регистрами на каждой стадии.

Вам возможно покажется что я тут много всего понаписал, но возможно некоторую пользу вы извлечете и пойдете в верном направлении. Опять повторяюсь, что вам нужно начать прорабатывать базовые и простейшие примеры, а не бросаться сразу на автогенерирующиеся конструкции (которыми и являются циклы) без понимания основ.

Изменено пользователем serjj

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не совсем согласен с 1. Я и для регистров использую блокирующее присвоение. Согласен с тем что надо знать отличие от неблокирующего, но что блокирующее только не для регистров не верно.

 

запись

a = a + b;
c = a + d;

равносильна

a <= a + b;
c <= a + b + d;

это всего лишь удобство записи....

 

с 2. Тоже не совсем понял. В разных always ISE вообще не даст присваивать одному регистру значения, скажет у регистра много разных источников, но внутри одного не обязательно if-if else - else, верилог дает очень удобную "перегрузку" которая делает запись более читаемой.

 

я всегда конструкции вида

always @(posedge clk)
   begin
      if(reset) 
         begin
            ....
            a <= 0;
         end   
       else
         begin
            a<= .....
         end
   end

 

предпочитаю более читаемую

 

always @(posedge clk)
   begin
      a<= .....

      if(reset) 
         begin
            ....
            a <= 0;
         end   
   end

 

всегда выполниться последние возможное присвоение...

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

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

 

Про циклы согласен - все сначала считают что это как в С цикл, в ХДЛ языках это всего лишь сокращение записи не более...

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

с 2. Тоже не совсем понял. В разных always ISE вообще не даст присваивать одному регистру значения, скажет у регистра много разных источников, но внутри одного не обязательно if-if else - else, верилог дает очень удобную "перегрузку" которая делает запись более читаемой.

Если мы пишем блокирующее присвоение, например в теле функции, то действительно можно спокойно написать

a = 'd1;
a = a + b;
a = a + c;
a = a + 1'b1;
...

И он будет просто наращивать сумматор, но если речь идёт о неблокирующем присвоение, то тут я за строгость - регистр а существует в одном экземпляре физически, он должен быть определен в одном месте и однозначно без "перегрузок", тогда мы сразу видим при каком сценарие какая логика задаёт его значение. И синтезатор это видит.

Не совсем согласен с 1. Я и для регистров использую блокирующее присвоение. Согласен с тем что надо знать отличие от неблокирующего, но что блокирующее только не для регистров не верно.

Пока не будет понимания основ про эту "приятную опцию" лучше забыть. ИМХО лучше допускать такое вообще только в функциях. Я тут пару месяцев назад в теме про SV функции потоптался изрядно по граблям с использованием блокирующих присвоений в always_ff блоках, это не то, чему нужно новичка учить, хаос в голове обеспечен :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) Изучите как блокирующие присвоение (=) отличается от неблокирующего (<=) и почему для регистров используется неблокирующее

2) Неправильно в двух или более разных местах присваивать значение одному и тому же регистру; если регистру могут присваиваться разные значения, это должно быть описано в одном always блоке через конструкции if-else if-else или case-endcase. Присвоение в разных местах без условной связи даст вам неопределенный синтез, все равно что написать: Пете 10 лет, а через пол страницы - Пете 13 лет :rolleyes:

3) логика на MULT это какой-то кошмар, его нужно либо переделать, сделав нормальное дерево, либо вынести MULT в блок комбинаторной логики always@(*). Тогда по клоку захватываются входные данные, т.е. ваши M и Х и выходные данные, например MULTREG, а само вычисление будет комбинаторным

4) вообще почитайте что такое циклы for и while в verilog, очень похоже, что вы их тут пытаетесь использовать по аналогии с С

5) вы добавили в case default условие, но что будет по дефолту с MULT? Если case конструкция используется для блокирующего присвоения, вы должны описать все возможные ситуации иначе состояние неопределенности переменной синтезируется как латч, что неправильно. Подозреваю, что это еще одно наследие С

Вы рисовали схему вашего устройства умножителя в виде базовых блоков (сумматоры/логика/регистры) например для небольшой разрядности (4/8)? Я бы на вашем месте для начала расписал бы для случая 8, например, без использования for весь алгоритм. И например в двух вариантах - чисто комбинаторном и в виде дерева суммирования с регистрами на каждой стадии.

Вам возможно покажется что я тут много всего понаписал, но возможно некоторую пользу вы извлечете и пойдете в верном направлении. Опять повторяюсь, что вам нужно начать прорабатывать базовые и простейшие примеры, а не бросаться сразу на автогенерирующиеся конструкции (которыми и являются циклы) без понимания основ.

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

2. Вы про

MULT = 33'b0;

?

Это тоже из С - обнулять переменные перед использованием.

Но ведь, насколько я понимаю, данную запись можно удалить безо всякого опасения.

3. Здесь не совсем понял. Можно поподробнее?

4. Здесь тоже не совсем понял. Можете привести пример правильного использования циклов?

5. По дефолту ничего с ним не будет, останется таким же.

 

Теперь по результатам моделирования: в случае использования неблокирующего присваивания количество LUT увеличивается с 1130 до 1640, умножитель перестаёт правильно работать.

Мне кажется, ваши советы, несомненно, хороши, особенно про default и latch, но часть их не совсем применима к этому алгоритму.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Не буфер а регистр. Всё правильно, конвеерное вычисление. Необходимо понимать зачем это применяется. Если вам в данном задание нужно получить минимальную задержку на вычисление, никто не заставляет делать конвеер, но нужно понимать зачем их вообще делают. Забегая вперед, в той книге, которую я выложил несколькими постами выше, в первой главе все это неплохо разжевывается.

Это тоже из С - обнулять переменные перед использованием.

Верилог не С, здесь вы работаете не с областями памяти, а с физическими ресурсами в виде ЛУТов, регистров и прочего. Когда вы описываете регистр, у вас не может быть двух разных описаний на один и тотже (физически) объект иначе как синтезатор поймет что от него требуется? Т.к. регистры хранят свои значения как память, их можно обнулять, но для этого лучше использовать сигнал сброса (это уже вообще отдельная тема). Если описывается комбинаторная логика, то многократные описания "навешивают" дополнительную логику на вашу схему. Обнуление кстати в случае комбинаторной логики совершенно избыточная операция.

4. Здесь тоже не совсем понял. Можете привести пример правильного использования циклов?

пример:

logic signed [7:0] q [0:3];
logic signed [6:0] a [0:3];
logic signed [6:0] b [0:3];
always@(*) begin
   for (int i=0; i<4; i++) begin
      q[i] = {{(1){a[i][6]}}, a[i]} + {{(1){b[i][6]}}, b[i]};
   end
end

создаст схему из 4-х однотипных умножителей upd.сумматоров.

пример:

logic [7:0] delayline [0:3];
always@(posedge clock) begin
   delayline [0] <= idata;
   for (int i=1; i<4; i++) begin
       delayline [i] <= delayline [i-1];
   end
end

создаст линию задержки глубиной 4 такта и шириной 8 бит.

5. По дефолту ничего с ним не будет, останется таким же.

И будет латч, почитайте в нете про латчи и почему делать их плохо. Не заканчивать case или if-else допускается только для регистров, т.к. если ни одно из условий не выполняеся, регистр просто сохраняет свое значение.

3. Здесь не совсем понял. Можно поподробнее?

Этот весь цикл, коль скоро у вас умножитель должен отрабатывать "сразу" нельзя так просто взять и затащить в always@(posedge clock), т.к. это комбинаторная логика, его следует вынести в always@(*). Далее данные по входу и по выходу должны захватываться по входному клоку. В итоге ваша комбинаторная схема будет описывать путь сигналов между входным и выходным регистрами. Этот путь вы сможете проанализировать по времени, сделать оценку на какой максимальной частоте сможет работать ваша схема для выбранного кристалла. Далее сам цикл: каждая "итерация" добавляет новый слой логики, исходными данными для которого служат выходные данные предыдущего слоя. На каждом слое следует полно описывать функцию выхода от входа, т.е. значение выхода для всех возможных вариантов. Если так хотите сделать через цикл, то следует на каждый слой завести свои переменные, т.е что-то вроде:

for(...)
if (...)
state[i]=state[i-1]+...;
else if (...)
state[i]=state[i-1]-...;
else
state[i]=state[i-1];

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

Мне кажется, ваши советы, несомненно, хороши, особенно про default и latch, но часть их не совсем применима к этому алгоритму.

Вам конечно виднее, ну а я наверное и так много времени на "не совсем применимые советы" потратил :biggrin: наверное разберетесь и так!

Изменено пользователем serjj

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...