0% found this document useful (0 votes)
16 views39 pages

Module-2 VERILOG HDL Coding Style For Synthesis

The document provides guidelines on Verilog HDL coding styles for synthesis, emphasizing the importance of synthesis-friendly, hardware-efficient, and portable designs. It outlines key synthesis constructs, coding guidelines, and best practices for combinational and sequential logic, including the use of state machines. The document also highlights the significance of avoiding simulation-only constructs and ensuring robust design through proper hierarchy and default assignments.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views39 pages

Module-2 VERILOG HDL Coding Style For Synthesis

The document provides guidelines on Verilog HDL coding styles for synthesis, emphasizing the importance of synthesis-friendly, hardware-efficient, and portable designs. It outlines key synthesis constructs, coding guidelines, and best practices for combinational and sequential logic, including the use of state machines. The document also highlights the significance of avoiding simulation-only constructs and ensuring robust design through proper hierarchy and default assignments.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

BECE407P ASIC DESIGN

Module-2:VERILOG HDL Coding Style for Synthesis

Dr. PRITAM BHATTACHARJEE


Assistant Professor (Senior Grade 2)
School of Electronics Engineering (SENSE)
Vellore Institute of Technology – Chennai
[Link]@[Link], +91 8132863424
Introduction
❖Verilog HDL used for digital design

❖RTL design for synthesis

❖Importance of coding style


Introduction
Objective
Understand and apply proper Verilog HDL coding styles to ensure your designs are:
• Synthesis-friendly
• Hardware efficient
• Portable across tools and FPGAs/ASICs
Why Coding Style Matters
• Ensures RTL code maps correctly to real hardware.
• Prevents simulation-synthesis mismatches.
• Improves timing closure, performance, and tool optimization.
• Avoids unintentional latches, race conditions, and resource bloat.
Key Synthesis Constructs

❖Supported: assign, always, if, case

❖Avoid: initial, #delays, $display (simulation-only)

❖Data types: wire, reg, integer


Data Type Table
Type Usage Notes
wire Continuous assign For combinational logic
reg Procedural assign For storage, FF outputs
integer Loop/indexing Avoid for synthesis outputs
Key Synthesis Constructs - Examples
A simple code snippet that demonstrates supported constructs for synthesis―showing usage of procedural blocks,
blocking/non-blocking assignments, supported data types, and why to avoid simulation-only elements.
module eg (input wire clk, input wire reset, input wire enable, input wire [3:0] data_in, output reg [3:0] out);

// Supported data type for synthesis


reg [3:0] internal_reg;

// Combinational logic using always @(*)


always @(*) begin
// Blocking assignment for combinational logic
if (enable)
internal_reg = data_in + 1; // Supported
else
internal_reg = 4'b0; // Supported
end

// Sequential logic using always @(posedge clk)


always @(posedge clk or posedge reset) begin
if (reset)
out <= 4'b0; // Non-blocking assignment for sequential logic
else
out <= internal_reg;
end

// Avoid this in synthesizable code:


// initial out = 0; // NOT supported for synthesis
// Avoid $display, #delay, $finish, etc.
endmodule
Key Synthesis Constructs - Examples
• Procedural Blocks:
• always @(*) for combinational logic.
• always @(posedge clk or posedge reset) for sequential (flip-flop) logic.
• Assignments:
• Blocking (=) for combinational logic inside always @(*).
• Non-blocking (<=) for sequential logic inside always @(posedge clk).
• Supported Data Types:
• reg, wire, and vector types.
• Simulation-Only Constructs Avoided:
• No initial blocks, # delays, or system tasks like $display.
• Hierarchical Design:
• All inputs/outputs clearly defined at the module interface.
Combinational vs Sequential
Type Use Syntax
Combinational always @(*) Blocking (=)
Sequential always @(posedge clk) Non-blocking (<=)

