Last active
December 24, 2015 01:59
-
-
Save troufster/6727762 to your computer and use it in GitHub Desktop.
avr.js
This file contains hidden or 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
//port of https://github.com/kiansheik/ard/tree/master/trunk/src/emulator | |
var debug = 1; | |
var Address = { | |
RAMEND : 0x02ff, | |
SPL : 0x5d, //(0x3D + 0x20) | |
SPH : 0x5e //(0x3E + 0x20) | |
}; | |
var LBYTEMASK = 0x00ff; | |
var HBYTEMASK = 0xff00; | |
//var SREG = 0x5f; //(0x3F + 0x20) | |
var CBIT = 1 << 0; | |
var ZBIT = 1 << 1; | |
var NBIT = 1 << 2; | |
var VBIT = 1 << 3; | |
var SBIT = 1 << 4; | |
var HBIT = 1 << 5; | |
var TBIT = 1 << 6; | |
var IBIT = 1 << 7; | |
function MemData() { | |
this.mem = new Int8Array(0xffff); | |
} | |
MemData.prototype = { | |
read : function(addr) { | |
return this.mem[addr]; | |
}, | |
readShort : function(addrHi, addrLo) { | |
var mem = this.mem; | |
return mem[addrHi] << 8 | mem[addrLo]; | |
}, | |
write : function(addr, data) { | |
/* | |
if(addr = 0x25) { | |
console.log(addr.toString(16),data); | |
}*/ | |
this.mem[addr] = data; | |
}, | |
writeShort : function(addrLo, addrHi, data) { | |
var mem = this.mem; | |
mem[addrLo] = LBYTEMASK & data; | |
mem[addrHi] = (HBYTEMASK & data) >>> 8; | |
} | |
}; | |
function MemEEProm() { | |
this.mem = new Uint8Array(256); | |
} | |
MemEEProm.prototype = { | |
read : function(addr) { return this.mem[addr];}, | |
readShort : function () {}, | |
readAll : function() { return this.mem;}, | |
write : function(addr, data) {} | |
}; | |
function MemProg() { | |
this.mem = new Int16Array(0x800); | |
this.ptr = 0; | |
} | |
MemProg.prototype = { | |
getPtr : function() { return this.ptr; }, | |
setPtr : function(b) { this.ptr = b; }, | |
stepPtr: function() { this.ptr += 1; }, | |
readFromPtr : function() { return this.mem[this.ptr];}, | |
read : function(addr) { return this.mem[addr]; }, | |
readAll : function() { return this.mem;}, | |
writeToPtr : function (data) { this.write(this.ptr, data)}, | |
write : function(addr, data) { this.mem[addr] = data;} | |
}; | |
function CmdSet(){ | |
this.cmds = { | |
EICALL : 0x9519, | |
EIJMP : 0x9419, | |
ELPM : 0x95D8, | |
ESPM : 0x95F8, | |
ICALL : 0x9509, | |
IJMP : 0x9409, | |
LPM3 : 0x95C8, | |
RET : 0x9508, | |
RETI : 0x9518, | |
SLEEP : 0x9588, | |
SPM : 0x95E8, | |
WDR : 0x95A8, | |
BREAK : 0x9598, | |
ADC : 0x1c00, | |
ADD : 0x0c00, | |
AND : 0x2000, | |
CP : 0x1400, | |
CPC : 0x0400, | |
CPSE : 0x1000, | |
EOR : 0x2400, | |
MOV : 0x2C00, | |
MUL : 0x9C00, | |
OR : 0x2800, | |
SBC : 0x0800, | |
SUB : 0x1800, | |
RJMP : 0xc000, | |
OUT : 0xb800, | |
LDI : 0xe000, | |
CPI : 0x3000, | |
BRNE : 0xF400, | |
LPM : 0x9005, | |
ST : 0x920d, | |
RCALL : 0xd000, | |
SEI : 0x9478, | |
IN : 0xb000, | |
ORI : 0x6000, | |
ANDI : 0X7000, | |
SBI : 0x9A00, | |
LDS : 0x9180, | |
LDS2 : 0x9190, | |
LDS3 : 0x91a0, | |
LDS4 : 0x91b0, | |
NOP : 0x0000, | |
MOVW : 0x0100, | |
SUBI : 0x5000, | |
SBCI : 0x4000, | |
LPM2 : 0x9004, | |
BREQ : 0xf000, | |
CLI : 0x9400, | |
SBRS : 0xFE00, | |
DEC : 0x940A, | |
JMP : 0x940C, | |
CALL : 0x940E, | |
PUSH : 0x920f, | |
LDZ : 0x8000, | |
STZ : 0x8200, | |
STS : 0x9200, | |
POP : 0x900f, | |
SBIS : 0x9B00 | |
}; | |
this.cmdMap = {}; | |
var cmdKeys = Object.keys(this.cmds); | |
for(var c in cmdKeys) { | |
this.cmdMap[this.cmds[cmdKeys[c]]] = cmdKeys[c]; | |
} | |
} | |
CmdSet.prototype.run = function(state, instr, mask, m) { | |
if (debug) console.log("->", instr.toString(16), this.cmdMap[mask], mask, mask.toString(16), m.toString(16)); | |
//http://www.atmel.com/images/doc0856.pdf | |
var memData = state.memData; | |
var memProg = state.getProgMem(); | |
switch(this.cmdMap[mask]) { | |
case 'SBIS': | |
var ra=((instr>>3)&0x1F); | |
var rb=(instr&0x0007); | |
var pc_cond=memProg.getPtr()+1; | |
var inst2=memProg.read(memProg.getPtr()+1); | |
if(state.is32bit(inst2)) pc_cond+=1; | |
var rc=memData.read(0x20+ra); | |
if(rc&(1<<rb)) | |
{ | |
memProg.setPtr(pc_cond); | |
} | |
break; | |
case 'POP': | |
var rd=(instr>>4)&0x1F; | |
if(debug) console.log('POP r' + rd); | |
var rc = memData.read(++state.SP); | |
memData.write(rd, rc); | |
break; | |
case 'STS': | |
var inst2= memProg.read(memProg.getPtr()+1); | |
var pc_next=memProg.getPtr()+2; | |
var rk = inst2; | |
rd=((instr>>4)&0x1F); | |
rk=inst2; | |
if(debug) console.log('STS 0x' +rk.toString(16)+ ", r" + rd); | |
var rc = memData.read(rd); | |
memData.write(rk,rc); | |
memProg.setPtr(pc_next-1); | |
break; | |
case 'STZ': | |
var rr=(instr>>4)&0x1F; | |
if(debug) console.log('ST Z, r' + rr); | |
var ra=memData.read(30); | |
var rb=memData.read(31); | |
var rk=(rb<<8)|ra; | |
var rc=memData.read(rr); | |
memData.write(rk,rc); | |
break; | |
case 'LDZ': | |
var rd=(instr>>4)&0x1F; | |
if(debug) console.log('LD r' + rd + ", Z"); | |
var ra=memData.read(30); | |
var rb=memData.read(31); | |
var rk=(rb<<8)|ra; | |
var rc=memData.read(rk); | |
memData.write(rd,rc); | |
break; | |
case 'PUSH': | |
var rd=(instr>>4)&0x1F; | |
if(debug) console.log('PUSH r' + rd); | |
var rc = memData.read(rd); | |
if(debug) console.log("SP!!", state.SP); | |
memData.write(state.SP--, rc); | |
if(debug) console.log("SP!!2", state.SP); | |
break; | |
case 'CALL': | |
var rk = memProg.read(memProg.getPtr()+1); | |
var pc_next = memProg.getPtr()+1; | |
if(debug) console.log('CALL 0x' + rk.toString(16)); | |
if(debug) console.log("SP!!", state.SP); | |
memData.write(state.SP--, (pc_next >> 8)&0xFF); | |
memData.write(state.SP--, (pc_next >> 0)&0xFF); | |
if(debug) console.log("SP!!", state.SP, pc_next); | |
memProg.setPtr(rk-1); | |
break; | |
case 'JMP': | |
var rk = memProg.read(memProg.getPtr()+1); | |
if(debug) console.log('JMP 0x' + rk.toString(16)); | |
//-1 since Processor always increments 1 :P | |
memProg.setPtr(rk-1); | |
break; | |
case 'RJMP': //RJMP 1100 kkkk kkkk kkkk | |
var rk = instr & 0x0fff; | |
if(rk&0x800) { | |
rk = rk | ~0xfff | |
} | |
var ptr = state.getProgMem().getPtr(); | |
state.getProgMem().setPtr(ptr+rk); | |
break; | |
case 'EOR': //EOR pattern 0010 01rd dddd rrrr | |
case 'CLR': //CLR pattern 0010 01dd dddd dddd | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if(debug) console.log('EOR', 'r'+rd + ", r" +rr); | |
if(rd==rr) | |
{ | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rc=(ra^rb)&0xFF; | |
memData.write(rd, rc); | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
state.set_zbit(); | |
} else { | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rc=(ra^rb)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
//clr_vbit(); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
} | |
break; | |
case 'OUT': //OUT pattern 1011 1aar rrrr aaaa | |
var rk = ((instr & 0x0600)>>5) | (instr & 0x000F); | |
var rd = (instr>>4)&0x1F; | |
if (debug) console.log('OUT', '0x'+ rk.toString(16) + "(" + rk +")" + ", r" + rd); | |
var ra = memData.read(rd); | |
//I/O(A) ← Rr | |
memData.write(rk+0x20,ra); | |
break; | |
case 'LDI': //LDI pattern 1110 kkkk dddd kkkk | |
var rk = rk=((instr&0x0F00)>>4)|(instr&0x000F); | |
var rd = 16+((instr>>4)&0xF); | |
if (debug) console.log('LDI', 'r'+rd + ", " +rk.toString(16) + "(" + rk +")"); | |
memData.write(rd, rk); | |
break; | |
case 'CPI': //CPI pattern 0011 kkkk dddd kkkk | |
var rk = ((instr&0x0F00)>>4)|(instr&0x000F); | |
var rd=16+((instr>>4)&0xF); | |
var ra = memData.read(rd); | |
if (debug) console.log("CPI r" + rd + ", " + rk, "?", ra); | |
var rc = (ra-rk) & 0xff; | |
//console.log("CPI:",state.sreg.toString(2)); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
//console.log("CPI:",state.sreg.toString(2)); | |
state.do_hflag_sub(ra,~rk,1); | |
state.do_cflag_sub(ra,~rk,1); | |
state.do_vflag(ra,~rk,1); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) { | |
if (debug) console.log("zbit should be set after this"); | |
state.set_zbit(); | |
} | |
if (debug) console.log('CPI rcz', rc, state.sreg.toString(2)); | |
state.do_sflag(); | |
if (debug) console.log('CPI rcz2 ', rc, state.sreg.toString(2)); | |
break; | |
case 'CPC': //CPC pattern 0000 01rd dddd rrrr | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
var ra = memData.read(rd); | |
var rb = memData.read(rr); | |
var rk, rx; | |
if(state.sreg&CBIT) rk=1; else rk=0; | |
if(state.sreg&ZBIT) rx=1; else rx=0; | |
if (debug) console.log("CPC zbit was", !!(state.sreg&ZBIT)); | |
if (debug) console.log("CPC r"+rd +", r" + rr, ra + "|" + rb); | |
var rc=(ra-rb-rk)&0xFF; | |
if (debug) console.log("CPC ra-rb-rk", ra,rb,rk, rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag_sub(ra,~rb,~rk); | |
state.do_cflag_sub(ra,~rb,~rk); | |
state.do_vflag(ra,~rb,rk); | |
if(rc&0x80) state.set_nbit(); | |
if((rc==0x00)&&(rx)) { | |
if (debug) console.log("zbit should be set after this"); | |
state.set_zbit(); | |
if (debug) console.log('CPC zbit ', state.sreg.toString(2)); | |
} | |
state.do_sflag(); | |
break; | |
case 'BRNE': //BRNE pattern 1111 01kk kkkk k001 | |
if (debug) console.log("BRNE sreg",state.sreg.toString(2)); | |
var rk=((instr>>3)&0x7F); | |
if(rk&0x40) rk|=~0x7F; | |
var pc_cond=(state.getProgMem().getPtr()+rk); | |
var rb=(instr&0x7); | |
// console.log("BRNE",rb, rk, state.sreg.toString(2)); | |
if(state.sreg&(1<<rb)) { | |
if (debug) console.log("BRNE not tripped") | |
} else { | |
state.getProgMem().setPtr(pc_cond); | |
} | |
break; | |
case 'LPM': //LPM pattern 1001 000d dddd 0100 | |
//LPM pattern 1001 0101 1100 1000 | |
//LPM pattern 1001 000d dddd 0101 | |
var rd=(instr>>4)&0x1F; | |
//Z reg? | |
var ra=memData.read(30); | |
var rb=memData.read(31); | |
var rk=(rb<<8)|ra; | |
var rc=memData.read(rk); | |
memData.write(rd,rc); | |
var rk=rk+1; | |
memData.write(30,(rk>>0)&0xFF); | |
memData.write(31,(rk>>8)&0xFF); | |
break; | |
case 'ST': | |
//STx pattern 1001 001r rrrr 1100 | |
//STx pattern 1001 001r rrrr 1101 | |
//STx pattern 1001 001r rrrr 1110 | |
var rr=(instr>>4)&0x1F; | |
var ra=memData.read(26); | |
var rb=memData.read(27); | |
var rk=(rb<<8)|ra; | |
//console.log(rk); | |
var rc=memData.read(rr); | |
//console.log('RC', rc, rk); | |
memData.write(rk,rc); | |
var rk=rk+1; | |
memData.write(26,(rk>>0)&0xFF); | |
memData.write(27,(rk>>8)&0xFF); | |
break; | |
case 'RCALL': //RCALL pattern 1101 kkkk kkkk kkkk | |
var rk=instr&0x0FFF; | |
if(rk&0x800) rk|=~0x0FFF; | |
var pc_cond=(state.getProgMem().getPtr()+rk); | |
if (debug) console.log("RCALL", rk, rk.toString(16), pc_cond, rk.toString(2)); | |
if (debug) console.log("RCALL SP", state.SP.toString(16)); | |
var nxt = state.getProgMem().getPtr(); | |
memData.write(state.SP--, (nxt >> 8) & 0xff ); | |
memData.write(state.SP--, (nxt >> 0) & 0xff ); | |
if (debug) console.log("Stack should be pushed and ready to jump"); | |
state.getProgMem().setPtr(pc_cond); | |
break; | |
case 'SEI': | |
var rb=((instr>>4)&0x7); | |
//Set corresponding bit in SREG | |
state.sreg |= (1<<rb); | |
if (debug) console.log("SEI set bit", state.sreg.toString(2)); | |
break; | |
case 'IN': | |
var rk=((instr&0x0600)>>5)|(instr&0x000F); | |
var rd=(instr>>4)&0x1F; | |
if (debug) console.log("IN r" + rd + ", 0x" + rk.toString(16)); | |
var rb = memData.read(0x20+rk); | |
memData.write(rd, rb); | |
break; | |
case 'ORI': | |
var rd=16+((instr>>4)&0xF); | |
var rk=((instr&0x0F00)>>4)|(instr&0x000F); | |
if (debug) console.log("ORI r" + rd + ", 0x" + rk.toString(16)); | |
var ra = memData.read(rd); | |
var rc = (ra|rk)&0xff; | |
memData.write(rd,rc); | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
if(rc&0x80) | |
{ | |
state.set_nbit(); | |
state.set_sbit(); | |
} | |
if(rc==0x00) state.set_zbit(); | |
break; | |
case 'ANDI': | |
//ANDI pattern 0111 kkkk dddd kkkk | |
//CBR pattern 0111 kkkk dddd kkkk | |
var rd=16+((instr>>4)&0xF); | |
var rk=((instr&0x0F00)>>4)|(instr&0x000F); | |
if (debug) console.log("ANDI r" + rd + ", 0x" + rk.toString(16)); | |
var ra=memData.read(rd); | |
var rc=(ra&rk)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
//clr_vbit(); | |
if(rc&0x80) | |
{ | |
state.set_nbit(); | |
state.set_sbit(); | |
} | |
if(rc==0x00) state.set_zbit(); | |
break; | |
case 'SBI': | |
//SBI pattern 1001 1010 aaaa abbb | |
var rb=instr&7; | |
var ra=(instr>>3)&0x001F; | |
if (debug) console.log("SBI " + ra + ", 0x" + rb.toString(16)); | |
var rc=memData.read(0x20+ra); | |
rc|=(1<<rb); | |
memData.write(0x20+ra,rc); | |
break; | |
case 'RET': | |
//RET pattern 1001 0101 0000 1000 | |
if(debug) console.log("SP!", state.SP); | |
var ra = memData.read(++state.SP); | |
var rb = memData.read(++state.SP); | |
var sp = (rb << 8) | (ra << 0); | |
if (debug) console.log("RET -> sp 0x" +sp.toString(16)); | |
state.getProgMem().setPtr(sp); | |
break; | |
case 'LDS4': | |
case 'LDS3': | |
case 'LDS2': | |
case 'LDS': | |
var pc = memProg.getPtr(); | |
var rk = memProg.read(pc+1); | |
rd=((instr>>4)&0x1F); | |
if (debug) console.log("LDS r" + rd + ", 0x" + rk.toString(16)); | |
var rc=memData.read(rk); | |
memData.write(rd, rc); | |
memProg.stepPtr(); | |
break; | |
case 'MOV': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if (debug) console.log("MOV r" + rd + ", r" + rr); | |
var rc = memData.read(rr); | |
memData.write(rd,rc); | |
break; | |
case 'MOVW': | |
var rd=((instr>>3)&0x1E); | |
var rr=((instr<<1)&0x1E); | |
if (debug) console.log("MOVW r" + rd + ", r" + rr); | |
var ra = memData.read(rr+0); | |
var rb = memData.read(rr+1); | |
memData.write(rd+0, ra); | |
memData.write(rd+1, rb); | |
break; | |
case 'SUBI': | |
var rd=16+((instr>>4)&0xF); | |
var rk=((instr&0x0F00)>>4)|(instr&0x000F); | |
if (debug) console.log("SUBI r" + rd + ", " + rk); | |
var ra =memData.read(rd); | |
var rc=(ra-rk)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag_sub(ra,~rk,1); | |
state.do_cflag_sub(ra,~rk,1); | |
state.do_vflag(ra,~rk,1); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
break; | |
case 'SBCI': | |
var rd=16+((instr>>4)&0xF); | |
var rb=((instr&0x0F00)>>4)|(instr&0x000F); | |
if (debug) console.log("SBCI r" + rd + ", " + rb); | |
var ra=memData.read(rd); | |
var rk, rx; | |
if(state.sreg&CBIT) rk=1; else rk=0; | |
if(state.sreg&ZBIT) rx=1; else rx=0; | |
var rc=(ra-rb-rk)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag_sub(ra,~rb,~rk); | |
state.do_cflag_sub(ra,~rb,~rk); | |
state.do_vflag(ra,~rb,rk); | |
if(rc&0x80) state.set_nbit(); | |
if((rc==0x00)&&(rx)) state.set_zbit(); | |
state.do_sflag(); | |
break; | |
case 'LPM3': | |
var rd=(instr>>4)&0x1F | |
if (debug) console.log("LPM r" + rd); | |
//Z | |
var ra = memData.read(30); | |
var rb = memData.read(31); | |
var rk = (rb<<8)|ra; | |
var rc = memData.read(rk); | |
memData.write(0,rc); | |
break; | |
case 'LPM2': | |
var rd=(instr>>4)&0x1F | |
if (debug) console.log("LPM r" + rd); | |
//Z | |
var ra = memData.read(30); | |
var rb = memData.read(31); | |
var rk = (rb<<8)|ra; | |
var rc = memData.read(rk); | |
memData.write(rd,rc); | |
break; | |
case 'AND': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if(rd==rr) | |
{ | |
if (debug) console.log("AND(tst) r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rc=(ra&ra)&0xFF; | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
if(rc&0x80) | |
{ | |
state.set_nbit(); | |
state.set_sbit(); | |
} | |
if(rc==0x00) state.set_zbit(); | |
} else { | |
if (debug) console.log("AND r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
varrc=(ra&rb)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
if(rc&0x80) | |
{ | |
state.set_nbit(); | |
state.set_sbit(); | |
} | |
if(rc==0x00) state.set_zbit(); | |
} | |
break; | |
case 'BREQ': | |
var rk=((instr>>3)&0x7F); | |
if(rk&0x40) rk|=~0x7F; | |
var pc_cond=(memProg.getPtr()+rk); | |
var rb=(instr&0x7); | |
if (debug) console.log("BREQ "+ rk); | |
if(state.sreg&(1<<rb)) | |
{ | |
memProg.setPtr(pc_cond); | |
} | |
break; | |
case 'CLI': | |
var rb=((instr>>4)&0x7); | |
if (debug) console.log("CLI"); | |
state.sreg&=~(1<<rb); | |
break; | |
case 'SBRS': | |
var rr=((instr>>4)&0x1F); | |
var rb=(instr&0x0007); | |
var pcc = memProg.getPtr()+1; | |
var instr2 = memData.read(pcc); | |
if(state.is32bit(instr2)) pcc+=1; | |
if (debug) console.log("SBRS r" + rr + ", " + rb); | |
rc = memData.read(rr); | |
if(rc&(1<<rb)) | |
{ | |
if (debug) console.log("SBRS Skip!"); | |
memProg.setPtr(pcc); | |
} | |
break; | |
case 'ADD': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if(rd==rr){ | |
if (debug) console.log("LSL r" + rd); | |
var ra=memData.read(rd); | |
var rc=(ra<<1)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
if(ra&0x08) state.set_hbit(); | |
if(ra&0x80) state.set_cbit(); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
switch(ra&0xC0) | |
{ | |
case 0x00: break; | |
case 0x40: state.set_vbit(); break; | |
case 0x80: state.set_vbit(); break; | |
case 0xC0: break; | |
} | |
state.do_sflag(); | |
} | |
else { | |
if (debug) console.log("ADD r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rc=(ra+rb)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag(ra,rb,0); | |
state.do_cflag(ra,rb,0); | |
state.do_vflag(ra,rb,0); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
} | |
break; | |
case 'ADC': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if(rd==rr) | |
{ | |
if (debug) console.log("ROL r" + rd); | |
var ra=memData.read(rd); | |
var rc=(ra<<1)&0xFF; | |
if(state.sreg&CBIT) rc|=0x01; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
if(ra&0x08) state.set_hbit(); | |
if(ra&0x80) state.set_cbit(); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
switch(ra&0xC0) | |
{ | |
case 0x00: break; | |
case 0x40: state.set_vbit(); break; | |
case 0x80: state.set_vbit(); break; | |
case 0xC0: break; | |
} | |
state.do_sflag(); | |
} else { | |
if (debug) console.log("ADC r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rk; | |
if(state.sreg&CBIT) rk=1; else rk=0; | |
var rc=(ra+rb+rk)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag(ra,rb,rk); | |
state.do_cflag(ra,rb,rk); | |
state.do_vflag(ra,rb,rk); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
} | |
break; | |
case 'DEC': | |
var rd=((instr>>4)&0x1F); | |
if (debug) console.log("DEC r" + rd); | |
var ra=memData.read(rd); | |
var rc=(ra-1)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(SBIT|VBIT|NBIT|ZBIT); | |
if(ra==0x80) state.set_vbit(); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
break; | |
case 'CP': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if (debug) console.log("CP r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rc=(ra-rb)&0xFF; | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag_sub(ra,~rb,1); | |
state.do_cflag_sub(ra,~rb,1); | |
state.do_vflag(ra,~rb,1); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
break; | |
case 'SBC': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if (debug) console.log("SBC r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rk, rx; | |
if(state.sreg&CBIT) rk=1; else rk=0; | |
if(state.sreg&ZBIT) rx=1; else rx=0; | |
var rc=(ra-rb-rk)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag_sub(ra,~rb,~rk); | |
state.do_cflag_sub(ra,~rb,~rk); | |
state.do_vflag(ra,~rb,rk); | |
if(rc&0x80) state.set_nbit(); | |
if((rc==0x00)&&(rx)) state.set_zbit(); | |
state.do_sflag(); | |
break; | |
case 'SUB': | |
var rd=((instr>>4)&0x1F); | |
var rr=((instr&0x0200)>>5)|(instr&0x000F); | |
if (debug) console.log("SUB r" + rd + ", r" + rr); | |
var ra=memData.read(rd); | |
var rb=memData.read(rr); | |
var rc=(ra-rb)&0xFF; | |
memData.write(rd,rc); | |
state.sreg&=~(HBIT|SBIT|VBIT|NBIT|ZBIT|CBIT); | |
state.do_hflag_sub(ra,~rb,1); | |
state.do_cflag_sub(ra,~rb,1); | |
state.do_vflag(ra,~rb,1); | |
if(rc&0x80) state.set_nbit(); | |
if(rc==0x00) state.set_zbit(); | |
state.do_sflag(); | |
break; | |
} | |
}; | |
CmdSet.prototype.hasCmd = function(instr) { | |
return (instr in this.cmdMap); | |
} | |
function Processor() { | |
/** | |
* Data memory | |
* 0x0000 - 0x001f -> registers | |
* 0x0020 - 0x005f -> 64 I/O registers | |
* 0x0060 - 0x00ff -> 160 external I/O registers | |
* 0x0100 - 0x02ff -> 512 bytes of internal SRAM | |
*/ | |
this.memProg = null; | |
this.memData = null; | |
this.memEEProm = null; | |
this.SP = 0xffff; | |
this.PC = 0; | |
this.CYCLES = 0; | |
this.sreg = 0; | |
this.reset(); | |
} | |
Processor.prototype = { | |
reset : function() { | |
// | |
this.memProg = new MemProg(); | |
this.memData = new MemData(); | |
this.memEEProm = new MemEEProm(); | |
this.cmdSet = new CmdSet(); | |
//reset stack pointer | |
this.writeSP(Address.RAMEND); | |
this.CYCLES = 0; | |
this.PC = 0; | |
this.SP = 0xffff; | |
this.resetSReg(); | |
}, | |
writeSP : function(sp) { | |
this.memData.writeShort(Address.SPL, Address.SPH, 0x07ff & sp); | |
}, | |
resetSReg : function() { | |
this.sreg = 0x0; | |
}, | |
set_tbit : function() { this.sreg|=TBIT; }, | |
clr_tbit : function() { this.sreg&=~TBIT; }, | |
set_sbit : function() { this.sreg|=SBIT; }, | |
clr_sbit : function() { this.sreg&=~SBIT; }, | |
set_vbit : function() { this.sreg|=VBIT; }, | |
set_nbit : function() { this.sreg|=NBIT; }, | |
set_zbit : function() { this.sreg|=ZBIT; }, | |
set_cbit : function() { this.sreg|=CBIT; }, | |
set_hbit : function() { this.sreg|=HBIT; }, | |
set_ibit : function() { this.sreg|=IBIT; }, | |
do_sflag : function() { | |
switch(this.sreg&(NBIT|VBIT)) | |
{ | |
case NBIT: | |
case VBIT: | |
this.set_sbit(); | |
break; | |
default: | |
this.clr_sbit(); | |
break; | |
} | |
}, | |
do_cflag : function(a, b, c ) | |
{ | |
a &=0xFF; | |
b &=0xFF; | |
c &=0x01; | |
this.sreg &=~CBIT; | |
//rc=(a&0x7F)+(b&0x7F)+c; //carry in | |
//rc = (rc>>7)+(a>>7)+(b>>7); //carry out | |
//if(rc&2) sreg|=CBIT; | |
var rc=a+b+c; | |
if(rc & 0x100) this.sreg|=CBIT; | |
}, | |
do_hflag : function( a,b,c) | |
{ | |
a&=0xF; | |
b&=0xF; | |
c&=0x1; | |
this.sreg&=~HBIT; | |
//rc=(a&0x7)+(b&0x7)+c; //carry in | |
//rc = (rc>>3)+(a>>3)+(b>>3); //carry out | |
//if(rc&2) sreg|=HBIT; | |
var rc=a+b+c; | |
if(rc&0x10) this.sreg|=HBIT; | |
}, | |
do_cflag_sub : function(a,b,c) | |
{ | |
a&=0xFF; | |
b&=0xFF; | |
c&=0x01; | |
this.sreg|=CBIT; | |
//rc=(a&0x7F)+(b&0x7F)+c; //carry in | |
//rc = (rc>>7)+(a>>7)+(b>>7); //carry out | |
//if(rc&2) sreg|=CBIT; | |
var rc=a+b+c; | |
if(rc&0x100) this.sreg&=~CBIT; | |
}, | |
do_hflag_sub : function(a,b,c) | |
{ | |
a&=0xF; | |
b&=0xF; | |
c&=0x1; | |
this.sreg|=HBIT; | |
//rc=(a&0x7)+(b&0x7)+c; //carry in | |
//rc = (rc>>3)+(a>>3)+(b>>3); //carry out | |
//if(rc&2) sreg|=HBIT; | |
var rc=a+b+c; | |
if(rc&0x10) this.sreg&=~HBIT; | |
}, | |
do_vflag : function(a,b,c) | |
{ | |
var rc,rd; | |
a&=0xFF; | |
b&=0xFF; | |
c&=0x01; | |
this.sreg&=~VBIT; | |
rc=(a&0x7F)+(b&0x7F)+c; //carry in | |
rc>>=7; //carry in in lsbit | |
rd=(rc&1)+((a>>7)&1)+((b>>7)&1); //carry out | |
rd>>=1; //carry out in lsbit | |
rc=(rc^rd)&1; //if carry in != carry out then signed overflow | |
if(rc) this.sreg|=VBIT; | |
}, | |
is32bit : function(instr) | |
{ | |
if((instr&0xFE0E)==0x940E) return 1; //CALL | |
if((instr&0xFE0E)==0x940C) return 1; //JMP | |
if((instr&0xFE0F)==0x9000) return 1; //LDS | |
if((instr&0xFE0F)==0x9200) return 1; //STS | |
return 0; | |
}, | |
invokeNextInstr : function() { | |
this.invokeInstr(this.memProg.readFromPtr()); | |
this.memProg.stepPtr(); | |
}, | |
invokeInstr : function(instr) { | |
var masks = [ | |
0xfe0f, //1111 111d dddd 1111, | |
0xff00 , //1111 1111 dddd dddd | |
0xffff, //1111 1111 1111 1111 | |
0xfc00, //1111 11dd dddd dddd | |
0xf800, //1111 1ddd dddd dddd, | |
0xf000 //1110 dddd dddd dddd, | |
]; | |
for(var i = 0; i < masks.length; i++) { | |
var maskInt = masks[i] & instr; | |
if (debug) console.log(masks[i].toString(16), maskInt.toString(16)); | |
if(this.cmdSet.hasCmd(maskInt)) { | |
this.cmdSet.run(this, instr, maskInt, masks[i]); | |
return; | |
} | |
} | |
throw new Error("Unsupported instruction" + instr + " " + instr.toString(16)+ " " + instr.toString(2)); | |
}, | |
readSP : function() { | |
return 0x07ff & this.memData.readShort(Address.SPL, Address.SPH); | |
}, | |
getProgMem : function() { | |
return this.memProg; | |
} | |
}; | |
//Go forth | |
fs.readFile('blink.hex', function(err, file) { | |
var hex = ihex.parse(file); | |
var p = new Processor(); | |
p.getProgMem().setPtr(0); | |
for(var i = 0; i < hex.data.length; i+=2) { | |
p.getProgMem().writeToPtr(hex.data.readUInt16LE(i)); | |
p.getProgMem().stepPtr(); | |
} | |
p.getProgMem().setPtr(0); | |
function logReg(r,m) { | |
console.log("::::R" +r +": 0x" + m.read(r).toString(16)); | |
} | |
function logRegs(r,r2,m) { | |
console.log("::::R" +r +": 0x" + m.read(r).toString(16),"::::R" +r2 +": 0x" + m.read(r2).toString(16)); | |
} | |
function logMem(a,m) { | |
console.log("::::MEM 0x" + a.toString(16)+": 0x" + m.read(a).toString(16)); | |
} | |
//console.log(p.getProgMem().readFromPtr().toString(16)); | |
//ermah | |
for(var i = 0; i < 28; i++) { | |
p.invokeNextInstr(); | |
var m = p.memData; | |
logMem(0x25,m); | |
logReg(17,m); | |
var state = { | |
r0 : m.read(0).toString(2), | |
r1 : m.read(1).toString(2), | |
r2 : m.read(2).toString(2), | |
r3 : m.read(3).toString(2), | |
r4 : m.read(4).toString(2), | |
r5 : m.read(5).toString(2), | |
r6 : m.read(6).toString(2), | |
r7 : m.read(7).toString(2), | |
r8 : m.read(8).toString(2), | |
r9 : m.read(9).toString(2), | |
r10 : m.read(10).toString(2), | |
r11 : m.read(11).toString(2), | |
r13 : m.read(13).toString(2), | |
r14 : m.read(14).toString(2), | |
r15 : m.read(15).toString(2), | |
r16 : m.read(16).toString(2), | |
r17 : m.read(17).toString(2), | |
r18 : m.read(18).toString(2), | |
r19 : m.read(19).toString(2), | |
r20 : m.read(20).toString(2), | |
r21 : m.read(21).toString(2), | |
r22 : m.read(22).toString(2), | |
r23 : m.read(23).toString(2), | |
r24 : m.read(24).toString(2), | |
r25 : m.read(25).toString(2), | |
r26 : m.read(26).toString(2), | |
r27 : m.read(27).toString(2), | |
r28 : m.read(28).toString(2), | |
r29 : m.read(29).toString(2), | |
r30 : m.read(30).toString(2), | |
r31 : m.read(31).toString(2), | |
r32 : m.read(32).toString(2), | |
PORTB : m.read(0x25) | |
}; | |
//console.log(state); | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment