搜索
bottom↓
回复: 27

高手们看下我这段VHDL程序哪里还有问题

[复制链接]

出0入0汤圆

发表于 2011-4-8 18:34:52 | 显示全部楼层 |阅读模式
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity adder is
        port
          (
            sec_modA : in std_logic;--模式选择信号
            sec_modB : in std_logic;--模式选择信号
            sec_modC : in std_logic;--模式选择信号
            sec_modD : in std_logic;--模式选择信号
            dat_in  : in std_logic_vector(7 downto 0);--系统时钟输入
            mcu_clk : in std_logic ;--单片机输出时钟信号
                ack : out std_logic;--输出搞定平,指示单片机可以发送数据
           datOutD : out std_logic_vector(15 downto 0)--数据从输出
              )
end entity;
architecture rtl of adder is
    signal temp:  std_logic_vector(7 downto 0);
    signal mtmp:  std_logic_vector(3 downto 0);
    subtype word is std_logic_vector(7 downto 0);
    type memory  is array(1 downto 0) of word;  --定义2个字节的内存
begin   
    ack<='1';--一开始就输出高电平,指示mcu可以发送数据
    temp<=dat_in; --读数据
    mtmp<= sec_modD & sec_modC & sec_modB & sec_modA;--读工作模式
N1:        process (mcu_clk,mtmp)
    variable i: integer range 0 to 1 :=0;
    variable REG8:  memory;--定义内存
    begin
    if(rising_edge(mcu_clk) ) then
                if(mtmp="0000" ) then
                  i:=0;
                  for n in 0 to 1 loop  --初始化内存
                   REG8(n):= "11111111";
                  end loop;
                elsif(mtmp="0001" ) then
                  REG8(i):=temp; --写内存
                  i:=i+1;
                elsif(mtmp="0010" ) then
                    datOutD<= REG8(0) & REG8(1);--将内存数据输出,以便检查内存数据是否正确
                   end if;       
     end if;
     end process;  
end rtl;

就是想通过单片机对CPLD内定义的2字节内存操作,波形仿真都对了,下载下去,单片机输出数据,CPLD根本就没有反应,高手们给点意见,我该如何去调试

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2011-4-8 18:37:33 | 显示全部楼层

(原文件名:1.GIF)

出0入0汤圆

 楼主| 发表于 2011-4-8 18:39:37 | 显示全部楼层
仿真正确了,当然管脚都已经配置过了,是否就说CPLD的程序是没有问题了,谁能给点意见,刚接触VHDL

出0入0汤圆

 楼主| 发表于 2011-4-8 18:58:18 | 显示全部楼层
路过的朋友,请发表下意见

出0入0汤圆

发表于 2011-4-8 19:08:38 | 显示全部楼层
你还在C语言的思想写VHDL,VHDL是描述硬件,有实时的特点,少用IF和FOR循环
程序的主要问题是在mcu_clk变化时,你那么多IF,CPLD做不了那么多事,不能捕捉到信号.

核心改动如下,你试试,另外你上位机控制信号mtmp应在mcu_clk跳变时处理好同步/异步的问题.

if(mtmp = "0000" ) then --初始化
  i:=0;
   REG8(1):= "11111111"; --初始化内存
   REG8(0):= "11111111"; --初始化内存
elsif(mtmp != "0000" ) then --非空运行
    if(rising_edge(mcu_clk) ) then   --上升沿时执行
        if(mtmp="0001" ) then        --mcu_clk上升沿同时mtmp="0001"时执行
            REG8(i):=temp; --写内存  --第一次将数据写入REG8(0),REG8(1)将在下一mcu_clk上升沿写入
            i:=i+1;                  --i+1
        elsif(mtmp="0010" ) then
            datOutD<= REG8(0) & REG8(1);--将内存数据输出,以便检查内存数据是否正确
        end if;
    end if;
end if;

出0入0汤圆

发表于 2011-4-8 19:21:59 | 显示全部楼层
优化如下:
if(rising_edge(mcu_clk) ) then
    case mtmp is
    when "0000" =>
        i:=0;  
        REG8(1):= "11111111"; --初始化内存  
        REG8(0):= "11111111"; --初始化内存
    when "0001" =>
        REG8(i):=temp; --第一次将数据写入REG8(0),REG8(1)将在下一mcu_clk上升沿写入
        i:=i+1;        --i+1
    when "0010" =>
        datOutD(15 downto 8)<= REG8(1);--将内存数据输出,以便检查内存数据是否正确
        datOutD(7 downto 0)<= REG8(0);--将内存数据输出,以便检查内存数据是否正确
    when others =>
        i := 0;
        REG8(1) := "XXXXXXXX";
        REG8(0) := "XXXXXXXX";
        datOutD := "XXXXXXXXXXXXXXXX";
    end case;
