Skip to content

Instantly share code, notes, and snippets.

Created April 8, 2017 09:41
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/373dd0bd0198a8d0f367a590969cccee to your computer and use it in GitHub Desktop.
Save anonymous/373dd0bd0198a8d0f367a590969cccee to your computer and use it in GitHub Desktop.
A simulator of the J1 Forth CPU - running SIMPL - on an Arduino Due (Atmel ARM M3)
// This is a cross compiler which uses the SIMPL text interpreter framework to compile short phrases of J1
// machine language which are then executed on a simulated J1
// J1_DUE_Sim_24
// This version runs on an Arduino Due - or any of the larger RAM Arduinos
// Ken Boak April 2017
char num_buff[11]; // buffer large enough to hold 10 digit 32 bit int
char *num_buff_ptr;
int i = 0 ;
int number = 0;
int number3 = 0;
int ch3 = 0;
int token = 0;
int assm = 0;
// int putcharx(int);
// int putchar1(int);
// SIMPL initialisation
#define bufRead(addr) (*(unsigned char *)(addr))
#define bufWrite(addr, b) (*(unsigned char *)(addr) = (b))
unsigned char bite;
unsigned int x = 0;
unsigned int y = 0;
int len = 48;
char array[26][48];
int a = 0; // integer variables a,b,c,d
int b = 0;
int c = 0;
int e = 5; // d is used to denote the digital port pin for I/O operations
int z = 0;
char name;
char* parray;
char buf[64];
char* addr;
// ------ J1 simulator functions
void setup_J1(void);
static void execute(int);
static void push(int);
static int pop(void);
//---------------------------------------------------------------------------------
// Variables used in J1 CPU model
unsigned short m[0x1000]; // 4096 words of RAM
static unsigned long time_gone = 0;
static unsigned short t;
static unsigned short n; //2nd item on stack
static unsigned short d[0x20]; // data stack
static unsigned short r[0x20]; // return stack
static unsigned short pc; // program counter, counts 16 bit words (cells)
static unsigned char dsp, rsp; // point to top entry
// static unsigned short* memory; // ram
static int sx[4] = { 0, 1, -2, -1 }; // 2-bit sign extension
unsigned int insn; // the 16 bit encoded instruction
unsigned int _t;
unsigned int _pc;
unsigned int target; // 13 bit target address for jumps and calls
unsigned int next_t;
long loop_count = 0;
int count = 0;
//---------------------------------------------------------------------------------
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
setup_J1();
Serial.println("Starting J1 Simulator");
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
parray = &array[0][0]; // parray is the pointer to the first element
}
//----------------------------------------------------------------------------------------------------------
// Start of the main while loop
//----------------------------------------------------------------------------------------------------------
void loop() {
txtRead(buf, 64);
txtChk(buf); // check if it is a colon definition
txtEval(buf);
} // End of while
//------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
void setup_J1(void) {
// Load up a simple count program into first 7 locations of memory
m[0] = 0x8020; // LIT 0x20 (0x20 is the address of the count variable
m[1] = 0x6C00; // Fetch [0020]
m[2] = 0x8001; // LIT 1 We are going to add 10
m[3] = 0x6200; // ADD
m[4] = 0x8020; // LIT 0x20
m[5] = 0x6020; // Store
m[6] = 0x0000; // JMP 0000
m[7] = 0x0000; // NOP
m[8] = 0x6000; // NOP
m[9] = 0x0000; // JMP 0000
m[10] = 0x0000;
m[11] = 0x0000; //LIT 31
m[12] = 0x0000; //LIT 51
m[13] = 0x0000; // OR
m[14] = 0x0000;
m[15] = 0x0000; // JMP 00
m[16] = 0x0000;
m[17] = 0x0000; //Literal 0x0123
m[18] = 0x0000;
m[19] = 0x0000;
m[20] = 0x0000;
m[21] = 0x6300;
m[22] = 0x6400;
m[23] = 0x6500;
m[24] = 0x6600;
m[25] = 0x6700;
m[26] = 0x6800;
m[27] = 0x6900;
m[28] = 0x6A00;
m[29] = 0x6B00;
m[30] = 0x6C00;
m[31] = 0x6D00;
m[32] = 0x0000; // Use this location as a counter
m[33] = 0x6F00;
m[34] = 0x0000;
m[35] = 0x2001;
m[36] = 0x4002;
m[37] = 0x8003;
m[38] = 0x8004;
m[39] = 0x8005;
m[40] = 0x8006;
//----------------------------------------------------------------------------------
// Clear the rest of the first 255 bytes of memory
for(i=41; i<=255; i++)
{
m[i] = 0; // clear memory
}
for(i=0; i<=32; i++) // clear data stack and return stack
{
d[i] = 0;
r[i] = 0;
}
pc = 0;
}
// End of Setup_J1
//--------------------------------------------------------------------------------------
// CPU Model
static void push(int v) // push v onto the data stack
{
dsp = 0x1f & (dsp + 1);
d[dsp] = t;
t = v;
}
static int pop(void) // pop value from the data stack and return it
{
int v = t;
t = d[dsp];
dsp = 0x1f & (dsp - 1);
return v;
}
// ------------------------------------------------------------------------
static void execute(int instruction) // This is the CPU model
{
insn = (instruction & 0xFFFF) ;
_pc = pc + 1;
if (insn & 0x8000) { // literal
push(insn & 0x7fff);
// Serial.println("PUSHED");
}
else {
int target = insn & 0x1fff;
switch (insn >> 13) {
case 0: // jump
_pc = target;
break;
case 1: // conditional jump
if (pop() == 0)
_pc = target;
break;
case 2: // call
rsp = 31 & (rsp + 1);
r[rsp] = _pc << 1;
_pc = target;
break;
case 3: // ALU
if (insn & 0x1000) /* R->PC */
_pc = r[rsp] >> 1;
n = d[dsp];
switch ((insn >> 8) & 0xf) {
case 0: _t = t; break;
case 1: _t = n; break;
case 2: _t = t + n; break;
case 3: _t = t & n; break;
case 4: _t = t | n; break;
case 5: _t = t ^ n; break;
case 6: _t = ~t; break;
case 7: _t = -(t == n); break;
case 8: _t = -((signed short)n < (signed short)t); break;
case 9: _t = n >> t; break;
case 10: _t = t - 1; break;
case 11: _t = r[rsp]; break;
case 12: _t = m[t]; break;
case 13: _t = n << t; break;
case 14: _t = (rsp << 8) + dsp; break;
case 15: _t = -(n < t); break;
}
dsp = 31 & (dsp + sx[insn & 3]);
rsp = 31 & (rsp + sx[(insn >> 2) & 3]);
if (insn & 0x80) /* T->N */
d[dsp] = t;
if (insn & 0x40) /* T->R */
r[rsp] = t;
if (insn & 0x20) /* N->[T] */
m[t] = n;
t = _t;
break;
}
}
pc = _pc;
insn = m[pc];
next_t = _t;
}
// End of CPU model
// ------------------------------------------------------------------------
// SIMPL Text Interpreter
// ------------------------------------------------------------------------
void txtRead (char *p, byte n) {
byte i = 0;
while (i < (n-1)) {
while (!Serial.available());
char ch = Serial.read();
if (ch == '\r' || ch == '\n') break;
if (ch >= ' ' && ch <= '~') {
*p++ = ch;
i++;
}
}
*p = 0;
}
void txtChk (char *buf) { // Check if the text starts with a colon and if so store in temp[]
if (*buf == ':') {
char ch;
int i =0;
while ((ch = *buf++)){
if (ch == ':') {
Serial.println(*buf); // get the name from the first character
name = *buf ;
buf++;
}
bufWrite((parray + (len*(name-65) +i)),*buf);
i++;
}
x = 1;
}
}
// ------------------------------------------------------------------------
void txtEval (char *buf) {
unsigned int k = 0;
char *loop;
char ch;
while ((ch = *buf++)) {
switch (ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
x = ch - '0';
while (*buf >= '0' && *buf <= '9') {
x = x*10 + (*buf++ - '0');
}
break;
case 'A': // Points the interpreter to the array containing the User defined words
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':
name = ch - 65;
addr = parray + (len*name);
txtEval(addr);
break;
//---------------------------------------------------------------------------------------------
// Decode the tokens and form the J1 machine Instructions
//---------------------------------------------------------------------------------------------
/*
* Literal 8000H + Value (15 bits)
*
* Jump 0000H + destination (13 bits)
*
* Conditional Jump 2000H + destination (13 bits)
*
* Call 4000H + destination (13 bits)
*
* ALU Operations Bits 8 - 11 + 6000H
*
* 0 T
* 1 N
* 2 T+N
* 3 T&N
* 4 T|N
* 5 T^N
* 6 ~T
* 7 N=T
* 8 T>N
* 9 N>>T
* 10 T-1
* 11 R
* 12 [T]
* 13 N<<T
* 14 Depth
* 15 Tu>N
*
* Stack Moves
*
* T->N Bit 7
* T->R Bit 6
* N->[T] Bit 5
* R->PC Bit 4
*
* ALU Return Stack Bits 3,2
*
* r+0 0
* r+1 1
* r-1 3
* r-2 2
*
* ALU Stack Variable Bits 1,0
*
* d+0 0
* d+1 1
* d-1 3
* d-2 2
*
*
*/
//---------------------------------------------------------------------------------------------
// Form the J1 opcodes
//---------------------------------------------------------------------------------------------
case '\r' :
break;
case '\n' :
break;
// ALU Logical and arithmetic Operations
case '#' : //NOP
token = 0;
Serial.print(" NOP ");
Serial.print( assm = (256 * token)+ 24576,HEX);
break;
case '+' : //ADD
token = 2;
Serial.print(" ADD ");
Serial.print( assm = (256 * token)+ 24576+3,HEX);
break;
case '&' : //AND
token = 3;
Serial.print(" AND ");
Serial.print( assm = (256 * token)+ 24576+3,HEX);
break;
case '|' : //OR
token = 4;
Serial.print(" OR ");
Serial.print( assm = (256 * token)+ 24576+3,HEX);
break;
case '^' : //XOR
token = 5;
Serial.print(" XOR ");
Serial.print( assm = (256 * token)+ 24576+3,HEX);
break;
case '~' : //INV
token = 6;
Serial.print(" INV ");
Serial.print( assm = (256 * token)+ 24576,HEX);
break;
case '-' : //SUB
token = 6;
assm = (128 * token)+ 24576;
Serial.print(" SUB ");
Serial.print( assm = (256 * token)+ 24576,HEX);
break;
case '*' : //MUL/SHL
token = 13;
assm = (256 * token)+ 24576 +3;
Serial.print(" SHL ");
Serial.print( assm, HEX);
break;
case '/' : //DIV/SHR
token = 9;
assm = (256 * token)+ 24576 +3;
Serial.print(" SHR ");
Serial.print( assm, HEX);
break;
//--------------------------------------------------------------
// Comparison Operations
//--------------------------------------------------------------
case '<' : //LT
token = 8;
assm = (256 * token)+ 24576 +3;
Serial.print(" LT ");
Serial.print( assm, HEX);
break;
case '=' : //EQ
token = 7;
assm = (256 * token)+ 24576 +3;
Serial.print( assm, HEX);
Serial.print(" EQ ");
break;
case '>' : //GT
token = 0;
Serial.print(" GT ");
break;
//--------------------------------------------------------------
// Stack Operations
//--------------------------------------------------------------
case ',' : //PUSH
token = 0;
Serial.print(" PUSH ");
Serial.print( assm = (256 * token)+ 24576 +3,HEX);
break;
case '.' : //POP/EMIT
token = 0;
Serial.print(" POP ");
break;
case '"' : //DUP
token = 0;
assm = 24576 + 128 + 1;
Serial.print(" DUP ");
Serial.print( assm ,HEX);
break;
case 39 : //DROP
token = 1;
assm = (256 * token)+ 24576 +3;
Serial.print(" DROP ");
Serial.print( assm ,HEX);
break;
case '$' : // SWAP
token = 1;
assm = (256 * token)+ 24576 +128 + 0 ;
Serial.print(" SWAP ");
Serial.print( assm ,HEX);
break;
case '%' : //OVER
token = 1;
assm = (256 * token)+ 24576 +128 + 1 ;
Serial.print(" OVER ");
Serial.print( assm ,HEX);
break;
case ' ' : //LIT
token = 0;
assm = 32768 + x ;
Serial.print(x);
Serial.print(" LIT ");
Serial.print(assm,HEX);
break;
//----------------------------------------------
// Conditional Execution - Program Flow
case '(' : //BEGIN
token = 0;
Serial.print(" BEGIN ");
break;
case ')' : //END
token = 0;
Serial.print(" END ");
break;
case '{' : //DO
token = 0;
Serial.print(" DO ");
break;
case '}' : //LOOP
token = 0;
Serial.print(" LOOP ");
break;
case 92 : //JUMP
token = 0;
assm = x ;
Serial.print(x);
Serial.print(" JUMP ");
break;
case ':' : //CALL
token = 0;
assm = 16384 + x;
Serial.print(x);
Serial.print(" CALL ");
break;
case ';' : //RET/EXIT
token = 0;
assm = 24576 + 4096 + 12;
Serial.print(" RET ");
Serial.print( assm ,HEX);
break;
case '?' : //?KEY
token = 0;
Serial.print("?KEY ");
break;
//--------------------------------------------------------------
// Memory Operations
//--------------------------------------------------------------
case '@' : //FETCH
token = 12;
assm = 24576 + (256 * token);
Serial.print(" FETCH ");
Serial.print(assm, HEX);
break;
case '!' : //STORE
token = 1;
assm = 24576 + (256 * token) + 32 + 3;
Serial.print(" STORE ");
Serial.print(assm, HEX);
break;
//--------------------------------------------------------------
// Compound Operations - a work in progress
//--------------------------------------------------------------
case '[' : //SWITCH
token = 0;
Serial.print(" SWITCH ");
break;
case ']' : //CASE
token = 0;
Serial.print(" CASE ");
break;
case '_' : //STRING
token = 0;
Serial.print(" STRING ");
break;
case '`' : //TOR - move T to R and vice versa
token = 11;
assm = (256 * token) + 24576 + 128 + 64 + 1 + 12;
Serial.print(" TOR ");
Serial.print(assm, HEX);
break;
case 'r' : //FROMR - move T to R and vice versa
token = 1;
assm = (256 * token) + 24576 + 64 + 3 + 8;
Serial.print(" FROMR ");
Serial.print(assm, HEX);
break;
} // End of Switch-Case
execute(assm); // single step the J1 instruction
// Some Debug output
Serial.print(" PC=");
Serial.print(pc,HEX);
Serial.print(" TOP=");
Serial.print(t,HEX);
Serial.print(" DS0=");
Serial.print(d[dsp],HEX);
Serial.print(" DS1=");
Serial.print(d[dsp-1],HEX);
Serial.print(" DS2=");
Serial.print(d[dsp-2],HEX);
Serial.print(" DS3=");
Serial.print(d[dsp-3],HEX);
Serial.print(" RTN=");
Serial.print(r[rsp],HEX);
Serial.print(" MEM20=");
Serial.print(m[32],HEX);
Serial.print(" MEM21=");
Serial.print(m[33],HEX);
Serial.print(" MEM22=");
Serial.print(m[34],HEX);
Serial.println();
}
// ------------------------------------------------------------------------
} // End of main loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment