Optimizing the registerfile code in systemverilog - verilog

I am implementing a 32bit RegFile(containing 32 registers). Now, for the combinational part, I am planning to use the switch case to out the read value of the 32registers based on the input register number. This is resulting in a switch case with 32cases and a default case. Is there any other way to optimize the code? Constraint is that my output needs to be a register and hence I am unable to use the following statement(containing assign):
assign rdDataA = rdAddrA == 0 ? reg0
Code:
module RegFile(input [4:0] src_rd_1,
input [4:0] src_rd_2,
input [4:0] des_wr_1,
input [31:0] data,
input clk,
input reset,
input wr_en,
output reg rd_val_1,
output reg rd_val_2
);
reg [31:0] register[31:0];
always_comb begin
case(src_rd_1)
5'd0:begin
rd_val_1=register[0];
end
5'd1:begin
rd_val_1=register[1];
end
5'd2:begin
rd_val_1=register[2];
end
5'd3:begin
rd_val_1=register[3];
end
5'd4:begin
rd_val_1=register[4];
//and so on...
end
Update:
I found out a way to optimize the code. I hope this would work...Any other suggestions are welcome
if(src_rd_1>=0)
begin
if(src_rd_1==0)
begin
rd_val_1=32'd0;
end
else
begin
rd_val_1=register[src_rd_1];
end
end
Any advise will helpful. TIA

The following is allowed by simulation tools:
always_comb begin
rd_val_1 = register[src_rd_1];
end
You'll have to try it out and see if your synthesis tool supports this.

Using reg doesn't mean it will synthesize to a register. To synthesize to a register a reg (or for SystemVerilogpreferablylogic`) should be assigned in a sequential always block.
always_ff #(posedge clk) begin
rd_val_1 <= register[src_rd_1];
end
Flopping the output makes it a clean, glitch-free output and doesn't add to the combinational propagation delay to any receiving modules.

Related

How to assign initial value to an input reg: Design compiler delete the assignment

I'm newbie in ASIC design. I have a design with for example two inputs a ,b. I'm using the following code for initialize these two signals. But the Design compiler generating a warning that the register "a" is a constant and will be removed. When I'm trying to do post-synthesis simulation these two signals are all 'z'. So how can I apply initial signal assignment to avoid such a problem?
always #(posedge(clk) or posedge (rst)) begin
if (rst) begin
a<=4d'5;
b <=4'd10;
end
end
While describing hardware system, you need to consider that input signals to your module comes from another module/system and their values are decided by that signals. Inputs to any module can only be wire type.
You can think of a module as a box that has inputs and outputs. The values of output signals are decided by input signal + logic inside the box. However, the module cannot decide what its inputs should be. It is only possible if there is feedback, and even in that case it would depend on other signals that are outside of the module's control.
As a result, output signals can be declared as output reg but the same is not true for inputs. However there is solution to your problem, I think what you want can be designed using the following method:
module your_module(
input clk,
input rst,
//other inputs and outputs that you might need
input [3:0] a,
input [3:0] b
);
//define registers
reg [3:0] a_register;
reg [3:0] b_register;
/*
These registers are defined to make it possible to
to give any value to that logics when posedge rst
is detected, otherwise you can use them as your
input logics
*/
//use initial block if you need
always#(posedge clk or posedge rst) begin
if(rst) begin
a_register <= 4'd5;
b_register <= 4'd10;
end
else
begin
a_register <= a;
b_register <= b;
// and use a_register and b_register as you want to use a and b
end
end
endmodule

What's wrong with my "parallel to serial" verilog code

