用Verilog语言设计一个除法器,能在 Basys2 开发板上实际运行。 被除数为 16 位,除数为 8 位,被除数和除数都用按键输入,结果用数码管显示,设置一个 使能开关,开关朝上拨时才进行运算。由于数码管和按键等资源数量较少,因此可以考虑采 取下面的方案实现。 LD2 LD1 LD0 指示状态,000 是起始状态,001 用于输入被除数高 8 位,010 用于输入被 除数低 8 位,011 用于输入除数(8 位),100 用于显示结果,101 用于显示被除数和除数 btn1 和 btn0 和数码管配合,用于改变准备输入的数据 btn2 用于将数码管显示的数据输入到相应的地方,同时切换状态。btn3 的功能也是切换状 态,如果用 btn3 切换状态,则不改变原来的数据。 sw6 如果为 1 表示允许进行除法运算,为 0 则表示不允许。 因为 LD2-LD0 为 100 和 101 时需要显示 6 位 16 进制数,而数码管只有 4 个,所以用 sw7 进行切换。LD2-LD0 为 100 时,sw7 为 0 时显示商,为 1 时显示余数,LD2-LD0 为 101 时, sw7 为 0 时显示被除数,为 1 时显示除数。
时间: 2024-02-06 19:09:16 浏览: 134
这是一个比较完整的设计,需要一些基本的Verilog语言知识以及FPGA开发板的使用经验。下面是一个可能的解决方案,仅供参考。
首先,我们需要定义一些常数,如状态的编码、数码管的位数等:
```verilog
`define STATE_IDLE 3'b000
`define STATE_DIVIDEND_HIGH 3'b001
`define STATE_DIVIDEND_LOW 3'b010
`define STATE_DIVISOR 3'b011
`define STATE_RESULT 3'b100
`define STATE_DISPLAY 3'b101
`define DIGIT_NUM 4
```
接下来定义一些输入输出端口:
```verilog
module divider(
input clk, rst,
input en,
input [7:0] divisor,
input [15:0] dividend,
output reg [3:0] seg,
output reg [2:0] ld,
output reg [7:0] an
);
// ...
endmodule
```
我们需要使用一个时钟和复位信号,以及使能信号、被除数和除数的输入端口,还有用于数码管的输出端口。
接下来定义一些状态机的变量:
```verilog
reg [2:0] state;
reg [7:0] dividend_temp;
reg [7:0] quotient;
reg [7:0] remainder;
reg [3:0] dividend_digit[2:0];
reg [3:0] divisor_digit[1:0];
reg [3:0] result_digit[5:0];
reg [3:0] display_digit[5:0];
reg digit_idx;
```
其中,`state`表示当前的状态,`dividend_temp`是被除数的一个缓存,`quotient`和`remainder`是商和余数,`dividend_digit`和`divisor_digit`分别表示被除数和除数的每一位数字,`result_digit`和`display_digit`分别表示结果和显示的数字,`digit_idx`表示当前正在显示的数字的索引。
接下来定义一些状态转移的逻辑:
```verilog
always @(posedge clk) begin
if (rst) begin
state <= `STATE_IDLE;
ld <= 3'b000;
quotient <= 0;
remainder <= 0;
dividend_digit <= {4{4'b0000}};
divisor_digit <= {2{4'b0000}};
result_digit <= {6{4'b0000}};
display_digit <= {6{4'b0000}};
digit_idx <= 0;
end else begin
case (state)
`STATE_IDLE:
ld <= 3'b000;
if (en) state <= `STATE_DIVIDEND_HIGH;
`STATE_DIVIDEND_HIGH:
ld <= 3'b001;
if (en) begin
dividend_temp[15:8] <= dividend[15:8];
state <= `STATE_DIVIDEND_LOW;
end
`STATE_DIVIDEND_LOW:
ld <= 3'b010;
if (en) begin
dividend_temp[7:0] <= dividend[7:0];
state <= `STATE_DIVISOR;
end
`STATE_DIVISOR:
ld <= 3'b011;
if (en) begin
divisor_digit[1] <= divisor[7:4];
divisor_digit[0] <= divisor[3:0];
state <= `STATE_RESULT;
end
`STATE_RESULT:
ld <= 3'b100;
if (en) begin
{quotient, remainder} <= dividend_temp / divisor;
state <= `STATE_DISPLAY;
end
`STATE_DISPLAY:
ld <= 3'b101;
case ({sw7, state})
2'b00_`STATE_RESULT:
result_digit <= {
quotient[15:12], quotient[11:8],
quotient[7:4], quotient[3:0],
remainder[3:0], 4'b0000
};
2'b01_`STATE_RESULT:
result_digit <= {
4'b0000, remainder[7:4],
remainder[3:0], 4'b0000, 2'b00,
quotient[7:4], quotient[3:0], 2'b00
};
2'b00_`STATE_DISPLAY:
display_digit <= {
dividend[15:12], dividend[11:8],
dividend[7:4], dividend[3:0], 2'b00,
2'b00, 2'b00, 2'b00
};
2'b01_`STATE_DISPLAY:
display_digit <= {
divisor[7:4], divisor[3:0], 2'b00,
2'b00, 2'b00, 2'b00, 2'b00
};
default:
display_digit <= {6{4'b0000}};
endcase
digit_idx <= digit_idx + 1;
if (digit_idx == (2*`DIGIT_NUM+2)) begin
digit_idx <= 0;
state <= `STATE_IDLE;
end
endcase
end
end
```
这里使用了Verilog中的case语句,根据当前状态和sw7的值来选择要显示的数字。注意到被除数和除数的每一位数字都是4位的,因此需要使用一个数组来存储。
最后,我们需要将数码管的输出和按键、开关等端口相连:
```verilog
assign an = 8'b1111_1110 >> digit_idx[3:0];
assign seg = display_digit[digit_idx-1][3:0];
```
这里使用了一个简单的方法,将数码管的8个段依次输出,根据`digit_idx`来选择要输出的数字。
完整代码如下:
阅读全文