1. Experimental code and notes (.v file)

`timescale 1ns / 1ps

// Create Date: 2021/10/15 17:10:25

module adder(
 input ia,
 input ib,
 input cin,
 output cout,
 output cur
);
 assign cur = ia ^ ib ^ cin;                   //当前位
 assign cout = ia & cin | ib & cin | ia & ib;  // 进位
endmodule

module add_8(
 input [7:0] a,
 input [7:0] b,
 input cin,
 output [7:0] s,
 output o,      // overflow,
 output cout
);
 wire c0,c1,c2,c3,c4,c5,c6,c7;
 adder d0(a[0],b[0],cin,c0,s[0]);
 adder d1(a[1],b[1],c0,c1,s[1]);
 adder d2(a[2],b[2],c1,c2,s[2]);
 adder d3(a[3],b[3], c2,c3,s[3]);
 adder d4(a[4],b[4],c3,c4,s[4]);
 adder d5(a[5],b[5],c4,c5,s[5]);
 adder d6(a[6],b[6],c5,c6,s[6]);
 adder d7(a[7],b[7],c6,c7,s[7]);
 assign cout = c7;
 assign o = (a[7] & b[7] & ~s[7]) | (~a[7] & ~b[7] & s[7]);  // 溢出
endmodule

module add_sub_8(
 input [7:0] a,
 input [7:0] b,
 input cin,
 input op,
 output [7:0] res,
 output overflow,
 output cout
);
 add_8 d4(a,{op,op,op,op,op,op,op,op} ^ b,op ^ cin,res,overflow,cout);
endmodule

module slt(
 input [7:0] a,
 input [7:0] b,
 output result
);
 wire o, c;
 wire [7:0] r;
 add_sub_8 sub(a, b, 0, 1, r, o, c);
 assign result = o ^ r[7];
 
endmodule



module shift(
    input [7:0] a,
    input b,
    input [1:0]m,
    output [7:0] out
);  // 将相与的值向左移动 m 位
    assign out = b == 1'b0 ? 8'b0000_0000 : ((8'b1111_1111 & a) << m);
 
endmodule

module mult(
    input [3:0] a,
    input [3:0] b,
    output [7:0] out
);
    wire [7:0] abs_a;       // a 的绝对值
    wire [7:0] abs_b;       // b 的绝对值
    wire flag;
    assign flag = a[3] ^ b[3];  // 通过对符号位的异或取得乘积的符号
    wire [3:0] t1;
    wire [3:0] t2;
    wire o1,c1,o2,c2,o3,c3,o4,c4,o5,c5,o6,c6;
    add_sub_8 m0(a,1,0,1,t1,o1,c1);  // a - 1
    add_sub_8 m1(b,1,0,1,t2,o2,c2);  // b - 1
    assign abs_a[7:4] = 4'b0000;    // 绝对值都是正数,所以拓展成 8 位后,前面四位都要补上 0
    assign abs_b[7:4] = 4'b0000; 
    assign abs_a[3:0] = a[3] == 1'b1 ? ~t1 : a;  // 取绝对值完成
    assign abs_b[3:0] = b[3] == 1'b1 ? ~t2 : b;
    wire [7:0] T1;
    wire [7:0] T2;
    wire [7:0] T3;
    wire [7:0] T4;
    shift h1(abs_a,abs_b[0],2'b00,T1);  // 四位数乘法转换成 四次加法运算
    shift h2(abs_a,abs_b[1],2'b01,T2);
    shift h3(abs_a,abs_b[2],2'b10,T3);
    shift h4(abs_a,abs_b[3],2'b11,T4); 
    
    wire [7:0] T5;
    wire [7:0] T6;
    wire [7:0] res;
    wire [7:0] T7;
    add_sub_8 m2(T1,T2,0,0,T5,o3,c3);  // T5 = T1 + T2
    add_sub_8 m3(T5,T3,0,0,T6,o4,c4);  // T6 = T5 + T3
    add_sub_8 m4(T6,T4,0,0,res,o5,c5); // res = T6 + T4
    
    add_sub_8 m5(~res,1,0,0,T7,o6,c6);  //  T7 = ~res + 1     即是取 res 的补码
    assign out = flag == 1'b1 ? T7 : res;  // 由乘积符号标志,确定输出的是原值还是它的补码
endmodule







module CPU(
    input read_to_R2,          // 是否把值存入 R2
    input alu,                 // 控制是否开启 alu 部分计算
    input clk,                 // 时钟
    input [7:0] b,             // 数据源
    output reg [7:0] led_id,
    output reg [6:0] out_led, // 数码管显示
    output ZF,                // 运算结果全零,则为 1
           CF,                // 进借位标志位
           OF,                // 溢出标志位
           SF,                // 符号标志位,与 F 的最高位相同
           PF                 // 奇偶标志位,F 有奇数个 1,则 PF=1,否则为 0
);
reg [7:0] R0;                // 对应地址码 00
reg [7:0] R1;                // 对应地址码 01
reg [7:0] R2;                // 对应地址码 10

reg [7:0] data_to_R2;       // 在 alu 计算 和 存入 R2 的值的零时变量

wire [7:0] res1,res2,res3,res4,res5;
wire res9;
wire OF1,OF2,OF3,OF4;
wire CF1,CF2,CF3,CF4;
reg of,cf;

reg [7:0] A1;
reg [7:0] B1;
wire [7:0] A;    // 第一个源数据
wire [7:0] B;    // 第二个源数据
assign A = A1;
assign B = B1;

add_sub_8 fun1(A,B,0,0,res1,OF1,CF1);    // res1 = A + B
add_sub_8 fun2(A,1,0,0,res2,OF2,CF2);    // res2 = A - 1
add_sub_8 fun3(A,B,0,1,res3,OF3,CF3);    // res3 = A - B
add_sub_8 fun4(A,1,0,1,res4,OF4,CF4);    // res4 = A - 1;
mult fun5(A[3:0],B[3:0],res5);           // res5 = A * B
slt fun9(A,B,res9);                      // 比较 A 和 B 的大小,A >= B, res9 = 0;    A < B, res9 = 1;


always@(b) begin

    if (read_to_R2 == 1'b1) R2 = data_to_R2;       // 是否将临时变量的值存如 R2
    
    if (b[7:6] == 2'b10 && alu == 1'b0) begin      // 写入数据进入寄存器
        if (b[5:4] == 2'b00) begin                 // 根据地址码,存入值
            if (b[3] == 1'b1) R0[7:4] = 4'b1111;   // 根据写入数(补码)最高位,判断并 4 位长拓展为 8 位,下同
            else              R0[7:4] = 4'b0000;
            R0[3:0] = b[3:0];
        end
        else if (b[5:4] == 2'b01) begin
            if (b[3] == 1'b1) R1[7:4] = 4'b1111;
            else              R1[7:4] = 4'b0000;
            R1[3:0] = b[3:0];
        end
        else if (b[5:4] == 2'b10) begin
            if (b[3] == 1'b1) begin
                R2[7:4] = 4'b1111;
                data_to_R2[7:4] = 4'b1111;
            end
            else begin
                R2[7:4] = 4'b0000;
                data_to_R2[7:4] = 4'b0000;
            end
            R2[3:0] = b[3:0];
            data_to_R2 = b[3:0];
        end
    end
    else if (alu == 1'b1) begin
        case(b[3:2])
            2'b00: A1 = R0;
            2'b01: A1 = R1;
            2'b10: A1 = R2;
        endcase
        case(b[1:0])
            2'b00: B1 = R0;
            2'b01: B1 = R1;
            2'b10: B1 = R2;
        endcase
        case(b[7:4])        // 以下模拟 alu 部分进行取出对应状态计算的结果和状态
            4'b0000: begin 
                data_to_R2 = res1;
                of = OF1;
                cf = CF1;
            end
            4'b0001: begin 
                data_to_R2 = res2;
                of = OF2;
                cf = CF2;
            end
            4'b0010: begin
                data_to_R2 = res3;
                of = OF3;
                cf = ~CF3;
            end
            4'b0011: begin
                data_to_R2 = res4;
                of = OF4;
                cf = ~CF4;
            end
            4'b1100: data_to_R2 = res5;
            4'b0100: data_to_R2 = A & B;
            4'b0101: data_to_R2 = A | B;
            4'b0110: data_to_R2 = A ^ B;
            4'b0111: data_to_R2 = res9;
        endcase
    end
end


// 数码管灯显示数据
wire [7:0] n;
assign n = b[7:0] == 8'b1111_0010 ? R2          :    // 读取 R2 的值
           b[7:0] == 8'b1111_0000 ? R0          :    // 读取 R0 的值
           b[7:0] == 8'b1111_0001 ? R1          :    // 读取 R1 的值
           b[7:0] == 8'b1111_0011 ? data_to_R2  :    // 读取储存 R2 值的中间变量
           b[7:0] == 8'b1111_0100 ? A           :    // 读取第二个源数据
           b[7:0] == 8'b1111_0101 ? B           :    // 读取第二个源数据
           8'b0000_0000;                             // default

assign OF = of;
assign CF = cf;
assign SF = n[7];
assign ZF = ~ (n[0] | n[1] | n[2] | n[3] | n[4] | n[5] | n[6] | n[7]);
assign PF = ~(n[0] ^ n[1] ^ n[2] ^ n[3] ^ n[4] ^ n[5] ^ n[6] ^ n[7]);




parameter CLK_COUNT = 249999;//时钟计数上限
reg [31:0] count;//计数
reg [1:0] id;//id0~3对应左到右四个数码管
wire flag;  //flag标记补码是否表示负数
assign flag=n[7];

//8位2进制,十进制至多3位
reg [7:0] n1;    //百位
reg [7:0] n2;    //十位
reg [7:0] n3;    //个位
reg [7:0] abs;
always @(*)
    case(flag) //求正数的个十百位
    1'b0:
		begin
		   n1 = n / 100 % 10;
		   n2 = n / 10 % 10;
		   n3 = n % 10;
		end
    1'b1:
		begin
		   abs=(~n)+1;  //求负数的个十百位
		   n1 = abs / 100 % 10;        
		   n2 = abs / 10 % 10;        
		   n3 = abs % 10;
		end
    endcase
    //时钟上升沿
always@(posedge clk) begin //根据时钟信号控制切换显示的数码管
    if (count == CLK_COUNT)begin
        count <= 0;
       id = (id + 1);//切换
    end
    else
        count <= count+1;
end
   
   
   //选择灯,显示数字
always@(id) begin        
    if (id == 0) begin           
		led_id <= 8'b1111_0111;//最左端灯亮
        if(n[7]==1)
			out_led<=7'b1111110;//负号
        else 
			out_led<=7'b1111111;//不显示
    end
	//其余三个管显示逻辑相同
    else if (id == 1) begin
        led_id <= 8'b1111_1011;
        begin
            case(n1)
                4'b0000: out_led = 7'b0000001;    //0
                4'b0001: out_led = 7'b1001111;    //1
                4'b0010: out_led = 7'b0010010;    //2
                4'b0011: out_led = 7'b0000110;    //3
                4'b0100: out_led = 7'b1001100;    //4
                4'b0101: out_led = 7'b0100100;    //5
                4'b0110: out_led = 7'b0100000;    //6
                4'b0111: out_led = 7'b0001111;    //7
                4'b1000: out_led = 7'b0000000;    //8
                4'b1001: out_led = 7'b0000100;    //9
            endcase
        end 
    end
    else if (id == 2) begin
        led_id <= 8'b1111_1101;
        begin
            case(n2)
                4'b0000: out_led = 7'b0000001;    //0
                4'b0001: out_led = 7'b1001111;    //1
                4'b0010: out_led = 7'b0010010;    //2
                4'b0011: out_led = 7'b0000110;    //3
                4'b0100: out_led = 7'b1001100;    //4
                4'b0101: out_led = 7'b0100100;    //5
                4'b0110: out_led = 7'b0100000;    //6
                4'b0111: out_led = 7'b0001111;    //7
                4'b1000: out_led = 7'b0000000;    //8
                4'b1001: out_led = 7'b0000100;    //9
            endcase
        end
    end
    else if (id == 3) begin
        led_id <= 8'b1111_1110;
	begin
		case(n3)
			4'b0000: out_led = 7'b0000001;    //0
			4'b0001: out_led = 7'b1001111;    //1
			4'b0010: out_led = 7'b0010010;    //2
			4'b0011: out_led = 7'b0000110;    //3
			4'b0100: out_led = 7'b1001100;    //4
			4'b0101: out_led = 7'b0100100;    //5
			4'b0110: out_led = 7'b0100000;    //6
			4'b0111: out_led = 7'b0001111;    //7
			4'b1000: out_led = 7'b0000000;    //8
			4'b1001: out_led = 7'b0000100;    //9
		endcase
	end
    end 
end
endmodule

Copy the code

2. Experimental constraint file code (.xdc file)

set_property IOSTANDARD LVCMOS33 [get_ports {led_id[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {led_id[0]}] set_property PACKAGE_PIN J17 [get_ports {led_id[0]}] set_property PACKAGE_PIN J18 [get_ports {led_id[1]}] set_property PACKAGE_PIN T9 [get_ports {led_id[2]}] set_property PACKAGE_PIN J14 [get_ports {led_id[3]}] set_property PACKAGE_PIN P14  [get_ports {led_id[4]}] set_property PACKAGE_PIN T14 [get_ports {led_id[5]}] set_property PACKAGE_PIN K2 [get_ports {led_id[6]}] set_property PACKAGE_PIN U13 [get_ports {led_id[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {out_led[0]}] set_property PACKAGE_PIN T10 [get_ports {out_led[6]}] set_property PACKAGE_PIN R10 [get_ports {out_led[5]}] set_property PACKAGE_PIN K16 [get_ports {out_led[4]}] set_property PACKAGE_PIN K13 [get_ports {out_led[3]}] set_property PACKAGE_PIN P15 [get_ports {out_led[2]}] set_property PACKAGE_PIN T11 [get_ports {out_led[1]}] set_property PACKAGE_PIN L18 [get_ports {out_led[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {b[0]}] set_property PACKAGE_PIN R13 [get_ports {b[7]}] set_property PACKAGE_PIN U18 [get_ports {b[6]}] set_property PACKAGE_PIN T18 [get_ports {b[5]}] set_property PACKAGE_PIN R17 [get_ports {b[4]}] set_property PACKAGE_PIN  R15 [get_ports {b[3]}] set_property PACKAGE_PIN M13 [get_ports {b[2]}] set_property PACKAGE_PIN L16 [get_ports {b[1]}] set_property PACKAGE_PIN J15 [get_ports {b[0]}] set_property IOSTANDARD LVCMOS33 [get_ports clk] set_property PACKAGE_PIN E3 [get_ports clk] set_property IOSTANDARD LVCMOS33 [get_ports alu] set_property PACKAGE_PIN T8 [get_ports alu] set_property IOSTANDARD LVCMOS33 [get_ports t] set_property PACKAGE_PIN U8 [get_ports t] set_property IOSTANDARD LVCMOS33 [get_ports ZF] set_property IOSTANDARD LVCMOS33 [get_ports CF] set_property IOSTANDARD LVCMOS33 [get_ports OF] set_property IOSTANDARD LVCMOS33 [get_ports SF] set_property IOSTANDARD LVCMOS33 [get_ports PF] set_property PACKAGE_PIN  R18 [get_ports ZF] set_property PACKAGE_PIN N14 [get_ports CF] set_property PACKAGE_PIN J13 [get_ports OF] set_property  PACKAGE_PIN K15 [get_ports SF] set_property PACKAGE_PIN H17 [get_ports PF]Copy the code