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

Помогите с нестабильным Reset в BrainFuck процесоре (Verilog)

Привет.

 

Помогите мне пожалуйста понять и исправить багу. Первым проэктом для себя избрал БрайнФак процессор, где Питоновский код генерирует бинарник, который загружается в процессор на Spartan-6, и даже все работает, програма исполняется без сбоев.

 

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

 

Сам ресет синхронный, и на саму ножку не навешены никаких штук по устранению дребезга контактов, может из-за этого?

Хотя насколько я понимаю, это не должно влиять, потому что ведь все высчитывается до условия с ресетом, а дальше лишь в послединй помент на основнаии ножки делается то или иное присваивание в регистры.

Да и я пробовал заменить код ресета на такой, но это тоже не помогло:

 

always @(posedge clk) begin
next_reset <= 0;
       if (reset) next_reset <= 1;
if (next_reset ) begin
             real code about reset;
       end

 

Уже что только не пробовал, а не могу найти ошибку (. Помогите пожалуйста.

 

Вот главный участок где ресет (простой wire). На гитхабе есть полный исходник - https://github.com/presidentua/bfp/blob/mas..._verilog/root.v

 

А если есть другие замечания по коду - с удовольствием выслушаю.

 

always @(posedge clk) begin
is_2byte <= 0;
prev_jmp <= command[2:0];
if (reset) begin
	ip <= 0;
	ptr <= 0;
	out_port <= 0;
	registers[0] <= 0;
	registers[1] <= 0;
	registers[2] <= 0;
	registers[3] <= 0;
end else if (is_2byte) begin
	ip <= registers[ptr] ? ip - {prev_jmp, command} : ip + 1;
end else begin
	ip <= ip + 1;
	casex(command)
		4'b0001: registers[ptr] <= registers[ptr] + 1; //+
		4'b0010: registers[ptr] <= registers[ptr] - 1; //-
		4'b0011: out_port <= registers[ptr]; // .
		4'b0100: registers[ptr] <= in_port;  // ,
		4'b0101: ptr <= ptr + 1; //>
		4'b0110: ptr <= ptr - 1; //<
		4'b1???: is_2byte <= 1; //[]
	endcase
end
end

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


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

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

Сам ресет синхронный, и на саму ножку не навешены никаких штук по устранению дребезга контактов, может из-за этого?

Если на моделировании все работает правильно, то скорее всего не выполняются временные ограничения (причем не обязательно связанные со сбросом, может Вы пытаетесь работать на 1Ггц и несколькими уровнями логики). Сделайте пересинхронизацию хоть через простой триггер:

always @(posedge clk) next_reset <= reset;

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

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


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

Спасибо. Вечером попробую как вы указали пересинхронизировать.

 

По частоте там немного по дурному сделал, у меня кварц в отладочной плате Nexus 3 на 100MGz, а через внутрений делить из IP у меня не получилось снизить частоту до нескольких герц, поэтому мне пришлось делать свой делитель частоты вручную, и синтезировалось все наверно ооочень плохо. Может из-за того что ему пришлось при синтезе эмулировать тактовую частоту, оно и не отрабатывает правильно.

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

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


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

По частоте там немного по дурному сделал, у меня кварц в отладочной плате Nexus 3 на 100MGz, а через внутрений делить из IP у меня не получилось снизить частоту до нескольких герц, поэтому мне пришлось делать свой делитель частоты вручную, и синтезировалось все наверно ооочень плохо. Может из-за того что ему пришлось при синтезе эмулировать тактовую частоту, оно и не отрабатывает правильно.

Ну 100МГц частота довольно низкая, не говоря уже об нескольких герц. Может Вы ее задали неправильно или асинхронная логика где-то или в ucf - файле что-то непрописали. Там уже надо смотреть отчеты синтезатора и предупреждения.

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


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

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

Попробуйте сделать счетчик, чо бы он разрешал следующий сигнал сброса скажем через 1000-10000 тактов.

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


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

А если есть другие замечания по коду - с удовольствием выслушаю.

 

always @(posedge clk) begin
is_2byte <= 0;
prev_jmp <= command[2:0];
if (reset) begin
end

 

Мутный он и не читаемый. Почему is_2byte и prev_jmp по ресету не устанавливаются.

Да и не все состояния в casex описаны.

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


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

Сам ресет синхронный, и на саму ножку не навешены никаких штук по устранению дребезга контактов, может из-за этого?

Несколько вопросов

1) Что значит "ресет синхронный"? Не значит-ли что у Вас вся схема описана с синхронным ресетом?

