From 0b2f6403eb3ba63d98c133c99612918b3e304d24 Mon Sep 17 00:00:00 2001 From: Alvaro Date: Mon, 7 Apr 2014 09:43:40 +0100 Subject: [PATCH] Preliminary RGB led controller --- zpu/hdl/zpuino/rgb/rgbctrl.vhd | 281 +++++++++++++++++++++++++++++++ zpu/hdl/zpuino/rgb/sim/rgb32.vhd | 55 ++++++ zpu/hdl/zpuino/rgb/sim/tb.vhd | 121 +++++++++++++ 3 files changed, 457 insertions(+) create mode 100644 zpu/hdl/zpuino/rgb/rgbctrl.vhd create mode 100644 zpu/hdl/zpuino/rgb/sim/rgb32.vhd create mode 100644 zpu/hdl/zpuino/rgb/sim/tb.vhd diff --git a/zpu/hdl/zpuino/rgb/rgbctrl.vhd b/zpu/hdl/zpuino/rgb/rgbctrl.vhd new file mode 100644 index 00000000..130ca4b2 --- /dev/null +++ b/zpu/hdl/zpuino/rgb/rgbctrl.vhd @@ -0,0 +1,281 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.zpu_config.all; +use work.zpupkg.all; +use work.zpuinopkg.all; + +entity zpuino_rgbctrl is + port ( + wb_clk_i: in std_logic; + wb_rst_i: in std_logic; + wb_dat_o: out std_logic_vector(wordSize-1 downto 0); + wb_dat_i: in std_logic_vector(wordSize-1 downto 0); + wb_adr_i: in std_logic_vector(maxIObit downto minIObit); + wb_we_i: in std_logic; + wb_cyc_i: in std_logic; + wb_stb_i: in std_logic; + wb_ack_o: out std_logic; + wb_inta_o:out std_logic; + id: out slot_id; + + displayclk: in std_logic; + -- RGB outputters + + R: out std_logic_vector(1 downto 0); + G: out std_logic_vector(1 downto 0); + B: out std_logic_vector(1 downto 0); + + COL: out std_logic_vector(3 downto 0); + + CLK: out std_logic; + STB: out std_logic; + OE: out std_logic + ); +end entity zpuino_rgbctrl; + + +architecture behave of zpuino_rgbctrl is + + constant WITDH: integer := 32; + --constant HEIGHT: integer := 16; + + signal clken: std_logic; + + subtype pwmtype is unsigned(4 downto 0); -- 32 values. + + type rgbpwm is array (0 to 3) of pwmtype; + + type tworgbpwm is array(0 to 1) of rgbpwm; + + signal transfer: std_logic; + signal in_transfer: std_logic := '0'; + + + + subtype rgbtype is std_logic_vector(2 downto 0); + type shifteddatatype is array(WITDH-1 downto 0) of rgbtype; + + type dualshifteddatatype is array(0 to 1) of shifteddatatype; + + signal shiftout, shiftdata: dualshifteddatatype; + + type shtype is ( + idle,shift,clock,strobe + ); + signal shstate: shtype; + + signal transfer_count: integer; + + -- Memory + subtype memwordtype is std_logic_vector(31 downto 0); + type memtype is array(0 to (32*16)) of memwordtype; + + shared variable mem: memtype := (others => x"3def3def"); + signal ack_transfer: std_logic := '0'; + + signal mraddr: unsigned(8 downto 0) := (others => '0'); + signal mrdata: std_logic_vector(31 downto 0); + signal mren: std_logic; + signal cpwm: unsigned (4 downto 0) := (others => '0'); + + signal column: unsigned(4 downto 0) := (others => '0'); + signal row: unsigned(5 downto 0) := (others => '0'); + + subtype colorvaluetype is unsigned(4 downto 0); + type utype is array(0 to 3) of colorvaluetype; + + type fillerstatetype is ( + compute, + preparesend, + send + ); + + signal fillerstate: fillerstatetype := compute; + + signal debug_compresult: std_logic_vector(2 downto 0); + signal memvalid: std_logic := '0'; + +begin + + + process(displayclk) + begin + if rising_edge(displayclk) then + if mren='1' then + mrdata <= mem( to_integer(mraddr) ); + end if; + end if; + end process; + + mraddr (8 downto 5) <= column(3 downto 0); + mraddr (4 downto 0) <= row(4 downto 0); + + -- This is an odd way for processing the PWM. Perhaps + -- we can reorganize the memory ? + + + process(displayclk) + variable ucomp: utype; + variable mword: unsigned(15 downto 0); + variable compresult: std_logic_vector(2 downto 0); + begin + if rising_edge(displayclk) then + + memvalid <= mren; + + case fillerstate is + when compute => + + mren <= '1'; + if mren='1' and row(5)='0' then + row <= row + 1; + end if; + + if memvalid='1' then + -- We have valid data; + if (row(5)='1') then + --fillerstate <= preparesend; + fillerstate <= send; + mren<='0'; + row(5)<='0'; + transfer<='1'; + column <= column + 1 ; + end if; + + + + -- Validate if PWM bit for this LED should be '1' or '0' + + genpwm: for i in 0 to 1 loop + -- We need to decompose into the individual components + mword := unsigned(mrdata((16*(i+1))-1 downto 16*i)); + + ucomp(2) := mword(4 downto 0); + ucomp(1) := mword(9 downto 5); + ucomp(0) := mword(14 downto 10); + -- Compare output for each of them + comparepwm: for j in 0 to 2 loop + if (ucomp(j)>=cpwm) then + compresult(j):='1'; + else + compresult(j):='0'; + end if; + -- At this point we have the comparation. Shift it into the correct + -- registers. + + end loop; + + + shiftdata(i)(31 downto 1) <= shiftdata(i)(30 downto 0); + shiftdata(i)(0) <= compresult; + end loop; + + if row(5)='1' and column(4)='1' then + -- Advance pwm counter + cpwm <= cpwm + 1; + column(4)<='0'; + end if; + end if; + + when preparesend => + -- transfer<='1'; +-- column <= column + 1 ; + fillerstate <= send; + + when send => + if ack_transfer='1' then + mren<='1'; + fillerstate<=compute; + transfer<='0'; + end if; + + end case; + end if; + + debug_compresult <= compresult; + + end process; + + -- 32x32 leds. if we use a whole 16-bit for each.... + -- we can read two RGB per clock. .. + + + + process(wb_clk_i) + begin + + end process; + + -- Main outputter process. + + process(displayclk) + begin + if rising_edge(displayclk) then + STB<='0'; + CLK<='0'; + ack_transfer<='0'; + case shstate is + when idle => + if transfer='1' then + -- Load shift registers. + shiftout <= shiftdata; + in_transfer<='1'; + transfer_count <= WITDH-1; + shstate<=shift; + ack_transfer <='1'; + end if; + + when shift => + + -- Shift data out. + + for i in 0 to 1 loop -- Array number + for n in 1 to WITDH-1 loop -- Number of leds + for c in 0 to 2 loop -- Color number + shiftout(i)(n-1)(c) <= shiftout(i)(n)(c); + end loop; + end loop; + end loop; + shstate<=clock; + + when clock => + + transfer_count <= transfer_count - 1; + + CLK<='1'; + if transfer_count=0 then + shstate <= strobe; + else + shstate <= shift; + end if; + when strobe => + STB <= '1'; + shstate <= idle; + + end case; + + end if; + + end process; + + -- Assign outputs + ol: for i in 0 to 1 generate + R(i) <= shiftout(i)(0)(0); + G(i) <= shiftout(i)(0)(1); + B(i) <= shiftout(i)(0)(2); + end generate; + +end behave; + + + + + + + + + + diff --git a/zpu/hdl/zpuino/rgb/sim/rgb32.vhd b/zpu/hdl/zpuino/rgb/sim/rgb32.vhd new file mode 100644 index 00000000..7ed03c7a --- /dev/null +++ b/zpu/hdl/zpuino/rgb/sim/rgb32.vhd @@ -0,0 +1,55 @@ + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity rgb32 is + port ( + R: in std_logic; + G: in std_logic; + B: in std_logic; + + Ro: out std_logic_vector(31 downto 0); + Go: out std_logic_vector(31 downto 0); + Bo: out std_logic_vector(31 downto 0); + + CLK: in std_logic; + STB: in std_logic; + OE: in std_logic + ); +end entity rgb32; + +architecture sim of rgb32 is + + subtype shregtype is std_logic_vector(31 downto 0); + + type rgbshregstype is array(0 to 2) of shregtype; + signal shregs: rgbshregstype; + + signal inrgb:std_logic_vector(2 downto 0); + +begin + inrgb(0)<=R; + inrgb(1)<=G; + inrgb(2)<=B; + + process(CLK) + begin + if rising_edge(CLK) then + for i in 0 to 2 loop + shregs(i)(31 downto 1) <= shregs(i)(30 downto 0); + shregs(i)(0) <= inrgb(i); + end loop; + end if; + end process; + + process(STB) + begin + if STB='1' then + Ro <= shregs(0); + Go <= shregs(1); + Bo <= shregs(2); + end if; + end process; + +end sim; diff --git a/zpu/hdl/zpuino/rgb/sim/tb.vhd b/zpu/hdl/zpuino/rgb/sim/tb.vhd new file mode 100644 index 00000000..868085a2 --- /dev/null +++ b/zpu/hdl/zpuino/rgb/sim/tb.vhd @@ -0,0 +1,121 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.zpu_config.all; +use work.zpupkg.all; +use work.zpuinopkg.all; + +entity tb is +end entity; + +architecture sim of tb is + signal clk: std_ulogic :='0'; + signal rst: std_ulogic :='0'; + signal dispclk: std_ulogic := '0'; + + + signal CLKPERIOD: time := 10 ns; + signal DISPLAYPERIOD: time := 33.33 ns; + + component zpuino_rgbctrl is + port ( + wb_clk_i: in std_logic; + wb_rst_i: in std_logic; + wb_dat_o: out std_logic_vector(wordSize-1 downto 0); + wb_dat_i: in std_logic_vector(wordSize-1 downto 0); + wb_adr_i: in std_logic_vector(maxIObit downto minIObit); + wb_we_i: in std_logic; + wb_cyc_i: in std_logic; + wb_stb_i: in std_logic; + wb_ack_o: out std_logic; + wb_inta_o:out std_logic; + id: out slot_id; + + displayclk: in std_logic; + -- RGB outputters + + R: out std_logic_vector(1 downto 0); + G: out std_logic_vector(1 downto 0); + B: out std_logic_vector(1 downto 0); + + COL: out std_logic_vector(3 downto 0); + + CLK: out std_logic; + STB: out std_logic; + OE: out std_logic + ); + end component zpuino_rgbctrl; + + component rgb32 is + port ( + R: in std_logic; + G: in std_logic; + B: in std_logic; + + Ro: out std_logic_vector(31 downto 0); + Go: out std_logic_vector(31 downto 0); + Bo: out std_logic_vector(31 downto 0); + + CLK: in std_logic; + STB: in std_logic; + OE: in std_logic + ); + end component rgb32; + + signal R,G,B: std_logic_vector(1 downto 0); + signal DPCLK, DPSTB, DPOE: std_logic; + signal COL: std_logic_vector(3 downto 0); + +begin + + dispclk <= not dispclk after DISPLAYPERIOD/2; + clk <= not clk after CLKPERIOD/2; + + + ctrl: zpuino_rgbctrl + port map ( + wb_clk_i => clk, + wb_rst_i => rst, + wb_dat_i => (others => '0'), + wb_adr_i => (others => '0'), + wb_we_i => '0', + wb_cyc_i => '0', + wb_stb_i => '0', + wb_ack_o => open, + wb_inta_o => open, + id => open, + + displayclk => dispclk, + + -- RGB outputters + + R => R, + G => G, + B => B, + + COL => COL, + + CLK => DPCLK, + STB => DPSTB, + OE => DPOE + ); + + shregs: for i in 0 to 1 generate + rgb: rgb32 + port map ( + R => R(i), + G => G(i), + B => B(i), + Ro => open, + Go => open, + Bo => open, + + CLK => DPCLK, + STB => DPSTB, + OE => DPOE + ); + end generate; + +end sim;