This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
user:mcooper6:m6800 [2011/12/10 16:18] – mcooper6 | user:mcooper6:m6800 [2012/12/05 00:23] (current) – [Logical Operations] mcooper6 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | <WRAP left 40%> | ||
+ | ~~TOC~~ | ||
+ | </ | ||
+ | // | ||
+ | // | ||
+ | <WRAP centeralign 90% bigger> | ||
+ | <WRAP bigger fgred> | ||
+ | <WRAP muchbigger> | ||
+ | JSON based replication of the Motorola 6800 | ||
+ | </ | ||
+ | <WRAP left 50%> | ||
+ | <WRAP info left 80% bgwhite> | ||
+ | What follows is a humble attempt at clarity via vast modularization. | ||
+ | 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 clear></ | ||
+ | // | ||
+ | // | ||
+ | =====m6800 as JSON Object===== | ||
+ | It is a short jaunt to visualize the m6800 as a JSON object. | ||
+ | < | ||
+ | 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 : { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }, | ||
+ | bus_control : { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }, | ||
+ | processor_control : { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }, | ||
+ | memory : {} | ||
+ | }; | ||
+ | </ | ||
+ | Using this notation, bits and bytes may be set via loops and simple statements like '' | ||
+ | < | ||
+ | for(v in bits){ | ||
+ | target[v] = bits[v] + some other stuff; | ||
+ | } | ||
+ | </ | ||
+ | ====Logical Operations==== | ||
+ | ===and=== | ||
+ | This function '' | ||
+ | < | ||
+ | /* | ||
+ | * 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[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | if(d[m6800.count(a) - 1]){ // test last bit for 1 | ||
+ | m6800.flags[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | m6800.flags[' | ||
+ | if(w){ | ||
+ | m6800.setByte(d, | ||
+ | d = {}; | ||
+ | }else{ | ||
+ | return d; | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | For example, taken from '' | ||
+ | < | ||
+ | var m = memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))]; | ||
+ | m6800.and(m6800.accume_a, | ||
+ | m6800.ui.setByte(m6800.accume_a, | ||
+ | m6800.ui.setFlag(m6800.flags, | ||
+ | m6800.ui.setFlag(m6800.flags, | ||
+ | </ | ||
+ | |||
+ | Functions like '' | ||
+ | |||
+ | <WRAP round info> | ||
+ | Curious about | ||
+ | |||
+ | It's is a JavaScript hook to an HTML element <ul id=' | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===or=== | ||
+ | < | ||
+ | /* | ||
+ | * 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[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | if(d[m6800.count(a) - 1]){ // test last bit for 1 | ||
+ | m6800.flags[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | m6800.flags[' | ||
+ | m6800.setByte(d, | ||
+ | d = {}; | ||
+ | }else{ | ||
+ | return d; | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | ===xor=== | ||
+ | < | ||
+ | /* | ||
+ | * 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[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | if(d[m6800.count(a) - 1]){ // test last bit for 1 | ||
+ | m6800.flags[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | m6800.flags[' | ||
+ | m6800.setByte(d, | ||
+ | d = {}; | ||
+ | }else{ | ||
+ | return d; | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | ===not=== | ||
+ | Given a byte, return the opposite of each bit position: | ||
+ | < | ||
+ | /* | ||
+ | * 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; | ||
+ | }; | ||
+ | </ | ||
+ | =====Instruction Set===== | ||
+ | The anatomy of the instruction | ||
+ | < | ||
+ | /* | ||
+ | * NAME - LOGIC COMMENT HERE | ||
+ | */ | ||
+ | m6800.instr.[type][' | ||
+ | name : ' | ||
+ | logic : ' | ||
+ | modes : { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }, | ||
+ | ccr : { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }, | ||
+ | f : function(){ | ||
+ | var m = memory[m6800.address_bus]; | ||
+ | alert(' | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | **'' | ||
+ | < | ||
+ | // | ||
+ | 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; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | This creates a global object that looks a little like this: | ||
+ | < | ||
+ | m6800.instr = { | ||
+ | |||
+ | /* | ||
+ | * object notation for operation codes (gleaned dynamically from instruction objects) | ||
+ | */ | ||
+ | 1B : { | ||
+ | mode : ' | ||
+ | name : ' | ||
+ | type : ' | ||
+ | } | ||
+ | |||
+ | ... more operation codes here | ||
+ | |||
+ | /* | ||
+ | * object notation for CLC - 0 -> C | ||
+ | */ | ||
+ | ccr[' | ||
+ | name : ' | ||
+ | logic : '0 -> C', | ||
+ | modes : { | ||
+ | ' | ||
+ | }, | ||
+ | ccr : { | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | }, | ||
+ | f : function(){ | ||
+ | m6800.flags[' | ||
+ | m6800.ui.setFlag(m6800.flags, | ||
+ | } | ||
+ | }, | ||
+ | |||
+ | ... more instructions here | ||
+ | }; | ||
+ | </ | ||
+ | Looking closer at the definition of the instruction you can see that the actual instruction name contains two identifiers, | ||
+ | *Arithmetic & logic operations : al | ||
+ | *Stack pointer and index register operations : sp | ||
+ | *Condition control register operations : ccr | ||
+ | *Jump & branch operations : jmp | ||
+ | Using this convention, the '' | ||
+ | <WRAP info round> | ||
+ | Do yourself a favor and head over to the [[http:// | ||
+ | </ | ||
+ | Now (with aid from a helper function) instructions may be called by op-code as simply as | ||
+ | < | ||
+ | | ||
+ | </ | ||
+ | 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: | ||
+ | < | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | 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: | ||
+ | < | ||
+ | var m = memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))]; | ||
+ | </ | ||
+ | ====Utilities==== | ||
+ | <WRAP info round> | ||
+ | Clever as you are ... you've no doubt noticed the reverse function. | ||
+ | </ | ||
+ | ===Reverse=== | ||
+ | < | ||
+ | /* | ||
+ | * 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; | ||
+ | }; | ||
+ | </ | ||
+ | ===Decrement=== | ||
+ | < | ||
+ | /* | ||
+ | * 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, | ||
+ | delete d[ct]; | ||
+ | m6800.setByte(d, | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | ===Equal To=== | ||
+ | < | ||
+ | /* | ||
+ | * 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; | ||
+ | }; | ||
+ | </ | ||
+ | ===Increment=== | ||
+ | Increment & decrement functions use a string key as the object lookup, and then increments or decrements the byte(s). | ||
+ | < | ||
+ | /* | ||
+ | * 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++; | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | ====Arithmetic & Logic==== | ||
+ | Since the addition function is called by some instructions which need '' | ||
+ | < | ||
+ | /* | ||
+ | * 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); | ||
+ | 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[' | ||
+ | if(d[m6800.count(a) - 1]){ | ||
+ | m6800.flags[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | m6800.flags[' | ||
+ | m6800.flags[' | ||
+ | |||
+ | if(m6800.count(a) <= 8){ | ||
+ | if((a[7] == b[7]) && d[7] != a[7]){ | ||
+ | m6800.flags[' | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | }else{ | ||
+ | m6800.flags[' | ||
+ | } | ||
+ | m6800.setByte(d, | ||
+ | d = {}; | ||
+ | return a; | ||
+ | }else{ | ||
+ | /* | ||
+ | * add condition code register as last element of d | ||
+ | * return d | ||
+ | */ | ||
+ | ccr[' | ||
+ | if(d[m6800.count(a) - 1]){ | ||
+ | ccr[' | ||
+ | }else{ | ||
+ | ccr[' | ||
+ | } | ||
+ | if(m6800.count(a) <= 8){ | ||
+ | if((a[7] == b[7]) && d[7] != a[7]){ | ||
+ | ccr[' | ||
+ | }else{ | ||
+ | ccr[' | ||
+ | } | ||
+ | }else{ | ||
+ | ccr[' | ||
+ | } | ||
+ | ccr[' | ||
+ | ccr[' | ||
+ | ccr[' | ||
+ | d[m6800.count(a)] = ccr; | ||
+ | return d; | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | 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 '' | ||
+ | < | ||
+ | /* | ||
+ | * 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), | ||
+ | delete d[ct]; | ||
+ | d = m6800.add(d, | ||
+ | return d; | ||
+ | }; | ||
+ | </ | ||
+ | ====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' | ||
+ | ===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. | ||
+ | |||
+ | From '' | ||
+ | < | ||
+ | switch(m6800.instr[op].mode){ | ||
+ | case ' | ||
+ | // RELATIVE -- contents of next address == signed offset to operand | ||
+ | html = '< | ||
+ | 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:</ | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | // submit function is called here | ||
+ | html = html + ' | ||
+ | // end submit function | ||
+ | html = html + '"></ | ||
+ | m6800.ui.modal(html, | ||
+ | // function not fired as user input is required | ||
+ | fire = 0; | ||
+ | break; | ||
+ | </ | ||
+ | < | ||
+ | m6800.util.REL = function(op){ | ||
+ | if(jQuery(' | ||
+ | var b = jQuery(' | ||
+ | m6800.setByte(m6800.program_counter, | ||
+ | memory.put(m6800.util.hexToBin(b)); | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | }else{ | ||
+ | alert(' | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.increment(' | ||
+ | m6800.setByte(m6800.address_bus, | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | } | ||
+ | m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f(); | ||
+ | m6800.ui.cancelModal(); | ||
+ | }; | ||
+ | </ | ||
+ | ===Immediate=== | ||
+ | In immediate addressing mode, the operand acted upon by the instruction is provided and placed in the address immediately following the instruction. | ||
+ | |||
+ | From '' | ||
+ | < | ||
+ | switch(m6800.instr[op].mode){ | ||
+ | case ' | ||
+ | // IMMEDIATE -- contents of next address == operand | ||
+ | var h = ''; | ||
+ | html = '< | ||
+ | switch(m6800.instr[op].name){ | ||
+ | case ' | ||
+ | case ' | ||
+ | case ' | ||
+ | html = html + 'Enter the two, 1 byte hex operands to be placed in memory:</ | ||
+ | h = '< | ||
+ | break; | ||
+ | default: | ||
+ | html = html + 'Enter the 1 byte hex operand to be placed in memory:</ | ||
+ | break; | ||
+ | } | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | // submit function is called here | ||
+ | html = html + ' | ||
+ | // end submit function | ||
+ | html = html + '"></ | ||
+ | m6800.ui.modal(html, | ||
+ | // function not fired as user input is required | ||
+ | fire = 0; | ||
+ | break; | ||
+ | </ | ||
+ | < | ||
+ | m6800.util.IMM = function(op){ | ||
+ | if(jQuery(' | ||
+ | var b = jQuery(' | ||
+ | m6800.setByte(m6800.program_counter, | ||
+ | memory.put(m6800.util.hexToBin(b)); | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | }else{ | ||
+ | alert(' | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.increment(' | ||
+ | m6800.setByte(m6800.address_bus, | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | } | ||
+ | switch(m6800.instr[op].name){ | ||
+ | case ' | ||
+ | case ' | ||
+ | case ' | ||
+ | if(jQuery(' | ||
+ | var b2 = jQuery(' | ||
+ | memory.put(m6800.util.hexToBin(b2)); | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | }else{ | ||
+ | alert(' | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.increment(' | ||
+ | m6800.setByte(m6800.address_bus, | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f(); | ||
+ | m6800.ui.cancelModal(); | ||
+ | }; | ||
+ | </ | ||
+ | Notice the switch on the operation name. '' | ||
+ | ===Direct=== | ||
+ | Direct addressing mode requires that the low order byte of the address of the operand be provided immediately after the instruction. | ||
+ | |||
+ | From '' | ||
+ | < | ||
+ | switch(m6800.instr[op].mode){ | ||
+ | case ' | ||
+ | //DIRECT -- contents of next address == low byte of address of operand | ||
+ | html = '< | ||
+ | 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:</ | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | // submit function is called here | ||
+ | html = html + ' | ||
+ | // end submit function | ||
+ | html = html + '"></ | ||
+ | m6800.ui.modal(html, | ||
+ | // function not fired as user input is required | ||
+ | fire = 0; | ||
+ | </ | ||
+ | < | ||
+ | m6800.util.DIR = function(op){ | ||
+ | if(jQuery(' | ||
+ | var b = jQuery(' | ||
+ | m6800.setByte(m6800.program_counter, | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | memory.put(m6800.util.hexToBin(b)); | ||
+ | }else{ | ||
+ | alert(' | ||
+ | m6800.increment(' | ||
+ | m6800.increment(' | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.program_counter, | ||
+ | } | ||
+ | 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.ui.setByte(m6800.address_bus, | ||
+ | m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f(); | ||
+ | m6800.ui.cancelModal(); | ||
+ | }; | ||
+ | </ | ||
+ | ===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. | ||
+ | |||
+ | From '' | ||
+ | < | ||
+ | switch(m6800.instr[op].mode){ | ||
+ | case ' | ||
+ | // EXTENDED -- contents of next TWO addresses == low and high bytes of address of operand | ||
+ | html = '< | ||
+ | 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 + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | // submit function is called here | ||
+ | html = html + ' | ||
+ | // end submit function | ||
+ | html = html + '"></ | ||
+ | m6800.ui.modal(html, | ||
+ | // function not fired as user input is required | ||
+ | fire = 0; | ||
+ | break; | ||
+ | </ | ||
+ | < | ||
+ | m6800.util.EXT = function(op){ | ||
+ | var b = ''; | ||
+ | var str = ''; | ||
+ | if(jQuery(' | ||
+ | b = jQuery(' | ||
+ | str = m6800.stringify(m6800.reverse(m6800.util.hexToBin(b))); | ||
+ | memory.put(m6800.util.hexToBin(b)); | ||
+ | }else{ | ||
+ | alert(' | ||
+ | str = m6800.stringify(memory.q[m6800.stringify(m6800.reverse(m6800.program_counter))]); | ||
+ | m6800.increment(' | ||
+ | } | ||
+ | |||
+ | if(jQuery(' | ||
+ | b = jQuery(' | ||
+ | str = str + m6800.stringify(m6800.reverse(m6800.util.hexToBin(b))); | ||
+ | memory.put(m6800.util.hexToBin(b)); | ||
+ | }else{ | ||
+ | alert(' | ||
+ | str = str + m6800.stringify(memory.q[m6800.stringify(m6800.reverse(m6800.program_counter))]); | ||
+ | m6800.increment(' | ||
+ | } | ||
+ | m6800.setByte(m6800.objectify(str), | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | switch(m6800.instr[op].name){ | ||
+ | case ' | ||
+ | // 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.set(m6800.stringify(m6800.reverse(m_l)), | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.stack_pointer, | ||
+ | // set the high byte second | ||
+ | m6800.setByte(m_h, | ||
+ | memory.set(m6800.stringify(m6800.reverse(m_h)), | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.stack_pointer, | ||
+ | // let it fall through and set the program counter | ||
+ | case ' | ||
+ | // need to position program counter now as it's harder to detect the addressing mode later | ||
+ | m6800.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.program_counter, | ||
+ | break; | ||
+ | } | ||
+ | m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f(); | ||
+ | m6800.ui.cancelModal(); | ||
+ | }; | ||
+ | </ | ||
+ | Notice the switch on '' | ||
+ | ===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 '' | ||
+ | < | ||
+ | switch(m6800.instr[op].mode){ | ||
+ | case ' | ||
+ | // INDEXED -- address of operand == contents of index register + offset <= 255 | ||
+ | html = '< | ||
+ | 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:</ | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | // submit function is called here | ||
+ | html = html + ' | ||
+ | // end submit function | ||
+ | html = html + '"></ | ||
+ | m6800.ui.modal(html, | ||
+ | // function not fired as user input is required | ||
+ | fire = 0; | ||
+ | break; | ||
+ | </ | ||
+ | < | ||
+ | m6800.util.INX = function(op){ | ||
+ | var addr; | ||
+ | if(jQuery(' | ||
+ | var b = jQuery(' | ||
+ | var c = m6800.util.hexToBin(b); | ||
+ | addr = m6800.add(m6800.index_register, | ||
+ | delete addr[m6800.count(m6800.index_register)]; | ||
+ | memory.put(c); | ||
+ | m6800.setByte(addr, | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | }else{ | ||
+ | alert(' | ||
+ | var c = memory.q[m6800.stringify(m6800.reverse(m6800.program_counter))]; | ||
+ | addr = m6800.add(m6800.index_register, | ||
+ | delete addr[m6800.count(m6800.index_register)]; | ||
+ | m6800.setByte(addr, | ||
+ | m6800.setByte(memory.q[m6800.stringify(m6800.reverse(m6800.address_bus))], | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.data_bus, | ||
+ | } | ||
+ | switch(m6800.instr[op].name){ | ||
+ | case ' | ||
+ | // 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.set(m6800.stringify(m6800.reverse(m_l)), | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.stack_pointer, | ||
+ | // set the high byte second | ||
+ | m6800.setByte(m_h, | ||
+ | memory.set(m6800.stringify(m6800.reverse(m_h)), | ||
+ | m6800.decrement(' | ||
+ | m6800.ui.setByte(m6800.stack_pointer, | ||
+ | // let it fall through and set the program counter | ||
+ | case ' | ||
+ | // need to position program counter now as it's harder to detect the addressing mode later | ||
+ | m6800.setByte(m6800.address_bus, | ||
+ | m6800.ui.setByte(m6800.program_counter, | ||
+ | break; | ||
+ | } | ||
+ | m6800.instr[m6800.instr[op].type][m6800.instr[op].name].f(); | ||
+ | m6800.ui.cancelModal(); | ||
+ | }; | ||
+ | </ | ||
+ | Again, notice the switch on '' | ||
+ | |||
+ | ===Inherent=== | ||
+ | Inherent addressing mode indicates that the address of the operand is inherent in the instruction. | ||
+ | |||
+ | From '' | ||
+ | < | ||
+ | case ' | ||
+ | // INHERENT -- address of operand included in instruction | ||
+ | m6800.setByte(m6800.program_counter, | ||
+ | m6800.ui.setByte(m6800.address_bus, | ||
+ | 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(); | ||
+ | } | ||
+ | </ | ||
+ | =====Memory===== | ||
+ | |||
+ | =====User Interface===== | ||
+ | It should go without saying that the *real* m6800 microprocessor does not have a "user interface" | ||
+ | ====Step 1==== | ||
+ | First, all the instructions are placed into object notation in the manner described above. | ||
+ | |||
+ | < | ||
+ | // | ||
+ | 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; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ====Step 2==== | ||
+ | Objects are create that describe the attributes of each '' | ||
+ | < | ||
+ | /* | ||
+ | * taken from m6800.ui.js ... output information for the condition code register instructions | ||
+ | */ | ||
+ | m6800.ui.instr.ccr = { | ||
+ | id : ' | ||
+ | title : ' | ||
+ | colgroup : { | ||
+ | 1 : ' | ||
+ | 2 : ' | ||
+ | 3 : ' | ||
+ | 4 : ' | ||
+ | 5 : ' | ||
+ | 6 : ' | ||
+ | 7 : ' | ||
+ | 8 : ' | ||
+ | 9 : ' | ||
+ | }, | ||
+ | thead : { | ||
+ | 1 : { | ||
+ | 1 : {span : 9, text : ' | ||
+ | }, | ||
+ | 2 : { | ||
+ | 1 : {span : 1, text : '', | ||
+ | 2 : {span : 1, text : ' | ||
+ | 3 : {span : 1, text : '', | ||
+ | 4 : {span : 6, text : ' | ||
+ | }, | ||
+ | 3 : { | ||
+ | 1 : {span : 1, text : ' | ||
+ | 5 : {span : 1, text : ' | ||
+ | 6 : {span : 1, text : ' | ||
+ | 7 : {span : 1, text : ' | ||
+ | 8 : {span : 1, text : ' | ||
+ | 9 : {span : 1, text : ' | ||
+ | 10 : {span : 1, text : ' | ||
+ | 11 : {span : 1, text : ' | ||
+ | 12 : {span : 1, text : ' | ||
+ | } | ||
+ | }, | ||
+ | f : function(){ | ||
+ | m6800.ui.instr_table(this, | ||
+ | } | ||
+ | }; | ||
+ | </ | ||
+ | The '' | ||
+ | < | ||
+ | /* | ||
+ | * taken from m6800.ui.js ... simple table builder FOR INSTRUCTIONS | ||
+ | */ | ||
+ | m6800.ui.instr_table = function(obj, | ||
+ | html = '< | ||
+ | //column groups | ||
+ | for(var v in obj.colgroup){ | ||
+ | html = html + '< | ||
+ | } | ||
+ | //< | ||
+ | html = html + '< | ||
+ | |||
+ | for(var h in obj.thead){ | ||
+ | html = html + '< | ||
+ | for(var i in obj.thead[h]){ | ||
+ | html = html + '< | ||
+ | } | ||
+ | html = html + '</ | ||
+ | } | ||
+ | html = html + '</ | ||
+ | //< | ||
+ | html = html + '< | ||
+ | for(var i in data){ | ||
+ | html = html + '< | ||
+ | html = html + '< | ||
+ | for(var j in data[i].modes){ | ||
+ | html = html + '< | ||
+ | if(data[i].modes[j]){ | ||
+ | html = html + '<a href="#" | ||
+ | } | ||
+ | html = html + '</ | ||
+ | } | ||
+ | html = html + '< | ||
+ | for(var k in data[i].ccr){ | ||
+ | html = html + '< | ||
+ | } | ||
+ | html = html + '</ | ||
+ | } | ||
+ | html = html + '</ | ||
+ | html = html + '</ | ||
+ | jQuery("# | ||
+ | }; | ||
+ | </ | ||
+ | This function iterates over each object in the passed '' | ||
+ | =====Links & Resources ===== | ||
+ | *[[http:// | ||
+ | *[[http:// | ||
+ | *[[http:// | ||
+ | *[[http:// |