whj19860123 发表于 2011-4-8 18:34:52

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

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 memoryis 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根本就没有反应,高手们给点意见,我该如何去调试

whj19860123 发表于 2011-4-8 18:37:33

http://cache.amobbs.com/bbs_upload782111/files_38/ourdev_629324SARIJ7.GIF
(原文件名:1.GIF)

whj19860123 发表于 2011-4-8 18:39:37

仿真正确了,当然管脚都已经配置过了,是否就说CPLD的程序是没有问题了,谁能给点意见,刚接触VHDL

whj19860123 发表于 2011-4-8 18:58:18

路过的朋友,请发表下意见

hawkflyking 发表于 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;

hawkflyking 发表于 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;

40130064 发表于 2011-4-8 19:28:19

这行要执行的话 datOutD<= REG8(0) & REG8(1); mcu_clk,要有一个有变化不知你MCU有没有给 估计是MCU程序问题

whj19860123 发表于 2011-4-8 19:35:06

谢谢,看了您的优化,写的真好,受益匪浅。谢谢

whj19860123 发表于 2011-4-8 19:37:33

给了,我再仔细检查下,呵呵真失败,搞了好几天没有弄出来

hawkflyking 发表于 2011-4-8 19:41:31

失败很好,印象深刻,记的牢.

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

whj19860123 发表于 2011-4-8 19:45:40

好的,受教了。

40130064 发表于 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:INstd_logic;
      
      WCLK      :INstd_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;

whj19860123 发表于 2011-4-8 19:48:55

好的,谢谢

whj19860123 发表于 2011-4-8 20:13:03

试了,可以。呵呵谢谢,今天终于进步了

hawkflyking 发表于 2011-4-9 00:41:44

那一段程序可以用啊,分析下问题出在哪里也好举一反三,
才显得这个帖子有点价值啊。不然路过的都飘过了~

whj19860123 发表于 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; 这段程序可以用

whj19860123 发表于 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;

http://cache.amobbs.com/bbs_upload782111/files_38/ourdev_629512L1MFAX.GIF
RTL图是用if语句写的 (原文件名:1.GIF)

http://cache.amobbs.com/bbs_upload782111/files_38/ourdev_629513UR3QU6.GIF
RTL图是用case语句写 (原文件名:2.GIF)

whj19860123 发表于 2011-4-9 11:17:00

怎么会有如此大的区别??

hawkflyking 发表于 2011-4-9 11:21:17

这是编译优化的结果:
if有分支判断,于是电路复杂了点;根据IF镶套的优先级来看.
CASE分支判断,你没有判断,所以直连了;
所以你要少用IF,多用CASE,尽量把所有的情况都写到分支中.

whj19860123 发表于 2011-4-9 11:30:06

再请问个问题,进程里的顺序语句在仿真时是有明显的顺序性,但是下载到硬件里后是如何执行的?看了书不是很理解,书上好像就说是执行到end process时再过δ时间去执行;

hawkflyking 发表于 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;

hawkflyking 发表于 2011-4-9 11:41:50

进程不是函数,你可以看作一个确实存在的硬件,收到指令就指定的部件.

whj19860123 发表于 2011-4-9 12:14:26

谢谢,那假如进程里if... elsif.... elsif...else end if;很多个;那么进程结束了,会不会导致判断来不及??

jinhancn 发表于 2011-4-9 12:40:19

学习了

hawkflyking 发表于 2011-4-9 13:32:32

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

jinhancn 发表于 2011-4-9 14:59:29

hawkflyking 牛人呵呵还是个好人

hawkflyking 发表于 2011-4-9 15:23:40

回复【25楼】jinhancn
-----------------------------------------------------------------------

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

40130064 发表于 2011-4-9 16:09:03

少用锁存器.
多用IF ,少用CASE -WHEN   哈 ^^^^
页: [1]
查看完整版本: 高手们看下我这段VHDL程序哪里还有问题