2012-03-23 20:30:31 +00:00
< html >
< head >
< title > CPU - 6502< / title >
< meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" >
2012-08-08 15:00:14 +00:00
< meta name = "generator" content = "HelpNDoc Personal Edition 3.6.0.345" >
2012-03-23 20:30:31 +00:00
< link type = "text/css" rel = "stylesheet" media = "all" href = "css/reset.css" / >
< link type = "text/css" rel = "stylesheet" media = "all" href = "css/base.css" / >
< link type = "text/css" rel = "stylesheet" media = "all" href = "css/hnd.css" / >
<!-- [if lte IE 8]>
< link type = "text/css" rel = "stylesheet" media = "all" href = "css/ielte8.css" / >
<![endif]-->
2012-07-01 14:11:24 +00:00
< style type = "text/css" >
#topic_header
{
background-color: #EFEFEF;
}
< / style >
2012-03-23 20:30:31 +00:00
< script type = "text/javascript" src = "js/jquery.min.js" > < / script >
< script type = "text/javascript" src = "js/hnd.js" > < / script >
2012-08-08 15:00:14 +00:00
< script type = "text/javascript" >
2012-03-23 20:30:31 +00:00
if (top.frames.length == 0)
2012-07-01 14:11:24 +00:00
{
var sTopicUrl = top.location.href.substring(top.location.href.lastIndexOf("/") + 1, top.location.href.length);
top.location.href = "fceux.html?" + sTopicUrl;
}
2012-03-23 20:30:31 +00:00
else if (top & & top.FrameTOC & & top.FrameTOC.SelectTocItem)
2012-07-01 14:11:24 +00:00
{
top.FrameTOC.SelectTocItem("6502CPU");
}
2012-03-23 20:30:31 +00:00
< / script >
< / head >
< body >
< div id = "topic_header" >
< div id = "topic_header_content" >
< h1 > CPU - 6502< / h1 >
< div id = "topic_breadcrumb" >
< a href = "Technicalinformation.html" > Technical Information< / a > › › < a href = "NESProcessor.html" > NES Processing< / a > › › < / div >
< / div >
< div id = "topic_header_nav" >
< a href = "NESProcessor.html" > < img src = "img/arrow_up.png" alt = "Parent" / > < / a >
< a href = "NESProcessor.html" > < img src = "img/arrow_left.png" alt = "Previous" / > < / a >
< a href = "PPU.html" > < img src = "img/arrow_right.png" alt = "Next" / > < / a >
< / div >
< div class = "clear" > < / div >
< / div >
< div id = "topic_content" >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # $Id: 6502_cpu.txt,v 1.1.1.1 2004/08/29 01:29:35 bryan Exp $< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # This file is part of Commodore 64 emulator< / span > < / p >
< p > < span class = "rvts65" > # and Program Development System.< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # See README for copyright notice< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # This file contains documentation for 6502/6510/8500/8502 instruction set.< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Written by< / span > < / p >
< p > < span class = "rvts65" > # John West (john@ucc.gu.uwa.edu.au)< / span > < / p >
< p > < span class = "rvts65" > # Marko MЉkelЉ (msmakela@kruuna.helsinki.fi)< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # $Log: 6502_cpu.txt,v $< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.1.1.1 2004/08/29 01:29:35 bryan< / span > < / p >
< p > < span class = "rvts65" > # no message< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.1 2002/05/21 00:42:27 xodnizel< / span > < / p >
< p > < span class = "rvts65" > # updates< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.8 1994/06/03 19:50:04 jopi< / span > < / p >
< p > < span class = "rvts65" > # Patchlevel 2< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.7 1994/04/15 13:07:04 jopi< / span > < / p >
< p > < span class = "rvts65" > # 65xx Register descriptions added< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.6 1994/02/18 16:09:36 jopi< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.5 1994/01/26 16:08:37 jopi< / span > < / p >
< p > < span class = "rvts65" > # X64 version 0.2 PL 1< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.4 1993/11/10 01:55:34 jopi< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.3 93/06/21 13:37:18 jopi< / span > < / p >
< p > < span class = "rvts65" > # X64 version 0.2 PL 0< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > # Revision 1.2 93/06/21 13:07:15 jopi< / span > < / p >
< p > < span class = "rvts65" > # *** empty log message ***< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > #< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > Note: To extract the uuencoded ML programs in this article most< / p >
< p > easily you may use e.g. "uud" by Edwin Kremer ,< / p >
< p > which extracts them all at once.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Documentation for the NMOS 65xx/85xx Instruction Set< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6510 Instructions by Addressing Modes< / p >
< p > 6502 Registers< / p >
< p > 6510/8502 Undocumented Commands< / p >
< p > Register selection for load and store< / p >
< p > Decimal mode in NMOS 6500 series< / p >
< p > 6510 features< / p >
< p > Different CPU types< / p >
< p > 6510 Instruction Timing< / p >
< p > How Real Programmers Acknowledge Interrupts< / p >
< p > Memory Management< / p >
< p > Autostart Code< / p >
< p > Notes< / p >
< p > References< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6510 Instructions by Addressing Modes< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > off- ++++++++++ Positive ++++++++++ ---------- Negative ----------< / span > < / p >
< p > < span class = "rvts65" > set 00 20 40 60 80 a0 c0 e0 mode< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > +00 BRK JSR RTI RTS NOP* LDY CPY CPX Impl/immed< / span > < / p >
< p > < span class = "rvts65" > +01 ORA AND EOR ADC STA LDA CMP SBC (indir,x)< / span > < / p >
< p > < span class = "rvts65" > +02 t t t t NOP*t LDX NOP*t NOP*t ? /immed< / span > < / p >
< p > < span class = "rvts65" > +03 SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* (indir,x)< / span > < / p >
< p > < span class = "rvts65" > +04 NOP* BIT NOP* NOP* STY LDY CPY CPX Zeropage< / span > < / p >
< p > < span class = "rvts65" > +05 ORA AND EOR ADC STA LDA CMP SBC Zeropage< / span > < / p >
< p > < span class = "rvts65" > +06 ASL ROL LSR ROR STX LDX DEC INC Zeropage< / span > < / p >
< p > < span class = "rvts65" > +07 SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* Zeropage< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > +08 PHP PLP PHA PLA DEY TAY INY INX Implied< / span > < / p >
< p > < span class = "rvts65" > +09 ORA AND EOR ADC NOP* LDA CMP SBC Immediate< / span > < / p >
< p > < span class = "rvts65" > +0a ASL ROL LSR ROR TXA TAX DEX NOP Accu/impl< / span > < / p >
< p > < span class = "rvts65" > +0b ANC** ANC** ASR** ARR** ANE** LXA** SBX** SBC* Immediate< / span > < / p >
< p > < span class = "rvts65" > +0c NOP* BIT JMP JMP () STY LDY CPY CPX Absolute< / span > < / p >
< p > < span class = "rvts65" > +0d ORA AND EOR ADC STA LDA CMP SBC Absolute< / span > < / p >
< p > < span class = "rvts65" > +0e ASL ROL LSR ROR STX LDX DEC INC Absolute< / span > < / p >
< p > < span class = "rvts65" > +0f SLO* RLA* SRE* RRA* SAX* LAX* DCP* ISB* Absolute< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > +10 BPL BMI BVC BVS BCC BCS BNE BEQ Relative< / span > < / p >
< p > < span class = "rvts65" > +11 ORA AND EOR ADC STA LDA CMP SBC (indir),y< / span > < / p >
< p > < span class = "rvts65" > +12 t t t t t t t t ?< / span > < / p >
< p > < span class = "rvts65" > +13 SLO* RLA* SRE* RRA* SHA** LAX* DCP* ISB* (indir),y< / span > < / p >
< p > < span class = "rvts65" > +14 NOP* NOP* NOP* NOP* STY LDY NOP* NOP* Zeropage,x< / span > < / p >
< p > < span class = "rvts65" > +15 ORA AND EOR ADC STA LDA CMP SBC Zeropage,x< / span > < / p >
< p > < span class = "rvts65" > +16 ASL ROL LSR ROR STX y) LDX y) DEC INC Zeropage,x< / span > < / p >
< p > < span class = "rvts65" > +17 SLO* RLA* SRE* RRA* SAX* y) LAX* y) DCP* ISB* Zeropage,x< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > +18 CLC SEC CLI SEI TYA CLV CLD SED Implied< / span > < / p >
< p > < span class = "rvts65" > +19 ORA AND EOR ADC STA LDA CMP SBC Absolute,y< / span > < / p >
< p > < span class = "rvts65" > +1a NOP* NOP* NOP* NOP* TXS TSX NOP* NOP* Implied< / span > < / p >
< p > < span class = "rvts65" > +1b SLO* RLA* SRE* RRA* SHS** LAS** DCP* ISB* Absolute,y< / span > < / p >
< p > < span class = "rvts65" > +1c NOP* NOP* NOP* NOP* SHY** LDY NOP* NOP* Absolute,x< / span > < / p >
< p > < span class = "rvts65" > +1d ORA AND EOR ADC STA LDA CMP SBC Absolute,x< / span > < / p >
< p > < span class = "rvts65" > +1e ASL ROL LSR ROR SHX**y) LDX y) DEC INC Absolute,x< / span > < / p >
< p > < span class = "rvts65" > +1f SLO* RLA* SRE* RRA* SHA**y) LAX* y) DCP* ISB* Absolute,x< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > ROR intruction is available on MC650x microprocessors after< / p >
< p > June, 1976.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Legend:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > t Jams the machine< / p >
< p > *t Jams very rarely< / p >
< p > * Undocumented command< / p >
< p > ** Unusual operation< / p >
< p > y) indexed using Y instead of X< / p >
< p > () indirect instead of absolute< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Note that the NOP instructions do have other addressing modes than the< / p >
< p > implied addressing. The NOP instruction is just like any other load< / p >
< p > instruction, except it does not store the result anywhere nor affects the< / p >
< p > flags.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6502 Registers< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The NMOS 65xx processors are not ruined with too many registers. In addition< / p >
< p > to that, the registers are mostly 8-bit. Here is a brief description of each< / p >
< p > register:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > PC Program Counter< / p >
< p > This register points the address from which the next instruction< / p >
< p > byte (opcode or parameter) will be fetched. Unlike other< / p >
< p > registers, this one is 16 bits in length. The low and high 8-bit< / p >
< p > halves of the register are called PCL and PCH, respectively. The< / p >
< p > Program Counter may be read by pushing its value on the stack.< / p >
< p > This can be done either by jumping to a subroutine or by causing< / p >
< p > an interrupt.< / p >
< p > S Stack pointer< / p >
< p > The NMOS 65xx processors have 256 bytes of stack memory, ranging< / p >
< p > from $0100 to $01FF. The S register is a 8-bit offset to the stack< / p >
< p > page. In other words, whenever anything is being pushed on the< / p >
< p > stack, it will be stored to the address $0100+S.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The Stack pointer can be read and written by transfering its value< / p >
< p > to or from the index register X (see below) with the TSX and TXS< / p >
< p > instructions.< / p >
< p > P Processor status< / p >
< p > This 8-bit register stores the state of the processor. The bits in< / p >
< p > this register are called flags. Most of the flags have something< / p >
< p > to do with arithmetic operations.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The P register can be read by pushing it on the stack (with PHP or< / p >
< p > by causing an interrupt). If you only need to read one flag, you< / p >
< p > can use the branch instructions. Setting the flags is possible by< / p >
< p > pulling the P register from stack or by using the flag set or< / p >
< p > clear instructions.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Following is a list of the flags, starting from the 8th bit of the< / p >
< p > P register (bit 7, value $80):< / p >
< p > N Negative flag< / p >
< p > This flag will be set after any arithmetic operations< / p >
< p > (when any of the registers A, X or Y is being loaded< / p >
< p > with a value). Generally, the N flag will be copied from< / p >
< p > the topmost bit of the register being loaded.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Note that TXS (Transfer X to S) is not an arithmetic< / p >
< p > operation. Also note that the BIT instruction affects< / p >
< p > the Negative flag just like arithmetic operations.< / p >
< p > Finally, the Negative flag behaves differently in< / p >
< p > Decimal operations (see description below).< / p >
< p > V oVerflow flag< / p >
< p > Like the Negative flag, this flag is intended to be used< / p >
< p > with 8-bit signed integer numbers. The flag will be< / p >
< p > affected by addition and subtraction, the instructions< / p >
< p > PLP, CLV and BIT, and the hardware signal -SO. Note that< / p >
< p > there is no SEV instruction, even though the MOS< / p >
< p > engineers loved to use East European abbreviations, like< / p >
< p > DDR (Deutsche Demokratische Republik vs. Data Direction< / p >
< p > Register). (The Russian abbreviation for their former< / p >
< p > trade association COMECON is SEV.) The -SO (Set< / p >
< p > Overflow) signal is available on some processors, at< / p >
< p > least the 6502, to set the V flag. This enables response< / p >
< p > to an I/O activity in equal or less than three clock< / p >
< p > cycles when using a BVC instruction branching to itself< / p >
< p > ($50 $FE).< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The CLV instruction clears the V flag, and the PLP and< / p >
< p > BIT instructions copy the flag value from the bit 6 of< / p >
< p > the topmost stack entry or from memory.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > After a binary addition or subtraction, the V flag will< / p >
< p > be set on a sign overflow, cleared otherwise. What is a< / p >
< p > sign overflow? For instance, if you are trying to add< / p >
< p > 123 and 45 together, the result (168) does not fit in a< / p >
< p > 8-bit signed integer (upper limit 127 and lower limit< / p >
< p > -128). Similarly, adding -123 to -45 causes the< / p >
< p > overflow, just like subtracting -45 from 123 or 123 from< / p >
< p > -45 would do.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Like the N flag, the V flag will not be set as expected< / p >
< p > in the Decimal mode. Later in this document is a precise< / p >
< p > operation description.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > A common misbelief is that the V flag could only be set< / p >
< p > by arithmetic operations, not cleared.< / p >
< p > 1 unused flag< / p >
< p > To the current knowledge, this flag is always 1.< / p >
< p > B Break flag< / p >
< p > This flag is used to distinguish software (BRK)< / p >
< p > interrupts from hardware interrupts (IRQ or NMI). The B< / p >
< p > flag is always set except when the P register is being< / p >
< p > pushed on stack when jumping to an interrupt routine to< / p >
< p > process only a hardware interrupt.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The official NMOS 65xx documentation claims that the BRK< / p >
< p > instruction could only cause a jump to the IRQ vector< / p >
< p > ($FFFE). However, if an NMI interrupt occurs while< / p >
< p > executing a BRK instruction, the processor will jump to< / p >
< p > the NMI vector ($FFFA), and the P register will be< / p >
< p > pushed on the stack with the B flag set.< / p >
< p > D Decimal mode flag< / p >
< p > This flag is used to select the (Binary Coded) Decimal< / p >
< p > mode for addition and subtraction. In most applications,< / p >
< p > the flag is zero.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The Decimal mode has many oddities, and it operates< / p >
< p > differently on CMOS processors. See the description of< / p >
< p > the ADC, SBC and ARR instructions below.< / p >
< p > I Interrupt disable flag< / p >
< p > This flag can be used to prevent the processor from< / p >
< p > jumping to the IRQ handler vector ($FFFE) whenever the< / p >
< p > hardware line -IRQ is active. The flag will be< / p >
< p > automatically set after taking an interrupt, so that the< / p >
< p > processor would not keep jumping to the interrupt< / p >
< p > routine if the -IRQ signal remains low for several clock< / p >
< p > cycles.< / p >
< p > Z Zero flag< / p >
< p > The Zero flag will be affected in the same cases than< / p >
< p > the Negative flag. Generally, it will be set if an< / p >
< p > arithmetic register is being loaded with the value zero,< / p >
< p > and cleared otherwise. The flag will behave differently< / p >
< p > in Decimal operations.< / p >
< p > C Carry flag< / p >
< p > This flag is used in additions, subtractions,< / p >
< p > comparisons and bit rotations. In additions and< / p >
< p > subtractions, it acts as a 9th bit and lets you to chain< / p >
< p > operations to calculate with bigger than 8-bit numbers.< / p >
< p > When subtracting, the Carry flag is the negative of< / p >
< p > Borrow: if an overflow occurs, the flag will be clear,< / p >
< p > otherwise set. Comparisons are a special case of< / p >
< p > subtraction: they assume Carry flag set and Decimal flag< / p >
< p > clear, and do not store the result of the subtraction< / p >
< p > anywhere.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > There are four kinds of bit rotations. All of them store< / p >
< p > the bit that is being rotated off to the Carry flag. The< / p >
< p > left shifting instructions are ROL and ASL. ROL copies< / p >
< p > the initial Carry flag to the lowmost bit of the byte;< / p >
< p > ASL always clears it. Similarly, the ROR and LSR< / p >
< p > instructions shift to the right.< / p >
< p > A Accumulator< / p >
< p > The accumulator is the main register for arithmetic and logic< / p >
< p > operations. Unlike the index registers X and Y, it has a direct< / p >
< p > connection to the Arithmetic and Logic Unit (ALU). This is why< / p >
< p > many operations are only available for the accumulator, not the< / p >
< p > index registers.< / p >
< p > X Index register X< / p >
< p > This is the main register for addressing data with indices. It has< / p >
< p > a special addressing mode, indexed indirect, which lets you to< / p >
< p > have a vector table on the zero page.< / p >
< p > Y Index register Y< / p >
< p > The Y register has the least operations available. On the other< / p >
< p > hand, only it has the indirect indexed addressing mode that< / p >
< p > enables access to any memory place without having to use< / p >
< p > self-modifying code.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6510/8502 Undocumented Commands< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > -- A brief explanation about what may happen while using don't care states.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > ANE $8B A = (A | #$EE) & X & #byte< / span > < / p >
< p > < span class = "rvts65" > same as< / span > < / p >
< p > < span class = "rvts65" > A = ((A & #$11 & X) | ( #$EE & X)) & #byte< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > In real 6510/8502 the internal parameter #$11< / p >
< p > may occasionally be #$10, #$01 or even #$00.< / p >
< p > This occurs when the video chip starts DMA< / p >
< p > between the opcode fetch and the parameter fetch< / p >
< p > of the instruction. The value probably depends< / p >
< p > on the data that was left on the bus by the VIC-II.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > LXA $AB C=Lehti: A = X = ANE< / span > < / p >
< p > < span class = "rvts65" > Alternate: A = X = (A & #byte)< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > TXA and TAX have to be responsible for these.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > SHA $93,$9F Store (A & X & (ADDR_HI + 1))< / span > < / p >
< p > < span class = "rvts65" > SHX $9E Store (X & (ADDR_HI + 1))< / span > < / p >
< p > < span class = "rvts65" > SHY $9C Store (Y & (ADDR_HI + 1))< / span > < / p >
< p > < span class = "rvts65" > SHS $9B SHA and TXS, where X is replaced by (A & X).< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Note: The value to be stored is copied also< / p >
< p > to ADDR_HI if page boundary is crossed.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > SBX $CB Carry and Decimal flags are ignored but the< / p >
< p > Carry flag will be set in substraction. This< / p >
< p > is due to the CMP command, which is executed< / p >
< p > instead of the real SBC.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > ARR $6B This instruction first performs an AND< / p >
< p > between the accumulator and the immediate< / p >
< p > parameter, then it shifts the accumulator to< / p >
< p > the right. However, this is not the whole< / p >
< p > truth. See the description below.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Many undocumented commands do not use AND between registers, the CPU< / p >
< p > just throws the bytes to a bus simultaneously and lets the< / p >
< p > open-collector drivers perform the AND. I.e. the command called 'SAX',< / p >
< p > which is in the STORE section (opcodes $A0...$BF), stores the result< / p >
< p > of (A & X) by this way.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > More fortunate is its opposite, 'LAX' which just loads a byte< / p >
< p > simultaneously into both A and X.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > $6B ARR< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > This instruction seems to be a harmless combination of AND and ROR at< / p >
< p > first sight, but it turns out that it affects the V flag and also has< / p >
< p > a special kind of decimal mode. This is because the instruction has< / p >
< p > inherited some properties of the ADC instruction ($69) in addition to< / p >
< p > the ROR ($6A).< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > In Binary mode (D flag clear), the instruction effectively does an AND< / p >
< p > between the accumulator and the immediate parameter, and then shifts< / p >
< p > the accumulator to the right, copying the C flag to the 8th bit. It< / p >
< p > sets the Negative and Zero flags just like the ROR would. The ADC code< / p >
< p > shows up in the Carry and oVerflow flags. The C flag will be copied< / p >
< p > from the bit 6 of the result (which doesn't seem too logical), and the< / p >
< p > V flag is the result of an Exclusive OR operation between the bit 6< / p >
< p > and the bit 5 of the result. This makes sense, since the V flag will< / p >
< p > be normally set by an Exclusive OR, too.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > In Decimal mode (D flag set), the ARR instruction first performs the< / p >
< p > AND and ROR, just like in Binary mode. The N flag will be copied from< / p >
< p > the initial C flag, and the Z flag will be set according to the ROR< / p >
< p > result, as expected. The V flag will be set if the bit 6 of the< / p >
< p > accumulator changed its state between the AND and the ROR, cleared< / p >
< p > otherwise.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Now comes the funny part. If the low nybble of the AND result,< / p >
< p > incremented by its lowmost bit, is greater than 5, the low nybble in< / p >
< p > the ROR result will be incremented by 6. The low nybble may overflow< / p >
< p > as a consequence of this BCD fixup, but the high nybble won't be< / p >
< p > adjusted. The high nybble will be BCD fixed in a similar way. If the< / p >
< p > high nybble of the AND result, incremented by its lowmost bit, is< / p >
< p > greater than 5, the high nybble in the ROR result will be incremented< / p >
< p > by 6, and the Carry flag will be set. Otherwise the C flag will be< / p >
< p > cleared.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > To help you understand this description, here is a C routine that< / p >
< p > illustrates the ARR operation in Decimal mode:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > unsigned< / span > < / p >
< p > < span class = "rvts65" > A, /* Accumulator */< / span > < / p >
< p > < span class = "rvts65" > AL, /* low nybble of accumulator */< / span > < / p >
< p > < span class = "rvts65" > AH, /* high nybble of accumulator */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > C, /* Carry flag */< / span > < / p >
< p > < span class = "rvts65" > Z, /* Zero flag */< / span > < / p >
< p > < span class = "rvts65" > V, /* oVerflow flag */< / span > < / p >
< p > < span class = "rvts65" > N, /* Negative flag */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > t, /* temporary value */< / span > < / p >
< p > < span class = "rvts65" > s; /* value to be ARRed with Accumulator */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > t = A & s; /* Perform the AND. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > AH = t > > 4; /* Separate the high */< / span > < / p >
< p > < span class = "rvts65" > AL = t & 15; /* and low nybbles. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > N = C; /* Set the N and */< / span > < / p >
< p > < span class = "rvts65" > Z = !(A = (t > > 1) | (C < < 7)); /* Z flags traditionally */< / span > < / p >
< p > < span class = "rvts65" > V = (t ^ A) & 64; /* and V flag in a weird way. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > if (AL + (AL & 1) > 5) /* BCD "fixup" for low nybble. */< / span > < / p >
< p > < span class = "rvts65" > A = (A & 0xF0) | ((A + 6) & 0xF);< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > if (C = AH + (AH & 1) > 5) /* Set the Carry flag. */< / span > < / p >
< p > < span class = "rvts65" > A = (A + 0x60) & 0xFF; /* BCD "fixup" for high nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > $CB SBX X < - (A & X) - Immediate< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > The 'SBX' ($CB) may seem to be very complex operation, even though it< / p >
< p > is a combination of the subtraction of accumulator and parameter, as< / p >
< p > in the 'CMP' instruction, and the command 'DEX'. As a result, both A< / p >
< p > and X are connected to ALU but only the subtraction takes place. Since< / p >
< p > the comparison logic was used, the result of subtraction should be< / p >
< p > normally ignored, but the 'DEX' now happily stores to X the value of< / p >
< p > (A & X) - Immediate. That is why this instruction does not have any< / p >
< p > decimal mode, and it does not affect the V flag. Also Carry flag will< / p >
< p > be ignored in the subtraction but set according to the result.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Proof:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > begin 644 vsbx< / span > < / p >
< p > < span class = "rvts65" > M`0@9$,D'GL(H-#,IJC(U-JS"*#0T*:HR-@```*D`H#V1*Z`_D2N@09$KJ0> %< / span > < / p >
< p > < span class = "rvts65" > M^QBE^VEZJ+$KH#F1*ZD`2"BI`*(`RP`(:-B@.5$K*4#P`E@`H#VQ*SAI`)$K< / span > < / p >
< p > < span class = "rvts65" > JD-Z@/[$K:0"1*Y#4J2X@TO\XH$& Q*VD`D2N0Q,;[$+188/_^]_:_OK> V< / span > < / p >
< p > < span class = "rvts65" > `< / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > and< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > begin 644 sbx< / span > < / p >
< p > < span class = "rvts65" > M`0@9$,D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI`*!-D2N@3Y$KH%& 1*ZD#< / span > < / p >
< p > < span class = "rvts65" > MA?L8I?M*2)`#J1@LJ3B@29$K:$J0`ZGX+*G8R)$K& /BXJ?2B8\L)AOP(:(7]< / span > < / p >
< p > < span class = "rvts65" > MV#B@3;$KH$\Q*Z!1\2L(1?SP`0!H1?TIM]#XH$VQ*SAI`)$KD,N@3[$K:0"1< / span > < / p >
< p > < span class = "rvts65" > 9*Y#!J2X@TO\XH%& Q*VD`D2N0L< ;[$))88-#X< / span > < / p >
< p > < span class = "rvts65" > `< / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > These test programs show if your machine is compatible with ours< / p >
< p > regarding the opcode $CB. The first test, vsbx, proves that SBX does< / p >
< p > not affect the V flag. The latter one, sbx, proves the rest of our< / p >
< p > theory. The vsbx test tests 33554432 SBX combinations (16777216< / p >
< p > different A, X and Immediate combinations, and two different V flag< / p >
< p > states), and the sbx test doubles that amount (16777216*4 D and C flag< / p >
< p > combinations). Both tests have run successfully on a C64 and a Vic20.< / p >
< p > They ought to run on C16, +4 and the PET series as well. The tests< / p >
< p > stop with BRK, if the opcode $CB does not work as expected. Successful< / p >
< p > operation ends in RTS. As the tests are very slow, they print dots on< / p >
< p > the screen while running so that you know that the machine has not< / p >
< p > jammed. On computers running at 1 MHz, the first test prints< / p >
< p > approximately one dot every four seconds and a total of 2048 dots,< / p >
< p > whereas the second one prints half that amount, one dot every seven< / p >
< p > seconds.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > If the tests fail on your machine, please let us know your processor's< / p >
< p > part number and revision. If possible, save the executable (after it< / p >
< p > has stopped with BRK) under another name and send it to us so that we< / p >
< p > know at which stage the program stopped.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The following program is a Commodore 64 executable that Marko M"akel"a< / p >
< p > developed when trying to find out how the V flag is affected by SBX.< / p >
< p > (It was believed that the SBX affects the flag in a weird way, and< / p >
< p > this program shows how SBX sets the flag differently from SBC.) You< / p >
< p > may find the subroutine at $C150 useful when researching other< / p >
< p > undocumented instructions' flags. Run the program in a machine< / p >
< p > language monitor, as it makes use of the BRK instruction. The result< / p >
< p > tables will be written on pages $C2 and $C3.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > begin 644 sbx-c100< / span > < / p >
< p > < span class = "rvts65" > M`,%XH`",#L& ,$,& ,$L& XJ8*B@LL7AOL(:(7\N#BM#L$M$,'M$L$(Q?OP`B@`< / span > < / p >
< p > < span class = "rvts65" > M:$7\\`,@4,'N#L'0U.X0P=#/SB#0[A+!T,< ``````````````)BJ\!> M#L$M< / span > < / p >
< p > < span class = "rvts65" > L$,'=_\'0":T2P=W_PM`!8,K0Z:T.P2T0P9D`PID`!*T2P9D`PYD`!< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Other undocumented instructions usually cause two preceding opcodes< / p >
< p > being executed. However 'NOP' seems to completely disappear from 'SBC'< / p >
< p > code $EB.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The most difficult to comprehend are the rest of the instructions< / p >
< p > located on the '$0B' line.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > All the instructions located at the positive (left) side of this line< / p >
< p > should rotate either memory or the accumulator, but the addressing< / p >
< p > mode turns out to be immediate! No problem. Just read the operand, let< / p >
< p > it be ANDed with the accumulator and finally use accumulator< / p >
< p > addressing mode for the instructions above them.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > RELIGION_MODE_ON< / p >
< p > /* This part of the document is not accurate. You can< / p >
< p > read it as a fairy tale, but do not count on it when< / p >
< p > performing your own measurements. */< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The rest two instructions on the same line, called 'ANE' and 'LXA'< / p >
< p > ($8B and $AB respectively) often give quite unpredictable results.< / p >
< p > However, the most usual operation is to store ((A | #$ee) & X & #$nn)< / p >
< p > to accumulator. Note that this does not work reliably in a real 64!< / p >
< p > In the Commodore 128 the opcode $8B uses values 8C, CC, EE, and< / p >
< p > occasionally 0C and 8E for the OR instead of EE,EF,FE and FF used in< / p >
< p > the C64. With a C128 running at 2 MHz #$EE is always used. Opcode $AB< / p >
< p > does not cause this OR taking place on 8502 while 6510 always performs< / p >
< p > it. Note that this behaviour depends on processor and/or video chip< / p >
< p > revision.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Let's take a closer look at $8B (6510).< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > A < - X & D & (A | VAL)< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > where VAL comes from this table:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > X high D high D low VAL< / p >
< p > even even --- $EE (1)< / p >
< p > even odd --- $EE< / p >
< p > odd even --- $EE< / p >
< p > odd odd 0 $EE< / p >
< p > odd odd not 0 $FE (2)< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > (1) If the bottom 2 bits of A are both 1, then the LSB of the result may< / p >
< p > be 0. The values of X and D are different every time I run the test.< / p >
< p > This appears to be very rare.< / p >
< p > (2) VAL is $FE most of the time. Sometimes it is $EE - it seems to be random,< / p >
< p > not related to any of the data. This is much more common than (1).< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > In decimal mode, VAL is usually $FE.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Two different functions have been discovered for LAX, opcode $AB. One< / p >
< p > is A = X = ANE (see above) and the other, encountered with 6510 and< / p >
< p > 8502, is less complicated A = X = (A & #byte). However, according to< / p >
< p > what is reported, the version altering only the lowest bits of each< / p >
< p > nybble seems to be more common.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > What happens, is that $AB loads a value into both A and X, ANDing the< / p >
< p > low bit of each nybble with the corresponding bit of the old< / p >
< p > A. However, there are exceptions. Sometimes the low bit is cleared< / p >
< p > even when A contains a '1', and sometimes other bits are cleared. The< / p >
< p > exceptions seem random (they change every time I run the test). Oops -< / p >
< p > that was in decimal mode. Much the same with D=0.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > What causes the randomness? Probably it is that it is marginal logic< / p >
< p > levels - when too much wired-anding goes on, some of the signals get< / p >
< p > very close to the threshold. Perhaps we're seeing some of them step< / p >
< p > over it. The low bit of each nybble is special, since it has to cope< / p >
< p > with carry differently (remember decimal mode). We never see a '0'< / p >
< p > turn into a '1'.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Since these instructions are unpredictable, they should not be used.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > There is still very strange instruction left, the one named SHA/X/Y,< / p >
< p > which is the only one with only indexed addressing modes. Actually,< / p >
< p > the commands 'SHA', 'SHX' and 'SHY' are generated by the indexing< / p >
< p > algorithm.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > While using indexed addressing, effective address for page boundary< / p >
< p > crossing is calculated as soon as possible so it does not slow down< / p >
< p > operation. As a result, in the case of SHA/X/Y, the address and data< / p >
< p > are processed at the same time making AND between them to take place.< / p >
< p > Thus, the value to be stored by SAX, for example, is in fact (A & X & < / p >
< p > (ADDR_HI + 1)). On page boundary crossing the same value is copied< / p >
< p > also to high byte of the effective address.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > RELIGION_MODE_OFF< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Register selection for load and store< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > bit1 bit0 A X Y< / span > < / p >
< p > < span class = "rvts65" > 0 0 x< / span > < / p >
< p > < span class = "rvts65" > 0 1 x< / span > < / p >
< p > < span class = "rvts65" > 1 0 x< / span > < / p >
< p > < span class = "rvts65" > 1 1 x x< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > So, A and X are selected by bits 1 and 0 respectively, while< / p >
< p > ~(bit1|bit0) enables Y.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Indexing is determined by bit4, even in relative addressing mode,< / p >
< p > which is one kind of indexing.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Lines containing opcodes xxx000x1 (01 and 03) are treated as absolute< / p >
< p > after the effective address has been loaded into CPU.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Zeropage,y and Absolute,y (codes 10x1 x11x) are distinquished by bit5.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Decimal mode in NMOS 6500 series< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Most sources claim that the NMOS 6500 series sets the N, V and Z< / p >
< p > flags unpredictably when performing addition or subtraction in decimal< / p >
< p > mode. Of course, this is not true. While testing how the flags are< / p >
< p > set, I also wanted to see what happens if you use illegal BCD values.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > ADC works in Decimal mode in a quite complicated way. It is amazing< / p >
< p > how it can do that all in a single cycle. Here's a C code version of< / p >
< p > the instruction:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > unsigned< / span > < / p >
< p > < span class = "rvts65" > A, /* Accumulator */< / span > < / p >
< p > < span class = "rvts65" > AL, /* low nybble of accumulator */< / span > < / p >
< p > < span class = "rvts65" > AH, /* high nybble of accumulator */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > C, /* Carry flag */< / span > < / p >
< p > < span class = "rvts65" > Z, /* Zero flag */< / span > < / p >
< p > < span class = "rvts65" > V, /* oVerflow flag */< / span > < / p >
< p > < span class = "rvts65" > N, /* Negative flag */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > s; /* value to be added to Accumulator */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > AL = (A & 15) + (s & 15) + C; /* Calculate the lower nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > AH = (A > > 4) + (s > > 4) + (AL > 15); /* Calculate the upper nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > if (AL > 9) AL += 6; /* BCD fixup for lower nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Z = ((A + s + C) & 255 != 0); /* Zero flag is set just< / span > < / p >
< p > < span class = "rvts65" > like in Binary mode. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > /* Negative and Overflow flags are set with the same logic than in< / span > < / p >
< p > < span class = "rvts65" > Binary mode, but after fixing the lower nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > N = (AH & 8 != 0);< / span > < / p >
< p > < span class = "rvts65" > V = ((AH < < 4) ^ A) & 128 & & !((A ^ s) & 128);< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > if (AH > 9) AH += 6; /* BCD fixup for upper nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > /* Carry is the only flag set after fixing the result. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > C = (AH > 15);< / span > < / p >
< p > < span class = "rvts65" > A = ((AH < < 4) | (AL & 15)) & 255;< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The C flag is set as the quiche eaters expect, but the N and V flags< / p >
< p > are set after fixing the lower nybble but before fixing the upper one.< / p >
< p > They use the same logic than binary mode ADC. The Z flag is set before< / p >
< p > any BCD fixup, so the D flag does not have any influence on it.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Proof: The following test program tests all 131072 ADC combinations in< / p >
< p > Decimal mode, and aborts with BRK if anything breaks this theory.< / p >
< p > If everything goes well, it ends in RTS.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > begin 600 dadc< / span > < / p >
< p > < span class = "rvts65" > M 0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@ 'BI& * A/N$_$B@+)$KH(V1< / span > < / p >
< p > < span class = "rvts65" > M*Q@(I?PI#X7]I?LI#V7]R0J0 FD%J"D/A?VE^RGP9?PI\ C $) ":0^JL @H< / span > < / p >
< p > < span class = "rvts65" > ML ?)H) & ""@X:5\X!?V%_0AH*3W@ ! ""8"HBD7[$ JE^T7\, 28"4"H**7[< / span > < / p >
< p > < span class = "rvts65" > M9?S0!)@) J@8N/BE^V7\V A%_= G:(3]1?W0(.;[T(?F_-"#:$D8\ )88*D=< / span > < / p >
< p > < span class = "rvts65" > 0& & 4KA?NI & 4LA?RI.& S[ A%< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > All programs in this chapter have been successfully tested on a Vic20< / p >
< p > and a Commodore 64 and a Commodore 128D in C64 mode. They should run on< / p >
< p > C16, +4 and on the PET series as well. If not, please report the problem< / p >
< p > to Marko M"akel"a. Each test in this chapter should run in less than a< / p >
< p > minute at 1 MHz.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > SBC is much easier. Just like CMP, its flags are not affected by< / p >
< p > the D flag.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Proof:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > begin 600 dsbc-cmp-flags< / span > < / p >
< p > < span class = "rvts65" > M 0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@ 'B@ (3[A/RB XH8:66HL2N@< / span > < / p >
< p > < span class = "rvts65" > M09$KH$R1*XII::BQ*Z!%D2N@4)$K^#BXI?OE_-@(:(7].+BE^^7\"& A%_? !< / span > < / p >
< p > < span class = "rvts65" > 5 .;[T./F_-#?RA"_8!@X& #CEY< 7%< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The only difference in SBC's operation in decimal mode from binary mode< / p >
< p > is the result-fixup:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > unsigned< / span > < / p >
< p > < span class = "rvts65" > A, /* Accumulator */< / span > < / p >
< p > < span class = "rvts65" > AL, /* low nybble of accumulator */< / span > < / p >
< p > < span class = "rvts65" > AH, /* high nybble of accumulator */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > C, /* Carry flag */< / span > < / p >
< p > < span class = "rvts65" > Z, /* Zero flag */< / span > < / p >
< p > < span class = "rvts65" > V, /* oVerflow flag */< / span > < / p >
< p > < span class = "rvts65" > N, /* Negative flag */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > s; /* value to be added to Accumulator */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > AL = (A & 15) - (s & 15) - !C; /* Calculate the lower nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > if (AL & 16) AL -= 6; /* BCD fixup for lower nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > AH = (A > > 4) - (s > > 4) - (AL & 16); /* Calculate the upper nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > if (AH & 16) AH -= 6; /* BCD fixup for upper nybble. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > /* The flags are set just like in Binary mode. */< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > C = (A - s - !C) & 256 != 0;< / span > < / p >
< p > < span class = "rvts65" > Z = (A - s - !C) & 255 != 0;< / span > < / p >
< p > < span class = "rvts65" > V = ((A - s - !C) ^ s) & 128 & & (A ^ s) & 128;< / span > < / p >
< p > < span class = "rvts65" > N = (A - s - !C) & 128 != 0;< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > A = ((AH < < 4) | (AL & 15)) & 255;< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > Again Z flag is set before any BCD fixup. The N and V flags are set< / p >
< p > at any time before fixing the high nybble. The C flag may be set in any< / p >
< p > phase.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Decimal subtraction is easier than decimal addition, as you have to< / p >
< p > make the BCD fixup only when a nybble overflows. In decimal addition,< / p >
< p > you had to verify if the nybble was greater than 9. The processor has< / p >
< p > an internal "half carry" flag for the lower nybble, used to trigger< / p >
< p > the BCD fixup. When calculating with legal BCD values, the lower nybble< / p >
< p > cannot overflow again when fixing it.< / p >
< p > So, the processor does not handle overflows while performing the fixup.< / p >
< p > Similarly, the BCD fixup occurs in the high nybble only if the value< / p >
< p > overflows, i.e. when the C flag will be cleared.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Because SBC's flags are not affected by the Decimal mode flag, you< / p >
< p > could guess that CMP uses the SBC logic, only setting the C flag< / p >
< p > first. But the SBX instruction shows that CMP also temporarily clears< / p >
< p > the D flag, although it is totally unnecessary.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The following program, which tests SBC's result and flags,< / p >
< p > contains the 6502 version of the pseudo code example above.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > begin 600 dsbc< / span > < / p >
< p > < span class = "rvts65" > M 0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@ 'BI& * A/N$_$B@+)$KH':1< / span > < / p >
< p > < span class = "rvts65" > M*S@(I?PI#X7]I?LI#^7]L /I!1@I#ZBE_"GPA?VE^RGP"#CE_2GPL KI7RBP< / span > < / p >
< p > < span class = "rvts65" > M#ND/.+ )*+ & Z0^P NE?A/T%_87]*+BE^^7\"& BH.+CXI?OE_-@(1?W0FVB$< / span > < / p >
< p > < span class = "rvts65" > 8_47]T)3F^]"> YOS0FFA)& - $J3C0B%A@< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Obviously the undocumented instructions RRA (ROR+ADC) and ISB< / p >
< p > (INC+SBC) have inherited also the decimal operation from the official< / p >
< p > instructions ADC and SBC. The program droradc proves this statement< / p >
< p > for ROR, and the dincsbc test proves this for ISB. Finally,< / p >
< p > dincsbc-deccmp proves that ISB's and DCP's (DEC+CMP) flags are not< / p >
< p > affected by the D flag.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > begin 644 droradc< / span > < / p >
< p > < span class = "rvts65" > M`0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI& *``A/N$_$B@+)$KH(V1< / span > < / p >
< p > < span class = "rvts65" > M*S@(I?PI#X7]I?LI#V7]R0J0`FD%J"D/A?VE^RGP9?PI\`C`$)`":0^JL`@H< / span > < / p >
< p > < span class = "rvts65" > ML`?)H)`& ""@X:5\X!?V%_0AH*3W@`!`""8"HBD7[$`JE^T7\,`28"4"H**7[< / span > < / p >
< p > < span class = "rvts65" > M9?S0!)@)`J@XN/BE^R;\9_S8"$7]T"=HA/U%_=`@YOO0A> ;\T(%H21CP`EA@< / span > < / p >
< p > < span class = "rvts65" > 2J1T892N%^ZD`92R%_*DX;/L`< / span > < / p >
< p > < span class = "rvts65" > `< / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > begin 644 dincsbc< / span > < / p >
< p > < span class = "rvts65" > M`0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'BI& *``A/N$_$B@+)$KH':1< / span > < / p >
< p > < span class = "rvts65" > M*S@(I?PI#X7]I?LI#^7]L`/I!1@I#ZBE_"GPA?VE^RGP"#CE_2GPL`KI7RBP< / span > < / p >
< p > < span class = "rvts65" > M#ND/.+`)*+`& Z0^P`NE?A/T%_87]*+BE^^7\"& BH.+CXI?O& _.?\V`A%_="9< / span > < / p >
< p > < span class = "rvts65" > ::(3]1?W0DN;[T)SF_-"8:$D8T`2I.-"& 6& #\< / span > < / p >
< p > < span class = "rvts65" > `< / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > begin 644 dincsbc-deccmp< / span > < / p >
< p > < span class = "rvts65" > M`0@9",D'GL(H-#,IJC(U-JS"*#0T*:HR-@```'B@`(3[A/RB`XH8:7> HL2N@< / span > < / p >
< p > < span class = "rvts65" > M3Y$KH%R1*XII> ZBQ*Z!3D2N@8)$KBFE_J+$KH%61*Z!BD2OX.+BE^^;\Q_S8< / span > < / p >
< p > < span class = "rvts65" > L"& B%_3BXI?OF_,?\"& A%_?`!`.;[T-_F_-#;RA"M8!@X& #CFYL;& Q\?GYP#8< / span > < / p >
< p > < span class = "rvts65" > `< / span > < / p >
< p > < span class = "rvts65" > end< / span > < / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6510 features< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o PHP always pushes the Break (B) flag as a `1' to the stack.< / p >
< p > Jukka Tapanim"aki claimed in C=lehti issue 3/89, on page 27 that the< / p >
< p > processor makes a logical OR between the status register's bit 4< / p >
< p > and the bit 8 of the stack pointer register (which is always 1).< / p >
< p > He did not give any reasons for this argument, and has refused to clarify< / p >
< p > it afterwards. Well, this was not the only error in his article...< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o Indirect addressing modes do not handle page boundary crossing at all.< / p >
< p > When the parameter's low byte is $FF, the effective address wraps< / p >
< p > around and the CPU fetches high byte from $xx00 instead of $xx00+$0100.< / p >
< p > E.g. JMP ($01FF) fetches PCL from $01FF and PCH from $0100,< / p >
< p > and LDA ($FF),Y fetches the base address from $FF and $00.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o Indexed zero page addressing modes never fix the page address on< / p >
< p > crossing the zero page boundary.< / p >
< p > E.g. LDX #$01 : LDA ($FF,X) loads the effective address from $00 and $01.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o The processor always fetches the byte following a relative branch< / p >
< p > instruction. If the branch is taken, the processor reads then the< / p >
< p > opcode from the destination address. If page boundary is crossed, it< / p >
< p > first reads a byte from the old page from a location that is bigger< / p >
< p > or smaller than the correct address by one page.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o If you cross a page boundary in any other indexed mode,< / p >
< p > the processor reads an incorrect location first, a location that is< / p >
< p > smaller by one page.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o Read-Modify-Write instructions write unmodified data, then modified< / p >
< p > (so INC effectively does LDX loc;STX loc;INX;STX loc)< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o -RDY is ignored during writes< / p >
< p > (This is why you must wait 3 cycles before doing any DMA --< / p >
< p > the maximum number of consecutive writes is 3, which occurs< / p >
< p > during interrupts except -RESET.)< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o Some undefined opcodes may give really unpredictable results.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > o All registers except the Program Counter remain unmodified after -RESET.< / p >
< p > (This is why you must preset D and I flags in the RESET handler.)< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Different CPU types< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The Rockwell data booklet 29651N52 (technical information about R65C00< / p >
< p > microprocessors, dated October 1984), lists the following differences between< / p >
< p > NMOS R6502 microprocessor and CMOS R65C00 family:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 1. Indexed addressing across page boundary.< / p >
< p > NMOS: Extra read of invalid address.< / p >
< p > CMOS: Extra read of last instruction byte.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 2. Execution of invalid op codes.< / p >
< p > NMOS: Some terminate only by reset. Results are undefined.< / p >
< p > CMOS: All are NOPs (reserved for future use).< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 3. Jump indirect, operand = XXFF.< / p >
< p > NMOS: Page address does not increment.< / p >
< p > CMOS: Page address increments and adds one additional cycle.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 4. Read/modify/write instructions at effective address.< / p >
< p > NMOS: One read and two write cycles.< / p >
< p > CMOS: Two read and one write cycle.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 5. Decimal flag.< / p >
< p > NMOS: Indeterminate after reset.< / p >
< p > CMOS: Initialized to binary mode (D=0) after reset and interrupts.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6. Flags after decimal operation.< / p >
< p > NMOS: Invalid N, V and Z flags.< / p >
< p > CMOS: Valid flag adds one additional cycle.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 7. Interrupt after fetch of BRK instruction.< / p >
< p > NMOS: Interrupt vector is loaded, BRK vector is ignored.< / p >
< p > CMOS: BRK is executed, then interrupt is executed.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > 6510 Instruction Timing< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The NMOS 6500 series processors always perform at least two reads< / p >
< p > for each instruction. In addition to the operation code (opcode), they< / p >
< p > fetch the next byte. This is quite efficient, as most instructions are< / p >
< p > two or three bytes long.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The processors also use a sort of pipelining. If an instruction does< / p >
< p > not store data in memory on its last cycle, the processor can fetch< / p >
< p > the opcode of the next instruction while executing the last cycle. For< / p >
< p > instance, the instruction EOR #$FF truly takes three cycles. On the< / p >
< p > first cycle, the opcode $49 will be fetched. During the second cycle< / p >
< p > the processor decodes the opcode and fetches the parameter #$FF. On< / p >
< p > the third cycle, the processor will perform the operation and store< / p >
< p > the result to accumulator, but simultaneously it fetches the opcode< / p >
< p > for the next instruction. This is why the instruction effectively< / p >
< p > takes only two cycles.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The following tables show what happens on the bus while executing< / p >
< p > different kinds of instructions.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Interrupts< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > NMI and IRQ both take 7 cycles. Their timing diagram is much like< / p >
< p > BRK's (see below). IRQ will be executed only when the I flag is< / p >
< p > clear. IRQ and BRK both set the I flag, whereas the NMI does not< / p >
< p > affect its state.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The processor will usually wait for the current instruction to< / p >
< p > complete before executing the interrupt sequence. To process the< / p >
< p > interrupt before the next instruction, the interrupt must occur< / p >
< p > before the last cycle of the current instruction.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > There is one exception to this rule: the BRK instruction. If a< / p >
< p > hardware interrupt (NMI or IRQ) occurs before the fourth (flags< / p >
< p > saving) cycle of BRK, the BRK instruction will be skipped, and< / p >
< p > the processor will jump to the hardware interrupt vector. This< / p >
< p > sequence will always take 7 cycles.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > You do not completely lose the BRK interrupt, the B flag will be< / p >
< p > set in the pushed status register if a BRK instruction gets< / p >
< p > interrupted. When BRK and IRQ occur at the same time, this does< / p >
< p > not cause any problems, as your program will consider it as a< / p >
< p > BRK, and the IRQ would occur again after the processor returned< / p >
< p > from your BRK routine, unless you cleared the interrupt source in< / p >
< p > your BRK handler. But the simultaneous occurrence of NMI and BRK< / p >
< p > is far more fatal. If you do not check the B flag in the NMI< / p >
< p > routine and subtract two from the return address when needed, the< / p >
< p > BRK instruction will be skipped.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > If the NMI and IRQ interrupts overlap each other (one interrupt< / p >
< p > occurs before fetching the interrupt vector for the other< / p >
< p > interrupt), the processor will most probably jump to the NMI< / p >
< p > vector in every case, and then jump to the IRQ vector after< / p >
< p > processing the first instruction of the NMI handler. This has not< / p >
< p > been measured yet, but the IRQ is very similar to BRK, and many< / p >
< p > sources state that the NMI has higher priority than IRQ. However,< / p >
< p > it might be that the processor takes the interrupt that comes< / p >
< p > later, i.e. you could lose an NMI interrupt if an IRQ occurred in< / p >
< p > four cycles after it.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > After finishing the interrupt sequence, the processor will start< / p >
< p > to execute the first instruction of the interrupt routine. This< / p >
< p > proves that the processor uses a sort of pipelining: it finishes< / p >
< p > the current instruction (or interrupt sequence) while reading the< / p >
< p > opcode of the next instruction.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > RESET does not push program counter on stack, and it lasts< / p >
< p > probably 6 cycles after deactivating the signal. Like NMI, RESET< / p >
< p > preserves all registers except PC.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Instructions accessing the stack< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > BRK< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -----------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R read next instruction byte (and throw it away),< / span > < / p >
< p > < span class = "rvts65" > increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 $0100,S W push PCH on stack (with B flag set), decrement S< / span > < / p >
< p > < span class = "rvts65" > 4 $0100,S W push PCL on stack, decrement S< / span > < / p >
< p > < span class = "rvts65" > 5 $0100,S W push P on stack, decrement S< / span > < / p >
< p > < span class = "rvts65" > 6 $FFFE R fetch PCL< / span > < / p >
< p > < span class = "rvts65" > 7 $FFFF R fetch PCH< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > RTI< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -----------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R read next instruction byte (and throw it away)< / span > < / p >
< p > < span class = "rvts65" > 3 $0100,S R increment S< / span > < / p >
< p > < span class = "rvts65" > 4 $0100,S R pull P from stack, increment S< / span > < / p >
< p > < span class = "rvts65" > 5 $0100,S R pull PCL from stack, increment S< / span > < / p >
< p > < span class = "rvts65" > 6 $0100,S R pull PCH from stack< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > RTS< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -----------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R read next instruction byte (and throw it away)< / span > < / p >
< p > < span class = "rvts65" > 3 $0100,S R increment S< / span > < / p >
< p > < span class = "rvts65" > 4 $0100,S R pull PCL from stack, increment S< / span > < / p >
< p > < span class = "rvts65" > 5 $0100,S R pull PCH from stack< / span > < / p >
< p > < span class = "rvts65" > 6 PC R increment PC< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > PHA, PHP< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -----------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R read next instruction byte (and throw it away)< / span > < / p >
< p > < span class = "rvts65" > 3 $0100,S W push register on stack, decrement S< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > PLA, PLP< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -----------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R read next instruction byte (and throw it away)< / span > < / p >
< p > < span class = "rvts65" > 3 $0100,S R increment S< / span > < / p >
< p > < span class = "rvts65" > 4 $0100,S R pull register from stack< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > JSR< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -------------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low address byte, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 $0100,S R internal operation (predecrement S?)< / span > < / p >
< p > < span class = "rvts65" > 4 $0100,S W push PCH on stack, decrement S< / span > < / p >
< p > < span class = "rvts65" > 5 $0100,S W push PCL on stack, decrement S< / span > < / p >
< p > < span class = "rvts65" > 6 PC R copy low address byte to PCL, fetch high address< / span > < / p >
< p > < span class = "rvts65" > byte to PCH< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Accumulator or implied addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -----------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R read next instruction byte (and throw it away)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Immediate addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch value, increment PC< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Absolute addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > JMP< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- -------------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low address byte, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R copy low address byte to PCL, fetch high address< / span > < / p >
< p > < span class = "rvts65" > byte to PCH< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,< / span > < / p >
< p > < span class = "rvts65" > LAX, NOP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch high byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 address R read from effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,< / span > < / p >
< p > < span class = "rvts65" > SLO, SRE, RLA, RRA, ISB, DCP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch high byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 address R read from effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address W write the value back to effective address,< / span > < / p >
< p > < span class = "rvts65" > and do the operation on it< / span > < / p >
< p > < span class = "rvts65" > 6 address W write the new value to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Write instructions (STA, STX, STY, SAX)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch high byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 address W write register to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Zero page addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,< / span > < / p >
< p > < span class = "rvts65" > LAX, NOP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 address R read from effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,< / span > < / p >
< p > < span class = "rvts65" > SLO, SRE, RLA, RRA, ISB, DCP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 address R read from effective address< / span > < / p >
< p > < span class = "rvts65" > 4 address W write the value back to effective address,< / span > < / p >
< p > < span class = "rvts65" > and do the operation on it< / span > < / p >
< p > < span class = "rvts65" > 5 address W write the new value to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Write instructions (STA, STX, STY, SAX)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 address W write register to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Zero page indexed addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,< / span > < / p >
< p > < span class = "rvts65" > LAX, NOP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 address R read from address, add index register to it< / span > < / p >
< p > < span class = "rvts65" > 4 address+I* R read from effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: I denotes either index register (X or Y).< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address is always zero,< / span > < / p >
< p > < span class = "rvts65" > i.e. page boundary crossings are not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,< / span > < / p >
< p > < span class = "rvts65" > SLO, SRE, RLA, RRA, ISB, DCP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ---------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 address R read from address, add index register X to it< / span > < / p >
< p > < span class = "rvts65" > 4 address+X* R read from effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address+X* W write the value back to effective address,< / span > < / p >
< p > < span class = "rvts65" > and do the operation on it< / span > < / p >
< p > < span class = "rvts65" > 6 address+X* W write the new value to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Note: * The high byte of the effective address is always zero,< / span > < / p >
< p > < span class = "rvts65" > i.e. page boundary crossings are not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Write instructions (STA, STX, STY, SAX)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- -------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 address R read from address, add index register to it< / span > < / p >
< p > < span class = "rvts65" > 4 address+I* W write to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: I denotes either index register (X or Y).< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address is always zero,< / span > < / p >
< p > < span class = "rvts65" > i.e. page boundary crossings are not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Absolute indexed addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,< / span > < / p >
< p > < span class = "rvts65" > LAX, LAE, SHS, NOP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch high byte of address,< / span > < / p >
< p > < span class = "rvts65" > add index register to low address byte,< / span > < / p >
< p > < span class = "rvts65" > increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 address+I* R read from effective address,< / span > < / p >
< p > < span class = "rvts65" > fix the high byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 5+ address+I R re-read from effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: I denotes either index register (X or Y).< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller by $100.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > + This cycle will be executed only if the effective address< / span > < / p >
< p > < span class = "rvts65" > was invalid during cycle #4, i.e. page boundary was crossed.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,< / span > < / p >
< p > < span class = "rvts65" > SLO, SRE, RLA, RRA, ISB, DCP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch high byte of address,< / span > < / p >
< p > < span class = "rvts65" > add index register X to low address byte,< / span > < / p >
< p > < span class = "rvts65" > increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 address+X* R read from effective address,< / span > < / p >
< p > < span class = "rvts65" > fix the high byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address+X R re-read from effective address< / span > < / p >
< p > < span class = "rvts65" > 6 address+X W write the value back to effective address,< / span > < / p >
< p > < span class = "rvts65" > and do the operation on it< / span > < / p >
< p > < span class = "rvts65" > 7 address+X W write the new value to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: * The high byte of the effective address may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller by $100.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Write instructions (STA, STX, STY, SHA, SHX, SHY)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch low byte of address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch high byte of address,< / span > < / p >
< p > < span class = "rvts65" > add index register to low address byte,< / span > < / p >
< p > < span class = "rvts65" > increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 address+I* R read from effective address,< / span > < / p >
< p > < span class = "rvts65" > fix the high byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address+I W write to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: I denotes either index register (X or Y).< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller by $100. Because< / span > < / p >
< p > < span class = "rvts65" > the processor cannot undo a write to an invalid< / span > < / p >
< p > < span class = "rvts65" > address, it always reads from the address first.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Relative addressing (BCC, BCS, BNE, BEQ, BPL, BMI, BVC, BVS)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ---------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch operand, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R Fetch opcode of next instruction,< / span > < / p >
< p > < span class = "rvts65" > If branch is taken, add operand to PCL.< / span > < / p >
< p > < span class = "rvts65" > Otherwise increment PC.< / span > < / p >
< p > < span class = "rvts65" > 4+ PC* R Fetch opcode of next instruction.< / span > < / p >
< p > < span class = "rvts65" > Fix PCH. If it did not change, increment PC.< / span > < / p >
< p > < span class = "rvts65" > 5! PC R Fetch opcode of next instruction,< / span > < / p >
< p > < span class = "rvts65" > increment PC.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: The opcode fetch of the next instruction is included to< / span > < / p >
< p > < span class = "rvts65" > this diagram for illustration purposes. When determining< / span > < / p >
< p > < span class = "rvts65" > real execution times, remember to subtract the last< / span > < / p >
< p > < span class = "rvts65" > cycle.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of Program Counter (PCH) may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller or bigger by $100.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > + If branch is taken, this cycle will be executed.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ! If branch occurs to different page, this cycle will be< / span > < / p >
< p > < span class = "rvts65" > executed.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Indexed indirect addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read instructions (LDA, ORA, EOR, AND, ADC, CMP, SBC, LAX)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ----------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 pointer R read from the address, add X to it< / span > < / p >
< p > < span class = "rvts65" > 4 pointer+X R fetch effective address low< / span > < / p >
< p > < span class = "rvts65" > 5 pointer+X+1 R fetch effective address high< / span > < / p >
< p > < span class = "rvts65" > 6 address R read from effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Note: The effective address is always fetched from zero page,< / span > < / p >
< p > < span class = "rvts65" > i.e. the zero page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read-Modify-Write instructions (SLO, SRE, RLA, RRA, ISB, DCP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ----------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 pointer R read from the address, add X to it< / span > < / p >
< p > < span class = "rvts65" > 4 pointer+X R fetch effective address low< / span > < / p >
< p > < span class = "rvts65" > 5 pointer+X+1 R fetch effective address high< / span > < / p >
< p > < span class = "rvts65" > 6 address R read from effective address< / span > < / p >
< p > < span class = "rvts65" > 7 address W write the value back to effective address,< / span > < / p >
< p > < span class = "rvts65" > and do the operation on it< / span > < / p >
< p > < span class = "rvts65" > 8 address W write the new value to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Note: The effective address is always fetched from zero page,< / span > < / p >
< p > < span class = "rvts65" > i.e. the zero page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Write instructions (STA, SAX)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ----------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 pointer R read from the address, add X to it< / span > < / p >
< p > < span class = "rvts65" > 4 pointer+X R fetch effective address low< / span > < / p >
< p > < span class = "rvts65" > 5 pointer+X+1 R fetch effective address high< / span > < / p >
< p > < span class = "rvts65" > 6 address W write to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Note: The effective address is always fetched from zero page,< / span > < / p >
< p > < span class = "rvts65" > i.e. the zero page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Indirect indexed addressing< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read instructions (LDA, EOR, AND, ORA, ADC, SBC, CMP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ----------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 pointer R fetch effective address low< / span > < / p >
< p > < span class = "rvts65" > 4 pointer+1 R fetch effective address high,< / span > < / p >
< p > < span class = "rvts65" > add Y to low byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address+Y* R read from effective address,< / span > < / p >
< p > < span class = "rvts65" > fix high byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 6+ address+Y R read from effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: The effective address is always fetched from zero page,< / span > < / p >
< p > < span class = "rvts65" > i.e. the zero page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller by $100.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > + This cycle will be executed only if the effective address< / span > < / p >
< p > < span class = "rvts65" > was invalid during cycle #5, i.e. page boundary was crossed.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Read-Modify-Write instructions (SLO, SRE, RLA, RRA, ISB, DCP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ----------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 pointer R fetch effective address low< / span > < / p >
< p > < span class = "rvts65" > 4 pointer+1 R fetch effective address high,< / span > < / p >
< p > < span class = "rvts65" > add Y to low byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address+Y* R read from effective address,< / span > < / p >
< p > < span class = "rvts65" > fix high byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 6 address+Y R read from effective address< / span > < / p >
< p > < span class = "rvts65" > 7 address+Y W write the value back to effective address,< / span > < / p >
< p > < span class = "rvts65" > and do the operation on it< / span > < / p >
< p > < span class = "rvts65" > 8 address+Y W write the new value to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: The effective address is always fetched from zero page,< / span > < / p >
< p > < span class = "rvts65" > i.e. the zero page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller by $100.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Write instructions (STA, SHA)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ----------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 pointer R fetch effective address low< / span > < / p >
< p > < span class = "rvts65" > 4 pointer+1 R fetch effective address high,< / span > < / p >
< p > < span class = "rvts65" > add Y to low byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 5 address+Y* R read from effective address,< / span > < / p >
< p > < span class = "rvts65" > fix high byte of effective address< / span > < / p >
< p > < span class = "rvts65" > 6 address+Y W write to effective address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Notes: The effective address is always fetched from zero page,< / span > < / p >
< p > < span class = "rvts65" > i.e. the zero page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > * The high byte of the effective address may be invalid< / span > < / p >
< p > < span class = "rvts65" > at this time, i.e. it may be smaller by $100.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Absolute indirect addressing (JMP)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- --------- --- ------------------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 PC R fetch opcode, increment PC< / span > < / p >
< p > < span class = "rvts65" > 2 PC R fetch pointer address low, increment PC< / span > < / p >
< p > < span class = "rvts65" > 3 PC R fetch pointer address high, increment PC< / span > < / p >
< p > < span class = "rvts65" > 4 pointer R fetch low address to latch< / span > < / p >
< p > < span class = "rvts65" > 5 pointer+1* R fetch PCH, copy latch to PCL< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Note: * The PCH will always be fetched from the same page< / span > < / p >
< p > < span class = "rvts65" > than PCL, i.e. page boundary crossing is not handled.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > How Real Programmers Acknowledge Interrupts< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > With RMW instructions:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; beginning of combined raster/timer interrupt routine< / span > < / p >
< p > < span class = "rvts65" > LSR $D019 ; clear VIC interrupts, read raster interrupt flag to C< / span > < / p >
< p > < span class = "rvts65" > BCS raster ; jump if VIC caused an interrupt< / span > < / p >
< p > < span class = "rvts65" > ... ; timer interrupt routine< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Operational diagram of LSR $D019:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # data address R/W< / span > < / p >
< p > < span class = "rvts65" > --- ---- ------- --- ---------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 4E PC R fetch opcode< / span > < / p >
< p > < span class = "rvts65" > 2 19 PC+1 R fetch address low< / span > < / p >
< p > < span class = "rvts65" > 3 D0 PC+2 R fetch address high< / span > < / p >
< p > < span class = "rvts65" > 4 xx $D019 R read memory< / span > < / p >
< p > < span class = "rvts65" > 5 xx $D019 W write the value back, rotate right< / span > < / p >
< p > < span class = "rvts65" > 6 xx/2 $D019 W write the new value back< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > The 5th cycle acknowledges the interrupt by writing the same< / span > < / p >
< p > < span class = "rvts65" > value back. If only raster interrupts are used, the 6th cycle< / span > < / p >
< p > < span class = "rvts65" > has no effect on the VIC. (It might acknowledge also some< / span > < / p >
< p > < span class = "rvts65" > other interrupts.)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > With indexed addressing:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; acknowledge interrupts to both CIAs< / span > < / p >
< p > < span class = "rvts65" > LDX #$10< / span > < / p >
< p > < span class = "rvts65" > LDA $DCFD,X< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Operational diagram of LDA $DCFD,X:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # data address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ---- ------- --- ---------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 BD PC R fetch opcode< / span > < / p >
< p > < span class = "rvts65" > 2 FD PC+1 R fetch address low< / span > < / p >
< p > < span class = "rvts65" > 3 DC PC+2 R fetch address high, add X to address low< / span > < / p >
< p > < span class = "rvts65" > 4 xx $DC0D R read from address, fix high byte of address< / span > < / p >
< p > < span class = "rvts65" > 5 yy $DD0D R read from right address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; acknowledge interrupts to CIA 2< / span > < / p >
< p > < span class = "rvts65" > LDX #$10< / span > < / p >
< p > < span class = "rvts65" > STA $DDFD,X< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Operational diagram of STA $DDFD,X:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # data address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ---- ------- --- ---------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 9D PC R fetch opcode< / span > < / p >
< p > < span class = "rvts65" > 2 FD PC+1 R fetch address low< / span > < / p >
< p > < span class = "rvts65" > 3 DC PC+2 R fetch address high, add X to address low< / span > < / p >
< p > < span class = "rvts65" > 4 xx $DD0D R read from address, fix high byte of address< / span > < / p >
< p > < span class = "rvts65" > 5 ac $DE0D W write to right address< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > With branch instructions:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; acknowledge interrupts to CIA 2< / span > < / p >
< p > < span class = "rvts65" > LDA #$00 ; clear N flag< / span > < / p >
< p > < span class = "rvts65" > JMP $DD0A< / span > < / p >
< p > < span class = "rvts65" > DD0A BPL $DC9D ; branch< / span > < / p >
< p > < span class = "rvts65" > DC9D BRK ; return< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > You need the following preparations to initialize the CIA registers:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > LDA #$91 ; argument of BPL< / span > < / p >
< p > < span class = "rvts65" > STA $DD0B< / span > < / p >
< p > < span class = "rvts65" > LDA #$10 ; BPL< / span > < / p >
< p > < span class = "rvts65" > STA $DD0A< / span > < / p >
< p > < span class = "rvts65" > STA $DD08 ; load the ToD values from the latches< / span > < / p >
< p > < span class = "rvts65" > LDA $DD0B ; freeze the ToD display< / span > < / p >
< p > < span class = "rvts65" > LDA #$7F< / span > < / p >
< p > < span class = "rvts65" > STA $DC0D ; assure that $DC0D is $00< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Operational diagram of BPL $DC9D:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # data address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ---- ------- --- ---------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 10 $DD0A R fetch opcode< / span > < / p >
< p > < span class = "rvts65" > 2 91 $DD0B R fetch argument< / span > < / p >
< p > < span class = "rvts65" > 3 xx $DD0C R fetch opcode, add argument to PCL< / span > < / p >
< p > < span class = "rvts65" > 4 yy $DD9D R fetch opcode, fix PCH< / span > < / p >
< p > < span class = "rvts65" > ( 5 00 $DC9D R fetch opcode )< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; acknowledge interrupts to CIA 1< / span > < / p >
< p > < span class = "rvts65" > LSR ; clear N flag< / span > < / p >
< p > < span class = "rvts65" > JMP $DCFA< / span > < / p >
< p > < span class = "rvts65" > DCFA BPL $DD0D< / span > < / p >
< p > < span class = "rvts65" > DD0D BRK< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; Again you need to set the ToD registers of CIA 1 and the< / span > < / p >
< p > < span class = "rvts65" > ; Interrupt Control Register of CIA 2 first.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Operational diagram of BPL $DD0D:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # data address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ---- ------- --- ---------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 10 $DCFA R fetch opcode< / span > < / p >
< p > < span class = "rvts65" > 2 11 $DCFB R fetch argument< / span > < / p >
< p > < span class = "rvts65" > 3 xx $DCFC R fetch opcode, add argument to PCL< / span > < / p >
< p > < span class = "rvts65" > 4 yy $DC0D R fetch opcode, fix PCH< / span > < / p >
< p > < span class = "rvts65" > ( 5 00 $DD0D R fetch opcode )< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; acknowledge interrupts to CIA 2 automagically< / span > < / p >
< p > < span class = "rvts65" > ; preparations< / span > < / p >
< p > < span class = "rvts65" > LDA #$7F< / span > < / p >
< p > < span class = "rvts65" > STA $DD0D ; disable all interrupt sources of CIA2< / span > < / p >
< p > < span class = "rvts65" > LDA $DD0E< / span > < / p >
< p > < span class = "rvts65" > AND #$BE ; ensure that $DD0C remains constant< / span > < / p >
< p > < span class = "rvts65" > STA $DD0E ; and stop the timer< / span > < / p >
< p > < span class = "rvts65" > LDA #$FD< / span > < / p >
< p > < span class = "rvts65" > STA $DD0C ; parameter of BPL< / span > < / p >
< p > < span class = "rvts65" > LDA #$10< / span > < / p >
< p > < span class = "rvts65" > STA $DD0B ; BPL< / span > < / p >
< p > < span class = "rvts65" > LDA #$40< / span > < / p >
< p > < span class = "rvts65" > STA $DD0A ; RTI/parameter of LSR< / span > < / p >
< p > < span class = "rvts65" > LDA #$46< / span > < / p >
< p > < span class = "rvts65" > STA $DD09 ; LSR< / span > < / p >
< p > < span class = "rvts65" > STA $DD08 ; load the ToD values from the latches< / span > < / p >
< p > < span class = "rvts65" > LDA $DD0B ; freeze the ToD display< / span > < / p >
< p > < span class = "rvts65" > LDA #$09< / span > < / p >
< p > < span class = "rvts65" > STA $0318< / span > < / p >
< p > < span class = "rvts65" > LDA #$DD< / span > < / p >
< p > < span class = "rvts65" > STA $0319 ; change NMI vector to $DD09< / span > < / p >
< p > < span class = "rvts65" > LDA #$FF ; Try changing this instruction's operand< / span > < / p >
< p > < span class = "rvts65" > STA $DD05 ; (see comment below).< / span > < / p >
< p > < span class = "rvts65" > LDA #$FF< / span > < / p >
< p > < span class = "rvts65" > STA $DD04 ; set interrupt frequency to 1/65536 cycles< / span > < / p >
< p > < span class = "rvts65" > LDA $DD0E< / span > < / p >
< p > < span class = "rvts65" > AND #$80< / span > < / p >
< p > < span class = "rvts65" > ORA #$11< / span > < / p >
< p > < span class = "rvts65" > LDX #$81< / span > < / p >
< p > < span class = "rvts65" > STX $DD0D ; enable timer interrupt< / span > < / p >
< p > < span class = "rvts65" > STA $DD0E ; start timer< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > LDA #$00 ; To see that the interrupts really occur,< / span > < / p >
< p > < span class = "rvts65" > STA $D011 ; use something like this and see how< / span > < / p >
< p > < span class = "rvts65" > LOOP DEC $D020 ; changing the byte loaded to $DD05 from< / span > < / p >
< p > < span class = "rvts65" > BNE LOOP ; #$FF to #$0F changes the image.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > When an NMI occurs, the processor jumps to Kernal code, which jumps to< / span > < / p >
< p > < span class = "rvts65" > ($0318), which points to the following routine:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > DD09 LSR $40 ; clear N flag< / span > < / p >
< p > < span class = "rvts65" > BPL $DD0A ; Note: $DD0A contains RTI.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > Operational diagram of BPL $DD0A:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > # data address R/W description< / span > < / p >
< p > < span class = "rvts65" > --- ---- ------- --- ---------------------------------< / span > < / p >
< p > < span class = "rvts65" > 1 10 $DD0B R fetch opcode< / span > < / p >
< p > < span class = "rvts65" > 2 11 $DD0C R fetch argument< / span > < / p >
< p > < span class = "rvts65" > 3 xx $DD0D R fetch opcode, add argument to PCL< / span > < / p >
< p > < span class = "rvts65" > 4 40 $DD0A R fetch opcode, (fix PCH)< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > With RTI:< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > ; the fastest possible interrupt handler in the 6500 family< / span > < / p >
< p > < span class = "rvts65" > ; preparations< / span > < / p >
< p > < span class = "rvts65" > SEI< / span > < / p >
< p > < span class = "rvts65" > LDA $01 ; disable ROM and enable I/O< / span > < / p >
< p > < span class = "rvts65" > AND #$FD< / span > < / p >
< p > < span class = "rvts65" > ORA #$05< / span > < / p >
< p > < span class = "rvts65" > STA $01< / span > < / p >
< p > < span class = "rvts65" > LDA #$7F< / span > < / p >
< p > < span class = "rvts65" > STA $DD0D ; disable CIA 2's all interrupt sources< / span > < / p >
< p > < span class = "rvts65" > LDA $DD0E< / span > < / p >
< p > < span class = "rvts65" > AND #$BE ; ensure that $DD0C remains constant< / span > < / p >
< p > < span class = "rvts65" > STA $DD0E ; and stop the timer< / span > < / p >
< p > < span class = "rvts65" > LDA #$40< / span > < / p >
< p > < span class = "rvts65" > STA $DD0C ; store RTI to $DD0C< / span > < / p >
< p > < span class = "rvts65" > LDA #$0C< / span > < / p >
< p > < span class = "rvts65" > STA $FFFA< / span > < / p >
< p > < span class = "rvts65" > LDA #$DD< / span > < / p >
< p > < span class = "rvts65" > STA $FFFB ; change NMI vector to $DD0C< / span > < / p >
< p > < span class = "rvts65" > LDA #$FF ; Try changing this instruction's operand< / span > < / p >
< p > < span class = "rvts65" > STA $DD05 ; (see comment below).< / span > < / p >
< p > < span class = "rvts65" > LDA #$FF< / span > < / p >
< p > < span class = "rvts65" > STA $DD04 ; set interrupt frequency to 1/65536 cycles< / span > < / p >
< p > < span class = "rvts65" > LDA $DD0E< / span > < / p >
< p > < span class = "rvts65" > AND #$80< / span > < / p >
< p > < span class = "rvts65" > ORA #$11< / span > < / p >
< p > < span class = "rvts65" > LDX #$81< / span > < / p >
< p > < span class = "rvts65" > STX $DD0D ; enable timer interrupt< / span > < / p >
< p > < span class = "rvts65" > STA $DD0E ; start timer< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > LDA #$00 ; To see that the interrupts really occur,< / span > < / p >
< p > < span class = "rvts65" > STA $D011 ; use something like this and see how< / span > < / p >
< p > < span class = "rvts65" > LOOP DEC $D020 ; changing the byte loaded to $DD05 from< / span > < / p >
< p > < span class = "rvts65" > BNE LOOP ; #$FF to #$0F changes the image.< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > When an NMI occurs, the processor jumps to Kernal code, which< / p >
< p > jumps to ($0318), which points to the following routine:< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > DD0C RTI< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > How on earth can this clear the interrupts? Remember, the< / p >
< p > processor always fetches two successive bytes for each< / p >
< p > instruction.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > A little more practical version of this is redirecting the NMI< / p >
< p > (or IRQ) to your own routine, whose last instruction is JMP< / p >
< p > $DD0C or JMP $DC0C. If you want to confuse more, change the 0< / p >
< p > in the address to a hexadecimal digit different from the one< / p >
< p > you used when writing the RTI.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > Or you can combine the latter two methods:< / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > < br / > < / span > < / p >
< p > < span class = "rvts65" > DD09 LSR $xx ; xx is any appropriate BCD value 00-59.< / span > < / p >
< p > < span class = "rvts65" > BPL $DCFC< / span > < / p >
< p > < span class = "rvts65" > DCFC RTI< / span > < / p >
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > This example acknowledges interrupts to both CIAs.< / p >
2012-09-28 19:41:12 +00:00
< p > < span class = "rvts65" > < br / > < / span > < / p >
2012-03-23 20:30:31 +00:00
< p > If you want to confuse the examiners of your code, you can use any< / p >
< p > of these techniques. Although these examples use no undefined opcodes,< / p >
< p > they do not necessarily run correctly on CMOS processors. However, the< / p >
< p > RTI example should run on 65C02 and 65C816, and the latter branch< / p >
< p > instruction example might work as well.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
2012-03-23 20:30:31 +00:00
< p > The RMW instruction method has been used in some demos, others were< / p >
< p > developed by Marko M"akel"a. His favourite is the automagical RTI< / p >
< p > method, although it does not have any practical applications, except< / p >
< p > for some time dependent data decryption routines for very complicated< / p >
< p > copy protections.< / p >
2012-08-08 15:00:14 +00:00
< p > < br / > < / p >
< p > < br / > < / p >
< p > < br / > < / p >
< p class = "rvps2" > < span class = "rvts13" > Created with the Personal Edition of HelpNDoc: < / span > < a class = "rvts14" href = "http://www.helpndoc.com/help-authoring-tool" > Full featured multi-format Help generator< / a > < / p >
2012-03-23 20:30:31 +00:00
< / div >
< div id = "topic_footer" >
< div id = "topic_footer_content" >
2012< / div >
< / div >
< / body >
< / html >