verilog实现十进制正数与ASCII码互转
1.小位宽数实现转ASCII码
1.小整数十进制转BCD码(8421码)
十进制数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
8421码 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 |
2.BCD码(8421码)转ASCII码
8421码 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 |
---|---|---|---|---|---|---|---|---|---|---|
ASCII码(BIN) | 110000 | 110001 | 110010 | 110011 | 110100 | 110101 | 110110 | 110111 | 111000 | 111001 |
ASCII码(DEC) | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
ASCII码(HEX) | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
2.大位宽正整数实现转ASCII码
1.整数数位分割(BCD码)
分离数位有多种方法,除法和比较法,除法理解简单,但是在verilog中占用资源严重,需要使用到除法IP核,以下采用比较法。
比较法分离数位:
假设一个数为num=123,使用A,B,C来代替百位,十位和个位。(以下为伪代码)
分离百位:
if(num >=900) A = 9; num = num - 900;
else if(num >=800) A = 8; num = num - 800;
else if(num >=700) A = 7; num = num - 700;
else if(num >=600) A = 6; num = num - 600;
else if(num >=500) A = 5; num = num - 500;
else if(num >=400) A = 4; num = num - 400;
else if(num >=300) A = 3; num = num - 300;
else if(num >=200) A = 2; num = num - 200;
else if(num >=100) A = 1; num = num - 100;
else A = 0; num = num ;
分离十位和个位:
if(num >=90) B = 9; C = num - 90;
else if(num >=80) B = 8; C = num - 80;
else if(num >=70) B = 7; C = num - 70;
else if(num >=60) B = 6; C = num - 60;
else if(num >=50) B = 5; C = num - 50;
else if(num >=40) B = 4; C = num - 40;
else if(num >=30) B = 3; C = num - 30;
else if(num >=20) B = 2; C = num - 20;
else if(num >=10) B = 1; C = num - 10;
else B = 0; C = 0 ;
2.verilog实现十进制正数转ASCII码
verilog
module dec_ascii16(
input clk ,
input rst ,
input valid ,
input [15:0] din ,//MAX = 65535
output rdy ,
output [39:0] dout
);
reg [$clog2(9999)-1:0] num0;
reg [$clog2(999)-1:0] num1;
reg [$clog2(99)-1:0] num2;
reg [4*4-1:0] dig0;
reg [3*4-1:0] dig1;
reg [2*4-1:0] dig2;
reg [1*4-1:0] dig3;
reg [1*4-1:0] dig4;
reg [3:0] valid_d;
always @(posedge clk)begin
if(rst)begin
valid_d <= 0;
end else begin
valid_d <= {valid_d,valid};
end
end
always @(posedge clk)begin
if(rst)begin
dig0 <= 0;
num0 <= 0;
end else begin
if(din >= 60000) begin dig0 <= {dig0,4'd6}; num0 <= din - 60000; end
else if(din >= 50000)begin dig0 <= {dig0,4'd5}; num0 <= din - 50000; end
else if(din >= 40000)begin dig0 <= {dig0,4'd4}; num0 <= din - 40000; end
else if(din >= 30000)begin dig0 <= {dig0,4'd3}; num0 <= din - 30000; end
else if(din >= 20000)begin dig0 <= {dig0,4'd2}; num0 <= din - 20000; end
else if(din >= 10000)begin dig0 <= {dig0,4'd1}; num0 <= din - 10000; end
else begin dig0 <= {dig0,4'd0}; num0 <= din ; end
end
end
always @(posedge clk)begin
if(rst)begin
dig1 <= 0;
num1 <= 0;
end else begin
if (num0 >= 9000)begin dig1 <= {dig1,4'd9}; num1 <= num0 - 9000; end
else if(num0 >= 8000)begin dig1 <= {dig1,4'd8}; num1 <= num0 - 8000; end
else if(num0 >= 7000)begin dig1 <= {dig1,4'd7}; num1 <= num0 - 7000; end
else if(num0 >= 6000)begin dig1 <= {dig1,4'd6}; num1 <= num0 - 6000; end
else if(num0 >= 5000)begin dig1 <= {dig1,4'd5}; num1 <= num0 - 5000; end
else if(num0 >= 4000)begin dig1 <= {dig1,4'd4}; num1 <= num0 - 4000; end
else if(num0 >= 3000)begin dig1 <= {dig1,4'd3}; num1 <= num0 - 3000; end
else if(num0 >= 2000)begin dig1 <= {dig1,4'd2}; num1 <= num0 - 2000; end
else if(num0 >= 1000)begin dig1 <= {dig1,4'd1}; num1 <= num0 - 1000; end
else begin dig1 <= {dig1,4'd0}; num1 <= num0 ; end
end
end
always @(posedge clk)begin
if(rst)begin
dig2 <= 0;
num2 <= 0;
end else begin
if (num1 >= 900)begin dig2 <= {dig2,4'd9}; num2 <= num1 - 900; end
else if(num1 >= 800)begin dig2 <= {dig2,4'd8}; num2 <= num1 - 800; end
else if(num1 >= 700)begin dig2 <= {dig2,4'd7}; num2 <= num1 - 700; end
else if(num1 >= 600)begin dig2 <= {dig2,4'd6}; num2 <= num1 - 600; end
else if(num1 >= 500)begin dig2 <= {dig2,4'd5}; num2 <= num1 - 500; end
else if(num1 >= 400)begin dig2 <= {dig2,4'd4}; num2 <= num1 - 400; end
else if(num1 >= 300)begin dig2 <= {dig2,4'd3}; num2 <= num1 - 300; end
else if(num1 >= 200)begin dig2 <= {dig2,4'd2}; num2 <= num1 - 200; end
else if(num1 >= 100)begin dig2 <= {dig2,4'd1}; num2 <= num1 - 100; end
else begin dig2 <= {dig2,4'd0}; num2 <= num1 ; end
end
end
always @(posedge clk)begin
if(rst)begin
dig3 <= 0;
dig4 <= 0;
end else begin
if (num2 >= 90)begin dig3 <= {dig3,4'd9}; dig4 <= num2 - 90; end
else if(num2 >= 80)begin dig3 <= {dig3,4'd8}; dig4 <= num2 - 80; end
else if(num2 >= 70)begin dig3 <= {dig3,4'd7}; dig4 <= num2 - 70; end
else if(num2 >= 60)begin dig3 <= {dig3,4'd6}; dig4 <= num2 - 60; end
else if(num2 >= 50)begin dig3 <= {dig3,4'd5}; dig4 <= num2 - 50; end
else if(num2 >= 40)begin dig3 <= {dig3,4'd4}; dig4 <= num2 - 40; end
else if(num2 >= 30)begin dig3 <= {dig3,4'd3}; dig4 <= num2 - 30; end
else if(num2 >= 20)begin dig3 <= {dig3,4'd2}; dig4 <= num2 - 20; end
else if(num2 >= 10)begin dig3 <= {dig3,4'd1}; dig4 <= num2 - 10; end
else begin dig3 <= {dig3,4'd0}; dig4 <= num2 ; end
end
end
assign dout = {4'h3,dig0[4*4-1 -:4],4'h3,dig1[3*4-1 -:4],4'h3,dig2[2*4-1 -:4],4'h3,dig3[1*4-1 -:4],4'h3,dig4[1*4-1 -:4]};
assign rdy = valid_d[3];
endmodule
3.大位宽ASCII码转正整数
1.BCD码转整数
使用A,B,C来代替百位,十位和个位。(以下为伪代码)
num = A*100 + B*10 + C
dec(100) = bin(1100100) = 2^6 + 2^5 + 2^2
dec(10) = bin(1010) = 2^3 + 2^1
num =A*(2^6 + 2^5 + 2^2) + B*(2^3 + 2^1) + C
2.verilog实现ASCII码转十进制正数
verilog
module ascii_dec16(
input clk ,
input rst ,
input valid ,
input [39:0] din ,//MAX = 65535
output rdy ,
output reg [15:0] dout
);
reg [$clog2(60000)-1:0] num0;
reg [$clog2(9000)-1:0] num1;
reg [$clog2(900)-1:0] num2;
reg [$clog2(90)-1:0] num3;
reg [$clog2(9)-1:0] num4;
reg [$clog2(65535)-1:0] num5;
reg [$clog2(65535)-1:0] num6;
reg [2:0] valid_d;
always @(posedge clk)begin
if(rst)begin
valid_d <= 0;
end else begin
valid_d <= {valid_d,valid};
end
end
//10 = 1010 = 2^3 + 2^1
//100 = 1100100 = 2^6 + 2^5 + 2^2
//1000 = 001111101000 = 2^10 - 2^5 + 2^3
//10000 = 0010011100010000 = 2^13 + 2^11 - 2^8 + 2^4
always @(posedge clk)begin
if(rst)begin
num0 <= 0;
end else begin
num0 <= {din[39-4 -:4],13'd0} + {din[39-4 -:4],11'd0} - {din[39-4 -:4],8'd0} + {din[39-4 -:4],4'd0};
end
end
always @(posedge clk)begin
if(rst)begin
num1 <= 0;
end else begin
num1 <= {din[39-12 -:4],10'd0} - {din[39-12 -:4],5'd0} + {din[39-12 -:4],3'd0};
end
end
always @(posedge clk)begin
if(rst)begin
num2 <= 0;
end else begin
num2 <= {din[39-20 -:4],6'd0} + {din[39-20 -:4],5'd0} + {din[39-20 -:4],2'd0};
end
end
always @(posedge clk)begin
if(rst)begin
num3 <= 0;
end else begin
num3 <= {din[39-28 -:4],3'd0} + {din[39-28 -:4],1'd0};
end
end
always @(posedge clk)begin
if(rst)begin
num4 <= 0;
end else begin
num4 <= din[39-36 -:4] ;
end
end
always @(posedge clk)begin
if(rst)begin
num5 <= 0;
end else begin
num5 <= num0 + num1 ;
end
end
always @(posedge clk)begin
if(rst)begin
num6 <= 0;
end else begin
num6 <= num2 + num3 + num4 ;
end
end
always @(posedge clk)begin
if(rst)begin
dout <= 0;
end else begin
dout <= num5 + num6 ;
end
end
assign rdy = valid_d[2];
endmodule
4.仿真
verilog
module tb_ascii();
reg clk;
reg rst;
initial begin
rst = 1;
#300
rst = 0;
end
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
wire rdy ;
wire [39:0] dout ;//MAX = 65535
reg valid ;
reg [15:0] din ;//MAX = 65535
always @(posedge clk)begin
if(rst)begin
valid <= 0;
din <= 0;
end else begin
valid <= 1;
din <= din + 1;
end
end
dec_ascii16 dec_ascii16(
.clk (clk ),
.rst (rst ),
.valid (valid ),
.din (din ),//MAX = 65535
.rdy (rdy ),
.dout (dout )
);
ascii_dec16 ascii_dec16(
.clk (clk ),
.rst (rst ),
.valid (rdy ),
.din (dout ),//MAX = 65535
.rdy ( ),
.dout ( )
);
endmodule