I am simulating a MIPS processor in Verilog for class, I am having the strangest problem. When I pass an instruction (a 32-bit bus) to the main module, it somehow changes. For example, when I set the instruction to 00100000000010000000000000000001, inside the module I print out the instruction as 00101001111010000000000000000001, which is clearly different. No inner modules directly interact with the inside instruction, as it just gets broken up into various other parts. What could be causing the bits to change simply by passing the bus to a module?
Here is the main processor code and test bench:
module SingleCycleProc(clk, instruction);
// input Reset_L, clk;
// input [31:0] startPC;
// output [31:0] dmemOut;
// reg [31:0] dmemOut;
input clk;
input [31:0] instruction;
//Fetch instruction and get new program counter
//wire [31:0] instruction, PC_out;
//reg [31:0] PC;
//InstrMem(PC, instruction);
wire [31:0] sign_extended;
//ProgramCounter(PC, PC_out, zero, sign_extended);
//Break up instruction into basic components
reg [5:0] opcode;
reg [5:0] funct;
reg [15:0] immediate;
reg [25:0] address;
reg [4:0] RSAddr, RTAddr, RDAddr;
wire [31:0] RSData, RTData, RDData;
SIGN_EXTEND(immediate, sign_extended);
//Generate CPU and ALU control bits
wire regDST, ALUSrc, memToReg, regWrite, memRead, memWrite, branch;
wire [1:0] ALUOp;
CPU_Control_unit(opcode, regDST, ALUSrc, memToReg, regWrite, memRead, memWrite, branch, ALUOp);
wire [3:0] alu_control;
ALU_Control_Unit(alu_control, funct, ALUOp);
//Generate the input addresses to the regfile, and retrieve data from regfile
wire [4:0] out;
MUX5_2to1(RTAddr, RDAddr, regDST, out);
RegFile(RSData, RTData, RSAddr, RTAddr, RDData, RDAddr, regWrite, clk);
//select intputs to the ALU and do calculation
wire [31:0] alu_in1;
MUX32_2to1(RTData, sign_extended, ALUSrc, alu_in1);
wire [31:0] alu_out;
wire overflow, cin, cout, zero, PCSrc;
wire [31:0] result;
and(PCSrc, branch, zero);
ALU_behav(RSData, alu_in1, alu_control, result, overflow, cin, cout, zero);
wire [31:0] memReadData;
DataMem(result, clk, memRead, memWrite, RTData, memReadData);
MUX32_2to1(result, memReadData, memToReg, RDData);
always #(negedge clk) begin
// assign PC = PC + 4;
assign opcode = instruction[31:26];
assign funct = instruction[5:0];
assign immediate = instruction[15:0];
assign address = instruction[25:0];
assign RSAddr = instruction[25:21];
assign RTAddr = instruction[20:16];
assign RDAddr = instruction[15:11];
// assign dmemOut = RDData;
end
// always #(~Reset_L) assign PC = startPC;
//Monitor changes in the program counter
// always #(PC)
// #10 $display($time," PC=%d Instr: op=%d rs=%d rt=%d rd=%d imm16=%d funct=%d",
// PC,instruction[31:26],instruction[25:21],instruction[20:16],instruction[15:11],instruction[15:0],instruction[5:0]);
//Monitors memory writes
always #(clk)
begin
#1 $display($time, " clk=%b instruction=%b", clk, instruction);
// #1 $display($time " clk=%b opcode=%b", clk, opcode);
// #1 $display($time,
// " clock=%b RSAddr=%d RSData=%d RTAddr=%d RTData=%d",
// clk, RSAddr, RSData, RTAddr, RTData);
// #1 $display($time, " clk=%b regDST=%b regWrite=%b ALUSrc=%b memRead=%b memWrite=%b memToReg=%b branch=%b ALUOp=%b ", clk, regDST, regWrite, ALUSrc, memRead, memWrite, memToReg, branch, ALUOp);
end
endmodule
module testCPU(clk, Reset_L, startPC, testData);
input clk;
input [31:0] testData;
output Reset_L;
output [31:0] startPC;
reg Reset_L;
reg [31:0] startPC;
reg [31:0] instruction;
SingleCycleProc(clk, instruction);
initial begin
// Your program 1
// Reset_L = 0; startPC = 0 * 4;
// #101 // insures reset is asserted across negative clock edge
// Reset_L = 1;
// #10000; // allow enough time for program 1 to run to completion
// Reset_L = 0;
// #1 $display("Program 1: Result: %d", testData);
//addi $8, $0, 1
instruction = 00100000000010000000000000000001;
#100
//add $8, $8, $8
instruction = 00000001000010000100000000100000;
#100
$finish;
end
endmodule // testCPU
module TopProcessor;
wire reset, clk, Reset_L;
wire [31:0] startPC;
wire [31:0] testData;
m555 system_clock(clk);
testCPU(clk, Reset_L, startPC, testData);
//SingleCycleProc SSProc(clk, Reset_L, startPC, testData);
endmodule // TopProcessor
You are not telling Verilog that the instruction is a binary number, so it is interpreting it as decimal. You need this:
instruction = 32'b00100000000010000000000000000001;
#100
//add $8, $8, $8
instruction = 32'b00000001000010000100000000100000;
Additionally, you should not be putting assign statements inside an always block. If you want these to be registers, use the verilog non-blocking assignment operator <= rather than the assign statement. Or if you want them to be wires, you can keep the assign just move them outside the always block.
Also, try not to mix posedge and negedge. Stick to posedge.
I have different modules instantiated in one single module. I want to execute them in sequence, I have enable and acknowledgement signals of all modules how can I do this?
Following is the code:
module memorycontroller(
input [7:0] A,
input [7:0] B,
input [1:0] adrress,
input clk,
output [7:0] A_mem,
output [7:0] B_mem
);
reg LMwrEnable, localmemEnable;
integer LMwrack, localmemack;
reg [7:0] A1, B1;
initial
begin
LMwrEnable = 1;
localmemEnable = 0;
end
memorywrite LMwr (
.clk ( clk ),
.A ( A ),
.B ( B ),
.adr ( adrress ),
.enable ( LMwrEnable ),
.ack ( LMwrack )
);
bram_tdp localmem (
.a_clk ( clk ),
.a_wr ( 1'b0 ),
.a_addr ( adrress ),
.a_din ( A1 ),
.a_dout ( A_mem ),
.b_clk ( clk ),
.b_wr ( 1'b0 ),
.b_addr ( adrress+1'b1 ),
.b_din ( B1 ),
.b_dout ( B_mem ),
.enable ( localmemEnable ),
.ack ( localmemack )
);
always#(posedge clk)
begin
if(LMwrack)
localmemEnable = 1;
end
endmodule
In initial statement I've enabled only LMwr module in initial block and on its ack signal I have enabled localmem module in always block but this is giving me wrong result. Can you tell me how to execute different modules in sequence?
Following is the memorywrite module
module memorywrite(
input clk,
input [7:0] A,
input [7:0] B,
input [1:0] adr,
input enable,
output ack
);
wire [7:0] C,C1;
bram_tdp localmem (
.a_clk(clk),
.a_wr(1'b1),
.a_addr(adr),
.a_din(A),
.a_dout(C),
.b_clk(clk),
.b_wr(1'b1),
.b_addr(adr+1'b1),
.b_din(B),
.b_dout(C1),
.enable(enable),
.ack(ack)
);
endmodule
This above code writes to the memory.
Following is the actual memory module which is being written by 2nd code stated above and read by 1st code stated above
module bram_tdp #(
parameter DATA = 8,
parameter ADDR = 2
) (
input enable,
output ack,
// Port A
input wire a_clk,
input wire a_wr,
input wire [ADDR-1:0] a_addr,
input wire [DATA-1:0] a_din,
output reg [DATA-1:0] a_dout,
// Port B
input wire b_clk,
input wire b_wr,
input wire [ADDR-1:0] b_addr,
input wire [DATA-1:0] b_din,
output reg [DATA-1:0] b_dout
);
// Shared memory
reg [DATA-1:0] mem [(2**ADDR)-1:0];
// Port A
always #(posedge a_clk) begin
if(enable) begin
a_dout <= mem[a_addr];
if(a_wr) begin
a_dout <= a_din;
mem[a_addr] <= a_din;
end
end
end
// Port B
always #(posedge b_clk) begin
if(enable) begin
b_dout <= mem[b_addr];
if(b_wr) begin
b_dout <= b_din;
mem[b_addr] <= b_din;
end
end
end
assign ack=1;
endmodule
Here is testbench:
module mmTesting;
// Inputs
reg [7:0] A;
reg [7:0] B;
reg [1:0] adrress;
reg clk;
// Outputs
wire [7:0] A_mem;
wire [7:0] B_mem;
// Instantiate the Unit Under Test (UUT)
memorycontroller uut (
.A(A),
.B(B),
.adrress(adrress),
.clk(clk),
.A_mem(A_mem),
.B_mem(B_mem)
);
initial begin
// Initialize Inputs
A = 0;
B = 0;
adrress = 0;
clk = 0;
// Wait 100 ns for global reset to finish
#100;
A = 5;
B = 5;
adrress = 0;
#100 A = 6;
B = 2;
adrress = 1;
// Add stimulus here
end
always #5 clk=!clk;
endmodule
Result should be same as what I am writing to the memory.
Just to clarify that Verilog is a hardware description and that both instantiations (not modules, as an uninstantiated module does not exist) can be executed and exist in parallel, unlike the C equivalent which would execute one then the other.
If you have instance A and B, you just need a FSM (Finite State Machine) to enable A wait for its completion signal, then disabling A enable B, waiting for B to complete and repeat.
NB: if the commented out code is not relevant to the question can it be removed, it is good practise to reduce your question to the minimum amount of code required to reproduce the problem.
I am trying to pass a array structure as reg [0:31]instructionmem[0:31] between two modules.
I coded it as follows :
Module No 1:
module module1(instructionmem);
output reg [0:31]instructionmem[0:31];
------------------
----lines of code---
---------------
endmodule
Module No 2:
module module2(instructionmem);
input [0:31]instructionmem[0:31];
--------------------------------
-----line of code---------------
-------------------------------
endmodule
Testbench:
module test_bench();
wire [0:31]instructionmem[0:31];
module1 m1(instructionmem);
module2 m2(instructionmem);
endmodule
I am getting errors for this implementation. So how can we send such array structures ?
This is not possible in Verilog. (See sec. 12.3.3, Syntax 12-4 of the Verilog 2005 standard document, IEEE Std. 1364-2005.)
Instead you should "flatten" the array and pass it as a simple vector, e.g.:
module module1(instructionmem);
output [32*32-1:0] instructionmem;
reg [31:0] instructionmem_array [31:0];
genvar i;
generate for (i = 0; i < 32; i = i+1) begin:instmem
assign instructionmem[32*i +: 32] = instructionmem_array[i];
end endgenerate
endmodule
module module2(instructionmem);
input [32*32-1:0] instructionmem;
reg [31:0] instructionmem_array [31:0];
integer i;
always #*
for (i = 0; i < 32; i = i+1)
instructionmem_array[i] = instructionmem[32*i +: 32];
endmodule
module test_bench(instructionmem);
output [32*32-1:0] instructionmem;
module1 m1(instructionmem);
module2 m2(instructionmem);
endmodule
I seem to have some issues anytime I try anything with I/O for verilog. Modelsim either throws function not supported for certain functions or does nothing at all. I simply need to read a file character by character and send each bit through the port. Can anyone assist
module readFile(clk,reset,dEnable,dataOut,done);
parameter size = 4;
//to Comply with S-block rules which is a 4x4 array will multiply by
// size so row is the number of size bits wide
parameter bits = 8*size;
input clk,reset,dEnable;
output dataOut,done;
wire [1:0] dEnable;
reg dataOut,done;
reg [7:0] addr;
integer file;
reg [31:0] c;
reg eof;
always#(posedge clk)
begin
if(file == 0 && dEnable == 2'b10)begin
file = $fopen("test.kyle");
end
end
always#(posedge clk) begin
if(addr>=32 || done==1'b1)begin
c <= $fgetc(file);
// c <= $getc();
eof <= $feof(file);
addr <= 0;
end
end
always#(posedge clk)
begin
if(dEnable == 2'b10)begin
if($feof(file))
done <= 1'b1;
else
addr <= addr+1;
end
end
//done this way because blocking statements should not really be used
always#(addr)
begin:Access_Data
if(reset == 1'b0) begin
dataOut <= 1'bx;
file <= 0;
end
else if(addr<32)
dataOut <= c[31-addr];
end
endmodule
I would suggest reading the entire file at one time into an array, and then iterate over the array to output the values.
Here is a snippet of how to read bytes from a file into a SystemVerilog queue. If you need to stick to plain old Verilog you can do the same thing with a regular array.
reg [8:0] c;
byte q[$];
int i;
// Read file a char at a time
file = $fopen("filename", "r");
c = $fgetc(file);
while (c != 'h1ff) begin
q.push_back(c);
$display("Got char [%0d] 0x%0h", i++, c);
c = $fgetc(file);
end
Note that c is defined as a 9-bit reg. The reason for is that $fgetc will return -1 when it reaches the end of the file. In order to differentiate between EOF and a valid 0xFF you need this extra bit.
I'm not familiar with $feof and don't see it in the Verilog 2001 spec, so that may be something specific to Modelsim. Or it could be the source of the "function not supported."
I am trying to design a simple 8-bit 2's complementor. Here is my code:
twos_complement_of_8bits.v
//`include "complementor.v"
module twos_complement_of_8bits(output [7:0] out, input [7:0] in);
integer i;
initial
begin
for(i = 0; i <= 7; i = i + 1)
complementor C(out[i], in[i]);
end
assign out = out + 1;
endmodule
I got an error at this line:
complementor C(out[i], in[i]);
Syntax error near 'C' found.
How can I fix it?
I think you can eliminate your complementor module, then change your twos_complement_of_8bits as follows:
module twos_complement_of_8bits (output [7:0] out, input [7:0] in);
assign out = ~in + 1;
endmodule
If that doesn't give you the output you want, please show some expected output values.
In more complicated situations, you can place arrays of instances of modules or use a generate block.
Here is an example of how to use a generate block:
module twos_complement_of_8bits (output [7:0] out, input [7:0] in);
wire [7:0] out_ones;
genvar i;
generate
for (i=0; i<=7; i=i+1) begin
complementor C[i] (out_ones[i], in[i]);
end
endgenerate
assign out = out_ones + 1;
endmodule