Digital Frontand Development Workflow
The complete digital IC design process follows this sequence:
- Design specification creation
- RTL implementation
- RTL simulation and verification
- Spyglass static analysis
- FPGA prototyping
- Design Compiler synthesis
- Formality equivalence checking on synthesized netlist
- Post-synthesis netlist simulation
- Physical design and place-and-route
- Formality checking on final netlist
- Post-layout simulation verification
- LVS verification
Toolchain Configuration
- Compiler: Synopsys VCS
- Debugger: Synopsys Verdi
- Synthesizer: Synopsys Design Compiler
- Static Enalyzer: Synopsys Spyglass
- Equivalence Checker: Synopsys Formality 2018
Coding Standards and Implementation
Naming Conventions
- Active-low signals use "_n" suffix
- Module names: lowercase_with_underscores
- Instance names: u_ prefix with numbering (u_module_0, u_module_1)
- Vector declaration: [high:low] with LSB at position 0
- Clock signals: "clk" prefix
- Reset signals: "rst" prefix
- Divided clocks: "clk_ratio" suffix (e.g., clk_128)
Module Structure Template
module example_module #
(
DATA_BITS = 32,
ADDR_BITS = 5
)
(
input clk,
input rst_n,
input [ADDR_BITS-1:0] cmd_addr,
output reg [DATA_BITS-1:0] cmd_data
);
// Macro definitions
`define CHIP_ID 32'h1234_5678
// Parameters
parameter MEM_DEPTH = 32;
// Internal signals
reg [DATA_BITS-1:0] memory [MEM_DEPTH-1:0];
// Logic implementation
always @(posedge clk or negedge rst_n) begin
// Implementation details
end
endmodule
Finite State Machine Implementation
module state_controller(
input clk,
input rst_n,
input [1:0] cmd_input,
output reg [1:0] state_out
);
parameter IDLE_ST = 2'b00;
parameter ACTIVE_ST = 2'b01;
parameter DONE_ST = 2'b10;
reg [1:0] curr_state, next_state;
// State register
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
curr_state <= IDLE_ST;
end else begin
curr_state <= next_state;
end
end
// Next state logic
always @(*) begin
case(curr_state)
IDLE_ST: begin
if(cmd_input == 2'b01) begin
next_state = ACTIVE_ST;
end else begin
next_state = IDLE_ST;
end
end
ACTIVE_ST: begin
if(cmd_input == 2'b10) begin
next_state = DONE_ST;
end else begin
next_state = ACTIVE_ST;
end
end
DONE_ST: begin
if(cmd_input == 2'b01) begin
next_state = IDLE_ST;
end else begin
next_state = DONE_ST;
end
end
default: next_state = IDLE_ST;
endcase
end
// Output logic
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state_out <= 2'b00;
end else begin
case(curr_state)
IDLE_ST: state_out <= 2'b00;
ACTIVE_ST: state_out <= 2'b01;
DONE_ST: state_out <= 2'b10;
default: state_out <= 2'b00;
endcase
end
end
endmodule
Register File Implementation
module register_bank #(
parameter ADDR_BITS = 5,
parameter DATA_BITS = 32,
parameter REG_COUNT = 32
) (
input clk,
input rst_n,
input write_en,
input [ADDR_BITS-1:0] read_addr1,
input [ADDR_BITS-1:0] read_addr2,
input [ADDR_BITS-1:0] write_addr,
input [DATA_BITS-1:0] write_data,
output [DATA_BITS-1:0] read_data1,
output [DATA_BITS-1:0] read_data2
);
reg [DATA_BITS-1:0] registers [REG_COUNT-1:0];
// Write port (synchronous)
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
for(int i=0; i<reg_count assign="" begin="" else="" end="" endmodule="" i="i+1)" if="" ports="" read="" read_data1="registers[read_addr1];" read_data2="registers[read_addr2];" registers="" write_data=""></reg_count>
Clock Divider Implementation
module clock_divider #(
parameter DIV_FACTOR = 10
) (
input clk,
input rst_n,
output reg div_clk
);
reg [7:0] counter;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
div_clk <= 0;
end else if (counter == DIV_FACTOR - 1) begin
counter <= 0;
div_clk <= ~div_clk;
end else begin
counter <= counter + 1;
end
end
endmodule
Project Directory Structure
.
|-- documentation
| `-- specifications.pdf
|-- libraries
| `-- technology_lib
|-- outputs
| |-- netlists
| `-- gds_files
|-- project
| |-- Makefile
| `-- file_list.f
|-- source
| |-- rtl
| `-- constraints
|-- testbench
| |-- test_data
| `-- test_module.v
`-- workspace
|-- synthesis
|-- equivalence
|-- analysis
|-- simulation
`-- debugging
Design Reliability Guidelines
- Single clock per synchronous always block
- Synchronous design methodology preferred
- Avoid clock signals as data inputs
- No logic in clock or reset paths
- Non-blocking assignments in sequential logic
- Blocking assignments in combinational logic
- Prevent latch inference
- Avoid combinational loops
- UTF-8 encoding for all source files
- ANSI-style port declarations
- One module per file principle