Перевод Verilog-кода на SystemVerilog

This commit is contained in:
Andrei Solodovnikov
2023-11-15 14:47:28 +03:00
parent 1b4f666e25
commit 1da4ed0173
11 changed files with 200 additions and 200 deletions

View File

@@ -0,0 +1,93 @@
module PS2Receiver(
input logic clk,
input logic kclk,
input logic kdata,
output logic [15:0] keycodeout,
output keycode_valid
);
logic flag;
logic [3:0] flag_shift;
logic kclkf, kdataf;
logic [3:0] cnt;
assign keycode_valid = flag_shift[0] && !flag_shift[2];
initial begin //for tb
cnt = 0;
keycodeout = 0;
flag_shift = 0;
flag = 0;
end
debouncer debounce(
.clk(clk),
.I0(kclk),
.I1(kdata),
.O0(kclkf),
.O1(kdataf)
);
always@(posedge clk) begin
flag_shift <= (flag_shift << 1) + flag;
end
always_ff @(negedge(kclkf))begin
case(cnt)
0:if(keycodeout != 16'hE000)keycodeout <= 0;//Start bit
1:keycodeout[0]<=kdataf;
2:keycodeout[1]<=kdataf;
3:keycodeout[2]<=kdataf;
4:keycodeout[3]<=kdataf;
5:keycodeout[4]<=kdataf;
6:keycodeout[5]<=kdataf;
7:keycodeout[6]<=kdataf;
8:keycodeout[7]<=kdataf;
//TODO ADD PARITY CHECK
9:begin
flag<=1'b1;
if(keycodeout[7:0] == 8'hE0) begin
keycodeout <= {keycodeout[7:0], 8'd0};
end
end
10:flag<=1'b0;
default: cnt <= 0;
endcase
if(cnt<=9) cnt<=cnt+1;
else if(cnt==10) cnt<=0;
end
endmodule
module debouncer(
input logic clk,
input logic I0,
input logic I1,
output logic O0,
output logic O1
);
logic [4:0]cnt0, cnt1;
logi Iv0=0,Iv1=0;
logi out0, out1;
always_ff @(posedge(clk))begin
if (I0==Iv0) begin
if (cnt0==19)O0<=I0;
else cnt0<=cnt0+1;
end
else begin
cnt0<="00000";
Iv0<=I0;
end
if (I1==Iv1)begin
if (cnt1==19)O1<=I1;
else cnt1<=cnt1+1;
end
else begin
cnt1<="00000";
Iv1<=I1;
end
end
endmodule

View File

@@ -1,93 +0,0 @@
module PS2Receiver(
input clk,
input kclk,
input kdata,
output reg [15:0] keycodeout,
output keycode_valid
);
reg flag;
reg [3:0] flag_shift;
wire kclkf, kdataf;
reg [3:0]cnt;
assign keycode_valid = flag_shift[0] && !flag_shift[2];
initial begin //for tb
cnt = 0;
keycodeout = 0;
flag_shift = 0;
flag = 0;
end
debouncer debounce(
.clk(clk),
.I0(kclk),
.I1(kdata),
.O0(kclkf),
.O1(kdataf)
);
always@(posedge clk) begin
flag_shift <= (flag_shift << 1) + flag;
end
always@(negedge(kclkf))begin
case(cnt)
0:if(keycodeout != 16'hE000)keycodeout <= 0;//Start bit
1:keycodeout[0]<=kdataf;
2:keycodeout[1]<=kdataf;
3:keycodeout[2]<=kdataf;
4:keycodeout[3]<=kdataf;
5:keycodeout[4]<=kdataf;
6:keycodeout[5]<=kdataf;
7:keycodeout[6]<=kdataf;
8:keycodeout[7]<=kdataf;
//TODO ADD PARITY CHECK
9:begin
flag<=1'b1;
if(keycodeout[7:0] == 8'hE0) begin
keycodeout <= {keycodeout[7:0], 8'd0};
end
end
10:flag<=1'b0;
default: cnt <= 0;
endcase
if(cnt<=9) cnt<=cnt+1;
else if(cnt==10) cnt<=0;
end
endmodule
module debouncer(
input clk,
input I0,
input I1,
output reg O0,
output reg O1
);
reg [4:0]cnt0, cnt1;
reg Iv0=0,Iv1=0;
reg out0, out1;
always@(posedge(clk))begin
if (I0==Iv0)begin
if (cnt0==19)O0<=I0;
else cnt0<=cnt0+1;
end
else begin
cnt0<="00000";
Iv0<=I0;
end
if (I1==Iv1)begin
if (cnt1==19)O1<=I1;
else cnt1<=cnt1+1;
end
else begin
cnt1<="00000";
Iv1<=I1;
end
end
endmodule

View File

@@ -0,0 +1,76 @@
module hex_digits(
input logic clk_i, rst_i,
input logic [4:0] hex0, // Входной сигнал со значением цифры, выводимой на нулевой (самый правый) индикатор
input logic [4:0] hex1, // Входной сигнал со значением цифры, выводимой на первый индикатор
input logic [4:0] hex2, // Входной сигнал со значением цифры, выводимой на второй индикатор
input logic [4:0] hex3, // Входной сигнал со значением цифры, выводимой на третий индикатор
input logic [4:0] hex4, // Входной сигнал со значением цифры, выводимой на четвертый индикатор
input logic [4:0] hex5, // Входной сигнал со значением цифры, выводимой на пятый индикатор
input logic [4:0] hex6, // Входной сигнал со значением цифры, выводимой на шестой индикатор
input logic [4:0] hex7, // Входной сигнал со значением цифры, выводимой на седьмой индикатор
output logic [6:0] hex_led, // Выходной сигнал, контролирующий каждый отдельный светодиод индикатора
output logic [7:0] hex_sel // Выходной сигнал, указывающий на какой индикатор выставляется hex_led
);
localparam pwm 1000 //шим сегментов
logic [9:0] counter;
logic [4:0] semseg;
logic [7:0] ANreg;
logic [6:0] hex_ledr;
assign hex_sel = ANreg;
assign hex_led = hex_ledr;
always_ff @(posedge clk_i) begin
if (rst_i) begin
counter <= 'b0;
ANreg[7:0] <= 8'b11111111;
hex_ledr <= 7'b1111111;
end
else begin
if (counter < pwm) counter <= counter + 'b1;
else begin
counter <= 'b0;
ANreg[1] <= ANreg[0];
ANreg[2] <= ANreg[1];
ANreg[3] <= ANreg[2];
ANreg[4] <= ANreg[3];
ANreg[5] <= ANreg[4];
ANreg[6] <= ANreg[5];
ANreg[7] <= ANreg[6];
ANreg[0] <= !(ANreg[6:0] == 7'b1111111);
end
case (1'b0)
ANreg[0]: semseg <= hex0;
ANreg[1]: semseg <= hex1;
ANreg[2]: semseg <= hex2;
ANreg[3]: semseg <= hex3;
ANreg[4]: semseg <= hex4;
ANreg[5]: semseg <= hex5;
ANreg[6]: semseg <= hex6;
ANreg[7]: semseg <= hex7;
endcase
case (semseg)
5'h10: hex_ledr <= 7'b0000001;
5'h11: hex_ledr <= 7'b1001111;
5'h12: hex_ledr <= 7'b0010010;
5'h13: hex_ledr <= 7'b0000110;
5'h14: hex_ledr <= 7'b1001100;
5'h15: hex_ledr <= 7'b0100100;
5'h16: hex_ledr <= 7'b0100000;
5'h17: hex_ledr <= 7'b0001111;
5'h18: hex_ledr <= 7'b0000000;
5'h19: hex_ledr <= 7'b0000100;
5'h1A: hex_ledr <= 7'b0001000;
5'h1B: hex_ledr <= 7'b1100000;
5'h1C: hex_ledr <= 7'b0110001;
5'h1D: hex_ledr <= 7'b1000010;
5'h1E: hex_ledr <= 7'b0110000;
5'h1F: hex_ledr <= 7'b0111000;
default: hex_ledr <= 7'b1111111;
endcase
end
end
endmodule

View File

@@ -1,76 +0,0 @@
module hex_digits(
input clk_i, rst_i,
input [4:0] hex0, // Входной сигнал со значением цифры, выводимой на нулевой (самый правый) индикатор
input [4:0] hex1, // Входной сигнал со значением цифры, выводимой на первый индикатор
input [4:0] hex2, // Входной сигнал со значением цифры, выводимой на второй индикатор
input [4:0] hex3, // Входной сигнал со значением цифры, выводимой на третий индикатор
input [4:0] hex4, // Входной сигнал со значением цифры, выводимой на четвертый индикатор
input [4:0] hex5, // Входной сигнал со значением цифры, выводимой на пятый индикатор
input [4:0] hex6, // Входной сигнал со значением цифры, выводимой на шестой индикатор
input [4:0] hex7, // Входной сигнал со значением цифры, выводимой на седьмой индикатор
output [6:0] hex_led, // Выходной сигнал, контролирующий каждый отдельный светодиод индикатора
output [7:0] hex_sel // Выходной сигнал, указывающий на какой индикатор выставляется hex_led
);
`define pwm 1000 //шим сегментов
reg [9:0] counter;
reg [4:0] semseg;
reg [7:0] ANreg;
reg [6:0] hex_ledr;
assign hex_sel = ANreg;
assign hex_led = hex_ledr;
always @(posedge clk_i) begin
if (rst_i) begin
counter <= 'b0;
ANreg[7:0] <= 8'b11111111;
hex_ledr <= 7'b1111111;
end
else begin
if (counter < `pwm) counter <= counter + 'b1;
else begin
counter <= 'b0;
ANreg[1] <= ANreg[0];
ANreg[2] <= ANreg[1];
ANreg[3] <= ANreg[2];
ANreg[4] <= ANreg[3];
ANreg[5] <= ANreg[4];
ANreg[6] <= ANreg[5];
ANreg[7] <= ANreg[6];
ANreg[0] <= !(ANreg[6:0] == 7'b1111111);
end
case (1'b0)
ANreg[0]: semseg <= hex0;
ANreg[1]: semseg <= hex1;
ANreg[2]: semseg <= hex2;
ANreg[3]: semseg <= hex3;
ANreg[4]: semseg <= hex4;
ANreg[5]: semseg <= hex5;
ANreg[6]: semseg <= hex6;
ANreg[7]: semseg <= hex7;
endcase
case (semseg)
5'h10: hex_ledr <= 7'b0000001;
5'h11: hex_ledr <= 7'b1001111;
5'h12: hex_ledr <= 7'b0010010;
5'h13: hex_ledr <= 7'b0000110;
5'h14: hex_ledr <= 7'b1001100;
5'h15: hex_ledr <= 7'b0100100;
5'h16: hex_ledr <= 7'b0100000;
5'h17: hex_ledr <= 7'b0001111;
5'h18: hex_ledr <= 7'b0000000;
5'h19: hex_ledr <= 7'b0000100;
5'h1A: hex_ledr <= 7'b0001000;
5'h1B: hex_ledr <= 7'b1100000;
5'h1C: hex_ledr <= 7'b0110001;
5'h1D: hex_ledr <= 7'b1000010;
5'h1E: hex_ledr <= 7'b0110000;
5'h1F: hex_ledr <= 7'b0111000;
default: hex_ledr <= 7'b1111111;
endcase
end
end
endmodule

View File

@@ -101,7 +101,7 @@ endmodule
Запрещено использовать процедурное присваивание (присваивание в блоке `always` или `initial`) объектам, не являющимися регистрами. Скорее всего, вы пытались выполнить `b = a;` или `b <= a;` блоке `always`/`initial`, где `b` является проводом.
```Verilog
```SystemVerilog
module adder(input a, input b, output c);
always @(*) begin
c = a ^ b; // ошибка, процедурное присваивание

View File

@@ -1,6 +1,6 @@
module half_divider(
input [31:0] numerator,
output[31:0] quotient
input logic [31:0] numerator,
output logic [31:0] quotient
);
assign quotient = numerator << 1'b1;

View File

@@ -1,11 +1,11 @@
module max_min(
input [31:0] a,
input [31:0] b,
output reg[31:0] max,
output reg[ 3:0] min
input logic [31:0] a,
input logic [31:0] b,
output logic [31:0] max,
output logic [ 3:0] min
);
always @(*) begin
always_comb @(*) begin
if(a > b) begin
max = a;
min = b;

View File

@@ -1,8 +1,8 @@
module tb();
reg [31:0] a;
reg [31:0] b;
wire [31:0] res;
logic [31:0] a;
logic [31:0] b;
logic [31:0] res;
vector_abs dut(
.x(a),

View File

@@ -1,12 +1,12 @@
module vector_abs(
input [31:0] x,
input [31:0] y,
output[31:0] abs
input logic [31:0] x,
input logic [31:0] y,
output logic [31:0] abs
);
wire [31:0] min;
wire [31:0] min_half;
logic [31:0] min;
logic [31:0] min_half;
max_min max_min_unit(
.a(x),

View File

@@ -7,7 +7,7 @@
При должном отношении, поиск ошибок может превратиться в увлекательное детективное расследование, где у вас есть "место преступления" (обнаруженное несоответствие в поведении, обычно это не сама ошибка, а ее следствие, круги на воде) и какой-то "набор улик" (фрагменты лога, исходный код). И вы по чуть-чуть будете разматывать "нераспутываемую паутину лжи", получая все новые улики, ведущие к истинной ошибке.
Этот документ посвящен практикуму по поискам подобных ошибок в **Verilog**-коде.
Этот документ посвящен практикуму по поискам подобных ошибок в **SystemVerilog**-коде.
- [Руководство по поиску и исправлению ошибок в проекте](#руководство-по-поиску-и-исправлению-ошибок-в-проекте)
- [Цель](#цель)
@@ -75,7 +75,7 @@
Открывается следующий код (с курсором на строчке `wire [31:0] res;`):
```Verilog
```SystemVerilog
module tb();
reg [31:0] a;
@@ -142,7 +142,7 @@ vector_abs dut(
Видим два сигнала в Z-состоянии и один сигнал в X-состоянии. Обычно, сигналы с Z-состоянием проще всего исправить, т.к. зачастую это забытое или некорректное подключение провода. Кроме того, сигнал, зависящий от сигнала с Z-состоянием может оказаться в X-состоянии, так что это может быть решением нашей проблемы, поэтому займемся проводами `min` и `min_half`. Сперва займемся сигналом `min` и перейдем к шагу 2 нашего алгоритма (нажимаем правой кнопкой мыши и выбираем `Go To Source Code`):
```Verilog
```SystemVerilog
module vector_abs(
input [31:0] x,
input [31:0] y,
@@ -217,7 +217,7 @@ vector_abs dut(
Значит надо смотреть как формируется результат в нашем устройстве, посмотрим на выход `abs` в модуле `vector_abs`:
```Verilog
```SystemVerilog
assign abs = max + min_half;
```
@@ -238,7 +238,7 @@ assign abs = max + min_half;
Как и с сигналом `abs`, необходимо определить сигналы, влияющие на значение сигнала `min_half`. Данный сигнал подключен к выходу `quotient` модуля `half_divider`, поэтому мы будем смотреть исходный код данного модуля:
```Verilog
```SystemVerilog
module half_divider(
input [31:0] numerator,
output[31:0] quotient
@@ -264,7 +264,7 @@ endmodule
Именно поэтому, когда мы в первый раз пытались посчитать результат "на бумаге", у нас было расхождение с моделью: когда мы делим 1 на 2, мы получаем 0.5, однако деление путем отбрасывания цифры округляет результат вниз (1/2=0, 15/10=1).
Как "отбросить" цифру средствами цифровой логики? Для этого используется операция сдвига вправо.
Операция сдвига вправо в **Verilog** записывается оператором `>>`. Справа от оператора указывается число "отбрасываемых цифр", в нашем случае одна. Но постойте, в логике присваивания стоит оператор `<<`. Это ошибка, исправим ее!
Операция сдвига вправо в **SystemVerilog** записывается оператором `>>`. Справа от оператора указывается число "отбрасываемых цифр", в нашем случае одна. Но постойте, в логике присваивания стоит оператор `<<`. Это ошибка, исправим ее!
Повторяем моделирование.
@@ -294,7 +294,7 @@ max + min/2 = 4 + 3/2 = 4 + 1 = 5
В глаза сразу же бросается, что сигнал `max` внешне отличается от всех остальных — он ведет себя как однобитный сигнал. Если все остальные сигналы 32-разрядные, то и сигнал `max` должен быть таким же. Перейдем к объявлению этого сигнала, чтобы это исправить (нажав правой кнопкой мыши, и выбрав `Go To Source Code`):
```Verilog
```SystemVerilog
module vector_abs(
input [31:0] x,
input [31:0] y,
@@ -314,7 +314,7 @@ max + min/2 = 4 + 3/2 = 4 + 1 = 5
//...
```
Это странно, курсор был установлен на строку `.max(max)`, хотя раньше в этом случае курсор устанавливался на строку, где объявлялся выбранный сигнал. Но вот в чем дело, если мы просмотрим файл внимательно, то не обнаружим объявления сигнала вовсе. Как так вышло, что мы использовали необъявленный сигнал, а САПР не выдал нам ошибку? Дело в том, что стандарт [IEEE 1364-2005](https://ieeexplore.ieee.org/document/1620780) для языка **Verilog** допускает подобное использование необъявленного сигнала. В этом случае, синтезатор неявно создаст одноименный одноразрядный сигнал, что и произошло.
Это странно, курсор был установлен на строку `.max(max)`, хотя раньше в этом случае курсор устанавливался на строку, где объявлялся выбранный сигнал. Но вот в чем дело, если мы просмотрим файл внимательно, то не обнаружим объявления сигнала вовсе. Как так вышло, что мы использовали необъявленный сигнал, а САПР не выдал нам ошибку? Дело в том, что стандарт [IEEE 1364-2005](https://ieeexplore.ieee.org/document/1620780) для языка **SystemVerilog** допускает подобное использование необъявленного сигнала. В этом случае, синтезатор неявно создаст одноименный одноразрядный сигнал, что и произошло.
Для исправления этой ошибки, объявим сигнал `max` с корректной разрядностью и повторим моделирование.

View File

@@ -25,9 +25,9 @@
10. Удалить папку
11. Повторить все действия самостоятельно
## Создание модуля на Verilog
## Создание модуля на SystemVerilog
1. Создать новый Verilog файл, для этого в окне `Sources` нажать на кнопку `+`
1. Создать новый SystemVerilog файл, для этого в окне `Sources` нажать на кнопку `+`
2. В открывшемся окне выбрать `Add or create design source` → Нажать `Next`
3. Нажать `Create File`В открывшемся окне ввести имя модуля `top` и выбрать тип файла SystemVerilog → Нажать `OK`В оставшемся окне нажать `Finish`
4. В открывшемся окне НЕ вводить названия портов и сразу нажать OK → После чего подтвердить выбор `Yes`