end if;

出0入0汤圆

发表于 2011-4-8 19:28:19 | 显示全部楼层
这行要执行的话 datOutD<= REG8(0) & REG8(1); mcu_clk,要有一个有变化不知你MCU有没有给 估计是MCU程序问题

出0入0汤圆

 楼主| 发表于 2011-4-8 19:35:06 | 显示全部楼层
谢谢,看了您的优化,写的真好,受益匪浅。谢谢

出0入0汤圆

 楼主| 发表于 2011-4-8 19:37:33 | 显示全部楼层
给了,我再仔细检查下,呵呵真失败,搞了好几天没有弄出来

出0入0汤圆

发表于 2011-4-8 19:41:31 | 显示全部楼层
失败很好,印象深刻,记的牢.

CPLD/FPGA不同于MCU,没有中断的概念,电路都是并行瞬间发生的,
复习复习课本前几章.

出0入0汤圆

 楼主| 发表于 2011-4-8 19:45:40 | 显示全部楼层
好的,受教了。

出0入0汤圆

发表于 2011-4-8 19:45:57 | 显示全部楼层
试试我这个简单的写程序,你要只是很能少字节传输。 基于寄存器和状态机变形 相当好用

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;   

ENTITY MCUPIORW IS
   PORT (

      REST,EN  :IN  std_logic;
      
      WCLK      :IN  std_logic;
   
     DATA_OUT        :OUT std_logic_vector(7 downto 0);  
      M_state        :IN std_logic_vector(7 downto 0);      
    DATA_IN ,abdata:IN std_logic_vector(15 downto 0));            
END MCUPIORW;


ARCHITECTURE EP2C5 OF MCUPIORW IS
TYPE state is (s0,s1,s2,s3,s4);
signal C_state  :state;
BEGIN
       
        PROCESS (WCLK,REST)
        BEGIN
        IF(REST='0')THEN
        C_state<=s0;
     DATA_OUT<= (OTHERS=>'1');   
        ELSIF WCLK = '1' AND WCLK 'EVENT THEN         
               IF(EN='1')THEN      
                                 IF (C_state=s0)THEN
                                 DATA_OUT <=DATA_IN(15 downto 8);  
                                 C_state<=s1;
                                 END IF;
                                 if (C_state=s1)THEN     
                                 DATA_OUT <= DATA_IN(7 downto 0);
                                 C_state<=s2;
                                 END IF;
                                  IF (C_state=s2)THEN
                                 DATA_OUT <=abdata(15 downto 8);  
                                 C_state<=s3;
                                 END IF;
                                 if (C_state=s3)THEN     
                                 DATA_OUT <= abdata(7 downto 0);
                                 C_state<=s4;
                                 END IF;
                                 if (C_state=s4)THEN     
                                  DATA_OUT<= M_state(7 downto 0);
                                 C_state<=s0;

                                 END IF;                
                        ELSE
                        DATA_OUT<= (OTHERS=>'1');        
                END IF;                
        END IF;
        END PROCESS;

END EP2C5;

出0入0汤圆

 楼主| 发表于 2011-4-8 19:48:55 | 显示全部楼层
好的,谢谢

出0入0汤圆

 楼主| 发表于 2011-4-8 20:13:03 | 显示全部楼层
试了,可以。呵呵谢谢,今天终于进步了

出0入0汤圆

发表于 2011-4-9 00:41:44 | 显示全部楼层
那一段程序可以用啊,分析下问题出在哪里也好举一反三,
才显得这个帖子有点价值啊。不然路过的都飘过了~

出0入0汤圆

 楼主| 发表于 2011-4-9 10:28:39 | 显示全部楼层
优化如下:
if(rising_edge(mcu_clk) ) then
    case mtmp is
    when "0000" =>
        i:=0;   
        REG8(1):= "11111111"; --初始化内存   
        REG8(0):= "11111111"; --初始化内存  
    when "0001" =>
        REG8(i):=temp; --第一次将数据写入REG8(0),REG8(1)将在下一mcu_clk上升沿写入  
        i:=i+1;        --i+1  
    when "0010" =>
        datOutD(15 downto 8)<= REG8(1);--将内存数据输出,以便检查内存数据是否正确  
        datOutD(7 downto 0)<= REG8(0);--将内存数据输出,以便检查内存数据是否正确  
    when others =>
        i := 0;
        REG8(1) := "XXXXXXXX";  
        REG8(0) := "XXXXXXXX";  
        datOutD := "XXXXXXXXXXXXXXXX";  
    end case;
