module Nes.CPU.Instructions.Stack (pha, php, pla, plp) where

import Nes.CPU.Instructions.After
import Nes.CPU.Monad
import Nes.CPU.State
import Nes.Internal.MonadState

-- | Pushes a copy of the accumulator on to the stack.
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#PHA
pha :: CPU r ()
pha :: forall r. CPU r ()
pha = CPU r ()
forall r. CPU r ()
tickOnce CPU r () -> CPU r Byte -> CPU r Byte
forall a b. CPU r a -> CPU r b -> CPU r b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> 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
Lens' CPUState Byte
registerA 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 ()
pushByteStack

-- | Pushes a copy of the status flags on to the stack.
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#PHP
--
-- Source: https://github.com/bugzmanov/nes_ebook/blob/785b9ed8b803d9f4bd51274f4d0c68c14a1b3a8b/code/ch3.3/src/cpu.rs#L486
php :: CPU r ()
php :: forall r. CPU r ()
php = Bool -> CPU r ()
forall r. Bool -> CPU r ()
pushStatusRegister Bool
True CPU r () -> CPU r () -> CPU r ()
forall a b. CPU r a -> CPU r b -> CPU r b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> CPU r ()
forall r. CPU r ()
tickOnce

-- | Pulls an 8 bit value from the stack and into the accumulator.
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#PLA
pla :: CPU r ()
pla :: forall r. CPU r ()
pla = do
    Byte
value <- CPU r Byte
forall r. CPU r Byte
popStackByte
    Int -> CPU r ()
forall r. Int -> CPU r ()
tick Int
2
    (Byte -> Identity Byte) -> CPUState -> Identity CPUState
Lens' CPUState Byte
registerA ((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 ()
forall r. Byte -> CPU r ()
setZeroAndNegativeFlags Byte
value

-- | Pulls an 8 bit value from the stack and into the accumulator.
--
-- https://www.nesdev.org/obelisk-6502-guide/reference.html#PLP
plp :: CPU r ()
plp :: forall r. CPU r ()
plp = CPU r ()
forall r. CPU r ()
popStatusRegister CPU r () -> CPU r () -> CPU r ()
forall a b. CPU r a -> CPU r b -> CPU r b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> CPU r ()
forall r. Int -> CPU r ()
tick Int
2