Classic Disk Drive simulation and binary file IO.

R

Rob Doyle

Guest
I've designed a PDP8 computer and RK08 disk drive controller.
I'm trying to test the RK08 controller with a simulated RK05
disk drive. The RK05 disk drive essentially has 6496
sectors and each sector has 256 (16 bit, 4 bits unused) words.
All disk operations occurs on sectors: a sector can be read
or written.

I have a 3,325,952 byte disk image that has the OS image
for testing.

I'm trying to write a testbench in VHDL that simulates the
RK05 disk drive using file IO. I don't do a lot of file IO
in VHDL and I'm struggling.

As far as I can see:

VHDL seems to preclude opening a file for read and write,
(or modification).
VHDL doesn't seem to have an easy way to 'seek' through
a file.

Verilog has $fseek() which seems like it would significantly
simplify everything. I'm not sure if Verilog can open
a file for read/write/update, either.

I *could* re-do the testbench in Verilog if doing this in
VHDL was impossible but:
- I'm much less competent in Verilog.
- I'd have to give up having a nice PDP8 simulator executable
generated by GHDL.

My preference would be to stick with VHDL.

Any suggestions?

Rob.
 
Rob Doyle <radioengr@gmail.com> writes:

I've designed a PDP8 computer and RK08 disk drive controller.
I'm trying to test the RK08 controller with a simulated RK05
disk drive. The RK05 disk drive essentially has 6496
sectors and each sector has 256 (16 bit, 4 bits unused) words.
All disk operations occurs on sectors: a sector can be read
or written.

I have a 3,325,952 byte disk image that has the OS image
for testing.

I'm trying to write a testbench in VHDL that simulates the
RK05 disk drive using file IO. I don't do a lot of file IO
in VHDL and I'm struggling.
Just do the file IO once at startup: read the whole file into an array
of integers within your disk drive model. Close that file and then
operate directly on the array.

If desired, provide a "write it back to disk" function which writes the
whole array back out all at once - to the same file, or somewhere else.

You might find simulations quicker if you make the big array a variable
within a process rather than a signal, but if you only write to it
rarely, it might not make much difference.

Finally, reading binary can be a pain in VHDL, some simulators behave
differently to others. It can sometimes be easier to convert the binary
file to a huge list of the same numbers but rendered in ASCII.

Cheers,
Martin

--
martin.j.thompson@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.co.uk/capabilities/39-electronic-hardware
 
On Tue, 29 Nov 2011 01:58:36 -0700, Rob Doyle wrote:

I've designed a PDP8 computer and RK08 disk drive controller. I'm trying
to test the RK08 controller with a simulated RK05 disk drive. The RK05
disk drive essentially has 6496 sectors and each sector has 256 (16 bit,
4 bits unused) words. All disk operations occurs on sectors: a sector
can be read or written.

I have a 3,325,952 byte disk image that has the OS image for testing.

My preference would be to stick with VHDL.
One suggestion would be to reduce the seek times by using multiple
smaller files ... 6496 would be way too many; how many tracks on that
drive? That suggests loading/modifying/saving an entire track (file) when
you need write access. It'll be plenty fast enough to simulate PDP11 file
I/O!

A sconversion program between the whole disk image and a directory full
of tracks should be easy, even in VHDL.

If that's a binary image, be aware that binary file formats are not well
defined in VHDL; the most you can be certain of is that you can write and
read back in the same version of the same simulator. Modelsim seems to
read commercial binary files in the expected (little-endian) manner.

However Xilinx ISIM (a) assumes opposite-endian-ness to Modelsim, and
insists on adding an undocumented header (which varies between ISIM
versions) on file output, and expects the same on file input. You can
work around this (on Linux) using "head" and "tail" to extract header and
data from an ISIM output file, and "cat" to join a previously extracted
header to a standard binary file so that ISIM can read it, but it's
tedious, unnecessary, and Xilinx refuse to document the process or fix it.
Start by writing some known data in ISIM, and look at the file in a hex
editor.

