• 4.3 Verilog练习(3)


    练习九.利用状态机的嵌套实现层次结构化设计

    目的:1.运用主状态机与子状态机产生层次化的逻辑设计;2.在结构化设计中灵活使用任务(task)结构。
    在上一节,我们学习了如何使用状态机的实例。实际上,单个有限状态机控制整个逻辑电路的运转在实际设计中是不多见,往往是状态机套用状态机,从而形成树状的控制核心。这一点也与我们提倡的层次化、结构化的自顶而下的设计方法相符,下面我们就将提供一个这样的示例以供大家学习。
    该例是一个简化的EPROM的串行写入器。事实上,它是一个EPROM读写器设计中实现写功能的部分经删节得到的,去除了EPROM的启动、结束和EPROM控制字的写入等功能,只具备这样一个雏形。

    工作的步骤是:1.地址的串行写入;2.数据的串行写入;3.给信号源应答,信号源给出下一个操作对象;4.结束写操作。通过移位令并行数据得以一位一位输出。

    // Module Name: writing
    
    `timescale 1ns / 1ps
    module writing(reset,clk,address,data,sda,ack);
    input reset,clk;
    input[7:0] data,address;
    output sda,ack; //sda负责串行数据输出;
                    //ack是一个对象操作完毕后,模块给出的应答信号。
    reg link_write; //link_write 决定何时输出。
    reg[3:0] state; //主状态机的状态字。
    reg[4:0] sh8out_state; //从状态机的状态字。
    reg[7:0] sh8out_buf; //输入数据缓冲。
    reg finish_F; //用以判断是否处理完一个操作对象。
    reg ack;
    parameter idle=0,addr_write=1,data_write=2,stop_ack=3;
    parameter bit0=1,bit1=2,bit2=3,bit3=4,bit4=5,bit5=6,bit6=7,bit7=8;
    assign sda = link_write? sh8out_buf[7] : 1'bz;
    
    always @(posedge clk)
    begin
        if(!reset) //复位。
            begin
            link_write<= 0;
            state <= idle;
            finish_F <= 0;
            sh8out_state<=idle;
            ack<= 0;
            sh8out_buf<=0;
            end
        else    
            case(state)
            idle:
                begin
                link_write <= 0;
                state <= idle;
                finish_F <= 0;
                sh8out_state<=idle;
                ack<= 0;
                sh8out_buf<=address;
                state <= addr_write;
                end
                
            addr_write: //地址的输入。
                begin
                    if(finish_F==0)
                     shift8_out; 
                    else
                        begin
                        sh8out_state <= idle;
                        sh8out_buf <= data;
                        state <= data_write;
                        finish_F <= 0;
                        end
                end
                
            data_write: //数据的写入。
                begin
                    if(finish_F==0)
                      shift8_out;
                    else
                        begin
                        link_write <= 0;
                        state <= stop_ack;
                        finish_F <= 0;
                        ack <= 1;
                        end
                end
                
            stop_ack: //完成应答。
                begin
                ack <= 0;
                state <= idle;
                end
          endcase
      end
       
            
    task shift8_out; //串行写入。
    begin
        case(sh8out_state)
        idle:
            begin
            link_write <= 1;
            sh8out_state <= bit0;
            end
        bit0:
            begin
            link_write <= 1;
            sh8out_state <= bit1;
            sh8out_buf <= sh8out_buf<<1;
            end
        bit1:
            begin
            sh8out_state<=bit2;
            sh8out_buf<=sh8out_buf<<1;
            end
        bit2:
            begin
            sh8out_state<=bit3;
            sh8out_buf<=sh8out_buf<<1;
            end
        bit3:
            begin
            sh8out_state<=bit4;
            sh8out_buf<=sh8out_buf<<1;
            end
        bit4:
            begin
            sh8out_state<=bit5;
            sh8out_buf<=sh8out_buf<<1;
            end
        bit5:
            begin
            sh8out_state<=bit6;
            sh8out_buf<=sh8out_buf<<1;
            end
        bit6:
            begin
            sh8out_state<=bit7;
            sh8out_buf<=sh8out_buf<<1;
            end
        bit7:
            begin
            link_write<= 0;
            finish_F<=finish_F+1;
            end
        endcase
        end
    endtask
    
    endmodule
    
    // Module Name: writing_simu
    
    `timescale 1ns / 1ps
    `define clk_cycle 50
    
    module writing_simu;
    reg reset,clk;
    reg[7:0] data,address;
    wire ack,sda;
    
    always #`clk_cycle clk = ~clk;
    
    initial
        begin
        clk=0;
        reset=1;
        data=0000_1010;
        address=0011_0110;
        #(2*`clk_cycle) reset=0;
        #(2*`clk_cycle) reset=1;
       // #(100*`clk_cycle) $stop;
    end
    
    always @(posedge ack) //接收到应答信号后,给出下一个处理对象。
        begin
        data=data+1;
        address=address+1;
        end
        
    writing writing(.reset(reset),.clk(clk),.data(data),.address(address),.ack(ack),.sda(sda));
    endmodule

    前8个周期存地址,后八个周期存数据。ACK=1,表示一次存储完成。

    练习十. 通过模块之间的调用实现自顶向下的设计

    目的:学习状态机的嵌套使用实现层次化、结构化设计。
    现代硬件系统的设计过程与软件系统的开发相似,设计一个大规模的集成电路的往往由模块多层次的引用和组合构成。 层次化、结构化的设计过程,能使复杂的系统容易控制和调试。 在Verilog HDL中,上层模块引用下层模块与C语言中程序调用有些类似,被引用的子模块在综合时作为其父模块的一部分被综合,形成相应的电路结构。在进行模块实例引用时,必须注意的是模块之间对应的端口,即子模块的端口与父模块的内部信号必须明确无误地一一对应,否则容易产生意想不到的后果。
    下面给出的例子是设计中遇到的一个实例,其功能是将并行数据转化为串行数据送交外部电路编码,并将解码后得到的串行数据转化为并行数据交由CPU处理。显而易见,这实际上是两个独立的逻辑功能,分别设计为独立的模块,然后再合并为一个模块显得目的明确、层次清晰。

    // Module Name: p_to_s
    //function:并行数据--->串行数据
    
    module p_to_s(D_in,T0,data,SEND,ESC,ADD_100);
     
    output D_in,T0; // D_in是串行输出,T0是移位时钟并给CPU中断,以确定何时给出下个数据。
    input [7:0] data; //并行输入的数据。
    input SEND,ESC,ADD_100; //SEND、ESC共同决定是否进行并到串的数据转化。ADD_100决定何时置数。
    
    wire D_in,T0;
    reg [7:0] DATA_Q,DATA_Q_buf;
    assign T0 = ! (SEND & ESC); //形成移位时钟。.
    assign D_in = DATA_Q[7]; //给出串行数据。
    
    always @(posedge T0 or negedge ADD_100) //ADD_100下沿置数,T0上沿移位。
        begin
        if(!ADD_100)
             DATA_Q = data;
        else
            begin
            DATA_Q_buf = DATA_Q<<1; //DATA_Q_buf作为中介,以令综合器
            DATA_Q = DATA_Q_buf; //能辨明。
            end
    end
    endmodule
    
    // Module Name: s_to_p
    //function:串行数据--->并行数据
    
    module s_to_p(T1, data, D_out,DSC,TAKE,ADD_101);
    
    output T1; //给CPU中断,以确定CPU何时取转化得到的并行数据。
    output [7:0] data;
    input D_out, DSC, TAKE, ADD_101; //D_out提供输入串行数据。DSC、TAKE共同决定何时取数。
    
    wire [7:0] data;
    wire T1,clk2;
    reg [7:0] data_latch, data_latch_buf;
    
    assign clk2 = DSC & TAKE ; //提供移位时钟。
    assign T1 = !clk2;
    assign data = (!ADD_101) ? data_latch : 8'bz;
    
    always@(posedge clk2)
        begin
        data_latch_buf = data_latch << 1; //data_latch_buf作缓冲
        data_latch = data_latch_buf; //,以令综合器能辩明。
        data_latch[0] = D_out;
    end
    endmodule
    
    // Module Name: sys
    
    module sys(D_in,T0,T1, data, D_out,SEND,ESC,DSC,TAKE,ADD_100,ADD_101);
    
    input D_out,SEND,ESC,DSC,TAKE,ADD_100,ADD_101;
    inout [7:0] data;
    output D_in,T0,T1;
    
    p_to_s p_to_s(.D_in(D_in),.T0(T0),.data(data),.SEND(SEND),.ESC(ESC),.ADD_100(ADD_100));
    s_to_p s_to_p(.T1(T1),.data(data),.D_out(D_out),.DSC(DSC),.TAKE(TAKE),.ADD_101(ADD_101));
    
    endmodule
    
    `timescale 1ns / 1ps
    
    // Module Name: sys_simu
    
    module sys_simu;
    reg D_out,SEND,ESC,DSC,TAKE,ADD_100,ADD_101;
    reg[7:0] data_buf;
    wire [7:0] data;
    wire clk2;
    assign data = (ADD_101) ? data_buf : 8'bz;
    //data在sys中是inout型变量,ADD_101
    //控制data是作为输入还是进行输出。
    assign clk2 =DSC && TAKE;
    
    initial
        begin
        SEND = 0;
        ESC = 0;
        DSC = 1;
        TAKE = 1;
        ADD_100 = 1;
        ADD_101 = 1;
    end
    
    initial
        begin
        data_buf = 8'b1011_1010;
        #90 ADD_100 = 0;
        #100 ADD_100 = 1;
    end
    
    always
        begin
        #50;
        SEND = ~SEND;
        ESC = ~ESC;    
        DSC = ~DSC;
        TAKE = ~TAKE;
    end
    
    initial
        begin
        #1500 ;
        SEND = 0;
        ESC = 0;
        DSC = 1;
        TAKE = 1;
        ADD_100 = 1;
        ADD_101 = 1;
        D_out = 0;
        #1150 ADD_101 = 0;  // 2650ns
        #100 ADD_101 =1;
     //   #100 $stop;
    end
    
    always @(negedge clk2) D_out = ~D_out;
    
    sys sys(.D_in(D_in),.T0(T0),.T1(T1),.data(data),.D_out(D_out),.ADD_101(ADD_101), .SEND(SEND),.ESC(ESC),.DSC(DSC),.TAKE(TAKE),.ADD_100(ADD_100));
    endmodule
    

  • 相关阅读:
    python保护变量(_),私有变量(__),私有方法,
    避免在循环体中创建对象
    HashMap的初始容量(initialCapacity)和装载因子(loadFactor)
    深入理解Java的接口和抽象类
    关于◎SuppressWarnings("unchecked")
    缓存技术PK:选择Memcached还是Redis?
    Maven详解之聚合与继承
    浅谈redis和memcached的区别
    《玩转Spring》第二章 BeanPostProcessor扩展
    使用Spring实现读写分离( MySQL实现主从复制)
  • 原文地址:https://www.cnblogs.com/l20902/p/10610900.html
Copyright © 2020-2023  润新知