| 
     Module       : Lazyboy . Types 
     Description : Hardware type definitions for Lazyboy 
     Copyright    : ( c ) Rose 2019 
     License      : BSD3 
     Maintainer   :  
     Stability    : experimental 
     Portability : POSIX 

     This module defines datatypes for the various aspects of the target hardware 
     including registers and instructions . 

    Module      : Lazyboy.Types
    Description : Hardware type definitions for Lazyboy
    Copyright   : (c) Rose 2019
    License     : BSD3
    Maintainer  : 
    Stability   : experimental
    Portability : POSIX

    This module defines datatypes for the various aspects of the target hardware
    including registers and instructions.
-}

{-# LANGUAGE OverloadedStrings #-}

module Lazyboy.Types where

import Control.Monad.Trans.RWS.Lazy
import Data.Int
import Data.Word
import Formatting                   (formatToString, (%))
import Formatting.ShortFormatters   (x)

  | A type alias that defines Lazyboy as a specialization of the
  RWS monad transformer stack . Reader goes unused ,  is utilized
  for an output list of Instructions , and State is merely an integer
-- which counts labels, thus naming them.
type Lazyboy a = RWS () [Instruction] Integer a

-- | Executes an action and returns a list of Instructions.
execLazyboy :: Lazyboy a -> [Instruction]
execLazyboy m = snd $ execRWS m () 1

-- | A type which represents an address or label.
data Location = Address Word16 | Name Label
  deriving (Eq)

instance Show Location where
    show (Address v)  = formatToString ("$" % x) v
    show (Name label) = show label

-- | A type representing Condition flags on the hardware.
data Condition = Zero | NonZero | Carry | NoCarry
  deriving (Eq)

instance Show Condition where
    show Zero    = "z"
    show NonZero = "nz"
    show Carry   = "c"
    show NoCarry = "nc"

  | Named 8 - bit registers .
data Register8 = A | B | C | D | E | H | L
  deriving (Read, Show, Eq)

  | Named 16 - bit registers .
data Register16 = BC | DE | HL | AF | SP | PC
  deriving (Read, Show, Eq)

-- | A type which represents a label, which may be local or global in scope.
data Label = Local Integer | Global Integer
  deriving (Eq)

instance Show Label where
    show (Local v)  = ".L" ++ show v
    show (Global v) = "L" ++ show v

-- | Type-level representations of instructions and primitive special forms.
data Instruction =
  ^ Load the value in one Register8 into another .
  | LDrn Register8 Word8       -- ^ Load the immediate Word8 into a Register8.
  ^ Load the Word8 stored at the address in HL into a Register8 .
  ^ Load the Word8 stored in a Register8 into the address in HL .
  ^ Load the immediate Word8 into the address in HL .
  | LDArr Register16           -- ^ Load the value at the address contained in a Register16 into A.
  | LDrrA Register16           -- ^ Load A into the address contained in a Register16.
  | LDAnn Location             -- ^ Load the Word8 stored in the Location into A.
  | LDnnA Location             -- ^ Load the Word8 stored in A into the Location.
  | LDAIO Word8                -- ^ Read into A from IO port n (FF00 + Word8).
  | LDIOA Word8                -- ^ Store the Word8 in A into IO port n (FF00 + Word8).
  | LDAIOC                     -- ^ Read from IO port FF00+C into A.
  ^ Store the Word8 in A into IO port FF00+C.
  ^ Store value in register A into byte pointed by HL and post - increment HL .
  ^ Store value in address in HL in A and post - increment HL .
  ^ Store value in register A into byte pointed by HL and post - decrement HL .
  ^ Store value in address in HL in A and post - decrement HL .
  | LDrrnn Register16 Location -- ^ Load a Location into a Register16.
  ^ Set the stack pointer ( SP ) to the value in HL .
  | PUSH Register16            -- ^ Push Register16 onto the stack.
  | POP Register16             -- ^ Pop Register16 from the stack.

  Jump & Call instructions
  | JP Location               -- ^ Immediately and unconditionally jump to a Location.
  ^ Immediately and unconditionally jump to the value contained in HL .
  | JPif Condition Location   -- ^ Conditionally jump to a Location.
  | CALL Location             -- ^ Call a Location.
  | CALLif Condition Location -- ^ Conditionally call a Location.
  | RET                       -- ^ Return from a labelled block.
  | RETif Condition           -- ^ Conditionally return from a labelled block.
  | RETi                      -- ^ Return and enable interrupts.
  | RST Word8                 -- ^ Call a restart vector.

  Arithmetic & Logical instructions
  | ADDAr Register8          -- ^ Add the value contained in a Register8 to A.
  | ADDAn Word8              -- ^ Add a Word8 to the value contained in A.
  ^ Add the value contained in the address stored in HL to A.
  | ADCAr Register8          -- ^ Add the value in a Register8 + the carry flag to A.
  | ADCAn Word8              -- ^ Add a Word8 + the carry flag to A.
  ^ Add the value pointed to by HL + the carry flag to A.
  | SUBAr Register8          -- ^ Subtract the value contained in a Register8 from A.
  | SUBAn Word8              -- ^ Subtract a Word8 from A.
  ^ Subtract from A the value contained at the address in HL .
  | SBCAr Register8          -- ^ Subtract from A the value contained in a Register8 + the carry flag.
  | SBCAn Word8              -- ^ Subtract from A a Word8 + the carry flag.
  | SBCAHL                   -- ^ Subtract from A the value contained in the address in HL + the carry flag.
  ^ Assign to A the value contained in a Register8 & A itself .
  | ANDn Word8               -- ^ Assign to A a Word8 & A itself.
  ^ Assign to A itself & the value in the address in HL .
  | XORr Register8           -- ^ Assign to A the value contained in a register ^ A itself
  | XORn Word8               -- ^ Assign to A a Word8 ^ itself.
  ^ Assign to A itself ^ the value in the address in HL .
  | ORr Register8            -- ^ Assign to A the value contained in a register | A itself.
  | ORn Word8                -- ^ Assign to A a Word8 | itself.
  ^ Assign to A itself | the value in the address in HL
  | CPr Register8            -- ^ Subtract from A the value in a Register8 and set flags accordingly, but don't store the result.
  | CPn Word8                -- ^ Subtract from A a Word8 and set flags accordingly, but don't store the result.
  ^ Subtract from A the value in the address in HL , set flags , but do n't store the result .
  | INCr Register8           -- ^ Increment the value in a Register8.
  ^ Increment the value at the address in HL .
  | DECr Register8           -- ^ Decrement the value in a Register8.
  ^ Decrement the value at the address in HL .
  | DAA                      -- ^ Decimal-adjust register A.
  | CPL                      -- ^ Complement accumulator (A = ~A).
  ^ Add the value contained in a Register16 to HL .
  | INCrr Register16         -- ^ Increment the value in a Register16.
  | DECrr Register16         -- ^ Decrement the value in a Register16.
  | ADDSPn Int8              -- ^ Add an Int8 to the stack pointer.
  | LDHLSPn Int8             -- ^ Load into HL the stack pointer + an Int8.

  -- Single-bit instructions
  ^ Test bit n in a Register8 , set the zero flag if not set .
  ^ Test bit n in the Word8 pointed by HL , set the zero flag if not set .
  | SETnr Word8 Register8    -- ^ Set bit n in a Register8.
  ^ Set bit n in the Word8 pointed by HL .
  ^ Unset bit n in Register8 .
  ^ Unset bit n in the Word8 pointed by HL .

  Rotate & shift instructions
  | RLCA                     -- ^ Rotate accumulator left.
  | RLA                      -- ^ Rotate accumulator left through carry.
  | RRCA                     -- ^ Rotate accumulator right.
  | RRA                      -- ^ Rotate accumulator rit through carry.
  | RLC Register8            -- ^ Rotate Register8 left.
  ^ Rotate value contained at address in HL left .
  | RL Register8             -- ^ Rotate Register8 left through carry.
  ^ Rotate value contained at address in HL left through carry .
  | RRC Register8            -- ^ Rotate Register8 right.
  ^ Rotate value contained at address in HL right .
  | RR Register8             -- ^ Rotate Register8 right through carry.
  ^ Rotate value contained at address in HL right through carry .
  | SLA Register8            -- ^ Shift Register8 left arithmetic.
  ^ Shift left arithmetic ( HL pointer ) .
  | SWAP Register8           -- ^ Exchange low and high nibbles in Register8.
  ^ Exchange low and high nibbles in HL pointer .
  | SRA Register8            -- ^ Shift Register8 right arithmetic.
  ^ Shift right arithmetic in HL pointer .
  | SRL Register8            -- ^ Shift Register8 right logical.
  ^ Shift right logical in HL pointer .

  -- CPU control instructions
  | CCF                      -- ^ Complement carry flag.
  | SCF                      -- ^ Set carry flag.
  | NOP                      -- ^ No operation.
  | HALT                     -- ^ Halt until interrupt.
  | STOP                     -- ^ Standby mode.
  | DI                       -- ^ Disable interrupts.
  | EI                       -- ^ Enable interrupts.

  -- RGBASM-specific convenience stuff.
  -- these would need revamping if we were to start generating native machine code
  | LABEL Label               -- ^ Create a numbered label.
  ^ Include the file at FilePath .
  | BYTES [Word8]             -- ^ Define some bytes in the form of a Word8 list with a global label.

  deriving (Eq)

# LANGUAGE OverloadedStrings #
 which counts labels, thus naming them.
 | Executes an action and returns a list of Instructions.
 | A type which represents an address or label.
 | A type representing Condition flags on the hardware.
 | A type which represents a label, which may be local or global in scope.
 | Type-level representations of instructions and primitive special forms.
 ^ Load the immediate Word8 into a Register8.
 ^ Load the value at the address contained in a Register16 into A.
 ^ Load A into the address contained in a Register16.
 ^ Load the Word8 stored in the Location into A.
 ^ Load the Word8 stored in A into the Location.
 ^ Read into A from IO port n (FF00 + Word8).
 ^ Store the Word8 in A into IO port n (FF00 + Word8).
 ^ Read from IO port FF00+C into A.
 ^ Load a Location into a Register16.
 ^ Push Register16 onto the stack.
 ^ Pop Register16 from the stack.
 ^ Immediately and unconditionally jump to a Location.
 ^ Conditionally jump to a Location.
 ^ Call a Location.
 ^ Conditionally call a Location.
 ^ Return from a labelled block.
 ^ Conditionally return from a labelled block.
 ^ Return and enable interrupts.
 ^ Call a restart vector.
 ^ Add the value contained in a Register8 to A.
 ^ Add a Word8 to the value contained in A.
 ^ Add the value in a Register8 + the carry flag to A.
 ^ Add a Word8 + the carry flag to A.
 ^ Subtract the value contained in a Register8 from A.
 ^ Subtract a Word8 from A.
 ^ Subtract from A the value contained in a Register8 + the carry flag.
 ^ Subtract from A a Word8 + the carry flag.
 ^ Subtract from A the value contained in the address in HL + the carry flag.
 ^ Assign to A a Word8 & A itself.
 ^ Assign to A the value contained in a register ^ A itself
 ^ Assign to A a Word8 ^ itself.
 ^ Assign to A the value contained in a register | A itself.
 ^ Assign to A a Word8 | itself.
 ^ Subtract from A the value in a Register8 and set flags accordingly, but don't store the result.
 ^ Subtract from A a Word8 and set flags accordingly, but don't store the result.
 ^ Increment the value in a Register8.
 ^ Decrement the value in a Register8.
 ^ Decimal-adjust register A.
 ^ Complement accumulator (A = ~A).
 ^ Increment the value in a Register16.
 ^ Decrement the value in a Register16.
 ^ Add an Int8 to the stack pointer.
 ^ Load into HL the stack pointer + an Int8.
 Single-bit instructions
 ^ Set bit n in a Register8.
 ^ Rotate accumulator left.
 ^ Rotate accumulator left through carry.
 ^ Rotate accumulator right.
 ^ Rotate accumulator rit through carry.
 ^ Rotate Register8 left.
 ^ Rotate Register8 left through carry.
 ^ Rotate Register8 right.
 ^ Rotate Register8 right through carry.
 ^ Shift Register8 left arithmetic.
 ^ Exchange low and high nibbles in Register8.
 ^ Shift Register8 right arithmetic.
 ^ Shift Register8 right logical.
 CPU control instructions
 ^ Complement carry flag.
 ^ Set carry flag.
 ^ No operation.
 ^ Halt until interrupt.
 ^ Standby mode.
 ^ Disable interrupts.
 ^ Enable interrupts.
 RGBASM-specific convenience stuff.
 these would need revamping if we were to start generating native machine code
 ^ Create a numbered label.
 ^ Define some bytes in the form of a Word8 list with a global label.
| 
     Module       : Lazyboy . Types 
     Description : Hardware type definitions for Lazyboy 
     Copyright    : ( c ) Rose 2019 
     License      : BSD3 
     Maintainer   :  
     Stability    : experimental 
     Portability : POSIX 

     This module defines datatypes for the various aspects of the target hardware 
     including registers and instructions . 

    Module      : Lazyboy.Types
    Description : Hardware type definitions for Lazyboy
    Copyright   : (c) Rose 2019
    License     : BSD3
    Maintainer  : 
    Stability   : experimental
    Portability : POSIX

    This module defines datatypes for the various aspects of the target hardware
    including registers and instructions.
-}


