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-описания) для контроллера светодиодов.
В первую очередь, здесь будет продублирована выдержка из спецификации на этот контроллер (общая часть раздела "[Описание контроллеров периферийных устройств](../../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
logic Y;
always @(*) begin
always_comb begin
case(S) // Описываем блок case, где значение сигнала S
// будет сравниваться с различными возможными его значениями
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-ти, расположенных вместе в форме крестовины). Семисегментные индикаторы в шестнадцатиричном формате отображают на левом блоке слагаемые А и В, а на правом - результат сложения. На светодиодах, расположенных над переключателями отображается результат в двоичном формате.
Управление сумматором через плату
![../../../.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` и ваше устройство прошьется.
Генерация битстрима
![../../../.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
(
.A (A),
.B (B),
.Pin (Pin),
.a_i (A),
.b_i (B),
.carry_i (Pin),
.S (S),
.Pout (Pout)
.sum_o (S),
.carry_o (Pout)
);
assign B = {24'b0,SW[7:0]};
@@ -127,4 +127,4 @@ always @(posedge CLK100) begin
end
end
endmodule
endmodule

View File

@@ -20,7 +20,7 @@
//////////////////////////////////////////////////////////////////////////////////
module tb_fulladder32();
`define __debug__
parameter TIME_OPERATION = 100;
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`
Управление АЛУ через плату
![../../../.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` и ваше устройство прошьется.
Генерация битстрима
![../../../.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
(
.ALUOp (operator_i),
.A (operand_a_i),
.B (operand_b_i),
.alu_op_i (operator_i),
.a_i (operand_a_i),
.b_i (operand_b_i),
.Result (result_o),
.Flag (comparison_result_o)
.result_o (result_o),
.flag_o (comparison_result_o)
);
assign operator_i = SW[4:0];
@@ -93,4 +93,4 @@ always @(posedge CLK100) begin
end
end
endmodule
endmodule

View File

@@ -60,6 +60,7 @@ reg [102:0] running_line;
initial
begin
running_line <= 0;
$display( "\nStart test: \n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop();
for ( i = 0; i < TEST_VALUES; i = i + 1 )
begin
@@ -10097,7 +10098,7 @@ initial line_dump = {
103'h3f27ac46eaaae4027700000000,
103'h16570085a76566615400000000,
103'h3cfd0b67e68d12a83e00000000,
103'h32d7053ffce4132de500000000,
103'hxxxxxxxxxxxxxxxxx000000000,
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-го байт. То что помимо значения третьего байта есть еще данные других байт нас в данный момент не интересует, важна только сама возможность указать адрес конкретного байта.
Деление на `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` — индекс последней ячейки памяти.
@@ -346,7 +346,7 @@ mоdulе rf_r𝚒sсv(
1. В `Design Sources` проекта создайте `SystemVerilog`-файл `rf_riscv.sv`.
2. Опишите в нем модуль регистрового файла с таким же именем и портами, как указано в задании.
1. Обратите внимание, что имя памяти (не название модуля, а имя объекта памяти внутри модуля) должно быть `rf_mem`. Такое имя необходимо для корректной работы верификационного окружения.
2. В отличии от памяти инструкций и данных, ячейки памяти регистрового файла должны быть 32-битными (а на 8-битными). Это означает, что реализация портов чтения и записи будет проще.
2. Как и у памяти инструкций, порты чтения регистрового файла должны быть **асинхронными**.
3. Не забывайте, что у вас 2 порта на чтение и 1 порт на запись, при этом каждый порт не зависит от остальных (в модуле 3 независимых входа адреса).
4. Чтение из нулевого регистра (чтение по адресу 0) всегда должно возвращать нулевое значение. Этого можно добиться двумя путями:
1. Путем добавления мультиплексора перед выходным сигналом чтения (мультиплексор будет определять, пойдут ли на выход данные из ячейки регистрового файла, либо в случае если адрес равен нулю, на выход пойдет константа ноль).

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,9 @@
module tb_data_mem();
parameter ADDR_SIZE = 4096;
parameter TIME_OPERATION = 50;
parameter ADDR_SIZE = 16384;
parameter TIME_OPERATION = 20;
parameter STEP = 8;
logic CLK;
logic REQ;
@@ -41,9 +42,7 @@ parameter TIME_OPERATION = 50;
);
logic [31:0] RDa;
integer i, err_count = 0;
assign A = i;
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();
REQ = 1;
WE = 0;
i = 1; #10;
i = 0; #10;
if (RD !== 32'hx) begin
$display("The data memory should not be initialized by the $readmemh function");
err_count = err_count + 1;
@@ -67,8 +66,8 @@ parameter TIME_OPERATION = 50;
WE = 1;
WD = $urandom;
end
for (i = 0; i < (ADDR_SIZE+1); i = i + 1) begin
if (i != (ADDR_SIZE+1)) begin
for (i = 0; i < (ADDR_SIZE+STEP); i = i + 1 + $urandom() % STEP) begin
if (i < (ADDR_SIZE)) begin
REQ = |($urandom %10);
WE = 0;
#TIME_OPERATION;
@@ -87,10 +86,11 @@ parameter TIME_OPERATION = 50;
end
end
else begin
WE = 0;
REQ = 1;
#TIME_OPERATION;
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;
end
end
@@ -98,29 +98,34 @@ parameter TIME_OPERATION = 50;
end
#TIME_OPERATION;
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;
i = 2;
#TIME_OPERATION;
if (RD !== 32'hba98_7654) begin
$display("data is being written to the cell incorrectly. RAM [0:7] must be 0x0123456789abcdef, time: %t", $time);
for (i = 0; i < 4; i = i + 1) begin
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;
end
#TIME_OPERATION;
end
@(posedge CLK)
i = 0;
i = 0; WE = 0; REQ = 1;
@(posedge 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);
err_count = err_count + 1;
end
@(posedge CLK); #5;
if (RD !== 32'h7654_3210) begin
$display("synchronous data memory read error, time: %t", $time);
@(posedge CLK);
i = {14{1'b1}};
repeat(2) @(posedge CLK);
if (RD === 'd3735928559) begin
$display("incorrect reading from address = %d, data = %h", A, RD);
err_count = err_count + 1;
end
$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 может обрабатывать файлы, содержащие комментарии (начинающиеся с `//`), пробелы и пустые строки, а так же наборы символов `0` и `1`. Комментарии, пробелы и пустые строки удаляются, после чего оставшиеся строки из 32 нулей и единиц нарезаются на четверки по 8 бит, конвертируются в шестнадцатиричные значения и записываются в выходной файл.
cyberconverter может обрабатывать файлы, содержащие комментарии (начинающиеся с `//`), пробелы и пустые строки, а так же наборы символов `0` и `1`. Комментарии, пробелы и пустые строки удаляются, после чего оставшиеся строки из 32 нулей и единиц конвертируются в шестнадцатиричные значения и записываются в выходной файл.
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 << "whitespaces and binary digits '0' or '1'.\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 << "will be produced.\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;
return -2;
}
// split 32-bits binary line into 4 little-endian hex lines and write them into file
for (size_t i = 0; i < 4; i++)
// Convert into hex lines and write them into file
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.
// If illegal character found, throw error.
size_t valid_char_num;
string byte_substr = str.substr(8*(3-i), 8);
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";
cerr << "Illegal character '" << str.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[9];
// convert int representation into hex string
snprintf(hex_byte_str, 9, "%08x", cur_word);
ofs << hex_byte_str << "\n";
}
ifs.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/)
- [Список типичных ошибок в Vivado и SystemVerilog](../Other/FAQ.md)
- [Тестовое окружение](../Basic%20Verilog%20structures/Testbench.md)
- [Готовые модули](Made-up%20modules)
## Порядок выполнения лабораторных работ для групп