Merge branch 'master' of github.com:MPSU/APS-reborn

This commit is contained in:
Andrei Solodovnikov
2023-09-22 10:04:56 +03:00
22 changed files with 7787 additions and 10458 deletions

View File

@@ -2,7 +2,7 @@
Для того, чтобы лучше понять, что от вас требуется в рамках лабораторной работы по периферийным устройствам, рассмотрим процесс разработки структурной схемы (не SystemVerilog-описания) для контроллера светодиодов. Для того, чтобы лучше понять, что от вас требуется в рамках лабораторной работы по периферийным устройствам, рассмотрим процесс разработки структурной схемы (не SystemVerilog-описания) для контроллера светодиодов.
В первую очередь, здесь будет продублирована выдержка из спецификации на этот контроллер (общая часть раздела "[Описание контроллеров периферийных устройств](../../Labs/7.%20Peripheral%20units/README.md#описание-контроллеров-периферийных-устройств)", а также подраздел "[Светодиоды](../../Labs/7.%20Peripheral%20units/README.md#светодиоды)"): В первую очередь, здесь будет продублирована выдержка из спецификации на этот контроллер (общая часть раздела "[Описание контроллеров периферийных устройств](../Labs/12.%20Peripheral%20units/README.md#описание-контроллеров-периферийных-устройств)", а также подраздел "[Светодиоды](../Labs/12.%20Peripheral%20units/README.md#светодиоды)"):
## Спецификация контроллера ## Спецификация контроллера

View File

@@ -124,7 +124,7 @@ end
```SystemVerilog ```SystemVerilog
logic Y; logic Y;
always @(*) begin always_comb begin
case(S) // Описываем блок case, где значение сигнала S case(S) // Описываем блок case, где значение сигнала S
// будет сравниваться с различными возможными его значениями // будет сравниваться с различными возможными его значениями
1'b0: Y <= D0; // Если S==0, то Y = D0 1'b0: Y <= D0; // Если S==0, то Y = D0

View File

@@ -4,20 +4,20 @@
После этого наше устройство будет выглядеть так: После этого наше устройство будет выглядеть так:
![../../../.pic/Labs/board%20files/board%20files/nexys_adder1.png](../../../.pic/Labs/board%20files/board%20files/nexys_adder1.png) ![../../../.pic/Labs/board%20files/nexys_adder1.png](../../../.pic/Labs/board%20files/nexys_adder1.png)
Подключенное окружение позволяет производить ввод входных значений (А, В и Pin) с помощью переключателей (номер переключателя отображен на самом краю платы), расположенных на плате. Операнд А задается переключателями 15-8, В: 7-0, Pin: тактовая кнопка BTND (нижняя из 5-ти, расположенных вместе в форме крестовины). Семисегментные индикаторы в шестнадцатиричном формате отображают на левом блоке слагаемые А и В, а на правом - результат сложения. На светодиодах, расположенных над переключателями отображается результат в двоичном формате. Подключенное окружение позволяет производить ввод входных значений (А, В и Pin) с помощью переключателей (номер переключателя отображен на самом краю платы), расположенных на плате. Операнд А задается переключателями 15-8, В: 7-0, Pin: тактовая кнопка BTND (нижняя из 5-ти, расположенных вместе в форме крестовины). Семисегментные индикаторы в шестнадцатиричном формате отображают на левом блоке слагаемые А и В, а на правом - результат сложения. На светодиодах, расположенных над переключателями отображается результат в двоичном формате.
Управление сумматором через плату Управление сумматором через плату
![../../../.pic/Labs/board%20files/board%20files/nexys_adder2.png](../../../.pic/Labs/board%20files/board%20files/nexys_adder2.png) ![../../../.pic/Labs/board%20files/nexys_adder2.png](../../../.pic/Labs/board%20files/nexys_adder2.png)
Для прошивки ПЛИС подключите утройство через USB, включите питание переключателем, выполните синтез и имплементацию вашего дизайна и сгенерируйте битстрим. Если на этом этапе у вас возникают ошибки, постарайтесь исправить из с помощью [`инструкции по работе с ошибками синтеза`](../../../Vivado%20Basics/Elaboration%20failed.md). После этого выберите в левом меню `Open Target` - `Auto Connect`, затем `Program Device` и ваше устройство прошьется. Для прошивки ПЛИС подключите утройство через USB, включите питание переключателем, выполните синтез и имплементацию вашего дизайна и сгенерируйте битстрим. Если на этом этапе у вас возникают ошибки, постарайтесь исправить из с помощью [`инструкции по работе с ошибками синтеза`](../../../Vivado%20Basics/Elaboration%20failed.md). После этого выберите в левом меню `Open Target` - `Auto Connect`, затем `Program Device` и ваше устройство прошьется.
Генерация битстрима Генерация битстрима
![../../../.pic/Labs/board%20files/board%20files/Program_Device1.png](../../../.pic/Labs/board%20files/board%20files/Program_Device1.png) ![../../../.pic/Labs/board%20files/Program_Device1.png](../../../.pic/Labs/board%20files/Program_Device1.png)
Прошивка ПЛИС Прошивка ПЛИС
![../../../.pic/Labs/board%20files/board%20files/Program_Device2.png](../../../.pic/Labs/board%20files/board%20files/Program_Device2.png) ![../../../.pic/Labs/board%20files/Program_Device2.png](../../../.pic/Labs/board%20files/Program_Device2.png)
Попробуйте выставить на переключателях различные слагаемые, убедитесь, что все работает исправно и сдавайте работу. Попробуйте выставить на переключателях различные слагаемые, убедитесь, что все работает исправно и сдавайте работу.

