summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2021-01-02 20:23:52 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2021-01-02 20:23:52 +0100
commit9490b470f3c0ac2357b60a56a893ab86556af634 (patch)
tree15d8358467ffdacc1bb76e9d9e926e6ee294070e
parentaff63a211e9b1e397adb9dce726d8153beb96dcd (diff)
download6502-9490b470f3c0ac2357b60a56a893ab86556af634.tar.gz
6502-9490b470f3c0ac2357b60a56a893ab86556af634.tar.bz2
added VIA
added some more opcodes (SEI, CLI)
-rw-r--r--README8
-rw-r--r--doc/6502.org_ Tutorials and Aids.html635
-rw-r--r--emu/6502.c67
-rw-r--r--emu/6502.h43
-rw-r--r--emu/6522.c68
-rw-r--r--emu/6522.h19
-rw-r--r--emu/emu.c3
-rw-r--r--emu/emul.c13
-rw-r--r--emu/tests/test_cpu_6502.c412
-rw-r--r--roms/7seg_counter_irq_timer.asm4
10 files changed, 1219 insertions, 53 deletions
diff --git a/README b/README
index d01bc3f..18343b1 100644
--- a/README
+++ b/README
@@ -127,6 +127,14 @@ work on emulator (disassembly and single-stepping)
10.12.2020
unit testing framework and first unit tests
+till 31.12.2020
+baby steps in testing
+via 6522
+handle timing/cycles properly
+
+2.1.2021
+work on via and interrupts
+
commands
--------
diff --git a/doc/6502.org_ Tutorials and Aids.html b/doc/6502.org_ Tutorials and Aids.html
new file mode 100644
index 0000000..f9a597f
--- /dev/null
+++ b/doc/6502.org_ Tutorials and Aids.html
@@ -0,0 +1,635 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!-- saved from url=(0046)http://www.6502.org/tutorials/6502opcodes.html -->
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>6502.org: Tutorials and Aids</title>
+<meta name="description" content="Learn how to do all kinds of things with the 6502 microprocessor.">
+
+</head>
+<body>
+<a href="http://www.6502.org/">[Return to Main Page]</a>
+<font size="+1">NMOS 6502 Opcodes</font>&nbsp;<font size="-1">by John Pickens,
+Updated by Bruce Clark and by Ed Spittles</font>
+<br><a href="http://www.6502.org/tutorials/tutorials.htm">[Up to Tutorials and Aids]</a>
+<br>
+<hr>
+<h2>INDEX</h2>
+<table border="2" cellpadding="2" width="90%" style="font-family:&#39;Lucida Console&#39;, monospace">
+ <tbody>
+ <tr>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BRA">Branches</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#DFLAG">Decimal Mode</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#IFLAG">Interrupt Flag</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#VFLAG">Overflow Flag</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#PC">Program
+ Counter</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#STACK">Stack</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TIMES">Times</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#WRAP">Wrap-around</a></td></tr></tbody></table>
+<p>
+</p><table border="2" cellpadding="2" width="90%">
+ <tbody>
+ <tr>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#ADC">ADC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#AND">AND</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#ASL">ASL</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BCC">BCC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BCS">BCS</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BEQ">BEQ</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BIT">BIT</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BMI">BMI</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BNE">BNE</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BPL">BPL</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BRK">BRK</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BVC">BVC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#BVS">BVS</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CLC">CLC</a></td></tr>
+ <tr>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CLD">CLD</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CLI">CLI</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CLV">CLV</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CMP">CMP</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CPX">CPX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#CPY">CPY</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#DEC">DEC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#DEX">DEX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#DEY">DEY</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#EOR">EOR</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#INC">INC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#INX">INX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#INY">INY</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#JMP">JMP</a></td></tr>
+ <tr>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#JSR">JSR</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#LDA">LDA</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#LDX">LDX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#LDY">LDY</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#LSR">LSR</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#NOP">NOP</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#ORA">ORA</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#PHA">PHA</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#PHP">PHP</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#PLA">PLA</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#PLP">PLP</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#ROL">ROL</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#ROR">ROR</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#RTI">RTI</a></td></tr>
+ <tr>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#RTS">RTS</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#SBC">SBC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#SEC">SEC</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#SED">SED</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#SEI">SEI</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#STA">STA</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#STX">STX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#STY">STY</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TAX">TAX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TAY">TAY</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TSX">TSX</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TXA">TXA</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TXS">TXS</a></td>
+ <td align="center"><a href="http://www.6502.org/tutorials/6502opcodes.html#TYA">TYA</a></td></tr></tbody></table>
+<p><a name="ADC">&nbsp;</a>
+</p><h2>ADC (ADd with Carry)</h2>
+<p>Affects Flags: N V Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate ADC #$44 $69 2 2
+Zero Page ADC $44 $65 2 3
+Zero Page,X ADC $44,X $75 2 4
+Absolute ADC $4400 $6D 3 4
+Absolute,X ADC $4400,X $7D 3 4+
+Absolute,Y ADC $4400,Y $79 3 4+
+Indirect,X ADC ($44,X) $61 2 6
+Indirect,Y ADC ($44),Y $71 2 5+
+
++ add 1 cycle if page boundary crossed
+
+</pre>ADC results are dependant on the setting of the <a href="http://www.6502.org/tutorials/6502opcodes.html#DFLAG">decimal flag</a>. In decimal
+mode, addition is carried out on the assumption that the values involved are
+packed BCD (Binary Coded Decimal).
+<p>There is no way to add without carry.
+
+</p><p><a name="AND">&nbsp;</a>
+</p><h2>AND (bitwise AND with accumulator) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate AND #$44 $29 2 2
+Zero Page AND $44 $25 2 3
+Zero Page,X AND $44,X $35 2 4
+Absolute AND $4400 $2D 3 4
+Absolute,X AND $4400,X $3D 3 4+
+Absolute,Y AND $4400,Y $39 3 4+
+Indirect,X AND ($44,X) $21 2 6
+Indirect,Y AND ($44),Y $31 2 5+
+
++ add 1 cycle if page boundary crossed
+</pre>
+
+<p><a name="ASL">&nbsp;</a>
+</p><h2>ASL (Arithmetic Shift Left) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Accumulator ASL A $0A 1 2
+Zero Page ASL $44 $06 2 5
+Zero Page,X ASL $44,X $16 2 6
+Absolute ASL $4400 $0E 3 6
+Absolute,X ASL $4400,X $1E 3 7
+
+</pre>ASL shifts all bits left one position. 0 is shifted into bit 0 and the
+original bit 7 is shifted into the Carry.
+<p>
+</p><p><a name="BIT">&nbsp;</a>
+</p><h2>BIT (test BITs) </h2>
+<p>Affects Flags: N V Z </p><pre>MODE SYNTAX HEX LEN TIM
+Zero Page BIT $44 $24 2 3
+Absolute BIT $4400 $2C 3 4
+
+</pre>BIT sets the Z flag as though the value in the address tested were ANDed
+with the accumulator. The N and V flags are set to match bits 7 and 6
+respectively in the value stored at the tested address.
+<p>BIT is often used to skip one or two following bytes as in:
+</p><p></p><pre>CLOSE1 LDX #$10 If entered here, we
+ .BYTE $2C effectively perform
+CLOSE2 LDX #$20 a BIT test on $20A2,
+ .BYTE $2C another one on $30A2,
+CLOSE3 LDX #$30 and end up with the X
+CLOSEX LDA #12 register still at $10
+ STA ICCOM,X upon arrival here.
+
+</pre>
+Beware: a BIT instruction used in this way as a NOP does have effects: the flags
+may be modified, and the read of the absolute address, if it happens to access an
+I/O device, may cause an unwanted action.
+<p><a name="BCC">&nbsp;</a> <a name="BCS">&nbsp;</a> <a name="BEQ">&nbsp;</a> <a name="BNE">&nbsp;</a> <a name="BMI">&nbsp;</a> <a name="BPL">&nbsp;</a> <a name="BVC">&nbsp;</a> <a name="BVS">&nbsp;</a> <a name="BRA">&nbsp;</a>
+</p><h2>Branch Instructions</h2>
+<p>Affect Flags: none
+</p><p>All branches are relative mode and have a length of two bytes. Syntax is "Bxx
+Displacement" or (better) "Bxx Label". See the notes on the <a href="http://www.6502.org/tutorials/6502opcodes.html#PC">Program Counter</a> for more on
+displacements.
+</p><p>Branches are dependant on the status of the flag bits when the op code is
+encountered. A branch not taken requires two machine cycles. Add one if the
+branch is taken and add one more if the branch crosses a page boundary. </p><pre>MNEMONIC HEX
+BPL (Branch on PLus) $10
+BMI (Branch on MInus) $30
+BVC (Branch on oVerflow Clear) $50
+BVS (Branch on oVerflow Set) $70
+BCC (Branch on Carry Clear) $90
+BCS (Branch on Carry Set) $B0
+BNE (Branch on Not Equal) $D0
+BEQ (Branch on EQual) $F0
+
+</pre>There is no BRA (BRanch Always) instruction but it can be easily emulated
+by branching on the basis of a known condition. One of the best flags to use for
+this purpose is the <a href="http://www.6502.org/tutorials/6502opcodes.html#VFLAG">oVerflow</a> which is unchanged
+by all but addition and subtraction operations.
+<p>
+A page boundary crossing occurs when the branch destination is on a different
+page than the instruction AFTER the branch instruction. For example:
+</p><pre> SEC
+ BCS LABEL
+ NOP
+</pre>
+A page boundary crossing occurs (i.e. the BCS takes 4 cycles) when (the
+address of) LABEL and the NOP are on different pages. This means that
+<pre> CLV
+ BVC LABEL
+ LABEL NOP
+</pre>
+the BVC instruction will take 3 cycles no matter what address it is located
+at.
+<p>
+</p><p><a name="BRK">&nbsp;</a>
+</p><h2>BRK (BReaK) </h2>
+<p>Affects Flags: B </p><pre>MODE SYNTAX HEX LEN TIM
+Implied BRK $00 1 7
+
+</pre>BRK causes a non-maskable interrupt and increments the program counter by
+one. Therefore an <a href="http://www.6502.org/tutorials/6502opcodes.html#RTI">RTI</a> will
+go to the address of the BRK +2 so that BRK may be used to replace a
+two-byte instruction for debugging and the subsequent RTI will be correct.
+<p>
+</p><p><a name="CMP">&nbsp;</a>
+</p><h2>CMP (CoMPare accumulator) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate CMP #$44 $C9 2 2
+Zero Page CMP $44 $C5 2 3
+Zero Page,X CMP $44,X $D5 2 4
+Absolute CMP $4400 $CD 3 4
+Absolute,X CMP $4400,X $DD 3 4+
+Absolute,Y CMP $4400,Y $D9 3 4+
+Indirect,X CMP ($44,X) $C1 2 6
+Indirect,Y CMP ($44),Y $D1 2 5+
+
++ add 1 cycle if page boundary crossed
+
+</pre>Compare sets flags as if a subtraction had been carried out. If the value
+in the accumulator is equal or greater than the compared value, the Carry will
+be set. The equal (Z) and negative (N) flags will be set based on equality or lack
+thereof and the sign (i.e. A&gt;=$80) of the accumulator.
+<p>
+</p><p><a name="CPX">&nbsp;</a>
+</p><h2>CPX (ComPare X register) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate CPX #$44 $E0 2 2
+Zero Page CPX $44 $E4 2 3
+Absolute CPX $4400 $EC 3 4
+
+</pre>Operation and flag results are identical to equivalent mode accumulator <a href="http://www.6502.org/tutorials/6502opcodes.html#CMP">CMP</a> ops.
+<p>
+</p><p><a name="CPY">&nbsp;</a>
+</p><h2>CPY (ComPare Y register) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate CPY #$44 $C0 2 2
+Zero Page CPY $44 $C4 2 3
+Absolute CPY $4400 $CC 3 4
+
+</pre>Operation and flag results are identical to equivalent mode accumulator <a href="http://www.6502.org/tutorials/6502opcodes.html#CMP">CMP</a> ops.
+<p>
+</p><p><a name="DEC">&nbsp;</a>
+</p><h2>DEC (DECrement memory) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Zero Page DEC $44 $C6 2 5
+Zero Page,X DEC $44,X $D6 2 6
+Absolute DEC $4400 $CE 3 6
+Absolute,X DEC $4400,X $DE 3 7
+
+</pre>
+<p><a name="EOR">&nbsp;</a>
+</p><h2>EOR (bitwise Exclusive OR) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate EOR #$44 $49 2 2
+Zero Page EOR $44 $45 2 3
+Zero Page,X EOR $44,X $55 2 4
+Absolute EOR $4400 $4D 3 4
+Absolute,X EOR $4400,X $5D 3 4+
+Absolute,Y EOR $4400,Y $59 3 4+
+Indirect,X EOR ($44,X) $41 2 6
+Indirect,Y EOR ($44),Y $51 2 5+
+
++ add 1 cycle if page boundary crossed
+</pre>
+<p><a name="CLC">&nbsp;</a> <a name="SEC">&nbsp;</a> <a name="CLD">&nbsp;</a> <a name="SED">&nbsp;</a> <a name="CLI">&nbsp;</a> <a name="SEI">&nbsp;</a> <a name="CLV">&nbsp;</a>
+</p><h2>Flag (Processor Status) Instructions</h2>
+<p>Affect Flags: as noted
+</p><p>These instructions are implied mode, have a length of one byte and require
+two machine cycles. </p><pre>MNEMONIC HEX
+CLC (CLear Carry) $18
+SEC (SEt Carry) $38
+CLI (CLear Interrupt) $58
+SEI (SEt Interrupt) $78
+CLV (CLear oVerflow) $B8
+CLD (CLear Decimal) $D8
+SED (SEt Decimal) $F8
+
+</pre>Notes:
+<p><a name="IFLAG">&nbsp;</a> The Interrupt flag is used to prevent (SEI) or
+enable (CLI) maskable interrupts (aka IRQ's). It does not signal the presence or
+absence of an interrupt condition. The 6502 will set this flag automatically in
+response to an interrupt and restore it to its prior status on completion of the
+interrupt service routine. If you want your interrupt service routine to permit
+other maskable interrupts, you must clear the I flag in your code.
+</p><p><a name="DFLAG">&nbsp;</a> The Decimal flag controls how the 6502 adds and
+subtracts. If set, arithmetic is carried out in packed binary coded decimal.
+This flag is unchanged by interrupts and is unknown on power-up. The implication
+is that a CLD should be included in boot or interrupt coding.
+</p><p><a name="VFLAG">&nbsp;</a> The Overflow flag is generally misunderstood and
+therefore under-utilised. After an ADC or SBC instruction, the overflow flag
+will be set if the twos complement result is less than -128 or greater than
++127, and it will cleared otherwise. In twos complement, $80 through $FF
+represents -128 through -1, and $00 through $7F represents 0 through +127.
+Thus, after:
+</p><pre> CLC
+ LDA #$7F ; +127
+ ADC #$01 ; + +1
+</pre>
+the overflow flag is 1 (+127 + +1 = +128), and after:
+<pre> CLC
+ LDA #$81 ; -127
+ ADC #$FF ; + -1
+</pre>
+the overflow flag is 0 (-127 + -1 = -128). The overflow flag is not
+affected by increments, decrements, shifts and logical operations i.e. only
+ADC, BIT, CLV, PLP, RTI and SBC affect it. There is no op code to set the
+overflow but a BIT test on an RTS instruction will do the trick.
+<p>
+</p><p>
+</p><p><a name="INC">&nbsp;</a>
+</p><h2>INC (INCrement memory) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Zero Page INC $44 $E6 2 5
+Zero Page,X INC $44,X $F6 2 6
+Absolute INC $4400 $EE 3 6
+Absolute,X INC $4400,X $FE 3 7
+</pre>
+<p>
+</p><p>
+</p><p><a name="JMP">&nbsp;</a>
+</p><h2>JMP (JuMP) </h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Absolute JMP $5597 $4C 3 3
+Indirect JMP ($5597) $6C 3 5
+
+</pre>JMP transfers program execution to the following address (absolute) or to
+the location contained in the following address (indirect). Note that there is
+no carry associated with the indirect jump so: <pre><strong>AN INDIRECT JUMP MUST NEVER USE A
+VECTOR BEGINNING ON THE LAST BYTE
+OF A PAGE</strong>
+</pre>For example if address $3000 contains $40, $30FF contains $80, and $3100
+contains $50, the result of JMP ($30FF) will be a transfer of control to $4080
+rather than $5080 as you intended i.e. the 6502 took the low byte of the address
+from $30FF and the high byte from $3000.
+<p>
+</p><p>
+</p><p><a name="JSR">&nbsp;</a>
+</p><h2>JSR (Jump to SubRoutine) </h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Absolute JSR $5597 $20 3 6
+
+</pre>JSR pushes the address-1 of the next operation on to the stack before
+transferring program control to the following address. Subroutines are normally
+terminated by a <a href="http://www.6502.org/tutorials/6502opcodes.html#RTS">RTS</a> op
+code.
+<p>
+</p><p>
+</p><p><a name="LDA">&nbsp;</a>
+</p><h2>LDA (LoaD Accumulator) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate LDA #$44 $A9 2 2
+Zero Page LDA $44 $A5 2 3
+Zero Page,X LDA $44,X $B5 2 4
+Absolute LDA $4400 $AD 3 4
+Absolute,X LDA $4400,X $BD 3 4+
+Absolute,Y LDA $4400,Y $B9 3 4+
+Indirect,X LDA ($44,X) $A1 2 6
+Indirect,Y LDA ($44),Y $B1 2 5+
+
++ add 1 cycle if page boundary crossed
+</pre>
+<p>
+</p><p>
+</p><p><a name="LDX">&nbsp;</a>
+</p><h2>LDX (LoaD X register) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate LDX #$44 $A2 2 2
+Zero Page LDX $44 $A6 2 3
+Zero Page,Y LDX $44,Y $B6 2 4
+Absolute LDX $4400 $AE 3 4
+Absolute,Y LDX $4400,Y $BE 3 4+
+
++ add 1 cycle if page boundary crossed
+</pre>
+<p>
+</p><p>
+</p><p><a name="LDY">&nbsp;</a>
+</p><h2>LDY (LoaD Y register) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate LDY #$44 $A0 2 2
+Zero Page LDY $44 $A4 2 3
+Zero Page,X LDY $44,X $B4 2 4
+Absolute LDY $4400 $AC 3 4
+Absolute,X LDY $4400,X $BC 3 4+
+
++ add 1 cycle if page boundary crossed
+</pre>
+<p>
+</p><p>
+</p><p><a name="LSR">&nbsp;</a>
+</p><h2>LSR (Logical Shift Right) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Accumulator LSR A $4A 1 2
+Zero Page LSR $44 $46 2 5
+Zero Page,X LSR $44,X $56 2 6
+Absolute LSR $4400 $4E 3 6
+Absolute,X LSR $4400,X $5E 3 7
+
+</pre>LSR shifts all bits right one position. 0 is shifted into bit 7 and the
+original bit 0 is shifted into the Carry.
+<p>
+</p><p>
+</p><p><a name="WRAP">&nbsp;</a>
+</p><h2>Wrap-Around</h2>
+<p>Use caution with indexed zero page operations as they are subject to
+wrap-around. For example, if the X register holds $FF and you execute LDA $80,X
+you will not access $017F as you might expect; instead you access $7F i.e.
+$80-1. This characteristic can be used to advantage but make sure your code is
+well commented.
+</p><p>
+It is possible, however, to access $017F when X = $FF by using the Absolute,X
+addressing mode of LDA $80,X. That is, instead of:
+</p><pre> LDA $80,X ; ZeroPage,X - the resulting object code is: B5 80
+</pre>
+which accesses $007F when X=$FF, use:
+<pre> LDA $0080,X ; Absolute,X - the resulting object code is: BD 80 00
+</pre>
+which accesses $017F when X = $FF (a at cost of one additional byte and one
+additional cycle). All of the ZeroPage,X and ZeroPage,Y instructions except
+STX ZeroPage,Y and STY ZeroPage,X have a corresponding Absolute,X and
+Absolute,Y instruction. Unfortunately, a lot of 6502 assemblers don't have an
+easy way to force Absolute addressing, i.e. most will assemble a LDA $0080,X
+as B5 80. One way to overcome this is to insert the bytes using the .BYTE
+pseudo-op (on some 6502 assemblers this pseudo-op is called DB or DFB,
+consult the assembler documentation) as follows:
+<pre> .BYTE $BD,$80,$00 ; LDA $0080,X (absolute,X addressing mode)
+</pre>
+The comment is optional, but highly recommended for clarity.
+<p>In cases where you are writing code that will be relocated you must consider
+wrap-around when assigning dummy values for addresses that will be adjusted.
+Both zero and the semi-standard $FFFF should be avoided for dummy labels. The
+use of zero or zero page values will result in assembled code with zero page
+opcodes when you wanted absolute codes. With $FFFF, the problem is in
+addresses+1 as you wrap around to page 0.
+</p><p><a name="PC">&nbsp;</a>
+</p><h2>Program Counter</h2>
+<p>When the 6502 is ready for the next instruction it increments the program
+counter before fetching the instruction. Once it has the op code, it increments
+the program counter by the length of the operand, if any. This must be accounted
+for when calculating branches or when pushing bytes to create a false return
+address (i.e. jump table addresses are made up of addresses-1 when it is
+intended to use an RTS rather than a JMP).
+</p><p>The program counter is loaded least signifigant byte first. Therefore the
+most signifigant byte must be pushed first when creating a false return address.
+
+</p><p>When calculating branches a forward branch of 6 skips the following 6 bytes
+so, effectively the program counter points to the address that is 8 bytes beyond
+the address of the branch opcode; and a backward branch of $FA (256-6) goes to
+an address 4 bytes before the branch instruction.
+</p><p><a name="TIMES">&nbsp;</a>
+</p><h2>Execution Times</h2>
+<p>Op code execution times are measured in machine cycles; one machine cycle
+equals one clock cycle. Many instructions require one extra cycle for
+execution if a page boundary is crossed; these are indicated by a + following
+the time values shown.
+</p><p>
+</p><p>
+</p><p><a name="NOP">&nbsp;</a>
+</p><h2>NOP (No OPeration) </h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Implied NOP $EA 1 2
+
+</pre>NOP is used to reserve space for future modifications or effectively REM
+out existing code.
+<p>
+</p><p>
+</p><p><a name="ORA">&nbsp;</a>
+</p><h2>ORA (bitwise OR with Accumulator) </h2>
+<p>Affects Flags: N Z </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate ORA #$44 $09 2 2
+Zero Page ORA $44 $05 2 3
+Zero Page,X ORA $44,X $15 2 4
+Absolute ORA $4400 $0D 3 4
+Absolute,X ORA $4400,X $1D 3 4+
+Absolute,Y ORA $4400,Y $19 3 4+
+Indirect,X ORA ($44,X) $01 2 6
+Indirect,Y ORA ($44),Y $11 2 5+
+
++ add 1 cycle if page boundary crossed
+</pre>
+<p>
+</p><p>
+</p><p><a name="TAX">&nbsp;</a> <a name="TXA">&nbsp;</a> <a name="TAY">&nbsp;</a> <a name="TYA">&nbsp;</a> <a name="INX">&nbsp;</a> <a name="DEX">&nbsp;</a> <a name="INY">&nbsp;</a> <a name="DEY">&nbsp;</a>
+</p><h2>Register Instructions </h2>
+<p>Affect Flags: N Z
+</p><p>These instructions are implied mode, have a length of one byte and require
+two machine cycles. </p><pre>MNEMONIC HEX
+TAX (Transfer A to X) $AA
+TXA (Transfer X to A) $8A
+DEX (DEcrement X) $CA
+INX (INcrement X) $E8
+TAY (Transfer A to Y) $A8
+TYA (Transfer Y to A) $98
+DEY (DEcrement Y) $88
+INY (INcrement Y) $C8
+</pre>
+<p>
+</p><p>
+</p><p><a name="ROL">&nbsp;</a>
+</p><h2>ROL (ROtate Left) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Accumulator ROL A $2A 1 2
+Zero Page ROL $44 $26 2 5
+Zero Page,X ROL $44,X $36 2 6
+Absolute ROL $4400 $2E 3 6
+Absolute,X ROL $4400,X $3E 3 7
+
+</pre>ROL shifts all bits left one position. The Carry is shifted into bit 0 and
+the original bit 7 is shifted into the Carry.
+<p>
+</p><p>
+</p><p><a name="ROR">&nbsp;</a>
+</p><h2>ROR (ROtate Right) </h2>
+<p>Affects Flags: N Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Accumulator ROR A $6A 1 2
+Zero Page ROR $44 $66 2 5
+Zero Page,X ROR $44,X $76 2 6
+Absolute ROR $4400 $6E 3 6
+Absolute,X ROR $4400,X $7E 3 7
+
+</pre>ROR shifts all bits right one position. The Carry is shifted into bit 7
+and the original bit 0 is shifted into the Carry.
+<p>
+</p><p>
+</p><p><a name="RTI">&nbsp;</a>
+</p><h2>RTI (ReTurn from Interrupt) </h2>
+<p>Affects Flags: all </p><pre>MODE SYNTAX HEX LEN TIM
+Implied RTI $40 1 6
+
+</pre>RTI retrieves the Processor Status Word (flags) and the Program Counter
+from the stack in that order (interrupts push the PC first and then the PSW).
+<p>Note that unlike RTS, the return address on the stack is the actual address
+rather than the address-1.
+</p><p>
+</p><p>
+</p><p><a name="RTS">&nbsp;</a>
+</p><h2>RTS (ReTurn from Subroutine) </h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Implied RTS $60 1 6
+
+</pre>RTS pulls the top two bytes off the stack (low byte first) and transfers
+program control to that address+1. It is used, as expected, to exit a subroutine
+invoked via <a href="http://www.6502.org/tutorials/6502opcodes.html#JSR">JSR</a> which
+pushed the address-1.
+<p>RTS is frequently used to implement a jump table where addresses-1 are pushed
+onto the stack and accessed via RTS eg. to access the second of four routines: </p><pre> LDX #1
+ JSR EXEC
+ JMP SOMEWHERE
+
+LOBYTE
+ .BYTE &lt;ROUTINE0-1,&lt;ROUTINE1-1
+ .BYTE &lt;ROUTINE2-1,&lt;ROUTINE3-1
+
+HIBYTE
+ .BYTE &gt;ROUTINE0-1,&gt;ROUTINE1-1
+ .BYTE &gt;ROUTINE2-1,&gt;ROUTINE3-1
+
+EXEC
+ LDA HIBYTE,X
+ PHA
+ LDA LOBYTE,X
+ PHA
+ RTS
+</pre>
+<p>
+</p><p><a name="SBC">&nbsp;</a>
+</p><h2>SBC (SuBtract with Carry)</h2>
+<p>Affects Flags: N V Z C </p><pre>MODE SYNTAX HEX LEN TIM
+Immediate SBC #$44 $E9 2 2
+Zero Page SBC $44 $E5 2 3
+Zero Page,X SBC $44,X $F5 2 4
+Absolute SBC $4400 $ED 3 4
+Absolute,X SBC $4400,X $FD 3 4+
+Absolute,Y SBC $4400,Y $F9 3 4+
+Indirect,X SBC ($44,X) $E1 2 6
+Indirect,Y SBC ($44),Y $F1 2 5+
+
++ add 1 cycle if page boundary crossed
+
+</pre>SBC results are dependant on the setting of the decimal flag. In decimal
+mode, subtraction is carried out on the assumption that the values involved are
+packed BCD (Binary Coded Decimal).
+<p>There is no way to subtract without the carry which works as an inverse
+borrow. i.e, to subtract you set the carry before the operation. If the carry is
+cleared by the operation, it indicates a borrow occurred.
+</p><p>
+</p><p>
+</p><p><a name="STA">&nbsp;</a>
+</p><h2>STA (STore Accumulator) </h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Zero Page STA $44 $85 2 3
+Zero Page,X STA $44,X $95 2 4
+Absolute STA $4400 $8D 3 4
+Absolute,X STA $4400,X $9D 3 5
+Absolute,Y STA $4400,Y $99 3 5
+Indirect,X STA ($44,X) $81 2 6
+Indirect,Y STA ($44),Y $91 2 6
+</pre>
+<p>
+</p><p><a name="TXS">&nbsp;</a> <a name="TSX">&nbsp;</a> <a name="PHA">&nbsp;</a> <a name="PLA">&nbsp;</a> <a name="PHP">&nbsp;</a> <a name="PLP">&nbsp;</a> <a name="STACK">&nbsp;</a>
+</p><h2>Stack Instructions</h2>
+<p>These instructions are implied mode, have a length of one byte and require
+machine cycles as indicated. The "PuLl" operations are known as "POP" on most
+other microprocessors. With the 6502, the stack is always on page one
+($100-$1FF) and works top down. </p><pre>MNEMONIC HEX TIM
+TXS (Transfer X to Stack ptr) $9A 2
+TSX (Transfer Stack ptr to X) $BA 2
+PHA (PusH Accumulator) $48 3
+PLA (PuLl Accumulator) $68 4
+PHP (PusH Processor status) $08 3
+PLP (PuLl Processor status) $28 4
+</pre>
+<p>
+</p><p>
+</p><p><a name="STX">&nbsp;</a>
+</p><h2>STX (STore X register)</h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Zero Page STX $44 $86 2 3
+Zero Page,Y STX $44,Y $96 2 4
+Absolute STX $4400 $8E 3 4
+</pre>
+<p>
+</p><p>
+</p><p><a name="STY">&nbsp;</a>
+</p><h2>STY (STore Y register)</h2>
+<p>Affects Flags: none </p><pre>MODE SYNTAX HEX LEN TIM
+Zero Page STY $44 $84 2 3
+Zero Page,X STY $44,X $94 2 4
+Absolute STY $4400 $8C 3 4
+</pre>
+<p>
+</p><p><font size="-1">Last Updated Oct 17, 2020.</font>
+
+</p></body></html> \ No newline at end of file
diff --git a/emu/6502.c b/emu/6502.c
index 98af83a..77ea952 100644
--- a/emu/6502.c
+++ b/emu/6502.c
@@ -168,17 +168,17 @@ bool cpu_6502_is_carry( cpu_6502_t *cpu )
static const int cycles[NOF_OPCODES] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 2 */ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ /* 2 */ 6, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0,
/* 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,
- /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
/* 6 */ 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 8 */ 0, 0, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 0, 0, 4, 0,
+ /* 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 3, 3, 0, 2, 0, 0, 0, 0, 4, 4, 0,
/* 9 */ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
- /* A */ 2, 0, 2, 0, 3, 3, 3, 0, 0, 2, 0, 0, 0, 0, 0, 0,
+ /* A */ 2, 0, 2, 0, 3, 3, 3, 0, 0, 2, 0, 0, 0, 4, 0, 0,
/* B */ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* C */ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0,
/* D */ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -188,17 +188,17 @@ static const int cycles[NOF_OPCODES] = {
static const char mnemonic[NOF_OPCODES][MAX_MENMONIC_LENGTH] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- /* 0 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
+ /* 0 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "ORA", "???", "???", "???", "???", "???", "???",
/* 1 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
- /* 2 */ "JSR", "???", "???", "???", "???", "???", "???", "???", "???", "???", "ROL", "???", "???", "???", "???", "???",
+ /* 2 */ "JSR", "???", "???", "???", "???", "???", "???", "???", "???", "AND", "ROL", "???", "???", "???", "???", "???",
/* 3 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
/* 4 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "JMP", "???", "???", "???",
- /* 5 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
+ /* 5 */ "???", "???", "???", "???", "???", "???", "???", "???", "CLI", "???", "???", "???", "???", "???", "???", "???",
/* 6 */ "RTS", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
- /* 7 */ "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
- /* 8 */ "???", "???", "???", "???", "???", "???", "STX", "???", "DEY", "???", "???", "???", "???", "???", "STX", "???",
+ /* 7 */ "???", "???", "???", "???", "???", "???", "???", "???", "SEI", "???", "???", "???", "???", "???", "???", "???",
+ /* 8 */ "???", "???", "???", "???", "???", "STA", "STX", "???", "DEY", "???", "???", "???", "???", "STA", "STX", "???",
/* 9 */ "BCC", "???", "???", "???", "???", "???", "???", "???", "???", "???", "TXS", "???", "???", "???", "???", "???",
- /* A */ "LDY", "???", "LDX", "???", "LDY", "LDA", "LDX", "???", "???", "LDA", "???", "???", "???", "???", "???", "???",
+ /* A */ "LDY", "???", "LDX", "???", "LDY", "LDA", "LDX", "???", "???", "LDA", "???", "???", "???", "STA", "???", "???",
/* B */ "BCS", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
/* C */ "???", "???", "???", "???", "???", "???", "???", "???", "INY", "???", "DEX", "???", "???", "???", "???", "???",
/* D */ "BNE", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???", "???",
@@ -345,6 +345,13 @@ void cpu_6502_step( cpu_6502_t *cpu )
update_negative_and_sign( cpu, cpu->A );
break;
+ case LDA_ABS:
+ operand16 = cpu_6502_read_word( cpu, cpu->PC );
+ cpu->PC += 2;
+ cpu->A = cpu_6502_read_byte( cpu, operand16 );
+ update_negative_and_sign( cpu, cpu->A );
+ break;
+
case STX_ZERO:
operand8 = cpu_6502_read_byte( cpu, cpu->PC );
cpu->PC++;
@@ -356,7 +363,19 @@ void cpu_6502_step( cpu_6502_t *cpu )
cpu->PC += 2;
cpu_6502_write_byte( cpu, operand16, cpu->X );
break;
-
+
+ case STA_ZERO:
+ operand8 = cpu_6502_read_byte( cpu, cpu->PC );
+ cpu->PC++;
+ cpu_6502_write_byte( cpu, operand8, cpu->A );
+ break;
+
+ case STA_ABS:
+ operand16 = cpu_6502_read_word( cpu, cpu->PC );
+ cpu->PC += 2;
+ cpu_6502_write_byte( cpu, operand16, cpu->A );
+ break;
+
case DEX_IMPL:
cpu->X--;
update_negative_and_sign( cpu, cpu->X );
@@ -391,6 +410,20 @@ void cpu_6502_step( cpu_6502_t *cpu )
cpu->A = tmp & 0xFF;
update_negative_and_sign( cpu, cpu->A );
break;
+
+ case AND_IMM:
+ operand8 = cpu_6502_read_byte( cpu, cpu->PC );
+ cpu->PC++;
+ cpu->A &= operand8;
+ update_negative_and_sign( cpu, cpu->A );
+ break;
+
+ case OR_IMM:
+ operand8 = cpu_6502_read_byte( cpu, cpu->PC );
+ cpu->PC++;
+ cpu->A |= operand8;
+ update_negative_and_sign( cpu, cpu->A );
+ break;
case CPX_IMM:
operand8 = cpu_6502_read_byte( cpu, cpu->PC );
@@ -463,6 +496,14 @@ void cpu_6502_step( cpu_6502_t *cpu )
cpu->PC++;
break;
+ case CLI_IMPL:
+ cpu->PS &= ~PS_I;
+ break;
+
+ case SEI_IMPL:
+ cpu->PS |= PS_I;
+ break;
+
case TXS_IMPL:
cpu->SP = cpu->X;
break;
diff --git a/emu/6502.h b/emu/6502.h
index c462fcc..a34443f 100644
--- a/emu/6502.h
+++ b/emu/6502.h
@@ -51,29 +51,36 @@ enum {
// opcodes
enum {
- LDX_IMM = 0xA2,
- LDX_ZERO = 0xA6,
- LDY_IMM = 0xA0,
- LDY_ZERO = 0xA4,
- LDA_IMM = 0xA9,
- LDA_ZERO = 0xA5,
+ LDX_IMM = 0xa2,
+ LDX_ZERO = 0xa6,
+ LDY_IMM = 0xa0,
+ LDY_ZERO = 0xa4,
+ LDA_IMM = 0xa9,
+ LDA_ZERO = 0xa5,
+ LDA_ABS = 0xad,
STX_ZERO = 0x86,
- STX_ABS = 0x8E,
- DEX_IMPL = 0xCA,
+ STX_ABS = 0x8e,
+ STA_ZERO = 0x85,
+ STA_ABS = 0x8d,
+ DEX_IMPL = 0xca,
DEY_IMPL = 0x88,
- INY_IMPL = 0xC8,
- INC_ZERO = 0xE6,
- ROL_ACC = 0x2A,
- BNE_REL = 0xD0,
+ INY_IMPL = 0xc8,
+ INC_ZERO = 0xe6,
+ ROL_ACC = 0x2a,
+ AND_IMM = 0x29,
+ OR_IMM = 0x09,
+ BNE_REL = 0xd0,
BCC_REL = 0x90,
- BCS_REL = 0xB0,
- JMP_ABS = 0x4C,
+ BCS_REL = 0xb0,
+ JMP_ABS = 0x4c,
JSR_ABS = 0x20,
RTS_IMPL = 0x60,
- TXS_IMPL = 0x9A,
- CPX_IMM = 0xE0,
- SBC_IMM = 0xE9,
- NOP_IMPL = 0xEA
+ CLI_IMPL = 0x58,
+ SEI_IMPL = 0x78,
+ TXS_IMPL = 0x9a,
+ CPX_IMM = 0xe0,
+ SBC_IMM = 0xe9,
+ NOP_IMPL = 0xea
};
enum {
diff --git a/emu/6522.c b/emu/6522.c
index df9144d..7cde206 100644
--- a/emu/6522.c
+++ b/emu/6522.c
@@ -22,14 +22,37 @@ void via_6522_init( via_6522_t *via, uint16_t addr, bool initialize )
if( initialize ) {
via->ddra = 0x00;
+ via->ddrb = 0x00;
+ via->pcr = 0x00;
+ via->ier = 0x00;
}
- bus_init( &via->bus );
+ bus_init( &via->busa );
+ bus_init( &via->busb );
}
-void via_6522_register( via_6522_t *via, device_t *device )
+void via_6522_reset( via_6522_t *via )
{
- bus_register( &via->bus, device, 0, 0 );
+ via->ddra = 0x00;
+ via->ddrb = 0x00;
+ via->pcr = 0x00;
+ via->ier = 0x00;
+}
+
+void via_6522_register( via_6522_t *via, int bus, device_t *device )
+{
+ switch( bus ) {
+ case PORTA:
+ bus_register( &via->busa, device, 0, 0 );
+ break;
+
+ case PORTB:
+ bus_register( &via->busb, device, 0, 0 );
+ break;
+
+ default:
+ fprintf( stderr, "ERROR: unable to register to VIA 6522 bus, use PORTA or PORTB\n" );
+ }
}
uint8_t via_6522_read( void *obj, uint16_t addr )
@@ -42,18 +65,38 @@ void via_6522_write( void *obj, uint16_t addr, uint8_t data )
via_6522_t *via = (via_6522_t *)obj;
switch( addr - via->addr ) {
- case DDRA:
- via->ddra = data;
- break;
-
case PORTA:
data &= via->ddra;
- for( int i = 0; i < via->bus.nof_devices; i++ ) {
- device_t *device = via->bus.devices[i].device;
+ for( int i = 0; i < via->busa.nof_devices; i++ ) {
+ device_t *device = via->busa.devices[i].device;
device->vtable->write( device, 0, data );
}
break;
+
+ case PORTB:
+ data &= via->ddrb;
+ for( int i = 0; i < via->busb.nof_devices; i++ ) {
+ device_t *device = via->busb.devices[i].device;
+ device->vtable->write( device, 0, data );
+ }
+ break;
+
+ case DDRB:
+ via->ddrb = data;
+ break;
+
+ case DDRA:
+ via->ddra = data;
+ break;
+ case PCR:
+ via->pcr = data;
+ break;
+
+ case IER:
+ via->ier = data;
+ break;
+
default:
fprintf( stderr, "ERROR: VIA 6522 not implemented address '%04X', data: '%02X'\n", addr, data );
break;
@@ -65,7 +108,8 @@ void via_6522_draw( void *obj, SDL_Renderer *renderer )
{
via_6522_t *via = (via_6522_t *)obj;
- via->bus.base.vtable->draw( &via->bus, renderer );
+ via->busa.base.vtable->draw( &via->busa, renderer );
+ via->busb.base.vtable->draw( &via->busb, renderer );
}
#endif
@@ -73,6 +117,8 @@ void via_6522_deinit( void *obj )
{
via_6522_t *via = (via_6522_t *)obj;
- bus_deinit( &via->bus );
+ bus_deinit( &via->busa );
+ bus_deinit( &via->busb );
+
device_deinit( &via->base );
}
diff --git a/emu/6522.h b/emu/6522.h
index 853bd3e..d3bade7 100644
--- a/emu/6522.h
+++ b/emu/6522.h
@@ -16,8 +16,16 @@
// the VIA is initialized with a base address, the addresses for
// the registers are relative to this base.
enum {
+ PORTB = 0x00,
PORTA = 0x01,
- DDRA = 0x03
+ DDRB = 0x02,
+ DDRA = 0x03,
+ T1LCL = 0x04,
+ T1LCH = 0x05,
+ ACR = 0x0b,
+ PCR = 0x0c,
+ IFR = 0x0d,
+ IER = 0x0e
};
typedef struct via_6522_t
@@ -27,14 +35,19 @@ typedef struct via_6522_t
uint16_t addr;
uint8_t ddra;
+ uint8_t ddrb;
+ uint8_t pcr;
+ uint8_t ier;
bool debug;
- bus_t bus;
+ bus_t busa;
+ bus_t busb;
} via_6522_t;
void via_6522_init( via_6522_t *via, uint16_t addr, bool initialize );
-void via_6522_register( via_6522_t *via, device_t *device );
+void via_6522_reset( via_6522_t *via );
+void via_6522_register( via_6522_t *via, int bus, device_t *device );
uint8_t via_6522_read( void *obj, uint16_t addr );
void via_6522_write( void *obj, uint16_t addr, uint8_t data );
diff --git a/emu/emu.c b/emu/emu.c
index 590f93e..b2293f9 100644
--- a/emu/emu.c
+++ b/emu/emu.c
@@ -53,7 +53,7 @@ int main( int argc, char *argv[] )
bus_register( &bus, &via.base, VIA_START, VIA_END );
seg7_init( &seg7, args_info.initialize_given );
- via_6522_register( &via, &seg7.base );
+ via_6522_register( &via, PORTA, &seg7.base );
cpu_6502_init( &cpu, &bus, args_info.initialize_given );
if( args_info.debug_given ) {
@@ -85,6 +85,7 @@ int main( int argc, char *argv[] )
emul_start( &emul );
cpu_6502_reset( &cpu );
+ via_6522_reset( &via );
emul_run( &emul, args_info.steps_arg );
diff --git a/emu/emul.c b/emu/emul.c
index ac4b64c..21ab58b 100644
--- a/emu/emul.c
+++ b/emu/emul.c
@@ -76,13 +76,14 @@ void emul_start( emul_t *emul )
static void print_help( void )
{
- fprintf( stderr, "CPU is paused, press\n"
+ fprintf( stderr, "Keyboard commands, press\n"
"(s) for single step\n"
"(f) fini (continue to next rts)\n"
"(c) for continue running\n"
"(b) break to single stepping\n"
"(+) speed up\n"
"(-) speed down\n"
+ "(p) push the button\n"
"(q) or (ESC) for shutting down\n" );
}
@@ -105,6 +106,9 @@ void emul_run( emul_t *emul, int nof_steps )
switch( event.type ) {
case SDL_KEYDOWN:
switch( event.key.keysym.sym ) {
+ case SDLK_h:
+ print_help( );
+ break;
case SDLK_ESCAPE:
case SDLK_q:
done = true;
@@ -138,6 +142,9 @@ void emul_run( emul_t *emul, int nof_steps )
}
fprintf( stderr, "CPU speed is %1.6f MHz now\n", ( (double)emul->speed / 1000000 ) );
break;
+ case SDLK_p:
+ // TODO:push the push button connected to CA1
+ break;
}
break;
@@ -153,10 +160,6 @@ void emul_run( emul_t *emul, int nof_steps )
SDL_RenderCopy( emul->renderer, emul->background_texture, NULL, NULL );
emul->bus->base.vtable->draw( emul->bus, emul->renderer );
- //~ for( int i = 0; i < emul->bus->nof_devices; i++ ) {
- //~ device_t *device = emul->bus->devices[i].device;
- //~ device->vtable->draw( device, emul->renderer );
- //~ }
SDL_RenderPresent( emul->renderer );
diff --git a/emu/tests/test_cpu_6502.c b/emu/tests/test_cpu_6502.c
index 94b68b4..2425be8 100644
--- a/emu/tests/test_cpu_6502.c
+++ b/emu/tests/test_cpu_6502.c
@@ -148,6 +148,68 @@ START_TEST( test_cpu_6502_txs )
}
END_TEST
+// CLI
+
+START_TEST( test_cpu_6502_cli )
+{
+ INIT_CPU_TEST
+
+ CODE_SET1( 0x58 ); // CLI
+
+ cpu.PS |= PS_I;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+1 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~PS_I, before_cpu.PS & ~PS_I );
+ ck_assert( !cpu_6502_is_interrupt( &cpu ) );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+// SEI
+
+START_TEST( test_cpu_6502_sei )
+{
+ INIT_CPU_TEST
+
+ CODE_SET1( 0x78 ); // SEI
+
+ cpu.PS &= ~PS_I;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+1 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~PS_I, before_cpu.PS & ~PS_I );
+ ck_assert( cpu_6502_is_interrupt( &cpu ) );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// LDA
START_TEST( test_cpu_6502_lda_flags_positive )
@@ -238,6 +300,37 @@ START_TEST( test_cpu_6502_lda_flags_zero )
}
END_TEST
+START_TEST( test_cpu_6502_lda_addr_abs )
+{
+ INIT_CPU_TEST
+
+ CODE_SET3( 0xad, 0x03, 0x01 ); // LDA #$0103
+
+ cpu.A = 0xff;
+ ram.cell[0x0103] = 0xea;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+3 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0xea );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 4 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// LDY
START_TEST( test_cpu_6502_ldy_flags_positive )
@@ -480,6 +573,68 @@ START_TEST( test_cpu_6502_stx_addr_abs )
}
END_TEST
+// STA
+
+START_TEST( test_cpu_6502_sta_addr_zero )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x85, 0x03 ); // STA $03
+
+ cpu.A = 0xea;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS, before_cpu.PS );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( &ram.cell[0x0], &before_ram.cell[0x0], 3 );
+ ck_assert_int_eq( ram.cell[0x03], 0xea );
+ ck_assert_mem_eq( &ram.cell[0x04], &before_ram.cell[0x04], 0x1FF - 0x03 );
+ ck_assert_int_eq( cpu.cycles, 3 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_sta_addr_abs )
+{
+ INIT_CPU_TEST
+
+ CODE_SET3( 0x8d, 0x03, 0x01 ); // STA #$0103
+
+ cpu.A = 0xea;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+3 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS, before_cpu.PS );
+ ck_assert_int_eq( cpu.A, before_cpu.A );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( &ram.cell[0x0], &before_ram.cell[0x0], 0x102 );
+ ck_assert_int_eq( ram.cell[0x0103], 0xea ); // modified value in memory
+ ck_assert_mem_eq( &ram.cell[0x104], &before_ram.cell[0x104], 0x1FF - 0x103 );
+ ck_assert_int_eq( cpu.cycles, 4 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// INC
START_TEST( test_cpu_6502_inc_flags_positive )
@@ -888,6 +1043,250 @@ START_TEST( test_cpu_6502_rol_flags_accumulator_carry )
}
END_TEST
+// AND
+
+START_TEST( test_cpu_6502_and_flags_positive )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0x0f ); // AND #$0f
+
+ cpu.A = 0x36;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x06 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_and_flags_negative )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0x8f ); // AND #$8f
+
+ cpu.A = 0xf6;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x86 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_and_flags_zero )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0x00 ); // AND #$00
+
+ cpu.A = 0xf6;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x00 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_and_addr_imm )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x29, 0xf0 ); // AND #$f0
+
+ cpu.A = 0xff;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0xf0 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+// ORA
+
+START_TEST( test_cpu_6502_ora_flags_positive )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x0f ); // ORA #$08
+
+ cpu.A = 0x37;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x3f );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_ora_flags_negative )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x22 ); // ORA #$22
+
+ cpu.A = 0x86;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0xa6 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_ora_flags_zero )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x00 ); // ORA #$00
+
+ cpu.A = 0x00;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x00 );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
+START_TEST( test_cpu_6502_ora_addr_imm )
+{
+ INIT_CPU_TEST
+
+ CODE_SET2( 0x09, 0x55 ); // ORA #$55
+
+ cpu.A = 0x1a;
+
+ COPY_CPU_TEST
+
+ cpu_6502_run_steps( &cpu, 1 );
+
+ PRINT_CPU_TEST
+
+ ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK );
+ ck_assert_int_eq( cpu.PC, before_cpu.PC+2 );
+ ck_assert_int_eq( cpu.SP, before_cpu.SP );
+ ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) );
+ ck_assert( !cpu_6502_is_zero( &cpu ) );
+ ck_assert( !cpu_6502_is_negative( &cpu ) );
+ ck_assert_int_eq( cpu.A, 0x5f );
+ ck_assert_int_eq( cpu.X, before_cpu.X );
+ ck_assert_int_eq( cpu.Y, before_cpu.Y );
+ ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size );
+ ck_assert_int_eq( cpu.cycles, 2 );
+
+ DEINIT_CPU_TEST
+}
+END_TEST
+
// CPX
START_TEST( test_cpu_6502_cpx_flags_equals )
@@ -1267,9 +1666,12 @@ static Suite *make_cpu_6502_testsuite( void )
create_cpu_6502_testcase( suite, "NOP", test_cpu_6502_nop );
create_cpu_6502_testcase( suite, "TXS", test_cpu_6502_txs );
+ create_cpu_6502_testcase( suite, "CLI", test_cpu_6502_cli );
+ create_cpu_6502_testcase( suite, "SEI", test_cpu_6502_sei );
create_cpu_6502_testcase( suite, "LDA (flags, positive)", test_cpu_6502_lda_flags_positive );
create_cpu_6502_testcase( suite, "LDA (flags, negative)", test_cpu_6502_lda_flags_negative );
create_cpu_6502_testcase( suite, "LDA (flags, zero)", test_cpu_6502_lda_flags_zero );
+ create_cpu_6502_testcase( suite, "LDA (addr, absolute)", test_cpu_6502_lda_addr_abs );
create_cpu_6502_testcase( suite, "LDX (flags, positive)", test_cpu_6502_ldx_flags_positive );
create_cpu_6502_testcase( suite, "LDX (flags, negative)", test_cpu_6502_ldx_flags_negative );
create_cpu_6502_testcase( suite, "LDX (flags, zero)", test_cpu_6502_ldx_flags_zero );
@@ -1278,6 +1680,8 @@ static Suite *make_cpu_6502_testsuite( void )
create_cpu_6502_testcase( suite, "LDY (flags, zero)", test_cpu_6502_ldy_flags_zero );
create_cpu_6502_testcase( suite, "STX (addr, zero)", test_cpu_6502_stx_addr_zero );
create_cpu_6502_testcase( suite, "STX (addr, absolute)", test_cpu_6502_stx_addr_abs );
+ create_cpu_6502_testcase( suite, "STA (addr, zero)", test_cpu_6502_sta_addr_zero );
+ create_cpu_6502_testcase( suite, "STA (addr, absolute)", test_cpu_6502_sta_addr_abs );
create_cpu_6502_testcase( suite, "INC (flags, positive)", test_cpu_6502_inc_flags_positive );
create_cpu_6502_testcase( suite, "INC (flags, negative)", test_cpu_6502_inc_flags_negative );
create_cpu_6502_testcase( suite, "INC (flags, zero)", test_cpu_6502_inc_flags_zero );
@@ -1291,6 +1695,14 @@ static Suite *make_cpu_6502_testsuite( void )
create_cpu_6502_testcase( suite, "DEY (flags, negative)", test_cpu_6502_dey_flags_negative );
create_cpu_6502_testcase( suite, "DEY (flags, zero)", test_cpu_6502_dey_flags_zero );
create_cpu_6502_testcase( suite, "ROL (flags, carry)", test_cpu_6502_rol_flags_accumulator_carry );
+ create_cpu_6502_testcase( suite, "AND (flags, positive)", test_cpu_6502_and_flags_positive );
+ create_cpu_6502_testcase( suite, "AND (flags, negative)", test_cpu_6502_and_flags_negative );
+ create_cpu_6502_testcase( suite, "AND (flags, zero)", test_cpu_6502_and_flags_zero );
+ create_cpu_6502_testcase( suite, "AND (addr, immediate)", test_cpu_6502_and_addr_imm );
+ create_cpu_6502_testcase( suite, "ORA (flags, positive)", test_cpu_6502_ora_flags_positive );
+ create_cpu_6502_testcase( suite, "ORA (flags, negative)", test_cpu_6502_ora_flags_negative );
+ create_cpu_6502_testcase( suite, "ORA (flags, zero)", test_cpu_6502_ora_flags_zero );
+ create_cpu_6502_testcase( suite, "ORA (addr, immediate)", test_cpu_6502_ora_addr_imm );
create_cpu_6502_testcase( suite, "CPX (flags, equals)", test_cpu_6502_cpx_flags_equals );
create_cpu_6502_testcase( suite, "CPX (flags, less)", test_cpu_6502_cpx_flags_less );
create_cpu_6502_testcase( suite, "CPX (flags, greater)", test_cpu_6502_cpx_flags_greater );
diff --git a/roms/7seg_counter_irq_timer.asm b/roms/7seg_counter_irq_timer.asm
index b031886..3da0f3c 100644
--- a/roms/7seg_counter_irq_timer.asm
+++ b/roms/7seg_counter_irq_timer.asm
@@ -30,8 +30,8 @@ reset:
sta PCR
lda ACR
- AND #$7F
- ORA #%01000000 ; setup timer for free running timer1, no PB7
+ and #$7F
+ ora #%01000000 ; setup timer for free running timer1, no PB7
sta ACR
lda #%00000111 ; set output on 7seg control pins of PORTA