packages feed

lion 0.1.0.0 → 0.2.0.0

raw patch · 7 files changed

+419/−186 lines, 7 filesdep ~clash-preludedep ~ice40-primdep ~lensPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: clash-prelude, ice40-prim, lens, mtl

API changes (from Hackage documentation)

- Lion.Core: [_toMem] :: FromCore dom -> Signal dom (Maybe ToMem)
- Lion.Core: [_toRvfi] :: FromCore dom -> Signal dom Rvfi
- Lion.Core: toMem :: forall dom_a19Es. Lens' (FromCore dom_a19Es) (Signal dom_a19Es (Maybe ToMem))
- Lion.Core: toRvfi :: forall dom_a19Es. Lens' (FromCore dom_a19Es) (Signal dom_a19Es Rvfi)
- Lion.Rvfi: instance Clash.XException.NFDataX (Lion.Rvfi.RvfiCsr n)
+ Lion.Core: CoreConfig :: PipeConfig -> CoreConfig (a :: AluConfig)
+ Lion.Core: Hard :: AluConfig
+ Lion.Core: PipeConfig :: BitVector 32 -> PipeConfig
+ Lion.Core: Soft :: AluConfig
+ Lion.Core: ToMem :: MemoryAccess -> BitVector 32 -> BitVector 4 -> Maybe (BitVector 32) -> ToMem
+ Lion.Core: [memAccess] :: ToMem -> MemoryAccess
+ Lion.Core: [memAddress] :: ToMem -> BitVector 32
+ Lion.Core: [memByteMask] :: ToMem -> BitVector 4
+ Lion.Core: [memWrite] :: ToMem -> Maybe (BitVector 32)
+ Lion.Core: [pipeConfig] :: CoreConfig (a :: AluConfig) -> PipeConfig
+ Lion.Core: [startPC] :: PipeConfig -> BitVector 32
+ Lion.Core: [toMem] :: FromCore dom -> Signal dom (Maybe ToMem)
+ Lion.Core: [toRvfi] :: FromCore dom -> Signal dom Rvfi
+ Lion.Core: class Alu (config :: AluConfig)
+ Lion.Core: data AluConfig
+ Lion.Core: data MemoryAccess
+ Lion.Core: defaultCoreConfig :: CoreConfig 'Soft
+ Lion.Core: defaultPipeConfig :: PipeConfig
+ Lion.Core: instance GHC.Classes.Eq (Lion.Core.CoreConfig a)
+ Lion.Core: instance GHC.Generics.Generic (Lion.Core.CoreConfig a)
+ Lion.Core: instance GHC.Show.Show (Lion.Core.CoreConfig a)
+ Lion.Core: newtype CoreConfig (a :: AluConfig)
+ Lion.Core: newtype PipeConfig
+ Lion.Rvfi: instance GHC.TypeNats.KnownNat n => Clash.XException.NFDataX (Lion.Rvfi.RvfiCsr n)
- Lion.Core: DataMem :: BitVector 32 -> BitVector 4 -> Maybe (BitVector 32) -> ToMem
+ Lion.Core: DataMem :: MemoryAccess
- Lion.Core: InstrMem :: BitVector 32 -> ToMem
+ Lion.Core: InstrMem :: MemoryAccess
- Lion.Core: core :: HiddenClockResetEnable dom => BitVector 32 -> Signal dom (BitVector 32) -> FromCore dom
+ Lion.Core: core :: forall a dom. HiddenClockResetEnable dom => Alu a => CoreConfig (a :: AluConfig) -> Signal dom (BitVector 32) -> FromCore dom
- Lion.Rvfi: rdataCsr :: forall n_aJcW. Lens' (RvfiCsr n_aJcW) ((:::) "rdata" (BitVector n_aJcW))
+ Lion.Rvfi: rdataCsr :: forall n_aKUp. Lens' (RvfiCsr n_aKUp) ((:::) "rdata" (BitVector n_aKUp))
- Lion.Rvfi: rmaskCsr :: forall n_aJcW. Lens' (RvfiCsr n_aJcW) ((:::) "rmask" (BitVector n_aJcW))
+ Lion.Rvfi: rmaskCsr :: forall n_aKUp. Lens' (RvfiCsr n_aKUp) ((:::) "rmask" (BitVector n_aKUp))
- Lion.Rvfi: wdataCsr :: forall n_aJcW. Lens' (RvfiCsr n_aJcW) ((:::) "wdata" (BitVector n_aJcW))
+ Lion.Rvfi: wdataCsr :: forall n_aKUp. Lens' (RvfiCsr n_aKUp) ((:::) "wdata" (BitVector n_aKUp))
- Lion.Rvfi: wmaskCsr :: forall n_aJcW. Lens' (RvfiCsr n_aJcW) ((:::) "wmask" (BitVector n_aJcW))
+ Lion.Rvfi: wmaskCsr :: forall n_aKUp. Lens' (RvfiCsr n_aKUp) ((:::) "wmask" (BitVector n_aKUp))

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for lion +## 0.2.0.0 -- 2021-03-27++* Update core/memory/peripheral interface+* Configurable ALU: choose between SB_MAC16 or generic (+) and (-)+* Optimize branch path for better fMax+ ## 0.1.0.0 -- 2021-02-28  * First version.
README.md view
@@ -6,10 +6,11 @@  Lion is a formally verified, 5-stage pipeline [RISC-V](https://riscv.org) core. Lion targets the [VELDT FPGA development board](https://standardsemiconductor.com) and is written in Haskell using [Clash](https://clash-lang.org). -This repository contains three parts:+This repository contains four parts:   1. The Lion library: a pipelined RISC-V core.   2. [lion-formal](https://github.com/standardsemiconductor/lion/tree/main/lion-formal): formally verify the core using [riscv-formal](https://github.com/standardsemiconductor/riscv-formal/tree/lion).   3. [lion-soc](https://github.com/standardsemiconductor/lion/tree/main/lion-soc): a System-on-Chip demonstrating usage of the Lion core on the VELDT.+  4. [lion-metric](https://github.com/standardsemiconductor/lion/tree/main/lion-metric): Observe Yosys synthesis metrics on the Lion Core.  ## Lion library ### Usage:@@ -18,16 +19,23 @@  When connecting the `core` to memory and peripherals, ensure single cycle latency. +## Clone the repository+1. `git clone https://github.com/standardsemiconductor/lion.git`+2. `cd lion`+3. `git submodule update --init`+ ## Features ### Current Support-Architecture: RV32I (no FENCE, ECALL, EBREAK) -- Default configuration+* Architecture: RV32I (no FENCE, ECALL, EBREAK)+* Configurable ALU adder and subtractor: use a generic (+) and (-) or SB_MAC16 hard IP  ### Future Support -**All features will be added in a configurable manner extending the default configuration noted above**+**All features will be added in a configurable manner extending the base RV32I configuration noted above** * Zicsr, Control and Status Register (CSR) Instructions * CSR registers * RV32IM-* Hard IP ALU++Check out the [Lion Development project](https://github.com/standardsemiconductor/lion/projects/1) to see which features are in progress.  [hackage]:            <https://hackage.haskell.org/package/lion> [hackage-badge]:      <https://img.shields.io/hackage/v/lion.svg?color=success>
lion.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               lion-version:            0.1.0.0+version:            0.2.0.0 synopsis:           RISC-V Core description:        Lion is a formally verified, 5-stage pipeline [RISC-V](https://riscv.org) core. Lion targets the [VELDT FPGA development board](https://standardsemiconductor.com) and is written in Haskell using [Clash](https://clash-lang.org). bug-reports:        https://github.com/standardsemiconductor/lion/issues@@ -21,18 +21,19 @@ library   exposed-modules: Lion.Core                  , Lion.Rvfi-  other-modules:   Lion.Instruction+  other-modules:   Lion.Alu+                 , Lion.Instruction                  , Lion.Pipe   hs-source-dirs: src   default-language: Haskell2010   build-depends: -    base >= 4.13 && < 4.15,+    base           >= 4.13  && < 4.15,     Cabal,-    generic-monoid >= 0.1 && < 0.2,-    mtl,-    lens,-    ice40-prim >= 0.1 && < 0.2,-    clash-prelude >= 1.2.5 && < 1.4,+    generic-monoid >= 0.1   && < 0.2,+    mtl            >= 2.2   && < 2.3,+    lens           >= 4.19  && < 5.1,+    ice40-prim     >= 0.3   && < 0.4,+    clash-prelude  >= 1.2.5 && < 1.5,     ghc-typelits-natnormalise,     ghc-typelits-extra,     ghc-typelits-knownnat@@ -57,11 +58,13 @@     GeneralizedNewtypeDeriving     LambdaCase     MagicHash+    MultiParamTypeClasses     MultiWayIf     NoImplicitPrelude     NoStarIsType     PolyKinds     RankNTypes+    ScopedTypeVariables     TemplateHaskell     TupleSections     TypeFamilies
+ src/Lion/Alu.hs view
@@ -0,0 +1,103 @@+{-| +Module      : Lion.Alu+Description : Lion arithmetic logic unit+Copyright   : (c) David Cox, 2021+License     : BSD-3-Clause+Maintainer  : standardsemiconductor@gmail.com++Configurable alu, choose between soft and hard adders/subtractors+-}++module Lion.Alu where++import Clash.Prelude+import Data.Function ( on )+import Data.Proxy+import Ice40.Mac +import Lion.Instruction++-- | ALU configuration+data AluConfig = Hard -- ^ use hard adder and subtractor from iCE40 SB_MAC16+               | Soft -- ^ use generic adder and subtractor: (+) and (-)+  deriving stock (Generic, Show, Eq)++class Alu (config :: AluConfig) where+  alu :: HiddenClockResetEnable dom +      => Proxy (config :: AluConfig)+      -> Signal dom Op+      -> Signal dom (BitVector 32)+      -> Signal dom (BitVector 32)+      -> Signal dom (BitVector 32)++instance Alu 'Soft where+  alu _ op in1 = register 0 . liftA3 aluFunc op in1 +    where+      aluFunc = \case +        Add  -> (+)+        Sub  -> (-)+        Sll  -> \x y -> x `shiftL` shamt y+        Slt  -> boolToBV ... (<) `on` sign+        Sltu -> boolToBV ... (<)+        Xor  -> xor+        Srl  -> \x y -> x `shiftR` shamt y+        Sra  -> \x y -> pack $ sign x `shiftR` shamt y+        Or   -> (.|.)+        And  -> (.&.)+        where+          shamt = unpack . resize . slice d4 d0+          sign = unpack :: BitVector 32 -> Signed 32+          (...) = (.).(.)+      +instance Alu 'Hard where+  alu _ op in1 in2 = mux isAddSub adderSubtractor $ register 0 $ baseAlu op in1 in2+    where+      isAdd = (Add == ) <$> op+      isSub = (Sub == ) <$> op+      isAddSub = delay False $ isAdd .||. isSub+      adderSubtractor = hardAddSub (boolToBit <$> isSub) in1 in2+  +baseAlu+  :: Signal dom Op+  -> Signal dom (BitVector 32)+  -> Signal dom (BitVector 32)+  -> Signal dom (BitVector 32)+baseAlu = liftA3 $ \case +  Add  -> \_ _ -> 0+  Sub  -> \_ _ -> 0+  Sll  -> \x y -> x `shiftL` shamt y+  Slt  -> boolToBV ... (<) `on` sign+  Sltu -> boolToBV ... (<)+  Xor  -> xor+  Srl  -> \x y -> x `shiftR` shamt y+  Sra  -> \x y -> pack $ sign x `shiftR` shamt y+  Or   -> (.|.)+  And  -> (.&.)+  where+    shamt = unpack . resize . slice d4 d0+    sign = unpack :: BitVector 32 -> Signed 32+    (...) = (.).(.)++-- | addSub32PipelinedUnsigned+hardAddSub+  :: HiddenClock dom+  => Signal dom Bit -- 0 = Add, 1 = Sub+  -> Signal dom (BitVector 32)+  -> Signal dom (BitVector 32)+  -> Signal dom (BitVector 32)+hardAddSub addSub x y = out+  where+    (out, _, _, _) = mac parameter input+    input = defaultInput{ a = slice d31 d16 <$> y+                        , b = slice d15 d0  <$> y+                        , c = slice d31 d16 <$> x+                        , d = slice d15 d0  <$> x+                        , addsubtop = addSub+                        , addsubbot = addSub+                        }+    parameter = defaultParameter{ topOutputSelect = 1+                                , topAddSubUpperInput = 1+                                , topAddSubCarrySelect = 2+                                , botOutputSelect = 1+                                , botAddSubUpperInput = 1+                                , mode8x8 = 1+                                }
src/Lion/Core.hs view
@@ -5,47 +5,84 @@ License     : BSD-3-Clause Maintainer  : standardsemiconductor@gmail.com -The Lion core is a 32-bit RISC-V 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.+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(..)-  , toMem-  , toRvfi   , P.ToMem(..)+  , P.MemoryAccess(..)+  , Alu   ) where  import Clash.Prelude-import Control.Lens+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 (a :: AluConfig) = CoreConfig+  { pipeConfig :: P.PipeConfig -- ^ pipeline configuration+  }+  deriving stock (Generic, Show, Eq)++-- | Default core configuration+--+-- ALU configuration = `Soft`+--+-- `pipeConfig` = `defaultPipeConfig`+defaultCoreConfig :: CoreConfig '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+  { 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   }-makeLenses ''FromCore --- | RISC-V Core+-- | RISC-V Core: RV32I core-  :: HiddenClockResetEnable dom-  => BitVector 32               -- ^ start address-  -> Signal dom (BitVector 32)  -- ^ core input, from memory/peripherals-  -> FromCore dom               -- ^ core output-core start toCore = FromCore-  { _toMem  = getFirst . P._toMem <$> fromPipe-  , _toRvfi = fromMaybe mkRvfi . getFirst . P._toRvfi <$> fromPipe+  :: forall a dom+   . HiddenClockResetEnable dom+  => Alu a+  => CoreConfig (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-    fromPipe = P.pipe start $ P.ToPipe <$> rs1Data <*> rs2Data <*> toCore+    -- 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
src/Lion/Instruction.hs view
@@ -15,6 +15,7 @@   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +-- | Writeback pipeline instruction data WbInstr = WbRegWr (Unsigned 5) (BitVector 32)              | WbLoad Load (Unsigned 5) (BitVector 4)              | WbStore@@ -22,14 +23,19 @@   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX -data MeInstr = MeRegWr      (Unsigned 5) (BitVector 32)+-- | Memory pipeline instruction+data MeInstr = MeRegWr      (Unsigned 5)+             | MeJump       (Unsigned 5) (BitVector 32)+             | MeBranch               | MeStore                   (BitVector 32) (BitVector 4) (BitVector 32)              | MeLoad  Load (Unsigned 5) (BitVector 32) (BitVector 4)              | MeNop   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +-- | Execute pipeline instruction data ExInstr = Ex       ExOp   (Unsigned 5) (BitVector 32)+             | ExJump   Jump   (Unsigned 5) (BitVector 32)              | ExBranch Branch              (BitVector 32)              | ExStore  Store               (BitVector 32)              | ExLoad   Load   (Unsigned 5) (BitVector 32)@@ -38,6 +44,7 @@   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +-- | ALU operation data Op = Add         | Sub         | Sll@@ -51,23 +58,7 @@   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX -alu :: Op -> BitVector 32 -> BitVector 32 -> BitVector 32-alu = \case-  Add  -> (+)-  Sub  -> (-)-  Sll  -> \x y -> x `shiftL` shamt y-  Slt  -> boolToBV ... (<) `on` sign-  Sltu -> boolToBV ... (<)-  Xor  -> xor-  Srl  -> \x y -> x `shiftR` shamt y-  Sra  -> \x y -> pack $ sign x `shiftR` shamt y-  Or   -> (.|.)-  And  -> (.&.)-  where-    shamt = unpack . resize . slice d4 d0-    sign = unpack :: BitVector 32 -> Signed 32-    (...) = (.).(.)-+-- | Branch operation data Branch = Beq             | Bne             | Blt@@ -77,6 +68,7 @@   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +-- | branch calculation branch :: Branch -> BitVector 32 -> BitVector 32 -> Bool branch = \case   Beq  -> not ... (/=)@@ -92,17 +84,21 @@  data ExOp = Lui           | Auipc-          | Jal-          | Jalr   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +data Jump = Jal | Jalr+  deriving stock (Generic, Show, Eq)+  deriving anyclass NFDataX++-- | Store operation data Store = Sb            | Sh            | Sw   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +-- | Load operation data Load = Lb           | Lh           | Lw@@ -115,8 +111,8 @@ parseInstr i = case i of   $(bitPattern ".........................0110111") -> Right $ Ex Lui   rd immU -- lui   $(bitPattern ".........................0010111") -> Right $ Ex Auipc rd immU -- auipc-  $(bitPattern ".........................1101111") -> Right $ Ex Jal   rd immJ -- jal-  $(bitPattern ".................000.....1100111") -> Right $ Ex Jalr  rd immI -- jalr+  $(bitPattern ".........................1101111") -> Right $ ExJump Jal  rd immJ -- jal+  $(bitPattern ".................000.....1100111") -> Right $ ExJump Jalr rd immI -- jalr   $(bitPattern ".................000.....1100011") -> Right $ ExBranch Beq  immB -- beq   $(bitPattern ".................001.....1100011") -> Right $ ExBranch Bne  immB -- bne   $(bitPattern ".................100.....1100011") -> Right $ ExBranch Blt  immB -- blt@@ -152,6 +148,9 @@   $(bitPattern "0000000..........111.....0110011") -> Right $ ExAlu And  rd -- and   _ -> Left IllegalInstruction   where+--    npcB = immB + pc+--    npcJ = immJ + pc+     rd = sliceRd i      immI :: BitVector 32@@ -164,7 +163,7 @@     immB = signExtend (slice d31 d31 i ++# slice d7 d7 i ++# slice d30 d25 i ++# slice d11 d8 i) `shiftL` 1      immU :: BitVector 32-    immU = (slice d31 d12 i) ++# 0+    immU = slice d31 d12 i ++# 0          immJ :: BitVector 32     immJ = signExtend (slice d31 d31 i ++# slice d19 d12 i ++# slice d20 d20 i ++# slice d30 d25 i ++# slice d24 d21 i) `shiftL` 1
src/Lion/Pipe.hs view
@@ -16,35 +16,79 @@ import Lion.Instruction import Lion.Rvfi +-- | Pipeline configuration+newtype PipeConfig = PipeConfig+  { startPC :: BitVector 32 -- ^ initial Program Counter address, default = 0+  }+  deriving stock (Generic, Show, Eq)++-- | Default pipeline configuration+-- +-- `startPC` = 0+defaultPipeConfig :: PipeConfig+defaultPipeConfig = PipeConfig 0+ -- | Pipeline inputs data ToPipe = ToPipe   { _fromRs1 :: BitVector 32   , _fromRs2 :: BitVector 32+  , _fromAlu :: BitVector 32   , _fromMem :: BitVector 32   }   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX makeLenses ''ToPipe +-- | Memory access - Lion has a shared instruction/memory bus+data MemoryAccess = InstrMem -- ^ instruction access+                  | DataMem  -- ^ data access+  deriving stock (Generic, Show, Eq)+  deriving anyclass NFDataX+ -- | Memory bus------   Lion has a shared instruction/memory bus-data ToMem = InstrMem         -- ^ instruction read-               (BitVector 32) -- ^ instruction address-           | DataMem                  -- ^ data access-               (BitVector 32)         -- ^ data address-               (BitVector 4)          -- ^ data byte mask-               (Maybe (BitVector 32)) -- ^ read=Nothing write=(Just wr)+data ToMem = ToMem+  { memAccess   :: MemoryAccess         -- ^ memory access type+  , memAddress  :: BitVector 32         -- ^ memory address+  , memByteMask :: BitVector 4          -- ^ memory byte mask+  , memWrite    :: Maybe (BitVector 32) -- ^ read=Nothing write=Just wr+  }   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX +-- | Construct instruction memory access+instrMem +  :: BitVector 32 -- ^ instruction address+  -> ToMem+instrMem addr = ToMem+  { memAccess   = InstrMem+  , memAddress  = addr+  , memByteMask = 0xF+  , memWrite    = Nothing+  }++-- | Construct data memory access+dataMem +  :: BitVector 32         -- ^ memory address+  -> BitVector 4          -- ^ byte mask+  -> Maybe (BitVector 32) -- ^ write+  -> ToMem+dataMem addr mask wrM = ToMem+  { memAccess   = DataMem+  , memAddress  = addr+  , memByteMask = mask+  , memWrite    = wrM+  }+ -- | Pipeline outputs data FromPipe = FromPipe-  { _toMem     :: First ToMem-  , _toRs1Addr :: First (Unsigned 5)-  , _toRs2Addr :: First (Unsigned 5)-  , _toRd      :: First (Unsigned 5, BitVector 32)-  , _toRvfi    :: First Rvfi+  { _toMem       :: First ToMem+  , _toRs1Addr   :: First (Unsigned 5)+  , _toRs2Addr   :: First (Unsigned 5)+  , _toRd        :: First (Unsigned 5, BitVector 32)+  , _toAluOp     :: First Op+  , _toAluInput1 :: First (BitVector 32)+  , _toAluInput2 :: First (BitVector 32)+  , _toRvfi      :: First Rvfi   }   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX@@ -53,14 +97,15 @@ makeLenses ''FromPipe  data Control = Control-  { _firstCycle :: Bool                             -- ^ First cycle True, then always False-  , _branching  :: Maybe (BitVector 32)             -- ^ execute stage branch-  , _deLoad     :: Bool                             -- ^ decode stage load-  , _exLoad     :: Bool                             -- ^ execute stage load-  , _meMemory   :: Bool                             -- ^ memory stage load/store-  , _wbMemory   :: Bool                             -- ^ writeback stage load/store-  , _meRegFwd   :: Maybe (Unsigned 5, BitVector 32) -- ^ memory stage register forwarding-  , _wbRegFwd   :: Maybe (Unsigned 5, BitVector 32) -- ^ writeback stage register forwading+  { _firstCycle  :: Bool                             -- ^ First cycle True, then always False+  , _exBranching :: Maybe (BitVector 32)             -- ^ execute stage branch/jump+  , _meBranching :: Bool                             -- ^ memory stage branch/jump+  , _deLoad      :: Bool                             -- ^ decode stage load+  , _exLoad      :: Bool                             -- ^ execute stage load+  , _meMemory    :: Bool                             -- ^ memory stage load/store+  , _wbMemory    :: Bool                             -- ^ writeback stage load/store+  , _meRegFwd    :: Maybe (Unsigned 5, BitVector 32) -- ^ memory stage register forwarding+  , _wbRegFwd    :: Maybe (Unsigned 5, BitVector 32) -- ^ writeback stage register forwading   }   deriving stock (Generic, Show, Eq)   deriving anyclass NFDataX@@ -68,14 +113,15 @@  mkControl :: Control mkControl = Control -  { _firstCycle = True   -  , _branching  = Nothing-  , _deLoad     = False-  , _exLoad     = False-  , _meMemory   = False-  , _wbMemory   = False-  , _meRegFwd   = Nothing-  , _wbRegFwd   = Nothing+  { _firstCycle  = True   +  , _exBranching = Nothing+  , _meBranching = False+  , _deLoad      = False+  , _exLoad      = False+  , _meMemory    = False+  , _wbMemory    = False+  , _meRegFwd    = Nothing+  , _wbRegFwd    = Nothing   }  data Pipe = Pipe@@ -107,9 +153,9 @@   deriving anyclass NFDataX makeLenses ''Pipe -mkPipe :: BitVector 32 -> Pipe-mkPipe start = Pipe-  { _fetchPC = start  +mkPipe :: PipeConfig -> Pipe+mkPipe config = Pipe+  { _fetchPC = startPC config    -- decode stage    , _dePC    = 0@@ -137,34 +183,23 @@ -- | 5-Stage RISC-V pipeline pipe    :: HiddenClockResetEnable dom-  => BitVector 32+  => PipeConfig   -> Signal dom ToPipe   -> Signal dom FromPipe-pipe start = mealy pipeMealy (mkPipe start)+pipe config = mealy pipeMealy (mkPipe config)   where     pipeMealy s i = let ((), s', o) = runRWS pipeM i s                     in (s', o)  --- | reset control signals (except first cycle)-resetControl :: MonadState Pipe m => m ()-resetControl = do-  control.branching .= Nothing-  control.deLoad    .= False-  control.exLoad    .= False-  control.meMemory  .= False-  control.wbMemory  .= False-  control.meRegFwd  .= Nothing-  control.wbRegFwd  .= Nothing- -- | Monadic pipeline pipeM :: RWS ToPipe FromPipe Pipe () pipeM = do-  resetControl   writeback   memory   execute   decode   fetch+  control .= mkControl{ _firstCycle = False } -- reset control  -- | Writeback stage writeback :: RWS ToPipe FromPipe Pipe ()@@ -201,20 +236,28 @@   wbIR   .= Nothing   wbRvfi <~ use meRvfi   withInstr meIR $ \case-    MeRegWr rd wr -> do+    MeNop -> wbIR ?= WbNop+    MeRegWr rd -> do+      wr <- view fromAlu       control.meRegFwd ?= (rd, wr)       wbIR ?= WbRegWr rd wr-    MeNop -> wbIR ?= WbNop+    MeJump rd pc4 -> do+      control.meBranching .= True+      control.meRegFwd ?= (rd, pc4)+      wbIR ?= WbRegWr rd pc4+    MeBranch -> do+      control.meBranching .= True+      wbIR ?= WbNop     MeStore addr mask value -> do       control.meMemory .= True-      scribe toMem $ First $ Just $ DataMem addr mask $ Just value+      scribe toMem $ First $ Just $ dataMem addr mask $ Just value       wbRvfi.rvfiMemAddr  .= addr       wbRvfi.rvfiMemWMask .= mask       wbRvfi.rvfiMemWData .= value       wbIR ?= WbStore     MeLoad op rdAddr addr mask -> do       control.meMemory .= True-      scribe toMem $ First $ Just $ DataMem addr mask Nothing+      scribe toMem $ First $ Just $ dataMem addr mask Nothing       wbRvfi.rvfiMemAddr  .= addr       wbRvfi.rvfiMemRMask .= mask       wbIR ?= WbLoad op rdAddr mask@@ -224,30 +267,37 @@ execute = do   meIR .= Nothing   meRvfi <~ use exRvfi-  pc <- meRvfi.rvfiPcRData <<~ use exPC-  meRvfi.rvfiPcWData .= pc + 4+  pc  <- meRvfi.rvfiPcRData <<~ use exPC+  pc4 <- meRvfi.rvfiPcWData <.= pc + 4   rs1Data <- meRvfi.rvfiRs1Data <<~ regFwd exRs1 fromRs1 (control.meRegFwd) (control.wbRegFwd)   rs2Data <- meRvfi.rvfiRs2Data <<~ regFwd exRs2 fromRs2 (control.meRegFwd) (control.wbRegFwd)   withInstr exIR $ \case     Ex op rd imm -> case op of-      Lui -> meIR ?= MeRegWr rd imm-      Auipc -> meIR ?= MeRegWr rd (pc + imm) -      Jal -> do-        npc <- meRvfi.rvfiPcWData <.= pc + imm-        meRvfi.rvfiTrap ||= (npc .&. 0x3 /= 0)-        control.branching ?= npc-        meIR ?= MeRegWr rd (pc + 4)-      Jalr -> do-        npc <- meRvfi.rvfiPcWData <.= clearBit (rs1Data + imm) 0-        meRvfi.rvfiTrap ||= (npc .&. 0x3 /= 0)-        control.branching ?= npc-        meIR ?= MeRegWr rd (pc + 4)-    ExBranch op imm -> do-      npc <- meRvfi.rvfiPcWData <<~ if branch op rs1Data rs2Data-                                      then control.branching <?= (pc + imm)-                                      else return $ pc + 4-      meRvfi.rvfiTrap ||= (npc .&. 0x3 /= 0)-      meIR ?= MeNop+      Lui -> do +        scribeAlu Add 0 imm+        meIR ?= MeRegWr rd+      Auipc -> do+        scribeAlu Add pc imm+        meIR ?= MeRegWr rd+    ExJump jump rd imm -> do+      case jump of+        Jal -> do+          npc <- meRvfi.rvfiPcWData <<~ control.exBranching <?= pc + imm+          meRvfi.rvfiTrap ||= isMisaligned npc+          meIR ?= MeJump rd pc4+        Jalr -> do+          npc <- meRvfi.rvfiPcWData <<~ control.exBranching <?= clearBit (rs1Data + imm) 0+          meRvfi.rvfiTrap ||= isMisaligned npc+          meIR ?= MeJump rd pc4+    ExBranch op imm ->+      if branch op rs1Data rs2Data+        then do+          branchPC <- meRvfi.rvfiPcWData <<~ control.exBranching <?= pc + imm+          meRvfi.rvfiTrap ||= isMisaligned branchPC+          meIR ?= MeBranch+        else do+          meRvfi.rvfiTrap ||= isMisaligned pc4+          meIR ?= MeNop     ExStore op imm -> do       let addr = rs1Data + imm            -- unaligned           addr' = addr .&. complement 0x3 -- aligned@@ -255,11 +305,11 @@         Sb -> let wr = concatBitVector# $ replicate d4 $ slice d7 d0 rs2Data               in meIR ?= MeStore addr' (byteMask addr) wr         Sh -> do-          meRvfi.rvfiTrap ||= (addr .&. 0x1 /= 0) -- trap on half-word boundary+          meRvfi.rvfiTrap ||= isMisalignedHalf addr -- trap on half-word boundary           let wr = concatBitVector# $ replicate d2 $ slice d15 d0 rs2Data           meIR ?= MeStore addr' (halfMask addr) wr         Sw -> do-          meRvfi.rvfiTrap ||= (addr .&. 0x3 /= 0) -- trap on word boundary+          meRvfi.rvfiTrap ||= isMisaligned addr -- trap on word boundary           meIR ?= MeStore addr' 0xF rs2Data     ExLoad op rdAddr imm -> do       control.exLoad .= True@@ -267,15 +317,28 @@           addr' = addr .&. complement 0x3 -- aligned       if | op == Lb || op == Lbu -> meIR ?= MeLoad op rdAddr addr' (byteMask addr)          | op == Lh || op == Lhu -> do-             meRvfi.rvfiTrap ||= (addr .&. 0x1 /= 0) -- trap on half-word boundary+             meRvfi.rvfiTrap ||= isMisalignedHalf addr -- trap on half-word boundary              meIR ?= MeLoad op rdAddr addr' (halfMask addr)          | otherwise -> do -- Lw-             meRvfi.rvfiTrap ||= (addr .&. 0x3 /= 0) -- trap on word boundary+             meRvfi.rvfiTrap ||= isMisaligned addr -- trap on word boundary              meIR ?= MeLoad op rdAddr addr' 0xF-    ExAlu    op rd     -> meIR ?= MeRegWr rd (alu op rs1Data rs2Data)-    ExAluImm op rd imm -> meIR ?= MeRegWr rd (alu op rs1Data imm)+    ExAlu op rd -> do+      scribeAlu op rs1Data rs2Data+      meIR ?= MeRegWr rd+    ExAluImm op rd imm -> do+      scribeAlu op rs1Data imm+      meIR ?= MeRegWr rd   where-    guardZero :: MonadState s m => Lens' s (Unsigned 5) -> BitVector 32 -> m (BitVector 32)+    scribeAlu op in1 in2 = do+      scribe toAluOp     $ First $ Just op+      scribe toAluInput1 $ First $ Just in1+      scribe toAluInput2 $ First $ Just in2++    guardZero  -- register x0 always has value 0.+      :: MonadState s m +      => Lens' s (Unsigned 5) +      -> BitVector 32 +      -> m (BitVector 32)     guardZero rsAddr rsValue = do       isZero <- uses rsAddr (== 0)       return $ if isZero@@ -295,36 +358,37 @@ -- | Decode stage decode :: RWS ToPipe FromPipe Pipe () decode = do-  exIR   .= Nothing+  exIR .= Nothing   exRvfi .= mkRvfi-  isFirstCycle <- control.firstCycle <<.= False -- first memory output undefined-  isBranching  <- uses (control.branching) isJust-  isWbMemory   <- use $ control.wbMemory-  isExLoad     <- use $ control.exLoad-  unless (isFirstCycle || isBranching || isWbMemory || isExLoad) $ do-    mem <- view fromMem-    case parseInstr mem of-      Right instr -> do-        exIR ?= instr-        exPC <~ use dePC-        exRvfi.rvfiInsn .= mem-        control.deLoad .= case instr of-          ExLoad _ _ _ -> True-          _ -> False-        scribe toRs1Addr . First . Just =<< exRvfi.rvfiRs1Addr <<~ exRs1 <.= sliceRs1 mem-        scribe toRs2Addr . First . Just =<< exRvfi.rvfiRs2Addr <<~ exRs2 <.= sliceRs2 mem-      Left IllegalInstruction -> fetchPC <~ use dePC -- roll-back PC, should handle trap+  exPC <~ use dePC+  mem <- exRvfi.rvfiInsn <<~ view fromMem+  scribe toRs1Addr . First . Just =<< exRvfi.rvfiRs1Addr <<~ exRs1 <.= sliceRs1 mem+  scribe toRs2Addr . First . Just =<< exRvfi.rvfiRs2Addr <<~ exRs2 <.= sliceRs2 mem+  isFirstCycle  <- use $ control.firstCycle -- first memory output undefined+  isMeBranching <- use $ control.meBranching+  isWbMemory    <- use $ control.wbMemory+  isExLoad      <- use $ control.exLoad+  isExBranching <- uses (control.exBranching) isJust+  let bubble = isFirstCycle || isMeBranching || isWbMemory || isExLoad || isExBranching+  case parseInstr mem of+    Right instr -> unless bubble $ do+      exIR ?= instr+      control.deLoad .= case instr of+        ExLoad{} -> True+        _        -> False+    Left IllegalInstruction -> do -- trap and instr=Nop (addi x0 x0 0)+      unless bubble $ exIR ?= ExAlu Add 0+      exRvfi.rvfiTrap .= True         - -- | fetch instruction---   stalled when instruction in memory stage needs bus   fetch :: RWS ToPipe FromPipe Pipe () fetch = do-  use (control.branching) >>= mapM_ (assign fetchPC)-  scribe toMem . First . Just . InstrMem =<< dePC <<~ use fetchPC+  scribe toMem . First . Just . instrMem =<< use fetchPC   isMeMemory <- use $ control.meMemory   isDeLoad   <- use $ control.deLoad-  unless (isMeMemory || isDeLoad) $ fetchPC += 4  +  use (control.exBranching) >>= \case+    Just npc -> fetchPC .= npc+    Nothing  -> unless (isMeMemory || isDeLoad) $ dePC <~ fetchPC <<+= 4  ------------- -- Utility --@@ -362,19 +426,27 @@ -- | slice address based on mask sliceByte :: BitVector 4 -> BitVector 32 -> BitVector 8 sliceByte = \case-  $(bitPattern "0001") -> slice d7  d0-  $(bitPattern "0010") -> slice d15 d8-  $(bitPattern "0100") -> slice d23 d16-  $(bitPattern "1000") -> slice d31 d24+  $(bitPattern "...1") -> slice d7  d0+  $(bitPattern "..1.") -> slice d15 d8+  $(bitPattern ".1..") -> slice d23 d16+  $(bitPattern "1...") -> slice d31 d24   _ -> const 0  -- | slice address based on mask sliceHalf :: BitVector 4 -> BitVector 32 -> BitVector 16 sliceHalf = \case-  $(bitPattern "0011") -> slice d15 d0-  $(bitPattern "1100") -> slice d31 d16+  $(bitPattern "..11") -> slice d15 d0+  $(bitPattern "11..") -> slice d31 d16   _ -> const 0 +-- | check if memory address misaligned on word boundary+isMisaligned :: (Bits a, Num a) => a -> Bool+isMisaligned a = a .&. 0x3 /= 0++-- | check if memory address misaligned on half-word boundary+isMisalignedHalf :: (Bits a, Num a) => a -> Bool+isMisalignedHalf a = a .&. 0x1 /= 0+ -- | run monadic action when instruction is Just withInstr :: MonadState s m => Lens' s (Maybe a) -> (a -> m ()) -> m () withInstr l k = use l >>= mapM_ k@@ -382,22 +454,25 @@ -- | Hazards Note -- -- Key:--- J = Jump--- O = Bubble--- S = Store--- * = Stall--- B = Branch--- +-- J  = JAL+-- JR = JALR+-- O  = Bubble+-- S  = Store+-- *  = Stall+-- B  = Branch+-- -- Jump/Branch--- +----+-----+-----+----+----+--- | IF | DE  | EX  | ME | WB |--- +====+=====+=====+====+====+--- | 4  | --- | --- | -- | -- |   --- +----+-----+-----+----+----+--- | 8  | J15 | --- | -- | -- |--- +----+-----+-----+----+----+--- | 15 |  O  | J15 | -- | -- |--- +----+-----+-----+----+----++-- +----+------+------+------+----++-- | IF |  DE  |  EX  |  ME  | WB |+-- +====+======+======+======+====++-- | 4  | ---- | ---- | ---- | -- |+-- +----+------+------+------+----++-- | 8  | JR20 | ---- | ---- | -- |+-- +----+------+------+------+----++-- | 12 |  O   | JR20 | ---- | -- |+-- +----+------+------+------+----++-- | 20 |  O   |  O   | JR20 | -- |+-- +----+------+------+------+----+ -- -- Store -- +-------+------+------+------+----+@@ -409,22 +484,24 @@ -- +-------+------+------+------+----+ -- | 12    | J100 |  S   | ---- | -- | -- +-------+------+------+------+----+--- | *100* |  O   | J100 |  S   | -- |+-- | *16*  |  O   | J100 |  S   | -- | -- +-------+------+------+------+----+ -- |  100  |  O   |  O   | J100 | S  | -- +-------+------+------+------+----+ -- -- Load--- +------+------+------+----+----+--- | IF   |  DE  |  EX  | ME | WB |--- +======+======+======+====+====+--- | 4    | ---- | ---- | -- | -- |--- +------+------+------+----+----+--- | *8*  |  L   | ---- | -- | -- |--- +------+------+------+----+----+--- | 8    |  O   |  L   | -- | -- |--- +------+------+------+----+----+--- | *12* | B100 |  O   | L  | -- |--- +------+------+------+----+----+--- | 100  |  O   | B100 | O  | L  |--- +------+------+------+----+----++-- +------+------+------+------+----++-- | IF   |  DE  |  EX  |  ME  | WB |+-- +======+======+======+======+====++-- | 4    | ---- | ---- | ---- | -- |+-- +------+------+------+------+----++-- | *8*  |  L   | ---- | ---- | -- |+-- +------+------+------+------+----++-- | 8    |  O   |  L   | ---- | -- |+-- +------+------+------+------+----++-- | *12* | B100 |  O   |  L   | -- |+-- +------+------+------+------+----++-- |  12  |  O   | B100 |  O   | L  |+-- +------+------+------+------+----++-- | 100  |  O   |  O   | B100 | O  |+-- +------+------+------+------+----+