Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
1,523 Views

Multiple RAM with different mif file

Hi all, 

 

I am doing a project to design 128 processors with a RAM in each processor. Every thing is the same but the initial data in the RAM. The design of the RAM is using the on chip memory. I know I can use the Quartus Wizard to initialize each RAM with a .mif file. But I have two questions here: 

 

1. Is there any other way to initialize the RAM with .mif file? If I use the wizard, I need to do 128 times, which is a big amount of work. 

 

2. Since the only difference is the initial data of the RAM among the processors, I am wondering if I can make a single entity with multiple architectures or I need to make a VHDL file for each processors? Which way is better? 

 

Many thanks for the help.
0 Kudos
10 Replies
Altera_Forum
Honored Contributor I
136 Views

use the ram unwrapped (expose its generics) and map at top level. 

for 128 names you can use a two dimensional array of (1:128) x string length then use a loop to map the mif name for each ram
Altera_Forum
Honored Contributor I
136 Views

thank you for your help. I am new to VHDL, can you explain a little bit more? 

 

I am not quite sure what is an unwrapped ram? I know how to port map the ram at top level module but I am not sure how to map the mif name to them? 

 

Thanks.
Altera_Forum
Honored Contributor I
136 Views

you will find the interface of original ram sleeping inside the ram.vhd in the generation folder, copy/paste it and use that as your ram module, ignore the vhdl wrapper generated by the tool. 

 

for 128 names, you can map 128 times directly if you don't get tired. but some of us will declare an array of 128 x string (=length of file name) and initialise it with 128 names then use a loop (1:128) to call the ram once only, each time mapping one element of file name array to ram. 

I personally used a string without initialisation but added a number to end of each file name and used something like & to concatenate the string when called up in the loop.
Altera_Forum
Honored Contributor I
136 Views

Thank you for your help. 

 

Did you means after generate a general ram file called ram.vhd via wizard, and copy the port to the top level module as a component. Then some how map the mif file to the corresponding ram in the top level module?
Altera_Forum
Honored Contributor I
136 Views

 

--- Quote Start ---  

Thank you for your help. 

 

Did you means after generate a general ram file called ram.vhd via wizard, and copy the port to the top level module as a component. Then some how map the mif file to the corresponding ram in the top level module? 

--- Quote End ---  

 

 

No, read that ram.vhd and it calls up another ram (in verilog or tdf...) but its interface called up is there. (just like surgeon opening abdomen!, taking out what he needs for biopsy)
Altera_Forum
Honored Contributor I
136 Views

How different are the init files? Are they mostly the same with a few bytes different that could be handled at startup? If not, I think what kaz is suggesting is to look into the file the Wizard generates and modify it. For example, I used the wizard to generate a RAM called ram_test and in the directory chosen for the core it created a file called ram_test.vhd which acts as a wrapper for the altsyncram megafunction on line 46: 

 

 