end if; 这段程序可以用

出0入0汤圆

 楼主| 发表于 2011-4-9 11:07:00 | 显示全部楼层
串行语句 if语句和case语句的区别,我写了个测试程序
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity adder is
        port
    (
         sec : in std_logic_vector(1 downto 0);
         Dout: out std_logic_vector(1 downto 0)
      
        );
end entity;
architecture rtl of adder is
signal temp : std_logic_vector ( 1 DOWNTO 0 );
begin   
  temp<= sec;
N1:        process (temp)
    begin
        if(temp="11") then Dout<="11";
    elsif (temp="10") then Dout<="10";
    elsif (temp="01") then Dout<="01";
    else   Dout<="00";
    end if;
    end process;  
end rtl;

--N1:        process (temp)
--    begin
--    case temp is
--    when "11" => Dout<="11";
--    when "10" => Dout<="10";
--    when "01" => Dout<="01";
--    when others => Dout<="00";
--    end case;
--    end process;  
--end rtl;


RTL图是用if语句写的 (原文件名:1.GIF)


RTL图是用case语句写 (原文件名:2.GIF)

出0入0汤圆

 楼主| 发表于 2011-4-9 11:17:00 | 显示全部楼层
怎么会有如此大的区别??

出0入0汤圆

发表于 2011-4-9 11:21:17 | 显示全部楼层
这是编译优化的结果:
if有分支判断,于是电路复杂了点;根据IF镶套的优先级来看.
CASE分支判断,你没有判断,所以直连了;
所以你要少用IF,多用CASE,尽量把所有的情况都写到分支中.

出0入0汤圆

 楼主| 发表于 2011-4-9 11:30:06 | 显示全部楼层
再请问个问题,进程里的顺序语句在仿真时是有明显的顺序性,但是下载到硬件里后是如何执行的?看了书不是很理解,书上好像就说是执行到end process时再过δ时间去执行;

出0入0汤圆

发表于 2011-4-9 11:40:04 | 显示全部楼层
所有process的顺序语句都是并行执行的,只有IF等判断语句的分支会按照优先级顺序执行下去;
而不管是CASE还是IF,分支判断语句内的顺序语句都是并行执行的.
比如
以下在CLK上升沿时分别判断A或B,并行执行,无关联;
process (clk,A,B)
if(rising_edge(clk) ) then  
IF A = '1' THEN
...
END IF;

IF B = '1' THEN
...
END IF;
end if
END process;

以下在CLK上升沿时分别先判断A再判断B,顺序执行,A比B快;
process (clk,A,B)
if(rising_edge(clk) ) then  
IF A = '1' THEN
...
ELSIF B = '1' THEN
X <= '0';   ---这里X,Y是同时赋值的.
Y <= '1';
END IF;
end if
END process;

出0入0汤圆

发表于 2011-4-9 11:41:50 | 显示全部楼层
进程不是函数,你可以看作一个确实存在的硬件,收到指令就指定的部件.

出0入0汤圆

 楼主| 发表于 2011-4-9 12:14:26 | 显示全部楼层
谢谢,那假如进程里if... elsif.... elsif...else end if;很多个;那么进程结束了,会不会导致判断来不及??

出0入0汤圆

发表于 2011-4-9 12:40:19 | 显示全部楼层
学习了

出0入0汤圆

发表于 2011-4-9 13:32:32 | 显示全部楼层
这要看跳变沿的速度,如果if语句的分支很多,每个分支等同于触发器或逻辑,那么累积的物理延迟不能超过CLK的周期的1/2(这样说不准确,或者说CLK跳变沿时,你的其他变量不能变化(或中间状态),不然仿真OK,扳子干活时跑飞(语句正确,但时序不达标).考虑到这种情况,应该转用case语句;尽量将If语句中的各种功能拆成小进程,信号偶合多的组合一个进程,并行运行关系不紧密的功能分开.

出0入0汤圆

发表于 2011-4-9 14:59:29 | 显示全部楼层
hawkflyking 牛人呵呵还是个好人

出0入0汤圆

发表于 2011-4-9 15:23:40 | 显示全部楼层
回复【25楼】jinhancn
-----------------------------------------------------------------------

我是菜鸟一只,潜水日久手痒.

出0入0汤圆

发表于 2011-4-9 16:09:03 | 显示全部楼层
少用锁存器.
多用IF ,少用CASE -WHEN   哈 ^^^^
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 15:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表