lion-0.3.0.0: src/Lion/Core.hs
{-|
Module : Lion.Core
Description : Lion RISC-V Core
Copyright : (c) David Cox, 2021
License : BSD-3-Clause
Maintainer : standardsemiconductor@gmail.com
The Lion core is a 32-bit [RISC-V](https://riscv.org/about/) processor written in Haskell using [Clash](https://clash-lang.org). Note, all peripherals and memory must have single cycle latency. See [lion-soc](https://github.com/standardsemiconductor/lion/tree/main/lion-soc) for an example of using the Lion core in a system.
-}
module Lion.Core
( core
, defaultCoreConfig
, P.defaultPipeConfig
, CoreConfig(..)
, AluConfig(..)
, P.PipeConfig(..)
, FromCore(..)
, P.ToMem(..)
, P.MemoryAccess(..)
, Alu
) where
import Clash.Prelude
import Data.Proxy
import Data.Maybe
import Data.Monoid
import Lion.Alu
import Lion.Rvfi
import qualified Lion.Pipe as P
import qualified Lion.Instruction as I (Op(Add))
-- | Core configuration
--
-- ALU configuration default: `Soft`
newtype CoreConfig (startPC :: Nat) (a :: AluConfig) = CoreConfig
{ pipeConfig :: P.PipeConfig (startPC :: Nat) -- ^ pipeline configuration
}
deriving stock (Generic, Show, Eq)
-- | Default core configuration
--
-- ALU configuration = `Soft`
--
-- `pipeConfig` = `defaultPipeConfig`
defaultCoreConfig :: CoreConfig 0 'Soft
defaultCoreConfig = CoreConfig
{ pipeConfig = P.defaultPipeConfig
}
-- | Core outputs
data FromCore dom = FromCore
{ toMem :: Signal dom (Maybe P.ToMem) -- ^ shared memory and instruction bus, output from core to memory and peripherals
, toRvfi :: Signal dom Rvfi -- ^ formal verification interface output, see [lion-formal](https://github.com/standardsemiconductor/lion/tree/main/lion-formal) for usage
}
-- | RISC-V Core: RV32I
core
:: forall a startPC dom
. HiddenClockResetEnable dom
=> Alu a
=> (KnownNat startPC, startPC <= 0xFFFFFFFF)
=> CoreConfig (startPC :: Nat) (a :: AluConfig) -- ^ core configuration
-> Signal dom (BitVector 32) -- ^ core input, from memory/peripherals
-> FromCore dom -- ^ core output
core config toCore = FromCore
{ toMem = getFirst . P._toMem <$> fromPipe
, toRvfi = fromMaybe mkRvfi . getFirst . P._toRvfi <$> fromPipe
}
where
-- alu connection
aluOp = fromMaybe I.Add . getFirst . P._toAluOp <$> fromPipe
aluInput1 = fromMaybe 0 . getFirst . P._toAluInput1 <$> fromPipe
aluInput2 = fromMaybe 0 . getFirst . P._toAluInput2 <$> fromPipe
aluOutput = alu (Proxy :: Proxy a) aluOp aluInput1 aluInput2
-- reg bank connection
rs1Addr = fromMaybe 0 . getFirst . P._toRs1Addr <$> fromPipe
rs2Addr = fromMaybe 0 . getFirst . P._toRs2Addr <$> fromPipe
rdWrM = getFirst . P._toRd <$> fromPipe
(rs1Data, rs2Data) = regBank rs1Addr rs2Addr rdWrM
-- pipeline connection
fromPipe = P.pipe (pipeConfig config) $ P.ToPipe <$> rs1Data
<*> rs2Data
<*> aluOutput
<*> toCore
-- | Register bank
regBank
:: HiddenClockResetEnable dom
=> Signal dom (Unsigned 5) -- ^ Rs1 Addr
-> Signal dom (Unsigned 5) -- ^ Rs2 Addr
-> Signal dom (Maybe (Unsigned 5, BitVector 32)) -- ^ Rd Write
-> Unbundled dom (BitVector 32, BitVector 32) -- ^ (Rs1Data, Rs2Data)
regBank rs1Addr rs2Addr rdWrM = (regFile rs1Addr, regFile rs2Addr)
where
regFile = flip (readNew (blockRamPow2 (repeat 0))) rdWrM