Created
September 6, 2015 16:18
-
-
Save anonymous/5edc63145756aab9284e to your computer and use it in GitHub Desktop.
J1 Emulator running on Arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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