自从08年开始学FPGA以来的一年,我都是从事VHDL的,当时写了uart第一版本,现在看来戳的不行了,而且有问题恶心,哇哇吐。。。 
 
因为时代的潮流09年我也开始了Verilog,后来有学了SOCP,NIOS II,一直走。。。 
 
10年暑假,因为准备比赛,再次写了Verilog 版本的uart,双向fifo协议收发,功能上可以,没多大问题。。。 
 
11年寒假,因为家里没有宽带,饥渴难耐,我TMD受不了自己那么空了。。。觉得自己一直来是自由发挥的,代码规范都不咋地,于是拿出《华为verilog规范》,又拿出以前的代码,怎么看都不顺眼,于是,创作了verilog 版的uart 第三版本!!! 
 
我用fifo测试收发文件,上万数据没出现过错误,而且比较稳定,比起网上那些随便搞搞的东西,左看右看都感觉自己的略胜一筹。。。 
 
当然我知道完美是没有极限的,所以我拿出三个文件,希望大家能够提出宝贵意见,看看还有什么可以优化的!!!!!!!!!!!!! 
 
首先我分了三个module: 
(1)clk_generator.v  负责接收个发送的时钟,修改bps就在此处,没有用常规的方法分频,因为觉得从完美的角度考虑,这有损是新片的最佳发挥,当然也会不稳定,再次我采纳了DDS中0~2^N 步进寻址的思维,设计了是能时钟 
(2)uart_receiver.v  负责uart的数据接收,相对于数据的发送稍微简单一点,因为此处为了达到数据的最稳定,不能一读取到有数据就采样,我设计在中间时刻采样,前后保持,用了16*bps的clk来工作 
(3)uart_transfer.v  扶着uart数据的发送,clk = bps,这是比较简单的一个模块,用脚趾头想想都能实现 
 
下面我贴出这几个代码,如果大家有时间希望能给我挑挑毛病,尤其是时钟模块,虽然我觉得直接偶数分频方法出来的不准确(为了数据的准确),但我的也不是很爽: 
 
/************************************************************** 
*        File Name                :                clk_generator.v                 
*        Author                        :                Crazy Bingo 
*        Version                        :                Quartus II 9.1 
*        CreateDate                :                2011/01/31 
*        Description                :                To generator different bps 
**************************************************************/ 
/*********************************** 
        fc        =        50*10^6 
        fo        =        fc*N/(2^32) 
        N        =        fo*(2^32)/fc 
                =        fo*(2^32)/(50*10^6) 
************************************/ 
module clk_generator 
( 
        input        clk, 
        input        rst_n, 
        output        clk_bps, 
        output        clk_smp 
); 
 
//------------------------------------------ 
/************clk_smp        = 16*clk_bps************ 
Freq_Word1        <=        32'd25770;                Freq_Word1        <=        32'd412317;                //300        bps 
Freq_Word1        <=        32'd51540;                Freq_Word2        <=        32'd824634;                //600        bps 
Freq_Word1        <=        32'd103079;                Freq_Word2        <=        32'd1649267;        //1200        bps 
Freq_Word1        <=        32'd206158;                Freq_Word2        <=        32'd3298535;        //2400        bps 
Freq_Word1        <=        32'd412317;                Freq_Word2        <=        32'd6597070;        //4800        bps 
Freq_Word1        <=        32'd824634;                Freq_Word2        <=        32'd13194140;        //9600        bps 
Freq_Word1        <=        32'd1649267;        Freq_Word2        <=        32'd26388279;        //19200        bps 
Freq_Word1        <=        32'd3298535;        Freq_Word2        <=        32'd52776558;        //38400        bps 
Freq_Word1        <=        32'd3693672;        Freq_Word2        <=        32'd59098750;        //43000        bps 
Freq_Word1        <=        32'd4810363;        Freq_Word2        <=        32'd76965814;        //56000        bps 
Freq_Word1        <=        32'd4947802;        Freq_Word2        <=        32'd79164837;        //57600        bps 
Freq_Word1        <=        32'd9895605;        Freq_Word2        <=        32'd158329674;        //115200bps 
Freq_Word1        <=        32'd10995116;        Freq_Word2        <=        32'd175921860;        //128000bps 
Freq_Word1        <=        32'd21990233;        Freq_Word2        <=        32'd351843721;        //256000bps 
*****************************************************/ 
//only want to generate beautiful clk for bsp and sample 
reg        [31:0]        bps_cnt1; 
reg        [31:0]        bps_cnt2; 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                bps_cnt1 <= 0; 
                bps_cnt2 <= 0; 
                end 
        else 
                begin 
                bps_cnt1 <= bps_cnt1+32'd10995116;        //Bps=128000bps 
                bps_cnt2 <= bps_cnt2+32'd175921860;        //Bps=128000bps*16 
                end 