Combinational Logic
• Use always @(*) or assign statements
• Assign every output in all branches to prevent latches
Sequential Logic (Flip-Flops)
• Use always @(posedge clk) (and/or posedge reset)
• Use non-blocking assignments (<=)
Coding Guidelines
• Use hierarchical modules • Break large designs
• Define all control paths into modules (hierarchy).
• Avoid incomplete if/case • Define all control paths (avoid
incomplete if/case).
• Reset all state elements
• Assign default values to outputs in
each process.
• Implement and connect resets for all
state elements.
• Group related combinational logic for
tool optimization.
Coding Guidelines - Examples
Break Large Designs into Modules Define All Control Paths (Avoid Incomplete if/case)
(Hierarchy)
module data_processor (
// Top-level module
input wire clk,
module top_system (
input wire reset,
input wire clk, input wire start,
input wire reset, input wire [7:0] data_in,
input wire start, output reg [7:0] data_out
input wire [7:0] data_in, );
output wire [7:0] result reg [1:0] state, next_state;
);
wire [7:0] processed_data; localparam IDLE = 2'd0, LOAD = 2'd1, PROC = 2'd2;

// Submodule: Data Processor // State Register with Reset


data_processor u_data_proc ( always @(posedge clk or posedge reset) begin
.clk(clk), if (reset)
state <= IDLE;
.reset(reset),
else
.start(start),
state <= next_state;
.data_in(data_in), end
.data_out(processed_data)
); // Next-State Logic: Complete case statement
always @(*) begin
// Submodule: Result Calculation next_state = state;
result_unit u_result ( case (state)
.clk(clk), IDLE: if (start) next_state = LOAD;
.reset(reset), LOAD: next_state = PROC;
.data_in(processed_data), PROC: next_state = IDLE;
.result(result) default: next_state = IDLE; // Handles unintentional states
); endcase
endmodule end
Coding Guidelines - Examples
Assign Default Values to Outputs in Each Process Implement and Connect Resets for All State Elements
Reset is shown in all state registers of
// Output Logic: Assign default and
override as necessary
the examples, ensuring ALL flip-flops are
always @(*) begin reset to known conditions.
data_out = 8'h00; // Default value Group Related Combinational Logic for Tool Optimization
case (state)
LOAD: data_out = data_in; module result_unit (
PROC: data_out = data_in + 8'd5; input wire clk,
endcase input wire reset,
end input wire [7:0] data_in,
endmodule output reg [7:0] result
);
reg [7:0] sum, diff;

// Grouped combinational logic


always @(*) begin
sum = data_in + 8'd3;
diff = data_in - 8'd1;
end

// Sequential logic for outputs


always @(posedge clk or posedge reset) begin
if (reset)
result <= 0;
else
result <= sum ^ diff; // Using grouped signals
end
endmodule
Coding Guidelines - Examples
Assign Default Values to Outputs in Each Process Implement and Connect Resets for All State Elements
Reset is shown in all state registers of
// Output Logic: Assign default and
override as necessary
the examples, ensuring ALL flip-flops are
always @(*) begin reset to known conditions.
data_out = 8'h00; // Default value Group Related Combinational Logic for Tool Optimization
case (state)
LOAD: data_out = data_in; module result_unit (
PROC: data_out = data_in + 8'd5; input wire clk,
endcase input wire reset,
end input wire [7:0] data_in,
endmodule output reg [7:0] result
);
reg [7:0] sum, diff;

Summary of Coding Practice Demonstrated // Grouped combinational logic


