mips verilog de rama de ciclo único

1

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
    
pregunta Ctuohey

2 respuestas

2

En cualquier bloque siempre secuencial, debe usar la asignación de no bloqueo (el signo menor que / igual, < =). Si no es la causa de este problema, causará una capa con seguridad.

    
respondido por el Matt
1

La regla es simplemente: Si un proceso escribe en una variable sincronizada con un evento, y otro proceso lee la variable same sincronizada con el evento same , debe escribir usando una NBA asegurándose de que la lectura proceso utiliza el valor antiguo de la variable. Si, en cambio, utiliza una asignación de bloqueo en esta situación, hay una condición de carrera entre obtener el valor nuevo o antiguo de la variable porque el orden de ejecución entre los procesos de lectura y escritura es indeterminado.

Por "evento" me refiero a un borde de un reloj o habilitar. Y por "mismo" me refiero a la expresión idéntica o combinada de la misma señal.

    
respondido por el dave_59

Lea otras preguntas en las etiquetas