I have a problem with translating VHDL to Verilog.
It's part of my source code on VHDL.
With I/O I somehow understood, but have some problems to translate this string
ib1 <= std_logic_vector(to_unsigned(i,ib1'length));
to verilog?
COMPONENT GenerateModel
PORT(
ib1 : IN std_logic_vector(3 downto 0);
);
END COMPONENT;
--Inputs
signal ib1 : std_logic_vector(3 downto 0) := (others => '0');
BEGIN
uut: GenerateModel PORT MAP (
ib1 => ib1,
);
process
begin
for i in 0 to 15 loop
ib1 <= std_logic_vector(to_unsigned(i,ib1'length));
wait for 10 ns;
end loop;
end process;
end;
To extend into Verilog from Paebbels' comment, the line you are looking at does an explicit conversion from the type of the loop variable i to the port variable ib1. In Verilog, that explicit conversion is not needed, you can just assign the port variable directly. So, for example (in Verilog IEEE 1364-1995 compatible):
integer i;
...
for (i = 0; i < 16; i = i + 1) begin
ib1 = i; // <-- The line
#10; // -- Assume 1 step is 1 ns, can specific timescale if needed
end
If you want, you can even loop through the variable directly if its of type reg (ie, not a net):
for (ib1 = 0; ib1 < 15; ib1 = ib1 + 1) begin
#10;
end
#10;
[Note that as Greg mentioned, you need to be sure you dont create an infinite loop as if ib1 is 4-bits wide, it will always be less than 16, thus I fixed the example above to loop until ib1 is 15 (4'b1111)]
Related
I have a question related to the implementation of a clocked SRAM memory which is is supposed to store data written by user and then display the memory content. In addition, I created a module named display which eases the reading process so that there is no need to provide the memory address from which data should be extracted, by incrementing a register after each reading. Nevertheless, when I simulate the circuit, I cannot see the correct output; thus, when I read the memory, I notice some undefined output sequences. I posted the corresponding code below.
//stores output data
module sram_1port_data(
input clk,//clocked memory
input wr_en,//when high, data is written, otherwise is read
input [15:0] address_in,//suppose timer cannout count more than 13ms
input [3:0] wr_data,//memory does not sotre values greater than 13(ms)
output reg [3:0] rd_data
);
reg [3:0] memory [2 ** 15 - 1 : 0];
always #(posedge clk) begin
if(wr_en) memory[address_in] <= wr_data;
else rd_data <= memory[address_in];
end
endmodule
//display interfacedesigned for the second memory
module display(
input clk,
input wr_en,
input [15:0] address_in,
input [3:0] wr_data,
output [3:0] rd_data
);
reg [15:0] pointer,address;
initial pointer = 16'd0;
sram_1port_data i0(.clk(clk),.wr_en(wr_en),.address_in(address),.wr_data(wr_data),.rd_data(rd_data));
always #(posedge clk) begin
if(!wr_en) begin
address <= pointer;
pointer <= pointer + 1;
end
else address <= address_in;
end
endmodule
//tb for display
module display_tb(
output reg clk,
output reg wr_en,
output reg [15:0] address_in,
output reg [3:0] wr_data,
output [3:0] rd_data
);
display i0(.clk(clk),.wr_en(wr_en),.address_in(address_in),.wr_data(wr_data),.rd_data(rd_data));
initial $dumpvars(0,display_tb);
initial begin
clk = 1'd1;
repeat (2000)
#100 clk = ~clk;
end
initial begin
wr_en = 1'd1;
#100000 wr_en = 1'd0;
end
integer i;
initial begin
wr_data = 3'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 wr_data = i;
end
end
initial begin
address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200 address_in = i;
end
end
endmodule
When I look at waveforms, I see that rd_data is unknown (X) on every other read. Looking at an internal address signal, I see that the unknowns are only for even addresses. Early in the simulation, you are only writing to even addresses.
In your testbench, you are using the same variable (i) in 2 different for loops. In your 2nd for loop, use a different variable name (j, for example):
integer j;
initial begin
address_in = 16'd0;
for(j = 1;j < 500;j = j + 1) begin
#200 address_in = j;
end
end
Now, all reads have known values because it writes to all addresses (even and odd).
You could also set the address inside the same for loop as the write data. This is likely a better approach in this case.
initial begin
wr_data = 3'd0;
address_in = 16'd0;
for(i = 1;i < 500;i = i + 1) begin
#200;
wr_data = i;
address_in = i;
end
end
I have an output txtfile with some float numbers and I like to print in different formats, y try with:
FormatFloat('00000;000.0;00.00', val)
FormatFloat('00.00;000.0;00000', val)
But I take wrong outputs. What I need is:
If val < 10 then output like '00.00'
If 10 < val < 100 then output like '000.0'
If val > 100 then output like '00000'
It's a huge amount of float values, so, I need a low processing solution and I think more conditionals will slow down the application. ¿Any advice?
Thank you
Using conditional tests to sort the values into separate outputs is not going to affect performance in a significant way. The format process is far more elaborate. One important thing about optimization is to only walk that path if you can measure a performance hit in the actual code.
if (val < 10) then
s := FormatFloat('00.00',val)
else
if (val < 100) then
s := FormatFloat('000.0',val)
else
s := FormatFloat('00000',val);
Also consider using the thread-safe FormatFloat with a supplied FormatSettings variable.
I suppose that conditionals would work faster, but consider this sketch (care about out-of-range values):
const
FormatString: array[-1..2] of string = ('0.000', '0.00', '0.0', '0');
var
x: Double;
i: integer;
begin
x := 0.314;
for i := 1 to 4 do begin
Memo1.Lines.Add(FormatFloat(FormatString[Floor(Log10(x))], x));
x := x * 10;
end;
0.314
3.14
31.4
314
I need to get some data from a module I was given, but I don't know if it is even possible or how to approach the problem.
Is it possible to get information from another module if that module doesn't have an entity map? It only has a generic with TIME statements.
Is it at all possible to get anything out of this module?
It writes to a memory, could I pull things out of that?
This is the file I have.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.STD_LOGIC_ARITH.all;
use STD.TEXTIO.all;
use IEEE.STD_LOGIC_TEXTIO.all;
entity MIPS is
generic (
MEM_DLY : TIME := 0.5 ns;
CYC_TIME: TIME := 2 ns
);
end entity MIPS;
architecture MIPS of MIPS is
signal PC : STD_LOGIC_VECTOR ( 31 downto 0 ) := X"0000_0010";
signal READ_DATA2 : STD_LOGIC_VECTOR ( 31 downto 0 ) := ( others => '0');
signal HUH : BIT_VECTOR ( 31 downto 0 );
signal HUHINS : STRING ( 1 to 25 );
signal INSTRUC : STD_LOGIC_VECTOR ( 31 downto 0 );
signal M_DATA_IN : STD_LOGIC_VECTOR ( 31 downto 0 ) := ( others => 'Z');
signal M_DATA_OUT : STD_LOGIC_VECTOR ( 31 downto 0 ):= ( others => 'Z');
signal M_ADDR : STD_LOGIC_VECTOR ( 11 downto 0 ) := ( others => '0');
signal CLK : STD_LOGIC := '0';
signal MEMREAD : STD_LOGIC := '0';
signal M_DATA_WHEN : STD_LOGIC := '0';
signal MEMWRITE : STD_LOGIC := '0';
signal CYCLE : INTEGER := 1;
begin
CLOCK_PROC:
process
begin
CLK <= '1';
wait for CYC_TIME/2;
CLK <= '0';
wait for CYC_TIME/2;
CYCLE <= CYCLE + 1;
end process;
TEST_PC_PROC:
process ( CLK ) is
begin
if RISING_EDGE ( CLK ) then
PC <= PC + 4;
end if;
end process;
INSTR_MEM_PROC:
process ( PC ) is -- make subject only to address
type INSTR_STR_ARY is array ( 0 to 1023 ) of STRING ( 1 to 25 );
variable MEMSTRR : INSTR_STR_ARY:=(others => " ");
type MEMORY is array ( 0 to 1023 ) of BIT_VECTOR ( 31 downto 0 );
variable MEM : MEMORY := ( others => X"0000_0000");
variable IADDR : INTEGER; -- integer for address
variable DTEMP : BIT_VECTOR ( 31 downto 0 );
variable INIT : INTEGER := 0; -- when to initialize...
file IN_FILE : TEXT open READ_MODE is "instr_mem.txt";
variable BUF : LINE;
variable ADR_STR : STD_LOGIC_VECTOR ( 31 downto 0 );
variable TADR : INTEGER;
variable TDATA : STD_LOGIC_VECTOR ( 31 downto 0 );
variable BDATA : BIT_VECTOR ( 31 downto 0 );
variable STR_ING : STRING ( 1 to 25 );
begin
if INIT = 0 then
while not (ENDFILE ( IN_FILE )) loop
READLINE ( IN_FILE, BUF );
HREAD ( BUF, ADR_STR ); -- get the address on the line
TADR := CONV_INTEGER ( ADR_STR (14 downto 2));
HREAD ( BUF, TDATA ); -- get the data on the line
BDATA := To_bitvector (TDATA);
MEM ( TADR ) := BDATA; -- put into memory
for J in 1 to 25 loop
STR_ING(J) := ' ';
end loop;
READ ( BUF, STR_ING ); -- get instruction string
MEMSTRR ( TADR ) := STR_ING;
report "iteration of loop";
end loop;
INIT := 1; -- when all data in, set INIT to 1;
end if; -- end of INIT check
IADDR := CONV_INTEGER ( PC ( 14 downto 2 ));
HUH <= MEM ( IADDR );
INSTRUC <= To_StdLogicVector ( MEM ( IADDR )) after MEM_DLY;
HUHINS <= MEMSTRR ( IADDR );
report "should hit INSTRUC";
end process;
M_DATA_IN_STMT:
M_DATA_IN <= READ_DATA2 ;
-- The following is the magic process
-- User must supply:
-- M_ADDR - memory address (data memory) as a 12 bit STD_LOGIC_VECTOR
-- Remember the M_ADDR is a WORD address
-- M_DATA_IN - value going to memory from hardware (data path)
-- Remember that this is 32 bit STD_LOGIC_VECTOR, user supplied
-- READ_DATA2 - this is to be replaced by user's sourceof info for memory
DATA_MEMORY_PROCESS: -- name of process ...
process ( M_ADDR, CLK, MEMREAD ) is -- Sens: M_ADDR, CLK, MEMREAD
file IN_FILE: TEXT open READ_MODE is "data_mem_init.txt"; -- initial data
file OUT_FILE: TEXT open WRITE_MODE is "mem_trans.txt"; -- results
variable BUF : LINE; -- declare BUF as LINE
variable TVAL : STD_LOGIC_VECTOR ( 31 downto 0 ); -- var for temp value
variable TADRHEX : STD_LOGIC_VECTOR ( 31 downto 0 ); -- var for address
variable TADR : INTEGER; -- address as integer
type MEM_TYPE is array ( 0 to 1023 ) of STD_LOGIC_VECTOR ( 31 downto 0 );
variable THE_MEMORY : MEM_TYPE := ( others => X"00000000" ); -- the memory
variable FIRST : BOOLEAN := TRUE; -- flag for first time thru
constant STR : STRING ( 1 to 3 ) := " "; -- 3 spaces - for printing
constant WR_STR : STRING ( 1 to 3 ) := "W "; -- for write
constant RD_STR : STRING ( 1 to 3 ) := "R "; -- for read
variable TSTR2 : STRING ( 1 to 29 ); -- to create a string
type MEMSTR_TYPE is array ( 0 to 1023 ) of STRING ( 1 to 29 ); --
variable INSTRS : MEMSTR_TYPE;
begin -- start here
if FIRST then -- first time thru,
while FIRST loop -- loop on data available - until
if not ( ENDFILE ( IN_FILE )) then -- end of file shows up
READLINE(IN_FILE, BUF); -- read a line from file,
HREAD(BUF, TADRHEX); -- get address from BUF
TADR := CONV_INTEGER ( TADRHEX ); -- turn it into integer
HREAD(BUF, TVAL); -- next, get value from BUF
THE_MEMORY(TADR/4) := TVAL; -- put TVAL into the memory
else -- the 'else' is for end of file
FIRST := FALSE; -- EOF shows up - set FIRST false
end if;
end loop; -- where loop ends...
end if; -- where if FIRST ends ...
if MEMREAD = '1' then -- now, memory function 'read'
M_DATA_OUT <= THE_MEMORY ( CONV_INTEGER ( M_ADDR ) / 4 ); -- get val from
M_DATA_WHEN <= not M_DATA_WHEN; -- and invert M_DATA_WHEN
else -- if not MEMREAD,
M_DATA_OUT <= ( others => 'Z' ); -- set memory out to 'Z's
end if;
if RISING_EDGE ( CLK ) then -- on clock edge...
if MEMREAD = '1' then -- if MEMREAD asserted,
TADR := CONV_INTEGER ( M_ADDR ) / 4; -- set TADR to address as int
TVAL := THE_MEMORY ( TADR ); -- and get contents to TVAL
WRITE (BUF, RD_STR); -- then build BUF; put read indi
HWRITE (BUF, M_ADDR); -- and the address
WRITE (BUF, STR); -- some spaces
HWRITE (BUF, TVAL); -- and the value
WRITE (BUF, STR); -- more spaces
WRITE (BUF, NOW); -- current simulation time
WRITELINE (OUT_FILE, BUF); -- and send line to file.
elsif MEMWRITE = '1' then -- if not read, but it is write
TADR := CONV_INTEGER ( M_ADDR ) / 4; -- set TADR to address as int
TVAL := M_DATA_IN; -- set TVAL as data in value
WRITE (BUF, WR_STR); -- start buffer with write indi
HWRITE (BUF, M_ADDR); -- then the address
WRITE (BUF, STR); -- then some spaces
HWRITE (BUF, TVAL); -- and the value written
WRITE (BUF, STR); -- still more spaces
WRITE (BUF, NOW); -- simulation time
WRITELINE (OUT_FILE, BUF); -- and send line to file
THE_MEMORY ( CONV_INTEGER ( M_ADDR ) / 4) := M_DATA_IN;
-- and finally, value to the mem
end if;
end if;
end process;
end architecture MIPS;
The code you presented simulates the memories that your MIPS processor will interact with - a program memory and a data memory.
Your MIPS will interact with the program memory by providing a value for PC; the corresponding instruction will be handed to your CPU on signal INSTRUCT. You'll probably delete the lines corresponding to the TEST_PC_PROC process, since the actual PC value will come from the MIPS. The program to be run by the CPU is given in file data_mem_init.txt. This program memory is asynchronous.
Your MIPS will interact with the data memory through signals M_ADDR, M_DATA_OUT, M_DATA_IN, and MEMREAD. To read data, your CPU will set M_ADDR and MEMREAD=1, and provide the address in M_ADDR. The given code will set M_DATA_OUT with the requested data. To write data, you will set M_DATA_IN or READ_DATA2 (or replace READ_DATA2 with a signal of your choice). The data will be written on the rising edge of CLK.
Don't be distracted by the WRITE/HWRITE calls, they just keep a log on file mem_trans.txt.
IMO, this interface is much more complicated than it needed to be. You're probably better or if you keep your MIPS implementation in totally separate files, and just add the signals needed to interact with this model to its ports list.
It's not entirely clear from your question what you are hoping to achieve with this mystery module that you have... but here's some ideas which might trigger something:
If you have a component for the module in question, then you can instantiate it within your design and then manipulate its inputs to make its outputs do what they should. Maybe it has some documentation to give you some clues!
If it writes to memory and you have a multi port memory controller within your system connected to the same memory, you could build something which will read data from the memory after your mystery module has written to it.
Or finally, if this is an FPGA, you can embed a logic analyser into the FPGA bitstream to observe the signals going to and from the secret module.
I've been working on coding a simple stack memory. It has 4 address bits and thus can store 16 elements. Everything works fine, but the problem is that when all 16 memory elements have been written to, the counter that keeps track of the memory location overflows and resets it to 0000. I cannot find out the reason for this. All my registers are of correct width.
reg_push and reg_pop are incremented and decremented together, and these are the registers that keep track of the memory location.
Here is the simulation showing the overflow.
Here is the code:
module stack # (parameter dbits = 3, abits = 4)(
input clock,
input reset,
input push,
input pop,
input [dbits-1:0] din,
output [dbits-1:0] dout,
output full,
output empty
);
reg [dbits-1:0] regarray[2**abits-1:0]; //number of words in fifo = 2^(number of address bits)
reg [abits-1:0] reg_push, reg_pop, next_push, next_pop;
reg full_reg, empty_reg, full_next, empty_next;
reg [dbits-1:0] out;
wire wr_en;
wire db_push, db_pop;
reg dffpop1, dffpop2, dffpush1, dffpush2;
always # (posedge clock) dffpush1 <= push;
always # (posedge clock) dffpush2 <= dffpush1;
assign db_push = ~dffpush2 & dffpush1; //monostable multivibrator to detect only one pulse of the button
always # (posedge clock) dffpop1 <= pop;
always # (posedge clock) dffpop2 <= dffpop1;
assign db_pop = ~dffpop2 & dffpop1; //monostable multivibrator to detect only one pulse of the button
assign wr_en = db_push & ~full; //only push if write signal is high and stack is not full
//always block for write operation
always # (posedge clock)
if(wr_en) regarray[reg_push] = din;
//always block for read operation
always # (posedge clock)
begin
if(db_pop)
out <= regarray[reg_pop];
end
always # (posedge clock or posedge reset)
begin
if(reset)
begin
full_reg <= 0;
empty_reg <= 1;
reg_push <= 0;
reg_pop <= 0;
end
else
begin
full_reg <= full_next;//created the next registers to avoid the error of mixing blocking and non blocking assignment to the same signal
empty_reg <= empty_next;
reg_push <= next_push;
reg_pop <= next_pop;
end
end
always # (*)
begin
full_next = full_reg; //default values stay the same
empty_next = empty_reg;
next_push = reg_push;
next_pop = reg_pop;
if(db_push)
begin
if(~full) //if stack is not full continue
begin
empty_next = 0;
next_push = reg_push + 1;
next_pop = reg_pop + 1;
if(reg_push == (2**abits - 1)) full_next = 1; //all registers have been written to
end
end
else if (db_pop)
begin
if(~empty) //if stack is not empty continue
begin
full_next = 0;
next_pop = reg_pop - 1;
next_push = reg_push - 1;
if(reg_pop == 0) empty_next = 1; //all data has been read
end
end
end
assign full = full_reg;
assign empty = empty_reg;
assign dout = out;
endmodule
Now if I use this stack without making it reach its full capacity, it will work perfectly. It's only when I store all 16 elements into it that the problem arises.
Extend your pop pointer an extra bit.
A 4-bit register can only store the a value 0 through 15. Any value above that will ignore the upper bits, effectively doing a mod 16. Hence assigning 16 will result in 0.
Option 1: expand to a 5-bit register:
Try changing:
reg [abits-1:0] reg_push, reg_pop, next_push, next_pop;
To:
reg [abits:0] reg_push, reg_pop, next_push, next_pop;
Option 2: Use full_reg are the 5th bit in evaluations:
Change:
if(reg_push == (2**abits - 1)) full_next = 1; //all registers have been written to
...
if(reg_pop == 0) empty_next = 1; //all data has been read
To:
if({full_reg,reg_push} >= (2**abits - 1)) full_next = 1; //all registers have been written to
...
if({full_reg,reg_pop} == 0) empty_next = 1; //all data has been read
I have this piece of IP that is supposed to be a 32 bits byte addressable memory. But I can't make it infer block rams, it is inferring a huge amount of flip flops...
It is supposed to fit on a Spartan3e (xc3s1200e-4fg320) which has only dual port block rams, indeed the memory is split into two arrays in an even-odd arrange...
Here is the code, I hope that might help understand what am I doing wrong?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
package mem_types is
type memory_t is array (natural range <>) of std_logic_vector(7 downto 0);
end mem_types;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.mem_types.all;
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity ram is
generic (
INIT : memory_t(0 to 4095) := (others => (others => '0'))
);
port ( clk, rst : in std_logic;
addr : in std_logic_vector(11 downto 0);
din : in std_logic_vector(31 downto 0);
dout : out std_logic_vector(31 downto 0);
we : std_logic_vector(3 downto 0)
);
end ram;
architecture Behavioral of ram is
type ramport_t is record
addr : std_logic_vector(10 downto 0);
dout : std_logic_vector(7 downto 0);
din : std_logic_vector(7 downto 0);
wea : std_logic;
end record;
signal port0a, port0b, port1a, port1b : ramport_t;
signal addr_a, addr_b, addr_c, addr_d : std_logic_vector(11 downto 0);
signal memory0, memory1 : memory_t(0 to 2047);
begin
addr_a <= addr;
addr_b <= addr+1;
addr_c <= addr+2;
addr_d <= addr+3;
port0a.addr <= addr_a(11 downto 1) when addr_a(0) = '0' else addr_b(11 downto 1);
port1a.addr <= addr_b(11 downto 1) when addr_b(0) = '1' else addr_a(11 downto 1);
port0b.addr <= addr_c(11 downto 1) when addr_c(0) = '0' else addr_d(11 downto 1);
port1b.addr <= addr_d(11 downto 1) when addr_d(0) = '1' else addr_c(11 downto 1);
dout(07 downto 00) <= port0a.dout when addr_a(0) = '0' else port1a.dout;
dout(15 downto 08) <= port1a.dout when addr_b(0) = '1' else port0a.dout;
dout(23 downto 16) <= port0b.dout when addr_c(0) = '0' else port1b.dout;
dout(31 downto 24) <= port1b.dout when addr_d(0) = '1' else port0b.dout;
port0a.din <= din(07 downto 00) when addr_a(0) = '0' else din(15 downto 08);
port1a.din <= din(15 downto 08) when addr_b(0) = '1' else din(07 downto 00);
port0b.din <= din(23 downto 16) when addr_c(0) = '0' else din(31 downto 24);
port1b.din <= din(31 downto 24) when addr_d(0) = '1' else din(23 downto 16);
port0a.wea <= we(0) when addr_a(0) = '0' else we(1);
port1a.wea <= we(1) when addr_b(0) = '1' else we(0);
port0b.wea <= we(2) when addr_c(0) = '0' else we(3);
port1b.wea <= we(3) when addr_d(0) = '1' else we(2);
port0a.dout <= memory0(conv_integer(port0a.addr));
port0b.dout <= memory0(conv_integer(port0b.addr));
port1a.dout <= memory1(conv_integer(port1a.addr));
port1b.dout <= memory1(conv_integer(port1b.addr));
process (clk, rst)
begin
if rst = '1' then
for a in 0 to 2047 loop
memory0(a) <= INIT(a*2);
end loop;
elsif falling_edge(clk) then
if (port0a.wea = '1') then
memory0(conv_integer(port0a.addr)) <= port0a.din;
end if;
if (port0b.wea = '1') then
memory0(conv_integer(port0b.addr)) <= port0b.din;
end if;
end if;
end process;
process (clk, rst)
begin
if rst = '1' then
for a in 0 to 2047 loop
memory1(a) <= INIT((a*2)+1);
end loop;
elsif falling_edge(clk) then
if (port1a.wea = '1') then
memory1(conv_integer(port1a.addr)) <= port1a.din;
end if;
if (port1b.wea = '1') then
memory1(conv_integer(port1b.addr)) <= port1b.din;
end if;
end if;
end process;
end Behavioral;
This is described in the Xilinx Synthesis Guide under Coding for FPGA Flow. I'm almost certain that reset loop is causing flops to be inferred. That code requires accessing all elements of the memory simultaneously, which is not possible with Block RAM.
You can't do this:
process (clk, rst)
begin
if rst = '1' then
for a in 0 to 2047 loop
memory0(a) <= INIT(a*2);
end loop;
...as that is asking for a resettable memory, rather than an initialised one.
To initialise, you need to change your signal declaration to be of the form
signal memory0 : memory_t(0 to 2047) := ( some list of integers or something that returns an array of integers);
The way you are currently doing it (with your init's interleaved) means you'll have to use a function:
function init_mem(init_values: memory_t) returns memory_t is
variable retval : memory_t(init_values'high/2)+1 downto 0);
begin
for i in retval'range loop
retval(i) := init_values(2*i);
end for;
end function;
(note that that was typed off the top of my head and I've not even tried to compile it, so apologies for any typos and syntax errors... but I hope you get the idea :)
Then you can use this to init the signal:
signal memory0 : memory_t(0 to 2047) := init_mem(INIT);
This will all work for simulation. You may or may not have success with the XST synthesiser inferring the INIT values - I haven't tried. Check the synthesis logfile to see what it reports - and please do report back to us whether it works and on what version of XST you tried it.