2) У Вас я так понял "синхронный" ресет сделан в виде кнопки, подключённой к простому входу и дальше напрямую попадает в описанные Вами флопы. Так?

3) Осцилографом видно дребезг на ресете?

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


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

Для меня больше не задача чтобы оно заработало, а понять почему.

 

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

 

Например я пересинкивал ресет через регистр:

 

always @(posedge clk) next_reset <= reset;

 

И это все равно не помогало. Тоесть сам Ресет он то работает, но через раз. А если по Верилогу смотреть, то поидее:

 

По клоку в next_reset запишеться значение кнопки, и пусть она там каждый раз меняться сотни тысяч раз, но это же не должно влиять на регистр? И в регист запишеться только одно конкретное значение.

 

Дальше на следующему такту переменные схемы выставляються в 0. Тоесть пусть там схема сбивается хоть тысячу раз, но после прекращения Ресета схема долна начать выполнять команды. И как оно так синтезируется что моя логика не работает, вот что меня ооочень мучает =).

 

Оно как-то синтезировалось что из схемы:

if (reset) begin
	ip <= 0;
	ptr <= 0;
	out_port <= 0;
	registers[0] <= 0;
	registers[1] <= 0;
	registers[2] <= 0;
	registers[3] <= 0;

Иногда(насколько понял из опытов) не все сбивается в 0, тоесть например ссылка на следующие регистр(ptr) не собьется, или какой то регистр не успеет обновиться. Может быть это из-за того что пришлось симулировать CLOCK-сигнал, а не использовать настоящую линию?

 

По замечания sazh:

- В casex затупил что пропустил одно значение (, исправлю.

 

А по обнулению, то тут я так понимаю нет смысла is_2byte обнулять еще и в ресете, потому что поскольку я в ресете его не трогаю, как раз присваивание со 2-рой строчки и сработает. А prev_jmp, это если предыдущая команда была из двух слов но поскольку is_2byte выставляется в 0, то prev_jmp он не нужен будет.

always @(posedge clk) begin //1
is_2byte <= 0; //2
prev_jmp <= command[2:0]; //3
if (reset) begin //4
end

 

Я вечером, как подсказал svedach сделаю дома чтобы после нажания Ресета, его нельзя было нажать следующие такты. Надеюсь это решит проблему.

 

--------

 

Torpeda,

1. У меня только этот один ресет, больше нигде его не использую.

2. Да, ресет как wire подходит от кнопки.

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

 

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


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

Дребезг как раз и сбрасывает несколько раз Ваш процессор. Когда кнопку отжимаете периодические замыкания через несколько тактов или сотен тактов пересбрасывают процессор. Синхронизация одним триггером проблему не решит.

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


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

Посмотрел Ваш код еще раз в первом посте, мне непонятно, каким образом меняется is_2byte

Т.е. он вроде бы каждый фронт в 0

always @(posedge clk) begin
is_2byte <= 0;

и при этом еще

...else begin
...casex(command)
4'b1???: is_2byte <= 1; //[]

Такого я нигде не видел (он вроде как всегда в нуле будет)...

По поводу дребезга - лучше делать сброс при отжатии кнопки - можно формировать с помощью счетчика или сдвигового регистра, если задержка несущественна. Т.е. сформировать импульс и дальше от него запускать, если активная 1, то импульс формируется так:

reg reset_r, reset_rr, new_reset;
always @(posedge clk) begin
    reset_r<=reset;
    reset_rr<=reset_r;
    new_reset<=~reset_r&reset_rr;
    end

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

Переменная command - синхронная? И в casex Вы пропустили не одно, а два значения - 0000 и 0111, если они не используются то пустите по default.

Да и посмотрите уже на signaltapII или в chipscope поведение сигналов, включая сброс - там проще будет посмотреть и определить причину сбоя (правда, дребезг определится, если попадет на момент фронта clk)

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


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

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

По клоку в next_reset запишеться значение кнопки, и пусть она там каждый раз меняться сотни тысяч раз, но это же не должно влиять на регистр? И в регист запишеться только одно конкретное значение.

1) Что видит осцилограф? Или, какая минимальная ширина пиков дребезга?

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

2) Вместо одного флопа на reset поставте 2 последовательно. Помогло?

 

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


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