View File

@@ -30,12 +30,12 @@ reg [15:0] LEDr;
fulladder32 DUT fulladder32 DUT
( (
.A (A), .a_i (A),
.B (B), .b_i (B),
.Pin (Pin), .carry_i (Pin),
.S (S), .sum_o (S),
.Pout (Pout) .carry_o (Pout)
); );
assign B = {24'b0,SW[7:0]}; assign B = {24'b0,SW[7:0]};

View File

@@ -20,7 +20,7 @@
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
module tb_fulladder32(); module tb_fulladder32();
`define __debug__
parameter TIME_OPERATION = 100; parameter TIME_OPERATION = 100;
parameter TEST_VALUES = 3000; parameter TEST_VALUES = 3000;

View File

@@ -4,20 +4,20 @@
После этого наше устройство будет выглядеть так: После этого наше устройство будет выглядеть так:
![../../../.pic/Labs/board%20files/board%20files/alu_9.png](../../../.pic/Labs/board%20files/board%20files/alu_9.png) ![../../../.pic/Labs/board%20files/alu_9.png](../../../.pic/Labs/board%20files/alu_9.png)
Подключенное окружение позволяет производить ввод входных значений (А и В) и управляющего сигнала (ALUOp) с помощью переключателей (номер переключателя отображен на самом краю платы), расположенных на плате. А: 15-11, В: 10-6, ALUOp: 4-0, а переключатель №5 активирует семисегментные индикаторы, на которых отображается на левом блоке операнды А и В, а на правом - ALUOp. На светодиодах, расположенных над переключателями отображается выходное значение в двоичном формате, а 15-й светодиод отвечает за сигнал `Flag` Подключенное окружение позволяет производить ввод входных значений (А и В) и управляющего сигнала (ALUOp) с помощью переключателей (номер переключателя отображен на самом краю платы), расположенных на плате. А: 15-11, В: 10-6, ALUOp: 4-0, а переключатель №5 активирует семисегментные индикаторы, на которых отображается на левом блоке операнды А и В, а на правом - ALUOp. На светодиодах, расположенных над переключателями отображается выходное значение в двоичном формате, а 15-й светодиод отвечает за сигнал `Flag`
Управление АЛУ через плату Управление АЛУ через плату
![../../../.pic/Labs/board%20files/board%20files/nexys_alu.png](../../../.pic/Labs/board%20files/board%20files/nexys_alu.png) ![../../../.pic/Labs/board%20files/nexys_alu.png](../../../.pic/Labs/board%20files/nexys_alu.png)
Для прошивки ПЛИС подключите утройство через USB, включите питание переключателем, выполните синтез и имплементацию вашего дизайна и сгенерируйте битстрим. Если на этом этапе у вас возникают ошибки, постарайтесь исправить из с помощью [`инструкции по работе с ошибками синтеза`](../../../Vivado%20Basics/Synthesis%20failed.md). После этого выберите в левом меню `Open Target` - `Auto Connect`, затем `Program Device` и ваше устройство прошьется. Для прошивки ПЛИС подключите утройство через USB, включите питание переключателем, выполните синтез и имплементацию вашего дизайна и сгенерируйте битстрим. Если на этом этапе у вас возникают ошибки, постарайтесь исправить из с помощью [`инструкции по работе с ошибками синтеза`](../../../Vivado%20Basics/Synthesis%20failed.md). После этого выберите в левом меню `Open Target` - `Auto Connect`, затем `Program Device` и ваше устройство прошьется.
Генерация битстрима Генерация битстрима
![../../../.pic/Labs/board%20files/board%20files/Program_Device1.png](../../../.pic/Labs/board%20files/board%20files/Program_Device1.png) ![../../../.pic/Labs/board%20files/Program_Device1.png](../../../.pic/Labs/board%20files/Program_Device1.png)
Прошивка ПЛИС Прошивка ПЛИС
![../../../.pic/Labs/board%20files/board%20files/Program_Device2.png](../../../.pic/Labs/board%20files/board%20files/Program_Device2.png) ![../../../.pic/Labs/board%20files/Program_Device2.png](../../../.pic/Labs/board%20files/Program_Device2.png)
Попробуйте выставить на переключателях различные опкоды, такие как сложение, вычитание, сдвиг и сравнения, убедитесь, что все работает исправно и сдавайте работу. Попробуйте выставить на переключателях различные опкоды, такие как сложение, вычитание, сдвиг и сравнения, убедитесь, что все работает исправно и сдавайте работу.

View File

@@ -26,12 +26,12 @@ reg minus;
alu_riscv DUT alu_riscv DUT
( (
.ALUOp (operator_i), .alu_op_i (operator_i),
.A (operand_a_i), .a_i (operand_a_i),
.B (operand_b_i), .b_i (operand_b_i),
.Result (result_o), .result_o (result_o),
.Flag (comparison_result_o) .flag_o (comparison_result_o)
); );
assign operator_i = SW[4:0]; assign operator_i = SW[4:0];

View File

@@ -60,6 +60,7 @@ reg [102:0] running_line;
initial initial
begin begin
running_line <= 0;
$display( "\nStart test: \n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop(); $display( "\nStart test: \n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop();
for ( i = 0; i < TEST_VALUES; i = i + 1 ) for ( i = 0; i < TEST_VALUES; i = i + 1 )
begin begin
@@ -10097,7 +10098,7 @@ initial line_dump = {
103'h3f27ac46eaaae4027700000000, 103'h3f27ac46eaaae4027700000000,
103'h16570085a76566615400000000, 103'h16570085a76566615400000000,
103'h3cfd0b67e68d12a83e00000000, 103'h3cfd0b67e68d12a83e00000000,
103'h32d7053ffce4132de500000000, 103'hxxxxxxxxxxxxxxxxx000000000,
103'h073ec21038e11e95ca00000000 103'h073ec21038e11e95ca00000000
}; };

View File

@@ -230,7 +230,7 @@ mоdulе instr_mеm(
Однако, если у памяти будут 32-рязрядные ячейки, доступ к конкретному байту будет осложнен, ведь каждая ячейка — это 4 байта. Как получить данные третьего байта памяти? Если обратиться к третьей ячейке в массиве — придут данные 12-15-ых байт байт (поскольку каждая ячейка содержит по 4 байта). Чтобы получить данные третьего байта, необходимо разделить пришедший адрес на 4 (отбросив остаток от деления). `3 / 4 = 0` — и действительно, если обратиться к нулевой ячейке памяти — будут получены данные 3-го, 2-го, 1-го и 0-го байт. То что помимо значения третьего байта есть еще данные других байт нас в данный момент не интересует, важна только сама возможность указать адрес конкретного байта. Однако, если у памяти будут 32-рязрядные ячейки, доступ к конкретному байту будет осложнен, ведь каждая ячейка — это 4 байта. Как получить данные третьего байта памяти? Если обратиться к третьей ячейке в массиве — придут данные 12-15-ых байт байт (поскольку каждая ячейка содержит по 4 байта). Чтобы получить данные третьего байта, необходимо разделить пришедший адрес на 4 (отбросив остаток от деления). `3 / 4 = 0` — и действительно, если обратиться к нулевой ячейке памяти — будут получены данные 3-го, 2-го, 1-го и 0-го байт. То что помимо значения третьего байта есть еще данные других байт нас в данный момент не интересует, важна только сама возможность указать адрес конкретного байта.
Деление на `2<sup>n</sup>` можно осуществить отбросив `n` младших бит числа. Таким образом на выход память инструкций должна выдавать данные, расположенные по адресу addr_i[31:2]; Деление на 2<sup>n</sup> можно осуществить отбросив `n` младших бит числа. Таким образом на выход память инструкций должна выдавать данные, расположенные по адресу addr_i[31:2];
Обращение в память по адресам, превышающим `4095` должно выдавать значение `32'd0`. Почему именно `4095`? `4095 / 4 = 1023` — индекс последней ячейки памяти. Обращение в память по адресам, превышающим `4095` должно выдавать значение `32'd0`. Почему именно `4095`? `4095 / 4 = 1023` — индекс последней ячейки памяти.
@@ -346,7 +346,7 @@ mоdulе rf_r𝚒sсv(
1. В `Design Sources` проекта создайте `SystemVerilog`-файл `rf_riscv.sv`. 1. В `Design Sources` проекта создайте `SystemVerilog`-файл `rf_riscv.sv`.
2. Опишите в нем модуль регистрового файла с таким же именем и портами, как указано в задании. 2. Опишите в нем модуль регистрового файла с таким же именем и портами, как указано в задании.
1. Обратите внимание, что имя памяти (не название модуля, а имя объекта памяти внутри модуля) должно быть `rf_mem`. Такое имя необходимо для корректной работы верификационного окружения. 1. Обратите внимание, что имя памяти (не название модуля, а имя объекта памяти внутри модуля) должно быть `rf_mem`. Такое имя необходимо для корректной работы верификационного окружения.
2. В отличии от памяти инструкций и данных, ячейки памяти регистрового файла должны быть 32-битными (а на 8-битными). Это означает, что реализация портов чтения и записи будет проще. 2. Как и у памяти инструкций, порты чтения регистрового файла должны быть **асинхронными**.
3. Не забывайте, что у вас 2 порта на чтение и 1 порт на запись, при этом каждый порт не зависит от остальных (в модуле 3 независимых входа адреса). 3. Не забывайте, что у вас 2 порта на чтение и 1 порт на запись, при этом каждый порт не зависит от остальных (в модуле 3 независимых входа адреса).
4. Чтение из нулевого регистра (чтение по адресу 0) всегда должно возвращать нулевое значение. Этого можно добиться двумя путями: 4. Чтение из нулевого регистра (чтение по адресу 0) всегда должно возвращать нулевое значение. Этого можно добиться двумя путями:
1. Путем добавления мультиплексора перед выходным сигналом чтения (мультиплексор будет определять, пойдут ли на выход данные из ячейки регистрового файла, либо в случае если адрес равен нулю, на выход пойдет константа ноль). 1. Путем добавления мультиплексора перед выходным сигналом чтения (мультиплексор будет определять, пойдут ли на выход данные из ячейки регистрового файла, либо в случае если адрес равен нулю, на выход пойдет константа ноль).

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,9 @@
module tb_data_mem(); module tb_data_mem();
parameter ADDR_SIZE = 4096; parameter ADDR_SIZE = 16384;
parameter TIME_OPERATION = 50; parameter TIME_OPERATION = 20;
parameter STEP = 8;
logic CLK; logic CLK;
logic REQ; logic REQ;
@@ -41,9 +42,7 @@ parameter TIME_OPERATION = 50;
); );
logic [31:0] RDa; logic [31:0] RDa;
integer i, err_count = 0; integer i, err_count = 0;
assign A = i; assign A = i;
parameter CLK_FREQ_MHz = 100; parameter CLK_FREQ_MHz = 100;
@@ -57,7 +56,7 @@ parameter TIME_OPERATION = 50;
$display( "\nStart test: \n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop(); $display( "\nStart test: \n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop();
REQ = 1; REQ = 1;
WE = 0; WE = 0;
i = 1; #10; i = 0; #10;
if (RD !== 32'hx) begin if (RD !== 32'hx) begin
$display("The data memory should not be initialized by the $readmemh function"); $display("The data memory should not be initialized by the $readmemh function");
err_count = err_count + 1; err_count = err_count + 1;
@@ -67,8 +66,8 @@ parameter TIME_OPERATION = 50;
WE = 1; WE = 1;
WD = $urandom; WD = $urandom;
end end
for (i = 0; i < (ADDR_SIZE+1); i = i + 1) begin for (i = 0; i < (ADDR_SIZE+STEP); i = i + 1 + $urandom() % STEP) begin
if (i != (ADDR_SIZE+1)) begin if (i < (ADDR_SIZE)) begin
REQ = |($urandom %10); REQ = |($urandom %10);
WE = 0; WE = 0;
#TIME_OPERATION; #TIME_OPERATION;
@@ -87,10 +86,11 @@ parameter TIME_OPERATION = 50;
end end
end end
else begin else begin
WE = 0;
REQ = 1; REQ = 1;
#TIME_OPERATION; #TIME_OPERATION;
if (RD !== 32'd3735928559) begin if (RD !== 32'd3735928559) begin
$display("When reading (write_enable_i = %h) at an address greater than 4095, it should return dead_beef yor data: %h_%h, time: %t", WE, RD[31:16],RD[15:0], $time); $display("When reading (write_enable_i = %h) at address greater than 16383 (current addr = %d), it should return dead_beef, but your data: %h_%h, time: %t", WE, A, RD[31:16],RD[15:0], $time);
err_count = err_count + 1; err_count = err_count + 1;
end end
end end
@@ -98,29 +98,34 @@ parameter TIME_OPERATION = 50;
end end
#TIME_OPERATION; #TIME_OPERATION;
REQ = 1; REQ = 1;
WE = 1;
#TIME_OPERATION;
for (i = 0; i < 8; i = i + 4) begin
WD = i? 32'hfecd_ba98: 32'h7654_3210;
#TIME_OPERATION;
end
WE = 0; WE = 0;
i = 2;
#TIME_OPERATION; #TIME_OPERATION;
if (RD !== 32'hba98_7654) begin for (i = 0; i < 4; i = i + 1) begin
$display("data is being written to the cell incorrectly. RAM [0:7] must be 0x0123456789abcdef, time: %t", $time); if(i==0) begin
repeat(2)@(posedge CLK);
#1; RDa = RD;
end else
if(RD !== RDa) begin
$display("incorrect conversion of the reading address = %h, time: %t", A, $time);
err_count = err_count + 1; err_count = err_count + 1;
end
#TIME_OPERATION;
end end
@(posedge CLK) i = 0; WE = 0; REQ = 1;
i = 0; @(posedge CLK);
@(negedge CLK); @(negedge CLK);
if (RD !== 32'hba98_7654) begin i = 4;
#1; RDa = RD;
@(posedge CLK); #1;
if (RD == RDa) begin
$display("reading from data memory must be synchronous, time: %t", $time); $display("reading from data memory must be synchronous, time: %t", $time);
err_count = err_count + 1; err_count = err_count + 1;
end end
@(posedge CLK); #5; @(posedge CLK);
if (RD !== 32'h7654_3210) begin i = {14{1'b1}};
$display("synchronous data memory read error, time: %t", $time); repeat(2) @(posedge CLK);
if (RD === 'd3735928559) begin
$display("incorrect reading from address = %d, data = %h", A, RD);
err_count = err_count + 1; err_count = err_count + 1;
end end
$display("Number of errors: %d", err_count); $display("Number of errors: %d", err_count);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -144,7 +144,7 @@
[cyberconverter](cyberconverter.cpp) — это программа, которая преобразует текстовый файл с инструкциями архитектуры CYBERcobra в текстовый файл, который сможет принять память инструкций. [cyberconverter](cyberconverter.cpp) — это программа, которая преобразует текстовый файл с инструкциями архитектуры CYBERcobra в текстовый файл, который сможет принять память инструкций.
cyberconverter может обрабатывать файлы, содержащие комментарии (начинающиеся с `//`), пробелы и пустые строки, а так же наборы символов `0` и `1`. Комментарии, пробелы и пустые строки удаляются, после чего оставшиеся строки из 32 нулей и единиц нарезаются на четверки по 8 бит, конвертируются в шестнадцатиричные значения и записываются в выходной файл. cyberconverter может обрабатывать файлы, содержащие комментарии (начинающиеся с `//`), пробелы и пустые строки, а так же наборы символов `0` и `1`. Комментарии, пробелы и пустые строки удаляются, после чего оставшиеся строки из 32 нулей и единиц конвертируются в шестнадцатиричные значения и записываются в выходной файл.
cyberconverter принимает до двух аргументов. Порядок запуска следующий: cyberconverter принимает до двух аргументов. Порядок запуска следующий:

View File

@@ -12,7 +12,7 @@ void print_help(const std::string program_name)
cout << "CYBERcobra program file may contain only comments (starting with \"//\"),\n"; cout << "CYBERcobra program file may contain only comments (starting with \"//\"),\n";
cout << "whitespaces and binary digits '0' or '1'.\n"; cout << "whitespaces and binary digits '0' or '1'.\n";
cout << "This program will erase this parts from every line and then convert\n"; cout << "This program will erase this parts from every line and then convert\n";
cout << "32-bits binary strings into 4 little endian 8-bit strings in hex-format.\n\n"; cout << "in hex-format.\n\n";
cout << "If output file omitted, the <input_file_base>_converted.<input_file_ext>\n"; cout << "If output file omitted, the <input_file_base>_converted.<input_file_ext>\n";
cout << "will be produced.\n\n"; cout << "will be produced.\n\n";
cout << "If input file omitted, program.txt will be used.\n\n"; cout << "If input file omitted, program.txt will be used.\n\n";
@@ -109,26 +109,20 @@ int main(int argc, char ** argv)
cerr << "line " << line_counter << " length is not equal 32 after trimming comments and whitespaces" << endl; cerr << "line " << line_counter << " length is not equal 32 after trimming comments and whitespaces" << endl;
return -2; return -2;
} }
// split 32-bits binary line into 4 little-endian hex lines and write them into file // Convert into hex lines and write them into file
for (size_t i = 0; i < 4; i++) size_t valid_char_num;
uint32_t cur_word = std::stoll(str, &valid_char_num, 2);
if(valid_char_num != 32)
{ {
// For every 8-bit part of 32-bit line get int representation. cerr << "Illegal character '" << str.at(valid_char_num) <<
// If illegal character found, throw error. "' found in line " << line_counter << ": \"" << str << "\"\n";
size_t valid_char_num; cerr << "Should be only '0' or '1'." << endl;
string byte_substr = str.substr(8*(3-i), 8); return -3;
int cur_byte = std::stoi(byte_substr, &valid_char_num, 2);
if(valid_char_num != 8)
{
cerr << "Illegal character '" << byte_substr.at(valid_char_num) <<
"' found in line " << line_counter << ": \"" << str << "\"\n";
cerr << "Should be only '0' or '1'." << endl;
return -3;
}
char hex_byte_str[3];
// convert int representation into hex string
snprintf(hex_byte_str, 3, "%02x", cur_byte);
ofs << hex_byte_str << "\n";
} }
char hex_byte_str[9];
// convert int representation into hex string
snprintf(hex_byte_str, 9, "%08x", cur_word);
ofs << hex_byte_str << "\n";
} }
ifs.close(); ifs.close();
ofs.close(); ofs.close();

