Close

Simulating the O/S

A project log for 8 Bit TTA Interpreter

TTA (Transport Triggered Architecture) is very simple CPU type.

agpcooperagp.cooper 05/25/2018 at 13:050 Comments

Simulating the O/S

I coded in C the cut down version of the Mouse-79 interpreter.

Did not like the '$' for the end of code so I made '\n' the end of code marker (still '$' internally) and used '\' as a line continuation code.

The intrepreter does not have unary minus (i.e. you cannot enter negative number directly), so I fixed that.

Finally, the interpreter needs an "exchange" code for the two top of data stack values. In Forth it is called SWAP. It was fixed in Mouse-83 by using the assignment operator. I think the exchange operator is better. I used the '%' symbol for it.

There are a number of Forth operators that could be added but that is for another day.

The Code

I split the code into two halves, the Op-Codes I have written that will be converted into micro-code and the Mouse interpreter. Here is the mouse interpreter:

// MOUSE O/S Language Reference
//
// $   [36]      CR/LF or NL end of program code, encoded with '$'
// "   [34]      print up to next "
// !   [33]      print CR/LF inside "'s
// ?   [63]      read number from stdin and push
// !   [33]      pop number from stack and print it
// n   [48-57]   push the integer n onto stack
// A-Z [65-90]   push address of variable on stack
// .   [46]      replace address on stack with value
// =   [61]      pop value, pop address, write value at address
// +   [43]      pop a, pop b, push a + b
// -   [45]      pop a, pop b, push a - b
// *   [42]      pop a, pop b, push a * b
// /   [47]      pop a, pop b, push a / b
// [   [91]      pop c, if c<=0 then skip to ] on same level
// ]   [93]      end if
// (   [40]      begin loop
// )   [41]      loop back to previous ( at same level
// ^   [94]      pop c, if c!=0 then break out of loop
// ' ' [32]      space, sometimes necessary to deliminate numbers
// \   [92]      continue on next line
// %   [37]      exchange top two data stack variable
// Example program:
//
// X 100 =
// (
//    X. ! " Bottle(s) of beer on the wall,!"
//    X. ! " bottle(s) of beer!"
//    "Take one down and pass it around,!"
//    X X. 1 - =
//    X. ! " bottle(s) of beer on the wall.!"
//    X. ^
// )
// $

#include <stdio.h>
#include <stdlib.h>
#include "OpCodes.c"

char     CODE[256];
int16_t  DATA_STACK[20];
int16_t  RETURN_STACK[20];
int16_t  VAR[26];
int16_t  DATA_PTR;
int16_t  CODE_PTR;
int16_t  RETURN_PTR;
int16_t  PARNUM;
int16_t  PARBAL;
int16_t  TEMPA;
int16_t  TEMPB;
char     CH;

void GETCHAR(void) {
  CODE_PTR=CODE_PTR+1;
  CH=CODE[CODE_PTR];
}

void PUSH_DATA(int16_t DATA) {
  DATA_PTR=DATA_PTR+1;
  DATA_STACK[DATA_PTR]=DATA;
}

int16_t POP_DATA(void) {
  int16_t tmp;

  tmp=DATA_STACK[DATA_PTR];
  DATA_PTR=DATA_PTR-1;
  if (DATA_PTR<-1) DATA_PTR=-1;
  return(tmp);
}

void PUSH(void) {
    RETURN_PTR=RETURN_PTR+1;
    RETURN_STACK[RETURN_PTR]=CODE_PTR;
}

void POP(void) {
    CODE_PTR=RETURN_STACK[RETURN_PTR];
    RETURN_PTR=RETURN_PTR-1;
    if (RETURN_PTR<-1) RETURN_PTR=-1;
}

void SKIP (char LCH,char RCH) {
    int16_t CNT;

    CNT=1;
    do {
        GETCHAR();
        if (CH==LCH) {
           CNT=CNT+1;
        } else if (CH==RCH) {
           CNT=CNT-1;
        }
    } while (CNT!=0);
}

void GETINT(void) {
  int16_t temp,tmp2;

  temp=0;
  while ((CH>='0')&&(CH<='9')) {
    tmp2=temp+temp;
    temp=tmp2+tmp2;
    temp=temp+temp;
    temp=temp+tmp2+CH-48;
    GETCHAR();
  }
  CODE_PTR=CODE_PTR-1;
  PUSH_DATA(temp);
}

void QUOTE(void) {
  do {
    GETCHAR();
    if (CH=='!') {
      PutChar('\n');
    } else if (CH!='"') {
      PutChar(CH);
    }
  } while (CH!='"');
}

int main (void)
{
  printf("RTN DATA");
  RETURN_PTR=-1;
  DATA_PTR=-1;
  while (1) {
    PutChar('\n');
    printf("%3d %4d",RETURN_PTR+1,DATA_PTR+1);
    PutChar('>');
    // Read Evalute Repeat Loop
    CODE_PTR=-1;
    do { // Read command
      CH=GetChar();
      if ((CH!='\r')&&(CH!='\n')&&(CH!='\\')&&(CH!='$')) {
        CODE_PTR=CODE_PTR+1;
        CODE[CODE_PTR]=CH;
      } else if (CH=='\r') {
        // Skip
      } else if (CH=='\n') {
        // Encode as $
        CH='$';
        CODE_PTR=CODE_PTR+1;
        CODE[CODE_PTR]=CH;
      } else if (CH=='\n') {
        // Skip
      } else {
        // '\' Extend line
        CODE_PTR=CODE_PTR+1;
        CODE[CODE_PTR]=' ';
        // Skip until \n
        while (GetChar()!='\n');
      }
    } while (CH!='$');

    // Evaluate command
    CODE_PTR=-1;
    do {
      GETCHAR();
      switch (CH) {
        case ' ':
        case ']':
        case '$':
          break;
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
          GETINT();
          break;
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
        case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
        case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
        case 'V': case 'W': case 'X': case 'Y': case 'Z':
          TEMPA=CH-65; // 0 based
          PUSH_DATA(TEMPA);
          break;
        case '?':
          TEMPA=rdInt();
          PUSH_DATA(TEMPA);
          break;
        case '!':
          TEMPA=POP_DATA();
          wrInt(TEMPA);
          break;
        case '+':
          TEMPA=POP_DATA();
          TEMPB=POP_DATA();
          PUSH_DATA(Add(TEMPA,TEMPB));
          break;
        case '-':
          GETCHAR();
          if ((CH>='0')&&(CH<='9')) {
            GETINT();
            TEMPA=0;
            TEMPB=POP_DATA();
          } else {
            CODE_PTR=CODE_PTR-1;
            TEMPA=POP_DATA();
            TEMPB=POP_DATA();
          }
          PUSH_DATA(Sub(TEMPA,TEMPB));
          break;
        case '*':
          TEMPA=POP_DATA();
          TEMPB=POP_DATA();
          PUSH_DATA(imul(TEMPA,TEMPB));
          break;
        case '/':
          TEMPA=POP_DATA();
          TEMPB=POP_DATA();
          PUSH_DATA(idiv(TEMPA,TEMPB));
          break;
        case '.':
          TEMPA=POP_DATA();
          TEMPB=VAR[TEMPA];
          PUSH_DATA(TEMPB);
          break;
        case'=':
          TEMPA=POP_DATA();
          TEMPB=POP_DATA();
          VAR[TEMPB]=TEMPA;
          break;
        case '"':
          QUOTE();
          break;
        case '[':
          TEMPA=POP_DATA();
          if (TEMPA<=0) SKIP('[',']');
          break;
        case '(':
          PUSH();
          break;
        case '^':
          TEMPA=POP_DATA();
          if (TEMPA<=0) {
            POP();
            SKIP('(',')');
          }
          break;
        case ')':
          CODE_PTR=RETURN_STACK[RETURN_PTR];
          break;
        case '%':
          TEMPA=POP_DATA();
          TEMPB=POP_DATA();
          PUSH_DATA(TEMPA);
          PUSH_DATA(TEMPB);
          break;
      }
    } while (CH!='$');

  };
  return 0;
}

Here is a run:

alanx@alanx ~/Documents/AlanC_Ccode_Mint/MouseOS $ ./MouseOS
RTN DATA
  0    0>\
  X 10 =                                     \
  (                                          \
    X. ! " Bottle(s) of beer on the wall,!"  \
    X. ! " bottle(s) of beer!"               \
    "Take one down and pass it around,!"     \
    X X. 1 - =                               \
    X. ! " bottle(s) of beer on the wall.!"  \
    X. ^                                     \
  )
10 Bottle(s) of beer on the wall,
10 bottle(s) of beer
Take one down and pass it around,
9 bottle(s) of beer on the wall.
9 Bottle(s) of beer on the wall,
9 bottle(s) of beer
Take one down and pass it around,
8 bottle(s) of beer on the wall.
8 Bottle(s) of beer on the wall,
8 bottle(s) of beer
Take one down and pass it around,
7 bottle(s) of beer on the wall.
7 Bottle(s) of beer on the wall,
7 bottle(s) of beer
Take one down and pass it around,
6 bottle(s) of beer on the wall.
6 Bottle(s) of beer on the wall,
6 bottle(s) of beer
Take one down and pass it around,
5 bottle(s) of beer on the wall.
5 Bottle(s) of beer on the wall,
5 bottle(s) of beer
Take one down and pass it around,
4 bottle(s) of beer on the wall.
4 Bottle(s) of beer on the wall,
4 bottle(s) of beer
Take one down and pass it around,
3 bottle(s) of beer on the wall.
3 Bottle(s) of beer on the wall,
3 bottle(s) of beer
Take one down and pass it around,
2 bottle(s) of beer on the wall.
2 Bottle(s) of beer on the wall,
2 bottle(s) of beer
Take one down and pass it around,
1 bottle(s) of beer on the wall.
1 Bottle(s) of beer on the wall,
1 bottle(s) of beer
Take one down and pass it around,
0 bottle(s) of beer on the wall.

  0    0>^C

I have had enough to drink tonight!

AlanX

Discussions