板子
照片
检查设备状态
其实根本就没有检查,总之插上就可以访问控制页面了。(我有一个USB接口坏了,所以之前访问不了)
实验指导书对应
• 手动时钟 → 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