This is my first post on StackOverflow.
I'm a Verilog newbie, though I have significant experience with Python, C, and C++. I am using Icarus Verilog version 10.1.1 on Windows 10, and am trying to write a dynamic memory allocator. For some reason, when this command is run:
iverilog dynmem.v dynmem_test.v -o dynmem_test.out
the following is outputted:
Assertion failed!
Program: c:\iverilog\lib\ivl\ivl.exe
File: ../verilog-10.1.1/pform.cc, Line 333
Expression: lexical_scope
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
What is the problem with my code, and should I submit a bug report for this?
dynmem.v:
`define WORD_SIZE 32
`ifndef DYNMEM_SIZE // size of dynamic memory in words
`define DYNMEM_SIZE 16384*8/WORD_SIZE // 16 KB
`endif
`define __DYNMEM_BIT_SIZE WORD_SIZE*DYNMEM_SIZE-1 // size of dynamic memory in bits
reg [__DYNMEM_BIT_SIZE:0] dynmem; // dynamic memory
reg [DYNMEM_SIZE:0] allocated; // bitvector telling which words are allocated
reg mutex = 0;
module dynreg(address,
ioreg,
read_en,
write_en,
realloc_en);
output reg [WORD_SIZE-1:0] address;
output reg [WORD_SIZE-1:0] ioreg;
output reg read_en; // rising edge: put word stored at location address into ioreg
output reg write_en; // rising edge: put word stored in ioreg into location address
output reg realloc_en; // rising edge: if ioreg=0, free memory, otherwise reallocate memory into buffer of size ioreg.
task malloc; // allocate dynamic memory
output reg [WORD_SIZE-1:0] size;
output reg [WORD_SIZE-1:0] start;
unsigned integer size_int = size; // convert size to integer
reg flag1 = 1;
while (mutex) begin end // wait on mutex
mutex = 1; // acquire mutex
// loop through possible starting locations
for (index=size_int-1; (index < DYNMEM_SIZE) && flag1; index=index+1) begin
// check if unallocated
reg flag2 = 1;
for (offset=0; (offset < size_int) && flag2; offset=offset+1)
if (allocated[index-offset])
flag2 = 0;
if (flag2) begin // if memory block is free
start = index;
flag1 = 0; // exit loop
end
end
// mark as allocated
for (i=0; i<size; i=i+1)
allocated[start-offset] = 1;
mutex = 0; // release mutex
endtask
task freealloc;
output reg [WORD_SIZE-1:0] size;
output reg [WORD_SIZE-1:0] start;
while (mutex) begin end // wait on mutex
mutex = 1; // acquire mutex
// deallocate locations
for (index=start; index > 0; index=index-1)
allocated[index] = 0;
mutex = 0; // release mutex
endtask
// internal registers
unsigned integer start; // start address
unsigned integer size; // block size
unsigned integer address_int; // address register converted to int
initial begin
// allocate memory
size = ioreg;
malloc(size, start);
end
always @(posedge(read_en)) begin
// read memory into ioreg
address_int = address;
ioreg[WORD_SIZE-1:0] = dynmem[8*(start+address_int)-1 -:WORD_SIZE-1];
end
always @(posedge(write_en)) begin
// write memory from ioreg
address_int = address;
dynmem[8*(start+address_int)-1 -:WORD_SIZE-1] = ioreg[WORD_SIZE-1:0];
end
always @(posedge(realloc_en)) begin
unsigned integer ioreg_int = ioreg; // convert ioreg to integer
reg [WORD_SIZE-1:0] new_start; // new start address
if (ioreg_int != 0) begin // if memory is to be reallocated, not freed
malloc(ioreg, new_start); // allocated new memory
// copy memory
for (i=0; i<size; i=i+1)
dynmem[8*(new_start+i)-1 -:WORD_SIZE-1] = dynmem[8*(start+i)-1 -:WORD_SIZE-1];
end
freealloc(size, start); // free previous memory
// update registers
size = ioreg_int;
start = new_start;
end
endmodule
dynmem_test.v:
module testmodule();
$monitor ("%g ioreg1=%b ioreg2=%b",
$time, ioreg1, ioreg2);
reg [WORD_SIZE-1:0] address1, address2;
reg [WORD_SIZE-1:0] ioreg1=5, ioreg2=10;
reg read_en1, read_en2;
reg write_en1, write_en2;
reg realloc_en1, realloc_en2;
#1 dynreg dr1(address1, ioreg1, read_en1, write_en1, realloc_en1);
#1 dynreg dr2(address2, ioreg2, read_en2, write_en2, realloc_en2);
address1 = 0;
ioreg1 = 23;
#1 write_en1 = 1;
write_en1 = 0;
address1 = 2;
ioreg1 = 53;
#1 write_en1 = 1;
write_en1 = 0;
address1 = 0;
#1 read_en1 = 1;
read_en1 = 0;
address1 = 2;
#1 read_en1 = 1;
read_en1 = 0;
#1 $finish;
endmodule
UPDATE: C:\iverilog\lib\verilog-10.1.1 doesn't exist, and, in fact, I searched in C:\iverilog for pform.cc and found no results. Strange.
#1 dynreg dr1(address1, ioreg1, read_en1, write_en1, realloc_en1);
Using a delay (#1
) on an instance declaration is probably confusing Icarus as much as it's confusing me. (What exactly is supposed to get delayed? Does the instance not exist for one simulation step?)
Remove those delays, and put all of the code in your testbench following those two instance declarations into an initial
block.
For what it's worth, dynreg
is probably not synthesizable as written. It has no clock input, and it contains several loops which cannot be unrolled in hardware.
UPDATE: C:\iverilog\lib\verilog-10.1.1 doesn't exist, and, in fact, I searched in C:\iverilog for pform.cc and found no results. Strange.
This path is probably referring to the location of the code on the developer's computer where your copy of Icarus was compiled. Unless you plan on trying to fix the bug that caused this crash yourself, you can safely ignore this.