From 9756b655b6ed7f616b82a5463936f95d588ac1a4 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Sat, 12 Nov 2022 20:17:56 +0100 Subject: [PATCH] Add seven-segments module and integrate it into the top level --- soc/lib/config.vhd | 3 + soc/peripheral/hex2physical.vhd | 42 +++++++ soc/peripheral/peripherals.vhd | 16 +++ soc/peripheral/seven_segment_display.vhd | 137 +++++++++++++++++++++++ soc/peripheral/simple_timer.vhd | 43 +++++++ soc/testbench/hex2physical_tb.vhd | 88 +++++++++++++++ soc/testbench/segment_tb.vhd | 78 +++++++++++++ soc/testbench/simple_timer_tb.vhd | 58 ++++++++++ soc/top/top.vhd | 24 +++- soc/top/top.xdc | 10 +- 10 files changed, 491 insertions(+), 8 deletions(-) create mode 100644 soc/peripheral/hex2physical.vhd create mode 100644 soc/peripheral/seven_segment_display.vhd create mode 100644 soc/peripheral/simple_timer.vhd create mode 100644 soc/testbench/hex2physical_tb.vhd create mode 100644 soc/testbench/segment_tb.vhd create mode 100644 soc/testbench/simple_timer_tb.vhd diff --git a/soc/lib/config.vhd b/soc/lib/config.vhd index 1ecfe86..2abe033 100644 --- a/soc/lib/config.vhd +++ b/soc/lib/config.vhd @@ -29,6 +29,7 @@ package config is constant CFG_LED : integer := CFG_DMEM+1; constant CFG_SW : integer := CFG_LED+1; constant CFG_TIMER : integer := CFG_SW+1; + constant CFG_SEG : integer := CFG_TIMER+1; ----------------------------- -- base address (BADR) & mask address (MADR) @@ -40,6 +41,7 @@ package config is constant CFG_BADR_LED : generic_addr_type := 16#000F0000#; constant CFG_BADR_SW : generic_addr_type := 16#000F0004#; constant CFG_BADR_TIMER : generic_addr_type := 16#000F0008#; + constant CFG_BADR_SEG : generic_addr_type := 16#000F00A0#; -- mask addr constant CFG_MADR_ZERO : generic_mask_type := 0; @@ -49,6 +51,7 @@ package config is constant CFG_MADR_LED : generic_mask_type := 16#3FFFFF#; -- size=1 byte constant CFG_MADR_SW : generic_mask_type := 16#3FFFFF# - (4 - 1); -- size=4 byte constant CFG_MADR_TIMER : generic_mask_type := 16#3FFFFF# - (8 - 1); -- size=8 byte (2 words) + constant CFG_MADR_SEG : generic_mask_type := 16#3FFFFF# - (8 - 1); -- size=8 byte (2 words) end package config; diff --git a/soc/peripheral/hex2physical.vhd b/soc/peripheral/hex2physical.vhd new file mode 100644 index 0000000..6c622a1 --- /dev/null +++ b/soc/peripheral/hex2physical.vhd @@ -0,0 +1,42 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; +use work.config.all; + +entity hex2physical is + port( + hex : in std_logic_vector(4 downto 0); + cathodes : out std_logic_vector(7 downto 0) + ); +end hex2physical; + +architecture Behavioral of hex2physical is +begin + + process(hex) + begin + case hex is + when "00000" => cathodes <= "10000001"; -- "0" + when "00001" => cathodes <= "11110011"; -- "1" + when "00010" => cathodes <= "01001001"; -- "2" + when "00011" => cathodes <= "01100001"; -- "3" + when "00100" => cathodes <= "00110011"; -- "4" + when "00101" => cathodes <= "00100101"; -- "5" + when "00110" => cathodes <= "00000101"; -- "6" + when "00111" => cathodes <= "11110001"; -- "7" + when "01000" => cathodes <= "00000001"; -- "8" + when "01001" => cathodes <= "00100001"; -- "9" + when "01010" => cathodes <= "00010001"; -- "A" + when "01011" => cathodes <= "00000111"; -- "B" + when "01100" => cathodes <= "10001101"; -- "C" + when "01101" => cathodes <= "01000011"; -- "D" + when "01110" => cathodes <= "00001101"; -- "E" + when "01111" => cathodes <= "00011101"; -- "F" + when others => cathodes <= "11111111"; -- "Off" + end case; + end process; + +end Behavioral; diff --git a/soc/peripheral/peripherals.vhd b/soc/peripheral/peripherals.vhd index 4b0e185..e5cd15d 100644 --- a/soc/peripheral/peripherals.vhd +++ b/soc/peripheral/peripherals.vhd @@ -57,6 +57,22 @@ package lt16soc_peripherals is ); end component; + component wb_segment is + generic( + memaddr : generic_addr_type; --:= CFG_BADR_SEG; + addrmask : generic_mask_type --:= CFG_BADR_SEG; + ); + port( + clk : in std_logic; + rst : in std_logic; + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type; + + anodes : out std_logic_vector(7 downto 0); + cathodes : out std_logic_vector(7 downto 0) + ); + end component; + end lt16soc_peripherals; package body lt16soc_peripherals is diff --git a/soc/peripheral/seven_segment_display.vhd b/soc/peripheral/seven_segment_display.vhd new file mode 100644 index 0000000..b10a9bb --- /dev/null +++ b/soc/peripheral/seven_segment_display.vhd @@ -0,0 +1,137 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +entity wb_segment is + generic( + memaddr : generic_addr_type; --:= CFG_BADR_SEG; + addrmask : generic_mask_type --:= CFG_MADR_SEG; + ); + port( + clk : in std_logic; + rst : in std_logic; + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type; + + anodes : out std_logic_vector(7 downto 0); + cathodes : out std_logic_vector(7 downto 0) + ); +end wb_segment; + +architecture Behavioral of wb_segment is + + signal ack : std_logic; + + signal hex_register : std_logic_vector(63 downto 0); + signal data_out : std_logic_vector(63 downto 0); + + signal hex : std_logic_vector(4 downto 0); + + signal timer_overflow : std_logic; + signal overflow_counter : integer range 0 to 7; + + component hex2physical + port( + hex : in std_logic_vector(4 downto 0); + cathodes : out std_logic_vector(7 downto 0) + ); + end component; + + component simple_timer + generic( + timer_start : std_logic_vector (31 downto 0) + ); + port( + clk : in std_logic; + rst : in std_logic; + timer_overflow : out std_logic + ); + end component; + +begin + + converter : hex2physical + port map( + hex => hex, + cathodes => cathodes + ); + + timer: simple_timer + generic map (timer_start => x"00000008") + port map( + clk => clk, + rst => rst, + timer_overflow => timer_overflow + ); + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + ack <= '0'; + data_out <= (others=>'0'); + hex_register <= (others=>'0'); + else + data_out <= (others=>'0'); + + if wslvi.stb = '1' and wslvi.cyc = '1' then + if wslvi.we='0' then + data_out <= hex_register; + else + -- Write enable + if wslvi.adr(2) = '0' then + hex_register(31 downto 0) <= dec_wb_dat(wslvi.sel,wslvi.dat); + else -- wslvi.adr(2) = '1' + hex_register(63 downto 32) <= dec_wb_dat(wslvi.sel,wslvi.dat); + end if; + end if; + + if ack = '0' then + ack <= '1'; + else + ack <= '0'; + end if; + else + ack <= '0'; + end if; + end if; + end if; + end process; + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + hex <= hex_register(4 downto 0); + anodes <= (others => '0'); + overflow_counter <= 0; + else + if timer_overflow = '1' then + if overflow_counter = 7 then + overflow_counter <= 0; + else + overflow_counter <= overflow_counter + 1; + end if; + + anodes <= (others => '0'); + anodes(overflow_counter) <= '1'; + + hex <= hex_register(overflow_counter * 8 + 4 downto overflow_counter * 8); + end if; + end if; + end if; + end process; + + wslvo.dat <= + data_out(31 downto 0) when wslvi.adr(2) = '0' else + data_out(63 downto 32) when wslvi.adr(2) = '1'; + + wslvo.ack <= ack; + wslvo.wbcfg <= wb_membar(memaddr, addrmask); + +end Behavioral; diff --git a/soc/peripheral/simple_timer.vhd b/soc/peripheral/simple_timer.vhd new file mode 100644 index 0000000..c81c8d4 --- /dev/null +++ b/soc/peripheral/simple_timer.vhd @@ -0,0 +1,43 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity simple_timer is + generic( + timer_start : std_logic_vector (31 downto 0) + ); + port( + clk : in std_logic; + rst : in std_logic; + timer_overflow : out std_logic + ); +end entity simple_timer; + +architecture Behavioral of simple_timer is + + signal counter : integer range 1 to to_integer(unsigned(timer_start)); + signal overflow : std_logic; + +begin + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + counter <= to_integer(unsigned(timer_start)); + else + overflow <= '0'; + + if counter = 1 then + counter <= to_integer(unsigned(timer_start)); + overflow <= '1'; + else + counter <= counter - 1; + end if; + end if; + end if; + end process; + + timer_overflow <= overflow; + +end Behavioral; diff --git a/soc/testbench/hex2physical_tb.vhd b/soc/testbench/hex2physical_tb.vhd new file mode 100644 index 0000000..86cad84 --- /dev/null +++ b/soc/testbench/hex2physical_tb.vhd @@ -0,0 +1,88 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +LIBRARY work; +USE work.lt16soc_peripherals.ALL; + +ENTITY hex2physical_tb IS +END ENTITY; + +ARCHITECTURE sim OF hex2physical_tb IS + + signal hex : std_logic_vector(4 downto 0) := "00000"; + signal cathodes : std_logic_vector(7 downto 0); + + component hex2physical + port( + hex : in std_logic_vector(4 downto 0); + cathodes : out std_logic_vector(7 downto 0) + ); + end component; + +BEGIN + + converter: hex2physical + port map( + hex => hex, + cathodes => cathodes + ); + + stimuli: process + begin + hex <= "00000"; + wait for 2 ns; + + hex <= "00001"; + wait for 2 ns; + + hex <= "00010"; + wait for 2 ns; + + hex <= "00011"; + wait for 2 ns; + + hex <= "00100"; + wait for 2 ns; + + hex <= "00101"; + wait for 2 ns; + + hex <= "00110"; + wait for 2 ns; + + hex <= "00111"; + wait for 2 ns; + + hex <= "01000"; + wait for 2 ns; + + hex <= "01001"; + wait for 2 ns; + + hex <= "01010"; + wait for 2 ns; + + hex <= "01011"; + wait for 2 ns; + + hex <= "01100"; + wait for 2 ns; + + hex <= "01101"; + wait for 2 ns; + + hex <= "01110"; + wait for 2 ns; + + hex <= "01111"; + wait for 2 ns; + + hex <= "10000"; + wait for 2 ns; + + assert false report "Simulation terminated!" severity failure; + end process stimuli; + +END ARCHITECTURE; diff --git a/soc/testbench/segment_tb.vhd b/soc/testbench/segment_tb.vhd new file mode 100644 index 0000000..11c36eb --- /dev/null +++ b/soc/testbench/segment_tb.vhd @@ -0,0 +1,78 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +LIBRARY work; +USE work.lt16soc_peripherals.ALL; +USE work.wishbone.ALL; +USE work.wb_tp.ALL; +USE work.config.ALL; + +ENTITY segment_tb IS +END ENTITY; + +ARCHITECTURE sim OF segment_tb IS + + constant CLK_PERIOD : time := 10 ns; + + signal clk : std_logic := '0'; + signal rst : std_logic; + signal data : std_logic_vector(31 downto 0); + + signal anodes : std_logic_vector(7 downto 0); + signal cathodes : std_logic_vector(7 downto 0); + + signal slvi : wb_slv_in_type; + signal slvo : wb_slv_out_type; + +BEGIN + + SIM_SLV: wb_segment + generic map( + memaddr => CFG_BADR_SEG, + addrmask => CFG_MADR_SEG + ) + port map( + clk => clk, + rst => rst, + wslvi => slvi, + wslvo => slvo, + + anodes => anodes, + cathodes => cathodes + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '1'; + wait for CLK_PERIOD; + rst <= '0'; + + data <= (others => '0'); + data(7 downto 0) <= "000" & "0" & x"A"; -- Unused & !Enable & Value + data(15 downto 8) <= "000" & "0" & x"B"; -- Unused & !Enable & Value + data(23 downto 16) <= "000" & "0" & x"C"; -- Unused & !Enable & Value + data(31 downto 24) <= "000" & "0" & x"D"; -- Unused & !Enable & Value + generate_sync_wb_single_write(slvi,slvo,clk,data); + + wait for 10 ns; + data <= (others => '0'); + data(7 downto 0) <= "000" & "0" & x"E"; -- Unused & !Enable & Value + data(15 downto 8) <= "000" & "0" & x"F"; -- Unused & !Enable & Value + data(23 downto 16) <= "000" & "0" & x"0"; -- Unused & !Enable & Value + data(31 downto 24) <= "000" & "0" & x"1"; -- Unused & !Enable & Value + generate_sync_wb_single_write(slvi,slvo,clk,data, ADR_OFFSET => 4); + + wait for 10 us; + + assert false report "Simulation terminated!" severity failure; + end process stimuli; + +END ARCHITECTURE; diff --git a/soc/testbench/simple_timer_tb.vhd b/soc/testbench/simple_timer_tb.vhd new file mode 100644 index 0000000..1d1abf8 --- /dev/null +++ b/soc/testbench/simple_timer_tb.vhd @@ -0,0 +1,58 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +LIBRARY work; +USE work.lt16soc_peripherals.ALL; + +ENTITY simple_timer_tb IS +END ENTITY; + +ARCHITECTURE sim OF simple_timer_tb IS + + constant CLK_PERIOD : time := 10 ns; + + signal rst : std_logic; + signal clk : std_logic := '0'; + signal overflow : std_logic; + + component simple_timer + generic( + timer_start : std_logic_vector (31 downto 0) + ); + port( + clk : in std_logic; + rst : in std_logic; + timer_overflow : out std_logic + ); + end component; + +BEGIN + + timer: simple_timer + generic map (timer_start => x"0000001F") + port map( + clk => clk, + rst => rst, + timer_overflow => overflow + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '1'; + wait for CLK_PERIOD; + rst <= '0'; + + wait for 5 us; + + assert false report "Simulation terminated!" severity failure; + end process stimuli; + +END ARCHITECTURE; diff --git a/soc/top/top.vhd b/soc/top/top.vhd index 09a5540..51852a3 100644 --- a/soc/top/top.vhd +++ b/soc/top/top.vhd @@ -14,7 +14,7 @@ use work.lt16soc_peripherals.all; entity lt16soc_top is generic( - programfilename : string := "../../programs/blinky.ram" -- see "Synthesize XST" process properties for actual value ("-generics" in .xst file)! + programfilename : string := "../../programs/timer_blinky.ram" -- see "Synthesize XST" process properties for actual value ("-generics" in .xst file)! ); port( -- clock signal @@ -25,7 +25,10 @@ port( led : out std_logic_vector(7 downto 0); btn : in std_logic_vector(4 downto 0); - sw : in std_logic_vector(15 downto 0) + sw : in std_logic_vector(15 downto 0); + + anodes : out std_logic_vector(7 downto 0); + cathodes : out std_logic_vector(7 downto 0) ); end entity lt16soc_top; @@ -37,7 +40,7 @@ architecture RTL of lt16soc_top is signal rst_gen : std_logic; - constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1111_1000_0000_0001"; + constant slv_mask_vector : std_logic_vector(0 to NWBSLV-1) := b"1111_1100_0000_0001"; constant mst_mask_vector : std_logic_vector(0 to NWBMST-1) := b"1000"; signal slvo : wb_slv_out_vector := (others=> wbs_out_none); @@ -200,5 +203,20 @@ begin port map( clk,rst_gen,slvi(CFG_TIMER),slvo(CFG_TIMER), irq_lines(3) ); + + segmentdev : wb_segment + generic map( + memaddr => CFG_BADR_SEG, + addrmask => CFG_MADR_SEG + ) + port map( + clk => clk, + rst => rst, + wslvi => slvi(CFG_SEG), + wslvo => slvo(CFG_SEG), + + anodes => anodes, + cathodes => cathodes + ); end architecture RTL; diff --git a/soc/top/top.xdc b/soc/top/top.xdc index ba81323..5db47d8 100644 --- a/soc/top/top.xdc +++ b/soc/top/top.xdc @@ -72,11 +72,11 @@ set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] ##Buttons set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { rst }]; #IO_L3P_T0_DQS_AD1P_15 Sch=cpu_resetn -set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { BTNC }]; #IO_L9P_T1_DQS_14 Sch=btnc -set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { BTNU }]; #IO_L4N_T0_D05_14 Sch=btnu -set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { BTNL }]; #IO_L12P_T1_MRCC_14 Sch=btnl -set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { BTNR }]; #IO_L10N_T1_D15_14 Sch=btnr -set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { BTND }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd +set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]; #IO_L9P_T1_DQS_14 Sch=btnc +set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]; #IO_L4N_T0_D05_14 Sch=btnu +set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L12P_T1_MRCC_14 Sch=btnl +set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L10N_T1_D15_14 Sch=btnr +set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btn[4] }]; #IO_L9N_T1_DQS_D13_14 Sch=btnd ##Pmod Headers