module Language.QBE.Simulator.Memory
(
Address,
Size,
showAddr,
Storable (toBytes, fromBytes),
Memory,
mkMemory,
memSize,
loadBytes,
storeBytes,
toMemAddr,
addrOverlap,
alignAddr,
)
where
import Data.Array.IO
( MArray,
getBounds,
newArray_,
readArray,
writeArray,
)
import Data.Bits (complement, (.&.))
import Data.Word (Word64)
import Language.QBE.Types qualified as QBE
import Numeric (showHex)
type Address = Word64
type Size = Word64
showAddr :: Address -> String
showAddr :: Address -> String
showAddr Address
addr = String
"0x" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Address -> String -> String
forall a. Integral a => a -> String -> String
showHex Address
addr String
""
class Storable valTy byteTy where
toBytes :: valTy -> [byteTy]
fromBytes :: QBE.LoadType -> [byteTy] -> Maybe valTy
data Memory a v = Memory
{ forall {k} (a :: * -> k -> *) (v :: k). Memory a v -> Address
memStart :: Address,
forall {k} (a :: * -> k -> *) (v :: k). Memory a v -> a Address v
memBytes :: a Address v
}
mkMemory :: (MArray t a IO) => Address -> Size -> IO (Memory t a)
mkMemory :: forall (t :: * -> * -> *) a.
MArray t a IO =>
Address -> Address -> IO (Memory t a)
mkMemory Address
startAddr Address
size = do
t Address a
ary <- (Address, Address) -> IO (t Address a)
forall i. Ix i => (i, i) -> IO (t i a)
forall (a :: * -> * -> *) e (m :: * -> *) i.
(MArray a e m, Ix i) =>
(i, i) -> m (a i e)
newArray_ (Address
0, Address
size Address -> Address -> Address
forall a. Num a => a -> a -> a
- Address
1)
Memory t a -> IO (Memory t a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Memory t a -> IO (Memory t a)) -> Memory t a -> IO (Memory t a)
forall a b. (a -> b) -> a -> b
$ Address -> t Address a -> Memory t a
forall {k} (a :: * -> k -> *) (v :: k).
Address -> a Address v -> Memory a v
Memory Address
startAddr t Address a
ary
toMemAddr :: Memory t a -> Address -> Address
toMemAddr :: forall {k} (t :: * -> k -> *) (a :: k).
Memory t a -> Address -> Address
toMemAddr Memory t a
mem Address
addr = Address
addr Address -> Address -> Address
forall a. Num a => a -> a -> a
- Memory t a -> Address
forall {k} (a :: * -> k -> *) (v :: k). Memory a v -> Address
memStart Memory t a
mem
addrOverlap :: Address -> Address -> Size -> Bool
addrOverlap :: Address -> Address -> Address -> Bool
addrOverlap Address
addr1 Address
addr2 Address
range =
Address
addr1 Address -> Address -> Bool
forall a. Ord a => a -> a -> Bool
< Address -> Address
endAddr Address
addr2 Bool -> Bool -> Bool
&& Address -> Address
endAddr Address
addr1 Address -> Address -> Bool
forall a. Ord a => a -> a -> Bool
> Address
addr2
where
endAddr :: Address -> Address
endAddr :: Address -> Address
endAddr Address
a = Address
a Address -> Address -> Address
forall a. Num a => a -> a -> a
+ Address
range
alignAddr :: Address -> Size -> Address
alignAddr :: Address -> Address -> Address
alignAddr Address
addr Address
align = (Address
addr Address -> Address -> Address
forall a. Num a => a -> a -> a
+ (Address
align Address -> Address -> Address
forall a. Num a => a -> a -> a
- Address
1)) Address -> Address -> Address
forall a. Bits a => a -> a -> a
.&. Address -> Address
forall a. Bits a => a -> a
complement (Address
align Address -> Address -> Address
forall a. Num a => a -> a -> a
- Address
1)
memSize :: (MArray t a IO) => Memory t a -> IO Size
memSize :: forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> IO Address
memSize = ((Address, Address) -> Address)
-> IO (Address, Address) -> IO Address
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Address -> Address -> Address
forall a. Num a => a -> a -> a
+ Address
1) (Address -> Address)
-> ((Address, Address) -> Address) -> (Address, Address) -> Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Address, Address) -> Address
forall a b. (a, b) -> b
snd) (IO (Address, Address) -> IO Address)
-> (Memory t a -> IO (Address, Address))
-> Memory t a
-> IO Address
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t Address a -> IO (Address, Address)
forall i. Ix i => t i a -> IO (i, i)
forall (a :: * -> * -> *) e (m :: * -> *) i.
(MArray a e m, Ix i) =>
a i e -> m (i, i)
getBounds (t Address a -> IO (Address, Address))
-> (Memory t a -> t Address a)
-> Memory t a
-> IO (Address, Address)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Memory t a -> t Address a
forall {k} (a :: * -> k -> *) (v :: k). Memory a v -> a Address v
memBytes
storeBytes :: (MArray t a IO) => Memory t a -> Address -> [a] -> IO ()
storeBytes :: forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> Address -> [a] -> IO ()
storeBytes Memory t a
mem Address
addr [a]
bytes =
((Address, a) -> IO ()) -> [(Address, a)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\(Address
off, a
val) -> Memory t a -> Address -> a -> IO ()
forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> Address -> a -> IO ()
storeByte Memory t a
mem (Address
addr Address -> Address -> Address
forall a. Num a => a -> a -> a
+ Address
off) a
val) ([(Address, a)] -> IO ()) -> [(Address, a)] -> IO ()
forall a b. (a -> b) -> a -> b
$
[Address] -> [a] -> [(Address, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Address
0 ..] [a]
bytes
where
storeByte :: (MArray t a IO) => Memory t a -> Address -> a -> IO ()
storeByte :: forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> Address -> a -> IO ()
storeByte Memory t a
m Address
a = t Address a -> Address -> a -> IO ()
forall (a :: * -> * -> *) e (m :: * -> *) i.
(MArray a e m, Ix i) =>
a i e -> i -> e -> m ()
writeArray (Memory t a -> t Address a
forall {k} (a :: * -> k -> *) (v :: k). Memory a v -> a Address v
memBytes Memory t a
m) (Address -> a -> IO ()) -> Address -> a -> IO ()
forall a b. (a -> b) -> a -> b
$ Memory t a -> Address -> Address
forall {k} (t :: * -> k -> *) (a :: k).
Memory t a -> Address -> Address
toMemAddr Memory t a
mem Address
a
{-# INLINEABLE storeBytes #-}
loadBytes :: (MArray t a IO) => Memory t a -> Address -> Size -> IO [a]
loadBytes :: forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> Address -> Address -> IO [a]
loadBytes Memory t a
mem Address
addr Address
byteSize =
(Address -> IO a) -> [Address] -> IO [a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (\Address
off -> Memory t a -> Address -> IO a
forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> Address -> IO a
loadByte Memory t a
mem (Address
addr Address -> Address -> Address
forall a. Num a => a -> a -> a
+ Address
off)) [Address
0 .. Address
byteSize Address -> Address -> Address
forall a. Num a => a -> a -> a
- Address
1]
where
loadByte :: (MArray t a IO) => Memory t a -> Address -> IO a
loadByte :: forall (t :: * -> * -> *) a.
MArray t a IO =>
Memory t a -> Address -> IO a
loadByte Memory t a
m = t Address a -> Address -> IO a
forall (a :: * -> * -> *) e (m :: * -> *) i.
(MArray a e m, Ix i) =>
a i e -> i -> m e
readArray (Memory t a -> t Address a
forall {k} (a :: * -> k -> *) (v :: k). Memory a v -> a Address v
memBytes Memory t a
m) (Address -> IO a) -> (Address -> Address) -> Address -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Memory t a -> Address -> Address
forall {k} (t :: * -> k -> *) (a :: k).
Memory t a -> Address -> Address
toMemAddr Memory t a
m
{-# INLINEABLE loadBytes #-}