module Lazyboy.Types where

import Control.Monad.Trans.RWS.Lazy
import Data.Int
import Data.Word
import Formatting                   (formatToString, (%))
import Formatting.ShortFormatters   (x)

  | A type alias that defines Lazyboy as a specialization of the
  RWS monad transformer stack . Reader goes unused ,  is utilized
  for an output list of Instructions , and State is merely an integer
type Lazyboy a = RWS () [Instruction] Integer a

execLazyboy :: Lazyboy a -> [Instruction]
execLazyboy m = snd $ execRWS m () 1

data Location = Address Word16 | Name Label
  deriving (Eq)

instance Show Location where
    show (Address v)  = formatToString ("$" % x) v
    show (Name label) = show label

data Condition = Zero | NonZero | Carry | NoCarry
  deriving (Eq)

instance Show Condition where
    show Zero    = "z"
    show NonZero = "nz"
    show Carry   = "c"
    show NoCarry = "nc"

  | Named 8 - bit registers .
data Register8 = A | B | C | D | E | H | L
  deriving (Read, Show, Eq)

  | Named 16 - bit registers .
data Register16 = BC | DE | HL | AF | SP | PC
  deriving (Read, Show, Eq)

data Label = Local Integer | Global Integer
  deriving (Eq)

instance Show Label where
    show (Local v)  = ".L" ++ show v
    show (Global v) = "L" ++ show v

