sher@cs.Buffalo.EDU (09/04/89)
When I found out I was going to teach compilers I decided that probably the assembly language of the machine they were going to be on was going to be a problem. Too complex, too little documentation, the possibility of crashing the machine .... I was looking for an assembly language that was portable (so I can use it on several machines), simple (so I can focus on theory) and easily modified (so I could fix mistakes and introduce complexity if such is needed). This led me to design a riscy assembly language out of C macros. Any machine with a C compiler could accept this assembly language so it was portable. It's a simple register machine with a large (but not enormous) stack and so on. Because I designed it this way I can monitor how many instructions are executed and how long they take and so illustrate optimization and other such concepts. However I can't easily do things like indirect memory (a la DEC20) or storing the pc (can't get it in C). Since I suspect there may be some fellow teachers of compilers (intro language processing to be exact) out there I thought with permission of the moderator I'd post the thing. Its only 100 odd lines long so net bandwidth won't be overwhelmed. Here it is: -David Sher Ps: I know the stack statements are a bit wierd, every machine has a bit of wierdness no? ------------------------------cut here------------------------------------ /* This file contains the macros that translate my pseudo assembly language into code. This allows me to have a machine independent assembly language for teaching compilers. Written in 1989 by David Sher, sher@cs.Buffalo.EDU. Released into the public domain by the author, who would appreciate it if his name were kept on any copies you make. */ #include <stdio.h> /* global variables that keep track of how long the program took and how many instructions were executed */ int INSTR_COUNT = 0; /* # of instructions */ int INSTR_TIME = 0; /* time for instructions */ /* ajay : System-wide constants (different sizes) */ #define WORD (sizeof(int)) #define BYTE (sizeof(char)) /* definitions of timings */ #define MEM_ACCESS 4 #define SIMPLE_OP 1 #define COMPLEX_OP 10 #define STACK_ACCESS 5 #define CONDITIONAL 2 #define IO_CALL 10 /* Place for registers */ int REGS[7]; /* Place for the stack */ int STACK[65535]; int *SP = STACK; /* Macros to control the main block */ /* begins the main block */ #define BEGIN main(){ /* ends the main block */ #define END printf("\nExecuted %d instructions, took %d units of time\n",INSTR_COUNT,INSTR_TIME); exit(0);} /* Macro for static storage allocation , and allocating strings .. */ #define BLOCK(NAME,SIZE) int NAME[(SIZE)]; /* Macros for moving between memory and registers */ #define LOAD(R,A) REGS[R] = *(A); INSTR_COUNT++; INSTR_TIME += MEM_ACCESS; #define LOAD_IMMEDIATE(R,A) REGS[R] = ((int) A); INSTR_COUNT++; INSTR_TIME += MEM_ACCESS; #define LOAD_INDIRECT(R,R2) REGS[R] = *((int *) REGS[R2]); INSTR_COUNT++; INSTR_TIME += MEM_ACCESS; #define STORE(R,A) *(A) = REGS[R]; INSTR_COUNT++; INSTR_TIME += MEM_ACCESS; #define STORE_INDIRECT(R,R2) *((int *) REGS[R2]) = REGS[R]; INSTR_COUNT++; INSTR_TIME += MEM_ACCESS; /* Macros for stack manipulation */ #define PUSH(R1,R2) ((REGS[R2])? (*(SP - REGS[R2] + 1) = REGS[R1]) : \ (*(++SP) = REGS[R1])); INSTR_COUNT++; INSTR_TIME += STACK_ACCESS; #define POP(R) REGS[R] = *SP--;INSTR_COUNT++; INSTR_TIME += SIMPLE_OP; #define GET(R1,R2) REGS[R1] = *(SP - REGS[R2] - 1); INSTR_COUNT++; INSTR_TIME += STACK_ACCESS; /* Macros for Arithmetic */ #define INC(R) REGS[R]++ ; INSTR_COUNT++ ; INSTR_TIME += SIMPLE_OP ; #define DEC(R) REGS[R]-- ; INSTR_COUNT++ ; INSTR_TIME += SIMPLE_OP ; #define ADD(R1,R2,R3) REGS[R3] = REGS[R1] + REGS[R2]; INSTR_COUNT++; INSTR_TIME += SIMPLE_OP; #define SUBTRACT(R1,R2,R3) REGS[R3] = REGS[R1] - REGS[R2]; INSTR_COUNT++; INSTR_TIME += SIMPLE_OP; #define MULTIPLY(R1,R2,R3) REGS[R3] = REGS[R1] * REGS[R2]; INSTR_COUNT++; INSTR_TIME += COMPLEX_OP; #define DIVIDE(R1,R2,R3) REGS[R3] = REGS[R1] / REGS[R2]; INSTR_COUNT++; INSTR_TIME += COMPLEX_OP; /* Flow of control statements */ #define NOP INSTR_COUNT++; INSTR_TIME += SIMPLE_OP; #define JUMP(L) INSTR_COUNT++; INSTR_TIME += SIMPLE_OP;goto L; #define JUMP_ZERO(R,L) INSTR_COUNT++; INSTR_TIME += CONDITIONAL;if( REGS[R] == 0 ) goto L; #define JUMP_NEGATIVE(R,L) INSTR_COUNT++; INSTR_TIME += CONDITIONAL;if( REGS[R] < 0 ) goto L; #define JUMP_POSITIVE(R,L) INSTR_COUNT++; INSTR_TIME += CONDITIONAL;if( REGS[R] > 0 ) goto L; /* SUBROUTINE management */ #define BEGIN_PROCEEDURE(NAME) void NAME(){ #define END_PROCEEDURE } #define CALL(NAME) NAME(); INSTR_COUNT++; INSTR_TIME += STACK_ACCESS; /* I/O management */ #define READ(R) REGS[R] = (int) getchar(); INSTR_COUNT++; INSTR_TIME += IO_CALL; #define WRITE(R) (void) putchar((char) REGS[R]); INSTR_COUNT++; INSTR_TIME += IO_CALL; /* debugging help ... */ #define DUMP printf("Register Dump :- \n"); printf(" R0 R1 R2 R3 R4 R5 R6\n"); printf("%7x %7x %7x %7x %7x %7x %7x\n\n",REGS[0],REGS[1],REGS[2],REGS[3],REGS[4],REGS[5],REGS[6]); -David Sher ARPA: sher@cs.buffalo.edu BITNET: sher@sunybcs UUCP: {rutgers,ames,boulder,decvax}!sunybcs!sher [From sher@cs.Buffalo.EDU] -- Send compilers articles to compilers@ima.isc.com or, perhaps, Levine@YALE.EDU { decvax | harvard | yale | bbn }!ima. Meta-mail to ima!compilers-request. Please send responses to the author of the message, not the poster.