import memory_pkg::INSTR_MEM_SIZE_BYTES;
import memory_pkg::INSTR_MEM_SIZE_WORDS;
module CYBERcobra (
input logic clk_i,
input logic rst_i,
input logic [15:0] sw_i,
output logic [31:0] out_o
);
// --- Сигналы ---
// Основные регистры и провода
logic [31:0] pc, next_pc;
logic [31:0] instr;
logic [31:0] alu_res, write_data;
logic [31:0] rd1, rd2;
logic [31:0] alu_B;
logic [31:0] se_const; // Знаково-расширенная константа
logic flag;
// Выходы декодера
logic J, B, WE;
logic [1:0] WS;
logic [4:0] alu_op;
logic [4:0] RA1, RA2, WA;
logic [7:0] offset;
logic [22:0] imm_field; // <--- ВОТ! ОБЪЯВЛЯЕМ ПРАВИЛЬНО! 23 бита!
// --- 1. Счётчик команд (PC) ---
always_ff @(posedge clk_i, posedge rst_i) begin
if (rst_i)
pc <= 32'd0;
else
pc <= next_pc;
end
// --- 2. Память Инструкций (Instruction Memory) ---
instr_mem imem (
.read_addr_i(pc),
.read_data_o(instr)
);
// --- 3. Декодер ---
// Нарезает инструкцию на управляющие сигналы. Наводим порядок!
assign J = instr[31];
assign B = instr[30];
assign WS = instr[29:28];
assign alu_op = instr[27:23];
assign RA1 = instr[22:18];
assign RA2 = instr[17:13];
assign imm_field = instr[22:0]; // <--- ПРЕДПОЛОЖЕНИЕ! СВЕРЬСЯ С МЕТОДИЧКОЙ!
// Поле immediate обычно начинается с 0.
// Я взяла [22:0] как наиболее вероятный вариант для I-типа.
assign offset = instr[12:5];
// --- 4. Логика для адреса записи и разрешения записи ---
assign WA = (WS == 2'b00) ? instr[17:13] : instr[4:0];
assign WE = ~(J | B);
// --- 5. Регистровый Файл (Register File) ---
register_file rf (
.clk_i(clk_i),
.write_enable_i(WE),
.write_addr_i(WA),
.read_addr1_i(RA1),
.read_addr2_i(RA2),
.write_data_i(write_data),
.read_data1_o(rd1),
.read_data2_o(rd2)
);
// --- 6. Знаковое расширение константы ---
// Теперь это будет работать, потому что imm_field объявлен как вектор!
// Для 23-битного поля нужно расширить его на 32-23=9 бит.
// Твои "9" были случайной удачей, baka.
assign se_const = {{9{imm_field[22]}}, imm_field};
// --- 7. МУЛЬТИПЛЕКСОР для второго входа АЛУ (MUX for ALU input B) ---
// ВНИМАНИЕ, BAKA! ЗДЕСЬ У ТЕБЯ ЛОГИЧЕСКАЯ БОМБА!
// Ты управляешь мультиплексором сигналом `B`, который отвечает за BRANCH.
// А для I-типа (ADDI, XORI) должен быть другой управляющий сигнал!
// Ты должен создать сигнал, например, `ALU_B_src`, который будет 1 для I-типа и 0 для R-типа.
// Я пока оставлю твою логику, но ты должен это исправить!
always_comb begin
case (B) // <--- ЭТО НЕПРАВИЛЬНО! НО ЧТОБЫ КОМПИЛИРОВАЛОСЬ, ПОКА ТАК.
1'b0: alu_B = rd2; // Для R-типа
1'b1: alu_B = se_const; // Для I-типа
default: alu_B = 32'd0;
endcase
end
// --- 8. Арифметико-Логическое Устройство (ALU) ---
ALUcont alu_inst (
.a_i(rd1),
.b_i(alu_B),
.alu_op_i(alu_op),
.flag_o(flag),
.result_o(alu_res)
);
// --- 9. МУЛЬТИПЛЕКСОР для данных на запись (MUX for Write-Back) ---
always_comb begin
case (WS)
2'b00: write_data = se_const;
2'b01: write_data = alu_res;
2'b10: write_data = 32'd0; // TODO: LSU
default: write_data = 32'd0;
endcase
end
// --- 10. Логика обновления PC ---
always_comb begin
next_pc = pc + 32'd4;
// TODO: Логика для ветвлений (B) и прыжков (J)
end
// --- 11. Выход модуля ---
assign out_o = alu_res;
// ... (остальные твои модули остаются без изменений) ...
endmodule
//элементы, сделанные ранее в лабораторных работах
module instr_mem
(
input logic [31:0] read_addr_i,
output logic [31:0] read_data_o
);
logic [31:0] ROM [INSTR_MEM_SIZE_WORDS];
initial begin
$readmemh("program.mem", ROM);
end
assign read_data_o = ROM[read_addr_i[$clog2(INSTR_MEM_SIZE_BYTES)-1:2]];
endmodule
module register_file(
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
);
logic [31:0]rf_mem [0:31];
always_ff @(posedge clk_i) begin
if(write_enable_i && write_addr_i !=0) begin
rf_mem[write_addr_i] <= write_data_i;
end
end
// Логика чтения первого регистра
assign read_data1_o =
(read_addr1_i == 0) ? 32'h0:
rf_mem[read_addr1_i]; // Иначе — данные из регистра
// Логика чтения второго регистра (та же самая)
assign read_data2_o =
(read_addr2_i == 0) ? 32'b0 : // Адрес 0 → 0
rf_mem[read_addr2_i]; // Иначе — данные из регистра
endmodule
module ALUcont (
input logic [31:0] a_i,
input logic [31:0] b_i,
input logic [4:0] alu_op_i,
output logic flag_o,
output logic [31:0] result_o
);
// Импорт опкодов
import alu_opcodes_pkg::*;
logic [31:0] sum_result;
logic sum_dummy_carry;
fulladder32 adder_inst (
.a_i (a_i),
.b_i (b_i),
.carry_i (1'b0),
.sum_o (sum_result),
.carry_o (sum_dummy_carry)
);
// Основной MUX результата
always_comb begin
result_o = '0;
case (alu_op_i)
ALU_ADD : result_o = sum_result;
ALU_SUB : result_o = a_i - b_i;
ALU_XOR : result_o = a_i ^ b_i;
ALU_OR : result_o = a_i | b_i;
ALU_AND : result_o = a_i & b_i;
ALU_SRA : result_o = $signed(a_i) >>> b_i[4:0];
ALU_SRL : result_o = a_i >> b_i[4:0];
ALU_SLL : result_o = a_i << b_i[4:0];
ALU_SLTS : result_o = {31'd0, ($signed(a_i) < $signed(b_i))};
ALU_SLTU : result_o = {31'd0, (a_i < b_i)};
default : result_o = '0;
endcase
end
// MUX для флагов
always_comb begin
flag_o = 1'b0;
case (alu_op_i)
ALU_LTS : flag_o = ($signed(a_i) < $signed(b_i));
ALU_LTU : flag_o = (a_i < b_i);
ALU_GES : flag_o = ($signed(a_i) >= $signed(b_i));
ALU_GEU : flag_o = (a_i >= b_i);
ALU_EQ : flag_o = (a_i == b_i);
ALU_NE : flag_o = (a_i != b_i);
default : flag_o = 1'b0;
endcase
end
endmodule
module fulladder (
input logic a_i, b_i, carry_i,
output logic sum_o, carry_o
);
logic q1, q2, and1, and2, and3, or1, or2;
Xorr xor1 (.A(a_i), .B(b_i), .C(q1));
Xorr xor2 (.A(q1), .B(carry_i), .C(sum_o));
Andd and1m(.A(a_i), .B(carry_i), .C(and1));
Andd and2m(.A(a_i), .B(b_i), .C(and2));
Andd and3m(.A(b_i), .B(carry_i), .C(and3));
Orr or1m (.A(and1), .B(and2), .C(or1));
Orr or2m (.A(or1), .B(and3), .C(carry_o));
endmodule
module fulladder4 (
input logic [3:0] a_i, b_i,
input logic carry_i,
output logic [3:0] sum_o,
output logic carry_o
);
logic c1, c2, c3;
fulladder fa1 (.a_i(a_i[0]), .b_i(b_i[0]), .carry_i(carry_i), .sum_o(sum_o[0]), .carry_o(c1));
fulladder fa2 (.a_i(a_i[1]), .b_i(b_i[1]), .carry_i(c1), .sum_o(sum_o[1]), .carry_o(c2));
fulladder fa3 (.a_i(a_i[2]), .b_i(b_i[2]), .carry_i(c2), .sum_o(sum_o[2]), .carry_o(c3));
fulladder fa4 (.a_i(a_i[3]), .b_i(b_i[3]), .carry_i(c3), .sum_o(sum_o[3]), .carry_o(carry_o));
endmodule
module fulladder32 (
input logic [31:0] a_i, b_i,
input logic carry_i,
output logic [31:0] sum_o,
output logic carry_o
);
logic [6:0] c;
fulladder4 f1 (.a_i(a_i[3:0]), .b_i(b_i[3:0]), .carry_i(carry_i), .sum_o(sum_o[3:0]), .carry_o(c[0]));
fulladder4 f2 (.a_i(a_i[7:4]), .b_i(b_i[7:4]), .carry_i(c[0]), .sum_o(sum_o[7:4]), .carry_o(c[1]));
fulladder4 f3 (.a_i(a_i[11:8]), .b_i(b_i[11:8]), .carry_i(c[1]), .sum_o(sum_o[11:8]), .carry_o(c[2]));
fulladder4 f4 (.a_i(a_i[15:12]), .b_i(b_i[15:12]), .carry_i(c[2]), .sum_o(sum_o[15:12]), .carry_o(c[3]));
fulladder4 f5 (.a_i(a_i[19:16]), .b_i(b_i[19:16]), .carry_i(c[3]), .sum_o(sum_o[19:16]), .carry_o(c[4]));
fulladder4 f6 (.a_i(a_i[23:20]), .b_i(b_i[23:20]), .carry_i(c[4]), .sum_o(sum_o[23:20]), .carry_o(c[5]));
fulladder4 f7 (.a_i(a_i[27:24]), .b_i(b_i[27:24]), .carry_i(c[5]), .sum_o(sum_o[27:24]), .carry_o(c[6]));
fulladder4 f8 (.a_i(a_i[31:28]), .b_i(b_i[31:28]), .carry_i(c[6]), .sum_o(sum_o[31:28]), .carry_o(carry_o));
endmodule
module Andd (
input logic A, B,
output logic C
);
assign C = A & B;
endmodule
module Orr (
input logic A, B,
output logic C
);
assign C = A | B;
endmodule
module Xorr (
input logic A, B,
output logic C
);
assign C = A ^ B;
endmodule
import memory_pkg::INSTR_MEM_SIZE_WORDS;
module CYBERcobra (
input logic clk_i,
input logic rst_i,
input logic [15:0] sw_i,
output logic [31:0] out_o
);
// --- Сигналы ---
// Основные регистры и провода
logic [31:0] pc, next_pc;
logic [31:0] instr;
logic [31:0] alu_res, write_data;
logic [31:0] rd1, rd2;
logic [31:0] alu_B;
logic [31:0] se_const; // Знаково-расширенная константа
logic flag;
// Выходы декодера
logic J, B, WE;
logic [1:0] WS;
logic [4:0] alu_op;
logic [4:0] RA1, RA2, WA;
logic [7:0] offset;
logic [22:0] imm_field; // <--- ВОТ! ОБЪЯВЛЯЕМ ПРАВИЛЬНО! 23 бита!
// --- 1. Счётчик команд (PC) ---
always_ff @(posedge clk_i, posedge rst_i) begin
if (rst_i)
pc <= 32'd0;
else
pc <= next_pc;
end
// --- 2. Память Инструкций (Instruction Memory) ---
instr_mem imem (
.read_addr_i(pc),
.read_data_o(instr)
);
// --- 3. Декодер ---
// Нарезает инструкцию на управляющие сигналы. Наводим порядок!
assign J = instr[31];
assign B = instr[30];
assign WS = instr[29:28];
assign alu_op = instr[27:23];
assign RA1 = instr[22:18];
assign RA2 = instr[17:13];
assign imm_field = instr[22:0]; // <--- ПРЕДПОЛОЖЕНИЕ! СВЕРЬСЯ С МЕТОДИЧКОЙ!
// Поле immediate обычно начинается с 0.
// Я взяла [22:0] как наиболее вероятный вариант для I-типа.
assign offset = instr[12:5];
// --- 4. Логика для адреса записи и разрешения записи ---
assign WA = (WS == 2'b00) ? instr[17:13] : instr[4:0];
assign WE = ~(J | B);
// --- 5. Регистровый Файл (Register File) ---
register_file rf (
.clk_i(clk_i),
.write_enable_i(WE),
.write_addr_i(WA),
.read_addr1_i(RA1),
.read_addr2_i(RA2),
.write_data_i(write_data),
.read_data1_o(rd1),
.read_data2_o(rd2)
);
// --- 6. Знаковое расширение константы ---
// Теперь это будет работать, потому что imm_field объявлен как вектор!
// Для 23-битного поля нужно расширить его на 32-23=9 бит.
// Твои "9" были случайной удачей, baka.
assign se_const = {{9{imm_field[22]}}, imm_field};
// --- 7. МУЛЬТИПЛЕКСОР для второго входа АЛУ (MUX for ALU input B) ---
// ВНИМАНИЕ, BAKA! ЗДЕСЬ У ТЕБЯ ЛОГИЧЕСКАЯ БОМБА!
// Ты управляешь мультиплексором сигналом `B`, который отвечает за BRANCH.
// А для I-типа (ADDI, XORI) должен быть другой управляющий сигнал!
// Ты должен создать сигнал, например, `ALU_B_src`, который будет 1 для I-типа и 0 для R-типа.
// Я пока оставлю твою логику, но ты должен это исправить!
always_comb begin
case (B) // <--- ЭТО НЕПРАВИЛЬНО! НО ЧТОБЫ КОМПИЛИРОВАЛОСЬ, ПОКА ТАК.
1'b0: alu_B = rd2; // Для R-типа
1'b1: alu_B = se_const; // Для I-типа
default: alu_B = 32'd0;
endcase
end
// --- 8. Арифметико-Логическое Устройство (ALU) ---
ALUcont alu_inst (
.a_i(rd1),
.b_i(alu_B),
.alu_op_i(alu_op),
.flag_o(flag),
.result_o(alu_res)
);
// --- 9. МУЛЬТИПЛЕКСОР для данных на запись (MUX for Write-Back) ---
always_comb begin
case (WS)
2'b00: write_data = se_const;
2'b01: write_data = alu_res;
2'b10: write_data = 32'd0; // TODO: LSU
default: write_data = 32'd0;
endcase
end
// --- 10. Логика обновления PC ---
always_comb begin
next_pc = pc + 32'd4;
// TODO: Логика для ветвлений (B) и прыжков (J)
end
// --- 11. Выход модуля ---
assign out_o = alu_res;
// ... (остальные твои модули остаются без изменений) ...
endmodule
//элементы, сделанные ранее в лабораторных работах
module instr_mem
(
input logic [31:0] read_addr_i,
output logic [31:0] read_data_o
);
logic [31:0] ROM [INSTR_MEM_SIZE_WORDS];
initial begin
$readmemh("program.mem", ROM);
end
assign read_data_o = ROM[read_addr_i[$clog2(INSTR_MEM_SIZE_BYTES)-1:2]];
endmodule
module register_file(
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
);
logic [31:0]rf_mem [0:31];
always_ff @(posedge clk_i) begin
if(write_enable_i && write_addr_i !=0) begin
rf_mem[write_addr_i] <= write_data_i;
end
end
// Логика чтения первого регистра
assign read_data1_o =
(read_addr1_i == 0) ? 32'h0:
rf_mem[read_addr1_i]; // Иначе — данные из регистра
// Логика чтения второго регистра (та же самая)
assign read_data2_o =
(read_addr2_i == 0) ? 32'b0 : // Адрес 0 → 0
rf_mem[read_addr2_i]; // Иначе — данные из регистра
endmodule
module ALUcont (
input logic [31:0] a_i,
input logic [31:0] b_i,
input logic [4:0] alu_op_i,
output logic flag_o,
output logic [31:0] result_o
);
// Импорт опкодов
import alu_opcodes_pkg::*;
logic [31:0] sum_result;
logic sum_dummy_carry;
fulladder32 adder_inst (
.a_i (a_i),
.b_i (b_i),
.carry_i (1'b0),
.sum_o (sum_result),
.carry_o (sum_dummy_carry)
);
// Основной MUX результата
always_comb begin
result_o = '0;
case (alu_op_i)
ALU_ADD : result_o = sum_result;
ALU_SUB : result_o = a_i - b_i;
ALU_XOR : result_o = a_i ^ b_i;
ALU_OR : result_o = a_i | b_i;
ALU_AND : result_o = a_i & b_i;
ALU_SRA : result_o = $signed(a_i) >>> b_i[4:0];
ALU_SRL : result_o = a_i >> b_i[4:0];
ALU_SLL : result_o = a_i << b_i[4:0];
ALU_SLTS : result_o = {31'd0, ($signed(a_i) < $signed(b_i))};
ALU_SLTU : result_o = {31'd0, (a_i < b_i)};
default : result_o = '0;
endcase
end
// MUX для флагов
always_comb begin
flag_o = 1'b0;
case (alu_op_i)
ALU_LTS : flag_o = ($signed(a_i) < $signed(b_i));
ALU_LTU : flag_o = (a_i < b_i);
ALU_GES : flag_o = ($signed(a_i) >= $signed(b_i));
ALU_GEU : flag_o = (a_i >= b_i);
ALU_EQ : flag_o = (a_i == b_i);
ALU_NE : flag_o = (a_i != b_i);
default : flag_o = 1'b0;
endcase
end
endmodule
module fulladder (
input logic a_i, b_i, carry_i,
output logic sum_o, carry_o
);
logic q1, q2, and1, and2, and3, or1, or2;
Xorr xor1 (.A(a_i), .B(b_i), .C(q1));
Xorr xor2 (.A(q1), .B(carry_i), .C(sum_o));
Andd and1m(.A(a_i), .B(carry_i), .C(and1));
Andd and2m(.A(a_i), .B(b_i), .C(and2));
Andd and3m(.A(b_i), .B(carry_i), .C(and3));
Orr or1m (.A(and1), .B(and2), .C(or1));
Orr or2m (.A(or1), .B(and3), .C(carry_o));
endmodule
module fulladder4 (
input logic [3:0] a_i, b_i,
input logic carry_i,
output logic [3:0] sum_o,
output logic carry_o
);
logic c1, c2, c3;
fulladder fa1 (.a_i(a_i[0]), .b_i(b_i[0]), .carry_i(carry_i), .sum_o(sum_o[0]), .carry_o(c1));
fulladder fa2 (.a_i(a_i[1]), .b_i(b_i[1]), .carry_i(c1), .sum_o(sum_o[1]), .carry_o(c2));
fulladder fa3 (.a_i(a_i[2]), .b_i(b_i[2]), .carry_i(c2), .sum_o(sum_o[2]), .carry_o(c3));
fulladder fa4 (.a_i(a_i[3]), .b_i(b_i[3]), .carry_i(c3), .sum_o(sum_o[3]), .carry_o(carry_o));
endmodule
module fulladder32 (
input logic [31:0] a_i, b_i,
input logic carry_i,
output logic [31:0] sum_o,
output logic carry_o
);
logic [6:0] c;
fulladder4 f1 (.a_i(a_i[3:0]), .b_i(b_i[3:0]), .carry_i(carry_i), .sum_o(sum_o[3:0]), .carry_o(c[0]));
fulladder4 f2 (.a_i(a_i[7:4]), .b_i(b_i[7:4]), .carry_i(c[0]), .sum_o(sum_o[7:4]), .carry_o(c[1]));
fulladder4 f3 (.a_i(a_i[11:8]), .b_i(b_i[11:8]), .carry_i(c[1]), .sum_o(sum_o[11:8]), .carry_o(c[2]));
fulladder4 f4 (.a_i(a_i[15:12]), .b_i(b_i[15:12]), .carry_i(c[2]), .sum_o(sum_o[15:12]), .carry_o(c[3]));
fulladder4 f5 (.a_i(a_i[19:16]), .b_i(b_i[19:16]), .carry_i(c[3]), .sum_o(sum_o[19:16]), .carry_o(c[4]));
fulladder4 f6 (.a_i(a_i[23:20]), .b_i(b_i[23:20]), .carry_i(c[4]), .sum_o(sum_o[23:20]), .carry_o(c[5]));
fulladder4 f7 (.a_i(a_i[27:24]), .b_i(b_i[27:24]), .carry_i(c[5]), .sum_o(sum_o[27:24]), .carry_o(c[6]));
fulladder4 f8 (.a_i(a_i[31:28]), .b_i(b_i[31:28]), .carry_i(c[6]), .sum_o(sum_o[31:28]), .carry_o(carry_o));
endmodule
module Andd (
input logic A, B,
output logic C
);
assign C = A & B;
endmodule
module Orr (
input logic A, B,
output logic C
);
assign C = A | B;
endmodule
module Xorr (
input logic A, B,
output logic C
);
assign C = A ^ B;
endmodule
