Soy bastante nuevo en Verilog, diseño de hardware y arquitectura de computadoras. Sin embargo, he intentado diseñar un procesador MIPS simplificado. Parece que, en su mayoría, funciona bien, pero siempre que lo simulo, se cuelga en una instrucción BEQ.
Estoy intentando que funcione con el siguiente programa (R1 está precargado con 32'd10 y R4 está precargado con 32'd1):
0 ADD R0 R1 R5; // R1 = 10
4 ADD R0 R1 R5; // R5 = 10 (redundant)
8 ADD R5 R6 R6; // R6 = R5 + R6
C SUB R5 R4 R5; // R5 = R5 - 1
10 SLT R4 R5 R7; // R4 < R5
14 BEQ R7 R4 -3; // Loop back to 8 if R5 > 1
Aquí está la salida de GTKWave:
Talcomoloentiendo,los16bitsbajosdelainstruccióndebenirasign_extend,dondeseconcatenancon16copiasdelbitdesigno.Estoluegovaashift_left2,dondeladirecciónsemultiplicapor4.Estoseagregaaladirecciónanterior+4.
LosdosoperandosenviadosalaALUsoniguales,porloqueseconfirmalaseñalz0.Laseñalderamificaciónesafirmadaporelmódulodecontrol,basándoseenlosbits[31:26]delainstrucción.LaramayelceroseANDanenbranch_and,loquehacequeseestablezcabranchnd.Estosealimentaaunmuxparaseleccionarladireccióndelaramaenlugardeladirecciónanteriorincrementadaysedevuelvealcontadordelprograma,asignadoanext_addressenelsiguienteciclodereloj,ysealimentaalamemoriadeinstruccionesparabuscarlasiguientedirección.
Parecequetodoestosucedeenmisimulación.Ladirecciónramificadasepuedeverenelcomplementoalos12segundosenlaimagenanterior,porloqueparecefuncionarcorrectamentehastaesepunto.Aunquenopuedoentenderporquésecuelga.Seguramenteestosolosedebeincluirenelcontadordelprograma,sedebeasignaranext_addressenlasiguienteposicióndelrelojysedebeusarparaobtenerlainstrucción.Sicambioelprogramaparaquenosetomelabifurcación,seseguiráejecutandohastaquesequedesininstrucciones,porloquepareceestarrelacionadoconlabifurcación.
Heintentadocambiarlaslistasdesensibilidad,agregar/eliminarelrelojdelosmódulosycasicualquierotracosaquepuedaimaginar.Talvezmeestéperdiendoalgoobvio.Apreciaríamuchosialguienpudieraayudar.Soynuevoaquí,asíquesiestanoeslaformacorrectadehacerunapreguntaosihayalgoquepuedahacerparaqueestapreguntaseamásfácilderesponder,hágamelosaber.
Gracias
moduleMIPS_tb();wire[4:0]rs1,rt1,rd1,writereg1;wire[31:0]ins,register0,register1,register4,register5,register6,register7,addin,aluout,nextadd,op1,op2,rfoutput2,dmreaddata,se_address,wdata,braddr,shaddr,incPCaddr;wirereg_write,branch,branchnd,z0,regds,memtoreg,memwrite,alusrc;regclock;regreset;MIPSmips1(clock,reset,rs1,rt1,rd1,writereg1,reg_write,ins,register1,register4,register5,register6,register7,branch,branchnd,z0,addin,aluout,nextadd,op1,op2,rfoutput2,dmreaddata,se_address,wdata,braddr,shaddr,incPCaddr,regds,memtoreg,memwrite,alusrc);initialbegin$dumpfile("MIPS_MIPS_tb.vcd");
$dumpvars(0, clock, reset, rs1, rt1, rd1, writereg1, reg_write, ins,
register1, register4, register5, register6, register7, branch, branchnd, z0, addin, aluout, nextadd,
op1, op2, rfoutput2, dmreaddata, se_address, wdata, braddr, shaddr, incPCaddr, regds, memtoreg, memwrite, alusrc);
reset = 1'b1;
clock = 1'b0;
#1
reset = 1'b0;
repeat(250)
#1
clock = !clock;
#1
$finish;
end
endmodule
MIPS
module MIPS(clock, reset, rs1, rt1, rd1, writereg1, reg_write, ins,
register1, register4, register5, register6, register7, branch, branchnd, z0, addin, aluout, nextadd,
op1, op2, rfoutput2, dmreaddata, se_address, wdata, braddr, shaddr, incPCaddr, regds, memtoreg, memwrite, alusrc);
input clock, reset;
output [4:0] rs1, rt1, rd1, writereg1;
output [31:0] ins, addin, aluout;
output reg_write;
output [31:0] register1, register4, register5, register6, register7, nextadd, op1, op2,
rfoutput2, dmreaddata, se_address, wdata, braddr, shaddr, incPCaddr;
output branch, branchnd, z0, regds, memtoreg, memwrite, alusrc;
wire [31:0] instruction, next_address, address_in, operand1, operand2, reg_file_output2,
ALU_result, data_mem_read_data, sign_extended_address, write_data,
branch_address, shifted_address, incremented_PC_address;
wire RegDst, Branch, MemtoReg, MemWrite, ALUSrc, RegWrite, zero, BEQ;
wire [1:0] ALUOp;
wire [4:0] rs, rt, rd, write_register;
wire [5:0] funct;
wire [15:0] addressop;
wire [3:0] ALU_control_vector;
assign rs1 = rs;
assign rt1 = rt;
assign rd1 = rd;
assign writereg1 = write_register;
assign reg_write = RegWrite;
assign ins = instruction;
assign z0 = zero;
assign branch = Branch;
assign branchnd = BEQ;
assign addin = address_in;
assign aluout = ALU_result;
assign nextadd = next_address;
assign op1 = operand1;
assign op2 = operand2;
assign rfoutput2 = reg_file_output2;
assign dmreaddata = data_mem_read_data;
assign se_address = sign_extended_address;
assign wdata = write_data;
assign braddr = branch_address;
assign shaddr = shifted_address;
assign incPCaddr = incremented_PC_address;
assign regds = RegDst;
assign memtoreg = MemtoReg;
assign memwrite = MemWrite;
assign alusrc = ALUSrc;
program_counter pc1(next_address, address_in, clock, reset);
register_file rf1(operand1, reg_file_output2, rs, rt, write_register, write_data, RegWrite,
register1, register4, register5, register6, register7);
ALU alu1(ALU_result, zero, operand1, operand2, ALU_control_vector);
ALU_control aluctrl1(ALU_control_vector, ALUOp, funct);
data_memory dm1(data_mem_read_data, reg_file_output2, ALU_result, MemWrite);
sign_extend se1(sign_extended_address, addressop);
instruction_memory im1(instruction, next_address);
control ctrl1(RegDst, Branch, MemtoReg, ALUOp, MemWrite, ALUSrc, RegWrite, instruction,
rs, rt, rd, funct, addressop);
branch_adder ba1(branch_address, shifted_address, incremented_PC_address);
PC_increment pci(incremented_PC_address, next_address);
branch_and brand(BEQ, Branch, zero);
shift_left2 shl2(shifted_address, sign_extended_address);
mux_2to1 branch_mux(address_in, BEQ, incremented_PC_address, branch_address);
mux_2to1_5bit write_reg_mux(write_register, RegDst, rt, rd);
mux_2to1 write_data_mux(write_data, MemtoReg, ALU_result, data_mem_read_data);
mux_2to1 ALU_source_mux(operand2, ALUSrc, reg_file_output2, sign_extended_address);
endmodule
Unidad de control
module control(RegDst, Branch, MemtoReg, ALUOp, MemWrite, ALUSrc, RegWrite, instruction,
rs, rt, rd, funct, addressop);
output RegDst, Branch, MemtoReg, MemWrite, ALUSrc, RegWrite;
output [4:0] rs, rt, rd;
output [5:0] funct;
output [15:0] addressop;
output [1:0] ALUOp;
input [31:0] instruction;
wire [5:0] Op = instruction[31:26];
assign rs = instruction[25:21];
assign rt = instruction[20:16];
assign rd = instruction[15:11];
assign funct = instruction[5:0];
assign addressop = instruction[15:0];
reg [7:0] Control;
assign RegDst = Control[7];
assign RegWrite = Control[6];
assign ALUSrc = Control[5];
assign MemWrite = Control[4];
assign MemtoReg = Control[3];
assign Branch = Control[2];
assign ALUOp = Control[1:0];
initial
Control = 7'd0;
always @(*)
casex(Op)
32'd0 : Control = 8'b11000010; // R-TYPE
32'd35 : Control = 8'b01101000; // LW
32'd43 : Control = 8'bx011x000; // SW
32'd4 : Control = 8'bx000x101; // BEQ
default : Control = 8'b00000000; // NOP
endcase
endmodule
Memoria de instrucciones
module instruction_memory(instruction, address);
output reg [31:0] instruction;
input [31:0] address;
reg [31:0] prog [40:0];
initial
begin
prog[0] <= 32'b000000_00000_00001_00101_00000000000;
prog[4] <= 32'b000000_00000_00001_00101_00000000000;
prog[8] <= 32'b000000_00000_00000_00110_00000000000;
prog[12] <= 32'b000000_00101_00110_00110_00000000000;
prog[16] <= 32'b000000_00101_00100_00101_00000000010;
prog[20] <= 32'b000000_00100_00101_00111_00000001010;
prog[24] <= 32'b000100_00111_00100_11111_11111111100;
prog[28] <= 32'b000000_00101_00100_00101_00000000010;
prog[32] <= 32'b000000_00101_00100_00111_00000001010;
prog[36] <= 32'b000000_00100_00110_00110_00000000000;
prog[40] <= 32'b000000_00100_00110_00110_00000000000;
end
always @(address)
instruction = prog[address];
endmodule
Sign Extend
module sign_extend(sign_extended_address, instruction_addr);
output reg [31:0] sign_extended_address;
input [15:0] instruction_addr;
always @(*)
begin
sign_extended_address[15:0] = instruction_addr;
if(instruction_addr[15]==1'b1)
sign_extended_address[31:16] = 16'b1111_1111_1111_1111;
else
sign_extended_address[31:16] = 16'b0000_0000_0000_0000;
end
endmodule
Unidad de control de ALU
module ALU_control(ALU_control_vector, ALUOp, funct);
output reg [3:0] ALU_control_vector;
input [1:0] ALUOp;
input [5:0] funct;
initial
ALU_control_vector = 4'b0000;
always @(*)
begin
case(ALUOp[1])
1'b0 : case(ALUOp[0])
1'b0 : ALU_control_vector = 4'b0010; // ADD for LW, SW
1'b1 : ALU_control_vector = 4'b0110; // SUB for BEQ
endcase
1'b1 : case(funct[3:0])
4'b0000 : ALU_control_vector = 4'b0010; // ADD
4'b0100 : ALU_control_vector = 4'b0000; // AND
4'b0101 : ALU_control_vector = 4'b0001; // OR
4'b0010 : ALU_control_vector = 4'b0110; // SUB
4'b1010 : ALU_control_vector = 4'b0111; // SLT
default : ALU_control_vector = 4'b0010; // ADD (doesn't matter)
endcase
endcase
end
endmodule
ALU
module ALU(ALU_result, zero, operand1, operand2, ALU_control_vector);
output reg [31:0] ALU_result;
output reg zero;
input [31:0] operand1, operand2;
input [3:0] ALU_control_vector;
initial
begin
ALU_result = 32'd0;
zero = 0;
end
always @(*)
begin
case(ALU_control_vector)
4'b0000 : ALU_result = operand1 & operand2;
4'b0001 : ALU_result = operand1 | operand2;
4'b0010 : ALU_result = operand1 + operand2;
4'b0110 : ALU_result = operand1 - operand2;
4'b0111 : ALU_result = (operand1 < operand2) ? 32'd1 : 32'd0;
endcase
if (ALU_result == 0)
zero = 1'b1;
else
zero = 1'b0;
end
endmodule
Registrar archivo
module register_file(operand1, reg_file_output2, rs, rt, write_register, write_data, RegWrite,
register1, register4, register5, register6, register7);
output reg [31:0] operand1, reg_file_output2;
output [31:0] register0, register1, register4, register5, register6, register7;
input [31:0] write_data;
input [4:0] rs, rt, write_register;
input RegWrite;
reg [31:0] registers [31:1]; // Register 0 reserved for "0"
assign register1 = registers[1];
assign register4 = registers[4];
assign register5 = registers[5];
assign register6 = registers[6];
assign register7 = registers[7];
initial
begin
registers[1] = 10;
registers[4] = 1;
registers[5] = 0;
registers[6] = 0;
registers[7] = 0;
operand1 = 0;
reg_file_output2 = 0;
end
always @(*)
begin
operand1 = (rs == 0) ? 32'd0 : registers[rs];
reg_file_output2 = (rt == 0) ? 32'd0 : registers[rt];
if(RegWrite)
registers[write_register] = write_data;
end
endmodule
Contador de programas
module program_counter(next_address, address, clock, reset);
output [31:0] next_address;
input [31:0] address;
input clock, reset;
reg [31:0] pc_next;
assign next_address = pc_next;
always @(posedge clock, posedge reset)
begin
if(reset)
pc_next = 32'd0;
else
pc_next = address;
end
endmodule
Suma de rama
module branch_adder(branch_address, shifted_addr_instruction, incremented_PC_addr);
output [31:0] branch_address;
input [31:0] shifted_addr_instruction, incremented_PC_addr;
assign branch_address = shifted_addr_instruction + incremented_PC_addr;
endmodule
Mux 1
module mux_2to1(out, select, a, b);
output reg [31:0] out;
input select;
input [31:0] a, b;
initial
out = 0;
always @(*)
begin
if(select)
out = b;
else
out = a;
end
endmodule
Mux 2
module mux_2to1_5bit(out, select, a, b);
output reg [4:0] out;
input select;
input [4:0] a, b;
initial
out = 0;
always @(*)
begin
if(select)
out = b;
else
out = a;
end
endmodule
Incrementador de PC
module PC_increment(incremented_PC_address, current_address);
output [31:0] incremented_PC_address;
input [31:0] current_address;
assign incremented_PC_address = current_address + 4;
endmodule
Rama / Cero Y
module branch_and(BEQ, branch, zero);
output BEQ;
input branch, zero;
and(BEQ, branch, zero);
endmodule
Dirección de cambio a la izquierda
module shift_left2(shifted_address, sign_extended_address);
output [31:0] shifted_address;
input [31:0] sign_extended_address;
assign shifted_address = sign_extended_address << 2;
endmodule
Memoria de datos
module data_memory(data_mem_read_data, data_mem_write_data, ALU_result, MemWrite);
output reg [31:0] data_mem_read_data;
input [31:0] ALU_result, data_mem_write_data;
input MemWrite;
wire MemRead = ~MemWrite;
reg [31:0] data_registers [255:0];
initial
data_mem_read_data = 0;
always @(ALU_result, data_mem_write_data)
begin
if(MemWrite)
data_registers[ALU_result] = data_mem_write_data;
if(MemRead)
data_mem_read_data = data_registers[ALU_result];
end
endmodule