aboutsummaryrefslogtreecommitdiff
path: root/src/Machine.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Machine.hs')
-rw-r--r--src/Machine.hs381
1 files changed, 1 insertions, 380 deletions
diff --git a/src/Machine.hs b/src/Machine.hs
index a16127f..a1ea028 100644
--- a/src/Machine.hs
+++ b/src/Machine.hs
@@ -1,12 +1,11 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
--- This module describes the basic types and operations for our machine.
+-- This module describes the basic types for our machine.
module Machine where
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as VM
import Prelude hiding (Word)
import Data.Word (Word32, Word16, Word8)
-import Data.Bits (testBit, setBit, clearBit, (.&.), (.|.), shift)
import Data.IORef
import Control.Monad
import Control.Monad.IO.Class (liftIO)
@@ -16,9 +15,6 @@ import Network.Socket
import Utils
--------------------------------------------------------------------------------
--- Base Types
-
type Long = Word32
type Word = Word16
type Byte = Word8
@@ -50,378 +46,3 @@ with :: (Machine -> b) -> (b -> IO a) -> Emulator a
with field f = do
m <- ask
liftIO $ f (field m)
-
-
--------------------------------------------------------------------------------
--- Data and Address Registers Access
-
-readD :: Int -> Int -> Emulator Long
-readD 0 s = with drs $ \rs -> do
- (r,_,_,_,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readD 1 s = with drs $ \rs -> do
- (_,r,_,_,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readD 2 s = with drs $ \rs -> do
- (_,_,r,_,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readD 3 s = with drs $ \rs -> do
- (_,_,_,r,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readD 4 s = with drs $ \rs -> do
- (_,_,_,_,r,_,_,_) <- readIORef rs
- return $ convertLong r s
-readD 5 s = with drs $ \rs -> do
- (_,_,_,_,_,r,_,_) <- readIORef rs
- return $ convertLong r s
-readD 6 s = with drs $ \rs -> do
- (_,_,_,_,_,_,r,_) <- readIORef rs
- return $ convertLong r s
-readD 7 s = with drs $ \rs -> do
- (_,_,_,_,_,_,_,r) <- readIORef rs
- return $ convertLong r s
-readD _ _ = return $ error "Incorrect Data register read"
-
-readA :: Int -> Int -> Emulator Long
-readA 0 s = with ars $ \rs -> do
- (r,_,_,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readA 1 s = with ars $ \rs -> do
- (_,r,_,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readA 2 s = with ars $ \rs -> do
- (_,_,r,_,_,_,_) <- readIORef rs
- return $ convertLong r s
-readA 3 s = with ars $ \rs -> do
- (_,_,_,r,_,_,_) <- readIORef rs
- return $ convertLong r s
-readA 4 s = with ars $ \rs -> do
- (_,_,_,_,r,_,_) <- readIORef rs
- return $ convertLong r s
-readA 5 s = with ars $ \rs -> do
- (_,_,_,_,_,r,_) <- readIORef rs
- return $ convertLong r s
-readA 6 s = with ars $ \rs -> do
- (_,_,_,_,_,_,r) <- readIORef rs
- return $ convertLong r s
-readA 7 s = isSupervisor >>= \sup -> if sup
- then with ssp $ \sp -> do
- v <- readIORef sp
- return $ convertLong v s
- else with usp $ \sp -> do
- v <- readIORef sp
- return $ convertLong v s
-readA _ _ = return $ error "Incorrect Address register read"
-
-
-writeD :: Int -> Int -> Long -> Emulator ()
-writeD 0 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (combineLong r r0 s,r1,r2,r3,r4,r5,r6,r7)
-writeD 1 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,combineLong r r1 s,r2,r3,r4,r5,r6,r7)
-writeD 2 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,r1,combineLong r r2 s,r3,r4,r5,r6,r7)
-writeD 3 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,r1,r2,combineLong r r3 s,r4,r5,r6,r7)
-writeD 4 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,r1,r2,r3,combineLong r r4 s,r5,r6,r7)
-writeD 5 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,r0,r2,r3,r4,combineLong r r5 s,r6,r7)
-writeD 6 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,r1,r2,r3,r4,r5,combineLong r r6 s,r7)
-writeD 7 s r = with drs $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6,r7) <- readIORef rs
- writeIORef rs (r0,r1,r2,r3,r4,r5,r6,combineLong r r7 s)
-writeD _ _ _ = return $ error "Incorrect Data register write"
-
-writeA :: Int -> Int -> Long -> Emulator ()
-writeA 0 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (combineLong r r0 s,r1,r2,r3,r4,r5,r6)
-writeA 1 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (r0,combineLong r r1 s,r2,r3,r4,r5,r6)
-writeA 2 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (r0,r1,combineLong r r2 s,r3,r4,r5,r6)
-writeA 3 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (r0,r1,r2,combineLong r r3 s,r4,r5,r6)
-writeA 4 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (r0,r1,r2,r3,combineLong r r4 s,r5,r6)
-writeA 5 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (r0,r0,r2,r3,r4,combineLong r r5 s,r6)
-writeA 6 s r = with ars $ \rs -> do
- (r0,r1,r2,r3,r4,r5,r6) <- readIORef rs
- writeIORef rs (r0,r1,r2,r3,r4,r5,combineLong r r6 s)
-writeA 7 s r = isSupervisor >>= \sup -> if sup
- then with ssp $ \sp -> do
- v <- readIORef sp
- writeIORef sp $ combineLong r v s
- else with usp $ \sp -> do
- v <- readIORef sp
- writeIORef sp $ combineLong r v s
-writeA _ _ _ = return $ error "Incorrect Address register write"
-
-
--------------------------------------------------------------------------------
--- PC Register Access
-
-readPC = with pc $ \pc -> do
- pc <- readIORef pc
- return pc
-
-writePC r = with pc $ \pc -> do
- writeIORef pc r
-
-incPC = with pc $ \pc -> do
- pcval <- readIORef pc
- writeIORef pc (pcval + 2)
-
-
--------------------------------------------------------------------------------
--- Status Register Access
-
-writeSR :: Word -> Emulator ()
-writeSR v = with sr $ \sr -> do
- writeIORef sr v
-
-readSR :: Emulator Word
-readSR = with sr $ \sr -> do
- sr <- readIORef sr
- return sr
-
-
-isTracing :: Emulator Bool
-isTracing = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 15
-
-isSupervisor :: Emulator Bool
-isSupervisor = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 13
-
-interruptLevel :: Emulator Int
-interruptLevel = with sr $ \sr -> do
- sr <- readIORef sr
- return $ extractBits sr [5, 6, 7]
-
-isExtend :: Emulator Bool
-isExtend = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 4
-
-isNegative :: Emulator Bool
-isNegative = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 3
-
-isZero :: Emulator Bool
-isZero = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 2
-
-isOverflow :: Emulator Bool
-isOverflow = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 1
-
-isCarry :: Emulator Bool
-isCarry = with sr $ \sr -> do
- sr <- readIORef sr
- return $ testBit sr 0
-
-
-setTracing :: Bool -> Emulator ()
-setTracing b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 15
-
-setSupervisor :: Bool -> Emulator ()
-setSupervisor b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 13
-
-setInterruptLevel :: Int -> Emulator ()
-setInterruptLevel v = do
- srv <- readSR
- writeSR $ srv .&. fromIntegral 0xF8FF .|. fromIntegral (shift v 16)
-
-setExtend :: Bool -> Emulator ()
-setExtend b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 4
-
-setNegative :: Bool -> Emulator ()
-setNegative b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 3
-
-setZero :: Bool -> Emulator ()
-setZero b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 2
-
-setOverflow :: Bool -> Emulator ()
-setOverflow b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 1
-
-setCarry :: Bool -> Emulator ()
-setCarry b = with sr $ \sr -> do
- srval <- readIORef sr
- writeIORef sr $ (if b then setBit else clearBit) srval 0
-
-
--------------------------------------------------------------------------------
--- Memmory Access
-
-getByte :: Long -> Emulator Byte
-getByte a | a < 0x8 = with rom $ \rom -> return $ rom V.! fromIntegral a
- | a < 0x7e0000 = with ram $ \ram ->
- if VM.length ram >= fromIntegral a
- then VM.unsafeRead ram (fromIntegral a)
- else return 0xff
- | a < 0x800000 = with rom $ \rom ->
- return $ rom V.! (fromIntegral a - 0x7e0000)
- | otherwise = return 0xff
-
- -- TODO: only even addresses are allowed
-getWord :: Long -> Emulator Word
-getWord a = do
- g <- getByte a
- l <- getByte (a + 1)
- return $ (fromIntegral g) * 256 + (fromIntegral l)
-
- -- TODO: only even addresses are allowed
-getLong :: Long -> Emulator Long
-getLong a = do
- g <- getWord a
- l <- getWord (a + 2)
- return $ (fromIntegral g) * 256 * 256 + (fromIntegral l)
-
-
-setByte :: Long -> Byte -> Emulator ()
-setByte a b | a < 0x8 = return ()
- | a < 0x7e0000 = with ram $ \ram ->
- VM.write ram (fromIntegral a) b
- | otherwise = return ()
-
- -- TODO: only even addresses are allowed
-setWord :: Long -> Word -> Emulator ()
-setWord a w = do
- setByte a (fromIntegral (div (fromIntegral w) 256))
- setByte (a + 1) (fromIntegral (rem (fromIntegral w) 256))
-
- -- TODO: only even addresses are allowed
-setLong :: Long -> Long -> Emulator ()
-setLong a l = do
- setWord a (fromIntegral (div (fromIntegral l) (256 * 256)))
- setWord (a + 2) (fromIntegral (rem (fromIntegral l) (256 * 256)))
-
-
-getMemory :: Long -> Int -> Emulator Long
-getMemory a 1 = do
- val <- getByte a
- return $ fromIntegral val
-getMemory a 2 = do
- val <- getWord a
- return $ fromIntegral val
-getMemory a 4 = do
- val <- getLong a
- return $ fromIntegral val
-getMemory _ _ = error "Bad size of getMemory"
-
-setMemory :: Long -> Int -> Long -> Emulator ()
-setMemory a 1 v = setByte a $ fromIntegral v
-setMemory a 2 v = setWord a $ fromIntegral v
-setMemory a 4 v = setLong a $ fromIntegral v
-setMemory _ _ _ = error "Bad size of setMemory"
-
-
--------------------------------------------------------------------------------
--- Operand Access
-
-skipOp :: Int -> Emulator ()
-skipOp 1 = incPC
-skipOp 2 = incPC
-skipOp 4 = do
- incPC
- incPC
-skipOp _ = error "Bad skipOp"
-
-getOp :: Int -> Int -> Int
- -> Emulator (Emulator Long, Long -> Emulator ())
-getOp 0 dr s = return (readD dr s, writeD dr s)
-getOp 1 ar s = return (readA ar s, writeA ar s)
-getOp 2 ar s = do
- addr <- readA ar 4
- return (getMemory addr s, setMemory addr s)
-getOp 3 ar s = do
- addr <- readA ar 4
- writeA ar 4 (addr + (fromIntegral s))
- return (getMemory addr s, setMemory addr s)
-getOp 4 ar s = do
- addr <- readA ar 4
- let naddr = addr - (fromIntegral s)
- writeA ar 4 addr
- return (getMemory naddr s, setMemory naddr s)
-getOp 5 ar s = do
- pc <- readPC
- skipOp 2
- disp <- getMemory pc 2
- addr <- readA ar 4
- let naddr = addr + disp
- return (getMemory naddr s, setMemory naddr s)
-getOp 6 ar s = do
- pc <- readPC
- skipOp 2
- prefix <- getMemory pc 1
- index <- (if testBit prefix 0 then readA else readD)
- (extractBits prefix [1..3])
- ((extractBits prefix [4] + 1) * 2)
- disp <- getMemory (pc + 1) 1
- addr <- readA ar 4
- let naddr = addr + index + disp
- return (getMemory naddr s, setMemory naddr s)
-getOp 7 2 s = do
- addr <- readPC
- skipOp 2
- disp <- getMemory addr 2
- let naddr = addr + disp
- return (getMemory naddr s, setMemory naddr s)
-getOp 7 3 s = do
- addr <- readPC
- skipOp 2
- prefix <- getMemory addr 1
- index <- (if testBit prefix 0 then readA else readD)
- (extractBits prefix [1..3])
- ((extractBits prefix [4] + 1) * 2)
- disp <- getMemory (addr + 1) 1
- let naddr = addr + index + disp
- return (getMemory naddr s, setMemory naddr s)
-getOp 7 0 s = do
- pc <- readPC
- skipOp 2
- addr <- getMemory pc 2
- return (getMemory addr s, setMemory addr s)
-getOp 7 1 s = do
- pc <- readPC
- skipOp 4
- addr <- getLong pc
- return (getMemory addr s, setMemory addr s)
-getOp 7 4 s = do
- addr <- readPC
- skipOp s
- let naddr = addr + if s == 1 then 1 else 0
- return (getMemory naddr s, setMemory naddr s)