User Tools

Site Tools


user:mcooper6:m6800

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
user:mcooper6:m6800 [2011/12/11 01:03] – [Step 2] mcooper6user:mcooper6:m6800 [2012/12/05 00:23] (current) – [Logical Operations] mcooper6
Line 1: Line 1:
 +<WRAP left 40%>
 +~~TOC~~
 +</WRAP>
 +//
 +//
 +<WRAP centeralign 90% bigger>
 +<WRAP bigger fgred>Lab46 Explorations</WRAP>
 +<WRAP muchbigger>m6800 Simulator</WRAP>
 +JSON based replication of the Motorola 6800
 +</WRAP>
 +<WRAP left 50%>
 +<WRAP info left 80% bgwhite>
 +What follows is a humble attempt at clarity via vast modularization.  The product of this exploration (that is the simulator) is found @ [[http://lab46.corning-cc.edu/~mcooper6/m6800/| http://lab46.corning-cc.edu/~mcooper6/m6800/]].
 +Please Note:
 +  * There is a lot of code.  Much of the code is posted here, but in all cases, the working simulator should be consulted for accuracy.
 +  * This is not an attempt to duplicate the circuitry of the m6800, but rather to imitate the interactions that must occur between bits and bytes of any given microprocessor of similar magnitude.
 +  * Very little consideration has been made for cross-browser support or non-JavaScript accessibility ... seriously, almost none.  The code below works in FF, likely in Opera too, but no effort has been made to even test in IE.
 +</WRAP>
 +</WRAP>
 +<WRAP clear></WRAP>
 +//
 +//
 +=====m6800 as JSON Object=====
 +It is a short jaunt to visualize the m6800 as a JSON object.  Like the accumulators and buses of the m6800, each member of a JSON object has a position and a value:
 +<code>
 +m6800 = {
 + accume_a : {
 + 0 : 1,
 + 1 : 0,
 + 2 : 0,
 + 3 : 0,
 + 4 : 0,
 + 5 : 0,
 + 6 : 0,
 + 7 : 0
 + },
 + accume_b : {
 + 0 : 1,
 + 1 : 1,
 + 2 : 1,
 + 3 : 1,
 + 4 : 1,
 + 5 : 1,
 + 6 : 1,
 + 7 : 1
 + },
 + data_bus : {
 + 0 : 0,
 + 1 : 0,
 + 2 : 0,
 + 3 : 0,
 + 4 : 0,
 + 5 : 0,
 + 6 : 1,
 + 7 : 1
 + },
 + address_bus : {
 + 0 : 0,
 + 1 : 0,
 + 2 : 0,
 + 3 : 0,
 + 4 : 0,
 + 5 : 0,
 + 6 : 0,
 + 7 : 0,
 + 8 : 0,
 + 9 : 0,
 + 10 : 0,
 + 11 : 0,
 + 12 : 0,
 + 13 : 0,
 + 14 : 0,
 + 15 : 0
 + },
 + index_register : {
 + 0 : 0,
 + 1 : 0,
 + 2 : 0,
 + 3 : 0,
 + 4 : 0,
 + 5 : 0,
 + 6 : 0,
 + 7 : 0,
 + 8 : 0,
 + 9 : 0
 + 10 : 0,
 + 11 : 0,
 + 12 : 0,
 + 13 : 0,
 + 14 : 0,
 + 15 : 0
 + },
 + stack_pointer : {
 + 0 : 0,
 + 1 : 0,
 + 2 : 0,
 + 3 : 0,
 + 4 : 0,
 + 5 : 0,
 + 6 : 0,
 + 7 : 0,
 + 8 : 0,
 + 9 : 0,
 + 10 : 0,
 + 11 : 0,
 + 12 : 0,
 + 13 : 0,
 + 14 : 0,
 + 15 : 0
 + },
 + program_counter : {
 + 0 : 0,
 + 1 : 0,
 + 2 : 0,
 + 3 : 0,
 + 4 : 0,
 + 5 : 0,
 + 6 : 0,
 + 7 : 0,
 + 8 : 0,
 + 9 : 0,
 + 10 : 0,
 + 11 : 0,
 + 12 : 0,
 + 13 : 0,
 + 14 : 0,
 + 15 : 0
 + },
 + flags : {
 + 'H' : 0,
 + 'I' : 0,
 + 'N' : 0,
 + 'Z' : 0,
 + 'V' : 0,
 + 'C' : 0
 + },
 + bus_control : {
 + 'IRQ' : 0,
 + 'R_W' : 0,
 + 'VMA' : 0
 + },
 + processor_control : {
 + 'DBE' : 0,
 + 'TSC' : 0,
 + 'Halt' : 0,
 + 'NMI' : 0,
 + 'BA' : 0,
 + 'Reset' : 0
 + },
 + memory : {}
 +};
 +</code>
  
 +Using this notation, bits and bytes may be set via loops and simple statements like ''m6800.accume_a[2] = 1'' ... or ''m6800.flags['C'] = 1'' ... etc.
 +<code>
 + for(v in bits){
 + target[v] = bits[v] + some other stuff;
 + }
 +</code>
 +====Logical Operations====
 +===and===
 +This function ''AND's'' two 8 bit bytes, and writes to the byte represented by ''a'' if ''w == 1'', otherwise a new 8 bit byte is created and returned.  Based upon the m6800 manual, all operations using ''AND'' interact with the ''Z'', ''N'', and ''V'' flags of the condition code register.
 +<code>
 +/*
 + * and a & b ... spit them out as d, or write to a if w (write)
 + */
 +m6800.and = function(a, b, w){
 + var z = 1;
 + var d = {};
 + for(var v in a){
 + d[v] = a[v] && b[v];
 + if(d[v]){
 + z = 0;
 + }
 + }
 + if(z){ //zero bit
 + m6800.flags['Z'] = 1;
 + }else{
 + m6800.flags['Z'] = 0;
 + }
 + if(d[m6800.count(a) - 1]){ // test last bit for 1
 + m6800.flags['N'] = 1;
 + }else{
 + m6800.flags['N'] = 0;
 + }
 + m6800.flags['V'] = 0;
 + if(w){
 + m6800.setByte(d, a);
 + d = {};
 + }else{
 + return d;
 + }
 +};
 +</code>
 +For example, taken from ''ANDA'' ...
 +<code>
 + var m = memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))]; // memory location pointed to by the address bus
 + m6800.and(m6800.accume_a, m, true); // writes to accume_a
 + m6800.ui.setByte(m6800.accume_a, "ul#accume_a_list"); // more on ui later
 + m6800.ui.setFlag(m6800.flags, 'N');
 + m6800.ui.setFlag(m6800.flags, 'Z');
 +</code>
 +
 +Functions like ''m6800.setByte()'' and ''m6800.ui.setFlag()'' are simply helper functions written purely for the purpose of reducing the amount of extra code.  See source.
 +
 +<WRAP round info>
 +Curious about   ul#accume_a_list   ? 
 +
 +It's is a JavaScript hook to an HTML element <ul id='accume_a_list'></ul>
 +</WRAP>
 +
 +
 +===or===
 +<code>
 +/*
 + * or a || b ... spit them out as d, or write to a if w (write)
 + */
 +m6800.or = function(a, b, w){
 + var z = 1;
 + var d = {};
 + for(var v in a){
 + d[v] = a[v] || b[v];
 + if(d[v]){
 + z = 0;
 + }
 + }
 + if(w){
 + if(z){ //zero bit
 + m6800.flags['Z'] = 1;
 + }else{
 + m6800.flags['Z'] = 0;
 + }
 + if(d[m6800.count(a) - 1]){ // test last bit for 1
 + m6800.flags['N'] = 1;
 + }else{
 + m6800.flags['Z'] = 0;
 + }
 + m6800.flags['V'] = 0;
 + m6800.setByte(d, a);
 + d = {};
 + }else{
 + return d;
 + }
 +};
 +</code>
 +===xor===
 +<code>
 +/*
 + * xor a xor b ... spit them out as d, or write to a if w (write)
 + */
 +m6800.xor = function(a, b, w){
 + var z = 1;
 + var d = {};
 + for(var v in a){
 +// d[v] = parseInt((!a[v] && b[v]) || (a[v] && !b[v]));
 + if(a[v] == b[v]){
 + d[v] = 0;
 + }else{
 + d[v] = 1;
 + }
 +
 + if(d[v]){
 + z = 0;
 + }
 + }
 + if(w){
 + if(z){ //zero bit
 + m6800.flags['Z'] = 1;
 + }else{
 + m6800.flags['Z'] = 0;
 + }
 + if(d[m6800.count(a) - 1]){ // test last bit for 1
 + m6800.flags['N'] = 1;
 + }else{
 + m6800.flags['N'] = 0;
 + }
 + m6800.flags['V'] = 0;
 + m6800.setByte(d, a);
 + d = {};
 + }else{
 + return d;
 + }
 +};
 +</code>
 +===not===
 +Given a byte, return the opposite of each bit position:
 +<code>
 +/*
 + * compliment byte (I.E. 1 = 0 ; 0 = 1)
 + */
 +m6800.compliment = function(b){
 + var d = {};
 + for(var v in b){
 + if(b[v]){
 + d[v] = 0;
 + }else{
 + d[v] = 1;
 + }
 + }
 + return d;
 +};
 +</code>
 +=====Instruction Set=====
 +The anatomy of the instruction
 +<code>
 +/*
 + * NAME - LOGIC COMMENT HERE
 + */
 +m6800.instr.[type]['B'] = {
 + name : 'B',
 + logic : 'logic',
 + modes : {
 + 'IMM' : 'BF',
 + 'DIR' : 'CF',
 + 'INX' : 'DF',
 + 'EXT' : 'EF',
 + 'INH' : 'FF'
 + },
 + ccr : {
 + 'H' : 'T',
 + 'I' : 'T',
 + 'N' : 'T',
 + 'Z' : 'T',
 + 'V' : 'T',
 + 'C' : 'T'
 + },
 + f : function(){
 + var m = memory[m6800.address_bus]; //more on memory later
 + alert('place instruction logic here');
 + }
 +};
 +</code>
 +**''ccr''** fields indicate the condition necessary to toggle each flag (see simulator).  The function **''f''** is where the primary logic of the instruction is found (the field labeled **''logic''** is text for the UI instruction table).  Each member of the **''modes''** object contain hex op codes.  Now a simple loop to create a series of op code objects:
 +<code>
 + //Instructions by Op Code
 + for(var v in m6800.instr){
 + for(var w in m6800.instr[v]){
 + if(m6800.instr[v][w].modes){
 + for(var x in m6800.instr[v][w].modes){
 + if(m6800.instr[v][w].modes[x] != ''){
 + m6800.instr[m6800.instr[v][w].modes[x]] = {};
 + m6800.instr[m6800.instr[v][w].modes[x]].mode = x;
 + m6800.instr[m6800.instr[v][w].modes[x]].name = w;
 + m6800.instr[m6800.instr[v][w].modes[x]].type = v;
 + }
 + }
 + }
 + }
 +  }
 +</code>
 +This creates a global object that looks a little like this:
 +<code>
 +m6800.instr = {
 +
 +/*
 + * object notation for operation codes (gleaned dynamically from instruction objects)
 + */
 +   1B : {
 +      mode : 'INH'
 +      name : 'ABA'
 +      type : 'al'
 +   }
 +
 +   ... more operation codes here
 +
 +/*
 + * object notation for CLC - 0 -> C
 + */
 +    ccr['CLC'] : {
 + name : 'CLC',
 + logic : '0 -> C',
 + modes : {
 + 'INH' : '0C'
 + },
 + ccr : {
 + 'H' : 'N',
 + 'I' : 'N',
 + 'N' : 'N',
 + 'Z' : 'N',
 + 'V' : 'N',
 + 'C' : 'R'
 + },
 + f : function(){
 + m6800.flags['C'] = 0;
 + m6800.ui.setFlag(m6800.flags, 'C');
 + }
 +   },
 +   
 +   ... more instructions here
 +};
 +</code>
 +Looking closer at the definition of the instruction you can see that the actual instruction name contains two identifiers, ''ccr'' and ''CLC'' In this notation, the ''ccr'' portion of the name indicates the instruction's type (strictly used for the purpose of modularized output) and the second portion is the name of the function, in this case ''CLC'' The concept of instruction types was taken from the m6800 manual: 
 +  *Arithmetic & logic operations : al
 +  *Stack pointer and index register operations : sp
 +  *Condition control register operations : ccr
 +  *Jump & branch operations : jmp
 +Using this convention, the ''JMP'' (jump) instruction would be called ''m6800.instr.jmp.JMP'' and ''INX'' (increment index register) instruction would be called ''m6800.instr.sp.INX''.
 +<WRAP info round>
 +Do yourself a favor and head over to the [[http://www.getfirebug.com|FireBug website]] and then hit the simulator.  Investigate the ''m6800'' object to see the overall object notation.  (also look for the ''memory'' object)
 +</WRAP>
 +Now (with aid from a helper function) instructions may be called by op-code as simply as 
 +<code>
 +   m6800.util.instr(data[i].modes[j])
 +</code>
 +It is a proud feat that this function is called from only 1 place in the source code.  Later, once the addressing mode is determined, the logic of the instruction is called: 
 +<code>
 +   m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f()
 +   ...(only called from 2 places)
 +</code>
 +Since the addressing mode handler takes care of the placement of the program counter and the address bus, each instruction will find it's operand (if necessary) via the following line:
 +<code>
 + var m = memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))];
 +</code>
 +====Utilities====
 +<WRAP info round>
 +Clever as you are ... you've no doubt noticed the reverse function.  Your typical JSON object to string function would generally start at the first member of the object, stringify-ing as it goes.  As such, the stringification of a 16 member object ordered 0 thru 15 would result in the zero-th member at the left of the string, and the 15th member at right (in other words, left-to-right) ... and so, it is necessary to reverse the object (and thus the resulting string) to achieve the typically right-to-left notation so loved by binary enthusiasts.
 +</WRAP>
 +===Reverse===
 +<code>
 +/*
 + * from m6800.js ... reverse any given byte(s) ... spit out as d
 + */
 +m6800.reverse = function(b){
 + var d = {};
 + for(var v in b){
 + d[m6800.count(b)-v-1] = b[v];
 + }
 + return d;
 +};
 +</code>
 +===Decrement===
 +<code>
 +/*
 + * decrement given byte(s)
 + */
 +m6800.decrement = function(key){
 + var b = m6800[key];
 + var ct = m6800.count(b);
 + var subtrahend = {};
 + if(b[0]){ // first bit = 1
 + b[0] = 0;
 + }else{
 + var i = 1;
 + subtrahend[0] = 1;
 + while(i < ct){
 + subtrahend[i] = 0;
 + i++;
 + }
 + var d = m6800.subtract(subtrahend, b, false);
 + delete d[ct];
 + m6800.setByte(d, m6800[key]);
 + }
 +};
 +</code>
 +===Equal To===
 +<code>
 +/*
 + * eq - is a equal to b ... return true, false
 + */
 +m6800.eq = function(a, b){
 + var eq = 1;
 + for(v in a){
 + if(a[v] != b[v]){
 + eq = 0;
 + }
 + }
 + return eq;
 +};
 +</code>
 +===Increment===
 +Increment & decrement functions use a string key as the object lookup, and then increments or decrements the byte(s).
 +<code>
 +/*
 + * increment given byte(s)
 + */
 +m6800.increment = function(key){
 + var b = m6800[key];
 + var ct = m6800.count(b);
 + var c = 0;
 + var i = 1;
 + if(b[0]){
 + c = 1;
 + b[0] = 0;
 + }else{
 + b[0] = 1;
 + }
 + while(c && i < ct){
 + if(b[i]){
 + b[i] = 0;
 + }else{
 + b[i] = 1;
 + c = 0;
 + }
 + i++;
 + }
 +};
 +</code>
 +====Arithmetic & Logic====
 +Since the addition function is called by some instructions which need ''CCR'' flags toggled, and other instructions which need other flags toggled (based upon a pattern of course) it is necessary to either set the necessary ''CCR'' flags directly, or create a new ''condition code register'' object and pass it back to the calling function to do with what it pleases:
 +<code>
 +/*
 + * add a & b together ... spit them out as d, or write to a if w (write)
 + */
 +m6800.add = function(a, b, w){
 + var c = 0; //carry
 + var h = 0; //half carry
 + var i = 0; //index
 + var z = 1; //zero
 + var v = 0; //overflow
 + var d = {}; //new value
 + var ccr = {}; // new ccr
 + for(i; i < m6800.count(a); i++){
 + if(i == 3 && ((a[i] && c) || (b[i] && c) || (a[i] && b[i]))){ // half carry
 + h = 1;
 + }
 + if(a[i] && b[i]){ //a & b == 1
 + if(c){ // carry = 1 => 1 + 1 + 1 = 1 => c = 1
 + d[i] = 1;
 + z = 0;
 + }else{ // carry = 0 => 1 + 1 = 0 => c =1
 + d[i] = 0;
 + c = 1;
 + }
 + }else{ //a and/or b == 0
 + if(a[i] || b[i]){ // a or b == 1 (not both)
 + if(c){ // carry = 1 => 1 + 0 + 1 = 0 => c = 1
 + d[i] = 0;
 + }else{ // carry = 0 => 1 + 0 = 1 => c = 0
 + d[i] = 1;
 + z = 0;
 + }
 + }else{ // a and b == 0
 + if(c){ //carry = 1 => 0 + 0 + 1 = 1 => c = 0
 + d[i] = 1;
 + c = 0;
 + z = 0;
 + }else{ //carry = 0 => 0 + 0 = 0 => c = 0; 
 + d[i] = 0;
 + }
 + }
 + }
 + };
 +
 + if(w){
 + /*
 + * set condition code register & write to accume_a
 + */
 + m6800.flags['Z'] = z;
 + if(d[m6800.count(a) - 1]){
 + m6800.flags['N'] = 1;
 + }else{
 + m6800.flags['N'] = 0;
 + }
 + m6800.flags['H'] = h;
 + m6800.flags['C'] = c;
 +
 + if(m6800.count(a) <= 8){
 + if((a[7] == b[7]) && d[7] != a[7]){
 + m6800.flags['V'] = 1;
 + }else{
 + m6800.flags['V'] = 0;
 + }
 + }else{
 + m6800.flags['V'] = 0;
 + }
 + m6800.setByte(d, a);
 + d = {};
 + return a;
 + }else{
 + /*
 + * add condition code register as last element of d
 + * return d
 + */
 + ccr['H'] = h;
 + if(d[m6800.count(a) - 1]){
 + ccr['N'] = 1;
 + }else{
 + ccr['N'] = 0;
 + }
 + if(m6800.count(a) <= 8){
 + if((a[7] == b[7]) && d[7] != a[7]){
 + ccr['V'] = 1;
 + }else{
 + ccr['V'] = 0;
 + }
 + }else{
 + ccr['V'] = 0;
 + }
 + ccr['Z'] = z;
 + ccr['V'] = v;
 + ccr['C'] = c;
 + d[m6800.count(a)] = ccr;
 + return d;
 + }
 +};
 +</code>
 +The subtract routine uses the 2's compliment method ... that is, add the compliment of the given operand, plus one.  Notice how the first call to ''add'' function calls ''false'', and the next line removes the extra ''CCR'' object prior to the second call to ''add'' ... again with ''false'', returning the new ''CCR'' object for the calling function to interpret.
 +<code>
 +/*
 + * subtract a from b ... spit them out as d, or write to a if w (write)
 + */
 +m6800.subtract = function(a, b, w){
 + var uno = {};
 + var ct = m6800.count(b);
 + var i = 0;
 + for(i; i < ct; i++){
 + if(i < 1){
 + uno[i] = 1;
 + }else{
 + uno[i] = 0;
 + }
 + }
 + var d = m6800.add(m6800.compliment(a), b, false);
 + delete d[ct];
 + d = m6800.add(d, uno, false);
 + return d;
 +};
 +</code>
 +====Index Register & Stack Pointer====
 +====Jump & Branch====
 +====Condition Code Register====
 +====Addressing Modes====
 +With the exception of inherent mode, addressing modes are handled in 2 steps: (1) collect the address(es) via hex input from the user, (2) after adjusting the address bus and program counter, fire the logic found in the instruction's ''f'' function.  The first step is found in the function ''m6800.util.instr(op)'' which passes the op-code from the ui (via click).  The second step is handled after the user provides hex input.
 +===Relative===
 +In relative addressing mode, the operand following the instruction is interpreted as a signed (that is positive or negative) 7 bit value that specifies the offset (from the program counter) to the next instruction.  Relative addressing mode is used for most of the jump and branch instructions.
 +
 +From ''m6800.util.instr(op)''
 +<code>
 + switch(m6800.instr[op].mode){
 + case 'REL':
 + // RELATIVE -- contents of next address == signed offset to operand
 + html = '<div class="message"><div class="instruction">' + m6800.instr[op].name + '<span class="name">(' + m6800.instr[op].mode + ')</span></div>';
 + html = html + 'Enter the 1 byte signed hex operand (-125 to +129) to be used as the offset from the address of the next instruction:</div>';
 + html = html + '<input type="text" id="h_byte" class="hex_byte" name="byte" maxlength="2" value="">';
 + html = html + '<span class="button">';
 + html = html + '<input type="button" id="submit_byte" name="submit_byte" value="Fire!" onclick="';
 +// submit function is called here
 + html = html + 'm6800.util.REL(\'' + op + '\')';
 +// end submit function
 + html = html + '"></span>';
 + m6800.ui.modal(html, function(){});
 +// function not fired as user input is required
 + fire = 0;
 + break;
 +</code>
 +<code>
 +m6800.util.REL = function(op){
 + if(jQuery('input#h_byte').val()){
 + var b = jQuery('input#h_byte').val().toUpperCase(); 
 + m6800.setByte(m6800.program_counter, m6800.address_bus);
 + memory.put(m6800.util.hexToBin(b));
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }else{
 + alert('OK ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)));
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.increment('address_bus');
 + m6800.setByte(m6800.address_bus, m6800.program_counter);
 + m6800.decrement('address_bus');
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }
 + m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f(); // fire instruction here
 + m6800.ui.cancelModal();
 +};
 +</code>
 +===Immediate===
 +In immediate addressing mode, the operand acted upon by the instruction is provided and placed in the address immediately following the instruction.  The program counter is then incremented to point to the next available address (that is, the address of the next instruction).
 +
 +From ''m6800.util.instr(op)''
 +<code>
 + switch(m6800.instr[op].mode){
 + case 'IMM':
 + // IMMEDIATE -- contents of next address == operand
 + var h = '';
 + html = '<div class="message"><div class="instruction">' + m6800.instr[op].name + '<span class="name">(' + m6800.instr[op].mode + ')</span></div>';
 + switch(m6800.instr[op].name){
 + case 'LDX':
 + case 'LDS':
 + case 'CPX':
 + html = html + 'Enter the two, 1 byte hex operands to be placed in memory:</div>';
 + h = '<input type="text" id="h_byte_2" class="hex_byte" name="byte_2" maxlength="2" value="">';
 + break;
 + default:
 + html = html + 'Enter the 1 byte hex operand to be placed in memory:</div>';
 + break;
 + }
 + html = html + '<input type="text" id="h_byte" class="hex_byte" name="byte" maxlength="2" value="">' + h;
 + html = html + '<span class="button">';
 + html = html + '<input type="button" id="submit_byte" name="submit_byte" value="Fire!" onclick="';
 +// submit function is called here
 + html = html + 'm6800.util.IMM(\'' + op + '\')';
 +// end submit function
 + html = html + '"></span>';
 + m6800.ui.modal(html, function(){});
 +// function not fired as user input is required
 + fire = 0;
 + break;
 +</code>
 +<code>
 +m6800.util.IMM = function(op){
 + if(jQuery('input#h_byte').val()){
 + var b = jQuery('input#h_byte').val().toUpperCase(); 
 + m6800.setByte(m6800.program_counter, m6800.address_bus);
 + memory.put(m6800.util.hexToBin(b));
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }else{
 + alert('OK ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)));
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.increment('address_bus');
 + m6800.setByte(m6800.address_bus, m6800.program_counter);
 + m6800.decrement('address_bus');
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }
 + switch(m6800.instr[op].name){
 + case 'LDX' :
 + case 'LDS' :
 + case 'CPX' :
 + if(jQuery('input#h_byte_2').val()){
 + var b2 = jQuery('input#h_byte_2').val().toUpperCase(); 
 + memory.put(m6800.util.hexToBin(b2));
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }else{
 + alert('OK ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)));
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.increment('address_bus');
 + m6800.setByte(m6800.address_bus, m6800.program_counter);
 + m6800.decrement('address_bus');
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }
 + break;
 + }
 + m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f();
 + m6800.ui.cancelModal();
 +};
 +</code>
 +Notice the switch on the operation name.  ''CPX'' (compare index register), ''LDS'' (load stack pointer) and ''LDX'' (load index register) each require the contents of two memory addresses (upper byte == m, lower byte == m+1) to load into or compare with either the 16 bit index register and 16 bit stack pointer.
 +===Direct===
 +Direct addressing mode requires that the low order byte of the address of the operand be provided immediately after the instruction.  This byte is concatenated to ZERO (that is, 8 zeros making up the high order byte).  Therefore, the direct addressing mode allows for addressing in the range of 0-255.  The address bus is then set to the location of the operand, and the program counter is incremented to point to the address of the next instruction.
 +
 +From ''m6800.util.instr(op)''
 +<code>
 + switch(m6800.instr[op].mode){
 + case 'DIR':
 + //DIRECT -- contents of next address == low byte of address of operand
 + html = '<div class="message"><div class="instruction">' + m6800.instr[op].name + '<span class="name">(' + m6800.instr[op].mode + ')</span></div>';
 + html = html + 'Enter the 1 byte hex operand (equal or less than 255) to be used as the low order byte of the memory location of the operand:</div>';
 + html = html + '<input type="text" id="h_byte" class="hex_byte" name="byte" maxlength="2" value="">';
 + html = html + '<span class="button">';
 + html = html + '<input type="button" id="submit_byte" name="submit_byte" value="Fire!" onclick="';
 +// submit function is called here
 + html = html + 'm6800.util.DIR(\'' + op + '\')';
 +// end submit function
 + html = html + '"></span>';
 + m6800.ui.modal(html, function(){});
 +// function not fired as user input is required
 + fire = 0;
 +</code>
 +<code>
 +m6800.util.DIR = function(op){
 + if(jQuery('input#h_byte').val()){
 + var b = jQuery('input#h_byte').val().toUpperCase();
 + m6800.setByte(m6800.program_counter, m6800.address_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + memory.put(m6800.util.hexToBin(b));
 + }else{
 + alert('OK ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)));
 + m6800.increment('address_bus');
 + m6800.increment('program_counter');
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.program_counter, 'ul#program_counter_list');
 + }
 + var str = m6800.stringify(m6800.cero) + m6800.stringify(m6800.reverse(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))]));
 + m6800.setByte(m6800.objectify(str), m6800.address_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f();
 + m6800.ui.cancelModal();
 +};
 +</code>
 +===Extended===
 +Extended addressing is much the same as direct addressing except that both the low order byte and high order byte of the address of the operand are provided.  This allows for addressing in the range 0 - 65,536 (be careful with extended addressing mode in the simulator, as there are only 512 address available).
 +
 +From ''m6800.util.instr(op)''
 +<code>
 + switch(m6800.instr[op].mode){
 + case 'EXT':
 + // EXTENDED -- contents of next TWO addresses == low and high bytes of  address of operand
 + html = '<div class="message"><div class="instruction">' + m6800.instr[op].name + '<span class="name">(' + m6800.instr[op].mode + ')</span></div>';
 + html = html + 'Enter the 2 byte hex operand to be combined as the low & high order bytes of the memory location of the operand:';
 + html = html + '<span class="alert">Be careful, you only have ' + m6800.count(memory.q) + ' memory addresses NOT ' + Math.pow(2, 16) + '</span></div>';
 + html = html + '<input type="text" id="h_byte" class="hex_byte" name="byte" maxlength="2" value="">';
 + html = html + '<input type="text" id="h_byte_2" class="hex_byte" name="byte_2" maxlength="2" value="">';
 + html = html + '<span class="button">';
 + html = html + '<input type="button" id="submit_byte" name="submit_byte" value="Fire!" onclick="';
 +// submit function is called here
 + html = html + 'm6800.util.EXT(\'' + op + '\')';
 +// end submit function
 + html = html + '"></span>';
 + m6800.ui.modal(html, function(){});
 +// function not fired as user input is required
 + fire = 0;
 + break;
 +</code>
 +<code>
 +m6800.util.EXT = function(op){
 + var b = '';
 + var str = '';
 + if(jQuery('input#h_byte').val()){
 + b = jQuery('input#h_byte').val().toUpperCase();
 + str = m6800.stringify(m6800.reverse(m6800.util.hexToBin(b)));
 + memory.put(m6800.util.hexToBin(b));
 + }else{
 + alert('OK ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)) + ' as the low order byte.');
 + str = m6800.stringify(memory.q[m6800.stringify(m6800.reverse(m6800.program_counter))]);
 + m6800.increment('program_counter');
 + }
 +
 + if(jQuery('input#h_byte_2').val()){
 + b = jQuery('input#h_byte_2').val().toUpperCase();
 + str = str + m6800.stringify(m6800.reverse(m6800.util.hexToBin(b)));
 + memory.put(m6800.util.hexToBin(b));
 + }else{
 + alert(' ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)) + ' as the high order byte.');
 + str = str + m6800.stringify(memory.q[m6800.stringify(m6800.reverse(m6800.program_counter))]);
 + m6800.increment('program_counter');
 + }
 + m6800.setByte(m6800.objectify(str), m6800.address_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + switch(m6800.instr[op].name){
 + case 'JSR':
 + // need to stack the program counter
 + var m_l = {
 + 0 : m6800.program_counter[0],
 + 1 : m6800.program_counter[1],
 + 2 : m6800.program_counter[2],
 + 3 : m6800.program_counter[3],
 + 4 : m6800.program_counter[4],
 + 5 : m6800.program_counter[5],
 + 6 : m6800.program_counter[6],
 + 7 : m6800.program_counter[7],
 + };
 + var m_h = {
 + 0 : m6800.program_counter[8],
 + 1 : m6800.program_counter[9],
 + 2 : m6800.program_counter[10],
 + 3 : m6800.program_counter[11],
 + 4 : m6800.program_counter[12],
 + 5 : m6800.program_counter[13],
 + 6 : m6800.program_counter[14],
 + 7 : m6800.program_counter[15],
 + };
 +// set the low byte first
 + m6800.setByte(m_l, memory.q[m6800.stringify(m6800.reverse(m6800.stack_pointer))]);
 + memory.set(m6800.stringify(m6800.reverse(m_l)), m6800.stringify(m6800.reverse(m6800.stack_pointer)));
 + m6800.decrement('stack_pointer');
 + m6800.ui.setByte(m6800.stack_pointer, "ul#stack_pointer_list");
 +// set the high byte second
 + m6800.setByte(m_h, memory.q[m6800.stringify(m6800.reverse(m6800.stack_pointer))]);
 + memory.set(m6800.stringify(m6800.reverse(m_h)), m6800.stringify(m6800.reverse(m6800.stack_pointer)));
 + m6800.decrement('stack_pointer');
 + m6800.ui.setByte(m6800.stack_pointer, "ul#stack_pointer_list");
 + // let it fall through and set the program counter
 + case 'JMP':
 + // need to position program counter now as it's harder to detect the addressing mode later
 + m6800.setByte(m6800.address_bus, m6800.program_counter);
 + m6800.ui.setByte(m6800.program_counter, "ul#program_counter_list");
 + break;
 + }
 + m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f();
 + m6800.ui.cancelModal();
 +};
 +</code>
 +Notice the switch on ''JSR'' (jump to subroutine) which requires that the program counter be stacked and ''JMP'' (jump), which requires that the program counter be adjusted, but not stacked.
 +===Indexed===
 +Indexed addressing mode requires adds the byte immediately provided to the value of the index register to provide the address of the operand to the function.
 +
 +From ''m6800.instr(op)''
 +<code>
 + switch(m6800.instr[op].mode){
 + case 'INX':
 + // INDEXED -- address of operand == contents of index register + offset <= 255
 + html = '<div class="message"><div class="instruction">' + m6800.instr[op].name + '<span class="name">(' + m6800.instr[op].mode + ')</span></div>';
 + html = html + 'Enter the 1 byte hex operand (equal or less than 255) to be added to the index register; used as the address of the operand:</div>';
 + html = html + '<input type="text" id="h_byte" class="hex_byte" name="byte" maxlength="2" value="">';
 + html = html + '<span class="button">';
 + html = html + '<input type="button" id="submit_byte" name="submit_byte" value="Fire!" onclick="';
 +// submit function is called here
 + html = html + 'm6800.util.INX(\'' + op + '\')';
 +// end submit function
 + html = html + '"></span>';
 + m6800.ui.modal(html, function(){});
 + // function not fired as user input is required
 + fire = 0;
 + break;
 +</code>
 +<code>
 +m6800.util.INX = function(op){
 + var addr;
 + if(jQuery('input#h_byte').val()){
 + var b = jQuery('input#h_byte').val().toUpperCase();
 + var c = m6800.util.hexToBin(b);
 + addr = m6800.add(m6800.index_register,c, false);
 + delete addr[m6800.count(m6800.index_register)];
 + memory.put(c);
 + m6800.setByte(addr, m6800.address_bus);
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }else{
 + alert('OK ... use the operand at ' + m6800.stringify(m6800.reverse(m6800.program_counter)));
 + var c = memory.q[m6800.stringify(m6800.reverse(m6800.program_counter))];
 + addr = m6800.add(m6800.index_register,c, false);
 + delete addr[m6800.count(m6800.index_register)];
 + m6800.setByte(addr, m6800.address_bus);
 + m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], m6800.data_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + m6800.ui.setByte(m6800.data_bus, 'ul#data_bus_list');
 + }
 + switch(m6800.instr[op].name){
 + case 'JSR': //jump to subroutine
 + // need to stack the program counter
 + var m_l = {
 + 0 : m6800.program_counter[0],
 + 1 : m6800.program_counter[1],
 + 2 : m6800.program_counter[2],
 + 3 : m6800.program_counter[3],
 + 4 : m6800.program_counter[4],
 + 5 : m6800.program_counter[5],
 + 6 : m6800.program_counter[6],
 + 7 : m6800.program_counter[7],
 + };
 + var m_h = {
 + 0 : m6800.program_counter[8],
 + 1 : m6800.program_counter[9],
 + 2 : m6800.program_counter[10],
 + 3 : m6800.program_counter[11],
 + 4 : m6800.program_counter[12],
 + 5 : m6800.program_counter[13],
 + 6 : m6800.program_counter[14],
 + 7 : m6800.program_counter[15],
 + };
 +// set the low byte first
 + m6800.setByte(m_l, memory.q[m6800.stringify(m6800.reverse(m6800.stack_pointer))]);
 + memory.set(m6800.stringify(m6800.reverse(m_l)), m6800.stringify(m6800.reverse(m6800.stack_pointer)));
 + m6800.decrement('stack_pointer');
 + m6800.ui.setByte(m6800.stack_pointer, "ul#stack_pointer_list");
 +// set the high byte second
 + m6800.setByte(m_h, memory.q[m6800.stringify(m6800.reverse(m6800.stack_pointer))]);
 + memory.set(m6800.stringify(m6800.reverse(m_h)), m6800.stringify(m6800.reverse(m6800.stack_pointer)));
 + m6800.decrement('stack_pointer');
 + m6800.ui.setByte(m6800.stack_pointer, "ul#stack_pointer_list");
 + // let it fall through and set the program counter
 + case 'JMP': // jump
 + // need to position program counter now as it's harder to detect the addressing mode later
 + m6800.setByte(m6800.address_bus, m6800.program_counter);
 + m6800.ui.setByte(m6800.program_counter, "ul#program_counter_list");
 + break;
 + }
 + m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f();
 + m6800.ui.cancelModal();
 +};
 +</code>
 +Again, notice the switch on ''JSR'' (jump to subroutine) which requires that the program counter be stacked and ''JMP'' (jump), which requires that the program counter be adjusted, but not stacked.
 +
 +===Inherent===
 +Inherent addressing mode indicates that the address of the operand is inherent in the instruction.  For example, ''ABA'' which adds ''accumulator A'' to ''accumulator B'' and places the result in ''accumulator A''.
 +
 +From ''m6800.util.instr(op)''
 +<code>
 + case 'INH':
 + // INHERENT -- address of operand included in instruction
 + m6800.setByte(m6800.program_counter, m6800.address_bus);
 + m6800.ui.setByte(m6800.address_bus, 'ul#address_bus_list');
 + break;
 +...
 +
 +this case does not set the fire flag to zero (which is initialized as 1) so
 +
 +...
 + if(fire){
 + m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f();
 + }
 +</code>
 +=====Memory=====
 +
 +=====User Interface=====
 +It should go without saying that the *real* m6800 microprocessor does not have a "user interface" in the terms that most computer users are accustomed, however this simulation needed a way to interact with users across different platforms, and in particular, not privy to the Lab46 command line.  Therefore, it could be said that the user interface for this simulator is strictly a figment of its creator's imagination whereby instructions are mapped and presented for user's clicking enjoyment.  However far off course this leads, and for what it's worth, here's how it's all put together for those who are interested:
 +====Step 1====
 +First, all the instructions are placed into object notation in the manner described above.  Then, as also shown previously, a quick, multi-nested loop iterates over the body of all instruction objects.
 +
 +<code>
 + //Instructions by Op Code
 + for(var v in m6800.instr){
 + for(var w in m6800.instr[v]){
 + if(m6800.instr[v][w].modes){
 + for(var x in m6800.instr[v][w].modes){
 + if(m6800.instr[v][w].modes[x] != ''){
 + m6800.instr[m6800.instr[v][w].modes[x]] = {};
 + m6800.instr[m6800.instr[v][w].modes[x]].mode = x;
 + m6800.instr[m6800.instr[v][w].modes[x]].name = w;
 + m6800.instr[m6800.instr[v][w].modes[x]].type = v;
 + }
 + }
 + }
 + }
 +  }
 +</code>
 +====Step 2====
 +Objects are create that describe the attributes of each ''type'' of instruction.  It looks like this:
 +<code>
 +/*
 + * taken from m6800.ui.js ... output information for the condition code register instructions
 + */
 +m6800.ui.instr.ccr = {
 + id : 'ccr',
 + title : 'Condition Code Register Operations',
 + colgroup : {
 + 1 : 'op',
 + 2 : 'inh',
 + 3 : 'logic',
 + 4 : 'h',
 + 5 : 'i',
 + 6 : 'n',
 + 7 : 'z',
 + 8 : 'v',
 + 9 : 'c'
 + },
 + thead : { 
 + 1 : {
 + 1 : {span : 9, text : 'Condition Code Register Operations', id : 'title'},
 + },
 + 2 : {
 + 1 : {span : 1, text : '', id : 'empty'},
 + 2 : {span : 1, text : 'Addressing Modes', id : ''},
 + 3 : {span : 1, text : '', id : 'empty'},
 + 4 : {span : 6, text : 'CCR', id : ''}
 + },
 + 3 : {
 + 1 : {span : 1, text : 'Operation', id : 'op'},
 + 5 : {span : 1, text : 'INH', id : 'inh'},
 + 6 : {span : 1, text : 'Boolean Operation', id : 'logic'},
 + 7 : {span : 1, text : 'H', id : 'h'},
 + 8 : {span : 1, text : 'I', id : 'i'},
 + 9 : {span : 1, text : 'N', id : 'n'},
 + 10 : {span : 1, text : 'Z', id : 'z'},
 + 11 : {span : 1, text : 'V', id : 'v'},
 + 12 : {span : 1, text : 'C', id : 'c'}
 + }
 + },
 + f : function(){
 + m6800.ui.instr_table(this, m6800.instr.ccr);
 + }
 +};
 +</code>
 +The ''colgroup'' members allow for some elegant table CSS, and each of the ''thead'' members maps directly to a table header in the graphic output.  As previous convention has shown, any logic that must be executed upon this global object is placed in the ''f'' member (in this case, the output function).  This is all thrown to the function ''m6800.ui.instr.table(obj, dataset)'':
 +<code>
 +/*
 + * taken from m6800.ui.js ... simple table builder FOR INSTRUCTIONS
 + */
 +m6800.ui.instr_table = function(obj, data){
 + html = '<table id="' + obj.id + '">';
 +//column groups
 + for(var v in obj.colgroup){
 + html = html + '<colgroup class="' + obj.colgroup[v] + '"></colgroup>';
 + }
 +//<thead>
 + html = html + '<thead>';
 +
 + for(var h in obj.thead){
 + html = html + '<tr>';
 + for(var i in obj.thead[h]){
 + html = html + '<th colspan="' + obj.thead[h][i].span + '" id="' + obj.thead[h][i].id + '">' + obj.thead[h][i].text + '</th>';
 + }
 + html = html + '</tr>';
 + }
 + html = html + '</thead>';
 +//<tbody>
 + html = html + '<tbody>';
 + for(var i in data){
 + html = html + '<tr>';
 + html = html + '<td class="op">' + data[i].name + '</td>';
 + for(var j in data[i].modes){
 + html = html + '<td>';
 + if(data[i].modes[j]){
 + html = html + '<a href="#" onClick="m6800.util.instr(\'' + data[i].modes[j] + '\'); return false;">' + data[i].modes[j] + '</a>';
 + }
 + html = html + '</td>';
 + }
 + html = html + '<td>' + data[i].logic + '</td>';
 + for(var k in data[i].ccr){
 + html = html + '<td>' + data[i].ccr[k] + '</td>';
 + }
 + html = html + '</tr>';
 + }
 + html = html + '</tbody>';
 + html = html + '</table>';
 + jQuery("#instructions").prepend(html);
 +};
 +</code>
 +This function iterates over each object in the passed ''obj'', creating a nifty nested table structure, then iterates over the members of the given ''data'' to fill the table with body rows.  Note the ''onClick'' function that is hard coded here, passing each instruction's operation code.  This is why the instruction handler is placed in the source code only once.
 +=====Links & Resources =====
 +  *[[http://en.wikipedia.org/wiki/Motorola_6800|Motorola 6800 (Wikipedia)]]
 +  *[[http://www.visual6502.org/| Visual Transistor-level Simulation of the 6502 CPU (and m6800)]]
 +  *[[http://www.fastchip.net/howcomputerswork/p1.html| How Computers Work; Processor and Main Memory]]
 +  *[[http://www.wickensonline.co.uk/hx-20/M6800applMan_Mar75.pdf|MC6800 operations manual (circa. 1975) ]]