2. 2A03简介
2A03简介
1.CPU
1.1 内部寄存器
1.累加寄存器A(Accumulator):8位寄存器,用于同算术逻辑单元(ALU)共同完成各种算术逻辑运算,它既为ALU提供原始操作数又担任存放ALU运算结果的任务。
2.变址寄存器X,Y(Index Register):变址寄存器有两个,均为8位寄存器,用于在变址寻址方式中存放地址偏移量,也可作为计数器使用,还可以作为通用寄存器用于暂存数据。
3.堆栈指针寄存器S(Stack Pointer):8位寄存器,用于指示系统堆栈栈顶位置。工作中,指向堆栈位置的低8位(16位地址$0100~$01FF),进栈加1,出栈减1。
4.程序计数器PC(Program Counter):16位寄存器,用两个寄存器组成,高8位为PCH,低8位为PCL,用于存放下一条指令的首地址。
5.标志寄存器P(Processor Status):标志寄存器P也称作程序状态(PSW)寄存器,8为寄存器,工作中只用到了6位,D4和D5未使用。
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
N(负数标志(Negative Flag)) | V(溢出标志(Overlow)) | B(中断请求标志(Break Command)) | D(BCD模式标志(Decimal Mode)) | I(中断禁止(屏蔽)标志(Interrupt Disable)) | Z(零标志(Zero)) | C(进位标志(Carry)) | |
表示本次结果是否为负,实质是把最高位复制到N中。 | 表示本次运算结果的溢出状态,有溢出置1,否则置0。 | 表示BRK中断指令已经被执行,将产生一个中断请求(IRQ) | 表示ALU进行的运算是十进制还是二进制。是置1,否置0。 | 表明是否允许中断,允许时为0,禁止时为1。 | 指令执行后的结果情况。为0置1,反之置0。 | 指令执行后最高位的进位状态。加法最高位有进位置1,减法最高位有借位置0,反之亦然。 |
1.2 寻址方式(来源:http://wiki.nesdev.com/w/index.php/CPU_addressing_modes)
Indexed addressing
Indexed addressing modes use the X or Y register to help determine the address. The 6502 has six main indexed addressing modes:
Abbr |
Name |
Formula |
Cycles |
d,x |
Zero page indexed |
val = PEEK((arg + X) % 256) |
4 |
d,y |
Zero page indexed |
val = PEEK((arg + Y) % 256) |
4 |
a,x |
Absolute indexed |
val = PEEK(arg + X) |
4+ |
a,y |
Absolute indexed |
val = PEEK(arg + Y) |
4+ |
(d,x) |
Indexed indirect |
val = PEEK(PEEK((arg + X) % 256) + PEEK((arg + X + 1) % 256) * 256) |
6 |
(d),y |
Indirect indexed |
val = PEEK(PEEK(arg) + PEEK((arg + 1) % 256) * 256 + Y) |
5+ |
Notes:
§ Abbreviations for addressing modes are those used in WDC's 65C816 data sheets.
§ + means add a cycle for write instructions or for page wrapping on read instructions, called the "oops" cycle below.
The 6502 has one 8-bit ALU and one 16-bit upcounter (for PC). To calculate a,x or a,y addressing in an instruction other than sta, stx, or sty, it uses the 8-bit ALU to first calculate the low byte while it fetches the high byte. If there's a carry out, it goes "oops", applies the carry using the ALU, and repeats the read at the correct address. Store instructions always have this "oops" cycle: the CPU first reads from the partially added address and then writes to the correct address. The same thing happens on (d),y indirect addressing.
The (d),y mode is used far more often than (d,x). The latter implies a table of addresses on zero page. On computers like the Apple II, where the BASIC interpreter uses up most of zero page, (d,x) is rarely used. But the NES has far more spare room in zero page, and music engine might use X = 0, 4, 8, or 12 to match APU register offsets.
Other addressing
Abbr |
Name |
Notes |
Implicit |
Instructions like RTS or CLC have no address operand, the destination of results are implied. |
|
A |
Accumulator |
Many instructions can operate on the accumulator, e.g. LSR A. Some assemblers will treat no operand as an implicit A where applicable. |
#v |
Immediate |
Uses the 8-bit operand itself as the value for the operation, rather than fetching a value from a memory address. |
d |
Zero page |
Fetches the value from an 8-bit address on the zero page. |
a |
Absolute |
Fetches the value from a 16-bit address anywhere in memory. |
label |
Relative |
Branch instructions (e.g. BEQ, BCS) have a relative addressing mode that specifies an 8-bit signed offset relative to the current PC. |
(a) |
Indirect |
The JMP instruction has a special indirect addressing mode that can jump to the address stored in a 16-bit pointer anywhere in memory. |
1.3 CPU指令(来源:http://obelisk.me.uk/6502/reference.html)
ADC |
AND |
ASL |
BCC |
BCS |
BEQ |
BIT |
BMI |
BNE |
BPL |
BRK |
BVC |
BVS |
CLC |
CLD |
CLI |
CLV |
CMP |
CPX |
CPY |
DEC |
DEX |
DEY |
EOR |
INC |
INX |
INY |
JMP |
JSR |
LDA |
LDX |
LDY |
LSR |
NOP |
ORA |
PHA |
PHP |
PLA |
PLP |
ROL |
ROR |
RTI |
RTS |
SBC |
SEC |
SED |
SEI |
STA |
STX |
STY |
TAX |
TAY |
TSX |
TXA |
TXS |
TYA |
ADC - Add with Carry
A,Z,C,N = A+M+C
This instruction adds the contents of a memory location to the accumulator together with the carry bit. If overflow occurs the carry bit is set, this enables multiple byte addition to be performed.
Processor Status after use:
C |
Carry Flag |
Set if overflow in bit 7 |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Set if sign bit is incorrect |
N |
Negative Flag |
Set if bit 7 set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$69 |
2 |
2 |
Zero Page |
$65 |
2 |
3 |
Zero Page,X |
$75 |
2 |
4 |
Absolute |
$6D |
3 |
4 |
Absolute,X |
$7D |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$79 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$61 |
2 |
6 |
(Indirect),Y |
$71 |
2 |
5 (+1 if page crossed) |
See also: SBC
AND - Logical AND
A,Z,N = A&M
A logical AND is performed, bit by bit, on the accumulator contents using the contents of a byte of memory.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$29 |
2 |
2 |
Zero Page |
$25 |
2 |
3 |
Zero Page,X |
$35 |
2 |
4 |
Absolute |
$2D |
3 |
4 |
Absolute,X |
$3D |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$39 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$21 |
2 |
6 |
(Indirect),Y |
$31 |
2 |
5 (+1 if page crossed) |
See also: EOR, ORA
ASL - Arithmetic Shift Left
A,Z,C,N = M*2 or M,Z,C,N = M*2
This operation shifts all the bits of the accumulator or memory contents one bit left. Bit 0 is set to 0 and bit 7 is placed in the carry flag. The effect of this operation is to multiply the memory contents by 2 (ignoring 2's complement considerations), setting the carry if the result will not fit in 8 bits.
Processor Status after use:
C |
Carry Flag |
Set to contents of old bit 7 |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Accumulator |
$0A |
1 |
2 |
Zero Page |
$06 |
2 |
5 |
Zero Page,X |
$16 |
2 |
6 |
Absolute |
$0E |
3 |
6 |
Absolute,X |
$1E |
3 |
7 |
See also: LSR, ROL, ROR
BCC - Branch if Carry Clear
If the carry flag is clear then add the relative displacement to the program counter to cause a branch to a new location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$90 |
2 |
2 (+1 if branch succeeds |
See also: BCS
BCS - Branch if Carry
Set
If the carry flag is set then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$B0 |
2 |
2 (+1 if branch succeeds |
See also: BCC
BEQ - Branch if Equal
If the zero flag is set then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$F0 |
2 |
2 (+1 if branch succeeds |
See also: BNE
BIT - Bit Test
A & M, N = M7, V = M6
This instructions is used to test if one or
more bits are set in a target memory location. The mask pattern in A is ANDed
with the value in memory to set or clear the zero flag, but the result is not
kept. Bits 7 and 6 of the value from memory are copied into the N and V flags.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if the result if the AND is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Set to bit 6 of the memory value |
N |
Negative Flag |
Set to bit 7 of the memory value |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Zero Page |
$24 |
2 |
3 |
Absolute |
$2C |
3 |
4 |
BMI - Branch if Minus
If the negative flag is set then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$30 |
2 |
2 (+1 if branch succeeds |
See also: BPL
BNE - Branch if Not
Equal
If the zero flag is clear then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$D0 |
2 |
2 (+1 if branch succeeds |
See also: BEQ
BPL - Branch if Positive
If the negative flag is clear then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$10 |
2 |
2 (+1 if branch succeeds |
See also: BMI
BRK - Force Interrupt
The BRK instruction forces the generation
of an interrupt request. The program counter and processor status are pushed on
the stack then the IRQ interrupt vector at $FFFE/F is loaded into the PC and
the break flag in the status set to one.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Set to 1 |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$00 |
1 |
7 |
The interpretation of a BRK depends on the
operating system. On the BBC Microcomputer it is used by language ROMs to
signal run time errors but it could be used for other purposes (e.g. calling
operating system functions, etc.).
BVC - Branch if Overflow
Clear
If the overflow flag is clear then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$50 |
2 |
2 (+1 if branch succeeds |
See also: BVS
BVS - Branch if Overflow
Set
If the overflow flag is set then add the
relative displacement to the program counter to cause a branch to a new
location.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Relative |
$70 |
2 |
2 (+1 if branch succeeds |
See also: BVC
CLC - Clear Carry Flag
C = 0
Set the carry flag to zero.
C |
Carry Flag |
Set to 0 |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$18 |
1 |
2 |
See also: SEC
CLD - Clear Decimal Mode
D = 0
Sets the decimal mode flag to zero.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Set to 0 |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$D8 |
1 |
2 |
NB:
The state of the decimal flag is uncertain when the CPU is powered up and it is
not reset when an interrupt is generated. In both cases you should include an
explicit CLD to ensure that the flag is cleared before performing addition or
subtraction.
See also: SED
CLI - Clear Interrupt
Disable
I = 0
Clears the interrupt disable flag allowing
normal interrupt requests to be serviced.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Set to 0 |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$58 |
1 |
2 |
See also: SEI
CLV - Clear Overflow
Flag
V = 0
Clears the overflow flag.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Set to 0 |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$B8 |
1 |
2 |
CMP - Compare
Z,C,N = A-M
This instruction compares the contents of
the accumulator with another memory held value and sets the zero and carry
flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Set if A >= M |
Z |
Zero Flag |
Set if A = M |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$C9 |
2 |
2 |
Zero Page |
$C5 |
2 |
3 |
Zero Page,X |
$D5 |
2 |
4 |
Absolute |
$CD |
3 |
4 |
Absolute,X |
$DD |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$D9 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$C1 |
2 |
6 |
(Indirect),Y |
$D1 |
2 |
5 (+1 if page crossed) |
See also: CPX, CPY
CPX - Compare X Register
Z,C,N = X-M
This instruction compares the contents of
the X register with another memory held value and sets the zero and carry flags
as appropriate.
Processor Status after use:
C |
Carry Flag |
Set if X >= M |
Z |
Zero Flag |
Set if X = M |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$E0 |
2 |
2 |
Zero Page |
$E4 |
2 |
3 |
Absolute |
$EC |
3 |
4 |
See also: CMP, CPY
CPY - Compare Y Register
Z,C,N = Y-M
This instruction compares the contents of
the Y register with another memory held value and sets the zero and carry flags
as appropriate.
Processor Status after use:
C |
Carry Flag |
Set if Y >= M |
Z |
Zero Flag |
Set if Y = M |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$C0 |
2 |
2 |
Zero Page |
$C4 |
2 |
3 |
Absolute |
$CC |
3 |
4 |
See also: CMP, CPX
DEC - Decrement Memory
M,Z,N = M-1
Subtracts one from the value held at a
specified memory location setting the zero and negative flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if result is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Zero Page |
$C6 |
2 |
5 |
Zero Page,X |
$D6 |
2 |
6 |
Absolute |
$CE |
3 |
6 |
Absolute,X |
$DE |
3 |
7 |
See also: DEX, DEY
DEX - Decrement X
Register
X,Z,N = X-1
Subtracts one from the X register setting
the zero and negative flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if X is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of X is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$CA |
1 |
2 |
See also: DEC, DEY
DEY - Decrement Y
Register
Y,Z,N = Y-1
Subtracts one from the Y register setting
the zero and negative flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if Y is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of Y is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$88 |
1 |
2 |
See also: DEC, DEX
EOR - Exclusive OR
A,Z,N = A^M
An exclusive OR is performed, bit by bit,
on the accumulator contents using the contents of a byte of memory.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$49 |
2 |
2 |
Zero Page |
$45 |
2 |
3 |
Zero Page,X |
$55 |
2 |
4 |
Absolute |
$4D |
3 |
4 |
Absolute,X |
$5D |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$59 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$41 |
2 |
6 |
(Indirect),Y |
$51 |
2 |
5 (+1 if page crossed) |
See also: AND, ORA
INC - Increment Memory
M,Z,N = M+1
Adds one to the value held at a specified
memory location setting the zero and negative flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if result is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Zero Page |
$E6 |
2 |
5 |
Zero Page,X |
$F6 |
2 |
6 |
Absolute |
$EE |
3 |
6 |
Absolute,X |
$FE |
3 |
7 |
See also: INX, INY
INX - Increment X
Register
X,Z,N = X+1
Adds one to the X register setting the zero
and negative flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if X is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of X is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$E8 |
1 |
2 |
See also: INC, INY
INY - Increment Y
Register
Y,Z,N = Y+1
Adds one to the Y register setting the zero
and negative flags as appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if Y is zero |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of Y is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$C8 |
1 |
2 |
See also: INC, INX
JMP - Jump
Sets the program counter to the address
specified by the operand.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Absolute |
$4C |
3 |
3 |
Indirect |
$6C |
3 |
5 |
NB:
An original 6502 has does not correctly fetch the target address if the
indirect vector falls on a page boundary (e.g. $xxFF where xx is any value from
$00 to $FF). In this case fetches the LSB from $xxFF as expected but takes the
MSB from $xx00. This is fixed in some later chips like the 65SC02 so for
compatibility always ensure the indirect vector is not at the end of the page.
JSR - Jump to Subroutine
The JSR instruction pushes the address
(minus one) of the return point on to the stack and then sets the program
counter to the target memory address.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Absolute |
$20 |
3 |
6 |
See also: RTS
LDA - Load Accumulator
A,Z,N = M
Loads a byte of memory into the accumulator
setting the zero and negative flags as appropriate.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of A is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$A9 |
2 |
2 |
Zero Page |
$A5 |
2 |
3 |
Zero Page,X |
$B5 |
2 |
4 |
Absolute |
$AD |
3 |
4 |
Absolute,X |
$BD |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$B9 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$A1 |
2 |
6 |
(Indirect),Y |
$B1 |
2 |
5 (+1 if page crossed) |
See also: LDX, LDY
LDX - Load X Register
X,Z,N = M
Loads a byte of memory into the X register
setting the zero and negative flags as appropriate.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if X = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of X is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$A2 |
2 |
2 |
Zero Page |
$A6 |
2 |
3 |
Zero Page,Y |
$B6 |
2 |
4 |
Absolute |
$AE |
3 |
4 |
Absolute,Y |
$BE |
3 |
4 (+1 if page crossed) |
See also: LDA, LDY
LDY - Load Y Register
Y,Z,N = M
Loads a byte of memory into the Y register
setting the zero and negative flags as appropriate.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if Y = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of Y is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$A0 |
2 |
2 |
Zero Page |
$A4 |
2 |
3 |
Zero Page,X |
$B4 |
2 |
4 |
Absolute |
$AC |
3 |
4 |
Absolute,X |
$BC |
3 |
4 (+1 if page crossed) |
See also: LDA, LDX
LSR - Logical Shift
Right
A,C,Z,N = A/2 or M,C,Z,N = M/2
Each of the bits in A or M is shift one
place to the right. The bit that was in bit 0 is shifted into the carry flag.
Bit 7 is set to zero.
Processor Status after use:
C |
Carry Flag |
Set to contents of old bit 0 |
Z |
Zero Flag |
Set if result = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Accumulator |
$4A |
1 |
2 |
Zero Page |
$46 |
2 |
5 |
Zero Page,X |
$56 |
2 |
6 |
Absolute |
$4E |
3 |
6 |
Absolute,X |
$5E |
3 |
7 |
See also: ASL, ROL, ROR
NOP - No Operation
The NOP instruction causes no changes to
the processor other than the normal incrementing of the program counter to the
next instruction.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$EA |
1 |
2 |
ORA - Logical Inclusive
OR
A,Z,N = A|M
An inclusive OR is performed, bit by bit,
on the accumulator contents using the contents of a byte of memory.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$09 |
2 |
2 |
Zero Page |
$05 |
2 |
3 |
Zero Page,X |
$15 |
2 |
4 |
Absolute |
$0D |
3 |
4 |
Absolute,X |
$1D |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$19 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$01 |
2 |
6 |
(Indirect),Y |
$11 |
2 |
5 (+1 if page crossed) |
See also: AND, EOR
PHA - Push Accumulator
Pushes a copy of the accumulator on to the
stack.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$48 |
1 |
3 |
See also: PLA
PHP - Push Processor
Status
Pushes a copy of the status flags on to the
stack.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$08 |
1 |
3 |
See also: PLP
PLA - Pull Accumulator
Pulls an 8 bit value from the stack and
into the accumulator. The zero and negative flags are set as appropriate.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of A is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$68 |
1 |
4 |
See also: PHA
PLP - Pull Processor
Status
Pulls an 8 bit value from the stack and
into the processor flags. The flags will take on new states as determined by
the value pulled.
Processor Status after use:
C |
Carry Flag |
Set from stack |
Z |
Zero Flag |
Set from stack |
I |
Interrupt Disable |
Set from stack |
D |
Decimal Mode Flag |
Set from stack |
B |
Break Command |
Set from stack |
V |
Overflow Flag |
Set from stack |
N |
Negative Flag |
Set from stack |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$28 |
1 |
4 |
See also: PHP
ROL - Rotate Left
Move each of the bits in either A or M one
place to the left. Bit 0 is filled with the current value of the carry flag
whilst the old bit 7 becomes the new carry flag value.
Processor Status after use:
C |
Carry Flag |
Set to contents of old bit 7 |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Accumulator |
$2A |
1 |
2 |
Zero Page |
$26 |
2 |
5 |
Zero Page,X |
$36 |
2 |
6 |
Absolute |
$2E |
3 |
6 |
Absolute,X |
$3E |
3 |
7 |
See also: ASL, LSR, ROR
ROR - Rotate Right
Move each of the bits in either A or M one
place to the right. Bit 7 is filled with the current value of the carry flag
whilst the old bit 0 becomes the new carry flag value.
Processor Status after use:
C |
Carry Flag |
Set to contents of old bit 0 |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of the result is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Accumulator |
$6A |
1 |
2 |
Zero Page |
$66 |
2 |
5 |
Zero Page,X |
$76 |
2 |
6 |
Absolute |
$6E |
3 |
6 |
Absolute,X |
$7E |
3 |
7 |
See also ASL, LSR, ROL
RTI - Return from
Interrupt
The RTI instruction is used at the end of
an interrupt processing routine. It pulls the processor flags from the stack
followed by the program counter.
Processor Status after use:
C |
Carry Flag |
Set from stack |
Z |
Zero Flag |
Set from stack |
I |
Interrupt Disable |
Set from stack |
D |
Decimal Mode Flag |
Set from stack |
B |
Break Command |
Set from stack |
V |
Overflow Flag |
Set from stack |
N |
Negative Flag |
Set from stack |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$40 |
1 |
6 |
RTS - Return from
Subroutine
The RTS instruction is used at the end of a
subroutine to return to the calling routine. It pulls the program counter
(minus one) from the stack.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$60 |
1 |
6 |
See also: JSR
SBC - Subtract with
Carry
A,Z,C,N = A-M-(1-C)
This instruction subtracts the contents of
a memory location to the accumulator together with the not of the carry bit. If
overflow occurs the carry bit is clear, this enables multiple byte subtraction
to be performed.
Processor Status after use:
C |
Carry Flag |
Clear if overflow in bit 7 |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Set if sign bit is incorrect |
N |
Negative Flag |
Set if bit 7 set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Immediate |
$E9 |
2 |
2 |
Zero Page |
$E5 |
2 |
3 |
Zero Page,X |
$F5 |
2 |
4 |
Absolute |
$ED |
3 |
4 |
Absolute,X |
$FD |
3 |
4 (+1 if page crossed) |
Absolute,Y |
$F9 |
3 |
4 (+1 if page crossed) |
(Indirect,X) |
$E1 |
2 |
6 |
(Indirect),Y |
$F1 |
2 |
5 (+1 if page crossed) |
See also: ADC
SEC - Set Carry Flag
C = 1
Set the carry flag to one.
C |
Carry Flag |
Set to 1 |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$38 |
1 |
2 |
See also: CLC
SED - Set Decimal Flag
D = 1
Set the decimal mode flag to one.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Set to 1 |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$F8 |
1 |
2 |
See also: CLD
SEI - Set Interrupt
Disable
I = 1
Set the interrupt disable flag to one.
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Set to 1 |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$78 |
1 |
2 |
See also: CLI
STA - Store Accumulator
M = A
Stores the contents of the accumulator into
memory.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Zero Page |
$85 |
2 |
3 |
Zero Page,X |
$95 |
2 |
4 |
Absolute |
$8D |
3 |
4 |
Absolute,X |
$9D |
3 |
5 |
Absolute,Y |
$99 |
3 |
5 |
(Indirect,X) |
$81 |
2 |
6 |
(Indirect),Y |
$91 |
2 |
6 |
See also: STX, STY
STX - Store X Register
M = X
Stores the contents of the X register into
memory.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Zero Page |
$86 |
2 |
3 |
Zero Page,Y |
$96 |
2 |
4 |
Absolute |
$8E |
3 |
4 |
See also: STA, STY
STY - Store Y Register
M = Y
Stores the contents of the Y register into
memory.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Zero Page |
$84 |
2 |
3 |
Zero Page,X |
$94 |
2 |
4 |
Absolute |
$8C |
3 |
4 |
See also: STA, STX
TAX - Transfer
Accumulator to X
X = A
Copies the current contents of the
accumulator into the X register and sets the zero and negative flags as
appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if X = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of X is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$AA |
1 |
2 |
See also: TXA
TAY - Transfer
Accumulator to Y
Y = A
Copies the current contents of the
accumulator into the Y register and sets the zero and negative flags as
appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if Y = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of Y is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$A8 |
1 |
2 |
See also: TYA
TSX - Transfer Stack
Pointer to X
X = S
Copies the current contents of the stack
register into the X register and sets the zero and negative flags as
appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if X = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of X is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$BA |
1 |
2 |
See also: TXS
TXA - Transfer X to
Accumulator
A = X
Copies the current contents of the X
register into the accumulator and sets the zero and negative flags as
appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of A is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$8A |
1 |
2 |
See also: TAX
TXS - Transfer X to
Stack Pointer
S = X
Copies the current contents of the X
register into the stack register.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Not affected |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Not affected |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$9A |
1 |
2 |
See also: TSX
TYA - Transfer Y to
Accumulator
A = Y
Copies the current contents of the Y
register into the accumulator and sets the zero and negative flags as
appropriate.
Processor Status after use:
C |
Carry Flag |
Not affected |
Z |
Zero Flag |
Set if A = 0 |
I |
Interrupt Disable |
Not affected |
D |
Decimal Mode Flag |
Not affected |
B |
Break Command |
Not affected |
V |
Overflow Flag |
Not affected |
N |
Negative Flag |
Set if bit 7 of A is set |
Addressing Mode |
Opcode |
Bytes |
Cycles |
Implied |
$98 |
1 |
2 |
See also: TAY
1.4 CPU内存分布(来源:http://wiki.nesdev.com/w/index.php/CPU_memory_map)
Address range |
Size |
Device |
$0000-$07FF |
$0800 |
2KB internal RAM |
$0800-$0FFF |
$0800 |
Mirrors of |
$1000-$17FF |
$0800 |
|
$1800-$1FFF |
$0800 |
|
$2000-$2007 |
$0008 |
NES PPU registers |
$2008-$3FFF |
$1FF8 |
Mirrors of |
$4000-$4017 |
$0018 |
NES APU and I/O registers |
$4018-$401F |
$0008 |
APU and I/O |
$4020-$FFFF |
$BFE0 |
Cartridge space: |
See Sample RAM map for
an example allocation strategy for the 2KB of internal RAM at $0000-$0800.
Note: Most common boards and iNES mappers
address ROM and Save/Work RAM in this format:
§ $6000-$7FFF = Battery Backed Save or Work
RAM
§ $8000-$FFFF = Usual ROM, commonly with
Mapper Registers (see MMC1 and UxROM for
example)
The CPU expects interrupt vectors in a
fixed place at the end of the cartridge space:
§ $FFFA-$FFFB = NMI vector
§ $FFFC-$FFFD = Reset vector
§ $FFFE-$FFFF = IRQ/BRK vector
If a mapper doesn't fix $FFFA-$FFFF to
some known bank (typically, along with the rest of the bank containing them,
e.g. $C000-$FFFF for a 16KiB banking mapper) or use some sort of reset
detection, the vectors need to be stored in all banks.
1.5 CPU通电状态(来源:http://wiki.nesdev.com/w/index.php/CPU_power_up_state)
At power-up
P = $34(IRQ
disabled)
A, X, Y = 0
S = $FD
$4017 = $00 (frame irq enabled)
$4015 = $00 (all channels disabled)
$4000-$400F = $00 (not sure about
$4010-$4013)
All 15 bits of noise channel LFSR = $0000.
The first time the LFSR is clocked from the all-0s state, it will shift in a 1.
Internal memory ($0000-$07FF) has
unreliable startup state. Some machines may have consistent RAM contents at
power-on, but others do not.
Emulators often
implement a consistent RAM startup state (e.g. all $00 or $FF, or a particular
pattern), and flash carts like the PowerPak may
partially or fully initialize RAM before starting a program, so an NES
programmer must be careful not to rely on the startup contents of RAM.
After reset
A, X, Y were not affected
S was decremented by 3 (but nothing was
written to the stack)
The I (IRQ disable) flag was set to true
(status ORed with $04)
The internal memory was unchanged
APU mode in $4017 was unchanged
APU was silenced ($4015 = 0)
1.6 CPU中断与复位(来源:http://wiki.nesdev.com/w/index.php/CPU_interrupts)
Detailed interrupt behavior
The NMI input is edge-sensitive (reacts to high-to-low transitions in the signal) while the IRQ input is level-sensitive (reacts to a low signal level). Both inputs are active low.
The NMI input is connected to an edge detector. This edge detector polls the status of the NMI line during φ2 of each CPU cycle (i.e., during the second half of each cycle) and raises an internal signal if the input goes from being high during one cycle to being low during the next. The internal signal goes high during φ1 of the cycle that follows the one where the edge is detected, and stays high until the NMI has been handled.
The IRQ input is connected to a level detector. If a low level is detected on the IRQ input during φ2 of a cycle, an internal signal is raised during φ1 the following cycle, remaining high for that cycle only (or put another way, remaining high as long as the IRQ input is low during the preceding cycle's φ2).
The output from the edge detector and level detector are polled at certain points to detect pending interrupts. For most instructions, this polling happens during the final cycle of the instruction, before the opcode fetch for the next instruction. If the polling operation detects that an interrupt has been asserted, the next "instruction" executed is the interrupt sequence.
Many references will claim that interrupts are polled during the last cycle of an instruction, but this is true only when talking about the output from the edge and level detectors. As can be deduced from above, it's really the status of the interrupt lines at the end of the second-to-last cycle that matters.
If both an NMI and an IRQ are pending at the end of an instruction, the NMI will be handled and the pending status of the IRQ forgotten (though it's likely to be detected again during later polling).
The interrupt sequences themselves do not perform interrupt polling, meaning at least one instruction from the interrupt handler will execute before another interrupt is serviced.
Delayed IRQ response after CLI, SEI, and PLP
The RTI instruction affects IRQ inhibition immediately. If an IRQ is pending and an RTI is executed that clears the I flag, the CPU will invoke the IRQ handler immediately after RTI finishes executing. This is due to RTI restoring the I flag from the stack before polling for interrupts.
The CLI, SEI, and PLP instructions on the other hand change the I flag after polling for interrupts (like all two-cycle instructions they poll the interrupt lines at the end of the first cycle), meaning they can effectively delay an interrupt until after the next instruction. For example, if an interrupt is pending and the I flag is currently set, executing CLI will execute the next instruction before the CPU invokes the IRQ handler.
Verification and testing of this behavior in emulators can be accomplished through test ROM images.
Branch instructions and interrupts
The branch instructions have more subtle interrupt polling behavior. Interrupts are always polled before the second CPU cycle (the operand fetch). Additionally, for taken branches that cross a page boundary, interrupts are polled before the PCH fixup cycle (see for a tick-by-tick breakdown of the branch instructions). An interrupt being detected at either of these polling points (including only being detected at the first one) will trigger a CPU interrupt.
Interrupt hijacking
Normally, the NMI vector is at $FFFA, the reset vector at $FFFC, and the IRQ and BRK vector at $FFFE. This means that when servicing an IRQ, the 6502 will push PC and P and then read the new program counter from $FFFE and $FFFF, as if JMP ($FFFE)
. But the MOS 6502 and by extension the 2A03/2A07 has a quirk that can cause an interrupt to use the wrong vector if two different interrupts occur very close to one another.
For example, if NMI is asserted during the first four ticks of a BRK instruction, the BRK instruction will execute normally at first (PC increments will occur and the status word will be pushed with the B flag set), but execution will branch to the NMI vector instead of the IRQ/BRK vector:
Each [] is a CPU tick. [...] is whatever tick precedes the BRK opcode fetch. Asserting NMI during the interval marked with * causes a branch to the NMI routine instead of the IRQ/BRK routine: ********************
[...][BRK][BRK][BRK][BRK][BRK][BRK][BRK]
In a tick-by-tick breakdown of BRK, this looks like
# address R/W description
--- ------- --- -----------------------------------------------
1 PC R fetch opcode, increment PC
2 PC R read next instruction byte (and throw it away),
increment PC
3 $0100,S W push PCH on stack, decrement S
4 $0100,S W push PCL on stack, decrement S
*** At this point, the signal status determines which interrupt vector is used ***
5 $0100,S W push P on stack (with B flag set), decrement S
6 $FFFE R fetch PCL, set I flag
7 $FFFF R fetch PCH
Similarly, an NMI can hijack an IRQ, and an IRQ can hijack a BRK (though it won't be as visible since they use the same interrupt vector). The tick-by-tick breakdown of all types of interrupts is essentially like that of BRK, save for whether the B bit is pushed as set and whether PC increments occur.
IRQ and NMI tick-by-tick execution
For exposition and to emphasize similarity with BRK, here's the tick-by-tick breakdown of IRQ and NMI (derived from ). A reset also goes through the same sequence, but suppresses writes, decrementing the stack pointer thrice without modifying memory. This is why the I flag is always set on reset.
# address R/W description
--- ------- --- -----------------------------------------------
1 PC R fetch opcode (and discard it - $00 (BRK) is forced into the opcode register instead)
2 PC R read next instruction byte (actually the same as above, since PC increment is suppressed. Also discarded.)
3 $0100,S W push PCH on stack, decrement S
4 $0100,S W push PCL on stack, decrement S
*** At this point, the signal status determines which interrupt vector is used ***
5 $0100,S W push P on stack (with B flag *clear*), decrement S
6 A R fetch PCL (A = FFFE for IRQ, A = FFFA for NMI), set I flag
7 A R fetch PCH (A = FFFF for IRQ, A = FFFB for NMI)
2. APU(来源:http://wiki.nesdev.com/w/index.php/APU)
Registers
- See APU Registers for a complete APU register diagram.
Registers | Channel | Units |
---|---|---|
$4000-$4003 | Pulse 1 | Timer, length counter, envelope, sweep |
$4004-$4007 | Pulse 2 | Timer, length counter, envelope, sweep |
$4008-$400B | Triangle | Timer, length counter, linear counter |
$400C-$400F | Noise | Timer, length counter, envelope, linear feedback shift register |
$4010-$4013 | DMC | Timer, memory reader, sample buffer, output unit |
$4015 | All | Channel enable and length counter status |
$4017 | All | Frame counter |
Pulse ($4000-4007)
- See APU Pulse
The pulse channels produce a variable-width pulse signal, controlled by volume, envelope, length, and sweep units.
$4000 / $4004 | DDLC VVVV | Duty (D), envelope loop / length counter halt (L), constant volume (C), volume/envelope (V) |
---|---|---|
$4001 / $4005 | EPPP NSSS | Sweep unit: enabled (E), period (P), negate (N), shift (S) |
$4002 / $4006 | TTTT TTTT | Timer low (T) |
$4003 / $4007 | LLLL LTTT | Length counter load (L), timer high (T) |
- The frequency of the pulse channels is a division of the CPU Clock (1.789773MHz NTSC, 1.662607MHz PAL). The output frequency (f) of the generator can be determined by the 11-bit period value (t) written to $4002-4003/$4006-4007. If t < 8, the corresponding pulse channel is silenced.
f = CPU / (16 * (t + 1))
t = (CPU / (16 * f)) - 1
- The width of the pulse is controlled by the duty bits in $4000/4004. See APU Pulse for details.
- The channel volume is a 4-bit value that is either constant, or controlled by an envelope (chosen by $4000/4004 bit 4). If using the envelope, the 4-bit value in $4000/4004 is the period of the envelope, otherwise it is the direct volume.
- The length counter and envelope units are clocked by the frame counter. If the envelope is not looped, the length counter must be enabled (making it redundant if longer than the envelope). The length counter simply silences the channel when it counts down to 0. The envelope starts at a volume of 15 and decrements every time the unit is clocked, stopping at 0 if not looped.
- Writing to $4003/4007 reloads the length counter, restarts the envelope, and resets the phase of the pulse generator. Because it resets phase, vibrato should only write the low timer register to avoid a phase reset click. At some pitches, particularly near A440, wide vibrato should normally be avoided (e.g. this flaw is heard throughout the Mega Man 2 ending).
- Registers $4001/4005 control the sweep unit. Enabling the sweep causes the pitch to constantly rise or fall. When the frequency reaches the end of the generator's range of output the channel is silenced. See APU Sweep for details.
- The two pulse channels are combined in a nonlinear mix (see mixer below).
Triangle ($4008-400B)
- See APU Triangle
The triangle channel produces a quantized triangle wave. It has no volume control, but it has a length counter as well as a higher resolution linear counter control (called "linear" since it uses the 7-bit value written to $4008 directly instead of a lookup table like the length counter).
$4008 | CRRR RRRR | Length counter halt / linear counter control (C), linear counter load (R) |
---|---|---|
$4009 | ---- ---- | Unused |
$400A | TTTT TTTT | Timer low (T) |
$400B | LLLL LTTT | Length counter load (L), timer high (T) |
- The triangle wave has 32 steps that output a 4-bit value.
- The linear counter control will silence the channel after a specified time with a resolution of 240Hz in NTSC (see frame counter below). It shares a control bit with the length counter in $4008, which means that they are always enabled at the same time, and whichever is longer is redundant. See APU Triangle for more linear counter details.
- The pitch of the triangle channel is one octave below the pulse channels with an equivalent timer value (i.e. use the formula above but divide the resulting frequency by two).
- Silencing the triangle channel merely halts it. It will continue to output its last value, rather than 0.
- There is no way to reset the triangle channel's phase.
Noise ($400C-400F)
- See APU Noise
The noise channel produces noise with a pseudo-random bit generator. It has a volume, envelope, and length counter like the pulse channels.
$400C | --LC VVVV | Envelope loop / length counter halt (L), constant volume (C), volume/envelope (V) |
---|---|---|
$400D | ---- ---- | Unused |
$400E | L--- PPPP | Loop noise (L), noise period (P) |
$400F | LLLL L--- | Length counter load (L) |
- The frequency of the noise is determined by a 4-bit value in $400E, which loads a period from a lookup table (see APU Noise).
- If bit 7 of $400E is set, the period of the random bit generation is drastically shortened, producing a buzzing tone (e.g. the metalic ding during Solstice's gameplay). The actual timbre produced depends on whatever bits happen to be in the generator when it is switched to periodic, and is somewhat random.
DMC ($4010-4013)
- See APU DMC
The delta modulation channel outputs a 7-bit PCM signal from a counter that can be driven by DPCM samples.
$4010 | IL-- RRRR | IRQ enable (I), loop (L), frequency (R) |
---|---|---|
$4011 | -DDD DDDD | Load counter (D) |
$4012 | AAAA AAAA | Sample address (A) |
$4013 | LLLL LLLL | Sample length (L) |
- DPCM samples are stored as a stream of 1-bit deltas that control the 7-bit PCM counter that the channel outputs. A bit of 1 will increment the counter, 0 will decrement, and it will clamp rather than overflow if the 7-bit range is exceeded.
- DPCM samples may loop if the loop flag in $4010 is set, and the DMC may be used to generate an IRQ when the end of the sample is reached if its IRQ flag is set.
- The playback rate is controlled by register $4010 with a 4-bit frequency index value (see APU DMC for frequency lookup tables).
- DPCM samples must begin in the memory range $C000-FFFF at an address set by register $4012 (address = %11AAAAAA.AA000000).
- The length of the sample in bytes is set by register $4013 (length = %LLLL.LLLL0001).
Other Uses
- The $4011 register can be used to play PCM samples directly by setting the counter value at a high frequency. Because this requires intensive use of the CPU, when used in games all other gameplay is usually halted to facilitate this.
- Because of the APU's nonlinear mixing, a high value in the PCM counter reduces the volume of the triangle and noise channels. This is sometimes used to apply limited volume control to the triangle channel (e.g. Super Mario Bros. adjusts the counter between levels to accomplish this).
- The DMC's IRQ can be used as an IRQ based timer when the mapper used does not have one available.
Status ($4015)
The status register is used to enable and disable individual channels, control the DMC, and can read the status of length counters and APU interrupts.
$4015 write | ---D NT21 | Enable DMC (D), noise (N), triangle (T), and pulse channels (2/1) |
---|
- Writing a zero to any of the channel enable bits will silence that channel and immediately set its length counter to 0.
- If the DMC bit is clear, the DMC bytes remaining will be set to 0 and the DMC will silence when it empties.
- If the DMC bit is set, the DMC sample will be restarted only if its bytes remaining is 0. If there are bits remaining in the 1-byte sample buffer, these will finish playing before the next sample is fetched.
- Writing to this register clears the DMC interrupt flag.
- Power-up and reset have the effect of writing $00, silencing all channels.
$4015 read | IF-D NT21 | DMC interrupt (I), frame interrupt (F), DMC active (D), length counter > 0 (N/T/2/1) |
---|
- N/T/2/1 will read as 1 if the corresponding length counter is greater than 0. For the triangle channel, the status of the linear counter is irrelevant.
- D will read as 1 if the DMC bytes remaining is more than 0.
- Reading this register clears the frame interrupt flag (but not the DMC interrupt flag).
- If an interrupt flag was set at the same moment of the read, it will read back as 1 but it will not be cleared.
Frame Counter ($4017)
- See APU Frame Counter
$4017 | MI-- ---- | Mode (M, 0 = 4-step, 1 = 5-step), IRQ inhibit flag (I) |
---|
The frame counter is controlled by register $4017, and it drives the envelope, sweep, and length units on the pulse, triangle and noise channels. It ticks approximately 4 times per frame (240Hz NTSC), and executes either a 4 or 5 step sequence, depending how it is configured. It may optionally issue an IRQ on the last tick of the 4 step sequence.
The following diagram illustrates the two modes, selected by bit 7 of $4017:
mode 0: mode 1: function
--------- ----------- -----------------------------
- - - f - - - - - IRQ (if bit 6 is clear)
- l - l l - l - - Length counter and sweep
e e e e e e e e - Envelope and linear counter
Both the 4 and 5-step modes operate at the same rate, but because the 5-step mode has an extra step, the effective update rate for individual units is slower in that mode (total update taking ~60Hz vs ~48Hz in NTSC). Writing to $4017 resets the frame counter and the quarter/half frame triggers happen simultaneously, but only on "odd" cycles (and only after the first "even" cycle after the write occurs) - thus, it happens either 2 or 3 cycles after the write (i.e. on the 2nd or 3rd cycle of the next instruction). After 2 or 3 clock cycles (depending on when the write is performed), the timer is reset. Writing to $4017 with bit 7 set ($80) will immediately clock all of its controlled units at the beginning of the 5-step sequence; with bit 7 clear, only the sequence is reset without clocking any of its units.
Note that the frame counter is not exactly synchronized with the PPU NMI; it runs independently at a consistent rate which is approximately 240Hz (NTSC). Some games (e.g. Super Mario Bros., Zelda) manually synchronize it by writing $C0 or $FF to $4017 once per frame.
Length Counter
- See APU Length Counter
The pulse, triangle, and noise channels each have their own length counter unit. It is clocked twice per sequence, and counts down to zero if enabled. When the length counter reaches zero the channel is silenced. It is reloaded by writing a 5-bit value to the appropriate channel's length counter register, which will load a value from a lookup table. (See APU Length Counter for the table.)
The triangle channel has an additional linear counter unit which is clocked four times per sequence (like the envelope of the other channels). It functions independently of the length counter, and will also silence the triangle channel when it reaches zero.
Mixer
- See APU Mixer
The APU audio output signal comes from two separate components. The pulse channels are output on one pin, and the triangle/noise/DMC are output on another, after which they are combined. Each of these channels has its own nonlinear DAC. For details, see APU Mixer.
After combining the two output signals, the final signal may go through a lowpass and highpass filter. For instance, RF demodulation in televisions usually results in a strong lowpass. The NES' RCA output circuitry has a more mild lowpass filter.
Glossary
- All APU channels have some form of frequency control. The term frequency is used where larger register value(s) correspond with higher frequencies, and the term period is used where smaller register value(s) correspond with higher frequencies.
- In the block diagrams, a gate takes the input on the left and outputs it on the right, unless the control input on top tells the gate to ignore the input and always output 0.
- Some APU units use one or more of the following building blocks:
-
- A divider outputs a clock periodically. It contains a period reload value, P, and a counter, that starts at P. When the divider is clocked, if the counter is currently 0, it is reloaded with P and generates an output clock, otherwise the counter is decremented. In other words, the divider's period is P + 1.
-
- A divider can also be forced to reload its counter immediately (counter = P), but this does not output a clock. Similarly, changing a divider's period reload value does not affect the counter. Some counters offer no way to force a reload, but at least synchronizes it to a known state once the current count expires.
-
- A divider may be implemented as a down counter (5, 4, 3, ...) or as a linear feedback shift register (LFSR). The dividers in the pulse and triangle channels are linear down-counters. The dividers for noise, DMC, and the APU Frame Counter are implemented as LFSRs to save gates compared to the equivalent down counter.
-
- A sequencer continuously loops over a sequence of values or events. When clocked, the next item in the sequence is generated.
-
- A timer is used in each of the five channels to control the sound frequency. It contains a divider which is clocked by the CPU clock. The triangle channel's timer is clocked on every CPU cycle, but the pulse, noise, and DMC timers are clocked only on every second CPU cycle and thus produce only even periods.
2. 2A03简介的更多相关文章
- 1. NES简介
NES(Nintendo Entertainment System)简介 NES是北美地区对任天堂发行的第三代家用游戏机的简称. 1.CPU NES使用一颗理光[1]制造的8位2A03 NMOS处理器 ...
- ASP.NET Core 1.1 简介
ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...
- MVVM模式和在WPF中的实现(一)MVVM模式简介
MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...
- Cassandra简介
在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...
- REST简介
一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...
- Microservice架构模式简介
在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...
- const,static,extern 简介
const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...
- HTTPS简介
一.简单总结 1.HTTPS概念总结 HTTPS 就是对HTTP进行了TLS或SSL加密. 应用层的HTTP协议通过传输层的TCP协议来传输,HTTPS 在 HTTP和 TCP中间加了一层TLS/SS ...
- 【Machine Learning】机器学习及其基础概念简介
机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...
随机推荐
- SLES Install
SUSE Linux Enterprise Server 12-SP3:zypper in -t patch SUSE-SLE-SERVER-12-SP3-2017-2036=1 To bring y ...
- python中令人惊艳的小众数据科学库
Python是门很神奇的语言,历经时间和实践检验,受到开发者和数据科学家一致好评,目前已经是全世界发展最好的编程语言之一.简单易用,完整而庞大的第三方库生态圈,使得Python成为编程小白和高级工程师 ...
- C#递归生成HTML树,C#递归生成xml树
C#递归生成HTML树 public StringBuilder str = new StringBuilder(); //定义一个字符串 private void get_navigation_ ...
- .yaml参数文件的编写和使用
一.在ROS底下使用.yaml文件配置参数 在ROS底下用起来还是非常方便的,首先,写一个读参数的函数getParam(),由于参数类型不止一种,所以要使用模板. 具体语句如下: template&l ...
- java-其他-索引
数据结构 设计模式 算法题
- java-网络通信-索引
HTTP协议 关于HTTP协议,一篇就够了 HTTP与HTTPS的区别 HTTP Keep-Alive模式 HTTP长连接和短连接 HTTP的长连接(持久连接)和短连接 HTTP的长连接 ...
- postman引用外部文件中的变量和数据
接口参数显示: 点击collections下文件夹test0424右边的箭头,点击run按钮: DataFile导入txt文件: 预览文件数据: 运行,成功:
- python各种web框架对比
0 引言 python在web开发方面有着广泛的应用.鉴于各种各样的框架,对于开发者来说如何选择将成为一个问题.为此,我特此对比较常见的几种框架从性能.使用感受以及应用情况进行一个粗略的 ...
- 设计在canal中的运用,看到随手记下
观察者模式,定义添加修改删除对应的操作 系统很多Monitor/Listener都是类似 Monitor内含listener,调用再触发 public synchronized void start( ...
- 6993: Dominoes(纯bfs)
题目描述Orz likes to play dominoes. Now giving an n*m chessboard and k dominoes whose size are 1*2, Orz ...