From c94765003fa1ec1e3b12b1d50e2de4dc6e2e6d0e Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Wed, 20 Feb 2019 17:44:15 +0100 Subject: [PATCH] Initial commit --- .gitmodules | 3 + .library_mapping.xml | 9 + .project | 45 ++++ .settings/com.sigasi.hdt.vhdl.version.prefs | 1 + .settings/org.eclipse.core.resources.prefs | 5 + bench/bench_top.vhd | 105 ++++++++ bench_top.gtkw | 80 +++++++ design/edgeDetector.vhd | 41 ++++ design/ram.vhd | 36 +++ design/synchronizer.vhd | 31 +++ design/top.vhd | 252 ++++++++++++++++++++ design/top_pkg.vhd | 6 + design/uart_rx.vhd | 161 +++++++++++++ design/uart_tx.vhd | 110 +++++++++ diamond/ws2812wall.ldf | 35 +++ diamond/ws2812wall.lpf | 2 + ws2812b-vhdl | 1 + 17 files changed, 923 insertions(+) create mode 100644 .gitmodules create mode 100644 .library_mapping.xml create mode 100644 .project create mode 100644 .settings/com.sigasi.hdt.vhdl.version.prefs create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 bench/bench_top.vhd create mode 100644 bench_top.gtkw create mode 100644 design/edgeDetector.vhd create mode 100644 design/ram.vhd create mode 100644 design/synchronizer.vhd create mode 100644 design/top.vhd create mode 100644 design/top_pkg.vhd create mode 100644 design/uart_rx.vhd create mode 100644 design/uart_tx.vhd create mode 100644 diamond/ws2812wall.ldf create mode 100644 diamond/ws2812wall.lpf create mode 160000 ws2812b-vhdl diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d1b27bd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ws2812b-vhdl"] + path = ws2812b-vhdl + url = git@github.com:cclassic/ws2812b-vhdl.git diff --git a/.library_mapping.xml b/.library_mapping.xml new file mode 100644 index 0000000..42bfdf5 --- /dev/null +++ b/.library_mapping.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..1493835 --- /dev/null +++ b/.project @@ -0,0 +1,45 @@ + + + ws2812-wall + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + com.sigasi.hdt.vhdl.ui.vhdlNature + org.eclipse.xtext.ui.shared.xtextNature + + + + Common Libraries + 2 + virtual:/virtual + + + Common Libraries/DRAG_REUSABLE_LIBRARIES_HERE.txt + 1 + sigasiresource:/vhdl/readme2.txt + + + Common Libraries/IEEE + 2 + sigasiresource:/vhdl/93/IEEE + + + Common Libraries/STD + 2 + sigasiresource:/vhdl/93/STD + + + Common Libraries/IEEE/Synopsys + 2 + sigasiresource:/vhdl/93/IEEE%20Synopsys + + + diff --git a/.settings/com.sigasi.hdt.vhdl.version.prefs b/.settings/com.sigasi.hdt.vhdl.version.prefs new file mode 100644 index 0000000..2eced90 --- /dev/null +++ b/.settings/com.sigasi.hdt.vhdl.version.prefs @@ -0,0 +1 @@ +=93 diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..240a6e2 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//Common\ Libraries/IEEE=utf-8 +encoding//Common\ Libraries/IEEE/Synopsys=utf-8 +encoding//Common\ Libraries/STD=utf-8 +encoding/Common\ Libraries=utf-8 diff --git a/bench/bench_top.vhd b/bench/bench_top.vhd new file mode 100644 index 0000000..4d07cfb --- /dev/null +++ b/bench/bench_top.vhd @@ -0,0 +1,105 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library design; +use design.all; + +entity bench_top is +end entity bench_top; + +architecture RTL of bench_top is + constant SIM_SPEEDUP : natural := 2; + + signal clk_hw : std_logic; + signal rst_hw : std_logic; + signal ws2812_out : std_logic_vector(4 - 1 downto 0); + signal uart_tx : std_logic; + +begin + top_inst : entity design.top + generic map( + f_clk => 24_000_000 / SIM_SPEEDUP, + ROWS => 4, + COLUMNS => 4 + ) + port map( + clk_hw => clk_hw, + rst_hw => rst_hw, + ws2812_out => ws2812_out, + uart_rx => uart_tx + ); + + clock_driver : process + constant period : time := (1 sec / 24_000_000); + begin + clk_hw <= '0'; + wait for period / 2; + clk_hw <= '1'; + wait for period / 2; + end process clock_driver; + + test : process is + constant UART_BITTIME : time := 1 sec / 115200 / SIM_SPEEDUP; + procedure uart_transmit(data : in std_logic_vector(7 downto 0)) is + begin + uart_tx <= '0'; + wait for UART_BITTIME; + for i in 0 to 7 loop + uart_tx <= data(i); + wait for UART_BITTIME; + end loop; + uart_tx <= '1'; + wait for UART_BITTIME; + end procedure uart_transmit; + + begin + rst_hw <= '0'; + uart_tx <= '1'; + wait until clk_hw = '1'; + wait until clk_hw = '1'; + rst_hw <= '1'; + wait until clk_hw = '1'; + wait for UART_BITTIME * 13; + wait until clk_hw = '1'; + + -- Write LED data (cmd 0x00) + uart_transmit(x"00"); + + uart_transmit(x"00"); -- Start address 0 + uart_transmit(x"00"); + + uart_transmit(x"00"); -- Write two LEDs + uart_transmit(x"02"); + + uart_transmit(x"01"); -- First LED + uart_transmit(x"02"); + uart_transmit(x"03"); + uart_transmit(x"11"); + uart_transmit(x"12"); + uart_transmit(x"13"); + uart_transmit(x"21"); + uart_transmit(x"22"); + uart_transmit(x"23"); + uart_transmit(x"31"); + uart_transmit(x"32"); + uart_transmit(x"33"); + + uart_transmit(x"a1"); -- Second LED + uart_transmit(x"a2"); + uart_transmit(x"a3"); + uart_transmit(x"b1"); + uart_transmit(x"b2"); + uart_transmit(x"b3"); + uart_transmit(x"c1"); + uart_transmit(x"c2"); + uart_transmit(x"c3"); + uart_transmit(x"d1"); + uart_transmit(x"d2"); + uart_transmit(x"d3"); + + -- Render (cmd 0x01) + uart_transmit(x"01"); + wait; + end process test; +end architecture RTL; diff --git a/bench_top.gtkw b/bench_top.gtkw new file mode 100644 index 0000000..ea0821c --- /dev/null +++ b/bench_top.gtkw @@ -0,0 +1,80 @@ +[*] +[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI +[*] Sun Jan 21 17:51:06 2018 +[*] +[dumpfile] "/tmp/SigasiCompileCache7616390032050217445/ws2812-wall/mentor/bench_top.ghw" +[dumpfile_mtime] "Sun Jan 21 17:50:57 2018" +[dumpfile_size] 5545813 +[savefile] "/home/markus/workspaceSigasi/ws2812-wall/bench_top.gtkw" +[timestart] 1288000000000 +[size] 1920 1043 +[pos] -1 -1 +*-34.891136 1372229144711 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] top. +[treeopen] top.bench_top. +[treeopen] top.bench_top.top_inst. +[treeopen] top.bench_top.top_inst.uart_rx_inst. +[sst_width] 267 +[signals_width] 261 +[sst_expanded] 1 +[sst_vpaned_height] 298 +@420 +top.bench_top.top_inst.renderer_state +@28 +top.bench_top.top_inst.render_stb +top.bench_top.top_inst.rst +top.bench_top.top_inst.clk +top.bench_top.top_inst.rst_hw +top.bench_top.top_inst.clk_hw +@c00022 +#{top.bench_top.ws2812_out[6:0]} top.bench_top.ws2812_out[3] top.bench_top.ws2812_out[2] top.bench_top.ws2812_out[1] top.bench_top.ws2812_out[0] +@28 +top.bench_top.ws2812_out[3] +top.bench_top.ws2812_out[2] +top.bench_top.ws2812_out[1] +top.bench_top.ws2812_out[0] +@1401200 +-group_end +@22 +#{top.bench_top.top_inst.renderer_data[167:0]} top.bench_top.top_inst.renderer_data[95] top.bench_top.top_inst.renderer_data[94] top.bench_top.top_inst.renderer_data[93] top.bench_top.top_inst.renderer_data[92] top.bench_top.top_inst.renderer_data[91] top.bench_top.top_inst.renderer_data[90] top.bench_top.top_inst.renderer_data[89] top.bench_top.top_inst.renderer_data[88] top.bench_top.top_inst.renderer_data[87] top.bench_top.top_inst.renderer_data[86] top.bench_top.top_inst.renderer_data[85] top.bench_top.top_inst.renderer_data[84] top.bench_top.top_inst.renderer_data[83] top.bench_top.top_inst.renderer_data[82] top.bench_top.top_inst.renderer_data[81] top.bench_top.top_inst.renderer_data[80] top.bench_top.top_inst.renderer_data[79] top.bench_top.top_inst.renderer_data[78] top.bench_top.top_inst.renderer_data[77] top.bench_top.top_inst.renderer_data[76] top.bench_top.top_inst.renderer_data[75] top.bench_top.top_inst.renderer_data[74] top.bench_top.top_inst.renderer_data[73] top.bench_top.top_inst.renderer_data[72] top.bench_top.top_inst.renderer_data[71] top.bench_top.top_inst.renderer_data[70] top.bench_top.top_inst.renderer_data[69] top.bench_top.top_inst.renderer_data[68] top.bench_top.top_inst.renderer_data[67] top.bench_top.top_inst.renderer_data[66] top.bench_top.top_inst.renderer_data[65] top.bench_top.top_inst.renderer_data[64] top.bench_top.top_inst.renderer_data[63] top.bench_top.top_inst.renderer_data[62] top.bench_top.top_inst.renderer_data[61] top.bench_top.top_inst.renderer_data[60] top.bench_top.top_inst.renderer_data[59] top.bench_top.top_inst.renderer_data[58] top.bench_top.top_inst.renderer_data[57] top.bench_top.top_inst.renderer_data[56] top.bench_top.top_inst.renderer_data[55] top.bench_top.top_inst.renderer_data[54] top.bench_top.top_inst.renderer_data[53] top.bench_top.top_inst.renderer_data[52] top.bench_top.top_inst.renderer_data[51] top.bench_top.top_inst.renderer_data[50] top.bench_top.top_inst.renderer_data[49] top.bench_top.top_inst.renderer_data[48] top.bench_top.top_inst.renderer_data[47] top.bench_top.top_inst.renderer_data[46] top.bench_top.top_inst.renderer_data[45] top.bench_top.top_inst.renderer_data[44] top.bench_top.top_inst.renderer_data[43] top.bench_top.top_inst.renderer_data[42] top.bench_top.top_inst.renderer_data[41] top.bench_top.top_inst.renderer_data[40] top.bench_top.top_inst.renderer_data[39] top.bench_top.top_inst.renderer_data[38] top.bench_top.top_inst.renderer_data[37] top.bench_top.top_inst.renderer_data[36] top.bench_top.top_inst.renderer_data[35] top.bench_top.top_inst.renderer_data[34] top.bench_top.top_inst.renderer_data[33] top.bench_top.top_inst.renderer_data[32] top.bench_top.top_inst.renderer_data[31] top.bench_top.top_inst.renderer_data[30] top.bench_top.top_inst.renderer_data[29] top.bench_top.top_inst.renderer_data[28] top.bench_top.top_inst.renderer_data[27] top.bench_top.top_inst.renderer_data[26] top.bench_top.top_inst.renderer_data[25] top.bench_top.top_inst.renderer_data[24] top.bench_top.top_inst.renderer_data[23] top.bench_top.top_inst.renderer_data[22] top.bench_top.top_inst.renderer_data[21] top.bench_top.top_inst.renderer_data[20] top.bench_top.top_inst.renderer_data[19] top.bench_top.top_inst.renderer_data[18] top.bench_top.top_inst.renderer_data[17] top.bench_top.top_inst.renderer_data[16] top.bench_top.top_inst.renderer_data[15] top.bench_top.top_inst.renderer_data[14] top.bench_top.top_inst.renderer_data[13] top.bench_top.top_inst.renderer_data[12] top.bench_top.top_inst.renderer_data[11] top.bench_top.top_inst.renderer_data[10] top.bench_top.top_inst.renderer_data[9] top.bench_top.top_inst.renderer_data[8] top.bench_top.top_inst.renderer_data[7] top.bench_top.top_inst.renderer_data[6] top.bench_top.top_inst.renderer_data[5] top.bench_top.top_inst.renderer_data[4] top.bench_top.top_inst.renderer_data[3] top.bench_top.top_inst.renderer_data[2] top.bench_top.top_inst.renderer_data[1] top.bench_top.top_inst.renderer_data[0] +@800022 +#{top.bench_top.top_inst.pixdata_next[6:0]} top.bench_top.top_inst.pixdata_next[3] top.bench_top.top_inst.pixdata_next[2] top.bench_top.top_inst.pixdata_next[1] top.bench_top.top_inst.pixdata_next[0] +@28 +top.bench_top.top_inst.pixdata_next[3] +top.bench_top.top_inst.pixdata_next[2] +top.bench_top.top_inst.pixdata_next[1] +top.bench_top.top_inst.pixdata_next[0] +@1001200 +-group_end +@800022 +#{top.bench_top.top_inst.pixdata_valid[6:0]} top.bench_top.top_inst.pixdata_valid[3] top.bench_top.top_inst.pixdata_valid[2] top.bench_top.top_inst.pixdata_valid[1] top.bench_top.top_inst.pixdata_valid[0] +@28 +top.bench_top.top_inst.pixdata_valid[3] +top.bench_top.top_inst.pixdata_valid[2] +top.bench_top.top_inst.pixdata_valid[1] +top.bench_top.top_inst.pixdata_valid[0] +@1001200 +-group_end +@420 +top.bench_top.top_inst.controller_state +@28 +top.bench_top.top_inst.uart_rx +@420 +top.bench_top.top_inst.uart_rx_inst.state +top.bench_top.top_inst.uart_rx_inst.bitcounter +@22 +#{top.bench_top.top_inst.uart_rx_inst.clkdivider[15:0]} top.bench_top.top_inst.uart_rx_inst.clkdivider[15] top.bench_top.top_inst.uart_rx_inst.clkdivider[14] top.bench_top.top_inst.uart_rx_inst.clkdivider[13] top.bench_top.top_inst.uart_rx_inst.clkdivider[12] top.bench_top.top_inst.uart_rx_inst.clkdivider[11] top.bench_top.top_inst.uart_rx_inst.clkdivider[10] top.bench_top.top_inst.uart_rx_inst.clkdivider[9] top.bench_top.top_inst.uart_rx_inst.clkdivider[8] top.bench_top.top_inst.uart_rx_inst.clkdivider[7] top.bench_top.top_inst.uart_rx_inst.clkdivider[6] top.bench_top.top_inst.uart_rx_inst.clkdivider[5] top.bench_top.top_inst.uart_rx_inst.clkdivider[4] top.bench_top.top_inst.uart_rx_inst.clkdivider[3] top.bench_top.top_inst.uart_rx_inst.clkdivider[2] top.bench_top.top_inst.uart_rx_inst.clkdivider[1] top.bench_top.top_inst.uart_rx_inst.clkdivider[0] +@28 +top.bench_top.top_inst.uart_rx_stb +@22 +#{top.bench_top.top_inst.uart_rx_data[7:0]} top.bench_top.top_inst.uart_rx_data[7] top.bench_top.top_inst.uart_rx_data[6] top.bench_top.top_inst.uart_rx_data[5] top.bench_top.top_inst.uart_rx_data[4] top.bench_top.top_inst.uart_rx_data[3] top.bench_top.top_inst.uart_rx_data[2] top.bench_top.top_inst.uart_rx_data[1] top.bench_top.top_inst.uart_rx_data[0] +@29 +top.bench_top.top_inst.controller_ram_we +@420 +top.bench_top.top_inst.byte_cnt +@22 +#{top.bench_top.top_inst.sr[167:0]} top.bench_top.top_inst.sr[95] top.bench_top.top_inst.sr[94] top.bench_top.top_inst.sr[93] top.bench_top.top_inst.sr[92] top.bench_top.top_inst.sr[91] top.bench_top.top_inst.sr[90] top.bench_top.top_inst.sr[89] top.bench_top.top_inst.sr[88] top.bench_top.top_inst.sr[87] top.bench_top.top_inst.sr[86] top.bench_top.top_inst.sr[85] top.bench_top.top_inst.sr[84] top.bench_top.top_inst.sr[83] top.bench_top.top_inst.sr[82] top.bench_top.top_inst.sr[81] top.bench_top.top_inst.sr[80] top.bench_top.top_inst.sr[79] top.bench_top.top_inst.sr[78] top.bench_top.top_inst.sr[77] top.bench_top.top_inst.sr[76] top.bench_top.top_inst.sr[75] top.bench_top.top_inst.sr[74] top.bench_top.top_inst.sr[73] top.bench_top.top_inst.sr[72] top.bench_top.top_inst.sr[71] top.bench_top.top_inst.sr[70] top.bench_top.top_inst.sr[69] top.bench_top.top_inst.sr[68] top.bench_top.top_inst.sr[67] top.bench_top.top_inst.sr[66] top.bench_top.top_inst.sr[65] top.bench_top.top_inst.sr[64] top.bench_top.top_inst.sr[63] top.bench_top.top_inst.sr[62] top.bench_top.top_inst.sr[61] top.bench_top.top_inst.sr[60] top.bench_top.top_inst.sr[59] top.bench_top.top_inst.sr[58] top.bench_top.top_inst.sr[57] top.bench_top.top_inst.sr[56] top.bench_top.top_inst.sr[55] top.bench_top.top_inst.sr[54] top.bench_top.top_inst.sr[53] top.bench_top.top_inst.sr[52] top.bench_top.top_inst.sr[51] top.bench_top.top_inst.sr[50] top.bench_top.top_inst.sr[49] top.bench_top.top_inst.sr[48] top.bench_top.top_inst.sr[47] top.bench_top.top_inst.sr[46] top.bench_top.top_inst.sr[45] top.bench_top.top_inst.sr[44] top.bench_top.top_inst.sr[43] top.bench_top.top_inst.sr[42] top.bench_top.top_inst.sr[41] top.bench_top.top_inst.sr[40] top.bench_top.top_inst.sr[39] top.bench_top.top_inst.sr[38] top.bench_top.top_inst.sr[37] top.bench_top.top_inst.sr[36] top.bench_top.top_inst.sr[35] top.bench_top.top_inst.sr[34] top.bench_top.top_inst.sr[33] top.bench_top.top_inst.sr[32] top.bench_top.top_inst.sr[31] top.bench_top.top_inst.sr[30] top.bench_top.top_inst.sr[29] top.bench_top.top_inst.sr[28] top.bench_top.top_inst.sr[27] top.bench_top.top_inst.sr[26] top.bench_top.top_inst.sr[25] top.bench_top.top_inst.sr[24] top.bench_top.top_inst.sr[23] top.bench_top.top_inst.sr[22] top.bench_top.top_inst.sr[21] top.bench_top.top_inst.sr[20] top.bench_top.top_inst.sr[19] top.bench_top.top_inst.sr[18] top.bench_top.top_inst.sr[17] top.bench_top.top_inst.sr[16] top.bench_top.top_inst.sr[15] top.bench_top.top_inst.sr[14] top.bench_top.top_inst.sr[13] top.bench_top.top_inst.sr[12] top.bench_top.top_inst.sr[11] top.bench_top.top_inst.sr[10] top.bench_top.top_inst.sr[9] top.bench_top.top_inst.sr[8] top.bench_top.top_inst.sr[7] top.bench_top.top_inst.sr[6] top.bench_top.top_inst.sr[5] top.bench_top.top_inst.sr[4] top.bench_top.top_inst.sr[3] top.bench_top.top_inst.sr[2] top.bench_top.top_inst.sr[1] top.bench_top.top_inst.sr[0] +@28 +top.bench_top.top_inst.controller_ram_addr[0] +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/design/edgeDetector.vhd b/design/edgeDetector.vhd new file mode 100644 index 0000000..f1b3472 --- /dev/null +++ b/design/edgeDetector.vhd @@ -0,0 +1,41 @@ +-- -------------------------------------------------------------------------- -- +-- edgeDetector.vhd: Basic edge detector +-- +-- Copyright (C) 2017 Markus Koch +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at http://mozilla.org/MPL/2.0/. +-- -------------------------------------------------------------------------- -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity edgeDetector is + port( + clk : in std_logic; + rst : in std_logic; + sig : in std_logic; + risingEdge : out std_logic; + fallingEdge : out std_logic; + anyEdge : out std_logic + ); +end entity edgeDetector; + +architecture RTL of edgeDetector is + signal temp : std_logic_vector(1 downto 0); +begin + shiftomat : process(rst, clk) is + begin + if rst = '1' then + temp <= "00"; + elsif rising_edge(clk) then + temp <= temp(0) & sig; + end if; + end process shiftomat; + + risingEdge <= '1' when (temp = "01") else '0'; + fallingEdge <= '1' when (temp = "10") else '0'; + anyEdge <= '1' when (temp = "01" or temp = "10") else '0'; +end architecture RTL; diff --git a/design/ram.vhd b/design/ram.vhd new file mode 100644 index 0000000..844b766 --- /dev/null +++ b/design/ram.vhd @@ -0,0 +1,36 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity ram is + generic( + WIDTH : natural := 8; + DEPTH : natural := 4 + ); + port( + clk : in std_logic; + addr_a : in std_logic_vector(DEPTH - 1 downto 0); + data_out_a : out std_logic_vector(WIDTH - 1 downto 0); + data_in_a : in std_logic_vector(WIDTH - 1 downto 0); + we_a : in std_logic; + addr_b : in std_logic_vector(DEPTH - 1 downto 0); + data_out_b : out std_logic_vector(WIDTH - 1 downto 0) + ); +end entity ram; + +architecture rtl of ram is + type memory_t is array (0 to integer(2**DEPTH) - 1) of std_logic_vector(WIDTH - 1 downto 0); + signal memory : memory_t; + +begin + ram_p : process(clk) is + begin + if (rising_edge(clk)) then + data_out_a <= memory(to_integer(unsigned(addr_a))); + if (we_a = '1') then + memory(to_integer(unsigned(addr_a))) <= data_in_a; + end if; + data_out_b <= memory(to_integer(unsigned(addr_b))); + end if; + end process ram_p; +end architecture rtl; diff --git a/design/synchronizer.vhd b/design/synchronizer.vhd new file mode 100644 index 0000000..3630ae0 --- /dev/null +++ b/design/synchronizer.vhd @@ -0,0 +1,31 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity synchronizer is + generic(COUNT : integer := 1); + port( + clk : in std_logic; + rst : in std_logic; + dIn : in std_logic_vector(COUNT - 1 downto 0); + dOut : out std_logic_vector(COUNT - 1 downto 0) + ); +end entity synchronizer; + +architecture RTL of synchronizer is + signal temp : std_logic_vector(COUNT - 1 downto 0); +begin + synch : process(rst, clk) is + begin + for i in 0 to COUNT - 1 loop + if rst = '1' then + temp(i) <= '0'; + dOut(i) <= '0'; + elsif rising_edge(clk) then + temp(i) <= dIn(i); + dOut(i) <= temp(i); + end if; + end loop; + end process synch; + +end architecture RTL; diff --git a/design/top.vhd b/design/top.vhd new file mode 100644 index 0000000..6720aef --- /dev/null +++ b/design/top.vhd @@ -0,0 +1,252 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +library ws2812b; +use ws2812b.all; + +use work.top_pkg.all; + +entity top is + generic( + f_clk : natural := 24_000_000; + ROWS : natural := 7; + COLUMNS : natural := 64 + ); + port( + clk_hw : in std_logic; -- HW clock + rst_hw : in std_logic; -- Hardware reset (active low) + + uart_rx : in std_logic; -- UART RX pin + + ws2812_out : out std_logic_vector(ROWS - 1 downto 0) -- WS2812B data line + ); +end entity top; + +architecture RTL of top is + constant RAM_WIDTH : natural := 8 * 3 * ROWS; + constant RAM_DEPTH : natural := integer(ceil(log2(real(COLUMNS)))); + constant UART_CKDIV : std_logic_vector(15 downto 0) := std_logic_vector(to_unsigned(f_clk / 115200, 16)); + + signal clk : std_logic; + signal rst : std_logic; + + signal pixData_red : color_vector(ROWS - 1 downto 0); + signal pixData_green : color_vector(ROWS - 1 downto 0); + signal pixData_blue : color_vector(ROWS - 1 downto 0); + signal pixData_valid : std_logic_vector(ROWS - 1 downto 0); + signal pixData_next : std_logic_vector(ROWS - 1 downto 0); + + signal uart_rx_data : std_logic_vector(7 downto 0); + signal uart_rx_stb : std_logic; + signal uart_rx_error : std_logic; + + type controller_state_t is (IDLE, ADDR, LENGTH, DATA); + signal controller_state : controller_state_t; + signal controller_ram_addr : std_logic_vector(RAM_DEPTH - 1 downto 0); + signal controller_ram_din : std_logic_vector(RAM_WIDTH - 1 downto 0); + signal controller_ram_dout : std_logic_vector(RAM_WIDTH - 1 downto 0); + signal controller_ram_we : std_logic; + signal sr : std_logic_vector(controller_ram_din'range); + signal byte_cnt : integer range 0 to ROWS * 3 - 1; + signal leds_left : integer range 0 to 2**RAM_DEPTH - 1; + + signal render_stb : std_logic; + type renderer_state_t is (IDLE, RENDER, LOCK); + signal renderer_state : renderer_state_t; + signal renderer_addr : std_logic_vector(RAM_DEPTH - 1 downto 0); + signal renderer_data : std_logic_vector(RAM_WIDTH - 1 downto 0); + +begin + clk <= clk_hw; + + reset_gen : process(clk, rst_hw) is + variable tmp : std_logic; + + begin + if (rst_hw = '0') then + tmp := '1'; + rst <= '1'; + elsif (rising_edge(clk)) then + rst <= tmp; + tmp := '0'; + end if; + end process reset_gen; + + ws2812b_phys : for i in 0 to ROWS - 1 generate + ws2812b_phy_inst : entity ws2812b.ws2812b_phy + generic map( + f_clk => f_clk + ) + port map( + clk => clk, + rst => rst, + so => ws2812_out(i), + pixData_red => pixData_red(i), + pixData_green => pixData_green(i), + pixData_blue => pixData_blue(i), + pixData_valid => pixData_valid(i), + pixData_next => pixData_next(i) + ); + end generate ws2812b_phys; + + -- Upon receiving ```renderer_stb```, it sends the data in memory out to the LEDs + renderer : process(clk, rst) is + procedure set_all_valid(state : std_logic) is + begin + for i in 0 to ROWS - 1 loop + pixData_valid(i) <= state; + end loop; + end procedure set_all_valid; + + begin + if (rst = '1') then + renderer_state <= IDLE; + renderer_addr <= (others => '0'); + set_all_valid('0'); + + elsif (rising_edge(clk)) then + case renderer_state is + when IDLE => + set_all_valid('0'); + renderer_addr <= (others => '0'); -- Note: We need to have been in this state for at least one cycle + if (render_stb = '1') then + set_all_valid('1'); + renderer_state <= RENDER; + end if; + + when RENDER => + if (pixData_next(0) = '1') then -- TODO: This expects all PHYs to run synchronously + renderer_addr <= std_logic_vector(unsigned(renderer_addr) + 1); + if (unsigned(renderer_addr) = (COLUMNS - 1)) then + set_all_valid('0'); + renderer_state <= LOCK; + end if; + end if; + + when LOCK => + set_all_valid('0'); + if (pixData_next(0) = '1') then + renderer_state <= IDLE; + end if; + end case; + end if; + end process renderer; + + pixData_connections : for i in 0 to ROWS - 1 generate + pixData_red(i) <= renderer_data(i * 24 + 7 downto i * 24); + pixData_green(i) <= renderer_data(i * 24 + 15 downto i * 24 + 8); + pixData_blue(i) <= renderer_data(i * 24 + 23 downto i * 24 + 16); + end generate pixData_connections; + + ram_inst : entity work.ram + generic map( + WIDTH => RAM_WIDTH, + DEPTH => RAM_DEPTH + ) + port map( + clk => clk, + addr_a => controller_ram_addr, + data_out_a => controller_ram_dout, + data_in_a => controller_ram_din, + we_a => controller_ram_we, + addr_b => renderer_addr, + data_out_b => renderer_data + ); + + controller : process(clk, rst) is + variable sr_v : std_logic_vector(sr'range); + begin + if (rst = '1') then + sr <= (others => '0'); + controller_state <= IDLE; + byte_cnt <= 0; + render_stb <= '0'; + controller_ram_addr <= (others => '0'); + controller_ram_we <= '0'; + + elsif (rising_edge(clk)) then + render_stb <= '0'; + controller_ram_we <= '0'; + + if (uart_rx_stb = '1') then + sr_v := sr(sr'high - uart_rx_data'length downto sr'low) & uart_rx_data; + sr <= sr_v; + end if; + + case controller_state is + when IDLE => + byte_cnt <= 0; + if (uart_rx_stb = '1') then + if (uart_rx_data = x"00") then + controller_state <= ADDR; + + elsif (uart_rx_data = x"01") then + render_stb <= '1'; + controller_state <= IDLE; + end if; + end if; + + when ADDR => + if (uart_rx_stb = '1') then + if (byte_cnt = 1) then + controller_ram_addr <= std_logic_vector(to_unsigned(to_integer(unsigned(sr_v(15 downto 0)) * 3), controller_ram_addr'length)); + controller_state <= LENGTH; + byte_cnt <= 0; + + else + byte_cnt <= byte_cnt + 1; + end if; + end if; + + when LENGTH => + if (uart_rx_stb = '1') then + if (byte_cnt = 1) then + leds_left <= to_integer(unsigned(sr_v(15 downto 0))) - 1; + controller_state <= DATA; + byte_cnt <= 0; + + else + byte_cnt <= byte_cnt + 1; + end if; + end if; + + when DATA => + if (controller_ram_we = '1') then + controller_ram_addr <= std_logic_vector(unsigned(controller_ram_addr) + 1); + end if; + if (uart_rx_stb = '1') then + if (byte_cnt = ROWS * 3 - 1) then + byte_cnt <= 0; + controller_ram_we <= '1'; + if (leds_left = 0) then + controller_state <= IDLE; + else + leds_left <= leds_left - 1; + end if; + else + byte_cnt <= byte_cnt + 1; + end if; + end if; + end case; + end if; + end process controller; + + controller_ram_din <= sr; + + uart_rx_inst : entity work.uart_rx + port map( + clk => clk, + rst => rst, + data => uart_rx_data, + byte_ready => uart_rx_stb, + error => uart_rx_error, + ckDiv => UART_CKDIV, + parityEnable => '0', + parityOdd => '0', + twoStopBits => '0', + rx => uart_rx + ); + +end architecture RTL; diff --git a/design/top_pkg.vhd b/design/top_pkg.vhd new file mode 100644 index 0000000..2001a8a --- /dev/null +++ b/design/top_pkg.vhd @@ -0,0 +1,6 @@ +library ieee; +use ieee.std_logic_1164.all; + +package top_pkg is + type color_vector is array(natural range <>) of std_logic_vector(7 downto 0); +end package top_pkg; diff --git a/design/uart_rx.vhd b/design/uart_rx.vhd new file mode 100644 index 0000000..bdf0cf3 --- /dev/null +++ b/design/uart_rx.vhd @@ -0,0 +1,161 @@ +-- -------------------------------------------------------------------------- -- +-- uart_rx.vhd: Basic UART (rx) +-- +-- Copyright (C) 2017 Markus Koch +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at http://mozilla.org/MPL/2.0/. +-- -------------------------------------------------------------------------- -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity uart_rx is + port( + clk : in std_logic; + rst : in std_logic; + data : out std_logic_vector(7 downto 0); + byte_ready : out std_logic; + error : out std_logic; + + ckDiv : in std_logic_vector(15 downto 0); + parityEnable : in std_logic; + parityOdd : in std_logic; + twoStopBits : in std_logic; + + rx : in std_logic + ); +end entity uart_rx; + +architecture RTL of uart_rx is + constant SYNCH_COUNT : integer := 11; -- Min. 8 + constant BITCOUNT : integer := 8; + + type state_t is (SYNCH, IDLE, START, RECEIVE, PARITY, STOP); + + signal state : state_t; + signal clkDivider : unsigned(15 downto 0); + signal bitCounter : integer range 0 to SYNCH_COUNT; + signal data_i : std_logic_vector(7 downto 0); + signal rx_edge : std_logic; + signal parity_calc : std_logic; + signal rx_i : std_logic; + +begin + synchronizer_inst : entity work.synchronizer + generic map( + COUNT => 1 + ) + port map( + clk => clk, + rst => rst, + dIn(0) => rx, + dOut(0) => rx_i + ); + + edgeDetector_inst : entity work.edgeDetector + port map(clk => clk, + rst => rst, + sig => rx_i, + risingEdge => open, + fallingEdge => open, + anyEdge => rx_edge); + + rxFSM : process(clk, rst, parityOdd, ckDiv) is + begin + if rst = '1' then + state <= SYNCH; + bitCounter <= SYNCH_COUNT; + clkDivider <= unsigned(ckDiv); + error <= '0'; + parity_calc <= parityOdd; + data_i <= x"00"; + data <= x"00"; + byte_ready <= '0'; + elsif rising_edge(clk) then + byte_ready <= '0'; + error <= '0'; + if (clkDivider = 0) then + clkDivider <= unsigned(ckDiv); + else + clkDivider <= clkDivider - 1; + end if; + case state is + when SYNCH => -- Wait for 11 consecutive ones + if (clkDivider = to_unsigned(0, clkDivider'length)) then + if rx_i = '1' then + if bitCounter = 0 then + state <= IDLE; + else + bitCounter <= bitcounter - 1; + end if; + else + bitCounter <= SYNCH_COUNT; + end if; + end if; + when IDLE => -- Detect transition for sync + if rx_i = '0' then + state <= START; + clkDivider <= unsigned('0' & ckDiv(15 downto 1)); -- cMax_half. After that we are in the middle of the start bit + parity_calc <= parityOdd; + end if; + when START => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + if rx_i = '0' then + state <= RECEIVE; + bitCounter <= 0; + else + report "uart_rx: START BIT ERROR" severity warning; + error <= '1'; + state <= SYNCH; + end if; + end if; + when RECEIVE => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + data_i(bitCounter) <= rx_i; + if rx_i = '1' then + parity_calc <= not parity_calc; + end if; + if bitCounter = BITCOUNT - 1 then + bitCounter <= 0; + if parityEnable = '1' then + state <= PARITY; + else + state <= STOP; + end if; + else + bitCounter <= bitCounter + 1; + end if; + end if; + when PARITY => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + if parity_calc = rx_i then + state <= STOP; + else + state <= SYNCH; + error <= '1'; + report "uart_rx: PARITY ERROR" severity warning; + end if; + end if; + when STOP => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + if (rx_i = '1') then + bitCounter <= bitCounter + 1; + if bitCounter = 1 or twoStopBits = '0' then + state <= IDLE; + data <= data_i; + byte_ready <= '1'; + end if; + else + error <= '1'; + state <= SYNCH; + report "uart_rx: STOP BIT ERROR" severity warning; + end if; + end if; + end case; + end if; + end process rxFSM; + +end architecture RTL; diff --git a/design/uart_tx.vhd b/design/uart_tx.vhd new file mode 100644 index 0000000..e1b335f --- /dev/null +++ b/design/uart_tx.vhd @@ -0,0 +1,110 @@ +-- -------------------------------------------------------------------------- -- +-- uart_tx.vhd: Basic UART (tx) +-- +-- Copyright (C) 2017 Markus Koch +-- +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this +-- file, You can obtain one at http://mozilla.org/MPL/2.0/. +-- -------------------------------------------------------------------------- -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity uart_tx is + port( + clk : in std_logic; + rst : in std_logic; + data : in std_logic_vector(7 downto 0); + byte_ready : in std_logic; + busy : out std_logic; + + ckDiv : in std_logic_vector(15 downto 0); + parityEnable : in std_logic; + parityOdd : in std_logic; + twoStopBits : in std_logic; + + tx : out std_logic + ); +end entity uart_tx; + +architecture RTL of uart_tx is + type state_t is (IDLE, START, TRANSMIT, PARITY, STOP); + + signal state : state_t; + signal clkDivider : unsigned(15 downto 0); + signal data_i : std_logic_vector(7 downto 0); + signal bitCounter : integer range 0 to 7; + signal parity_calc : std_logic; + +begin + txFSM : process(clk, rst, ckDiv, parityOdd) is + begin + if rst = '1' then + data_i <= x"00"; + state <= IDLE; + tx <= '1'; + bitCounter <= 0; + busy <= '0'; + clkDivider <= unsigned(ckDiv); + parity_calc <= parityOdd; + elsif rising_edge(clk) then + busy <= '1'; + + if (clkDivider = 0) then + clkDivider <= unsigned(ckDiv); + else + clkDivider <= clkDivider - 1; + end if; + + case state is + when IDLE => + busy <= '0'; + tx <= '1'; + if byte_ready = '1' then + data_i <= data; + state <= START; + clkDivider <= unsigned(ckDiv); + bitCounter <= 0; + parity_calc <= '0'; + busy <= '1'; + tx <= '1'; + end if; + when START => + tx <= '0'; + state <= TRANSMIT; + when TRANSMIT => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + tx <= data_i(bitCounter); + if data_i(bitCounter) = '1' then + parity_calc <= not parity_calc; + end if; + if bitCounter = 7 then + bitCounter <= 0; + if parityEnable = '1' then + state <= PARITY; + else + state <= STOP; + end if; + else + bitCounter <= bitCounter + 1; + end if; + end if; + when PARITY => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + tx <= parity_calc; + state <= STOP; + end if; + when STOP => + if (clkDivider = to_unsigned(0, clkDivider'length)) then + tx <= '1'; + bitCounter <= bitCounter + 1; + if (bitCounter = 1 and twoStopBits = '0') or (bitCounter = 2 and twoStopBits = '1') then + state <= IDLE; + end if; + end if; + end case; + end if; + end process txFSM; +end architecture RTL; diff --git a/diamond/ws2812wall.ldf b/diamond/ws2812wall.ldf new file mode 100644 index 0000000..d0c6ab7 --- /dev/null +++ b/diamond/ws2812wall.ldf @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/diamond/ws2812wall.lpf b/diamond/ws2812wall.lpf new file mode 100644 index 0000000..325063a --- /dev/null +++ b/diamond/ws2812wall.lpf @@ -0,0 +1,2 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; diff --git a/ws2812b-vhdl b/ws2812b-vhdl new file mode 160000 index 0000000..6e52496 --- /dev/null +++ b/ws2812b-vhdl @@ -0,0 +1 @@ +Subproject commit 6e5249641d014cbe0b3723ff22c1637231e351f7