Open c-93 opened 9 months ago
// But the alternative (a vector with registers) crashes bluesim. Vector#(9, Reg#(File)) file_descriptors_vec = ?;
The above code doesn't create registers. An interface assigned with ?
will ignore writes and return an undetermined value, and so I'd guess that the segfault comes from trying to access the bogus file handle. Use an assignment like this instead:
file_descriptors_vec <- replicateM(mkRegU);
I would avoid using ?
when possible, because it can mask problems that BSC would otherwise be able to catch. In particular, I would avoid ever writing this:
Vector#(n,T) vec = ?;
If you declare a vector with no assignment on the same line, and then assign individually to the elements, BSC is smart enough to detect which elements of a vector have been unassigned and will give you an error if you attempt to access them. For example:
Vector#(3,Bool) vec;
vec[0] = True;
vec[1] = False;
$display(fshow(vec)); // This will give an error because vec[3] is not set
But if vec
was assigned with ?
to start, then you're disabling BSC's ability to check for uninitialized entries, because you've given the vector a value.
If you ever need to explicitly create a vector with uninitialized entires, you can use newVector
. I see that BSC currently has a limitation (that should be fixed) that nested Vectors can't be tracked for uninitialized values. So you'd have to do this:
Vector#(n, Vector#(m, Bool)) vec2d = replicate(newVector);
vec2d[0][0] = True; // Currently this will trigger an error if newVector isn't used
Anyway, does replacing ?
with replicateM(mkRegU)
prevent the segfault?
Maybe the Bluesim implementation of $fgetc
can be updated to check the file descriptor argument that's given to it, so that you can get a helpful error instead of a segfault? We could use fcntl(fd, F_GETFD)
, maybe, although would that extra overhead slow down simulation for users who don't want it? Plus, there's also a risk that the descriptor is open somewhere else, and the check wouldn't detect that the access should still be considered invalid.
Some other notes, if you don't mind me commenting:
I used mkRegU
in place of mkReg(?)
, because then the register doesn't use a reset signal; the mkReg(?)
instance will have a reset value, but you're saying that you don't care what that value is.
Also note that you can use a Maybe
type to combine the valid bit with the value:
Vector#(9, Reg#(Maybe#(File))) fd_vec <- replicateM(mkReg(tagged Invalid));
rule openFile( fd_vec[0] matches tagged Invalid &&& !readDoneVec[0] );
...
fd_vec[0] <= tagged Valid file_descr;
...
endrule
rule readFile( fd_vec[0] matcges tagged Valid .fd &&& !readDoneVec[0] );
...
c <- $fgetc(fd);
...
endrule
Thanks for your fast and detailed explanation!
Yes, your suggestion (correctly initializing by using replicateM(mkRegU)
) fixes my mistake.
You may close the issue.
I agree, a better error message could be helpful. Could this be implemented as a basic compile-time check, without simulation runtime overhead?
It would be interesting to see the behavior when generated to Verilog and run through various simulators, to see if they segfault as well, or if they do some kind of check. (It occurs to me that Bluesim could keep track of the file descriptors that it has opened, from calls to $fopen
, and could check whether the argument to tasks like $fgetc
is one of those values. But a static check as you suggest would be better.)
One simple check that BSC could do is to check whether the expression for a file descriptor argument contains a don't-care value (?
). That would work in this case and would be easy to implement.
A more robust check would be to see whether the argument comes ultimately from an $fopen
call. However, that requires analysis of the state element(s) that the descriptor is stored in and then read from. That may not be hard for registers, but BSC may have to give up if the value is stored in another module or passed across synthesis boundaries. Of course, it's unfortunate that simulation-only values like the file descriptor need to be stored in a normal register at all; there's been an idea before that maybe BSC should support a new kind of module (mkSimReg
or something) that could be used for storing such values, and that wouldn't turn into a register in the generated Verilog (and could be guarded by synthesis_off..on
pragmas). If there was something like that, maybe it would make the analysis easier (but I haven't thought through it).
But certainly we could do the don't-care check.
Hello together,
I would like to report a behavior, which I don't fully understand, yet.
Task: I am reading 9 binary file(s) (zero.bin .... eight.bin) in bluesim. In the below code example, I am just reading one file to keep it simple.
Problem: When keeping track of the file descriptors, a Vector of Regs crashes bluesim with a segfault when reading (not opening) the first byte of the first file.
Easy functional workaround: Instead, use a register containing a vector of file descriptors.
Minimal Code example below:
Variables:
Open File(s). Here we open just one file and use only the first index of our vector.
Read the file from the first index of the Vector.
Output:
Stackdump from journalctl (project paths shortened):