Thanks for the ideas, guys!
What I found so far, it mostly comes down mostly to coding style, whether blockRAM is implemented or not.
Trying to force blockRAM implementation with following code didn't work, Quartus does it's thing and doesn't care....
type lcdram16x8 is array (255 downto 0) of std_logic_vector (7 downto 0);
signal lcd16x8: lcdram16x8;
attribute ramstyle : string;
attribute ramstyle of lcd16x8 : signal is "M4K";
Quartus doesn't like conditional blockRAM inside if/case/... statements, what works is to read blockRAM directly and use the result conditonally.
I.e: Read "LCD_rom_out <= lcd16x8(to_integer(unsigned(LCD_charcounter)));" directly without conditonal statements.
And put "LCD_data <= LCD_rom_out;" inside conditional statements.
Code that gets Block RAM implemented:
process (t20us_SQW) --LCD write
begin
if (t20us_SQW'Event and t20us_SQW = '1') then
--if (f10Hz_SQW'Event and f10Hz_SQW = '1') then
LCD_rom_out <= lcd16x8(to_integer(unsigned(LCD_charcounter)));
if (LCD_enable_SQW = '1') then
LCD_enable_SQW <= LCD_enable_SQW XOR '1';
if (LCD_init = '1') then --initial mode
--LCD_charcounter <= LCD_charcounter+'1';
case LCD_charcounter(5 downto 0) is
when "000000" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00111000"; --001ABC00, A=interface lenght, B=Number of display lines, C=Font selection
LCD_charcounter <= LCD_charcounter+'1';
when "000001" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00001100"; --00001ABC, A=Display ON=1/OFF=0, Cursor ON=1/OFF=0, Blinking Cursor character ON=1/OFF=0
LCD_charcounter <= LCD_charcounter+'1';
when "000010" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00000110"; --000001AB, A=Display write address increment ON=1/OFF=0, B=Display shift/rolling ON=1/OFF=0
LCD_init <='0'; --initialisation complete
LCD_charcounter <= "000000" ;
when "111111" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00000010"; --Cursor return to start
LCD_init <='1'; --initialisation restart
LCD_charcounter <= "000000" ;
when others => LCD_RS <='1';
LCD_charcounter <= "000000" ;
end case;
elsif (LCD_init = '0') then --initial mode
case LCD_charcounter(5 downto 0) is
when "111111" => LCD_init <='1'; --initialisation restart
--LCD_charcounter <= "000000" ;
when others => LCD_RS <='1';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <= LCD_rom_out;
LCD_charcounter <= LCD_charcounter+'1';
end case;
--ROM_addr <= LCD_dcounter;
--LED5 <= '1';
--LCD_data <="10101010";
--rom_counter <= rom_counter+'1';
--rom256x8_out <= rom256x8(to_integer(unsigned(LCD_dcounter)));
--LCD_data <= rom256x8(to_integer(unsigned(LCD_dcounter)));
end if;
else
LCD_enable <='0' ;
LCD_enable_SQW <= LCD_enable_SQW XOR '1';
end if;
end if;
end process;
If you want to read the blockRAM directly "LCD_data <= lcd16x8(to_integer(unsigned(LCD_charcounter)));" inside conditional statement structure, it gets implemented in huge logic block. FAIL!
process (t20us_SQW) --LCD write
begin
if (t20us_SQW'Event and t20us_SQW = '1') then
--if (f10Hz_SQW'Event and f10Hz_SQW = '1') then
--LCD_rom_out <= lcd16x8(to_integer(unsigned(LCD_charcounter)));
if (LCD_enable_SQW = '1') then
LCD_enable_SQW <= LCD_enable_SQW XOR '1';
if (LCD_init = '1') then --initial mode
--LCD_charcounter <= LCD_charcounter+'1';
case LCD_charcounter(5 downto 0) is
when "000000" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00111000"; --001ABC00, A=interface lenght, B=Number of display lines, C=Font selection
LCD_charcounter <= LCD_charcounter+'1';
when "000001" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00001100"; --00001ABC, A=Display ON=1/OFF=0, Cursor ON=1/OFF=0, Blinking Cursor character ON=1/OFF=0
LCD_charcounter <= LCD_charcounter+'1';
when "000010" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00000110"; --000001AB, A=Display write address increment ON=1/OFF=0, B=Display shift/rolling ON=1/OFF=0
LCD_init <='0'; --initialisation complete
LCD_charcounter <= "000000" ;
when "111111" => LCD_RS <='0';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <="00000010"; --Cursor return to start
LCD_init <='1'; --initialisation restart
LCD_charcounter <= "000000" ;
when others => LCD_RS <='1';
LCD_charcounter <= "000000" ;
end case;
elsif (LCD_init = '0') then --initial mode
case LCD_charcounter(5 downto 0) is
when "111111" => LCD_init <='1'; --initialisation restart
--LCD_charcounter <= "000000" ;
when others => LCD_RS <='1';
LCD_RW<='0' ;
LCD_enable<='1' ;
LCD_data <= lcd16x8(to_integer(unsigned(LCD_charcounter)));
--LCD_data <= LCD_rom_out;
LCD_charcounter <= LCD_charcounter+'1';
end case;
--ROM_addr <= LCD_dcounter;
--LED5 <= '1';
--LCD_data <="10101010";
--rom_counter <= rom_counter+'1';
--rom256x8_out <= rom256x8(to_integer(unsigned(LCD_dcounter)));
--LCD_data <= rom256x8(to_integer(unsigned(LCD_dcounter)));
end if;
else
LCD_enable <='0' ;
LCD_enable_SQW <= LCD_enable_SQW XOR '1';
end if;
end if;
end process;
Conditionally writing BlockRAM should work similarly, by evaluating the data written, store it in a register and then write if direcly in the next cycle, without using any conditional statements
Smallest Cyclone1 (EP1C3T144) has about 3000LUTs and 60kBit BlockRAM, more than plentiful for small projects, especially if you are used to CPLDs
Somewhat hard to fill all that logic in small projects, if not wasted as memory. Also like the facts that it's still TQFP and thereby easy solderable/exchangeable if fried.