Design and Construction of a PC-Based Stack Machine Simulator for Undergraduate Science & Engineering Courses

Fitratullah Khan and Sohail Anwar Department of Computer Science The University of Texas at Brownsville Brownsville, Texas 78520

Abstract - A senior level compiler design course in an top of the stack. The instructions pop operands from the stack undergraduate computer science and engineering program and push results back on to the stack. usually deals with teaching the students the basics of compiler The stack machine designed by the authors consists of a construction. A thorough understanding of the grammar of a code segment, a stack segment, an formal language and a compiler designed for it can only be (ALU), and four address registers. The code segment has the truly obtained by writing a working compiler for the language. program to be executed. The stack segment holds the A semester long feat of constructing the lexical, syntactic, intermediate data and addresses generated during program semantic, and code generation phases of a compiler exposes execution. A portion of the stack is set aside to store global the students to the inner workings of the compiler. The final data as well. The four address registers are pointers into the phase of testing the integrity and effectiveness of the code and stack segments: constructed compiler is both important and rewarding for a ! Instruction Pointer (IP) points to the next student. Furthermore, since the impetus of such an instruction to be executed, undergraduate course is to deal with the issues of compiler ! Stack Pointer (SP) points to the valid item on top construction rather than intricacies of different machines, it is of the stack, instructive to generate the code for a simple stack machine, ! Local Scope Pointer (LSP) points to the local incorporating a hardware stack, rather than dealing with a data declared within a procedure and the register-based machine such as a microcomputer. However, parameters passed to the procedure, and the educational institutions have the latter as a well ! Parent Scope Pointer (PSP) points to the data established computing platform. Therefore, for testing a defined in the outer static scope. constructed compiler for a stack machine, it is feasible to make Each of the segments is 64KWords, where a word is 16 a microcomputer-based stack machine simulator. This paper bits. Hence, each segment is 64K deep and 16-bit wide, and presents the working design of a PC-based stack machine the addresses of the locations within a segment range from simulator developed by the authors for use in an undergraduate computer science and engineering course in compiler design. This paper begins by putting forward the architecture of the virtual stack machine for which the simulator is designed and constructed. The stack machine’s instruction set is explained and then followed by a discussion of its encoding scheme. The main data structures and the different stages of the simulator are elaborated upon, culminating in a description of the salient features of the simulator that make it an effective tool in a compiler construction course. This includes the simulator’s different analytical features such as measuring space-time complexity to analyze the effectiveness of a compiled code.

The Architecture of the Virtual Stack Machine

The stack machine simulator presented in this paper is a Virtual Stack Machine (VSM) running on a Personal Computer (PC). Typically, a VSM has a program memory and a data stack [1]. The program instructions reside in the program memory, and the data that the instructions operate on are available from the Figure 1 Architecture of the VSM 0000H (Hexadecimal) to FFFFH. Each register is 16-bit wide It is important to note that LSP points to the local scope to address any location within the 64K range of a segment. and can be pushed on the stack to create a dynamic link among Figure 1 shows the architecture of the VSM. Note that all the stack frames of the procedures called dynamically [5]. In address and data paths are 16-bit wide. The instruction pointer Figure 2, this chain of dynamic links is depicted by the saved points within the code segment. Similarly, the stack and scope old value of LSP on top of the return address. This is typically pointers only point to locations within the stack segment. The done by pushing LSP before setting LSP to point to the local globally defined data are also made to reside within the stack scope of the procedure. segment rather than having a segment of their own. This Note that the memory of the VSM is a word addressable design approach provides a set of simple data structures upon rather than a byte addressable memory. All operations and which to build the stack machine simulator. instructions are in units of words. In case of an Input/Output The stack grows from high memory to low memory as is (I/O) operation involving characters, the least significant byte the case in Intel architecture [2]. The stack pointer points contains the character, whereas the most significant byte has to the valid item on top of the stack. Hence, a push operation zeros. Besides providing simplicity and uniformity, this first decrements the stack pointer by 1 and then the specified approach provides 64KWords of memory rather than 64KBytes operand is pushed on to the stack. The pop operation first pops with 16-bit pointers. the contents of the location pointed by the stack pointer and then increments the stack pointer by 1. Instruction Set of the Virtual Stack Machine The global data are stored in the high memory region in the stack segment starting from FFFFH. The normal stack Generally, an assembly language program for a stack machine starts where the global variables end. PSP points to the last is comprised of arithmetic, logical, input/output, control, stack location containing a global variable, thereby demarcating the altering, and assembler directive instructions. Table I two regions, global data and normal stack. summarizes the complete instruction set of the designed VSM. Figure 2 shows a snapshot of the stack illustrating the Note that the assembler directives are not part of the machine’s functions of SP, LSP, and PSP. The figure shows the possible instruction set. However, these directives are found in an values of the stack after a procedure, with two passed assembly language program written for the VSM. They have parameters and one , is called. The stack frame been included in the table for completeness. or the activation record of the called procedure shown is It is important to note that the result of some binary operations, such as subtraction and division, are sensitive to the order of operands on the stack. The description of such instructions in Table I explicitly names the operands to state the expected order. For example, in case of a division operation the divisor is at the top (lower memory address) of the stack whereas the location below it (higher memory address) has the dividend [5]. Similarly, in case of a subtraction operation, the lower address has the subtrahend and the higher address the minuend. POPI and RTI are dereferencing type of operations in which an operand becomes the address of another operand. This is also called indirect addressing [6]. These operations are mostly required when dealing with arrays and variables passed by reference rather than passed by value [1].