-- megafunction wizard: %RAM: 1-PORT% -- GENERATION: STANDARD -- VERSION: WM1.0 -- MODULE: altsyncram -- ============================================================ -- File Name: ram_test.vhd -- Megafunction Name(s): -- altsyncram -- -- Simulation Library Files(s): -- altera_mf -- ============================================================ -- ************************************************************ -- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! -- -- 16.1.2 Build 203 01/18/2017 SJ Standard Edition -- ************************************************************ LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY altera_mf; USE altera_mf.altera_mf_components.all; ENTITY ram_test IS PORT ( address : IN STD_LOGIC_VECTOR (7 DOWNTO 0); clock : IN STD_LOGIC := '1'; data : IN STD_LOGIC_VECTOR (12 DOWNTO 0); wren : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR (12 DOWNTO 0) ); END ram_test; ARCHITECTURE SYN OF ram_test IS SIGNAL sub_wire0 : STD_LOGIC_VECTOR (12 DOWNTO 0); BEGIN q <= sub_wire0(12 DOWNTO 0); altsyncram_component : altsyncram GENERIC MAP ( clock_enable_input_a => "BYPASS", clock_enable_output_a => "BYPASS", init_file => "./cores/rom_test_001.mif", intended_device_family => "MAX 10", lpm_hint => "ENABLE_RUNTIME_MOD=NO", lpm_type => "altsyncram", numwords_a => 256, operation_mode => "SINGLE_PORT", outdata_aclr_a => "NONE", outdata_reg_a => "CLOCK0", power_up_uninitialized => "FALSE", read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", widthad_a => 8, width_a => 13, width_byteena_a => 1 ) PORT MAP ( address_a => address, clock0 => clock, data_a => data, wren_a => wren, q_a => sub_wire0 ); END SYN;  

 

On line 50 there is a generic named init_file mapped to the hardwired string "./cores/rom_test_001.mif" I chose in the wizard. You need to modify their wrapper so ram_test entity has a generic init_file string variable that you can set in a generate loop in you main code. That's alot of files though.
Altera_Forum
Honored Contributor I
136 Views

Thank you for your help! 

 

I am not sure if I understand this fully. Correct me if I am wrong. 

 

Suppose these 128 RAMs are all true dual port RAM. Then the set up for a True Dual Port RAM in altsyncram will be something look like following  

altsyncram_component : altsyncram GENERIC MAP ( address_reg_b => "CLOCK0", clock_enable_input_a => "BYPASS", clock_enable_input_b => "BYPASS", clock_enable_output_a => "BYPASS", clock_enable_output_b => "BYPASS", indata_reg_b => "CLOCK0", -- init_file => "init_data_1.mif", -- this line state the initial file of the ram intended_device_family => "Stratix V", lpm_type => "altsyncram", numwords_a => 128, numwords_b => 128, operation_mode => "BIDIR_DUAL_PORT", outdata_aclr_a => "NONE", outdata_aclr_b => "NONE", outdata_reg_a => "CLOCK0", outdata_reg_b => "CLOCK0", power_up_uninitialized => "FALSE", ram_block_type => "M20K", read_during_write_mode_mixed_ports => "DONT_CARE", read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ", widthad_a => 7, widthad_b => 7, width_a => 32, width_b => 32, width_byteena_a => 1, width_byteena_b => 1, wrcontrol_wraddress_reg_b => "CLOCK0" ) PORT MAP ( address_a => address_a, address_b => address_b, clock0 => clock, data_a => data_a, data_b => data_b, rden_a => rden_a, rden_b => rden_b, wren_a => wren_a, wren_b => wren_b, q_a => sub_wire0, q_b => sub_wire1 );  

 

If I want to make these map each ram to it I need to do something like 

RAM_1 : altsyncram GENERIC MAP ( init_file => "init_data_1.mif" ) PORT MAP ( -- ports mapping ...... );  

 

Is that what you mean? 

 

And I am not sure how to use loop to finish this. Since in my design, the top level module will be 128 processor connected together, and the RAM is located in each processor module. (Which I think is the lower level module). 

 

And this leads to my Question 2 in the main post. Since each processor is the identical but the initial data of the ram, what is the better way to make it? One entity with multiple architectures?  

 

Thanks again for your help.
Altera_Forum
Honored Contributor I
136 Views

Not exactly. You've commented out the init_file and the defaults for altsyncram differ from what you want.  

 

It's helpful to go to the Altera libs and see what they are doing. On my machine, altsyncram is in: 

 

"C:\intelFPGA\16.1\quartus\libraries\vhdl\altera_mf\altera_mf_components.vhd

 

If using a wrapper such as the wizard generates, you just want to make the init_file a variable you can set. See lines that say "LOOK HERE". 

 

LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY altera_mf; USE altera_mf.altera_mf_components.all; ENTITY ram_test IS -- LOOK HERE add the following generic. GENERIC ( my_init_file : string := "UNUSED" ) PORT ( address : IN STD_LOGIC_VECTOR (7 DOWNTO 0); clock : IN STD_LOGIC := '1'; data : IN STD_LOGIC_VECTOR (12 DOWNTO 0); wren : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR (12 DOWNTO 0) ); END ram_test; ARCHITECTURE SYN OF ram_test IS SIGNAL sub_wire0 : STD_LOGIC_VECTOR (12 DOWNTO 0); BEGIN q <= sub_wire0(12 DOWNTO 0); altsyncram_component : altsyncram GENERIC MAP ( clock_enable_input_a => "BYPASS", clock_enable_output_a => "BYPASS", init_file => my_init_file, -- LOOK HERE my_init_file passed in from ram_test instantiation in your main code. intended_device_family => "MAX 10", lpm_hint => "ENABLE_RUNTIME_MOD=NO", lpm_type => "altsyncram", numwords_a => 256, operation_mode => "SINGLE_PORT", outdata_aclr_a => "NONE", outdata_reg_a => "CLOCK0", power_up_uninitialized => "FALSE", read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", widthad_a => 8, width_a => 13, width_byteena_a => 1 ) PORT MAP ( address_a => address, clock0 => clock, data_a => data, wren_a => wren, q_a => sub_wire0 ); END SYN; 

 

So you can use the megawizard to generate a "template" but then "unwrap" it as kaz says and make things variables that the wizard hardwires. 

 

Then when you instantiate ram_test (in my example), pass in the desired mif file name for each of the 128 cpu's in the generic map of each instance. If you use a simple pattern (eg file_001.mif, file_002.mif ...) you should be able to do it in a generate loop with dynamically generated file names. If you have not used VHDL generate, you should research that a bit on your own. 

 

Some people would prefer to get rid of the ram_test wrapper altogether and just instantiate the altsyncram directly in their main code. Again, using your 128 different file name for init_file. That may be what you were suggesting. Just take the altsyncram instantiation generated by the wizard but make init_file a variable that you set in a generate loop. In your example: 

 

CPU_LIST for i in 1 to 128 generate CPU_RAM_I : altsyncram GENERIC MAP ( address_reg_b => "CLOCK0", clock_enable_input_a => "BYPASS", clock_enable_input_b => "BYPASS", clock_enable_output_a => "BYPASS", clock_enable_output_b => "BYPASS", indata_reg_b => "CLOCK0", init_file => GetInitFileName(i), -- LOOK HERE write function to generate file name for cpu 'i' intended_device_family => "Stratix V", lpm_type => "altsyncram", numwords_a => 128, numwords_b => 128, operation_mode => "BIDIR_DUAL_PORT", outdata_aclr_a => "NONE", outdata_aclr_b => "NONE", outdata_reg_a => "CLOCK0", outdata_reg_b => "CLOCK0", power_up_uninitialized => "FALSE", ram_block_type => "M20K", read_during_write_mode_mixed_ports => "DONT_CARE", read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ", widthad_a => 7, widthad_b => 7, width_a => 32, width_b => 32, width_byteena_a => 1, width_byteena_b => 1, wrcontrol_wraddress_reg_b => "CLOCK0" ) PORT MAP ( address_a => address_a, address_b => address_b, clock0 => clock, data_a => data_a, data_b => data_b, rden_a => rden_a, rden_b => rden_b, wren_a => wren_a, wren_b => wren_b, q_a => sub_wire0, q_b => sub_wire1 ); end generate;  

 

I have not actually compiled the above code, so don't hold me to minor syntax errors.  

 

I think this implicitly answers question 2; one entity and one architecture and a generic to load the correct data file. I've actually never used multiple architectures.  

 

However, I doubt this whole approach is a good idea. I assume your cpu's have registers that need initialized along with RAM that needs a program loaded. The usual way to do this is to have a First Stage Boot Loader (FSBL) that goes and reads init data from a fixed address in user FLASH and then passes off to a second stage boot loader to load user programs (you may not need that). The bootstrap boot loader is in hardware in the CPU but you could probably share a single one across all the CPU's.  

 

Of course, the mif files are strored in FLASH, but they will be part of your configuration stream. So every time you change the CPU firmware, you're going to have to resynthesize your whole system instead of just updating a user area of FLASH. This will make development especially cumbersome not to mention future upgrades.  

 

 

I guess I'm the king of unsolicited suggestions this week. Only you know your system requirements.
Altera_Forum
Honored Contributor I
136 Views

Thank you VERY MUCH for your help! This is extremely helpful!

Altera_Forum
Honored Contributor I
136 Views

I did find this that might be helpful: 

 

https://www.altera.com/support/support-resources/knowledge-base/solutions/rd12062004_8707.html (https://www.altera.com/support/support-resources/knowledge-base/solutions/rd12062004_8707.html

 

It shows "How can I change the memory initialization date without performing a full compilation in the Quartus". So I was wrong about having to resynthesize each time if you change your code and your way via mif files may work just fine. However, you still need to run the Assembler and download the bitstream and it might make field upgrades difficult.
Reply