-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathCPU.hs
More file actions
68 lines (57 loc) · 2.59 KB
/
Copy pathCPU.hs
File metadata and controls
68 lines (57 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleContexts #-}
module Hardware.CPU (CPUState, Halt(..), cpu) where
import Clash.Prelude
import Hardware.StackMachine (State(Initializing),
step1, step2, outputOf, terminal)
import Hardware.MMU (Pending, RAMStatus(NoUpdate), RAMAction(X),
initiate, next, service, check)
import Hardware.Model (Output(..))
-- Halt?
data Halt = DoHalt | Don'tHalt deriving (Show, Generic, NFDataX)
-- Are we waiting for a single memory action (read/write/etc.) to complete?
data Waiting = No | Yes deriving (Show, Generic, NFDataX)
-- We need to keep track of the evaluator state as well as the MMU state.
data CPUState = CPU State Pending Waiting deriving (Show, Generic, NFDataX)
-- The state of the MMU when the CPU is initialized.
-- If you look at the definition of step1, this corresponds
-- to loading the SKI combinator from 0x0. This is where the
-- root of the program tree goes.
bootup :: Pending
bootup = initiate (step1 Initializing)
-- The transition function of the CPU.
step :: CPUState -> RAMStatus -> (CPUState, RAMAction, Maybe Output)
step (CPU state pending Yes) NoUpdate = (CPU state pending Yes, X, Nothing)
step (CPU state pending _ ) update = (CPU state' pending'' waiting', action, output)
where
pending' = service pending update
result = check pending' -- Did we finish a transaction?
state' = case result of
Nothing -> state -- Memory transaction did not finish.
Just result -> step2 state result -- Finished! Calculate new state.
pending'' = case result of
Nothing -> pending' -- We can keep servicing this transaction
Just _ -> initiate (step1 state') -- Start servicing new transaction.
action = next pending''
output = case result of
Nothing -> Nothing -- We only output if we're in a brand new state
Just _ -> outputOf state' -- New state, new output.
waiting' = case action of
X -> No
_ -> Yes
checkIfDone :: CPUState -> Halt
checkIfDone (CPU state _ _) = if terminal state then DoHalt else Don'tHalt
cpu :: HiddenClockResetEnable System
=> Signal System RAMStatus
-> Signal System (RAMAction, Maybe Output, Halt)
cpu ramstatus = bundle (action, output, halt)
where
state :: Signal System CPUState
state = register (CPU Initializing bootup No) state'
state' :: Signal System CPUState
action :: Signal System RAMAction
output :: Signal System (Maybe Output)
(state', action, output) = unbundle $ step <$> state <*> ramstatus
halt :: Signal System Halt
halt = checkIfDone <$> state