Index of /~squier/Teaching/HardwareFundamentals/LC3-trunk/run

[ICO]NameLast modifiedSizeDescription

[PARENTDIR]Parent Directory   -  
[TXT]Makefile 2011-12-09 07:14 6.7K 

#------------------------------
# lc3/trunk/run/README.html
#------------------------------
                                                                          

This directory is where we run our verilog simulations of our Electric design. See Makefile for some specific simulation scenarios. Running a simulation requires a couple of steps.

1. Get verilog code from your Electric design. 
   1.a. Start Electric, and open your design libraries.
   1.b. Open one of your testbench cells, e.g., "test".
   1.c. Use Electric's menu command,
       Tools.Simulation(Verilog).WriteVerilogDeck
   Write the test.v file into this "trunk/run" directory.

2. Compiling test.v,
    iverilog test.v
gives a simulation file, "a.out". (Use "-o" flag to rename a.out.)

3. Run the simulator,
    vvp a.out
                                                                          

Booting the LC3, initial memory content.

In a typical system, at power-up, machine code stored in a Read-Only-Memory (ROM) is executed. This system startup is called "bootstrapping". The boot process reads in operating system code to memory from some storage device, typically a disk drive. Once the code is in memory, the boot code jumps to it, thereby starting the operating system. In LC3 simulation, we pretend booting has occurred: simulation begins with the PC = 0x0200, and it is assumed LC3 machine code has already been written into memory at that location by a boot process. Effectively, the boot process is simulation initialization.

Our verilog testbenches contain verilog code to write LC3 machine instructions into the LC3's memory as part of the simulator's initialization phase. Verilog code provides two ways of doing this: (1) directly write one or more 16-bit machine instructions to the memory module's data structure, for example,

    top.mem.data[ 16'h0200] = 16'b0001010111000101;
                                                                          
writes an LC3 ADD instruction to memory location 0x0200; or (2) read a file containing LC3 machine instructions and write them into the memory module's data array, for example:
    $readmemb("lc3os.bin", top.mem.data, 'h0200);
                                                                          
reads an ASCII coded representation of an LC3 executable, which was created from an LC3 assembly language source code file, "lc3os.asm". If we are using method (2), before we run the simulation, we must have the file, lc3os.bin, prepared and available in this run directory.

The verilog command "readmemb" specifies which simulated device's data array to load. One can optionally specify starting and ending locations to pre-load. Readmemb begins loading at the start location or 0 if not specified. It reads data into the array until either it reaches the ending location or it runs out of data. If readmemb runs out of data it will complain, but simulation will proceed nevertheless.

Readmemb() reads text characters and interprets them as circuit signal values. The text is binary-encoded signals in plain text. For instance, the LC3's operating system's machine code is in "lc3os.bin". The content of this file is ASCII text for zeroes and ones, which gives the memory cells their initial signal values. The part of memory intitialized is the operating system's part of memory, which is located between 0x01FF and 0x3000. These .bin files we call "binary" files, even though they contain character data.

Building ".bin" files

A few machine instructions can be hand edited into the verilog code as in (1), above. However, code longer than a few instructions is prepared from assembly language source code. That is, it is translated from LC3 assembly language source to LC3 machine code. This is the usual process for creating "binary object" (.obj) files whose contents can be loaded to memory and executed in real machines.

However, we are not loading actual "binary object" files into real machines, we are loading plain-text representations of them into a simulated machine: The simulator can only read text files. So, in addition to assembling to binary object files, we must translate those .obj files into plain-text files (our ".bin" files).

Obj2bin translates the .obj machine code to plain-text zeroes and ones in a ".bin" file. After that translation, we need to edit out the .obj's informational header, which is simply the first line of the file. So, the entire work flow is:

     [ .asm assembly language file ]

 ==> [ lc3as ] ==> .obj binary (link/load) object file

 ==> [ obj2bin ] ==> .bin binary-coded text file

 ==> [ editor, deletes .obj header ] ==> readmemb loadable .bin file

OR, equivalently on the commandline,

    lc3as foo.asm 
    cat foo.obj | obj2bin | sed '1d' > foo.bin
                                                                          

At this writing, our verilog testbench code reads in "lc3os.bin" or "prog.bin". For details on the above, see the Makefile in ../src and testbenches in ../lib.

Connecting physical I/O devices to the LC3 simulation

The simulation driver, kb.c, connects the host system's keyboard and display to the simulated LC3 keyboard and display controllers. We can run the simulation as a standalone hardware simulator, by compiling kb.c and running it at the commandline:

    %> ../bin/kb
                                                                          
(kill the simulation by hitting the [ESC] key). This will start a child processes on the host system that runs the verilog simulation as if you had type "vvp a.out" at the commandline. Key strokes will be sent to the LC3 simulation via a handshaking protocol. Display is handled similarly. You must have a testbench compiled and named a.out in "trunk/run" before running kb.