Чем больше я смотрю на Verilog, тем больше непонимаю. Вчера весь вечер провел заливаю разныеш прошивки, которые вместо того чтобы все обьяснить еще сильнее запутали ситуацию.

 

Вообщем получается что дребезг не причем. Если я убираю Ресет - все нормально отрабатывает, если делаю чтобы вначале всегда был ресет один раз (кнопка ресета вообще не подключена), то тогда процессор работает неправильно. Делал так:

 

reg reset;
always @(posedge clock)
if (!reset) begin
   // reset code
   reset <= 1;
else begin
   // processor
end
end

 

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

 

По casex там те команды что не используются поидее означают NOP инструкцию в процессоре, и ничего не должны делать. В моейм случае:

ip <= ip + 1;
casex(command)
4'b0001: registers[ptr] <= registers[ptr] + 1; //+
4'b0010: registers[ptr] <= registers[ptr] - 1; //-
4'b0011: out_port <= registers[ptr]; // .
4'b0100: registers[ptr] <= in_port;  // ,
4'b0101: ptr <= ptr + 1; //>
4'b0110: ptr <= ptr - 1; //<
4'b1???: is_2byte <= 1; //[]
endcase

Он в те команды которые не используются выполнит лишь ip <= ip + 1;, поскольку я его выше описал.

 

 

Сам результат плохого Ресета удалось исправить тем что сбрасываю IP регистр не на первую команду, а на последнюю в ip <= 7'b1111111; По которой поидее лежит инстркуция 4'b0000 что у меня NOP означет и дальше, он нормально все исполняет.

 

...else begin
...casex(command)
4'b1???: is_2byte <= 1; //[]

Тут весь код для того что JMP инструкция у меня состоит из 2-х блоков по 4бита. Получается я вначале проверяю что первый бит 1 - 4'b1???, и если так то выставляю флажок is_2byte. И значит на следующую инструкцию будет JMP на {предидущая команда из 4-х битов, текущая команда из 4-х битов}.

 

Я за всеми этими тестами так и не успел вчера в ISim'e посмотреть что в нем получается с этими разными изменениями. Да и еще попробую вместо сгенерированого в IP Memory где храниться команды использовать простой масив из регистров. Я же к совему стыду на него Даташит не читал, может там нужно ждать пару тактов чтобы получать коректные данные к примеру или еще что-то в таком роде.

 

PS: до запуска на апаратуре процессора, я думал что немногу понимаю HDL. Как же я ошибался =)

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


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

Если я убираю Ресет - все нормально отрабатывает, если делаю чтобы вначале всегда был ресет один раз (кнопка ресета вообще не подключена), то тогда процессор работает неправильно. Делал так:

reg reset;
always @(posedge clock)
if (!reset) begin
   // reset code
   reset <= 1;
else begin
   // processor
end
end

 

Cудя по этому коду Вы делаете "нулевой импульс" в начале, а потом reset=1

При этом, у Вас описана схема с "активным ывсоким" уровнем ресета:

always @(posedge clk) begin
is_2byte <= 0;
prev_jmp <= command[2:0];
if (reset) begin
ip <= 0;
ptr <= 0;
out_port <= 0;

Т.е. выходит что Вы просто держите схему в ресете, а не импульс в начале даёте. Вот и неработает.

 

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


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

Нашел багу! =)

 

Вообще прочитал Даташит по 9Ram блоке и там писалось что даные буду на следующем такте, так что этот вариант отбросил. Дальше уже подумал что придется с этой багой мириться, поскольку идей не возникало где искать. Но вспомнил одно предложения с какой-то книги по Верилогу, типа "Чтобы найти ошибку, побудьте в роли синтезатора и подумайте как бы вы реализовывали в апаратуре каждую строчку". В результате все строчки нормально ложились в голове на апаратные штуки, но мне не очень понравился следующий код:

 

casex(command)
4'b0001: registers[ptr] <= registers[ptr] + 1; //+
4'b0010: registers[ptr] <= registers[ptr] - 1; //-

 

и я его заменил та такой:

cur_reg <= registers[ptr];
casex(command)
4'b0001: registers[ptr] <= cur_reg + 1; //+
4'b0010: registers[ptr] <= cur_reg - 1; //-

 

И это полностью решило ошибку! Конечно я не совсем понимаю как у него так получилось синтезировать код что он давал сбой во время ресета а в остальных случаях отлично работал. Но все же )

 

Всем спасибо большое за помощь!

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


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

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

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

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

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

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

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

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

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

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