end 
 
//------------------------------------------ 
//clk_bps sync bps generater 
reg        clk_bps_r0,clk_bps_r1,clk_bps_r2; 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                clk_bps_r0 <= 0; 
                clk_bps_r1 <= 0; 
                clk_bps_r2 <= 0; 
                end 
        else 
                begin 
                if(bps_cnt1 < 32'h7FFF_FFFF) 
                        clk_bps_r0 <= 0; 
                else 
                        clk_bps_r0 <= 1; 
                clk_bps_r1 <= clk_bps_r0; 
                clk_bps_r2 <= clk_bps_r1; 
                end 
end 
assign        clk_bps = ~clk_bps_r2 & clk_bps_r1; 
 
//------------------------------------------ 
//clk_smp sync receive bps generator 
reg        clk_smp_r0,clk_smp_r1,clk_smp_r2; 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                clk_smp_r0 <= 0; 
                clk_smp_r1 <= 0; 
                clk_smp_r2 <= 0; 
                end 
        else 
                begin 
                if(bps_cnt2 < 32'h7FFF_FFFF) 
                        clk_smp_r0 <= 0; 
                else 
                        clk_smp_r0 <= 1; 
                clk_smp_r1 <= clk_smp_r0; 
                clk_smp_r2 <= clk_smp_r1; 
                end 
end 
assign        clk_smp = ~clk_smp_r2 & clk_smp_r1; 
 
endmodule 
 
 
 
/************************************************************** 
*        File Name                :                uart_receiver.v                 
*        Author                        :                Crazy Bingo 
*        Version                        :                Quartus II 9.1 
*        CreateDate                :                2011/01/31 
*        Description                :                rxd data Receiver 
**************************************************************/ 
module uart_receiver 
( 
        input                                clk, 
        input                                clk_smp,        //clk_smp=16*clk_bps 
        input                                rst_n, 
         
        input                                rxd, 
        output                                rxd_flag,        //the flag of receive over 
        output        reg        [7:0]        rxd_data         
); 
 
//--------------------------------- 
//sync the data: rxd_sync 
reg        rxd_sync_r0,rxd_sync_r1;                                 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                rxd_sync_r0 <= 1; 
                rxd_sync_r1 <= 1; 
                end 
        else if(clk_smp == 1) 
                begin 
                rxd_sync_r0 <= rxd; 
                rxd_sync_r1 <= rxd_sync_r0; 
                end 
end 
wire        rxd_sync = rxd_sync_r1; 
 
//--------------------------------- 
//sample data from pc to cpu 
parameter        R_IDLE                =        1'b0;                //>=7 clk_smp : receive flag  
parameter        R_SAMPLE        =        1'b1;                //sample data programmer 
reg                        rxd_state; 
reg        [3:0]        smp_cnt;                                        //sample cycle counter 
reg        [2:0]        rxd_cnt;                                        //the lenth of data 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                smp_cnt <= 0; 
                rxd_cnt <= 0; 
                rxd_data <= 0; 
                rxd_state <= R_IDLE; 
                end 
        else if(clk_smp == 1) 
                begin 
                case(rxd_state) 
                R_IDLE: 
                        begin 
                        rxd_cnt <= 0; 
                        if(rxd_sync == 1'b0) 
                                begin 
                                smp_cnt <= smp_cnt + 1'b1; 
                                if(smp_cnt == 4'd7)                //8 clk_smp enable 
                                        rxd_state <= R_SAMPLE; 
                                end 
                        else 
                                smp_cnt <= 0; 
                        end 
                R_SAMPLE:         
                        begin 
                        smp_cnt <= smp_cnt +1'b1; 
                        if(smp_cnt == 4'd7) 
                                begin 
                                rxd_cnt <= rxd_cnt +1'b1; 
                                if(rxd_cnt == 4'd7) 
                                        rxd_state <= R_IDLE; 
                                case(rxd_cnt) 
                                3'd0:        rxd_data[0] <= rxd_sync; 
                                3'd1:        rxd_data[1] <= rxd_sync; 
                                3'd2:        rxd_data[2] <= rxd_sync; 
                                3'd3:        rxd_data[3] <= rxd_sync; 
                                3'd4:        rxd_data[4] <= rxd_sync; 
                                3'd5:        rxd_data[5] <= rxd_sync; 
                                3'd6:        rxd_data[6] <= rxd_sync; 
                                3'd7:        rxd_data[7] <= rxd_sync; 
                                endcase 
                                end 
                        end 
                endcase 
                end 
end 
wire        rxd_flag_r = (rxd_cnt == 4'd7) ? 1'b1 : 1'b0; 
 
//--------------------------------- 
//the signal flag of rxd receive over 
reg        rxd_flag_r0,rxd_flag_r1; 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                rxd_flag_r0 <= 0; 
                rxd_flag_r1 <= 0; 
                end 
        else 
                begin 
                rxd_flag_r0 <= rxd_flag_r; 
                rxd_flag_r1 <= rxd_flag_r0; 
                end 
end 
assign        rxd_flag = ~rxd_flag_r1 & rxd_flag_r0; 
 
endmodule 
 
 
/************************************************************** 
*        File Name                :                uart_transfer.v                 
*        Author                        :                Crazy Bingo 
*        Version                        :                Quartus II 9.1 SP2 
*        CreateDate                :                2011/01/31 
*        Description                :                txd data Transfer 
**************************************************************/ 
module uart_transfer 
( 
        input                        clk, 
        input                        clk_bps, 
        input                        rst_n, 
        input                        txd_en,                //txd data mark 
        input        [7:0]        txd_data, 
         
        output                        txd_flag,        //txd data over mark 
        output        reg                txd 
); 
 
//------------------------------------- 
//transfer data from cpu to pc 
parameter        T_IDLE        =        1'b0;        //test the flag to transfer data 
parameter        T_SEND        =        1'b1;        //uart transfer data 
reg                        txd_state; 
reg        [3:0]        txd_cnt;                        //txd data counter 
reg                        txd_flag_r; 
always@(posedge clk        or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                txd_state <= T_IDLE; 
                txd_flag_r <= 0; 
                txd        <= 1'b1;         
                end 
        else 
                begin 
                case(txd_state) 
                T_IDLE:                 
                        begin 
                        txd <= 1; 
                        txd_flag_r <= 0; 
                        if(txd_en == 1) 
                                txd_state <= T_SEND; 
                        else 
                                txd_state <= T_IDLE; 
                        end         
                T_SEND:         
                        begin 
                        if(clk_bps == 1) 
                                begin 
                                if(txd_cnt < 4'd9)         
                                        txd_cnt <= txd_cnt + 1'b1; 
                                else 
                                        begin 
                                        txd_cnt <= 0; 
                                        txd_state <= T_IDLE; 
                                        txd_flag_r <= 1; 
                                        end 
                                case(txd_cnt) 
                                4'd0:        txd <= 0; 
                                4'd1:        txd <= txd_data[0]; 
                                4'd2:        txd <= txd_data[1]; 
                                4'd3:        txd <= txd_data[2]; 
                                4'd4:        txd <= txd_data[3]; 
                                4'd5:        txd <= txd_data[4]; 
                                4'd6:        txd <= txd_data[5]; 
                                4'd7:        txd <= txd_data[6]; 
                                4'd8:        txd <= txd_data[7]; 
                                4'd9:        txd <= 1; 
                                endcase 
                                end         
                        end                 
                endcase 
                end 
end 
 
//------------------------------------- 
//Capture the falling of data transfer over 
reg        txd_flag_r0,txd_flag_r1; 
always@(posedge clk or negedge rst_n) 
begin 
        if(!rst_n) 
                begin 
                txd_flag_r0 <= 0; 
                txd_flag_r1 <= 0; 
                end 
        else 
                begin 
                txd_flag_r0 <= txd_flag_r; 
                txd_flag_r1 <= txd_flag_r0; 
                end 
end 
assign        txd_flag = txd_flag_r1 & ~txd_flag_r0; 
 
endmodule 
 
 
点击此处下载 ourdev_618188VEGAZ0.rar(文件大小:3K) (原文件名:uart_io_design.rar)  
文件在此处上传,谁要用我没意见,反正XXX 
 
但给我挑毛病,因为我看大部分人写的uart都不是很爽,所以 ,谢谢了 
 |