chenbingjy 发表于 2023-4-13 16:39

夏宇闻老师书第16章例子仿真的问题

<p>程序实现一个EEPROM(AT24C02/4/8/16)</p>

<p>代码如下:</p>

<pre>
<code>`timescale 1ns/1ps

module EEPROM_WR(sda,scl,ACK,RESET,CLK,WR,RD,ADDR,DATA);
output scl;
output ACK;
input RESET;
input CLK;
input WR,RD;
input ADDR;
inout sda;
inout DATA;

reg ACK;
reg scl;
reg WF,RF;
reg FF;
reg head_buf;
reg stop_buf;
reg sh8out_buf;
reg sh8out_state;
reg sh8in_state;
reg head_state;
reg stop_state;
reg main_state;
reg data_from_rm;
reg link_sda;
reg link_read;
reg link_head;
reg link_write;
reg link_stop;
wire sda1,sda2,sda3,sda4;

//串行数据在开关控制下有秩序的输出或输入
assign sda1=(link_head) ? head_buf :1'b0;
assign sda2=(link_write) ? sh8out_buf : 1'b0;
assign sda3=(link_stop) ?stop_buf :1'b0;
assign sda4=(sda1|sda2|sda3);
assign sda=(link_sda)? sda4:1'bz;
assign DATA=(link_read)?data_from_rm:8'hzz;

//主状态机状态定义

parameter
        Idle                                =11'b00000000001,
        Ready                                =11'b00000000010,
        Write_start                =11'b00000000100,
        Ctrl_write                =11'b00000001000,
        Addr_write                =11'b00000010000,
        Data_write                =11'b00000100000,
        Read_start                =11'b00001000000,
        Ctrl_read                =11'b00010000000,
        Data_read                =11'b00100000000,
        Stop                           =11'b01000000000,
        Ackn                                =11'b10000000000,
       
//并行数据串行输出状态
        sh8out_bit7=9'b000000001,
        sh8out_bit6=9'b000000010,
        sh8out_bit5=9'b000000100,
        sh8out_bit4=9'b000001000,
        sh8out_bit3=9'b000010000,
        sh8out_bit2=9'b000100000,
        sh8out_bit1=9'b001000000,
        sh8out_bit0=9'b010000000,
        sh8out_end =9'b100000000;
       
//串行数据并行输出状态
parameter sh8in_begin                        =10'b0000000001,
                       sh8in_bit7                                =10'b0000000010,
                       sh8in_bit6                                =10'b0000000100,
                       sh8in_bit5                                =10'b0000001000,
                       sh8in_bit4                                =10'b0000010000,
                       sh8in_bit3                                =10'b0000100000,
                       sh8in_bit2                                =10'b0001000000,
                       sh8in_bit1                                =10'b0010000000,
                       sh8in_bit0                                =10'b0100000000,
                       sh8in_end                                =10'b1000000000,
                       
//启动状态
                        head_begin=3'b001,
                        head_bit       =3'b010,
                        head_end       =3'b100,
//停止状态
                        stop_begin        =3'b001,
                        stop_bit                =3'b010,
                        stop_end                =3'b100;

parameter        YES        =1,
                                NO                =0;
//产生串行时钟SCL,为输入时钟的2分频
always @(negedge CLK)
        if(RESET)
                scl&lt;=0;
        else       
                scl&lt;=~scl;
               
//主状态机程序
always @(posedge CLK)
        if(RESET)
                begin
                        link_read&lt;=NO;
                        link_write&lt;=NO;
                        link_head&lt;=NO;
                        link_stop&lt;=NO;
                        link_sda&lt;=NO;
                        ACK&lt;=0;
                        RF&lt;=0;
                        WF&lt;=0;
                        FF&lt;=0;
                        main_state&lt;=Idle;
                end
        else       
                begin
                        casex(main_state)
                                Idle:
                                        begin       
                                                link_read&lt;=NO;
                                                link_write&lt;=NO;
                                                link_head&lt;=NO;
                                                link_stop&lt;=NO;
                                                link_sda&lt;=NO;
                                                if(WR)
                                                        begin
                                                                WF&lt;=1;
                                                                main_state&lt;=Ready;
                                                        end
                                                else if(RD)
                                                        begin
                                                                RF&lt;=1;
                                                                main_state&lt;=Ready;
                                                        end
                                                else
                                                        begin
                                                                WF&lt;=0;
                                                                RF&lt;=0;
                                                                main_state&lt;=Idle;
                                                        end
                                                end
                                Ready:
                                        begin       
                                                link_read&lt;=NO;
                                                link_write&lt;=NO;
                                                link_stop&lt;=NO;
                                                link_head&lt;=YES;
                                                link_sda&lt;=YES;
                                                head_buf&lt;=2'b10;
                                                stop_buf&lt;=2'b01;
                                                head_state&lt;=head_begin;
                                                FF&lt;=0;
                                                ACK&lt;=0;
                                                main_state&lt;=Write_start;
                                        end
                Write_start:
                                        if(FF==0)
                                                shift_head;
                                        else
                                                begin
                                                        sh8out_buf&lt;={1'b1,1'b0,1'b1,1'b0,ADDR,1'b0};
                                                        link_head&lt;=NO;
                                                        link_write&lt;=YES;
                                                        FF&lt;=0;
                                                        sh8out_state&lt;=sh8out_bit6;
                                                        main_state&lt;=Ctrl_write;
                                                end
        Ctrl_write:
                                        if(FF==0)
                                                shift8_out;
                                        else
                                                begin
                                                        sh8out_state&lt;=sh8out_bit7;
                                                        sh8out_buf &lt;= ADDR;
                                                        FF&lt;=0;
                                                        main_state&lt;=Addr_write;
                                                end
        Addr_write:
                                        if(FF==0)
                                                shift8_out;
                                        else
                                                begin
                                                        FF&lt;=0;
                                                        if(WF)
                                                                begin
                                                                        sh8out_state&lt;=   sh8out_bit7;
                                                                        sh8out_buf &lt;=DATA;
                                                                        main_state        &lt;=Data_write;
                                                          end
                                                        if(RF)
                                                                begin
                                                                        head_buf&lt;= 2'b10;
                                                                        head_state&lt;=head_begin;
                                                                        main_state&lt;=Read_start;
                                                                end
                                       end
        Data_write:
                        if(FF==0)
                                shift8_out;
                        else
                                begin       
                                        stop_state&lt;=stop_begin;
                                        main_state&lt;=Stop;
                                        link_write&lt;=NO;
                                        FF&lt;=0;
                                end
        Read_start:
                        if(FF==0)
                                shift_head;
                        else       
                                begin
                                        sh8out_buf&lt;={1'b1,1'b0,1'b1,1'b0,ADDR,1'b1};
                                        link_head&lt;=NO;
                                        link_sda&lt;=YES;
                                        link_write&lt;=YES;
                                        FF&lt;=0;
                                        sh8out_state&lt;=sh8out_bit6;
                                        main_state&lt;=Ctrl_read;
                                end
        Ctrl_read:
                        if(FF==0)
                                shift8_out;
                        else
                                begin
                                       
                                        link_sda&lt;=NO;
                                        link_write&lt;=NO;
                                        FF&lt;=0;
                                        sh8in_state&lt;=sh8in_begin;
                                        main_state&lt;=Data_read;
                                end
                               
        Data_read:
                        if(FF==0)
                                shift8in;
                        else       
                                begin
                                        link_stop&lt;=YES;
                                        link_sda&lt;=YES;
                                        stop_state&lt;=stop_bit;
                                        FF&lt;=0;
                                        main_state&lt;=Stop;
                                end
        Stop:
                        if(FF==0)
                                shift_stop;
                        else
                                begin
                                        ACK&lt;=1;
                                        FF&lt;=0;
                                        main_state&lt;=Ackn;
                                end
                               
        Ackn:
                        begin       
                                ACK&lt;=0;
                                WF&lt;=0;
                                RF&lt;=0;
                                main_state&lt;=Idle;
                        end
        default:
                        main_state&lt;=Idle;
        endcase
end
//串行数据转换为并行数据任务
task shift8in;
                begin
                        casex(sh8in_state)
                                sh8in_begin:
                                        sh8in_state&lt;=sh8in_bit7;
                                sh8in_bit7:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit6;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit7;
                           sh8in_bit6:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit5;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit6;
                                sh8in_bit5:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit4;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit5;
                                sh8in_bit4:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit3;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit4;
                                sh8in_bit3:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit2;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit3;
                                sh8in_bit2:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit1;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit2;
                                sh8in_bit1:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_bit0;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit1;
                                sh8in_bit0:
                                        if(scl)
                                                begin
                                                        data_from_rm &lt;=sda;
                                                        sh8in_state&lt;=sh8in_end;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_bit0;
                                sh8in_end:
                                        if(scl)
                                                begin
                                                        link_read&lt;=YES;
                                                        FF&lt;=1;
                                                        sh8in_state&lt;=sh8in_bit7;
                                                end
                                        else
                                                sh8in_state&lt;=sh8in_end;
                                default:
                                        begin
                                                link_read&lt;=NO;
                                                sh8in_state&lt;=sh8in_bit7;
                                        end
                        endcase
                end
        endtask
       
//并行数据转换为串行数据任务
task shift8_out;
        begin
                casex(sh8out_state)
                        sh8out_bit7:
                                if(!scl)
                                        begin
                                                link_sda&lt;=YES;
                                                link_write&lt;=YES;
                                                sh8out_state&lt;=sh8out_bit6;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit7;
                        sh8out_bit6:
                                if(!scl)
                                        begin
                                                link_sda&lt;=YES;
                                                link_write&lt;=YES;
                                                sh8out_state&lt;=sh8out_bit5;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit6;
                        sh8out_bit5:
                                if(!scl)
                                        begin
                                               
                                                sh8out_state&lt;=sh8out_bit4;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit5;
                        sh8out_bit4:
                                if(!scl)
                                        begin
                                               
                                                sh8out_state&lt;=sh8out_bit3;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit4;       
                        sh8out_bit3:
                                if(!scl)
                                        begin
                                               
                                                sh8out_state&lt;=sh8out_bit2;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit3;       
                        sh8out_bit2:
                                if(!scl)
                                        begin
                                               
                                                sh8out_state&lt;=sh8out_bit1;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit2;
                        sh8out_bit1:
                                if(!scl)
                                        begin
                                               
                                                sh8out_state&lt;=sh8out_bit0;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit1;       
                        sh8out_bit0:
                                if(!scl)
                                        begin
                                               
                                                sh8out_state&lt;=sh8out_end;
                                                sh8out_buf&lt;=sh8out_buf&lt;&lt;1;
                                        end
                                else
                                        sh8out_state&lt;=sh8out_bit0;               
               sh8out_end:
                                if(!scl)
                                        begin
                                               
                                                link_sda&lt;=NO;
                                                link_write&lt;=NO;
                                                FF&lt;=1;
                                               
                                        end
                                else
                                        sh8out_state&lt;=sh8out_end;       
                        endcase
                end
        endtask
       
//输出启动信号任务
task shift_head;
        begin
                casex(head_state)
                        head_begin:
                                if(!scl)
                                        begin
                                                link_write&lt;=NO;
                                                link_sda&lt;=YES;
                                                link_head&lt;=YES;
                                                head_state&lt;=head_bit;
                                        end
                                else
                                        head_state&lt;=head_begin;
                        head_bit:
                                if(scl)
                                        begin       
                                                FF&lt;=1;
                                                head_buf&lt;=head_buf&lt;&lt;1;
                                                head_state&lt;=head_end;
                                        end
                                else
                                        head_state&lt;=head_bit;
                        head_end:
                                if(!scl)
                                        begin
                                                link_head&lt;=NO;
                                                link_write&lt;=YES;
                                        end
                                else
                                        head_state&lt;=head_end;
                        endcase
                end
        endtask
       
//输出停止信号任务
task shift_stop;
        begin       
       
                casex(stop_state)
                        stop_begin:
                                if(!scl)
                                        begin               
                                                link_sda&lt;=YES;
                                                link_write&lt;=NO;
                                                link_stop&lt;=YES;
                                                stop_state&lt;=stop_bit;
                                        end
                                else
                                        stop_state&lt;=stop_begin;
                        stop_bit:
                                if(scl)
                                        begin       
                                                stop_buf&lt;=stop_buf&lt;&lt;1;
                                                stop_state&lt;=stop_end;
                                        end
                                else
                                        stop_state&lt;=stop_bit;
                        stop_end:
                                if(!scl)
                                        begin
                                                link_head&lt;=NO;
                                                link_stop&lt;=NO;
                                                link_sda&lt;=NO;
                                                FF&lt;=1;
                                        end
                                else
                                        stop_state&lt;=stop_end;
                                       
                        endcase
                end
        endtask
endmodule

                               
       
                               
                               
                               
</code></pre>

<p>仿真文件如下:</p>

<pre>
<code>`timescale 1ns/1ps
`define timeslice 200

module signal(RESET,CLK,RD,WR,ADDR,ACK,DATA);
output RESET;
output CLK;
output RD,WR;
output ADDR;
input ACK;
inout DATA;

reg RESET;
reg CLK;
reg RD,WR;
reg W_R;
reg ADDR;
reg data_to_eeprom;
reg addr_mem;
reg data_mem;
reg ROM;
integer i,j;
integer OUTFILE;

parameter test_number=5;
assign DATA=(W_R)? 8'bz:data_to_eeprom;

always #(`timeslice/2)
        CLK=~CLK;

//读写信号输入
initial
        begin
                i=0;j=0;
                W_R=0;
                CLK=0;
                RD=0;
                WR=0;
                #1000;
                RESET=0;
                repeat(test_number)
                begin
                        #(5*`timeslice);
                        WR=1;
                        #(`timeslice);
                        WR=0;
                        @(posedge ACK);
                end
                #(10* `timeslice);
                W_R=1;
                repeat(test_number)
                        begin
                                #(5*`timeslice);
                                RD=1;
                                #(`timeslice);
                                RD=0;
                                @(posedge ACK);
                        end
                end
//写操作
initial
        begin
                $display("writing-----writing-----writing-----writing");
                #(2*`timeslice);
                for(i=0;i&lt;test_number;i=i+1)
                        begin       
                                ADDR=addr_mem;
                                data_to_eeprom=data_mem;
                                $fdisplay(OUTFILE,"@%0h   %0h",ADDR,data_to_eeprom);
                                @(posedge ACK);
                        end
                end
               
//读操作
initial       
        @(posedge W_R)
                begin
                        ADDR=addr_mem;
                        $fclose(OUTFILE);
                        $readmemh("eeprom.dat",ROM);
                        $display("Begin READING-----READING-----READING-----READING");
                        for(j=0;j&lt;=test_number;j=j+1)
                                begin
                                        ADDR=addr_mem;
                                        @(posedge ACK);
                                        if(DATA==ROM)
                                                $display("DATA %0h ==ROM[%0h]----READ RIGHT",DATA,ADDR);
                                        else
                                                $display("DATA %0h != ROM[%0h]-----READ WRONG",DATA,ADDR);
                                end
                        end
                initial
                        begin
                                OUTFILE=$fopen("eeprom.dat");
                                $readmemh("addr.dat",addr_mem);
                                $readmemh("data.dat",data_mem);
                        end
                endmodule
               
               
                </code></pre>