• Hierarchy: Design is split into clear modules always @(*) begin
(top_system, data_processor, result_unit). sum = data_in + 8'd3;
• Complete Control Paths: All if and case statements diff = data_in - 8'd1;
include else/default to avoid unintended latches. end
• Default Assignments: Outputs are assigned default values at
the start of each process. // Sequential logic for outputs
• Resets: Every stateful element (register/FF) uses an explicit always @(posedge clk or posedge reset) begin
reset. if (reset)
• Logic Grouping: Related combinational calculations are result <= 0;
grouped in the same process for clearer, synthesizable paths else
and improved optimization. result <= sum ^ diff; // Using grouped signals
These practices ensure your designs are robust, maintainable, and end
synthesis-optimized. endmodule
State Machines
• Use case statements
• Enumerated types
• One-hot, binary encoding
• Assign defaults
State Machines - Examples
Finite State Machines (FSMs) are essential for designing control logic in digital systems. Well-coded FSMs are critical
for robust, synthesizable hardware. Here’s a detailed explanation:
State Machines - Examples
Finite State Machines (FSMs) are essential for designing control logic in digital systems. Well-coded FSMs are critical
for robust, synthesizable hardware. Here’s a detailed explanation:
1. Use Enumerated Types or One-Hot Encoding as Required by the Synthesis Tool
• Enumerated Types: With Verilog-2001 and later, you can use typedef enum for more readable state encoding.
The synthesizer chooses the optimal encoding by default (often binary), or you can specify.
• One-Hot Encoding: Each state has a single high bit (e.g., for four states: 4'b0001, 4'b0010, 4'b0100,
4'b1000). Some tools and FPGAs optimize for this, yielding faster, simpler logic.
• Example: Enumerated States (Preferred Practice) Example: One-Hot Encoding (Tool-Specific, e.g., for FPGAs)
typedef enum logic [1:0] { parameter IDLE = 4'b0001, LOAD = 4'b0010,
IDLE = 2'b00, PROC = 4'b0100, DONE = 4'b1000;
LOAD = 2'b01, reg [3:0] state, next_state;
PROC = 2'b10,
DONE = 2'b11
} state_t;

state_t state, next_state;


State Machines - Examples
2. Assign All Outputs in Every State (Avoid Latches)
▪ Outputs should be assigned a definite value in every state—otherwise, synthesis infers a latch (undesirable).
▪ Always initialize or set default output values at the start of the combinational process, then override in
specific states.
Example: Output Assignment in FSM (No Latches)
always @(*) begin
out_signal = 1'b0; // Default

Every output is set regardless of the current state.


data_out = 8'h00; // Default

case (state)
IDLE: begin
out_signal = 1'b0;
end
LOAD: begin
data_out = data_in;
end
PROC: begin
data_out = data_in + 8'd1;
end
DONE: begin
out_signal = 1'b1;
end
default: begin
// Covers unintentional state
out_signal = 1'b0;
data_out = 8'h00;
end
endcase
end
State Machines - Examples
2. Assign All Outputs in Every State (Avoid Latches)
▪ Outputs should be assigned a definite value in every state—otherwise, synthesis infers a latch (undesirable).
▪ Always initialize or set default output values at the start of the combinational process, then override in
specific states. 3. Implement Clearly Defined Reset States (Synchronous or
Example: Output Assignment in FSM (No Latches) Asynchronous)
always @(*) begin ▪ Synchronous Reset: State register reset synchronously
out_signal = 1'b0; // Default
with the clock.

Every output is set regardless of the current state.


data_out = 8'h00; // Default
▪ Asynchronous Reset: State register reset immediately,
case (state)
IDLE: begin triggered by the reset signal.
out_signal = 1'b0;
end Example: Synchronous State Register with Reset
LOAD: begin
always @(posedge clk) begin
data_out = data_in;
if (reset)
end
state <= IDLE; // Defined reset state
PROC: begin
else
data_out = data_in + 8'd1;
state <= next_state;
end
end
DONE: begin
out_signal = 1'b1;
end
default: begin
// Covers unintentional state
out_signal = 1'b0;
data_out = 8'h00;
end
endcase
end
State Machines - Examples
2. Assign All Outputs in Every State (Avoid Latches)
▪ Outputs should be assigned a definite value in every state—otherwise, synthesis infers a latch (undesirable).
▪ Always initialize or set default output values at the start of the combinational process, then override in
specific states. 3. Implement Clearly Defined Reset States (Synchronous or
Example: Output Assignment in FSM (No Latches) Asynchronous)
always @(*) begin ▪ Synchronous Reset: State register reset synchronously
out_signal = 1'b0; // Default
with the clock.

Every output is set regardless of the current state.


data_out = 8'h00; // Default
▪ Asynchronous Reset: State register reset immediately,
case (state)
IDLE: begin triggered by the reset signal.
out_signal = 1'b0;
end Example: Synchronous State Register with Reset
LOAD: begin
always @(posedge clk) begin
data_out = data_in;
if (reset)
end
state <= IDLE; // Defined reset state
PROC: begin
else
data_out = data_in + 8'd1;
state <= next_state;
end
end
DONE: begin
out_signal = 1'b1; Example: Asynchronous Reset
end
default: begin always @(posedge clk or posedge reset) begin
// Covers unintentional state if (reset)
out_signal = 1'b0; state <= IDLE;
data_out = 8'h00; else
end state <= next_state;
endcase end
end
State Machines - Examples
2. Assign All Outputs in Every State (Avoid Latches)
▪ Outputs should be assigned a definite value in every state—otherwise, synthesis infers a latch (undesirable).
▪ Always initialize or set default output values at the start of the combinational process, then override in
specific states. 3. Implement Clearly Defined Reset States (Synchronous or
Example: Output Assignment in FSM (No Latches) Asynchronous)
always @(*) begin ▪ Synchronous Reset: State register reset synchronously

Best Practice: Explicitly define the reset state to


out_signal = 1'b0; // Default
with the clock.

Every output is set regardless of the current state.


data_out = 8'h00; // Default

ensure the FSM starts in a known state after reset.


▪ Asynchronous Reset: State register reset immediately,
case (state)
IDLE: begin triggered by the reset signal.
out_signal = 1'b0;
end Example: Synchronous State Register with Reset
LOAD: begin
always @(posedge clk) begin
data_out = data_in;
if (reset)
end
state <= IDLE; // Defined reset state
PROC: begin
else
data_out = data_in + 8'd1;
state <= next_state;
end
end
DONE: begin
out_signal = 1'b1; Example: Asynchronous Reset
end
default: begin always @(posedge clk or posedge reset) begin
// Covers unintentional state if (reset)
out_signal = 1'b0; state <= IDLE;
data_out = 8'h00; else
end state <= next_state;
endcase end
end
Complete FSM Example incorporating these Guidelines
typedef enum logic [1:0] {IDLE = 2'b00, LOAD = 2'b01, PROC = 2'b10, DONE = 2'b11}
fsm_state_t;

module fsm_example (input wire clk, input wire reset, input wire start, input wire
[7:0] data_in, output reg [7:0] data_out, output reg done);
fsm_state_t state, next_state;

// State register: synchronous reset


always @(posedge clk) begin
if (reset)
state <= IDLE;
Summary of Key Points
else
state <= next_state;
▪ Enumerate or clearly encode states—use
end typedef enum or one-hot as needed.
// Next-state logic ▪ Assign outputs for every state—never leave
always @(*) begin
next_state = state; outputs unassigned.
case (state)
IDLE: next_state = (start) ? LOAD : IDLE;
▪ Define resets explicitly—FSM must enter a
LOAD: next_state =
PROC: next_state =
PROC;
DONE;
known state after reset.
DONE: next_state = IDLE; Adhering to these principles ensures your FSMs are
default: next_state = IDLE; // Robustness
endcase robust, synthesis-friendly, and behave as intended
end
on hardware.
// Output logic: assign all outputs in each state
always @(*) begin
data_out = 8'h00; // default
done = 1'b0; // default

case (state)
IDLE: ;
LOAD: data_out = data_in;
PROC: data_out = data_in + 8'd4;
DONE: done = 1'b1;
endcase
end
endmodule
Synthesizable Verilog code and Testbench for "overlapping sequence detection of 0010 using state machine"
overlapping sequence detector that Current Next Output
Input
detects the binary pattern 0010 using State State (Z)
// Combinational logic: next state and output logic
always @(*) begin S0 0 S1 0
a Mealy machine. next_state = state;
z = 0; S0 1 S0 0
•S0: Initial state (no bits detected yet) case (state) S1 0 S2 0
S0: begin
•S1: Detected '0' if (x == 0) S1 1 S0 0
next_state = S1;
•S2: Detected '00' else
S2 0 S2 0
•S3: Detected '001' next_state = S0;
z = 0;
S2 1 S3 0
end S3 0 S1 1
S1: begin
Verilog code if (x == 0)
S3 1 S0 0
next_state = S2;
module seq_det_0010 ( else
input wire clk, next_state = S0;
input wire rst_n, z = 0;
input wire x, // serial input bit stream end
output reg z // output S2: begin
); if (x == 0)
next_state = S2;
// State Encoding else
parameter S0 = 2'd0, S1 = 2'd1, S2 = 2’d2, S3 = 2’d3; next_state = S3;
reg [1:0] state, next_state; z = 0;
end
// Sequential logic: state update S3: begin
always @(posedge clk or negedge rst_n) begin if (x == 0) begin
if (!rst_n) next_state = S1;
state <= S0; z = 1; // Sequence 0010 detected
else end else begin
state <= next_state; next_state = S0;
end z = 0;
end
end
endcase
end

endmodule
Synthesizable Verilog code and Testbench for "overlapping sequence detection of 0010 using state machine"

Testbench
`timescale 1ns/1ps
module tb_seq_det_0010();

reg clk, rst_n, x;


wire z;

seq_det_0010 DUT(.clk(clk), .rst_n(rst_n), .x(x), .z(z));

// Clock generation
initial clk = 0;
always #5 clk = ~clk;

// Stimulus
initial begin
rst_n = 0;
x = 0;
#12 rst_n = 1;

// Test sequence: 0 0 1 0 0 0 1 0 (should detect "0010" twice, with overlap)


#10 x = 0;
#10 x = 0;
#10 x = 1;
#10 x = 0; // "0010" detected, z = 1
#10 x = 0;
#10 x = 0;
#10 x = 1;
#10 x = 0; // "0010" detected again, with overlap
#40; // End
$finish;
end
Clock & Reset Design
• Prefer single clock domain per block.
• Use synchronous reset where possible.
• Register all block outputs for easy timing analysis.
• Synchronize external asynchronous resets to the clock.
Clock & Reset Design
Example: Synthesis-Ready Verilog Code for Clock and Reset
module reg_block (
input wire clk, // Clock input
input wire reset, // Synchronous reset
input wire enable,
input wire [7:0] d_in,
output reg [7:0] q_out
);
always @(posedge clk) begin
if (reset) // Synchronous reset active
q_out <= 8'b0; // Initialize to a known value
else if (enable)
q_out <= d_in; // Register update on clock edge
end
endmodule
Clock & Reset Design
Example: Synthesis-Ready Verilog Code for Clock and Reset Key Points in Clock & Reset Coding for Synthesis
module reg_block (
input wire clk, // Clock input • Single Clock Domain:
input wire reset, // Synchronous reset
input wire enable, • Use one clock per block or module whenever
input wire [7:0] d_in,
output reg [7:0] q_out possible.
);
always @(posedge clk) begin • Avoid unnecessary complexity and clock
if (reset) // Synchronous reset active
q_out <= 8'b0; // Initialize to a known value domain crossings in a unit.
else if (enable)
q_out <= d_in; // Register update on clock edge • Synchronous Reset (Preferred):
end
endmodule • The reset logic updates state only on a
positive clock edge.
• Synchronous resets are more predictable and
easier to constrain/timing optimize in
ASIC/FPGA flow.
• Example here uses if (reset) within
an always @(posedge clk) block.
Clock & Reset Design
Example: Synthesis-Ready Verilog Code for Clock and Reset Asynchronous Reset (If Required, Use Carefully):
module reg_block (
input wire clk, // Clock input • If hardware constraints need asynchronous reset,
input wire reset, // Synchronous reset
input wire enable,
write:
input wire [7:0] d_in, always @(posedge clk or posedge reset) begin
output reg [7:0] q_out
); if (reset)//Asynchronously sets value immediately
always @(posedge clk) begin
q_out <= 8'b0;
if (reset) // Synchronous reset active
q_out <= 8'b0; // Initialize to a known value else if (enable)
else if (enable)
q_out <= d_in; // Register update on clock edge q_out <= d_in;
end end
endmodule
• Asynchronous resets are instantly responsive but
can introduce metastability if not properly
synchronized for de-assertion.
Clock & Reset Design
Example: Synthesis-Ready Verilog Code for Clock and Reset • Register Block Outputs:
module reg_block (
input wire clk, // Clock input ▪ All output signals (especially across module
input wire reset, // Synchronous reset
input wire enable,
boundaries) should be registered to help with
input wire [7:0] d_in, static timing analysis and placement/routing.
output reg [7:0] q_out
);
always @(posedge clk) begin
• No Clock Gating Logic in RTL:
if (reset) // Synchronous reset active
q_out <= 8'b0; // Initialize to a known value ▪ Avoid gating clock signals with
else if (enable)
q_out <= d_in; // Register update on clock edge
combinational logic or enable signals.
end
endmodule ▪ Instead, use enable signals inside sequential
blocks, as shown, for power/cell optimization.
Clock gating will be implemented
automatically in the synthesis/physical tools
when requested.
• All FFs Initialized:
▪ Explicit reset path ensures all registers begin
in a known state, crucial for reliable hardware
bring-up and functional simulation.
Memory Block Coding
• Inferred RAM/ROM
• Synchronous read/write
• Use arrays (reg [n:0] mem [m:0];)
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
1. Single-Port RAM (Synchronous Write, Asynchronous Read) • Declares a 16×8 memory using reg [7:0]
module single_port_ram ( mem[0:15].
input wire clk,
input wire we,
input wire [3:0] addr,
• Write happens on the clock’s rising edge
input wire [7:0] din, (synchronous).
output reg [7:0] dout
);
reg [7:0] mem [0:15]; // 16 × 8-bit memory
• Read is combinational (asynchronous).
// Synchronous write, asynchronous read • Many FPGAs infers distributed RAM with
always @(posedge clk) begin
if (we)
this template. Some ASIC flows require
mem[addr] <= din; synchronous read.
end

always @(*) begin


dout = mem[addr]; // Asynchronous read
end
endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
2. Single-Port RAM with Synchronous Read (Fully Synchronous FF/Block RAM)
module sync_ram (
input wire clk,
▪ Both read and write occur on clock edge.
input wire we, ▪ The output holds the data present at the addressed
input wire [3:0] addr,
input wire [7:0] din,
location after the clock edge.
output reg [7:0] dout ▪ Most FPGAs and ASICs infer true dual-port/block RAM
);
reg [7:0] mem [0:15];
with this style.

always @(posedge clk) begin


if (we)
mem[addr] <= din; // Synchronous write
dout <= mem[addr]; // Synchronous read
end
endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
3. Dual-Port RAM (Two Independent Ports) ▪ Both ports can read/write independently at different addresses.
module dual_port_ram ( ▪ FPGAs map this to hardware block RAM with two ports.
input wire clk,
// Port A signals
▪ Always avoid simultaneous write to same address from both
input wire we_a, ports—behavior is undefined.
input wire [3:0] addr_a,
input wire [7:0] din_a,
output reg [7:0] dout_a,
// Port B signals
input wire we_b,
input wire [3:0] addr_b,
input wire [7:0] din_b,
output reg [7:0] dout_b
);
reg [7:0] mem [0:15];

always @(posedge clk) begin


// Port A
if (we_a)
mem[addr_a] <= din_a;
dout_a <= mem[addr_a];
// Port B
if (we_b)
mem[addr_b] <= din_b;
dout_b <= mem[addr_b];
end
endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
3. Dual-Port RAM (Two Independent Ports) • No Dedicated Dual-Port RAM Hardware: ASIC standard cell libraries
typically do not include configurable block RAMs like FPGAs. Instead,
module dual_port_ram (
input wire clk, memories must be constructed from either:
// Port A signals
input wire we_a,
• Custom memory macros generated by memory compilers (offered by
input wire [3:0] addr_a, foundries or EDA vendors),
input wire [7:0] din_a,
output reg [7:0] dout_a,
• Or, if small, arrays of flip-flops/registers synthesized from standard-cell
// Port B signals D flip-flops.
input wire we_b,
input wire [3:0] addr_b, • Memory Compiler Macros:
input wire [7:0] din_b,
• Dual-port or multi-port SRAMs are often instantiated as memory hard
output reg [7:0] dout_b
); macros. These are pre-designed and characterized blocks that are not
reg [7:0] mem [0:15]; synthesized from behavioural code, but instead are instantiated as black-
box macros with specific library views (.lib, .lef, etc.).
always @(posedge clk) begin
// Port A • When writing portable Verilog, you use a generic "coding style" for a dual-
if (we_a) port RAM (matching the macro's behaviour), and during synthesis, you
mem[addr_a] <= din_a;
dout_a <= mem[addr_a];
either:
// Port B • Replace/infer ("black-box replace") that code with the foundry's
if (we_b)
mem[addr_b] <= din_b;
optimized dual-port memory,
dout_b <= mem[addr_b]; • Or guide the synthesis tool (via constraints/pragmas or scripts) to use
end
endmodule a specific macro matching your interface.
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
3. Dual-Port RAM (Two Independent Ports) • Small DPRAMs with Flops:
module dual_port_ram ( • If your memory is small and a macro is not used/inferred, the
input wire clk, synthesis tool will build the RAM using arrays of
// Port A signals
input wire we_a, registers/flip-flops. This is inefficient for anything above a
input wire [3:0] addr_a, few words/depth, but functionally correct for ASIC.
input wire [7:0] din_a,
output reg [7:0] dout_a, • This means that a dual-port RAM (with two independent
// Port B signals read/write ports) would require duplicating underlying
input wire we_b,
input wire [3:0] addr_b, registers such that every collision/priority/clocking rule is
input wire [7:0] din_b, satisfied with combinatorial and sequential logic — an
output reg [7:0] dout_b
); approach that is area and power expensive.
reg [7:0] mem [0:15];

always @(posedge clk) begin


// Port A
if (we_a)
mem[addr_a] <= din_a;
dout_a <= mem[addr_a];
// Port B
if (we_b)
mem[addr_b] <= din_b;
dout_b <= mem[addr_b];
end
endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
Key Points
3. Dual-Port RAM (Two Independent Ports)
module dual_port_ram ( • Performance and Area:
input wire clk,
// Port A signals • ASIC dual-port macros are highly optimized for area and
input wire we_a, timing.
input wire [3:0] addr_a,
input wire [7:0] din_a,
output reg [7:0] dout_a,
• If not mapped to a macro, synthesized RAMs will be much
// Port B signals larger and slower than FPGA block RAMs.
input wire we_b,
input wire [3:0] addr_b, • Design Flow:
input wire [7:0] din_b,
output reg [7:0] dout_b • Synopsys Design Compiler, Cadence Genus, or similar tools
);
reg [7:0] mem [0:15];
allow you to specify which memories should be "black-
boxed" and then replaced with foundry-specific macros
always @(posedge clk) begin
// Port A
during Place & Route.
if (we_a)
mem[addr_a] <= din_a; • Verification:
dout_a <= mem[addr_a];
// Port B • Since macros are black boxes, their functionality is normally
if (we_b) simulated using behavioural models (Verilog) that match the
mem[addr_b] <= din_b;
dout_b <= mem[addr_b]; macro's interface.
end
endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
3. Dual-Port RAM (Two Independent Ports)
module dual_port_ram (
input wire clk,
// Port A signals
input wire we_a,
input wire [3:0] addr_a,
input wire [7:0] din_a,
output reg [7:0] dout_a,
// Port B signals
input wire we_b,
input wire [3:0] addr_b,
input wire [7:0] din_b,
output reg [7:0] dout_b
);
reg [7:0] mem [0:15];

always @(posedge clk) begin


// Port A
if (we_a)
mem[addr_a] <= din_a;
dout_a <= mem[addr_a];
// Port B
if (we_b)
mem[addr_b] <= din_b;
dout_b <= mem[addr_b];
end
endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
module rom_init (
4. ROM (Read-Only Memory) • ROM contents are “hardcoded” input wire [3:0] addr,
output reg [7:0] data);
module rom ( using a case statement. reg [7:0] rom [0:15]; // 16 × 8 ROM
input wire [2:0] addr, • Can also use initial begin
output reg [7:0] dout // Initialize ROM contents
); ... for simulation or synthesis initial begin
always @(*) begin rom[0] = 8'hDE;
case (addr)
with inferred ROMs in some rom[1] = 8'hAD;
3'd0: dout = 8'hA5; tools. rom[2] = 8'hBE;
3'd1: dout = 8'h1C; rom[3] = 8'hEF;
3'd2: dout = 8'hBE; rom[4] = 8'h12;
3'd3: dout = 8'hEF; rom[5] = 8'h34;
// ... (initialize as needed) rom[6] = 8'h56;
default: dout = 8'h00; rom[7] = 8'h78;
endcase rom[8] = 8'h9A;
end rom[9] = 8'hBC;
endmodule rom[10] = 8'hCD;
rom[11] = 8'hEF;
▪ The initial begin ... end block loads constant values into the ROM array at rom[12] = 8'h00;
rom[13] = 8'h11;
elaboration time, which is fully supported for simulation. rom[14] = 8'h22;
▪ Some ASIC flows can also infer a ROM from this construct, mapping it to rom[15] = 8'h33;
embedded ROM resources. Some synthesis tools might require a specific setting to end
preserve initial values. always @(*) begin
data = rom[addr];
▪ Not all ASIC tools support this for synthesis—always check your tool end
documentation and target technology capabilities. endmodule
Memory Block Coding
Synthesizable memory coding allows the synthesis tools to infer hardware RAM/ROM from your Verilog RTL.
Correct memory coding style ensures proper mapping to physical resources (block RAM, LUT RAM, registers) in
ASICs and FPGAs.
Best Practice Guidelines
• Module Memories, Use Arrays: Use reg [WIDTH-1:0] mem [0:DEPTH-1] for RAM/ROM.
• Synchronous Write, Synchronous/Asynchronous Read: Synchronous clocking ensures reliable synthesis and
timing closure.
• No initial or dynamic allocation at runtime: Use static definitions and initialization for synthesizability.
• Explicit Behaviour for Write/Read-Write: Always define what happens on simultaneous read/write to the same
address—if not defined, results differ across vendors.
• Arrays are Not Synthesizable at the Top Module Port: Keep memory arrays internal to modules, not directly
exposed at I/O.
Tri-state & I/O Ports
• Restrict tri-state logic to top-level
• Conditional assignments only where essential
• Avoid internally
Best Practice Summary
Practice Reason
Register I/O Timing closure
Non-blocking for seq. logic Synthesizer-friendly
Avoid unwanted latches Stability
Use @(*)for comb. logic Accurate sensitivity

You might also like