module ShamIV where import Hardware.Chalk import Control.Applicative import Control.Monad.State import Data.Stream (Stream(..)) import Data.Maybe data Reg = R0 | R1 | R2 | R3 deriving (Show, Eq) type Regs = (Int, Int, Int, Int) data Cmd = ADD | SUB | INC deriving (Show, Eq) type Operand = (Reg, Maybe Int) data Transaction = Transaction {dest :: Operand, cmd :: Cmd, srcs :: [Operand]} deriving (Show, Eq) setDest :: Transaction -> Int -> Transaction setDest (Transaction (r,_) cmd srcs) i = Transaction (r, Just i) cmd srcs initRegs :: Regs initRegs = (0,0,0,0) regFile :: Signal Transaction -> Signal Transaction -> Signal Transaction regFile writes reads = loop (regStep <$> writes <*> reads) initRegs regStep :: Transaction -> Transaction -> Regs -> (Transaction , Regs) regStep write@(Transaction wrOp _ _) read regs = let regs' = updateReg wrOp regs read' = updateTransaction regs read in (read' , regs') updateReg (R0, Just x) (a,b,c,d) = (x,b,c,d) updateReg (R1, Just x) (a,b,c,d) = (a,x,c,d) updateReg (R2, Just x) (a,b,c,d) = (a,b,x,d) updateReg (R3, Just x) (a,b,c,d) = (a,b,c,x) updateTransaction :: Regs -> Transaction -> Transaction updateTransaction regs t = t {srcs = map (updateOperand regs) (srcs t)} updateOperand regs (r, _ ) = (r , Just (lookupReg r regs)) lookupReg R0 (a,b,c,d) = a lookupReg R1 (a,b,c,d) = b lookupReg R2 (a,b,c,d) = c lookupReg R3 (a,b,c,d) = d alu :: Signal Transaction -> Signal Transaction alu cmds = interpret <$> cmds where interpret :: Transaction -> Transaction interpret trans@(Transaction dest cmd srcs) = setDest trans (eval cmd (map (fromJust . snd) srcs)) eval :: Cmd -> [Int] -> Int eval ADD [x, y] = x + y eval SUB [x, y] = x - y eval INC [x] = x + 1 sham :: Signal Transaction -> Signal Transaction sham instrs = aluOutputD where aluInput = regFile aluOutputD instrs aluOutput = alu aluInput aluOutputD = delay nop aluOutput nop = Transaction (R0, Just 0) ADD [(R0,Just 0) , (R0,Just 0)] bypass :: Signal Transaction -> Signal Transaction -> Signal Transaction bypass ins outs = checkHazard <$> ins <*> outs where checkHazard t1 t2 = let destReg = reg $ dest t2 sourceRegs = map reg $ srcs t1 new = t1 {srcs = merge (dest t2) (srcs t1)} merge :: Operand -> [Operand] -> [Operand] merge o os = map (mergeOp o) os mergeOp (r1,x) (r2,y) | r1 == r2 = (r2,x) | otherwise = (r1,x) in if destReg `elem` sourceRegs then new else t1 reg :: Operand -> Reg reg = fst