Skip to content

Instantly share code, notes, and snippets.

@troufster
Last active December 24, 2015 01:59
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 troufster/6727762 to your computer and use it in GitHub Desktop.
Save troufster/6727762 to your computer and use it in GitHub Desktop.
avr.js
//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