DATAPATH SIMULATOR (DS) by Emily Ezust Given a Mic-1 microprogram and a Mac-1-based assembly language program, DS assembles the program and simulates the datapath of Andrew Tanenbaum's hypothetical Complex Instruction Set Computer (CISC). In this discussion, "Mac-1" will refer to the numerical code of bits, and "assembly language" will refer to its mnemonic alphanumeric representation. "Mic-1" will refer to the set of 32-bit microinstructions and "MAL" (Micro Assembly Language) will refer to the Pascal-like set of pseudomicrocode instructions. DS #includes the following files and expects them to be in the same directory before compilation: structs.h - contains all structs constants.h - contains all constants ----------------------------------------------------------------- MENU ^^^^ 0. This menu. 1. Enter program editor 2. Enter microcode editor 3. Edit contents of specified register 4. Edit contents of RAM at specified location 5. Run program in slow motion 6. Run program at full speed 7. Run program up to specified breakpoint 8. Display contents of RAM 9. Load microprogram 10. Display microprogram 11. Save microprogram 12. Unload microprogram 13. Load program 14. Display program 15. Save program 16. Unload program 17. Refresh screen 18. Configure 99. Quit EDITING: Options 1 through 4 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Editing is mostly self-explanatory; however, there are a few things that should be noted. In the microprogram editor, command "1" will edit a Mic-1 microinstruction at a given control store location (i.e., microinstruction sequence number). Once it has been entered, the old instruction at that location is displayed above a blank, 13-part template, at the left end of which the cursor is then positioned. The user may now enter the new numbers for each component, pressing after each one. Pressing alone will signal the wish to keep the old value. See the Microprogram Section for details about the microinstruction's components. (These details are given in the editor in a summary form) In the assembly language program editor, whenever instructions are displayed or entered, their MAL equivalent appears on the line below. The following registers can be edited: PC (program counter) AC (accumulator) SP (stack pointer) IR (instruction register) TIR (temporary instruction register) A (free... used for temporary values) Locations in RAM can only be edited if they are outside of the program. The only way to edit the program is to use option 1. RUNNING ^^^^^^^ Options 5 and 6 will begin the runs if both a Mic-1 microprogram and an assembly language program have been loaded. Loading the MAL form of the microcode is optional; however, it is more instructive to do so because MIR will display the pseudocode at run-time. See the loading sections for more details. At the beginning of each run, the stack pointer is set to its default value (SP_DEFAULT from constants.h) and the program counter is set to zero. Note: the program counter (PC) is not touched, since the user can set this to whatever he or she wants. Next, the instructions in the microprogram are carried out beginning with instruction zero. The microprogram is responsible for decoding and carrying out the assembly language instructions and, as it does this, the screen displays in MAL the current miroinstruction in the MIR, along with the microprogram counter, the contents of the registers and the path of the data. The path is animated by a mobile 'D', representing the data currently in the bus. The actual data is shown in the Data: field. The user can choose slow motion (5) or full speed (6) for running. The delay factors for slow motion are global variables found in dpcur.c. They refer to number of clock cycles. The delay of the 'D' moving along the buses can be changed by the user through the Configure option. Since the numbers aren't very meaninful, the user will have to experiment a little with different values. In slow motion, there are three cases where DS pauses: when data hits a special site along the path (such as a register, the ALU, or the shifter), that site will be highlighted onscreen and data will pause with delay factor DELAY_H. Reads and writes will be pointed out at the bottom of the screen. Before data moves from any one coordinate to another, it will pause with delay factor DELAY. At full speed, there are no pauses. During the run, each time a register is changed, the line describing its contents will be updated. Every time data flows into the ALU from the upper input, the function will be displayed over the "A". Every time data flows into the ALU from the lower input, the state of the conditional bits will be displayed. Example: & A This signifies that the function is binary AND, L and the n bit was set (i.e., the result U after the operation was negative). n The functions are: + (normal addition) & (binary AND) ~ (binary complement) (no operation - the value of the lower input is returned) The possible states for conditional bits are: + (positive - result is not negative) n (n has been set - result is negative) z (z has been set - result is zero) Note: Tanenbaum uses positive to mean nonnegative. For example, the assembly language instruction JPOS will jump if the contents of the register AC are greater than or equal to zero. Option 7 allows the user to set a breakpoint. Then the user is asked at which speed to run the program. Further work might include implementing a list of breakpoints; currenly, only one breakpoint is allowed. DISPLAYING ^^^^^^^^^^ If there is a program loaded, it can be displayed using option 14. This displays assembly language with corresponding RAM location numbers; to see the actual numerical representation (Mac-1 in decimal), it is necessary to use option 8. If there is a microprogram loaded, it can be displayed using option 12. This displays each microinstruction on a separate line (with corresponding control store location numbers), in thirteen-integer format. See the Program and Microprogram sections for more details of representations. LOADING, UNLOADING, SAVING ^^^^^^^^^^^^^^^^^^^^^^^^^^ See Microprogram and Program sections for details on loading and saving them. Unloading a microprogram or a program simply sets num_inst or program_size to 0 (respectively), effectively clearing the control store or RAM. MICROPROGRAM ^^^^^^^^^^^^ Note: The 13-integer form of Tanenbaum's Mic-1 microprogram can be found in the file MCP. The MAL microprogram provided in the textbook can be found in the file MAL. The option to load the microprogram queries the user for both of these programs. If the user does not provide the MAL micoprogram, running can still proceed; however, in the register display area, MIR will show nothing at run-time. The microprogram-loader will read thirteen integers for each microinstruction so if there are n lines in the program, there should be n*13 integers in the file. Each microinstruction should have an integer corresponding to each of the following components (in order): AMUX, COND, ALU, SHIFT, MBR, MAR, RD, WR, ENC, C, B, A, ADDR. Each component directs the datapath or helps with program management in some way: A and B specify which registers from which data will be fed. C specifies which register the C bus will feed if ENC (enable C) is on. Register numbers can be found above, in the editing section. AMUX loads data from the A-latch, (0) or from the Memory Buffer Register (MBR), (1). COND determines which microinstruction is next by checking a certain condition. If the condition is true, the next microinstruction is given by ADDR. The codes are: 0 = no jump; 1 = jump if N (that is, if N(egative) was set when the data passed through the Arithmetic Logic Unit (ALU)); 2 = jump if Z (that is, if Z(ero) was set when the data passed through the ALU); 3 = jump always. ALU specifies the function for the ALU. It is slightly misleading to call the two ALU-inputs "A" and "B" but we will do so with the understanding that A could have come from the MBR. The functions are as follows: 1 returns sum, A + B 2 returns binary and, A & B (AKA band(A,B)) 3 returns A input 4 returns complement of A, ~A (AKA inv(A)) SHIFTER specifies the shifting function for the SHIFTER. The input is the output of the ALU. Functions are: 0, no shift; 1, right shift; 2, left shift. 3 is not used. RD and WR begin or conclude reads and writes. It takes two RDs or two WRs in sucession to effect a read or a write (respectively). MAR: if 1, loads MAR from the B bus. MBR: if 1, loads MBR from the SHIFTER. ------------------------------------------------------------------------------- PROGRAM ^^^^^^^ The program-loader will expect a file with one assembly language instruction per line, for example, LOCO 17 ADDD 5 PUSH An assembly language instruction consists of a four-letter opcode alone or followed by either an address or a constant. Note that "POP" was lengthened to "POPX" for the sake of simplicity. The loader will convert each instruction to Mac-1 and store it in ram as an integer. Each Mac-1 instruction consists of sixteen bits with the opcode begininning in the highest (leftmost) bit. There are three categories of instructions (the numbers following the categories refer to how many of them there are in our assembly language): - four-bit opcode followed by a twelve-bit address (fifteen) - eight-bit opcode followed by an eight-bit constant (two) - sixteen-bit opcode alone (six) Because the assembly language opcodes do not convey how much room is left for addresses or constants, "x" will represent a 12-bit-long address and "y" will represent an 8-bit-long constant. Here is a list of legal assembly language instructions: LODD x: Load direct LODL x: Load local POPI : Pop indirect STOD x: Store direct STOL x: Store local PUSH : Push onto stack ADDD x: Add direct ADDL x: Add local POPX : Pop from stack SUBD x: Subtract direct SUBL x: Subtract local RETN : Return JPOS x: Jump positive JNEG x: Jump negative SWAP : Swap AC, SP JZER x: Jump zero JNZE x: Jump not zero INSP y: Increment SP JUMP x: Jump CALL x: Call procedure DESP y: Decrement SP LOCO x: Load constant PSHI : Push indirect AMASK and SMASK are masks to obtain x and y respectively and they are initialized in the main program. x and y will never be negative. Note: LOCO takes in a constant from 0 to 4095. The stack pointer is initialized to 1000. It can be changed by the assembly language program by using the SWAP instruction. Here are MAL representations of the microcode equivalents of the assembly language instructions (the program editor displays one of these whenever an instruction is edited): LODD x ac := ram[x] STOD x ram[x] := ac ADDD x ac := ac + ram[x] SUBD x ac := ac - ram[x] JPOS x if ac >= 0 then pc := x JZER x if ac == 0 then pc := x JUMP x pc := x LOCO x ac := x LODL x ac := ram[sp + x] STOL x ram[sp + x] := ac ADDL x ac := ac + ram[sp + x] SUBL x ac := ac - ram[sp + x] JNEG x if ac < 0 then pc := x JNZE x if ac != 0 then pc := x CALL x sp := sp - 1; ram[sp] := pc; pc := x PSHI sp := sp - 1; ram[sp] := ram[ac] POPI ram[ac] := ram[sp]; sp = sp + 1 PUSH sp := sp - 1; ram[sp] := ac POPX ac := ram[sp]; sp := sp + 1 RETN pc := ram[sp]; sp := sp + 1 SWAP a := ac; ac := sp; sp := a INSP y sp := sp + y DESP y sp := sp - y