Instruction Encoding

Figure 2 A Snapshot of the Stack The instructions of the VSM are either two words wide or one word wide. The two-word instructions are those that require an actually a function of the execution of a set of assembly address, offset, or an immediate value. Table II shows the language instructions either generated by a compiler or directly for each instruction. Note that the of an coded by a programmer [4]. Therefore, it is up to the compiler instruction always appears as the Least Significant Word or the programmer to adhere to the intended use of different (LSW). For a two-word instruction, the Most Significant Word registers. For example, LSP can be used to point to global data (MSW) contains the address, offset, or an immediate value. and PSP to local scope instead, however, that is not the intended use of the registers. Table I Instruction Set of the Virtual Stack Machine

Instruction Description (all operands and results are on stack unless otherwise specified) Directives: end Physical end of the program (not a machine instruction) exit Halt the execution of the program and exit (not a machine instruction) Arithmetic: add Pop the top two locations, add, and push the result div Pop the dividend and divisor, divide, and push the quotient and then the remainder mlt Pop the multiplicand and multiplier, multiply, and push the result neg Pop the top location, negate, and push the result sub Pop subtrahend and minuend, subtract, and push the result Logical: and Pop the top two locations, perform bitwise AND, and push the result not Pop the top location, perform bitwise NOT, and push the result or Pop the top two locations, perform bitwise OR, and push the result Input/Output: getc Get a character byte from the standard input, pad it with zeros on the left, and push it geti Get a 16-bit integer from the standard input and push it putc Pop the top location and print the least significant byte as a character on the standard output puti Pop the top location and print it as a 16-bit integer on the standard output Control Flow: call label Push the return address and transfer the control to the instruction at address label ret nloc Pop the return address into IP and increment SP by nloc cmp Without popping stack, subtract the top location from the one below and push the result jmp label Unconditionally jump to the instruction at address label jlt label Pop the top location and jump to label if the popped location is less than 0 jgt label Pop the top location and jump to label if the popped location is greater than 0 jz label Pop the top location and jump to label if the popped location is zero jnz label Pop the top location and jump to label if the popped location is not zero Stack Operations: push REG* Push the value of REG push int Push a 16-bit integer value push n[REG] Push the contents of the location addressed by n+[REG] pop REG Pop the top location into REG pop n[REG] Pop the top of stack into the location addressed by n+[REG] popi Pop the top of stack, point to the location addressed by it, and pop the top into this location rti Pop the top of stack, point to the location addressed by it, and push the location’s contents xchg Exchange the values of the top two locations mov REG,SP Set REG to the value of SP isp n Increment SP by n (a negative value of n will decrement it) *REG is either LSP or PSP

The execution time of an instruction is evaluated on the instruction is considered to be one clock unit by the simulator. basis of its use of the ALU, registers, and the number of times Furthermore, the evaluation of an effective address, such as it needs to access the code or stack segment. An ALU n[LSP], is counted as one clock unit. operation, code memory access, stack memory access, or a As an example, consider the instruction ADD. It pops two register to register move costs one unit. The fetch and decode operands (2 clock units), computes the result (1 clock unit), and phases, being different from the execution phase, of an pushes it on stack (1 clock unit). This costs 4 units. As another instruction are not reflected in the execution times given in example, consider JLT LABEL instruction. The stack is Table II. The cumulative cost of fetching and decoding an popped (1 clock unit), the ALU is used to check if the Table II Instruction Format, Encoding, and Execution Time

