Frequently asked questions

This document is a work in progress.

Installing and running mic1

  • What do I need to run mic1?
  • I've downloaded and installed mic1. What do I need to do now?

    Writing IJVM programs

  • How do I use the I/O instructions, IN and OUT?
  • How do I use methods in an IJVM program?
  • Why doesn't keyboard input read by the IN instruction show up in "Standard out"?
  • How do I use constants in my program? tbd
  • How do I use local variables? tbd
  • Can I declare global variables? tbd

    General mic1 simulator questions

  • Why does the PC start at 0xFFFFFFFF instead of 0x0?
  • Why is nop1 the first microinstruction, instead of Main1?
  • How does I/O work? tbd
  • What's the deal with the Debug frame? tbd
  • Why does the debug frame show some addresses as word-addresses and others as byte-addresses?

    Questions about sample program echo.jas

  • Why doesn't the backspace key work in echo.jas?


    What do I need to run mic1?

    Java Development Kit (JDK) 1.0 or later for Win95/98/NT or some flavor of Unix. There is not currently a distribution available for Macintosh.

    Some of the java programs may be used in a text-only environment (ijvmasm, mic1asm, mic1dasm, dump) but the simulator itself and certain other programs (mic1sim, gijvmasm, gmic1asm) require a graphical environment. For Win95/98/NT users this should not a problem, but for Unix users, this means that you will need X-Windows to run the simulator or GUI assemblers.

    Also, for the Win95/98/NT distribution, you will need approximately 700Kbytes of free disk space to do the install. The Unix installation requires about 600Kbytes.


    I've downloaded and installed mic1. What do I need to do now?

    Before you run any of the mic1 software, you must set several environment variables.


    How do I use the I/O instructions, IN and OUT?
    IN and OUT use ASCII codes to represent keyboard characters. See add.jas for examples of how to convert character strings into numeric values.


    How do I use methods in an IJVM program?

    If you are using the included microprogram (mic1ijvm.mic1), the following is the proper procedure for declaring and invoking a method in an IJVM program. To illustrate this, we will write a sample method called DIFF_NEG_YN, which takes two parameters, calculates the difference, prints "Y" if the difference is negative, "N" if positive, and sets as a return value the difference.

    1. Declare the method. Use the .method directive to name the method and any parameters. Our example method is named DIFF_NEG_YN and has two parameters, which we will name p1 and p2. Our method declaration would thus look like this:
        .method DIFF_NEG_YN (p1,p2)
      
      The parameter list is comma-seperated. The names in the list are automatically declared as local variables and assigned the values passed to the method. If a method takes no parameters, the method name should be followed by empty parenthesis, ie, .method PRINT ().
    2. Declare any local variables for the method. Use the .var and .end-var directives to declare local variables. For our example, we will declare a local variable called diff
        .var
        diff
        .end-var
      
    3. Write the contents of the method. This is the program code for the method. This code can access local variables (parameters and locally declared variables), global constants (declared in the .constant section of the program), and the local stack. The invoked method has no means of accessing the stack or the local variables of the invoking method. Likewise, any jumps (GOTO, IFEQ, IFLT, IF_ICMPEQ) can only happen within a method -- jumps between methods are not allowed. Here is the code for our sample program:
      	ILOAD p1	// Push the first parameter
      	ILOAD p2	// Push the second parameter
      	SUB		// Subtract
      	ISTORE diff	// Store the difference in diff
      	ILOAD diff	// Push diff
      	IFLT lt 	// If diff < 0, goto lt
      	BIPUSH 0x4E	//  else, print "N"
      	OUT
      	GOTO return
      lt:	BIPUSH 0x59	// (diff < 0)
      	OUT		// print "Y"
      return:	ILOAD diff  	// Push diff
      	IRETURN		// Return (value of diff will be pushed onto the
      			//  top of the invoking method's stack)
      
      .end-method
      
      The method must end with the .end-method directive. The IRETURN instruction is necessary for the method to properly execute.
    4. Write the code for invoking the method. These steps must be followed to properly invoke a method.
      1. Push OBJREF. This may be any value. For more information on OBJREF, see chapter 4 of Structured Computer Organization. In our example program, we will push a constant called OBJREF, which was declared in the .constant section of the program.
        	LDC_W OBJREF
        
      2. Push values that are to be method parameters in the order they are declared in the method declaration.
        	BIPUSH 0x10
        	BIPUSH 0x15
        
        When the method is called, p1 will be assigned the value 0x10 and p2 will be assigned the value of 0x15.
      3. Invoke the method using INVOKEVIRTUAL
        	INVOKEVIRTUAL DIFF_NEG_YN
        
      4. The return value of the method is on the top of the stack. For our example program, we will just ignore this value.
        	POP
        
    Here is the complete listing of our sample program
    // --- Start program ---
    
    .constant 
    OBJREF 0x10
    .end-constant
    
    .main
    	LDC_W OBJREF
    	BIPUSH 0x10
    	BIPUSH 0x15
    	INVOKEVIRTUAL DIFF_NEG_YN
    	POP
    	HALT
    .end-main
    
    
    .method DIFF_NEG_YN (p1,p2)
    
    .var
    diff
    .end-var
    
    	ILOAD p1	// Push the first parameter
    	ILOAD p2	// Push the second parameter
    	SUB		// Subtract
    	ISTORE diff	// Store the difference in diff
    	ILOAD diff	// Push diff
    	IFLT lt 	// If diff < 0, goto lt
    	BIPUSH 0x4E	//  else, print "N"
    	OUT
    	GOTO return
    lt:	BIPUSH 0x59	// (diff < 0)
    	OUT		// print "Y"
    return:	ILOAD diff  	// Push diff
    	IRETURN		// Return (value of diff will be pushed onto the
    			//  top of the invoking method's stack)
    .end-method
    
    // --- End program ---
    

    Why doesn't keyboard input read by the IN instruction show up in "Standard out"?

    Because you might not want it to. The IN instruction reads from a device that is strictly an input device, and the OUT instruction writes to a device that is strictly an output device. If you want to display what the user is typing while running your IJVM program, you will need to cause this to happen by doing an explicit OUT instruction for each character that you read and want to echo.


    Why does the PC start at 0xFFFFFFFF instead of 0x0?

    It seemed reasonable that the control store should begin execution at control store location 0x000. This happens to be the location for the NOP IJVM instruction, so we begin our interpretation loop there. We then proceed to "Main1" to increment the PC, and begin a fetch from this incremented address (the fetch happens at the end of the clock cycle and the fetched value is not available from MBR until the end of the next cycle). Since we want execution of the ISA-level program to begin at 0x00000000, we have accomplished this by pre-setting the PC to 0xFFFFFFFF and allowing the initial increment along with an initial NOP, this "wastes" one micro-instruction every time we RESET the machine.

    We could have used the same approach (with PC 0xFFFFFFFF) and started at "Main1" instead of "nop1", in the mic1ijvm.mal microprogram, but then we would have had to anchor "Main1" at some particular location which would then have to be well-known to the "hardware" designers. It seemed more reasonable to agree that the first micro-instruction to be executed would always be the one at control store location 0x000 which is fine for the mic1ijvm interpreter, and probably a reasonable design choice for many microprograms (opcode 0x00 is often a NOP instruction for many ISA-level designers).

    Another approach would have been to designate some other location as the first micro-instruction and require that a "fetch" happen with PC 0x00000000 (and then another instruction to wait for the fetch into the MBR to complete) before entering the main loop. Since many microprograms have similar increment/fetch loops, we felt that it was reasonable to require that the PC be started at 0xFFFFFFFF as part of the hardware design.

    Feedback on this item is particularly welcomed (rayo@ontko.com).


    Why is nop1 the first microinstruction, instead of Main1?

    In order for "goto(MBR)" to work when MBR contains the opcode for NOP, the control store location 0x000 must contain the microinstruction "nop1". This means that "Main1" must be at some other location not used by one of the other opcodes, and that if we wanted to start our execution of the microprogram at "Main1" this location would have to be well known to the hardware designers for the mic1 hardware. Since we may want to be able to run other microprograms on the mic1 architecture, it seemed reasonable to pick control store location 0x000 as our starting address for all such microprograms.

    While any address would do as a starting location, this one seemed particularly appropriate, since many microprograms might employ "goto(MBR)" and many ISA-level languages might employ opcode 0x00 as a NOP instruction.

    Feedback on this item is particularly welcomed (rayo@ontko.com).


    Why doesn't the backspace key work in echo.jas?

    Because the simulator output device (a Java TextArea) doesn't handle backspace characters. It's hard to decide whether this is a feature or a limitation. The "Standard Out" window is not meant to simulate a cursor-addressable screen display, but only a serial device that displays the next printable character it receives.

    We could modify the behavior of the standard output device to interpret the backspace character as "delete the last character (if any) on the current line in the output buffer", but we feel this would be more confusing an implementation of a simple output device than one which ignores non-printable characters.


    Why does the debug frame show some addresses as word-addresses and others as byte-addresses?

    The MAR stores a number that is a word address (not a word-aligned byte-address), and the PC stores a byte address. This is specified in Chapter 4, of Tanenbaum. When the MAR is expressed on the memory bus, it is at that point shifted by two bits.


    This page maintained by Ray Ontko (rayo@ontko.com).
    Last updated: Saturday, March 13, 1999