verilog实现十进制正数与ASCII码互转

时间:2025-03-28 09:01:24

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码

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码转十进制正数

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.仿真

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