I'm trying to design a parallel to serial converter. But my final waveform look like this:
Here is my code, thanks in advance.
module parallel2serial#(parameter size=4)(pin, clk, load, rst, sout, finish);
input [size-1 :0] pin;
input clk, rst, load;
output reg finish;
output sout;
reg [2:0]count;
reg [size-1 :0] data;
reg dout;
always#(posedge clk)begin
if(!rst)begin dout<=0; end
else if(!load)begin
data<=data>>1;
dout<=data[size-1];
end
else data<=pin;
end
always#(posedge clk)begin
if(!rst)begin count<=0; finish<=0;end
else begin
if(count==2'b11) begin count<=0; finish<=1;end
else begin count<=count+1; finish<=0;end
end
end
assign sout=dout;
endmodule
There's at least one mistake. You're shifting data towards the least significant bit (to the right), while taking the output from the most significant bit. You should either output lsb instead of msb, or change the direction of register shifting.

Verilog code runs in simulation as i predicted but does not in FPGA

I try to write an UART transmitter module. It gets data from data[7:0] and then sends it serially via Tx. I wrote a module named Tester for testing transmitter. It simulates in Isim as I predicted but does not in Spartan-6. I watched the Tx pin with osciloscope, I saw only logic 1. I could not detect the problem. What have I done incorrectly?
module Tester(
clk,
data,
oclk,
Tx
);
input wire clk;
output reg [7:0] data;
output wire oclk;
output wire Tx;
assign oclk = clk;
initial begin
data<=8'b11001010;
end
UartTransmitter UT(.clk(clk),.data(8'b11001010),.Tx(Tx),.transmit(1'b1));
endmodule
module UartTransmitter(
//Inputs
clk,
reset,
data,
transmit,
//Output
Tx
);
input wire clk;
input wire reset;
input wire [7:0] data;
input wire transmit;
output reg Tx;
reg [16:0] counter;
reg durum;
reg s_durum;
reg sendbyone;
reg [10:0]buffer;
reg [3:0]nbitstransmitted;
parameter IDLE = 1'b0;
parameter TRANSMITTING = 1'b1;
initial begin
counter=0;
Tx=1;
s_durum = IDLE;
durum=IDLE;
sendbyone=0;
buffer=0;
nbitstransmitted=0;
end
always #(posedge clk) begin
counter<=counter+1;
if(counter>=13019) begin
counter<=0;
sendbyone<=1;
end else begin
sendbyone<=0;
end
durum<=s_durum;
end
always #(*) begin
s_durum=durum;
if((durum==IDLE) && (transmit==1)) begin
buffer={1'b1,^data,data,1'b0};
s_durum=TRANSMITTING;
end
else if(durum==TRANSMITTING && (sendbyone==1)) begin
if(nbitstransmitted<10) begin
Tx=buffer[nbitstransmitted];
nbitstransmitted=nbitstransmitted+1;
end else if(nbitstransmitted==10)begin
Tx=buffer[10];
nbitstransmitted=0;
s_durum=IDLE;
end
end
end
endmodule
buffer, Tx and nbitstransmitted are inferred latches. Latches are inferred when a variable is not guaranteed assignment with in an combinational block (always #*). buffer is a simple latch because the control logic is coming from flops. Tx will be simple latch after nbitstransmitted is changed to a flip-flop. The main issue is nbitstransmitted because it has feedback. With the current design in simulation if data changes when durum==TRANSMITTING && sendbyone then nbitstransmitted will increment. Even if data is from a flop in the same clock domain, on the FPGA there can be skew on each bit and trigger multiple updates.
Complex latches are prone to race conditions and use up lots of area. As an example, I copied the provide code to EDAplayground and synthesized it with Yosys 0.3.0. With the "show diagram" enabled it will show a large number of gates used with sufficient latch feedback. Try running here (Sorry I cannot upload the diagram, maybe someone else can)
The solution is easy by following the same strategy already used for durum; create a next state variable. sticking with the current convention, create new variables for buffer, Tx and nbitstransmitted with the respected names with a s_ prefix. The combinational block (always #*) will assign the s_ signals and should default to there respected counter part. And the sequential block (always #(posedge clk)) will assign the flops by their respected s_. The flops with remove the asynchronous feedback and simplify the design. For cleaner design, I moved the counter<=counter+1; into the else condition and commented out if(nbitstransmitted==10). Try running here
Other note not related to the issue:
The reset signal is not being used. I suggest using it in the sequential block and remove the initial block. Most FPGAs support initial and most ASIC do not. I prefer using reset signals over initial blocks because it allows resetting the device without having to power cycle. Just a suggestion.

Default values of RAM

I writing in Verilog HDL for synthesis and I want to instantiate a DUAL PORT RAM with default values (zeros), how can do it?
Thanks, Netanel
As you mentioned Virtex-7 - look in the Xilinx Synthesis manual for examples of how to write Verilog that infers a memory block.
In Appendix C you can find this code:
// Dual-Port Block RAM with Two Write Ports
// File: HDL_Coding_Techniques/rams/rams_16.v
module v_rams_16 (clka,clkb,ena,enb,wea,web,addra,addrb,dia,dib,doa,dob);
input clka,clkb,ena,enb,wea,web;
input [9:0] addra,addrb;
input [15:0] dia,dib;
output [15:0] doa,dob;
reg [15:0] ram [1023:0];
reg [15:0] doa,dob;
always #(posedge clka) begin if (ena)
begin
if (wea)
ram[addra] <= dia;
doa <= ram[addra];
end
end
always #(posedge clkb) begin if (enb)
begin
if (web)
ram[addrb] <= dib;
dob <= ram[addrb];
end
end
endmodule
I'm not a Verilogger, but I'm sure you can tweak the ram declaration to make it initialise with all zeros.

Assign a synthesizable initial value to a reg in Verilog

I'm an FPGA noob trying to learn Verilog. How can I "assign" a value to a reg in an always block, either as an initial value, or as a constant. I'm trying to do something like this in the code below. I get an error because the 8 bit constant doesn't count as input. I also don't want to trigger the always off of a clock. I just want to assign a register to a specific value. As I want it to be synthesisable I can't use an initial block. Thanks a lot.
module top
(
input wire clk,
output wire [7:0] led
);
reg [7:0] data_reg ;
always #*
begin
data_reg = 8'b10101011;
end
assign led = data_reg;
endmodule
You can combine the register declaration with initialization.
reg [7:0] data_reg = 8'b10101011;
Or you can use an initial block
reg [7:0] data_reg;
initial data_reg = 8'b10101011;
You should use what your FPGA documentation recommends. There is no portable way to initialize register values other than using a reset net. This has a hardware cost associated with it on most synthesis targets.
The other answers are all good. For Xilinx FPGA designs, it is best not to use global reset lines, and use initial blocks for reset conditions for most logic. Here is the white paper from Ken Chapman (Xilinx FPGA guru)
http://japan.xilinx.com/support/documentation/white_papers/wp272.pdf
The always #* would never trigger as no Right hand arguments change. Why not use a wire with assign?
module top (
input wire clk,
output wire [7:0] led
);
wire [7:0] data_reg ;
assign data_reg = 8'b10101011;
assign led = data_reg;
endmodule
If you actually want a flop where you can change the value, the default would be in the reset clause.
module top
(
input clk,
input rst_n,
input [7:0] data,
output [7:0] led
);
reg [7:0] data_reg ;
always #(posedge clk or negedge rst_n) begin
if (!rst_n)
data_reg <= 8'b10101011;
else
data_reg <= data ;
end
assign led = data_reg;
endmodule
Hope this helps
When a chip gets power all of it's registers contain random values. It's not possible to have an an initial value. It will always be random.
This is why we have reset signals, to reset registers to a known value. The reset is controlled by something off chip, and we write our code to use it.
always #(posedge clk) begin
if (reset == 1) begin // For an active high reset
data_reg = 8'b10101011;
end else begin
data_reg = next_data_reg;
end
end

Resources