CodeClock Code Clock Instruction Instruction MSW LSWUnits MSW LSW Units add 0001H 4 jz label label 0053H 2 or 3 div 0002H 5 jnz label label 0054H 2 or 3 mlt 0003H 4 push LSP 0060H 1 neg 0004H 3 push PSP 0061H 1 sub 0005H 4 push int int 0062H 2 and 0010H 4 push n[LSP] n 0063H 4 or 0011H 4 push n[PSP] n 0064H 4 not 0012H 3 pop LSP 0065H 1 getc 0020H 2 pop PSP 0066H 1 geti 0021H 2 pop n[LSP] n 0067H 4 putc 0022H 2 pop n[PSP] n 0068H 4 puti 0023H 2 popi 0069H 3 call label label 0030H 2 rti 0070H 3 ret nloc nloc 0031H 2 xchg 0071H 4 cmp 0040H 4 mov LSP,SP 0080H 1 jmp label label 0050H 1 mov PSP,SP 0081H 1 jlt label label 0051H 2 or 3* isp n n 0082H 2 jgt label label 0052H 2 or 3 *The cost is 3 units if the jump is made, otherwise, the cost is 2 units popped value is less than 0 (1 clock unit), and the jump-address converted into an equivalent assembly language program, is fetched from the code segment in case the value is less than rather than a machine language code, for the target machine. 0 (1 clock unit). If the jump is made, the cost is 3 units, The assembly code acts as an intermediate language which is otherwise, the cost is 2 units [7]. more instructive than its machine code counterpart [9]. The simulator has a built-in assembler to facilitate the execution of The VSM Simulator this assembly code. The simulator also accepts the machine code directly so that the students can learn encoding of The simulator for the virtual stack machine is written in the C instructions. The simulator parses the machine code for programming language. As documented earlier, the stack syntactic errors before loading it in the code segment of the machine consists of code and data segments, each 64K deep VSM for execution. Figure 3 depicts the different stages of the and 16-bit wide, four 16-bit registers, and an ALU. The code simulator before a code segment is accepted for execution. and stack segments are represented by arrays of unsigned The simulator shows the process of execution graphically integers with indices ranging from 0000H to FFFFH. The four by charting out the code and stack segments and the four registers are declared as 16-bit unsigned integers to cover the address registers on screen, and displaying their current values full range of the segments [8]. as the instructions are executed one by one. Break-points can A program is assembled as it is loaded into the code be set and the execution can be carried out in single-step mode segment for execution. All references are resolved at the load to facilitate debugging. There are several built-in counters time, thereby relieving the simulator of expensive symbol table in the simulator that keep track of important statistics for the referencing during run time. code being executed. Students can use these statistics to In a typical undergraduate compiler design course a compare different compiled codes and, hence, measure the student is made to build a working compiler by constructing performance of their compilers. These statistics also can be lexical, syntax, semantics, and code generation phases. The used to run a benchmark program to fine tune a compiler. code generation phase usually is required to be written in a Table III documents the statistics available to the user of the manner such that the source program being compiled is simulator for analysis purposes. Figure 3 Passage of Code through Different Stages of the VSM Simulator

Table III Performance Statistics Generated by the Simulator

Size (Words) # of Data References # of Code References Execution Time (Clock Units) •Code •Global •One-word instructions •Overall •Global data •Local •Two-word instructions •Average per call •Maximum stack growth •Average global per stack •Individual instructions •Categories of Instructions •Average stack frame •Average local per stack

Conclusions students and colleagues for useful feedback, encouragement, and support for the work in this paper. In a typical undergraduate compiler design course in computer science and engineering curricula, a student is familiarized with Selected References the theory and practice of compiler design via assigning projects leading to a working compiler. Since the emphasis of 1) Aho, A., Sethi, R., Ullman, J., “Compilers: Principles, the course is to learn compiler design rather than deal with Techniques, and Tools,” Addison-Wesley Publishing idiosyncracies of the architecture of a machine, it is instructive Company, 1988. to design a compiler for a simple stack machine. The absence 2) K. Irvine, “Assembly Language for the IBM-PC,” Prentice- of a physical stack machine in today’s PC world necessitates Hall, Inc., 1993. construction of a virtual stack machine simulator for testing the 3) Y. Yu and C. Marut, “Assembly Language Programming compilers built for it. This paper presented the design and and Organization of the IBM PC,” Mitchell McGraw- construction of such a virtual stack machine simulator and Hill, 1992. described its use in an undergraduate compiler design course. 4) J. Bennet, “Introduction to Compiling Techniques: A First In doing so, the architecture of the virtual stack machine was Course Using ANSI C, LEX and YACC,” McGraw-Hill detailed along with its instruction set, instruction format, Book Company, Inc., 1990. encoding scheme, and execution times. The last part of the 5) V. Hamacher, Z. Vranesic, and S. Zaki, “Computer paper describes the function and interface of the simulator from Organization,” McGraw-Hill Book Company, Inc., 1996. the user perspective. The interactive graphical user interface 6) J. Tremblay and P. Sorenson, “The Theory and Practice of and the statistics generated by the simulator, make it an Compiler Writing,” McGraw-Hill Book Company, Inc., effective tool for analyzing compiled codes and, hence, 1985. measuring the performance of different compilers. 7) J. Uffenbeck, “Microcomputers and : The 8080, 8085, and Z-80 Programming, interfacing, and Acknowledgments Troubleshooting,” Prentice-Hall, Inc., 1985. 8) M. Waite, S. Prata, and D. Martin, “C Primer Plus,” The author gratefully acknowledges his experience as a student Howard W. Sams & Co., Inc., 1984. at The University of Kansas, Lawrence, where he took a 9) R. Hunter, “The Design and Construction of Compilers,” compiler construction course which inspired the work John Wiley & Sons, 1981. presented in this paper. The authors greatly appreciate their