美文网首页
八周造个CPU(?):LED秒表实验

八周造个CPU(?):LED秒表实验

作者: 张慕晖 | 来源:发表于2017-12-15 15:38 被阅读77次

    板子

    照片

    image.png

    检查设备状态

    其实根本就没有检查,总之插上就可以访问控制页面了。(我有一个USB接口坏了,所以之前访问不了)


    image.png

    实验指导书对应

    • 手动时钟 → touch_btn[4]
    • RST →touch_btn[5]
    • 50M CLK→clk_in
    • L[n] → leds[15:0]
    • DPY0 →leds[23:16],DPY1 →leds[31:24]
    • SW[n] → dip_sw[n]
    • RAM1 → base_ram
    • RAM2 → ext_ram

    用LED显示秒表

    程序

    Timer的程序是从实验指导书上抄的,做了一点改动,因为板子上的rst按下时为'1'。但是,诡异的是,实际效果是按下rst时秒表计数暂停,而非置0。

    clock.vhd

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;
    
    entity clock is
        Port ( clk : in STD_LOGIC;
               rst : in STD_LOGIC;
               seg1 : out UNSIGNED (6 downto 0);
               seg2 : out UNSIGNED (6 downto 0));
    end clock;
    
    architecture Behavioral of clock is
        signal clk_out: STD_LOGIC := '0';
        signal cnt: UNSIGNED(25 downto 0) := "00000000000000000000000000";
        signal cnt_H: UNSIGNED(3 downto 0) := "0000";
        signal cnt_L: UNSIGNED(3 downto 0) := "0000";
    begin
    
        -- 时钟分频,产生1HZ时钟信号clk_out
        process(clk)
        begin
            if rising_edge(clk) then
                cnt <= cnt + "1";
                if cnt = "00000000000000000000000000" then
                    clk_out <= '0';
                end if;
                if cnt = "10111110101111000010000000" then
                    cnt <= "00000000000000000000000000";
                    clk_out <= '1';
                end if;
            end if;
        end process;
    
        -- 秒表计数,分别产生十位和个位
        process(clk_out, rst)
            variable tmp_L, tmp_H: UNSIGNED(3 downto 0) := "0000";
        begin
            if rst = '1' then
                cnt_H <= "0000";
                cnt_L <= "0000";
            else
                if rising_edge(clk_out) then
                    tmp_L := cnt_L + "1";
                    if tmp_L > "1001" then
                        tmp_L := "0000";
                        tmp_H := cnt_H + "1";
                        if tmp_H > "1001" then
                            tmp_H := "0000";
                        end if;
                    end if;
                end if;
            end if;
            cnt_L <= tmp_L;
            cnt_H <= tmp_H;
        end process;
        
        -- 个位译码到七段数码管显示
        process(cnt_L)
        begin
            case cnt_L is
                when "0000" => 
                    seg1 <= not "1000000";
                when "0001" => 
                    seg1 <= not "1111001";
                when "0010" => 
                    seg1 <= not "0100100";
                when "0011" => 
                    seg1 <= not "0110000";
                when "0100" => 
                    seg1 <= not "0011001";
                when "0101" => 
                    seg1 <= not "0010010";
                when "0110" => 
                    seg1 <= not "0000010";
                when "0111" => 
                    seg1 <= not "1111000";
                when "1000" => 
                    seg1 <= not "0000000";
                when "1001" => 
                    seg1 <= not "0010000";
                when others => 
                    seg1 <= not "1111111";
            end case;
        end process;
        
        -- 十位译码到七段数码管显示
        process(cnt_H)
        begin
            case cnt_H is
                when "0000" => 
                    seg2 <= not "1000000";
                when "0001" => 
                    seg2 <= not "1111001";
                when "0010" => 
                    seg2 <= not "0100100";
                when "0011" => 
                    seg2 <= not "0110000";
                when "0100" => 
                    seg2 <= not "0011001";
                when "0101" => 
                    seg2 <= not "0010010";
                when "0110" => 
                    seg2 <= not "0000010";
                when "0111" => 
                    seg2 <= not "1111000";
                when "1000" => 
                    seg2 <= not "0000000";
                when "1001" => 
                    seg2 <= not "0010000";
                when others => 
                    seg2 <= not "1111111";
            end case;
        end process;
        
    end Behavioral;
    

    test_bench.v

    相比实验指导书上做了一点改动。(显然,从vhdl改到了verilog)

    `timescale 1ns / 1ns
    module Timer_testbench();
    
        reg CLOCK_50;
        reg rst;
        wire[6:0] seg1;
        wire[6:0] seg2;
        
        // The CLOCK flips every 10 ns, so the frequency is 50MHZ
        initial begin
            CLOCK_50 = 1'b0;
            forever #10 CLOCK_50 = ~CLOCK_50;
        end 
        
        initial begin
            rst = 1'b1;
            #1000 rst = 1'b0;
        end
        
        clock clock0(
            .clk(CLOCK_50),
            .rst(rst),
            .seg1(seg1),
            .seg2(seg2)
        );
        
    endmodule
    

    clock.xdc

    set_property PACKAGE_PIN D18 [get_ports clk]
    set_property IOSTANDARD LVCMOS33 [get_ports clk]
    set_property PACKAGE_PIN H19 [get_ports rst]
    set_property IOSTANDARD LVCMOS33 [get_ports rst]
    
    set_property PACKAGE_PIN H14 [get_ports {seg1[0]}]
    set_property PACKAGE_PIN H16 [get_ports {seg1[1]}]
    set_property PACKAGE_PIN F15 [get_ports {seg1[2]}]
    set_property PACKAGE_PIN H15 [get_ports {seg1[3]}]
    set_property PACKAGE_PIN G15 [get_ports {seg1[4]}]
    set_property PACKAGE_PIN G19 [get_ports {seg1[5]}]
    set_property PACKAGE_PIN J8 [get_ports {seg1[6]}]
    
    set_property PACKAGE_PIN E5 [get_ports {seg2[0]}]
    set_property PACKAGE_PIN D6 [get_ports {seg2[1]}]
    set_property PACKAGE_PIN G8 [get_ports {seg2[2]}]
    set_property PACKAGE_PIN G7 [get_ports {seg2[3]}]
    set_property PACKAGE_PIN G6 [get_ports {seg2[4]}]
    set_property PACKAGE_PIN F4 [get_ports {seg2[5]}]
    set_property PACKAGE_PIN G5 [get_ports {seg2[6]}]
    
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[0]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[1]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[2]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[3]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[4]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[5]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg1[6]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[0]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[1]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[2]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[3]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[4]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[5]}]
    set_property IOSTANDARD LVCMOS33 [get_ports {seg2[6]}]
    

    Debug

    模拟仿真

    Vivado自带的仿真恐怕很辣鸡,跑了一分多钟才跑1s,简直是浪费人生。当然,平时的时域肯定比1s要小得多……

    8位数码管的端口映射

    调LED显示调到怀疑人生!

    32位的示例工程约束文件(.xdc)里是这么写的:

    #DPY0
    set_property PACKAGE_PIN D16 [get_ports {leds[16]}]
    set_property PACKAGE_PIN F15 [get_ports {leds[17]}]
    set_property PACKAGE_PIN H15 [get_ports {leds[18]}]
    set_property PACKAGE_PIN G15 [get_ports {leds[19]}]
    set_property PACKAGE_PIN H16 [get_ports {leds[20]}]
    set_property PACKAGE_PIN H14 [get_ports {leds[21]}]
    set_property PACKAGE_PIN G19 [get_ports {leds[22]}]
    set_property PACKAGE_PIN J8 [get_ports {leds[23]}]
    
    #DPY2
    set_property PACKAGE_PIN H9 [get_ports {leds[24]}]
    set_property PACKAGE_PIN G8 [get_ports {leds[25]}]
    set_property PACKAGE_PIN G7 [get_ports {leds[26]}]
    set_property PACKAGE_PIN G6 [get_ports {leds[27]}]
    set_property PACKAGE_PIN D6 [get_ports {leds[28]}]
    set_property PACKAGE_PIN E5 [get_ports {leds[29]}]
    set_property PACKAGE_PIN F4 [get_ports {leds[30]}]
    set_property PACKAGE_PIN G5 [get_ports {leds[31]}]
    

    所以此时的问题是,怎么把这些和8段数码管对上?好吧,8段数码管是有一套标准的映射的——(以下1表示亮,0表示暗,当然这取决于用的是什么类型的数码管了……)

    数字 输出到数码管的vector
    0 1000000
    1 1111001
    2 0100100
    3 0110000
    4 0011001
    5 0010010
    6 0000010
    7 1111000
    8 0000000
    9 0010000

    其中对(7段)数码管的默认标号大概长这样:

    -----6-----
    |         |
    1         5
    |         |
    -----0-----
    |         |
    2         4
    |         |
    -----3-----
    

    所以leds数组的编号和这个默认编号有什么关系呢?试了一圈,答案是根本没有!!(当然,也可能是他遵守了什么很高级的规定,但我根本没有理解。)

    最后试出来的约束文件长这样:

    # 右边的数码管
    set_property PACKAGE_PIN H14 [get_ports {seg1[0]}]
    set_property PACKAGE_PIN H16 [get_ports {seg1[1]}]
    set_property PACKAGE_PIN F15 [get_ports {seg1[2]}]
    set_property PACKAGE_PIN H15 [get_ports {seg1[3]}]
    set_property PACKAGE_PIN G15 [get_ports {seg1[4]}]
    set_property PACKAGE_PIN G19 [get_ports {seg1[5]}]
    set_property PACKAGE_PIN J8 [get_ports {seg1[6]}]
    # D16应该对应小数点,但我大概用不到
    
    # 左边的数码管
    set_property PACKAGE_PIN E5 [get_ports {seg2[0]}]
    set_property PACKAGE_PIN D6 [get_ports {seg2[1]}]
    set_property PACKAGE_PIN G8 [get_ports {seg2[2]}]
    set_property PACKAGE_PIN G7 [get_ports {seg2[3]}]
    set_property PACKAGE_PIN G6 [get_ports {seg2[4]}]
    set_property PACKAGE_PIN F4 [get_ports {seg2[5]}]
    set_property PACKAGE_PIN G5 [get_ports {seg2[6]}]
    # H9应该对应小数点,但我大概用不到
    

    说起来,这个芯片的管脚分配也挺乱的,不知道是按照什么原则分配的。

    在图形界面里一个个点着设端口映射的时候就很有安全感,比自己狂敲代码舒服一些。

    现在Vivado编译到Bit Stream大概需要2分钟,不知道CPU要编译多久。

    照片

    秒表的效果

    最后默默把博客链接放到这里……http://ilovestudy.wikidot.com/cpu-in-8-weeks-0

    相关文章

      网友评论

          本文标题:八周造个CPU(?):LED秒表实验

          本文链接:https://www.haomeiwen.com/subject/xgqfbxtx.html