I have no experience with GHDL and binary file I/O (or with GHDL at all)

Alternatively it might be easier to be extravagant with disk space, and
make the converter translate into a textual format (e.g. hex) for
portable VHDL.

- Brian
 
On 11/29/2011 3:52 AM, Martin Thompson wrote:
Rob Doyle<radioengr@gmail.com> writes:

I've designed a PDP8 computer and RK08 disk drive controller.
I'm trying to test the RK08 controller with a simulated RK05
disk drive. The RK05 disk drive essentially has 6496
sectors and each sector has 256 (16 bit, 4 bits unused) words.
All disk operations occurs on sectors: a sector can be read
or written.

I have a 3,325,952 byte disk image that has the OS image
for testing.

I'm trying to write a testbench in VHDL that simulates the
RK05 disk drive using file IO. I don't do a lot of file IO
in VHDL and I'm struggling.

Just do the file IO once at startup: read the whole file into an array
of integers within your disk drive model. Close that file and then
operate directly on the array.
That's a really good idea.

I was worried that it might take a while to read the entire disk image
into the 'big array' but it seemed like it was the simplest approach
and it made seeking around the disk simple also.

I decided to write a test program to see what kind of performance this
approach might achieve. If it is too slow, I'll try "Plan B".

If desired, provide a "write it back to disk" function which writes the
whole array back out all at once - to the same file, or somewhere else.
I'm going to put this off until later. That way I can't mung up the
disk image.

You might find simulations quicker if you make the big array a variable
within a process rather than a signal, but if you only write to it
rarely, it might not make much difference.
Both Xilinx ISE and GHDL hang if the 'big array' is signal. I had to
reboot the PC to get control back from ISE... The mouse barely moved,
the disk drive lite was on continuously, and I couldn't even get into
Task Manager to kill ISE. I manually aborted GHDL after a while.

It looks like I *can* use a shared variable for the 'big array' - that
way I can access the 'big array' from multiple processes. Again, this
works for both ISE and GHDL - and the performance is pretty good.

Finally, reading binary can be a pain in VHDL, some simulators behave
differently to others. It can sometimes be easier to convert the binary
file to a huge list of the same numbers but rendered in ASCII.
The disk image is little-endian. I read the disk image a character at
at time and built the 16-bit "words" properly. I believe this to be
portable to different simulators. The disk image, however, is probably
not portable to big-endian systems.

Cheers,
Martin
I really really appreciate the assistance and good ideas from everyone.
The PDP8 thing isn't my day job.

Just a minor plug for GHDL -
I can compile the PDP8 VHDL code with GHDL and get a 'stand-alone'
PDP-8 simulator executable. For example, I used to have an
executable that had the RAM preloaded with FOCAL-69. I can
synthesize the same code with Xilinx XST and load it into the
target hardware.

Regards,
Rob.

-------------------------- test program ----------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_textio.all;
use std.textio.all;

entity test_disk is
end test_disk;

architecture behav of test_disk is

subtype word_t is std_logic_vector(0 to 15);
type image_t is array(0 to 1662976) of word_t;
file OUTFILE : text is out "STD_OUTPUT";
type imageFILE_t is file of character;
file imageFILE : imageFILE_t;
shared variable image : image_t;
shared variable size : integer := 0;

begin

