#include #include #include #define TRUE 1 #define FALSE 0 // Sweet, a variation on Steve Wozniak's sweet 16 // enable the next definition for fast version //#define FAST_SWEET // program opcodes typedef enum { // program control NOP, HALT, #ifdef FAST_SWEET PAUSE, #endif // JMP is absolute JMP, // BRAs are relative to _BEGINNING_ of instruction // i.e. BRA 0 is infinite loop BRA, BZ, BNZ, BLT, BGT, BLE, BGE, // CALLs are absolute. Data stack is unchanged CALL, CZ, CNZ, CLT, CGT, CLE, CGE, // Returns. Data stack is unchanged RET, RZ, RNZ, RLT, RGT, RLE, RGE, // Test TOS, replace by condition EQ, NEQ, LT, GT, LE, GE, // Data stack management PUSH, POP, DUP, SWAP, OVER, ROLL, // Address stack management (pusha 0 pushes current address) PUSHA, POPA, LOADA, STOA, ATOS, // Infinite loop LOOP, ENDLOOP, // Counted loop. Push loop count before entering DO, ENDDO, // Shifts SHR, SHL, // Unary operators NEG, INC, DEC, // Arithmetic operations ADD, SUB, MUL, DIV, // Logical operations NOT, AND, OR, XOR, // Memory access operations LOAD, STORE, LDX, STX, } op; typedef enum{UNC, ccZ, ccNZ, ccLT, ccGT, ccLE, ccGE}cc; // function prototypes int sweet(op program[]); int check_cc(cc code); // data structures static short stack[1024]; static short return_stack[1024]; static short heap[1024]; static short sp = 0; // stack pointer static short rsp = 0; // pointer for return stack // executable program (declared as array) #include "program.h" // check condition codes int check_cc(cc code){ switch(code){ case UNC: return TRUE; break; case ccZ: return (stack[sp-1] == 0); break; case ccNZ: return (stack[sp-1] != 0); break; case ccLT: return (stack[sp-1] < 0); break; case ccGT: return (stack[sp-1] > 0); break; case ccLE: return (stack[sp-1] <= 0); break; case ccGE: return (stack[sp-1] >= 0); break; } return FALSE; } // The Sweet Interpreter int sweet(op program[]){ int i; short temp; static short ip = 0; op instr; static int busy = FALSE; if(!busy){ ip = 0; busy = TRUE; } #ifdef FAST_SWEET while(1){ #endif printf("fetching instruction %d, ", ip); instr = program[ip++]; switch(instr){ case NOP: printf("NOP\n"); break; case HALT: printf("HALT\n"); busy = FALSE; // FOR TESTING ONLY printf("instruction pointer = %d\n", ip); printf("stack pointer = %d\n", sp); printf("stack = "); for(i=0; i < sp; i++) printf("%d ", stack[i]); printf("\nreturn pointer = %d\n", rsp); printf("return stack = "); for(i=0; i < rsp; i++) printf("%d ", return_stack[i]); printf("\nheap = "); for(i=0; i < 5; i++) printf("%d ", heap[i]); break; #ifdef FAST_SWEET case PAUSE: printf("PAUSE\n"); break; #endif case JMP: printf("JMP %d\n", program[ip]); ip = program[ip]; break; case BRA: case BZ: case BNZ: case BLT: case BGT: case BLE: case BGE: printf("Bcc %d (transfer ", program[ip]); if(check_cc(instr - BRA)){ printf("taken)\n"); ip += program[ip]-1; } else{ printf("not taken)\n"); ++ip; } break; case CALL: case CZ: case CNZ: case CLT: case CGT: case CLE: case CGE: printf("CALLcc %d (transfer ", program[ip]); if(check_cc(instr - CALL)){ printf("taken)\n"); return_stack[rsp++] = ip+1; ip = program[ip]; } else printf("not taken)\n"); ++ip; break; case RET: case RZ: case RNZ: case RLT: case RGT: case RLE: case RGE: printf("RETcc (transfer "); if(check_cc(instr - RET)){ printf("taken)\n"); ip = return_stack[--rsp]; } else printf("not taken)\n"); break; case LOOP: printf("LOOP\n"); return_stack[rsp++] = ip-1; break; case ENDLOOP: printf("ENDLOOP\n"); ip = return_stack[--rsp]; break; case DO: printf("DO\n"); return_stack[rsp++] = ip-1; break; case ENDDO: if((--stack[sp-1]) != 0){ printf("ENDDO (%d) (transfer taken)\n", stack[sp-1]); ip = return_stack[--rsp]; } else{ printf("ENDDO %d (transfer not taken)\n", stack[sp-1]); --sp; --rsp; } break; case PUSHA: printf("PUSHA %d\n", program[ip]); return_stack[rsp++] = ip+program[ip]-1; ++ip; break; case POPA: --rsp; printf("POPA (%d)\n", return_stack[rsp]); break; case STOA: printf("moving %d from data to return stack\n", stack[sp-1]); return_stack[rsp++] = stack[--sp]; break; case ATOS: printf("moving %d from return to data stack\n", return_stack[rsp-1]); stack[sp++] = return_stack[--rsp]; break; case LOADA: stack[sp++] = program[return_stack[rsp-1]++]; printf("loading %d from program memory\n", stack[sp-1]); break; case EQ: stack[sp-1] = (stack[sp-1] == 0); printf("EQ (%d)\n", stack[sp-1]); break; case NEQ: stack[sp-1] = (stack[sp-1] != 0); printf("NEQ (%d)\n", stack[sp-1]); break; case LT: stack[sp-1] = (stack[sp-1] < 0); printf("LT (%d)\n", stack[sp-1]); break; case GT: stack[sp-1] = (stack[sp-1] > 0); printf("GT (%d)\n", stack[sp-1]); break; case LE: stack[sp-1] = (stack[sp-1] <= 0); printf("LE (%d)\n", stack[sp-1]); break; case GE: stack[sp-1] = (stack[sp-1] >= 0); printf("GE (%d)\n", stack[sp-1]); break; case PUSH: temp = program[ip]; printf("PUSH %d\n", temp); stack[sp++] = program[ip++]; break; case POP: temp = stack[--sp]; printf("POP (%d)\n", temp); break; case DUP: temp = stack[sp-1]; printf("DUP (%d)\n", temp); stack[sp] = stack[sp - 1]; ++sp; break; case SWAP: temp = stack[sp-1]; stack[sp-1] = stack[sp-2]; stack[sp-2] = temp; printf("SWAP %d\n", stack[sp-1]); break; case OVER: stack[sp] = stack[sp-2]; ++sp; printf("OVER %d\n", stack[sp-1]); break; case ROLL: temp = stack[sp-3]; stack[sp-3] = stack[sp-2]; stack[sp-2] = stack[sp-1]; stack[sp-1] = temp; printf("ROLL (%d)\n", stack[sp-1]); break; case NEG: stack[sp-1] = -stack[sp-1]; printf("NEG (%d)\n", stack[sp-1]); break; case INC: ++stack[sp-1]; printf("INC (%d)\n", stack[sp-1]); break; case DEC: --stack[sp-1]; printf("DEC (%d)\n", stack[sp-1]); break; case NOT: stack[sp-1] = !stack[sp-1]; printf("NOT (%d)\n", stack[sp-1]); break; case SHR: stack[sp-1] = stack[sp-1] >> 1; printf("SHR (%d)\n", stack[sp-1]); break; case SHL: stack[sp-1] = stack[sp-1] << 1; printf("SHL (%d)\n", stack[sp-1]); break; case ADD: --sp; stack[sp-1] += stack[sp]; printf("ADD (%d)\n", stack[sp-1]); break; case SUB: --sp; stack[sp-1] -= stack[sp]; printf("SUB (%d)\n", stack[sp-1]); break; case MUL: --sp; stack[sp-1] *= stack[sp]; printf("MUL (%d)\n", stack[sp-1]); break; case DIV: --sp; stack[sp-1] /= stack[sp]; printf("DIV (%d)\n", stack[sp-1]); break; case AND: --sp; stack[sp-1] &= stack[sp]; printf("AND (%d)\n", stack[sp-1]); break; case OR: --sp; stack[sp-1] |= stack[sp]; printf("OR (%d)\n", stack[sp-1]); break; case XOR: --sp; stack[sp-1] ^= stack[sp]; printf("XOR (%d)\n", stack[sp-1]); break; case LOAD: printf("LOADing %d from address %d\n", heap[stack[sp-1]], stack[sp-1]); stack[sp-1] = heap[stack[sp-1]]; break; case STORE: printf("STORing %d to address %d\n", stack[sp-2], stack[sp-1]); heap[stack[sp-1]] = stack[sp-2]; sp -= 2; break; case LDX: printf("LOADing indexed %d from address %d\n", heap[stack[sp-1]+stack[sp-2]], stack[sp-1]+stack[sp-2]-1); stack[sp-1] = heap[stack[sp-1]+stack[sp-2]-1]; break; case STX: printf("STORing indexed %d to address %d\n", stack[sp-2], stack[sp-1]+stack[sp-3]-1); heap[stack[sp-1]+stack[sp-3]-1] = stack[sp-2]; sp -= 2; break; } printf("stack = "); for(i=0; i < sp; i++) printf("%d ", stack[i]); printf("\nreturn stack = "); for(i=0; i < rsp; i++) printf("%d ", return_stack[i]); printf("\n"); sp = min(max(sp, 0), 255); ip %= 1024; #ifdef FAST_SWEET } #endif return !busy; } void main(void){ do{ // getchar(); } while(!sweet(program)); }