View File

@@ -0,0 +1,7 @@
# Заготовленные модули
Все лабораторные работы курса построены по последовательному принципу: модули предыдущих лабораторных работ используются для описания модулей следующих лабораторных работ.
Это приводит к тому, что нельзя выполнить очередную лабу, не выполнив все предыдущие. В случае, если нужен модуль из лабы, которой нет в учебном плане, либо по какой-то причине вы не появились на лабораторном занятии / не успели сделать лабу, у вас всё ещё остается возможность продолжить обучение. Для этого, вы можете воспользоваться реализациями модулей из данной папки.
Обратите внимание на то, что реализации этих модулей неоптимальны, странны и намеренным образом сделаны так, чтобы было тяжело разобраться в принципе их работы. Это сделано для того, чтобы сохранить таинство выполнения соответствующей этому модулю лабы и разумеется ни один из этих модулей не может использоваться на защите лабораторной работы, посвященной этому модулю.

View File

@@ -0,0 +1,11 @@
module fulladder32(
input logic [31:0] a_i,
input logic [31:0] b_i,
input logic carry_i,
output logic [31:0] sum_o,
output logic carry_o
);
assign {carry_o, sum_o} = a_i + b_i + carry_i;
endmodule

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
module data_mem (
input logic clk_i,
input logic [31:0] addr_i,
input logic [31:0] write_data_i,
input logic write_enable_i,
input logic mem_req_i,
output logic [31:0] read_data_o
);
`define akjsdnnaskjdndat $clog2(128)
`define cdyfguvhbjnmkdat $clog2(`akjsdnnaskjdndat)
`define qwenklfsaklasddat $clog2(`cdyfguvhbjnmkdat)
`define asdasdhkjasdsadat (34>>`cdyfguvhbjnmkdat)
logic [31:0] RAM [0:4095];
logic [31:0] addr;
assign addr = {2'b0, addr_i[31:2]};
always_ff @(posedge clk_i) begin
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}] <= write_data_i['h1f:'h1c];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}] <= write_data_i[42-23-:`asdasdhkjasdsadat];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}] <= write_data_i[`akjsdnnaskjdndat-:`asdasdhkjasdsadat];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}] <= write_data_i[42-19-:`asdasdhkjasdsadat];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}] <= write_data_i['h1b:'h18];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][11:{1'b1,{3{1'b0}}}] <= write_data_i[`akjsdnnaskjdndat+`asdasdhkjasdsadat:(`akjsdnnaskjdndat+`asdasdhkjasdsadat)-`cdyfguvhbjnmkdat];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{2{1'b1}}:{3{1'b0}}] <= write_data_i[`akjsdnnaskjdndat-`asdasdhkjasdsadat-:`asdasdhkjasdsadat];
if(write_enable_i&mem_req_i) RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:4'b1100] <= write_data_i[(`akjsdnnaskjdndat<<(`asdasdhkjasdsadat-`cdyfguvhbjnmkdat)) + (`asdasdhkjasdsadat-`cdyfguvhbjnmkdat):12];
end
always_ff@(posedge clk_i) begin
case(1)
!mem_req_i||write_enable_i: read_data_o <= 'd4195425967;
mem_req_i&&(addr_i<={14{1'b1}}): begin
read_data_o['h1f:'h1c]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}];
read_data_o[42-23-:`asdasdhkjasdsadat]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}];
read_data_o[`akjsdnnaskjdndat-:`asdasdhkjasdsadat]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}];
read_data_o[42-19-:`asdasdhkjasdsadat]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}];
read_data_o['h1b:'h18]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}];
read_data_o[`akjsdnnaskjdndat+`asdasdhkjasdsadat:(`akjsdnnaskjdndat+`asdasdhkjasdsadat)-`cdyfguvhbjnmkdat]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][11:8];
read_data_o[`akjsdnnaskjdndat-`asdasdhkjasdsadat-:`asdasdhkjasdsadat]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][3:0];
read_data_o[(`akjsdnnaskjdndat<<(`asdasdhkjasdsadat-`cdyfguvhbjnmkdat))+(`asdasdhkjasdsadat-`cdyfguvhbjnmkdat):12]<=RAM[addr[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:12];
end
default: read_data_o <= 'd3735928559;
endcase
end
endmodule

View File

@@ -0,0 +1,29 @@
module instr_mem(
input logic [31:0] addr_i,
output logic [31:0] read_data_o
);
`define akjsdnnaskjdn $clog2(128)
`define cdyfguvhbjnmk $clog2(`akjsdnnaskjdn)
`define qwenklfsaklasd $clog2(`cdyfguvhbjnmk)
`define asdasdhkjasdsa (34 >> `cdyfguvhbjnmk)
reg [31:0] RAM [0:1023];
initial $readmemh("program.txt", RAM);
always_comb begin
case(addr_i > {12{1'b1}})
0: begin
read_data_o['h1f:'h1c]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][{5{1'b1}}:{3'd7,2'b00}];
read_data_o[42-23-:`asdasdhkjasdsa]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][19:{1'b1,4'h0}];
read_data_o[`akjsdnnaskjdn-:`asdasdhkjasdsa]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][{3{1'b1}}:{1'b1,2'h0}];
read_data_o[42-19-:`asdasdhkjasdsa]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][23:{{2{2'b10}},1'b0}];
read_data_o['h1b:'h18]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][27:{2'b11,3'b000}];
read_data_o[`akjsdnnaskjdn+`asdasdhkjasdsa:(`akjsdnnaskjdn+`asdasdhkjasdsa)-`cdyfguvhbjnmk]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][11:8];
read_data_o[`akjsdnnaskjdn-`asdasdhkjasdsa-:`asdasdhkjasdsa]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][3:0];
read_data_o[(`akjsdnnaskjdn<<(`asdasdhkjasdsa-`cdyfguvhbjnmk)) + (`asdasdhkjasdsa-`cdyfguvhbjnmk):12 ]=RAM[{2'b00, addr_i[{5{1'b1}}:2]}][{4{1'b1}}:12];
end
default: read_data_o = 'hBA & 'h45;
endcase
end
endmodule

View File

@@ -0,0 +1,63 @@
module rf_riscv(
input logic clk_i,
input logic write_enable_i,
input logic [ 4:0] write_addr_i,
input logic [ 4:0] read_addr1_i,
input logic [ 4:0] read_addr2_i,
input logic [31:0] write_data_i,
output logic [31:0] read_data1_o,
output logic [31:0] read_data2_o
);
`define akjsdnnaskjdnreg $clog2(128)
`define cdyfguvhbjnmkreg $clog2(`akjsdnnaskjdnreg)
`define qwenklfsaklasdreg $clog2(`cdyfguvhbjnmkreg)
`define asdasdhkjasdsareg (34 >> `cdyfguvhbjnmkreg)
logic [(`asdasdhkjasdsareg<<`qwenklfsaklasdreg)+15:0] rf_mem [`asdasdhkjasdsareg*8];
always_ff @(posedge clk_i) begin
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}] <= write_data_i['h1f:'h1c];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}] <= write_data_i[42-23-:`asdasdhkjasdsareg];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}] <= write_data_i[`akjsdnnaskjdnreg-:`asdasdhkjasdsareg];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}] <= write_data_i[42-19-:`asdasdhkjasdsareg];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}] <= write_data_i['h1b:'h18];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][11:{1'b1,{3{1'b0}}}] <= write_data_i[`akjsdnnaskjdnreg+`asdasdhkjasdsareg:(`akjsdnnaskjdnreg+`asdasdhkjasdsareg)-`cdyfguvhbjnmkreg];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{2{1'b1}}:{3{1'b0}}] <= write_data_i[`akjsdnnaskjdnreg-`asdasdhkjasdsareg-:`asdasdhkjasdsareg];
if(write_enable_i) rf_mem[write_addr_i[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:4'b1100] <= write_data_i[(`akjsdnnaskjdnreg<<(`asdasdhkjasdsareg-`cdyfguvhbjnmkreg)) + (`asdasdhkjasdsareg-`cdyfguvhbjnmkreg):12];
end
always_comb begin
case(read_addr1_i === ('hBA & 'h45))
0: begin
read_data1_o['h1f:'h1c]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}];
read_data1_o[42-23-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}];
read_data1_o[`akjsdnnaskjdnreg-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}];
read_data1_o[42-19-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}];
read_data1_o['h1b:'h18]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}];
read_data1_o[`akjsdnnaskjdnreg+`asdasdhkjasdsareg:(`akjsdnnaskjdnreg+`asdasdhkjasdsareg)-`cdyfguvhbjnmkreg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][11:8];
read_data1_o[`akjsdnnaskjdnreg-`asdasdhkjasdsareg-:`asdasdhkjasdsareg]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][3:0];
read_data1_o[(`akjsdnnaskjdnreg<<(`asdasdhkjasdsareg-`cdyfguvhbjnmkreg)) + (`asdasdhkjasdsareg-`cdyfguvhbjnmkreg):12 ]=rf_mem[read_addr1_i[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:12];
end
default: read_data1_o = 'hBA & 'h45;
endcase
end
always_comb begin
case(read_addr2_i === ('hBA & 'h45))
0: begin
read_data2_o['h1f:'h1c]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][{5{1'b1}}:{3'd7,2'b00}];
read_data2_o[42-23-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][19:{1'b1,4'h0}];
read_data2_o[`akjsdnnaskjdnreg-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][{3{1'b1}}:{1'b1,2'h0}];
read_data2_o[42-19-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][23:{{2{2'b10}},1'b0}];
read_data2_o['h1b:'h18]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][27:{2'b11,3'b000}];
read_data2_o[`akjsdnnaskjdnreg+`asdasdhkjasdsareg:(`akjsdnnaskjdnreg+`asdasdhkjasdsareg)-`cdyfguvhbjnmkreg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][11:8];
read_data2_o[`akjsdnnaskjdnreg-`asdasdhkjasdsareg-:`asdasdhkjasdsareg]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][3:0];
read_data2_o[(`akjsdnnaskjdnreg<<(`asdasdhkjasdsareg-`cdyfguvhbjnmkreg)) + (`asdasdhkjasdsareg-`cdyfguvhbjnmkreg):12 ]=rf_mem[read_addr2_i[{1'b1,2'b0}:'hBA & 'h45]][{4{1'b1}}:12];
end
default: read_data2_o = 'hBA & 'h45;
endcase
end
endmodule

View File

@@ -31,6 +31,7 @@
- [Базовые конструкции Verilog](../Basic%20Verilog%20structures/) - [Базовые конструкции Verilog](../Basic%20Verilog%20structures/)
- [Список типичных ошибок в Vivado и SystemVerilog](../Other/FAQ.md) - [Список типичных ошибок в Vivado и SystemVerilog](../Other/FAQ.md)
- [Тестовое окружение](../Basic%20Verilog%20structures/Testbench.md) - [Тестовое окружение](../Basic%20Verilog%20structures/Testbench.md)
- [Готовые модули](Made-up%20modules)
## Порядок выполнения лабораторных работ для групп ## Порядок выполнения лабораторных работ для групп