process
variable c : character;
variable lin : line;
variable word : word_t;
begin
write(lin, string'("Reading Disk Image..."));
writeline(OUTFILE, lin);
file_open(imageFILE, "diskpack.rk05", read_mode);
while not endfile(imageFILE) loop
read(imageFILE, c);
word(8 to 15) := std_logic_vector(to_unsigned(
character'pos(c), 8));
read(imageFILE, c);
word(0 to 7) := std_logic_vector(to_unsigned(
character'pos(c), 8));
image(size) := word;
size := size + 1;
end loop;
write(lin, string'("Done Reading Disk Image."));
writeline(OUTFILE, lin);
write(lin, string'("Read "));
write(lin, size * 2);
write(lin, string'(" bytes"));
writeline(OUTFILE, lin);
wait;
end process;


process
variable index : integer := 10;
variable lin : line;
begin
write(lin, string'("----> "));
hwrite(lin, image(index));
writeline(OUTFILE, lin);
wait;
end process;

end behav;

------------------------------- end test program ---------------------

------------------------------- simulation results -------------------

$ time ghdl -r -g --workdir=work --ieee=synopsys test_disk
Reading Disk Image...
Done Reading Disk Image.
Read 3325952 bytes
----> 007F

real 0m1.950s
user 0m0.000s
sys 0m0.016s
 
Rob Doyle <radioengr@gmail.com> writes:

On 11/29/2011 3:52 AM, Martin Thompson wrote:
You might find simulations quicker if you make the big array a variable
within a process rather than a signal, but if you only write to it
rarely, it might not make much difference.

Both Xilinx ISE and GHDL hang if the 'big array' is signal. I had to reboot the
PC to get control back from ISE... The mouse barely moved, the disk drive lite
was on continuously, and I couldn't even get into Task Manager to kill ISE. I
manually aborted GHDL after a while.

It looks like I *can* use a shared variable for the 'big array' - that
way I can access the 'big array' from multiple processes. Again, this
works for both ISE and GHDL - and the performance is pretty good.
You are using a protected type for your shared variable aren't you? If
not, you are asking for problems from race-conditions. Your code below
is probably going to work alright, but it you start reading and writing
to the shared variable from multiple processes you are likely to find
life gets annoyingly interesting...

Either keep your variable to a single process and create a RAM-like
model with address and data lines and control signals, or create a
protected type with read and write functions to mediate access to it.
The latter might not work in ISE. I think GHDL supports protected
types.

Both of those options have well-defined access semantics.

Finally, reading binary can be a pain in VHDL, some simulators behave
differently to others. It can sometimes be easier to convert the binary
file to a huge list of the same numbers but rendered in ASCII.

The disk image is little-endian. I read the disk image a character at
at time and built the 16-bit "words" properly. I believe this to be
portable to different simulators. The disk image, however, is probably
not portable to big-endian systems.
One problem I have had in the past (with GHDL IIRC) was that an EOF
character within the file caused it to report end-of-file and return no
more data. And the ISE simulator (at one point, not sure if it still
does) required a special header on binary files before it would read
them.


I really really appreciate the assistance and good ideas from everyone.
The PDP8 thing isn't my day job.
But fun, right :)

<snip>

------------------------------- simulation results -------------------

$ time ghdl -r -g --workdir=work --ieee=synopsys test_disk
I'd recommend against -ieee=synopsys, especially given you are using numeric_std already.

Reading Disk Image...
Done Reading Disk Image.
Read 3325952 bytes
----> 007F
I don't think there's any guarantee that the process which prints the 7F
will run after the file is read. It might depend on the order the
processes come in the source file, or it might be completely random.

Cheers,
Martin

--
martin.j.thompson@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.co.uk/capabilities/39-electronic-hardware
 
"You are using a protected type for your shared variable aren't you?"

Clearly, he is not, he is using the VHDL-93 style of shared variable.



---------------------------------------
Posted through http://www.FPGARelated.com
 
"RCIngham" <robert.ingham@n_o_s_p_a_m.n_o_s_p_a_m.gmail.com> writes:

"You are using a protected type for your shared variable aren't you?"

Clearly, he is not, he is using the VHDL-93 style of shared variable.
Yes, I noticed the code later, but neglected to change that comment!

Sorry about that all!

Cheers,
Martin

--
martin.j.thompson@trw.com
TRW Conekt - Consultancy in Engineering, Knowledge and Technology
http://www.conekt.co.uk/capabilities/39-electronic-hardware
 

Welcome to EDABoard.com

Sponsor

Back
Top