Saturday, May 12, 2018

Incrementing and Decrementing


My 6502 Emulation portion of my 2600 emulator continues with a look at increment and decrement operations.

Moving memory around is often very important, but right now we are doing it one byte at a time. The index operations allow for looping through blocks of memory but that requires the ability to create a loop. Before we can do that, we need to be able to increment or decrement the index registers. Since increasing or decreasing an index register by one is an exceedingly common operation, there are commands specifically for doing this. Strangely enough there is not a way of incrementing or decrementing the accumulator by one, though there is addition and subtraction commands which we will be covering later.

The INX and INY commands are used to increment the X or Y registers. When the register has the value of 255 incrementing it wraps the value making it become 0. DEX and DEY are used for decrementing the X or Y registers. When they are 0, decrementing wraps the register making them 255.

While there is no commands for incrementing or decrementing the accumulator, there is an INC and a DEC command that apply to memory at an indicated address. This is handy to have as it lets you modify a variable in memory without needing to load it into a register.

The most common use of increment and decrement operations, as mentioned above, is looping. This requires branching instructions at a minimum, so we will take a look at branching instructions next.

INCINCrement memory
Address Mode
Decimal OPCode
Hexadecimal OpCode
Size
Cycles
Zero Page
230
$E6
2
5
Zero Page, X
246
$F6
2
6
Absolute
238
$EE
3
6
Absolute,X
254
$FE
3
7
Flags affected: NZ
Usage: Incrementing a byte in memory
Test Code:
; INC, INX, INY tests
     LDX #$10
     LDY #255
     INC $50
     INC $41,X
     INC $110
     INC $101,X
     INX
     INY
     BRK
.ORG $50
.BYTE 1 2
.ORG $110
.BYTE 3 4
; expect M50=2, M51=3, M110=4, M111=5, X=17, Y=0, Z=1

Implementation:
// zero page
val addressToInc = mem.read(state.ip+1)
mem.write(addressToInc, setNumberFlags((mem.read(addressToInc) + 1) and 255))

// zero page,X
val addressToInc = mem.read(state.ip+1) + state.x
mem.write(addressToInc, setNumberFlags((mem.read(addressToInc) + 1) and 255))

// absolute
val addressToInc = findAbsoluteAddress(state.ip)
mem.write(addressToInc, setNumberFlags((mem.read(addressToInc) + 1) and 255))

// absolute,X
val addressToInc = findAbsoluteAddress(state.ip) + state.x
mem.write(addressToInc, setNumberFlags((mem.read(addressToInc) + 1) and 255))


INXINcrement X register
Address Mode
Decimal OPCode
Hexadecimal OpCode
Size
Cycles
Implied
232
$E8
1
2
Flags affected: NZ
Usage: Adding one to value in x register. Useful for looping.
Test Code:
; INC, INX, INY tests
     LDX #$10
     LDY #255
     INC $50
     INC $41,X
     INC $110
     INC $101,X
     INX
     INY
     BRK
.ORG $50
.BYTE 1 2
.ORG $110
.BYTE 3 4
; expect M50=2, M51=3, M110=4, M111=5, X=17, Y=0, Z=1

Implementation:
state.x = setNumberFlags((state.x+1) and 255)


INYINcrement Y register
Address Mode
Decimal OPCode
Hexadecimal OpCode
Size
Cycles
Implied
200
$C8
1
2
Flags affected: NZ
Cycle Notes: remove if none
Usage: Adding one to value in y register. Useful for looping.
Test Code:
; INC, INX, INY tests
     LDX #$10
     LDY #255
     INC $50
     INC $41,X
     INC $110
     INC $101,X
     INX
     INY
     BRK
.ORG $50
.BYTE 1 2
.ORG $110
.BYTE 3 4
; expect M50=2, M51=3, M110=4, M111=5, X=17, Y=0, Z=1

Implementation:
state.y = setNumberFlags((state.y+1) and 255)


DECDECrement memory
Address Mode
Decimal OPCode
Hexadecimal OpCode
Size
Cycles
Zero Page
198
$C6
2
5
Zero Page, X
214
$D6
2
6
Absolute
206
$CE
3
6
Absolute, X
222
$DE
3
7
Flags affected: NZ
Cycle Notes: remove if none
Usage: When you would use this command
Test Code:
; DEC, DEX, DEY tests
     LDX #$10
     LDY #0
     DEC $50
     DEC $41,X
     DEC $110
     DEC $101,X
     DEX
     DEY
     BRK
.ORG $50
.BYTE 1 2
.ORG $110
.BYTE 3 4
; expect M50=0, M51=1, M110=2, M111=3, X=15, Y=255, N=1

Implementation:
// zero page
val addressToDec = mem.read(state.ip+1)
mem.write(addressToDec, setNumberFlags((mem.read(addressToDec) - 1) and 255))

// zero page,X
val addressToDec = mem.read(state.ip+1) + state.x
mem.write(addressToDec, setNumberFlags((mem.read(addressToDec) - 1) and 255))

// absolute
val addressToDec = findAbsoluteAddress(state.ip)
mem.write(addressToDec, setNumberFlags((mem.read(addressToDec) - 1) and 255))

// absolute,X
val addressToDec = findAbsoluteAddress(state.ip) + state.x
mem.write(addressToDec, setNumberFlags((mem.read(addressToDec) - 1) and 255))



DEXDEcrement X register
Address Mode
Decimal OPCode
Hexadecimal OpCode
Size
Cycles
Implied
202
$CA
1
2
Flags affected: NZ
Usage: Decreasing X register by 1 is usually done for countdown loops
Test Code:
; DEC, DEX, DEY tests
     LDX #$10
     LDY #0
     DEC $50
     DEC $41,X
     DEC $110
     DEC $101,X
     DEX
     DEY
     BRK
.ORG $50
.BYTE 1 2
.ORG $110
.BYTE 3 4
; expect M50=0, M51=1, M110=2, M111=3, X=15, Y=255, N=1

Implementation:
state.x = setNumberFlags((state.x-1) and 255)

DEYDEcrement Y register
Address Mode
Decimal OPCode
Hexadecimal OpCode
Size
Cycles
Implied
136
$88
1
2
Flags affected: NZ
Usage: Decreasing Y register by 1 is usually done for countdown loops
Test Code:
; DEC, DEX, DEY tests
     LDX #$10
     LDY #0
     DEC $50
     DEC $41,X
     DEC $110
     DEC $101,X
     DEX
     DEY
     BRK
.ORG $50
.BYTE 1 2
.ORG $110
.BYTE 3 4
; expect M50=0, M51=1, M110=2, M111=3, X=15, Y=255, N=1

Implementation:
state.y = setNumberFlags((state.y-1) and 255)

No comments:

Post a Comment