<p>仿真出不来波形:</p>

<p></p>

<p>请问高手,哪里有问题?谢谢!</p>

chenbingjy 发表于 2023-4-13 19:16

<p>仿真代码我改了一下:</p>

<pre>
<code>`timescale 1ns/1ps
`define timeslice 200

module signal(RESET,CLK,RD,WR,ADDR,ACK,DATA);
output RESET;
output CLK;
output RD,WR;
output ADDR;
input ACK;
inout DATA;

reg RESET;
reg CLK;
reg RD,WR;
reg W_R;
reg ADDR;
reg data_to_eeprom;
reg addr_mem;
reg data_mem;
reg ROM;
reg Cnt;
integer i,j;
integer OUTFILE;

parameter test_number=5;
assign DATA=(W_R)? 8'bz:data_to_eeprom;
assign ACK=Cnt;

always #(`timeslice/2)
        CLK=~CLK;

always @(posedge CLK)
                Cnt&lt;=Cnt+1;
//读写信号输入
initial
        begin
                RESET=1;
                i=0;j=0;
                W_R=0;
                CLK=0;
                Cnt=0;
                RD=0;
                WR=0;
                #1000;
                RESET=0;
                repeat(test_number)
                begin
                        #(5*`timeslice);
                        WR=1;
                        #(`timeslice);
                        WR=0;
                        @(posedge ACK);
                end
                #(10* `timeslice);
                W_R=1;
                repeat(test_number)
                        begin
                                #(5*`timeslice);
                                RD=1;
                                #(`timeslice);
                                RD=0;
                                @(posedge ACK);
                        end
                end
