module Nes.CPU.Instructions.Compare (cmp, cpx, cpy) where

import Nes.CPU.Instructions.Addressing
import Nes.CPU.Instructions.After
import Nes.CPU.Monad
import Nes.CPU.State
import Nes.FlagRegister
import Nes.Internal.MonadState
import Nes.Memory

-- | Computes (Register A - _value in memory_)
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#CMP
cmp :: AddressingMode -> CPU r ()
cmp :: forall r. AddressingMode -> CPU r ()
cmp = Register -> AddressingMode -> CPU r ()
forall r. Register -> AddressingMode -> CPU r ()
compareWithRegister Register
A

-- | Computes (Register X - _value in memory_)
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#CPX
cpx :: AddressingMode -> CPU r ()
cpx :: forall r. AddressingMode -> CPU r ()
cpx = Register -> AddressingMode -> CPU r ()
forall r. Register -> AddressingMode -> CPU r ()
compareWithRegister Register
X

-- | Computes (Register Y - _value in memory_)
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#CPY
cpy :: AddressingMode -> CPU r ()
cpy :: forall r. AddressingMode -> CPU r ()
cpy = Register -> AddressingMode -> CPU r ()
forall r. Register -> AddressingMode -> CPU r ()
compareWithRegister Register
Y

{-# INLINE compareWithRegister #-}
compareWithRegister :: Register -> AddressingMode -> CPU r ()
compareWithRegister :: forall r. Register -> AddressingMode -> CPU r ()
compareWithRegister Register
reg AddressingMode
mode = do
    Byte
value <- AddressingMode -> CPU r Addr
forall r. AddressingMode -> CPU r Addr
getOperandAddr AddressingMode
mode CPU r Addr -> (Addr -> CPU r Byte) -> CPU r Byte
forall a b. CPU r a -> (a -> CPU r b) -> CPU r b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Addr -> () -> CPU r Byte
forall a (m :: * -> *). MemoryInterface a m => Addr -> a -> m Byte
`readByte` ())
    Byte
regValue <- Getting Byte CPUState Byte -> CPU r Byte
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (Getting Byte CPUState Byte -> CPU r Byte)
-> Getting Byte CPUState Byte -> CPU r Byte
forall a b. (a -> b) -> a -> b
$ Register -> Lens' CPUState Byte
register Register
reg
    let diff :: Byte
diff = Byte
regValue Byte -> Byte -> Byte
forall a. Num a => a -> a -> a
- Byte
value
    Byte -> CPU r ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags Byte
diff
    (StatusRegister -> Identity StatusRegister)
-> CPUState -> Identity CPUState
Lens' CPUState StatusRegister
status ((StatusRegister -> Identity StatusRegister)
 -> CPUState -> Identity CPUState)
-> (StatusRegister -> StatusRegister) -> CPU r ()
forall s (m :: * -> *) a.
MonadState s m =>
ASetter' s a -> (a -> a) -> m ()
%= Flag StatusRegister -> Bool -> StatusRegister -> StatusRegister
forall a. FlagRegister a => Flag a -> Bool -> a -> a
setFlag' Flag StatusRegister
StatusRegisterFlag
Carry (Byte
regValue Byte -> Byte -> Bool
forall a. Ord a => a -> a -> Bool
>= Byte
value)