思路:在FPGA中进行乘除法运算是比较耗费资源的一种方法,想要在不影响延迟并尽量减少资源损耗,必须从硬件的特点上进行设计。根据寄存器的原理,由于是二进制,所以左移或右移一位相当于×2或÷2,同样×3相当于左移一位再加原数据,×7相当于左移两位加上左移一位再加上原数据,×8正好相当于左移三位。也就是解法一的原理。
解法一:此方法是最容易想到的
- `timescale 1ns/1ns
- module multi_sel(
- input [7:0]d ,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0]out
- );
- //*************code***********//
- reg [1:0] cnt;
- reg [7:0] d_r;
- always @(posedge clk or negedge rst) begin
- if(!rst) begin
- cnt <= 2'b0;
- end
- else if(cnt == 2'd3)begin
- cnt <= 2'd0;
- end
- else begin
- cnt <= cnt + 2'd1;
- end
- end
- always @(posedge clk or negedge rst) begin
- if(!rst) begin
- out <= 0;
- input_grant <= 0;
- d_r <= 0;
- end
- else begin
- case (cnt)
- 2'd0 : begin
- out <= d;
- d_r <= d;
- input_grant <= 1'b1;
- end
- 2'd1 : begin
- out <= d_r + (d_r << 1);
- input_grant <= 1'b0;
- end
- 2'd2 : begin
- out <= d_r + (d_r << 1) + (d_r << 2);
- end
- 2'd3 : begin
- out <=(d_r << 3);
- end
- default : begin
- out <= 0;
- input_grant <= 0;
- end
- endcase
- end
- end
- always @(posedge clk or negedge rst) begin
- if(!rst) begin
-
- end
-
- end
- //*************code***********//
- endmodule
解法二:
根据题意分析,可以得到状态转换:
设输入为d,计数器为cnt
移位运算逻辑:
| 位运算 | |
| 1 | d |
| 3 | (din<<2)-din |
| 7 | (din<<3)-din |
| 8 | (din<<3) |
状态机逻辑
| cnt | out | inout_grant |
| 0 | 直接输出d,并寄存d的值为din | 1 |
| 1 | (din<<2)-din | 0 |
| 2 | (din<<3)-din | 0 |
| 3 | (din<<3) | 0 |
- `timescale 1ns/1ns
- module multi_sel(
- input [7:0]d ,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0]out
- );
- //*************code***********//
- reg [1:0] cnt;
- reg [7:0] din;
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- begin
- cnt <= 0;
- din <= 0;
- out <= 0;
- input_grant <= 0;
- end
- else begin
- cnt <= cnt + 2'd1;
- case(cnt)
- 2'd0:begin
- input_grant <= 1;
- din <= d;
- out <= d;
- end
- 2'd1:begin
- input_grant <= 0;
- out <= (din << 2) - din;
- end
- 2'd2:begin
- input_grant <= 0;
- out <= (din << 3) - din;
- end
- 2'd3:begin
- input_grant <= 0;
- out <= (din << 3);
- end
- endcase
- end
- end
- //*************code***********//
- endmodule
或者
- `timescale 1ns/1ns
- module multi_sel
- (
- input [7:0] d,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0] out
- );
- reg [1:0] cnt;
- reg [7:0] din;
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- cnt <= 2'd0;
- else if(cnt == 2'd3)
- cnt <= 2'd0;
- else
- cnt <= cnt + 2'd1;
- end
- always@(posedge clk or negedge rst)
- begin
- if(!rst)begin
- input_grant <= 0;
- din <= 8'd0;
- end
- else if(cnt == 2'd0)begin
- din <= d;
- input_grant <= 1;
- end
- else begin
- din <= din;
- input_grant <= 0;
- end
- end
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- out <= 11'd0;
- else
- case(cnt)
- 2'd0:out <= d;
- 2'd1:out <= (din << 2) - din;
- 2'd2:out <= (din << 3) - din;
- 2'd3:out <= (din << 3);
- default: out <= 11'd0;
- endcase
- end
- endmodule
解法三:利用乘法器,虽然浪费资源
- `timescale 1ns/1ns
- module multi_sel
- (
- input [7:0] d,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0] out
- );
- reg [1:0] cnt;
- reg [7:0] din;
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- cnt <= 2'd0;
- else if(cnt == 2'd3)
- cnt <= 2'd0;
- else
- cnt <= cnt + 2'd1;
- end
- always@(posedge clk or negedge rst)
- begin
- if(!rst)begin
- input_grant <= 0;
- din <= 8'd0;
- end
- else if(cnt == 2'd0)begin
- din <= d;
- input_grant <= 1;
- end
- else begin
- din <= din;
- input_grant <= 0;
- end
- end
- always@(posedge clk or negedge rst)
- begin
- if(!rst)
- out <= 11'd0;
- else
- case(cnt)
- 2'd0:out <= d;
- 2'd1:out <= din * 3;
- 2'd2:out <= din * 7;
- 2'd3:out <= din * 8;
- default: out <= 11'd0;
- endcase
- end
- endmodule
解法四:状态机,注意每次状态跳转之间的联系,out保存的是上一状态的值
- `timescale 1ns/1ns
- module multi_sel(
- input [7:0]d ,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0]out
- );
- //*************code***********//
- reg [1:0]state;
- reg [7:0]d_temp;
- always@(posedge clk,negedge rst) begin
- if(!rst) begin
- out <= 0;
- input_grant <= 0;
- state <= 2'b00;
- end
- else begin
- case(state)
- 2'b00:begin
- d_temp <=d;
- out <= d;
- state <= 2'b01;
- input_grant <= 1;
- end
- 2'b01:begin
- d_temp <=d_temp;
- out <= d_temp + (out<<1);//用的是上一状态的Out
- state <= 2'b11;
- input_grant <= 0;
- end
- 2'b11:begin
- d_temp <=d_temp;
- out <= d_temp + (out<<1);//用的是上一状态的Out
- state <= 2'b10;
- input_grant <= 0;
- end
- 2'b10:begin
- d_temp <=d_temp;
- out <= d_temp + out;//用的是上一状态的Out
- state <= 2'b00;
- input_grant <= 0;
- end
- default:begin
- out <=0;
- state <= 2'b00;
- input_grant <= 0;
- end
-
- endcase
- end
- end
-
-
- //*************code***********//
- endmodule
-
解法五:状态机
- `timescale 1ns/1ns
- module multi_sel(
- input [7:0]d ,
- input clk,
- input rst,
- output reg input_grant,
- output reg [10:0]out
- );
- //*************code***********//
- parameter TIMES1=0, TIMES3=1, TIMES7=2, TIMES8=3;
- reg [1:0] state;
- reg [7:0] d_r;
-
- always @(posedge clk or negedge rst) begin
- if(~rst) begin
- input_grant <= 1'b0;
- out <= 11'b0;
- state <= TIMES1;
- end
- else begin
- case(state)
- TIMES1: begin
- input_grant <= 1'b1;
- out <= d;
- state <= TIMES3;
- d_r <= d;
- end
- TIMES3: begin
- input_grant <= 1'b0;
- out <= (d_r<<1) + d_r;
- state <= TIMES7;
- d_r <= d_r;
- end
- TIMES7: begin
- input_grant <= 1'b0;
- out <= (d_r<<3) - d_r;
- state <= TIMES8;
- d_r <= d_r;
- end
- TIMES8: begin
- input_grant <= 1'b0;
- out <= d_r<<3;
- state <= TIMES1;
- d_r <= d_r;
- end
- default: begin
- input_grant <= 1'b0;
- out <= 11'b0;
- state <= TIMES1;
- d_r <= 8'b0;
- end
- endcase
- end
- end
- //*************code***********//
- endmodule
疑惑:解法四和五中后面三个状态d_temp和d_r为什么不能赋值为d?
Testbench
-
-
- `timescale 1ns/1ns
- module testbench();
- reg clk=0;
- always #1 clk = ~clk; // Create clock with period=10
- // parameter daclare
- parameter T = 2;
- // reg declare
- reg rst ;
- reg [7:0] d;
- wire [10:0] out;
- wire input_grant;
-
- initial begin
- rst = 1'b0;
- d = 8'd143;
- #T rst = 1'b1;
- #(3*T) d = 8'd7;
- #(5*T) d = 8'd6;
- #T d = 8'd6;
- #T d = 8'd128;
- #T d = 8'd129;
- #(5*T) $finish;
- end
-
- // instantiate
- multi_sel u_multi_sel(
- .d(d),
- .clk(clk),
- .rst(rst),
- .input_grant(input_grant),
- .out(out)
- );
- //end
- initial begin
- $dumpfile("out.vcd");
- // This will dump all signal, which may not be useful
- //$dumpvars;
- // dumping only this module
- //$dumpvars(1, testbench);
- // dumping only these variable
- // the first number (level) is actually useless
- $dumpvars(0, testbench);
- end
-
- endmodule