diff --git a/modules/wishbone/Manifest.py b/modules/wishbone/Manifest.py index 8be1f73113d1dc364ad37150aa9517c7310ce710..0fefbad32bd0032d63c0da1f5c48c1bb4774a029 100644 --- a/modules/wishbone/Manifest.py +++ b/modules/wishbone/Manifest.py @@ -17,6 +17,7 @@ modules = { "local" : "wb_xilinx_fpga_loader", "wb_clock_crossing", "wb_dma", + "wb_serial_lcd", "wbgen2" ]}; diff --git a/modules/wishbone/wb_serial_lcd/Manifest.py b/modules/wishbone/wb_serial_lcd/Manifest.py new file mode 100644 index 0000000000000000000000000000000000000000..08aebb35c6b571b14835ef104f24ab325ec983e6 --- /dev/null +++ b/modules/wishbone/wb_serial_lcd/Manifest.py @@ -0,0 +1 @@ +files = [ "wb_serial_lcd.vhd" ] diff --git a/modules/wishbone/wb_serial_lcd/wb_serial_lcd.vhd b/modules/wishbone/wb_serial_lcd/wb_serial_lcd.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9c1e28f5111599ede01cd945224209a4d9b602b5 --- /dev/null +++ b/modules/wishbone/wb_serial_lcd/wb_serial_lcd.vhd @@ -0,0 +1,158 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.wishbone_pkg.all; +use work.genram_pkg.all; + +entity wb_serial_lcd is + generic( + g_cols : natural := 40; + g_rows : natural := 24; + g_wait : natural := 1); -- How many cycles per state change + port( + slave_clk_i : in std_logic; + slave_rstn_i : in std_logic; + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out; + + di_clk_i : in std_logic; + di_scp_o : out std_logic; + di_lp_o : out std_logic; + di_flm_o : out std_logic; + di_dat_o : out std_logic); +end entity; + +architecture rtl of wb_serial_lcd is + type t_state is (CLK_HIGH, FLM_HIGH, LP_HIGH, SLEEP1, SLEEP2, + CLK_LOW, SLEEP3, LP_LOW, FLM_LOW, SET_DATA); + + constant c_lo : natural := f_ceil_log2((g_cols+31)/32); + constant c_hi : natural := f_ceil_log2(g_rows); + constant c_bits : natural := c_lo+c_hi; + + signal r_state : t_state := SET_DATA; + signal r_row : integer range 0 to g_rows-1 := 0; + signal r_col : integer range 0 to g_cols-1 := 0; + signal r_wait : integer range 0 to g_wait-1 := 0; + signal r_lp : std_logic := '0'; + signal r_flm : std_logic := '0'; + signal r_ack : std_logic := '0'; + + signal s_wea : std_logic; + signal s_qa : std_logic_vector(31 downto 0); + signal s_qb : std_logic_vector(31 downto 0); + signal s_ab : std_logic_vector(c_bits-1 downto 0); + +begin + + slave_o.rty <= '0'; + slave_o.err <= '0'; + slave_o.stall <= '0'; + + s_wea <= slave_i.cyc and slave_i.stb and slave_i.we; + s_ab(c_bits-1 downto c_lo) <= std_logic_vector(to_unsigned(r_row, c_hi)); + s_ab(c_lo -1 downto 0) <= std_logic_vector(to_unsigned(r_col, c_lo+5)(c_lo+4 downto 5)); + + mem : generic_dpram + generic map( + g_data_width => 32, + g_size => 2**c_bits, + g_with_byte_enable => true, + g_dual_clock => false) + port map( + clka_i => slave_clk_i, + bwea_i => slave_i.sel, + wea_i => s_wea, + aa_i => slave_i.adr(c_bits+1 downto 2), + da_i => slave_i.dat, + qa_o => s_qa, + clkb_i => di_clk_i, + bweb_i => (others => '0'), + web_i => '0', + ab_i => s_ab, + db_i => (others => '0'), + qb_o => s_qb); + + -- Provide WB access to the frame buffer + wb : process(slave_clk_i) is + begin + if rising_edge(slave_clk_i) then + r_ack <= slave_i.cyc and slave_i.stb; + slave_o.ack <= r_ack; + slave_o.dat <= s_qa; + end if; + end process; + + -- Draw the frame buffer to the display + main : process(di_clk_i) is + begin + if rising_edge(di_clk_i) then + if r_wait /= g_wait-1 then + r_wait <= r_wait + 1; + else + r_wait <= 0; + + case r_state is + + when CLK_HIGH => + di_scp_o <= '1'; + r_state <= FLM_HIGH; + + when FLM_HIGH => + di_flm_o <= r_flm; + r_state <= LP_HIGH; + + when LP_HIGH => + di_lp_o <= r_lp; + r_state <= SLEEP1; + + when SLEEP1 => + r_state <= SLEEP2; + + when SLEEP2 => + r_state <= CLK_LOW; + + when CLK_LOW => + di_scp_o <= '0'; + r_state <= SLEEP3; + + when SLEEP3 => + r_state <= LP_LOW; + + when LP_LOW => + di_lp_o <= '0'; + r_state <= FLM_LOW; + + when FLM_LOW => + di_flm_o <= '0'; + r_state <= SET_DATA; + + when SET_DATA => + di_dat_o <= s_qb(to_integer(31 - to_unsigned(r_col, c_lo+5)(4 downto 0))); + r_state <= CLK_HIGH; + + if r_col /= g_cols-1 then + r_lp <= '0'; + r_flm <= '0'; + r_col <= r_col + 1; + r_row <= r_row; + elsif r_row /= g_rows-1 then + r_lp <= '1'; + r_flm <= '0'; + r_col <= 0; + r_row <= r_row + 1; + else + r_lp <= '1'; + r_flm <= '1'; + r_col <= 0; + r_row <= 0; + end if; + + end case; + end if; + end if; + end process; + +end rtl; diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd index 4c0c081d390607e5433e2163d31a0dbb85f0ded0..b37d1566c474003ec9478993fd27e0098dfc54b7 100644 --- a/modules/wishbone/wishbone_pkg.vhd +++ b/modules/wishbone/wishbone_pkg.vhd @@ -658,6 +658,39 @@ package wishbone_pkg is irqs_i : in std_logic_vector(g_num_interrupts-1 downto 0); irq_master_o : out std_logic); end component; + + constant c_wb_serial_lcd_sdb : t_sdb_device := ( + abi_class => x"0000", -- undocumented device + abi_ver_major => x"01", + abi_ver_minor => x"00", + wbd_endian => c_sdb_endian_big, + wbd_width => x"7", -- 8/16/32-bit port granularity + sdb_component => ( + addr_first => x"0000000000000000", + addr_last => x"00000000000000ff", + product => ( + vendor_id => x"0000000000000651", -- GSI + device_id => x"b77a5045", + version => x"00000001", + date => x"20130222", + name => "SERIAL-LCD-DISPLAY "))); + component wb_serial_lcd + generic( + g_cols : natural := 40; + g_rows : natural := 24; + g_wait : natural := 1); + port( + slave_clk_i : in std_logic; + slave_rstn_i : in std_logic; + slave_i : in t_wishbone_slave_in; + slave_o : out t_wishbone_slave_out; + di_clk_i : in std_logic; + di_scp_o : out std_logic; + di_lp_o : out std_logic; + di_flm_o : out std_logic; + di_dat_o : out std_logic); + end component; + end wishbone_pkg; package body wishbone_pkg is