Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17252 Discussions

Trying to understand on-chip memory

BobA
Novice
1,639 Views

Hi. I'm using the ROM: 1-PORT in the IP Catalog. I've been unable to find a code example of accessing that on-chip memory. I hope someone here can help.

The IP Catalog wizard generates code for a module:

module rom (
address,
clock,
q);
	input	[10:0]  address;
	input	  clock;
	output	[7:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
	tri1	  clock;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

	wire [7:0] sub_wire0;
	wire [7:0] q = sub_wire0[7:0];

	altsyncram	altsyncram_component (
				.address_a (address),
				.clock0 (clock),
				.q_a (sub_wire0),
				.aclr0 (1'b0),
				.aclr1 (1'b0),
				.address_b (1'b1),
				.addressstall_a (1'b0),
				.addressstall_b (1'b0),
				.byteena_a (1'b1),
				.byteena_b (1'b1),
				.clock1 (1'b1),
				.clocken0 (1'b1),
				.clocken1 (1'b1),
				.clocken2 (1'b1),
				.clocken3 (1'b1),
				.data_a ({8{1'b1}}),
				.data_b (1'b1),
				.eccstatus (),
				.q_b (),
				.rden_a (1'b1),
				.rden_b (1'b1),
				.wren_a (1'b0),
				.wren_b (1'b0));
	defparam
		altsyncram_component.address_aclr_a = "NONE",
		altsyncram_component.clock_enable_input_a = "BYPASS",
		altsyncram_component.clock_enable_output_a = "BYPASS",
`ifdef NO_PLI
		altsyncram_component.init_file = "G:/My Drive/microcode1.rif"
`else
		altsyncram_component.init_file = "G:/My Drive/microcode1.hex"
`endif
,
		altsyncram_component.intended_device_family = "MAX 10",
		altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
		altsyncram_component.lpm_type = "altsyncram",
		altsyncram_component.numwords_a = 2048,
		altsyncram_component.operation_mode = "ROM",
		altsyncram_component.outdata_aclr_a = "NONE",
		altsyncram_component.outdata_reg_a = "CLOCK0",
		altsyncram_component.widthad_a = 11,
		altsyncram_component.width_a = 8,
		altsyncram_component.width_byteena_a = 1;


endmodule

 

and then I instantiate in my own Verilog code:

 

   rom rom_inst (.address ( address ), .clock ( clock ), .q ( q ));

What I don't understand is what q should be. Should it be 'reg [7:0] q;' or 'wire [7:0] q;'?

 

It seems to me, it would have to be a reg, especially since we're using a clock to fetch memory. But look at lines 12-18 in the generated module:

12	wire [7:0] sub_wire0;
13	wire [7:0] q = sub_wire0[7:0];
14
15	altsyncram	altsyncram_component (
16				.address_a (address),
17				.clock0 (clock),
18				.q_a (sub_wire0),

It's using a wire to receive the memory contents! I would've thought that, inside altsyncram, there's an always block that, on the rising edge of clock0, reads the memory contents into a register. But a wire makes me think it's just combinational.

 

And what does that mean for my code? Do I need an always block clocking the rom module's q output into a register? And when should I do that? I assume I cannot trust that q has valid data on it, at the same clock rising edge that triggered the memory read. I need to wait for the memory access time, right?

 

Thank you for your help.

Labels (1)
0 Kudos
1 Solution
RichardTanSY_Altera
1,582 Views

You should declare the output q as a wire, because the ROM module already registers the output internally.

You do not need to add your own always @(posedge clk) just to capture q, unless you want to add pipeline stages or synchronize it further.

 

The altsyncram component is configured with:

 

altsyncram_component.outdata_reg_a = "CLOCK0"

 

This means the output is registered on the rising edge of clock0 inside the IP — so the ROM fetches data synchronously, with output changes one clock cycle after the address is applied.

 

So even though q is declared as a wire, it is driven by a register inside the ROM IP. That’s why your code can simply declare:

 

wire [7:0] q;
rom rom_inst (
 .address (address),
 .clock (clock),
 .q  (q)
);

And it should works exactly as a synchronous ROM should.

So yes — you're absolutely right: you cannot use q on the same clock edge that you apply the address. You need to wait one clock cycle.

 

Regards,

Richard Tan

 

View solution in original post

5 Replies
RichardTanSY_Altera
1,583 Views

You should declare the output q as a wire, because the ROM module already registers the output internally.

You do not need to add your own always @(posedge clk) just to capture q, unless you want to add pipeline stages or synchronize it further.

 

The altsyncram component is configured with:

 

altsyncram_component.outdata_reg_a = "CLOCK0"

 

This means the output is registered on the rising edge of clock0 inside the IP — so the ROM fetches data synchronously, with output changes one clock cycle after the address is applied.

 

So even though q is declared as a wire, it is driven by a register inside the ROM IP. That’s why your code can simply declare:

 

wire [7:0] q;
rom rom_inst (
 .address (address),
 .clock (clock),
 .q  (q)
);

And it should works exactly as a synchronous ROM should.

So yes — you're absolutely right: you cannot use q on the same clock edge that you apply the address. You need to wait one clock cycle.

 

Regards,

Richard Tan

 

FvM
Honored Contributor II
1,573 Views

Hi,
small correction to above description.

Internal block RAM doesn't necessarily register RAM/ROM output. It always registers memory address, write data and related control signals, output register is optional and controlled by parameter outdata_reg_a/b which can be UNREGISTERED, CLOCK0 or CLOCK1.

Respectively RAM/ROM output has either 1 or 2 clock cycles latency.

Using "wire" to connect memory output port q should work for both configurations.

Regards
Frank

RichardTanSY_Altera
1,484 Views

Hi @BobA ,

 

Do you have further inquiries regarding this case?

 

Regards,

Richard Tan

 

0 Kudos
BobA
Novice
1,473 Views

Do you have further inquiries regarding this case?

No, I think I get it. Thanks.

0 Kudos
RichardTanSY_Altera
1,431 Views

Thank you for the confirmation.


Now, I will transitioning this thread to community support. If you have any further questions or concerns, please don't hesitate to reach out. Please login to https://supporttickets.intel.com/s/?language=en_US , view details of the desire request, and post a feed/response within the next 15 days to allow me to continue to support you. After 15 days, this thread will be transitioned to community support.

The community users will be able to help you on your follow-up questions.

 

Thank you and have a great day!

 

Best Regards,

Richard Tan


0 Kudos
Reply