yosys记录
ALU实验
参考https://nju-projectn.github.io/dlco-lecture-note/exp/03.html
写了个实验3的代码
top.v
`timescale 1ns/1ns
module top (
input clk,
input [2:0] op,
input [3:0] A,
input [3:0] B,
output [3:0] O,
output C_OUT
);
reg empty_reg = 0;
always @(posedge clk) begin
empty_reg <= ~empty_reg;
end
wire inv_B_flag;
assign inv_B_flag = (op == 3'b001) | (op == 3'b110) | (op == 3'b111);
wire [3:0] oped_B;
assign oped_B = (inv_B_flag) ? (~B) : B;
wire c_in;
assign c_in = inv_B_flag;
wire [3:0] s_out;
wire c_out;
assign C_OUT = c_out;
adder u_adder(
.a_in ( A ),
.b_in ( oped_B ),
.c_in ( c_in ),
.s_out ( s_out ),
.c_out ( c_out )
);
assign O = (op == 3'b000) ? s_out :
(op == 3'b001) ? s_out :
(op == 3'b010) ? ~A :
(op == 3'b011) ? A & B :
(op == 3'b100) ? A | B :
(op == 3'b101) ? A ^ B :
(op == 3'b110) ? {3'b0, s_out[3]} :
(op == 3'b111) ? {3'b0, ~(|s_out)} : 0 ;
initial begin
$display("hello, this is adder");
// $display("[%0t] Tracing to logs/vlt_dump.vcd...\n", $time);
$dumpfile("logs/vlt_dump.vcd");
$dumpvars();
// $display("[%0t] Model running...\n", $time);
end
endmodule
adder.v
adder.v 使用了超前进位c,参考https://blog.csdn.net/weixin_39921131/article/details/111178335
module adder (
input [3:0] a_in,
input [3:0] b_in,
input c_in,
output [3:0] s_out,
output c_out
);
wire [3:0]G;
wire [3:0]P;
wire [4:0]C;
assign P = a_in ^ b_in;
assign G = a_in & b_in;
assign C[0] = c_in;
assign C[1] = G[0] | (P[0] & c_in);
assign C[2] = G[1] | (P[1] & G[0]) | (P[1] & P[0] & c_in);
assign C[3] = G[2] | (P[2] & G[1]) | (P[2] & P[1] & G[0]) | (P[2] & P[1] & P[0] & c_in);
assign C[4] = G[3] | (P[3] & G[2]) | (P[3] & P[2] & G[1]) | (P[3] & P[2] & P[1] & G[0]) | (P[3] & P[2] & P[1] & P[0] & c_in);
assign s_out = P ^ C[3:0];
assign c_out = C[4];
endmodule
sim.cpp
sim.cpp 类似于 vivado中的tb.v类似,只不过这个是通过cpp来生成激励
在开启trace之后,如果需要查看波形,则tfp->dump(contextp->time());
contextp->timeInc(1);
是必须的,只有例化tfp并调用了dump数据才会落实到最后wave.vcd文件中去
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
#include <string>
// Include common routines
#include <verilated.h>
// Include model header, generated from Verilating "top.v"
#include "Vtop.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
std::string INT_OP_2_STR_OP[] = {"+", "-", "~", "&", "|", "^", "lt", "eq"};
void print_info(const Vtop* top) {
std::string str_op = INT_OP_2_STR_OP[(const int)top->op];
std::bitset<4> bin_A(top->A);
std::bitset<4> bin_B(top->B);
std::bitset<4> bin_O(top->O);
if (str_op == "~") {
std::cout << str_op << " A" << " = " << str_op << " " << bin_A << " = " << bin_O << std::endl;
} else {
std::cout << "A " << str_op << " B" << " = " ;
std::cout << bin_A << " " << str_op << " " << bin_B << " = " << bin_O << std::endl;
}
}
int main(int argc, char** argv) {
// See a similar example walkthrough in the verilator manpage.
// This is intended to be a minimal example. Before copying this to start a
// real project, it is better to start with a more complete example,
// e.g. examples/c_tracing.
// Construct a VerilatedContext to hold simulation time, etc.
VerilatedContext* contextp = new VerilatedContext;
VerilatedVcdC* tfp = new VerilatedVcdC(); //初始化VCD对象指针
contextp->commandArgs(argc, argv);
Vtop* top = new Vtop{contextp};
contextp->traceEverOn(true); //打开追踪功能
top->trace(tfp, 0);
tfp->open("wave.vcd"); //设置输出的文件wave.vcd
top->op = 0b000;
top->A = 0b1010;
top->B = 0b0101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b001;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b010;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b011;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b100;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b101;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
printf("\nis lt: \n");
top->op = 0b110;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b110;
top->A = 0b1110;
top->B = 0b1001;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b110;
top->A = 0b1110;
top->B = 0b1110;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
printf("\nis eq: \n");
top->op = 0b111;
top->A = 0b1010;
top->B = 0b1101;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b111;
top->A = 0b1110;
top->B = 0b1001;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->op = 0b111;
top->A = 0b1110;
top->B = 0b1110;
top->eval();
print_info(top);
tfp->dump(contextp->time());
contextp->timeInc(1);
top->eval();
tfp->dump(contextp->time());
contextp->timeInc(1);
// Final model cleanup
top->final();
tfp->close();
// Destroy model
delete top;
delete contextp;
// Return good completion status
return 0;
}
Makefile
此处Makefile是通过verilator生成,sim的可执行文件top
其中–trace参数在需要查看波形的时候必须要提供
verilator的结果将全部存放在build/目录下
TOPNAME = top
INC_PATH ?=
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
else
export VERILATOR_ROOT
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
endif
VERILATOR_CFLAGS += -MMD --build -cc --exe\
--x-assign fast --x-initial fast \
--assert --trace -Wall --build --coverage
# -O3
BUILD_DIR = ./build
OBJ_DIR = $(BUILD_DIR)/obj_dir
LOG_DIR = $(BUILD_DIR)/log
BIN = $(BUILD_DIR)/$(TOPNAME)
default: $(BIN)
$(shell mkdir -p $(BUILD_DIR))
$(shell mkdir -p $(LOG_DIR))
# project source
VSRCS = $(shell find $(abspath ./vsrc) -name "*.v")
CSRCS = $(shell find $(abspath ./csrc) -name "*.c" -or -name "*.cc" -or -name "*.cpp")
# rules for verilator
INCFLAGS = $(addprefix -I, $(INC_PATH))
CXXFLAGS += $(INCFLAGS) -DTOP_NAME="\"V$(TOPNAME)\""
$(BIN): $(VSRCS) $(CSRCS)
@rm -rf $(OBJ_DIR)
$(VERILATOR) $(VERILATOR_CFLAGS) \
--top-module $(TOPNAME) $^ \
$(addprefix -CFLAGS , $(CXXFLAGS)) $(addprefix -LDFLAGS , $(LDFLAGS)) \
--Mdir $(OBJ_DIR) \
-o $(abspath $(BIN))
all: default
run: $(BIN)
@$^
clean:
rm -rf $(BUILD_DIR)
.PHONY: default all clean run
iEDAMakefile
这个Makefile拷贝了yosys-sta的环境到本目录
即make -f iEDAMakefile init
之后的make -f iEDAMakefile sta
是通过iEDA对verilator生成的综合后文件做静态时序分析
所有结果将存放在result/目录下
PROJ_PATH = $(shell pwd)
PROJ_NAME = $(notdir $(PROJ_PATH))
YOSYS_PATH = /home/odjvnrij/yosys-sta
IEDA_PATH = /home/odjvnrij/yosys-sta/bin/iEDA
DESIGN ?= top
export CLK_FREQ_MHZ ?= 500
LIB_DIR = $(PROJ_PATH)/lib
SCRIPT_DIR = $(PROJ_PATH)/scripts
NANGATE45_DIR = $(PROJ_PATH)/nangate45
RESULT_DIR = $(PROJ_PATH)/result/$(DESIGN)-$(CLK_FREQ_MHZ)MHz
SDC_FILE ?= $(PROJ_PATH)/$(DESIGN).sdc
RTL_FILES ?= $(shell find $(PROJ_PATH)/vsrc -name "*.v")
NETLIST_SYN_V = $(RESULT_DIR)/$(DESIGN).netlist.syn.v
NETLIST_FIXED_V = $(RESULT_DIR)/$(DESIGN).netlist.fixed.v
TIMING_RPT = $(RESULT_DIR)/$(DESIGN).rpt
init:
mkdir -p $(NANGATE45_DIR)
cp -r $(YOSYS_PATH)/nangate45/* $(NANGATE45_DIR)
mkdir -p $(SCRIPT_DIR)
cp -r $(YOSYS_PATH)/scripts/* $(SCRIPT_DIR)
syn: init $(NETLIST_SYN_V)
$(NETLIST_SYN_V): $(RTL_FILES) $(SCRIPT_DIR)/yosys.tcl
mkdir -p $(@D)
echo tcl $(SCRIPT_DIR)/yosys.tcl $(DESIGN) \"$(RTL_FILES)\" $@ | yosys -l $(@D)/yosys.log -s -
fix-fanout: init $(NETLIST_FIXED_V)
$(NETLIST_FIXED_V): $(SCRIPT_DIR)/fix-fanout.tcl $(SDC_FILE) $(NETLIST_SYN_V)
$(IEDA_PATH) -script $^ $(DESIGN) $@ 2>&1 | tee $(RESULT_DIR)/fix-fanout.log
sta: init $(TIMING_RPT)
$(TIMING_RPT): $(SCRIPT_DIR)/sta.tcl $(SDC_FILE) $(NETLIST_FIXED_V)
$(IEDA_PATH) -script $^ $(DESIGN) 2>&1 | tee $(RESULT_DIR)/sta.log
clean:
-rm -rf result/
.PHONY: syn fix-fanout sta clean
top.sdc
约束文件,貌似set_input_delay中只支持固定值,不支持类似-min -max等参数
set_output_delay也不支持,会报错
set clk_port_name clk
set CLK_FREQ_MHZ 500
if {[info exists env(CLK_FREQ_MHZ)]} {
set CLK_FREQ_MHZ $::env(CLK_FREQ_MHZ)
} else {
puts "Warning: Environment CLK_FREQ_MHZ is not defined. Use $CLK_FREQ_MHZ MHz by default."
}
set clk_io_pct 0.2
set clk_port [get_ports $clk_port_name]
create_clock -name core_clock -period [expr 1000.0 / $CLK_FREQ_MHZ] $clk_port
set_clock_uncertainty -setup 0.2 [get_clocks core_clock]
set_clock_uncertainty -hold 0.1 [get_clocks core_clock]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {op[0]}]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {op[1]}]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {op[2]}]
set_input_delay 2 -clock [get_clocks core_clock] [get_ports {A[0]}]
set_input_delay 2 -clock [get_clocks core_clock] [get_ports {A[1]}]
set_input_delay 2 -clock [get_clocks core_clock] [get_ports {A[2]}]
set_input_delay 2 -clock [get_clocks core_clock] [get_ports {A[3]}]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {B[0]}]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {B[1]}]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {B[2]}]
set_input_delay 1 -clock [get_clocks core_clock] [get_ports {B[3]}]
ALU实验静态时序分析结果
make -f iEDAMakefile sta
之后,会结合工艺库进行编译,在result/top.v就能看到结合工艺库之后的门级网表
由于没有使用时序电路,只加了个寄存器翻转的always电路,中间可能综合器给优化掉了,所有没有分析出时钟路径
nangate45库
nangate45/lib/merged.lib 存放了工艺库下所有期间的各种参数
最后编辑:odjvnrij 更新时间:2024-11-01 21:09