Created
April 25, 2015 18:26
-
-
Save anonymous/559008675da22f909053 to your computer and use it in GitHub Desktop.
Animated J1 Forth Processor Simulator to run on ZPUino
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
// An animated simulator for James Bowman's J1 Forth Processr | |
// Runs on ZPUino and produces animated VGA window into memory | |
// Ken Boak April 2015 | |
// ZPUino by Alvarp Lopez | |
// Papilio Duo and Logic Start Shield by Gadget Factory | |
//Uncomment to use with a Computing Shield on Papilio DUO | |
//#define circuit Computing_Shield2 | |
//Uncomment to use with a LogicStart Shield on Papilio DUO | |
#define circuit LogicStart_Shield2 | |
#include <Adafruit_GFX.h> | |
#include <ZPUino_GFX.h> | |
#include <PLL.h> | |
// Assign human-readable names to some common 16-bit color values: | |
#define BLACK 0x0000 | |
#define BLUE 0x001F | |
#define RED 0xF800 | |
#define GREEN 0x07E0 | |
#define CYAN 0x07FF | |
#define MAGENTA 0xF81F | |
#define YELLOW 0xFFE0 | |
#define WHITE 0xFFFF | |
#define min(x,y) ((x)>(y) ? (y):(x)) | |
ZPUino_GFX gfx; | |
unsigned short m[0x4000]; /* 32kb or RAM */ | |
static unsigned short t; | |
static unsigned short s; | |
static unsigned short d[0x20]; /* data stack */ | |
static unsigned short r[0x20]; /* return stack */ | |
static unsigned short pc; /* program counter, counts 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; | |
unsigned int _t; | |
unsigned int _pc; | |
unsigned int target; | |
unsigned int next_t; | |
void setup(void) { | |
Serial.begin(115200); | |
gfx.begin( &modeline_800x600_60 ); //Highest mode supported by Papilio DUO 2MB | |
gfx.fillScreen(WHITE); | |
gfx.setTextColor(BLACK); | |
/* | |
m[0] = 0x8123; //Literal 123 | |
m[1] = 0x6000; | |
m[2] = 0x6100; | |
m[3] = 0x6200; | |
m[4] = 0x6300; | |
m[5] = 0x6400; | |
m[6] = 0x6500; | |
m[7] = 0x6600; | |
m[8] = 0x6700; | |
m[9] = 0x6800; | |
m[10] = 0x6900; | |
m[11] = 0x6A00; | |
m[12] = 0x6B00; | |
m[13] = 0x6C00; | |
m[14] = 0x6D00; | |
m[15] = 0x6E00; | |
m[16] = 0x6F00; | |
m[17] = 0x0000; | |
m[18] = 0x2001; | |
m[19] = 0x4002; | |
m[20] = 0x8003; | |
m[21] = 0x8004; | |
m[22] = 0x8005; | |
m[23] = 0x8006; | |
m[24] = 0x8007; | |
*/ | |
// Load up a simple program into first 40 locations of memory | |
m[0] = 0x6000; // NOP | |
m[1] = 0x8010; // LIT 10 | |
m[2] = 0x8010; // LIT 10 | |
m[3] = 0x6200; // ADD | |
m[4] = 0x2001; // BZ 1 | |
m[5] = 0x000B; // JMP 0B | |
m[6] = 0x6000; // NOP | |
m[7] = 0x6000; // NOP | |
m[8] = 0x6000; | |
m[9] = 0x6000; | |
m[10] = 0x6000; | |
m[11] = 0x8031; //LIT 31 | |
m[12] = 0x8051; //LIT 51 | |
m[13] = 0x6400; // OR | |
m[14] = 0x6700; | |
m[15] = 0x0000; // JMP 00 | |
m[16] = 0x6000; | |
for(int i=32; i<=1024; 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; | |
} | |
dump_memory(); // show the first 1024 words of memory in dump window | |
disassemble(0,40, 0xFFF0); // Produce the disaassembler window | |
pc = 0; | |
} | |
void loop(void) { | |
// gfx.fillScreen(WHITE); | |
gfx.setCursor(0,0); | |
gfx.setTextSize(1); | |
data_stack_print(0,0,GREEN); | |
return_stack_print(0,0,YELLOW); | |
display_regs(); | |
execute(m[pc] ); // get the next instruction and execute it using the cpu model | |
highlight_address(pc,CYAN); | |
disassemble(pc,0, YELLOW); | |
// highlight_pc(YELLOW); | |
// display_regs(); | |
delay(500); | |
highlight_address(pc,0xFFF0); // back to pale yellow | |
// highlight_pc(0xFFF0); | |
disassemble(pc,0, 0xFFF0); | |
delay(500); | |
} // end of loop | |
void clear_address(int address, int colour) | |
{ | |
int row; | |
int column; | |
int page; | |
int pagestart; | |
page = address/1024; // defines the 1K page start | |
pagestart = 1024 * page; | |
row = (address -pagestart)/16; | |
column = (address - pagestart)%16; | |
row = row * 8; | |
column = (column +2) * 30; | |
Serial.print(row); | |
Serial.print(" "); | |
Serial.println(column); | |
gfx.setTextColor(BLACK,colour); | |
gfx.setCursor(column,row); | |
gfx.setTextSize(1); | |
gfx.print(" "); | |
} | |
void highlight_address(int address, int colour) | |
{ | |
int row; | |
int column; | |
int page; | |
int pagestart; | |
page = address/1024; // defines the 1K page start | |
pagestart = 1024 * page; | |
row = (address -pagestart)/16; | |
column = (address - pagestart)%16; | |
row = row * 8; | |
column = (column +2) * 30; | |
Serial.print(row); | |
Serial.print(" "); | |
Serial.println(column); | |
gfx.setTextColor(BLACK,colour); | |
gfx.setCursor(column,row); | |
gfx.setTextSize(1); | |
gfx.print(m[address],HEX); | |
} | |
void data_stack_print(int x_pos, int y_pos, int colour) | |
{ | |
for(int k = 0; k<=31; k++) | |
{ | |
gfx.setTextColor(BLACK,WHITE); | |
gfx.setCursor(570, (y_pos + 8 *k)); | |
gfx.setTextSize(1); | |
gfx.print(k, HEX); | |
gfx.setTextColor(BLACK,colour); | |
gfx.setCursor(600, (y_pos + 8 *k)); | |
gfx.setTextSize(1); | |
if(d[k] >=0 && d[k] < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(d[k] >=16 && d[k] < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if(d[k] >=256 && d[k] < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(d[k], HEX); | |
} | |
} | |
void return_stack_print(int x_pos, int y_pos, int colour) | |
{ | |
for(int k = 0; k<=31; k++) | |
{ | |
gfx.setTextColor(BLACK,colour); | |
gfx.setCursor(660, (y_pos + 8 *k)); | |
gfx.setTextSize(1); | |
if(r[k] >=0 && r[k] < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(r[k] >=16 && r[k] < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if(r[k] >=256 && r[k] < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(r[k], HEX); | |
} | |
} | |
void disassemble(int address, int range, int colour) // Produce a dissasmbler display output | |
{ | |
int mode; | |
int insn; | |
int target; | |
int literal; | |
for(int i = 0; i <=range; i++) // define the instruction range for disassembly | |
{ | |
if(m[address+i] & 0x8000) | |
{ | |
mode = 8; | |
} | |
else if (m[address+i] & 0x7000) | |
{ | |
mode = (m[address+i] & 0x7000) >>12; | |
} | |
else if (!(m[address+i] & 0xF000)) | |
{ | |
mode = 0; | |
} | |
gfx.setTextColor(BLACK,colour); | |
gfx.setTextSize(1); | |
gfx.setCursor(570, (256 + 8 *i)); | |
if (i == 0) | |
{ | |
gfx.setCursor(570, (256 + 8 *address)); | |
} | |
//-------------------------------------------------------------- | |
// Print out the Address | |
if(address+i >= 0 && address+i < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(address+i >=16 && address+i < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if(address+i >=256 && address+i < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(address+i,HEX); | |
gfx.print(" "); | |
// Serial.print(address+i,HEX); | |
// Serial.print(" "); | |
//---------------------------------------------------------- | |
//Print out the data | |
if(m[address+i] >=0 && m[address+i] < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(m[address+i] >=16 && m[address+i] < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if(m[address+i] >=256 && m[address+i] < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(m[address +i], HEX); | |
//Serial.print(m[address +i], HEX); | |
//Serial.print(" "); | |
//----------------------------------------------------------- | |
// Print out the Mode | |
Serial.println(mode); | |
/* | |
*/ | |
gfx.print(" "); | |
gfx.print(mode); | |
gfx.print(" "); | |
//----------------------------------------------------------- | |
//Print out literals | |
if(mode == 8) | |
{ | |
gfx.print("LIT "); | |
literal = (m[address +i] & 0x7fff); | |
gfx.print(" "); | |
if(literal >=0 && literal < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(literal >=16 && literal < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if (literal >=256 && literal < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(literal, HEX); | |
} | |
//------------------------------------------------------------ | |
if(mode == 0) | |
{ | |
gfx.print("JMP "); | |
} | |
if(mode == 2) | |
{ | |
gfx.print("BRZ "); | |
} | |
if(mode == 4) | |
{ | |
gfx.print("CALL"); | |
} | |
if (mode == 0 | mode == 2 | mode == 4) | |
{ | |
target = (m[address +i] & 0x1fff); | |
gfx.print(" "); | |
if(target >=0 && target < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(target >=16 && target < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if (target >=256 && target < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(target, HEX); | |
} | |
//----------------------------------------------- | |
// Decode the ALU Instructions | |
if (mode == 6) | |
{ | |
insn = (m[address+i] & 0x0F00)>>8; | |
switch(insn) | |
{ | |
case 0: | |
gfx.print("NOP "); | |
break; | |
case 1: | |
gfx.print("COPY"); | |
break; | |
case 2: | |
gfx.print("ADD "); | |
break; | |
case 3: | |
gfx.print("AND "); | |
break; | |
case 4: | |
gfx.print("OR "); | |
break; | |
case 5: | |
gfx.print("XOR "); | |
break; | |
case 6: | |
gfx.print("NEG "); | |
break; | |
case 7: | |
gfx.print("= "); | |
break; | |
case 8: | |
gfx.print("< "); | |
break; | |
case 9: | |
gfx.print("SRA "); | |
break; | |
case 10: | |
gfx.print("1- "); | |
break; | |
case 11: | |
gfx.print("R@ "); | |
break; | |
case 12: | |
gfx.print("MEM "); | |
break; | |
case 13: | |
gfx.print("SLA "); | |
break; | |
case 14: | |
gfx.print("DSP "); | |
break; | |
case 15: | |
gfx.print("U< "); | |
break; | |
} | |
} | |
gfx.print(" "); | |
// gfx.println(insn); | |
} | |
} | |
void display_regs(void) // Display the PC TOP 2ND DSP RSP INSN | |
{ | |
gfx.setTextColor(BLACK,0xFFF0); | |
gfx.setTextSize(1); | |
gfx.setCursor(60, (544)); | |
gfx.println("PC TOP 2ND DSP RSP INST"); | |
gfx.setCursor(60, (552)); | |
gfx.print(" "); // Clear the last reg_dump | |
gfx.setCursor(60, (552)); | |
gfx.print(pc,HEX); | |
gfx.setCursor(120, (552)); | |
gfx.print(_t,HEX); | |
gfx.setCursor(180, (552)); | |
gfx.print(s,HEX); | |
gfx.setCursor(240, (552)); | |
gfx.print(dsp,HEX); | |
gfx.setCursor(300, (552)); | |
gfx.print(rsp,HEX); | |
gfx.setCursor(360, (552)); | |
gfx.print(m[pc],HEX); | |
} | |
//-------------------------------------------------------------------------------------- | |
// 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; | |
Serial.print("PC "); | |
Serial.print(" "); | |
Serial.print((_pc), HEX); | |
if (insn & 0x8000) { // literal | |
Serial.print(" LIT"); | |
Serial.print(" "); | |
Serial.print((insn & 0x7fff), HEX); | |
push(insn & 0x7fff); | |
Serial.print(" TOP "); | |
Serial.print(t, HEX); | |
Serial.print(" 2ND "); | |
Serial.print(d[dsp], HEX); | |
} else { | |
target = insn & 0x1fff; | |
switch (insn >> 13) { | |
case 0: // jump | |
Serial.print(" MEM"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
_pc = target; | |
Serial.print(" JMP"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
break; | |
case 1: // conditional jump | |
Serial.print(" MEM"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
if (pop() == 0) | |
_pc = target; | |
Serial.print(" 0BR"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
break; | |
case 2: // call | |
Serial.print(" MEM"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
rsp = 31 & (rsp + 1); | |
r[rsp] = _pc << 1; | |
_pc = target; | |
Serial.print(" CALL"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
break; | |
case 3: // alu | |
Serial.print(" ALU"); | |
Serial.print(" "); | |
Serial.print(target, HEX); | |
if (insn & 0x1000) {/* r->pc */ | |
_pc = r[rsp] >> 1; | |
} | |
s = d[dsp]; | |
switch ((insn >> 8) & 0xf) { | |
case 0: _t = t; | |
Serial.print(" NOP"); | |
Serial.print(" "); | |
break; /* nop */ | |
case 1: _t = s; | |
Serial.print(" COPY"); | |
Serial.print(" "); | |
break; /* copy */ | |
case 2: _t = t+s; | |
Serial.print(" ADD"); | |
Serial.print(" "); | |
break; /* + */ | |
case 3: _t = t&s; | |
Serial.print(" AND"); | |
Serial.print(" "); | |
break; /* and */ | |
case 4: _t = t|s; | |
Serial.print(" OR "); | |
Serial.print(" "); | |
break; /* or */ | |
case 5: _t = t^s; | |
Serial.print(" XOR"); | |
Serial.print(" "); | |
break; /* xor */ | |
case 6: _t = ~t; | |
Serial.print(" NOT"); | |
Serial.print(" "); | |
break;/* invert */ | |
case 7: _t = -(t==s); | |
Serial.print(" EQU"); | |
Serial.print(" "); | |
break; /* = */ | |
case 8: _t = -((signed short)s < (signed short)t); | |
Serial.print(" < "); | |
Serial.print(" "); | |
break; /* < */ | |
case 9: _t = s>>t; | |
Serial.print(" >> "); | |
Serial.print(" "); | |
break; /* rshift */ | |
case 0xa: _t = t-1; | |
Serial.print(" 1- "); | |
Serial.print(" "); | |
break; /* 1- */ | |
case 0xb: _t = r[rsp]; | |
Serial.print(" r@ "); | |
Serial.print(" "); | |
break; /* r@ */ | |
case 0xc: // _t = (t==0xf008)?eth_poll():(t==0xf001)?1:(t==0xf000)?getch():memory[t>>1]; | |
Serial.print(" I/O "); | |
Serial.print(" "); | |
break; /* @ */ | |
case 0xd: _t = s<<t; | |
Serial.print(" << "); | |
Serial.print(" "); | |
break; /* lshift */ | |
case 0xe: _t = (rsp<<8) + dsp; | |
Serial.print(" dsp"); | |
Serial.print(" "); | |
break; /* dsp */ | |
case 0xf: _t = -(s<t); | |
Serial.print(" U<"); | |
Serial.print(" "); | |
break; /* u< */ | |
} | |
/* | |
Serial.print(" TOP "); | |
Serial.print(_t, HEX); | |
Serial.print(" 2ND "); | |
Serial.print(s, HEX); | |
*/ | |
dsp = 31 & (dsp + sx[insn & 3]); /* dstack+- */ | |
rsp = 31 & (rsp + sx[(insn >> 2) & 3]); /* rstack+- */ | |
if (insn & 0x80) /* t->s */ | |
d[dsp] = t; | |
if (insn & 0x40) /* t->r */ | |
r[rsp] = t; | |
if (insn & 0x20) /* s->[t] */ | |
m[t] = s; | |
// (t==0xf008)?eth_transmit(): (t==0xf002)?(rsp=0):(t==0xf000)?putch(s):(memory[t>>1]=s); /* ! */ | |
t = _t; | |
break; | |
} | |
} | |
Serial.print(" TOP "); | |
Serial.print(_t, HEX); | |
Serial.print(" 2ND "); | |
Serial.print(s, HEX); | |
pc = _pc; | |
insn = memory[pc]; | |
next_t = _t; | |
// Print_Regs(); | |
Serial.println(); | |
} | |
// End of CPU model | |
// ------------------------------------------------------------------------ | |
void dump_memory(void) | |
{ | |
for(int i=0; i<=1024; i=i+16) | |
{ | |
// m[i] = random(0,65535); | |
gfx.setTextColor(BLACK, (i%32)*1+0xFFF0); //Subtle yellow background on every other line | |
//----------------------------------------------------------------------- | |
// Print out the Row Address | |
if(i >=0 && i < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(i >=16 && i < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if(i >=256 && i < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(i,HEX); | |
gfx.print(" "); | |
//------------------------------------------------------------------------- | |
// Print out the data | |
for(int j=0; j<=15; j++) | |
{ | |
if(m[i+j] >=0 && m[i+j] < 16) //Pad all hex out to 4 digits | |
{ | |
gfx.print("000"); | |
} | |
else if(m[i+j] >=16 && m[i+j] < 256) | |
{ | |
gfx.print("00"); | |
} | |
else if(m[i+j] >=256 && m[i+j] < 4096) | |
{ | |
gfx.print("0"); | |
} | |
gfx.print(m[i+j],HEX); | |
gfx.print(" "); | |
} | |
// if(j=15) | |
gfx.println(); | |
} | |
} | |
//------------------------------------------------------------------- | |
// Highlight the pc in the disassembler window | |
void highlight_pc(int colour) | |
{ | |
gfx.setTextColor(BLACK,colour); | |
gfx.setTextSize(1); | |
gfx.setCursor(570, 256 + (8 *pc)); | |
gfx.print(" "); //Print a block of highlighted colour at pc location | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment