Skip to content

Instantly share code, notes, and snippets.

Created September 6, 2015 16:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/5edc63145756aab9284e to your computer and use it in GitHub Desktop.
Save anonymous/5edc63145756aab9284e to your computer and use it in GitHub Desktop.
J1 Emulator running on Arduino
// J1 Forth Processor simulator on Arduino Duemillenove 63K instructions per second -
// A simple 10 instruction loop - used to test execution speed
// Ken Boak April - September 2015
//------------------------------------------------------------------------------------------------
// Variables used in J1 CPU model
unsigned short m[0x0100]; // 256 words of RAM
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;
//------------------------------------------------------------------------------------------------
void setup(void) {
Serial.begin(115200);
pinMode(6,OUTPUT);
// Load up a simple program into first 40 locations of memory
m[0] = 0x8010; // LIT 10
m[1] = 0x6C00; // Fetch
m[2] = 0x6000; // NOP
m[3] = 0x8001; // LIT 1
m[4] = 0x6200; // ADD
m[5] = 0x8010; // LIT 10
m[6] = 0x6020; // Store
m[7] = 0x6030; // Store
m[8] = 0x6200; // ADD
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] = 0x6E00;
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 1K of memory
for(int i=41; i<=255; i++)
{
m[i] = 0; // clear memory
}
for(int i=0; i<=32; i++) // clear data stack and return stack
{
d[i] = 0;
r[i] = 0;
}
pc = 0;
}
// End of Setup
//-----------------------------------------------------------------------
void loop(void) {
execute(m[pc]); // get the next instruction and execute it using the cpu model
if(!pc) // print the millis each time the pc = 0
{
loop_count ++;
if(!(loop_count % 100000))
{
digitalWrite(6, HIGH);
Serial.print(millis());
Serial.print(" ");
Serial.println(pc);
digitalWrite(6,LOW);
}
}
} // end of loop
//--------------------------------------------------------------------------------------
// 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);
}
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
// ------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment