diff options
author | Aleksey Veresov <aleksey@veresov.pro> | 2021-04-07 23:35:02 +0300 |
---|---|---|
committer | Aleksey Veresov <aleksey@veresov.pro> | 2021-04-07 23:35:02 +0300 |
commit | b4605da3594b88f34087e4707e3129d98ff99ed6 (patch) | |
tree | e4667dc6a748a916d5763d1cc6d25b42fe0d80b5 /src/Control.hs | |
parent | 5dfcc43bfed0e3db9ec1fdae9dea6eea0c5ca220 (diff) | |
download | suem-b4605da3594b88f34087e4707e3129d98ff99ed6.tar suem-b4605da3594b88f34087e4707e3129d98ff99ed6.tar.xz suem-b4605da3594b88f34087e4707e3129d98ff99ed6.zip |
Change in modules.
Diffstat (limited to 'src/Control.hs')
-rw-r--r-- | src/Control.hs | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/src/Control.hs b/src/Control.hs new file mode 100644 index 0000000..65b3831 --- /dev/null +++ b/src/Control.hs @@ -0,0 +1,389 @@ +-- module describing control operations on machine +module Control where + +import Prelude hiding (Word) +import qualified Data.Vector.Unboxed as V +import qualified Data.Vector.Unboxed.Mutable as VM +import Data.Bits (testBit, setBit, clearBit, (.&.), (.|.), shift) +import Data.IORef +import Control.Monad +import Machine +import Utils +import Device + + +------------------------------------------------------------------------------- +-- 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 = deviceGetByte a + + -- TODO: only even addresses are allowed +getWord :: Long -> Emulator Word +getWord a | a < 0x800000 = do + g <- getByte a + l <- getByte (a + 1) + return $ (fromIntegral g) * 256 + (fromIntegral l) + | otherwise = deviceGetWord a + + -- 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 = deviceSetByte a b + + -- TODO: only even addresses are allowed +setWord :: Long -> Word -> Emulator () +setWord a w | a < 0x800000 = do + setByte a (fromIntegral (div (fromIntegral w) 256)) + setByte (a + 1) (fromIntegral (rem (fromIntegral w) 256)) + | otherwise = deviceSetWord a w + + -- 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) |