/* Author: Jose Romeo Vela Date: March 24, 2002 email: jrvela@aristasol.com http://www.aristasol.com/ This software is licensed under GNU's GPL. For details see http://www.gnu.org/ Copyright (c) 2002, Jose Romeo Vela ============================================================================== Modifications: 4/9/2002 jrv Check for NULL file handle on IN and OUT operations. 4/13/2002 jrv2 Cleaned the code in the case statement in function cinc_exec. 4/15/2002 jrv3 Fix a bug introduced by jrv2 in cardiac_SUB */ #include #include "config.h" int cinc_fetch(struct cardiac_s * cardiac) { int rc = 0; if (cardiac->ram[cardiac->pc] > 0) { /* fetch the opcode */ cardiac->opcode=cardiac->ram[cardiac->pc]/100; /* fetch the address or operand */ cardiac->address=cardiac->ram[cardiac->pc] - cardiac->opcode*100; /* increment the program counter */ cardiac->pc++; } else { /* negative instructions are invalid */ rc = 1; } return(rc); } int cinc_exec(struct cardiac_s * cardiac) { int rc = 0; int exit_code = 0; /* execute the instruction indicated in the opcode */ switch (cardiac->opcode) { case 0: exit_code = cardiac_INP(cardiac); break; case 1: exit_code = cardiac_CLA(cardiac); break; case 2: exit_code = cardiac_ADD(cardiac); break; case 3: exit_code = cardiac_TAC(cardiac); break; case 4: exit_code = cardiac_SFT(cardiac); break; case 5: exit_code = cardiac_OUT(cardiac); break; case 6: exit_code = cardiac_STO(cardiac); break; case 7: exit_code = cardiac_SUB(cardiac); break; case 8: exit_code = cardiac_JMP(cardiac); break; case 9: exit_code = cardiac_HRS(cardiac); break; } if (exit_code) { rc = 100+cardiac->opcode*10+exit_code; cardiac->running = FALSE; } return(rc); } void setsign(struct cardiac_s * cardiac) { /* separate the sign from the absolute value of the accumulator */ if (cardiac->ac<0) { cardiac->ac_sign = -1; cardiac->ac = abs(cardiac->ac); } else { cardiac->ac_sign = 1; } } /* Each CARDIAC instruction is implemented with a separate function. These functions are named cardiac_ followded by the abbriviated instruction name as per CARDIAC's documentation. Here is a summary of the instructions code abbr Meaning 0 INP Input 1 CLA Clear and Add 2 ADD Add 3 TAC Test Accumulator Contents 4 SFT Shift 5 OUT Output 6 STO Store 7 SUB Subtract 8 JMP Jump 9 HRS Halt and Reset */ int cardiac_INP(struct cardiac_s * cardiac) { int rc = 0; int scan_rc; int cont; if (cardiac->IN == NULL) { /* No IN file specified in command line option */ rc = 3; return(rc); } if ( cardiac-> IN == stdin) { fprintf(tty,"%s",CINCPROMPT); }; if ( (scan_rc = fscanf(cardiac->IN,"%4d",&cont)) > 0) { cardiac->ram[cardiac->address]=cont; } else { /* IN file could not be opened */ rc = 2; } return(rc); } int cardiac_CLA(struct cardiac_s * cardiac) { /* clear AC and add */ int rc = 0; cardiac->ac = cardiac->ram[cardiac->address]; setsign(cardiac); return(rc); } int cardiac_ADD(struct cardiac_s * cardiac) { int rc = 0; cardiac->ac = cardiac->ram[cardiac->address] + cardiac->ac_sign*cardiac->ac; setsign(cardiac); /* Truncate the AC to 4 digits */ cardiac->ac = itrunc(cardiac->ac,4); return(rc); } int cardiac_TAC(struct cardiac_s * cardiac) { int rc = 0; if (cardiac->ac_sign < 0) cardiac->pc = cardiac->address; return(rc); } int cardiac_SFT(struct cardiac_s * cardiac) { int rc = 0; int left; int right; /* left is how many digits to shift left */ left = cardiac->address/10; /* right is how many digits to shift right */ right = cardiac->address - left*10; /* shift left */ cardiac->ac = cardiac->ac*ipow(10,left); /* Truncate the AC to 4 digits */ cardiac->ac = itrunc(cardiac->ac,4); /* shift right */ cardiac->ac = cardiac->ac/ipow(10,right); return(rc); } int cardiac_OUT(struct cardiac_s * cardiac) { int rc = 0; if (cardiac->OUT == NULL) { rc = 3; return(rc); } fprintf(cardiac->OUT,"% 04d\n",cardiac->ram[cardiac->address]); return(rc); } int cardiac_STO(struct cardiac_s * cardiac) { int rc = 0; if (cardiac->address != 0) { cardiac->ram[cardiac->address] = (cardiac->ac - (cardiac->ac/1000)*1000) * cardiac->ac_sign; if (cardiac->address == (MAXRAM-1)) { /* last memory cell allways has opcode 8 (JMP) */ cardiac->ram[cardiac->address] = abs(cardiac->ram[cardiac->address]); cardiac->ram[cardiac->address] = cardiac->ram[cardiac->address] - (cardiac->ram[cardiac->address]/100)*100+800; } } return(rc); } int cardiac_SUB(struct cardiac_s * cardiac) { int rc = 0; cardiac->ac = cardiac->ac_sign*cardiac->ac - cardiac->ram[cardiac->address]; setsign(cardiac); /* Truncate the AC to 4 digits */ cardiac->ac = itrunc(cardiac->ac,4); return(rc); } int cardiac_JMP(struct cardiac_s * cardiac) { int rc = 0; cardiac->ram[MAXRAM-1] = 800+cardiac->pc; cardiac->pc = cardiac->address; return(rc); } int cardiac_HRS(struct cardiac_s * cardiac) { int rc = 0; cardiac->pc = cardiac->address; /* stop cardiac */ cardiac->running = 0; return(rc); } int ipow(int a, int b) { /* a to the power of b */ int pow; int i; pow = 1; for (i = 1; i <= b; i++) pow *= a; return(pow); } int itrunc(int a, int b) { /* truncate a to b digits. */ int r; int max; max = ipow(10,b); if (a >= max) { r = a - (a/max)*(max); } else { r = a; } return(r); }