//写操作
initial
        begin
                $display("writing-----writing-----writing-----writing");
                #(2*`timeslice);
               
                for(i=0;i&lt;=test_number;i=i+1)
                        begin       
                                ADDR=addr_mem;
                                data_to_eeprom=data_mem;
                                //$fdisplay(OUTFILE,"%0h   %0h",ADDR,data_to_eeprom);
                                $fdisplay(OUTFILE,"%h",data_to_eeprom);
                                @(posedge ACK);
                               
                        end
                end
               
//读操作
initial       
        @(posedge W_R)
                begin
                        ADDR=addr_mem;
                        $fclose(OUTFILE);
                       
                        $readmemh("./eeprom.dat",ROM);
                        $display("Begin READING-----READING-----READING-----READING");
                        for(j=0;j&lt;=test_number;j=j+1)
                                begin
                                        ADDR=addr_mem;
                                       
                                       
                                        @(posedge ACK);
                                        $display("ROM=%0h",ROM);
                                        if(data_mem==ROM)
                                                $display("DATA %0h ==ROM[%0h]----READ RIGHT",data_mem,ADDR);
                                        else
                                                $display("DATA %0h != ROM[%0h]-----READ WRONG",data_mem,ADDR);
                                end
                        end
                initial
                        begin
                                OUTFILE=$fopen("./eeprom.dat");
                               
                                $readmemh("./addr.dat",addr_mem);
                               
                                $readmemh("./data.dat",data_mem);
                               
                        end
                endmodule
               
               
                </code></pre>

<p>这样仿真结果就是对的</p>

<p></p>

<p>可是有个问题,代码里面是ROM,按说不应该加1的。</p>

<p>可是不加1,</p>

<pre>
<code>if(data_mem==ROM)
                                                $display("DATA %0h ==ROM[%0h]----READ RIGHT",data_mem,ADDR);
                                        else
                                                $display("DATA %0h != ROM[%0h]-----READ WRONG",data_mem,ADDR);</code></pre>

<p>仿真结果就不对:</p>

<p></p>

<p>请问高手,这是怎么回事呢?谢谢!</p>
页: [1]
查看完整版本: 夏宇闻老师书第16章例子仿真的问题