data Instruction =
  ^ Load the value in one Register8 into another .
  ^ Load the Word8 stored at the address in HL into a Register8 .
  ^ Load the Word8 stored in a Register8 into the address in HL .
  ^ Load the immediate Word8 into the address in HL .
  ^ Store the Word8 in A into IO port FF00+C.
  ^ Store value in register A into byte pointed by HL and post - increment HL .
  ^ Store value in address in HL in A and post - increment HL .
  ^ Store value in register A into byte pointed by HL and post - decrement HL .
  ^ Store value in address in HL in A and post - decrement HL .
  ^ Set the stack pointer ( SP ) to the value in HL .

  Jump & Call instructions
  ^ Immediately and unconditionally jump to the value contained in HL .

  Arithmetic & Logical instructions
  ^ Add the value contained in the address stored in HL to A.
  ^ Add the value pointed to by HL + the carry flag to A.
  ^ Subtract from A the value contained at the address in HL .
  ^ Assign to A the value contained in a Register8 & A itself .
  ^ Assign to A itself & the value in the address in HL .
  ^ Assign to A itself ^ the value in the address in HL .
  ^ Assign to A itself | the value in the address in HL
  ^ Subtract from A the value in the address in HL , set flags , but do n't store the result .
  ^ Increment the value at the address in HL .
  ^ Decrement the value at the address in HL .
  ^ Add the value contained in a Register16 to HL .

  ^ Test bit n in a Register8 , set the zero flag if not set .
  ^ Test bit n in the Word8 pointed by HL , set the zero flag if not set .
  ^ Set bit n in the Word8 pointed by HL .
  ^ Unset bit n in Register8 .
  ^ Unset bit n in the Word8 pointed by HL .

  Rotate & shift instructions
  ^ Rotate value contained at address in HL left .
  ^ Rotate value contained at address in HL left through carry .
  ^ Rotate value contained at address in HL right .
  ^ Rotate value contained at address in HL right through carry .
  ^ Shift left arithmetic ( HL pointer ) .
  ^ Exchange low and high nibbles in HL pointer .
  ^ Shift right arithmetic in HL pointer .
  ^ Shift right logical in HL pointer .


  ^ Include the file at FilePath .

  deriving (Eq)
