/*---------------------------------------------------------------------- File : regmach.h Contents: register machine simulation, definitions and functions Author : Christian Borgelt History : 02.12.1997 file created from original rmsim.c 05.12.1997 some comments corrected 07.07.1998 check for a division by zero added ----------------------------------------------------------------------*/ #ifndef __REGMACH__ #define __REGMACH__ /*---------------------------------------------------------------------- Preprocessor Definitions ----------------------------------------------------------------------*/ #define PRG_BEGIN INIT(); STATE(); while (1) { switch (pc) { case #define PRG_END -1: default: \ printf("\nillegal instruction number %i\n", pc); \ return; }} #define REGCNT (int)(sizeof(c)/sizeof(int)) #define INIT() rm_init(cinit, n, c, REGCNT) #define STATE() rm_state(pc, c, REGCNT) #define CHECK(a) if (((a) < 0) || ((a) >= REGCNT)) { \ printf("illegal register number %i\n", a); return; } #define ZERO(x) if ((x) == 0) { printf("division by 0\n"); return; } #define INST(i,a) printf("%s %i\n", i, a); #define BREAK STATE(); break; case /*---------------------------------------------------------------------- Register Machine Instructions ----------------------------------------------------------------------*/ /* --- input/output instructions --- */ #define LOAD(a) INST("LOAD", a); CHECK(a); c[0] = c[a]; pc++; BREAK #define CLOAD(a) INST("CLOAD",a); c[0] = (a); pc++; BREAK #define STORE(a) INST("STORE",a); CHECK(a); c[a] = c[0]; pc++; BREAK /* --- extended input/output instructions --- */ #ifdef EXINST #define INDLOAD(a) INST("INDLOAD", a); CHECK(a); CHECK(c[a]); \ c[0] = c[c[a]]; pc++; BREAK #define INDSTORE(a) INST("INDSTORE", a); CHECK(a); CHECK(c[a]); \ c[c[a]] = c[0]; pc++; BREAK #endif /* --- arithmetic instructions --- */ #define ADD(a) INST("ADD", a); CHECK(a); c[0] += c[a]; pc++; BREAK #define CADD(a) INST("CADD", a); c[0] += (a); pc++; BREAK #define SUB(a) INST("SUB", a); CHECK(a); c[0] -= c[a]; \ if (c[0] < 0) c[0] = 0; pc++; BREAK #define CSUB(a) INST("CSUB ",a); c[0] -= (a); \ if (c[0] < 0) c[0] = 0; pc++; BREAK #define MULT(a) INST("MULT", a); CHECK(a); c[0] *= c[a]; pc++; BREAK #define CMULT(a) INST("CMULT",a); c[0] *= (a); pc++; BREAK #define DIV(a) INST("DIV", a); CHECK(a); ZERO(c[a]); \ c[0] /= c[a]; pc++; BREAK #define CDIV(a) INST("CDIV", a); ZERO(a); c[0] /= (a); pc++; BREAK /* --- extended arithmetic instructions --- */ #ifdef EXINST #define INDADD(a) INST("INDADD", a); CHECK(a); CHECK(c[a]); \ c[0] += c[c[a]]; pc++; BREAK #define INDSUB(a) INST("INDSUB", a); CHECK(a); CHECK(c[a]); \ c[0] -= c[c[a]]; if (c[0] < 0) c[0] = 0; pc++; BREAK #define INDMULT(a) INST("INDMULT",a); CHECK(a); CHECK(c[a]); \ c[0] *= c[c[a]]; pc++; BREAK #define INDDIV(a) INST("INDDIV", a); CHECK(a); CHECK(c[a]); \ c[0] /= c[c[a]]; pc++; BREAK #endif /* --- jump instructions --- */ #define GOTO(a) pc = (a); INST("GOTO", a); BREAK #define IF(a) printf("IF (c0 = 0) "); if (c[0] != 0) pc++; else /* --- stop instruction --- */ #define END printf("END\n"); return; case /*---------------------------------------------------------------------- With the above definitions you can write a register machine program in a C-function. Only slight modifications of the syntax used in the lecture are necessary. These are: The instruction number must be followed by a colon and the argument of an instruction as well as the condition of an IF must be enclosed in parantheses (these changes are due to the limited capabilities of the C-preprocessor). For some examples of how to use the above definitions see the functions `example3_7', `example3_8', `exercise16', `exercise17a', and `exercise17b' in the file `rmsim.c'. Note that the names of the function arguments (`cinit', `n') and the names of the local variables (`pc', `c') must not be changed, since they are referred to in the above definitions. Note also that it is checked, whether a referenced register exists in the vector c and whether the instruction jumped to with a GOTO instruction or reached by normal instruction execution exists in the program. If the referenced register or the instruction with the number contained in `pc' does not exist, an error message is printed and the function is aborted. If you want to use the extended instruction set, which allow indirect register references, define the preprocessor constant EXINST (extended instruction set), either with a `#define EXINST' in the C-program in which you write your register machine programs (before the `#include "regmach.h"') or with the compiler option -D (Gnu C-compiler). ----------------------------------------------------------------------*/ /*---------------------------------------------------------------------- Functions ----------------------------------------------------------------------*/ extern void rm_init (int cinit[], int n, int c[], int m); extern void rm_state (int pc, int c[], int m); #endif