top.v
module top(
input [3:0] A,
input [3:0] B,
input [2:0] ALUctr,
output reg [3:0] ALUout,
output reg [3:0] temp,
output reg less,
output reg of,zf,cf
);
reg [3:0] xb;
always@(*)begin
ALUout = 4'b0;temp = 4'b0; less = 1'b0; of = 0; zf = 0; cf = 0; xb = 4'd0; // 初始化
casez(ALUctr)
3'b00z:begin // add or sub
xb = B ^ { {4{ALUctr[0]}} }; // 根据最后一位确定加减法 加:000 减:001 减法则取反
{cf,ALUout} = xb + A + {3'b0,ALUctr[0]};
of = (A[3] == xb[3]) && (ALUout[3] != A[3]);
zf = ~(|ALUout);
end
3'b011:begin // and
ALUout = A & B;
end
3'b100:begin // or
ALUout = A | B;
end
3'b101:begin // xor
ALUout = A ^ B;
end
3'b110:begin // cmp
xb = B ^ 4'b1111; // 用减法进行比较大小
{cf,temp} = xb + A + 4'b1;
of = (A[3] == xb[3]) && (temp[3] != A[3]);
zf = ~(|temp);
less = temp[3] ~^ of;
if(less == 0) ALUout = 4'b1;
else ALUout = 4'b0;
end
3'b111:begin // equl
xb = B ^ 4'b1111;
{cf,temp} = xb + A + 4'b1;
of = (A[3] == xb[3]) && (temp[3] != A[3]);
zf = ~(|temp);
if(zf == 1) ALUout = 4'b1;
else ALUout = 4'b0;
end
default:ALUout = 4'b0; // avoid latch
endcase
end
endmodule
为什么不用方法二进行减法overflow计算
assign t_add_Cin =( {n{Cin}}^B )+ Cin; // 在这里请注意^运算和+运算的顺序
assign { Carry, Result } = A + t_add_Cin;
assign Overflow = (A[n-1] == t_add_Cin[n-1]) && (Result [n-1] != A[n-1]);
参考A=0111 B=1000时的情况,方法二不能正确判断overflow
sim_main.cpp
sim_main.cpp的说明可见文章
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<nvboard.h>
#include"Vtop.h"
#include"verilated.h"
#include"verilated_vcd_c.h"
void nvboard_bind_all_pins(Vtop* top);
int main(int argc, char** argv) {
VerilatedContext* contextp = new VerilatedContext;
contextp->traceEverOn(true);
contextp->commandArgs(argc, argv);
Vtop* top = new Vtop{contextp};
nvboard_bind_all_pins(top);
nvboard_init();
VerilatedVcdC* m_trace = new VerilatedVcdC;
top->trace(m_trace, 99);
m_trace->open("wave.vcd");
while (!contextp->gotFinish()) {
nvboard_update();
contextp->timeInc(1);
//----测试----
top->A = 0b0001;
top->B = 0b0001;
top->ALUctr = 0b000;
//----测试---- 此处为测试:1 + 1
top->eval();
m_trace->dump(contextp->time());
}
m_trace->close();
delete top;
delete contextp;
return 0;
}
Makefile
参考NVBoard的Makefile
Makefile文件的说明可见文章
TOPNAME = top
NXDC_FILES = constr/top.nxdc
INC_PATH ?=
VERILATOR = verilator
VERILATOR_CFLAGS += -MMD --build --trace -cc \
-O3 --x-assign fast --x-initial fast --noassert
BUILD_DIR = ./build
OBJ_DIR = $(BUILD_DIR)/obj_dir
BIN = $(BUILD_DIR)/$(TOPNAME)
default: $(BIN)
$(shell mkdir -p $(BUILD_DIR))
# constraint file
SRC_AUTO_BIND = $(abspath $(BUILD_DIR)/auto_bind.cpp)
$(SRC_AUTO_BIND): $(NXDC_FILES)
python3 $(NVBOARD_HOME)/scripts/auto_pin_bind.py $^ $@
# project source
VSRCS = $(shell find $(abspath ./vsrc) -name "*.v")
CSRCS = $(shell find $(abspath ./csrc) -name "*.c" -or -name "*.cc" -or -name "*.cpp")
CSRCS += $(SRC_AUTO_BIND)
# rules for NVBoard
include $(NVBOARD_HOME)/scripts/nvboard.mk
# rules for verilator
INCFLAGS = $(addprefix -I, $(INC_PATH))
CXXFLAGS += $(INCFLAGS) -DTOP_NAME="\"V$(TOPNAME)\""
LDFLAGS += -lSDL2 -lSDL2_image
$(BIN): $(VSRCS) $(CSRCS) $(NVBOARD_ARCHIVE)
@rm -rf $(OBJ_DIR) wave.vcd
$(VERILATOR) $(VERILATOR_CFLAGS) \
--top-module $(TOPNAME) $^ \
$(addprefix -CFLAGS , $(CXXFLAGS)) $(addprefix -LDFLAGS , $(LDFLAGS)) \
--Mdir $(OBJ_DIR) --exe -o $(abspath $(BIN))
all: default
run: $(BIN)
./build/top +trace
gtkwave wave.vcd
clean:
rm -rf $(BUILD_DIR) wave.vcd
.PHONY: default all clean run
接入NVBoard
可以用NVBoard进行数据输入和输出,在top.nxdc文件中进行引脚绑定。
top=top
A (SW3,SW2,SW1,SW0)
B (SW7,SW6,SW5,SW4)
ALUctr (SW10,SW9,SW8)
ALUout (SW15,SW14,SW13,SW12)
演示一下1+1
SW每一位代表二进制中的每一位,图为0001(A)+0001(B) = 0010(ALUout)