module Nes.CPU.Instructions.Transfer (
    -- * Transfer to/from register A
    tax,
    tay,
    txa,
    tya,

    -- * Transfter between register X and Status
    txs,
    tsx,
) where

import Control.Monad
import Nes.CPU.Instructions.After (setZeroAndNegativeFlags)
import Nes.CPU.Monad
import Nes.CPU.State
import Nes.Internal.MonadState
import Nes.Memory (Byte)

-- | Transfer Register A to X
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#TAX
tax :: CPU r ()
tax :: forall r. CPU r ()
tax = Register -> Register -> CPU r Byte
forall r. Register -> Register -> CPU r Byte
transferToRegister Register
A Register
X CPU r Byte -> (Byte -> CPU r ()) -> CPU r ()
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
>>= Byte -> CPU r ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags

-- | Transfer Register A to Y
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#TAY
tay :: CPU r ()
tay :: forall r. CPU r ()
tay = Register -> Register -> CPU r Byte
forall r. Register -> Register -> CPU r Byte
transferToRegister Register
A Register
Y CPU r Byte -> (Byte -> CPU r ()) -> CPU r ()
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
>>= Byte -> CPU r ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags

-- | Transfer Register X to A
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#TXA
txa :: CPU r ()
txa :: forall r. CPU r ()
txa = Register -> Register -> CPU r Byte
forall r. Register -> Register -> CPU r Byte
transferToRegister Register
X Register
A CPU r Byte -> (Byte -> CPU r ()) -> CPU r ()
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
>>= Byte -> CPU r ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags

-- | Transfer Register Y to A
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#TYA
tya :: CPU r ()
tya :: forall r. CPU r ()
tya = Register -> Register -> CPU r Byte
forall r. Register -> Register -> CPU r Byte
transferToRegister Register
Y Register
A CPU r Byte -> (Byte -> CPU r ()) -> CPU r ()
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
>>= Byte -> CPU r ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags

-- | Transfer Register X to S
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#TXS
txs :: CPU r ()
txs :: forall r. CPU r ()
txs = CPU r Byte -> CPU r ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (CPU r Byte -> CPU r ()) -> CPU r Byte -> CPU r ()
forall a b. (a -> b) -> a -> b
$ Register -> Register -> CPU r Byte
forall r. Register -> Register -> CPU r Byte
transferToRegister Register
X Register
S

-- | Transfer Register S to X
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#TSX
tsx :: CPU r ()
tsx :: forall r. CPU r ()
tsx = CPU r () -> CPU r ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (CPU r () -> CPU r ()) -> CPU r () -> CPU r ()
forall a b. (a -> b) -> a -> b
$ Register -> Register -> CPU r Byte
forall r. Register -> Register -> CPU r Byte
transferToRegister Register
S Register
X CPU r Byte -> (Byte -> CPU r ()) -> CPU r ()
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
>>= Byte -> CPU r ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags

{-# INLINE transferToRegister #-}
transferToRegister :: Register -> Register -> CPU r Byte
transferToRegister :: forall r. Register -> Register -> CPU r Byte
transferToRegister Register
src Register
dest = do
    Byte
value <- 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
src
    Register -> Lens' CPUState Byte
register Register
dest ((Byte -> Identity Byte) -> CPUState -> Identity CPUState)
-> Byte -> CPU r ()
forall s (m :: * -> *) a.
MonadState s m =>
ASetter' s a -> a -> m ()
.= Byte
value
    Byte -> CPU r Byte
forall a. a -> CPU r a
forall (m :: * -> *) a. Monad m => a -> m a
return Byte
value