Reputation: 77
I am fairly new to Verilog and I am stuck on a particular problem of doing an assignment operation to an inout wire port. The issue I faced is after the assignment to the inout port -_memd_data
in the processor_core module, I get XXXXXXXX as the result in the _memd_data
variable when it should be 0x5b78193a.
Line with issue: assign _memd_data = (mem_dWE)? mem_o_data : 32'bz
;
Before assigning the data, below are the lines of code that occured before the execution of that line above (can't figure out what is wrong, looks completely fine to me).
STR: //Result store
begin
if(memAddr==7) begin
csmemd = 1;
mem_o_data <= R[R1]; //STR r1, [r2]
mem_dWE = 1;
memAddr <= memAddr + Addr;
Brief explanation of this small project: Basically it simulates the workings of a single cycle processor. The processor_core module should be able to fetch memory from the imem module based on a given address and decode the instruction fetched, then load the data from the data memory which is the dmem module, then condition_uct a XOR operation on the data with an encryption key(0x5a5b5c5d) fetched from the imem instruction address and compute the result and store the resulting data back to the dmem module to replace the old data. Also simulates an encryption of data.
Note: I only need to implement the processor_core module, feels like I am so close, but yet so far from getting it done..
I am using Vivado software to code this.
TestBench
`timescale 1ns / 1ps
module Nexys4_MAT_Top(
//CLK Input
input CLK100MHZ ,
input CPU_RESETN,
//Push Button Inputs
input BTNC ,
// Slide Switch Inputs
input [15:0] SW ,
// LED Outputs
output [15:0] LED ,
// Seven Segment Display Outputs
output CA ,
output CB ,
output CC ,
output CD ,
output CE ,
output CF ,
output CG ,
output [ 7:0] AN ,
output DP
);
//CLK: 100MHz
parameter periodCLK_2 = 5;
parameter perioddump = 10;
parameter delay = 1;
parameter delay_in = 2;
//Clock & reset signals
wire clk_main ;
wire rstn ;
//Processor signals
wire [ 4:0] memAddr ;
wire [31:0] memData_I ;
wire [ 5:0] memAddr_d ;
wire [31:0] _memd_data ;
wire [31:0] _memd_data_cpu ;
wire dmem_wr ;
wire csmemd ;
reg CLK_TB;
reg RSTN;
// CLK_TB //
initial
begin
CLK_TB = 1'b0;
#(perioddump);
CLK_TB = 1'b1;
forever
begin
CLK_TB = !CLK_TB;
#(periodCLK_2);
end
end
initial begin
global_reset();
repeat(1) @(posedge CLK_TB); #delay;
repeat(1) @(posedge CLK_TB); #delay;
repeat(10) @(posedge CLK_TB);#delay;
end
task global_reset;
begin
repeat(2) @(posedge CLK_TB); #delay;
repeat(2) @(posedge CLK_TB); #delay;
RSTN = 1'b0;
repeat(2) @(posedge CLK_TB); #delay;
RSTN = 1'b1;
end
endtask
// Circuit implementation
clkrst u_clkrst(
.CLK100MHZ (CLK_TB ),
.rst_btn (RSTN ),
.clk_out (clk_main ),
.rstn (rstn )
);
processor_core u_processor(
.clk (clk_main ),
.rstn (rstn ),
.memAddr (memAddr ),
.memData_I (memData_I ),
.memAddr_d (_memd_data_cpu ),
._memd_data (_memd_data ),
.mem_dWE (mem_dWE ),
.csmemd (csmemd )
);
imem u_imem(
.clk (clk_main ),
.rstn (rstn ),
.addr (memAddr ),
.cs (1'b1 ),
.we (1'b0 ),
.data (memData_I )
);
dmem u_dmem(
.clk (clk_main ),
.rstn (rstn ),
.addr (_memd_data_cpu ),
.cs (csmemd ),
.we (mem_dWE ),
.data (_memd_data )
);
endmodule
Design sources
`timescale 1ns / 1ps
module processor_core(
input clk ,//Input clock
input rstn ,//Reset signal, low active
output [ 4:0] memAddr ,//instruction memory address
input [31:0] memData_I ,//instruction memory data
output [ 5:0] memAddr_d ,//data memory address
inout [31:0] _memd_data ,
output mem_dWE ,
output csmemd
);
// For I/O signals
reg [ 4:0] memAddr ;
reg [ 5:0] memAddr_d ;
reg mem_dWE ;
reg csmemd ;
// For internal signals
reg [31:0] _memd_data_i ;//The input data from dmem
reg [31:0] mem_o_data ;//The output data for dmem
parameter AND = 4'h2;
parameter SUB = 4'h4;
parameter ORR = 4'h5;
parameter XOR = 4'h1;
parameter ADD = 4'h2;
parameter MOV = 4'h3;
parameter LDR = 4'h5;
parameter STR = 4'h6;
parameter CMP = 4'h4;
parameter N = 3;
parameter Z = 2;
parameter C = 1;
parameter V = 0;
reg [3:0] nzcv_;
parameter Addr = 1;
reg[31:0] condition_;
reg[0:0] condition_tionCarry;
reg[3:0] Aluchk;
reg[3:0]Opcde_chk;
reg[31:0]Br_check;
reg[7:0]IVal;
reg[23:0]branc_offs;
reg[3:0] R1;
reg[3:0] R2;
reg[3:0] R3;
reg[31:0] R[15:0];
reg [31:0] b;
integer index;
integer clk_count;
assign _memd_data = (mem_dWE)? mem_o_data : 32'bz; //Issue with assignment
always @ (posedge clk or negedge rstn) begin
if (!rstn) begin
_memd_data_i <= 32'h0;
end
else begin
_memd_data_i <= _memd_data;
end
end
always @ (posedge clk or negedge rstn)
begin
if(!rstn) begin
nzcv_[N] = 0;
nzcv_[Z] = 0;
nzcv_[C] = 0;
nzcv_[V] = 0;
Br_check<=32'h0;
IVal<=0;
mem_o_data = 32'h0;
R1<=0;
R2<=0;
R3<=0;
end
else begin
Aluchk = memData_I[31:31];
R1 = memData_I[15:12];
R2 = memData_I[11:8];
R3 = memData_I[7:4];
branc_offs = memData_I[27:4];
Opcde_chk = memData_I[30:28];
Br_check = memData_I[31:0];
IVal = memData_I[27:16];
case(Br_check)
BEQ:
begin
if(nzcv_[Z] == 1'b1) //BEQ Done
$stop;
end
BNE:
begin
if(nzcv_[Z] == 1'b0)
memAddr <= memAddr - branc_offs;
end
case(Aluchk)
1'b1:
begin
case(Opcde_chk)
XOR: //ADD ompute Result
begin
if(memAddr==6) begin
// csmemd = 0;
R[R1] = R[R2] ^ R[R3];
// mem_dWE = 1;
// csmemd = 1;
mem_o_data <= R[R1];
memAddr <= memAddr + Addr;
end
end
ADD:
begin
// mem_dWE = 0;
if(memAddr==8) begin
mem_dWE = 0;
// R[R2]<=R[R2]+IVal;
memAddr_d<=memAddr_d+IVal;
// memAddr_d = R[R2];
memAddr <= memAddr + Addr;
end
end
endcase
end
1'b0:
begin
case(Opcde_chk)
MOV:
begin
clk_count = clk_count + 1;
if(memAddr==0) begin
R[R3][31:24] <= IVal;
end
if(memAddr==4 && clk_count == 5) begin
R[R2] <= IVal;
end
memAddr <= memAddr + Addr;
end
LDR:
begin
if(memAddr==5) begin
csmemd = 1;
R[R1] = 0;
R[R1] = _memd_data_i; //LDR r1, [r2]
memAddr <= memAddr + Addr;
end
end
STR: //Result store
begin
if(memAddr==7) begin
csmemd = 1;
mem_o_data <= R[R1];
mem_dWE = 1;
memAddr <= memAddr + Addr;
// mem_o_data = R[R1];
end
end
endcase
end
endcase
end
end
endmodule
`timescale 1ns / 1ps
module dmem(
input clk ,//Input clock
input rstn ,//Reset signal, low active
input [ 5:0] addr ,//memory address
input cs ,
input we ,
inout [31:0] data
);
// For I/O signals
// For internal signals
reg [31:0] mem[0:63] ;
// Circuit implementation
assign data = (cs) ? mem[addr] : 32'bz;
always @ (posedge clk or negedge rstn) begin
if (!rstn) begin
//The hard coded data, or plain text
mem[ 0] <= 32'h43314220;
mem[ 1] <= 32'h42020032;
mem[ 2] <= 32'h00650039;
mem[ 3] <= 32'h01150032;
mem[ 4] <= 32'h01150097;
mem[ 5] <= 32'h01020101;
mem[ 6] <= 32'h00320116;
mem[ 7] <= 32'h01010120;
mem[ 8] <= 32'h01160032;
mem[ 9] <= 32'h01190105;
mem[10] <= 32'h01160104;
mem[11] <= 32'h00320099;
mem[12] <= 32'h01110100;
mem[13] <= 32'h01010032;
mem[14] <= 32'h00480120;
mem[15] <= 32'h00490050;
mem[16] <= 32'h00510052;
mem[17] <= 32'h00330000;
end
else begin
if (we&&cs)
begin
mem[addr] <= data;
end
end
end
endmodule
`timescale 1ns / 1ps
`timescale 1ns / 1ps
module imem(
input clk ,//Input clock
input rstn ,//Reset signal, low active
input [ 4:0] addr ,//memory address
input cs ,
input we ,
inout [31:0] data
);
// For I/O signals
// For internal signals
reg [31:0] mem[0:11] ;
// Circuit implementation
assign data = (cs) ? mem[addr] : 32'bz;
always @ (posedge clk or negedge rstn) begin
if (!rstn) begin
//The hard coded instructions
mem[ 0] <= 32'h10330030;
mem[ 1] <= 32'h203f0030;
mem[ 2] <= 32'h30120030;
mem[ 3] <= 32'h40220030;
mem[ 4] <= 32'h30000230;
mem[ 5] <= 32'h50001200;
mem[ 6] <= 32'h90005130;
mem[ 7] <= 32'h10006000;
mem[ 8] <= 32'ha3011430;
mem[ 9] <= 32'h40120400;
mem[10] <= 32'h200000b1;
mem[11] <= 32'h20000000;
end
else begin
if (cs && we)
begin
mem[addr] = data;
end
end
end
endmodule
module clkrst(
input CLK100MHZ ,//On-board input clock
input rst_btn ,//On-board reset from button, HIGH active
output clk_out ,//The working clk for the rest of circuit
output rstn //The working reset for the rest of circuit, LOW active
);
// For I/O signals
reg clk_50m ;
reg clk_25m ;
// For internal signals
// Circuit implementation
assign rstn = rst_btn;
assign clk_out = CLK100MHZ;
endmodule
Upvotes: 1
Views: 793
Reputation: 62037
In your testbench, the dmem_data
wire is connected to 2 module instance output ports:
processor_core u_processor(
.dmem_data (dmem_data ),
//...
);
dmem u_dmem(
.data (dmem_data )
//...
);
That is fine, but only if one of them is active. Your problem is that both drivers are active at the same time. These are the 2 drivers:
assign dmem_data = (dmem_we)? dmem_data_o : 32'bz; //Issue with assignment
assign data = (cs) ? mem[addr] : 32'bz;
Since dmem_we
and cs
are both 1 at the same time (starting at time 145ns, for example), both are trying to drive the same signal with different values. This results in contention which is why you get X
(unknown).
Here is one place where the tristate enables are both set to 1:
if(imem_addr==7) begin
dmem_cs = 1;
dmem_data_o <= R[R1]; //STR r1, [r2]
dmem_we = 1;
You need to change this logic.
Upvotes: 1