├── .envrc ├── .github └── workflows │ └── documentation.yml ├── .gitignore ├── .gitmodules ├── Doc ├── ByExample.adoc └── img │ ├── blarney-icon1-400x400.png │ ├── blarney-icon1.svg │ └── blarney-icon2-400x400.png ├── Examples ├── Background │ ├── Background.hs │ ├── Background.out │ └── Makefile ├── BasicRTL │ ├── BasicRTL.hs │ ├── BasicRTL.out │ └── Makefile ├── Bit0 │ ├── Bit0.hs │ ├── Bit0.out │ └── Makefile ├── BitPat │ ├── BitPat.hs │ ├── BitPat.out │ └── Makefile ├── BitScan │ ├── BitScan.hs │ ├── BitScan.out │ └── Makefile ├── CPU │ ├── CPU.hs │ ├── CPU.out │ ├── Makefile │ ├── Spec.hs │ ├── Spec.out │ └── instrs.hex ├── CheckAdder │ ├── CheckAdder.hs │ └── Makefile ├── CheckBasicCircuits │ ├── CheckBasicCircuits.hs │ └── Makefile ├── CheckFirstHot │ ├── CheckFirstHot.hs │ └── Makefile ├── CheckQueue │ ├── CheckQueue.hs │ └── Makefile ├── CheckSklansky │ ├── CheckSklansky.hs │ └── Makefile ├── Counter │ ├── Counter.hs │ ├── Counter.out │ └── Makefile ├── Derive │ ├── Derive.hs │ ├── Derive.out │ └── Makefile ├── Either │ ├── Either.hs │ ├── Either.out │ └── Makefile ├── FIFO │ ├── FIFO.hs │ ├── FIFO.out │ └── Makefile ├── Factorial │ ├── Factorial.hs │ ├── Factorial.out │ └── Makefile ├── GCDFarm │ ├── GCDFarm.hs │ ├── GCDFarm.out │ └── Makefile ├── Heat │ ├── Heat.hs │ ├── Heat.out │ ├── Makefile │ └── Mesh.hs ├── Interface │ ├── Interface.hs │ ├── Interface.out │ └── Makefile ├── Iterator │ ├── Iterator.hs │ └── Makefile ├── Lookup │ ├── Lookup.hs │ ├── Lookup.out │ └── Makefile ├── Makefile ├── MasterSlave │ ├── Makefile │ ├── MasterSlave.hs │ └── MasterSlave.out ├── NameBits │ ├── Makefile │ ├── NameBits.hs │ └── NameBits.out ├── NoC │ ├── Makefile │ ├── NoC.hs │ └── NoC.out ├── Option │ ├── Makefile │ ├── Option.hs │ └── Option.out ├── Queue │ ├── Makefile │ ├── Queue.hs │ └── Queue.out ├── RAM │ ├── Makefile │ ├── RAM.hs │ └── RAM.out ├── RAMBE │ ├── Makefile │ ├── RAMBE.hs │ └── RAMBE.out ├── RAMQuad │ ├── Makefile │ ├── RAMQuad.hs │ └── RAMQuad.out ├── SizedStack │ ├── Makefile │ ├── SizedStack.hs │ └── SizedStack.out ├── Sorter │ ├── Makefile │ ├── Sorter.hs │ └── Sorter.out ├── SourceSink │ ├── Makefile │ ├── SourceSink.hs │ └── SourceSink.out ├── Stack │ ├── Makefile │ ├── Stack.hs │ └── Stack.out ├── StackTesting │ ├── Makefile │ └── StackTesting.hs ├── Vectors │ ├── Makefile │ ├── Vectors.hs │ └── Vectors.out └── blarneyTest.mk ├── Haskell ├── Blarney.hs ├── Blarney │ ├── Backend.hs │ ├── Backend │ │ ├── NewSMT.hs │ │ ├── SMT.hs │ │ ├── SMT │ │ │ ├── BasicDefinitions.hs │ │ │ ├── NetlistUtils.hs │ │ │ └── Utils.hs │ │ ├── Simulation.hs │ │ └── Verilog.hs │ ├── BitPat.hs │ ├── BitScan.hs │ ├── ClientServer.hs │ ├── Connectable.hs │ ├── Core.hs │ ├── Core │ │ ├── BV.hs │ │ ├── Bit.hs │ │ ├── Bits.hs │ │ ├── ClockReset.hs │ │ ├── Common.hs │ │ ├── FShow.hs │ │ ├── Flatten.hs │ │ ├── IfThenElse.hs │ │ ├── Interface.hs │ │ ├── JList.hs │ │ ├── Lookup.hs │ │ ├── Module.hs │ │ ├── NetHelpers.hs │ │ ├── Opts.hs │ │ ├── Prim.hs │ │ ├── RAM.hs │ │ ├── RTL.hs │ │ ├── Ternary.hs │ │ └── Utils.hs │ ├── Interconnect.hs │ ├── Misc │ │ ├── ANSIEscapeSequences.hs │ │ └── MonadLoops.hs │ ├── Netlist.hs │ ├── Netlist │ │ ├── Passes.hs │ │ └── Passes │ │ │ ├── ConstantEliminate.hs │ │ │ ├── ConstantFold.hs │ │ │ ├── ConstantPropagate.hs │ │ │ ├── DeadNetEliminate.hs │ │ │ ├── DontCareDeInline.hs │ │ │ ├── NamePropagate.hs │ │ │ ├── NetInline.hs │ │ │ ├── Prune.hs │ │ │ ├── Types.hs │ │ │ ├── Utils.hs │ │ │ └── ZeroWidthNetIgnore.hs │ ├── Option.hs │ ├── Prelude.hs │ ├── PulseReg.hs │ ├── PulseWire.hs │ ├── QuadPortRAM.hs │ ├── Queue.hs │ ├── Recipe.hs │ ├── SourceSink.hs │ ├── Stack.hs │ ├── Stmt.hs │ ├── Stream.hs │ ├── TaggedUnion.hs │ ├── TypeFamilies.hs │ └── Vector.hs └── BlarneyPlugins │ └── Namer │ ├── BlarneyPlugins │ └── Namer.hs │ └── blarney-plugins-namer.cabal ├── LICENSE ├── Makefile ├── README.adoc ├── Scripts ├── blc └── blci ├── Test └── test.sh ├── Verilog ├── Altera │ ├── BlockRAM.v │ ├── BlockRAMBE.v │ ├── BlockRAMDual.v │ ├── BlockRAMDualBE.v │ ├── BlockRAMQuad.v │ ├── BlockRAMTrueDual.v │ └── BlockRAMTrueDualBE.v ├── BlockRAM.v ├── BlockRAMBE.sv ├── BlockRAMDual.v ├── BlockRAMDualBE.sv ├── BlockRAMQuad.v ├── BlockRAMTrueDual.v └── BlockRAMTrueDualBE.sv ├── blarney-logo-dark.svg ├── blarney-logo.svg ├── blarney.cabal └── blarneyDirs.mk /.envrc: -------------------------------------------------------------------------------- 1 | export BLARNEY_ROOT=$(pwd) 2 | export PATH=$BLARNEY_ROOT/Scripts:$PATH 3 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Generate and deploy documentation 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | 9 | GenDoc: 10 | name: Generate documentation 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: haskell/actions/setup@v1 15 | with: 16 | ghc-version: '9.2.1' 17 | - name: Generate documentation 18 | run: | 19 | cabal haddock \ 20 | --haddock-html \ 21 | --haddock-option "--odir=doc" \ 22 | --haddock-option "--title=blarney" \ 23 | --haddock-option "--source-module=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/tree/$GITHUB_SHA/%{FILE}" \ 24 | --haddock-option "--source-entity=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/tree/$GITHUB_SHA/%{FILE}#L%{LINE}" \ 25 | - name: Upload documentation artifact 26 | uses: actions/upload-artifact@v4 27 | with: 28 | name: doc 29 | path: doc 30 | 31 | PublishDoc: 32 | name: Publish documentation 33 | needs: GenDoc 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Download documentation artifact 37 | uses: actions/download-artifact@v4 38 | with: 39 | name: doc 40 | - name: Deploy documentation 41 | run: | 42 | git init 43 | git checkout --orphan haddock 44 | git remote add origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY 45 | git config user.name the-blarney-fairy 46 | git config user.email the-blarney-fairy@users.noreply.github.com 47 | git add --all 48 | git commit -m "deploy documentation for $GITHUB_SHA" 49 | git push origin -f haddock 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.hi 2 | *.o 3 | dist-newstyle/ 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "blarney-vendor-ip"] 2 | path = blarney-vendor-ip 3 | url = https://github.com/blarney-lang/blarney-vendor-ip 4 | -------------------------------------------------------------------------------- /Doc/img/blarney-icon1-400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blarney-lang/blarney/087ff9884d6ec5648b007b46069a163bfd5f0a2e/Doc/img/blarney-icon1-400x400.png -------------------------------------------------------------------------------- /Doc/img/blarney-icon2-400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blarney-lang/blarney/087ff9884d6ec5648b007b46069a163bfd5f0a2e/Doc/img/blarney-icon2-400x400.png -------------------------------------------------------------------------------- /Examples/Background/Background.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Recipe 3 | import System.Environment 4 | 5 | block :: [Action ()] -> Recipe 6 | block acts = Seq (map Action acts) 7 | 8 | top :: Module () 9 | top = do 10 | vecA :: RAM (Bit 8) (Bit 32) <- makeRAM 11 | vecB :: RAM (Bit 8) (Bit 32) <- makeRAM 12 | 13 | vecCNoPipe :: RAM (Bit 8) (Bit 32) <- makeRAM 14 | vecCPipe :: RAM (Bit 8) (Bit 32) <- makeRAM 15 | 16 | globalTime :: Reg (Bit 32) <- makeReg 0 17 | 18 | i :: Reg (Bit 8) <- makeReg 0 19 | i0 :: Reg (Bit 8) <- makeReg dontCare 20 | 21 | res :: Reg (Bit 32) <- makeReg dontCare 22 | let testSeq = 23 | Seq [ 24 | While (i.val .<. 20) ( 25 | block [ 26 | display "storing " i.val, 27 | vecA.store i.val (zeroExtend i.val), 28 | vecB.store i.val (zeroExtend i.val), 29 | i <== i.val + 1 30 | ] 31 | ), 32 | 33 | block [ 34 | i <== 0, 35 | display "starting at " globalTime.val 36 | ], 37 | 38 | While (i.val .<. 20) ( 39 | block [ 40 | do vecA.load i.val 41 | vecB.load i.val 42 | display "loading un-pipelined at time " globalTime.val, 43 | do vecCNoPipe.store i.val (vecA.out + vecB.out) 44 | i <== i.val + 1 45 | ] 46 | ), 47 | 48 | block [ 49 | display "un-pipelined loop ending at " globalTime.val, 50 | i <== 0, 51 | display "C values after un-pipelined add" 52 | ], 53 | 54 | While (i.val .<. 20) ( 55 | block [ 56 | vecCNoPipe.load i.val, 57 | display "C[" i.val "] = " vecCNoPipe.out, 58 | i <== i.val + 1 59 | ] 60 | ), 61 | 62 | block [ 63 | i <== 0, 64 | display "Clearing C values" 65 | ], 66 | 67 | While (i.val .<. 20) ( 68 | block [ 69 | vecCPipe.store i.val 0, 70 | i <== i.val + 1 71 | ] 72 | ), 73 | 74 | 75 | block [ 76 | i <== 0, 77 | display "Running pipelined vector add...", 78 | display "starting pipelined loop at " globalTime.val 79 | ], 80 | 81 | While (i.val .<. 20) ( 82 | Seq [ 83 | Background ( 84 | Seq [ 85 | Action do 86 | vecA.load i.val 87 | vecB.load i.val 88 | i0 <== i.val 89 | display "load values at time " globalTime.val, 90 | Action do 91 | vecCPipe.store i0.val (vecA.out + vecB.out) 92 | ] 93 | ), 94 | block [i <== i.val + 1] 95 | ] 96 | ), 97 | 98 | block [ 99 | display "ending pipelined loop at " globalTime.val, 100 | i <== 0, 101 | display "After pipelined add..." 102 | ], 103 | 104 | While (i.val .<. 20) ( 105 | block [ 106 | vecCPipe.load i.val, 107 | display "C[" i.val "] = " vecCPipe.out, 108 | i <== i.val + 1 109 | ] 110 | ) 111 | 112 | ] 113 | 114 | always do 115 | globalTime <== globalTime.val + 1 116 | 117 | done <- runRecipeOn (reg 1 0) testSeq 118 | 119 | always (when done finish) 120 | 121 | return () 122 | 123 | main :: IO () 124 | main = do 125 | args <- getArgs 126 | if | "--simulate" `elem` args -> simulate top 127 | | otherwise -> writeVerilogTop top "Background" "Background-Verilog/" 128 | -------------------------------------------------------------------------------- /Examples/Background/Background.out: -------------------------------------------------------------------------------- 1 | storing 0 2 | storing 1 3 | storing 2 4 | storing 3 5 | storing 4 6 | storing 5 7 | storing 6 8 | storing 7 9 | storing 8 10 | storing 9 11 | storing 10 12 | storing 11 13 | storing 12 14 | storing 13 15 | storing 14 16 | storing 15 17 | storing 16 18 | storing 17 19 | storing 18 20 | storing 19 21 | starting at 81 22 | loading un-pipelined at time 82 23 | loading un-pipelined at time 84 24 | loading un-pipelined at time 86 25 | loading un-pipelined at time 88 26 | loading un-pipelined at time 90 27 | loading un-pipelined at time 92 28 | loading un-pipelined at time 94 29 | loading un-pipelined at time 96 30 | loading un-pipelined at time 98 31 | loading un-pipelined at time 100 32 | loading un-pipelined at time 102 33 | loading un-pipelined at time 104 34 | loading un-pipelined at time 106 35 | loading un-pipelined at time 108 36 | loading un-pipelined at time 110 37 | loading un-pipelined at time 112 38 | loading un-pipelined at time 114 39 | loading un-pipelined at time 116 40 | loading un-pipelined at time 118 41 | loading un-pipelined at time 120 42 | un-pipelined loop ending at 122 43 | C values after un-pipelined add 44 | C[0] = 0 45 | C[1] = 2 46 | C[2] = 4 47 | C[3] = 6 48 | C[4] = 8 49 | C[5] = 10 50 | C[6] = 12 51 | C[7] = 14 52 | C[8] = 16 53 | C[9] = 18 54 | C[10] = 20 55 | C[11] = 22 56 | C[12] = 24 57 | C[13] = 26 58 | C[14] = 28 59 | C[15] = 30 60 | C[16] = 32 61 | C[17] = 34 62 | C[18] = 36 63 | C[19] = 38 64 | Clearing C values 65 | Running pipelined vector add... 66 | starting pipelined loop at 229 67 | load values at time 230 68 | load values at time 231 69 | load values at time 232 70 | load values at time 233 71 | load values at time 234 72 | load values at time 235 73 | load values at time 236 74 | load values at time 237 75 | load values at time 238 76 | load values at time 239 77 | load values at time 240 78 | load values at time 241 79 | load values at time 242 80 | load values at time 243 81 | load values at time 244 82 | load values at time 245 83 | load values at time 246 84 | load values at time 247 85 | load values at time 248 86 | load values at time 249 87 | ending pipelined loop at 250 88 | After pipelined add... 89 | C[0] = 0 90 | C[1] = 2 91 | C[2] = 4 92 | C[3] = 6 93 | C[4] = 8 94 | C[5] = 10 95 | C[6] = 12 96 | C[7] = 14 97 | C[8] = 16 98 | C[9] = 18 99 | C[10] = 20 100 | C[11] = 22 101 | C[12] = 24 102 | C[13] = 26 103 | C[14] = 28 104 | C[15] = 30 105 | C[16] = 32 106 | C[17] = 34 107 | C[18] = 36 108 | C[19] = 38 109 | -------------------------------------------------------------------------------- /Examples/Background/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Background.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/BasicRTL/BasicRTL.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import System.Environment 3 | 4 | top :: Module () 5 | top = do 6 | -- Create a register 7 | cycleCount :: Reg (Bit 4) <- makeReg 0 8 | -- Check for DEBUG plusarg 9 | let isDebug = testPlusArgs "DEBUG" 10 | 11 | always do 12 | -- Increment on every cycle 13 | cycleCount <== cycleCount.val + 1 14 | 15 | -- Display value an every cycle 16 | display "cycleCount = " cycleCount.val 17 | 18 | -- Terminate simulation when count reaches 10 19 | when (cycleCount.val .==. 10) do 20 | display "Finished" 21 | finish 22 | 23 | -- Display "DEBUG" when +DEBUG is passed as a plusargs 24 | when isDebug do 25 | display "running with +DEBUG" 26 | 27 | main :: IO () 28 | main = do 29 | args <- getArgs 30 | if | "--simulate" `elem` args -> simulate top 31 | | otherwise -> writeVerilogTop top "BasicRTL" "BasicRTL-Verilog/" 32 | -------------------------------------------------------------------------------- /Examples/BasicRTL/BasicRTL.out: -------------------------------------------------------------------------------- 1 | cycleCount = 0 2 | cycleCount = 1 3 | cycleCount = 2 4 | cycleCount = 3 5 | cycleCount = 4 6 | cycleCount = 5 7 | cycleCount = 6 8 | cycleCount = 7 9 | cycleCount = 8 10 | cycleCount = 9 11 | cycleCount = 10 12 | Finished 13 | -------------------------------------------------------------------------------- /Examples/BasicRTL/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = BasicRTL.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Bit0/Bit0.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import System.Environment 3 | 4 | data MyIfc n = MyIfc { meh0 :: Bit n 5 | , meh8 :: Bit 8 } deriving (Generic, Interface) 6 | 7 | testMyIfc :: Bit 8 -> Module (MyIfc 0) 8 | testMyIfc val = return $ MyIfc { meh0 = 0, meh8 = val } 9 | 10 | makeTestMyIfc :: Bit 8 -> Module (MyIfc 0) 11 | makeTestMyIfc = makeInstance "testMyIfc" 12 | 13 | top :: Module () 14 | top = do 15 | let a :: Bit 0 = dontCare 16 | let b :: Bit 0 = dontCare 17 | someInst <- makeTestMyIfc 10 18 | 19 | always do 20 | if a .==. b then display "Bit 0 .==. true" 21 | else display "Bit 0 .==. false" 22 | if a .!=. b then display "Bit 0 .!=. true" 23 | else display "Bit 0 .!=. false" 24 | if a .<. b then display "Bit 0 .<. true" 25 | else display "Bit 0 .<. false" 26 | if a .<=. b then display "Bit 0 .<=. true" 27 | else display "Bit 0 .<=. false" 28 | display "concat (10 :: Bit 8) with a Bit 0: " (someInst.meh8 # a) 29 | display "zeroExtend a Bit 0 to a Bit 4: " (zeroExtend a :: Bit 4) 30 | display "signExtend a Bit 0 to a Bit 4: " (signExtend a :: Bit 4) 31 | display "displaying a Bit 0: " a 32 | finish 33 | 34 | main :: IO () 35 | main = do 36 | args <- getArgs 37 | if | "--simulate" `elem` args -> simulate top 38 | | otherwise -> do writeVerilogModule testMyIfc "testMyIfc" "Bit0-Verilog/" 39 | writeVerilogTop top "Bit0" "Bit0-Verilog/" 40 | -------------------------------------------------------------------------------- /Examples/Bit0/Bit0.out: -------------------------------------------------------------------------------- 1 | Bit 0 .==. true 2 | Bit 0 .!=. false 3 | Bit 0 .<. false 4 | Bit 0 .<=. true 5 | concat (10 :: Bit 8) with a Bit 0: 10 6 | zeroExtend a Bit 0 to a Bit 4: 0 7 | signExtend a Bit 0 to a Bit 4: 0 8 | displaying a Bit 0: 0 9 | -------------------------------------------------------------------------------- /Examples/Bit0/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Bit0.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/BitPat/BitPat.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.BitPat 3 | import System.Environment 4 | 5 | -- Opcode | Meaning 6 | -- ----------+-------------------------------------------------------- 7 | -- 00ZZNNNN | Write value 0000NNNN to register ZZ 8 | -- 01ZZXXYY | Add register XX to register YY and store in register ZZ 9 | -- 10NNNNYY | Branch back by NNNN instructions if YY is non-zero 10 | -- 11NNNNNN | Halt 11 | 12 | -- Instruction dispatch 13 | top :: Module () 14 | top = always do 15 | -- Sample add instruction 16 | let instr :: Bit 8 = 0b01_00_01_10 17 | 18 | -- Dispatch 19 | match instr 20 | [ 21 | literal @2 0b00 <#> variable @2 <#> variable @4 22 | ==> 23 | \z n -> display "li " z ", " n 24 | 25 | , literal @2 0b01 <#> variable @2 <#> variable @2 <#> variable @2 26 | ==> 27 | \z x y -> display "add " z ", " x ", " y 28 | 29 | , literal @2 0b10 <#> variable @4 <#> variable @2 30 | ==> 31 | \n y -> display "bnz " y ", " n 32 | 33 | , literal @2 0b11 <#> variable @6 34 | ==> 35 | \n -> display "halt" >> finish 36 | ] 37 | 38 | finish 39 | 40 | -- Main function 41 | main :: IO () 42 | main = do 43 | args <- getArgs 44 | if | "--simulate" `elem` args -> simulate top 45 | | otherwise -> writeVerilogTop top "BitPat" "BitPat-Verilog/" 46 | -------------------------------------------------------------------------------- /Examples/BitPat/BitPat.out: -------------------------------------------------------------------------------- 1 | add 0, 1, 2 2 | -------------------------------------------------------------------------------- /Examples/BitPat/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = BitPat.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/BitScan/BitScan.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.BitScan 3 | import System.Environment 4 | 5 | -- Semantics of add instruction 6 | sem_add :: Bit 5 -> Bit 5 -> Bit 5 -> Action () 7 | sem_add rs2 rs1 rd = display "add r" rd ", r" rs1 ", r" rs2 8 | 9 | -- Semantics of addi instruction 10 | sem_addi :: Bit 12 -> Bit 5 -> Bit 5 -> Action () 11 | sem_addi imm rs1 rd = display "addi r" rd ", r" rs1 ", " imm 12 | 13 | -- Semantics of store instruciton 14 | sem_sw :: Bit 12 -> Bit 5 -> Bit 5 -> Action () 15 | sem_sw imm rs2 rs1 = display "sw r" rs2 ", " imm "(r" rs1 ")" 16 | 17 | top :: Module () 18 | top = always do 19 | let instr :: Bit 32 = 0b1000000_00001_00010_010_00001_0100011 20 | 21 | match instr 22 | [ 23 | "0000000 rs2[4:0] rs1[4:0] 000 rd[4:0] 0110011" ==> sem_add, 24 | " imm[11:0] rs1[4:0] 000 rd[4:0] 0010011" ==> sem_addi, 25 | "imm[11:5] rs2[4:0] rs1[4:0] 010 imm[4:0] 0100011" ==> sem_sw 26 | ] 27 | 28 | finish 29 | 30 | -- Main function 31 | main :: IO () 32 | main = do 33 | args <- getArgs 34 | if | "--simulate" `elem` args -> simulate top 35 | | otherwise -> writeVerilogTop top "BitScan" "BitScan-Verilog/" 36 | -------------------------------------------------------------------------------- /Examples/BitScan/BitScan.out: -------------------------------------------------------------------------------- 1 | sw r1, 2049(r2) 2 | -------------------------------------------------------------------------------- /Examples/BitScan/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = BitScan.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/CPU/CPU.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import System.Environment 3 | 4 | -- Tiny 8-bit CPU with a 4-stage pipeline 5 | -- 6 | -- Opcode | Meaning 7 | -- ----------+-------------------------------------------------------- 8 | -- 00DDNNNN | Write value 0000NNNN to register DD 9 | -- 01DDAABB | Add register AA to register BB and store in register DD 10 | -- 10NNNNBB | Branch back by NNNN instructions if BB is non-zero 11 | -- 11NNNNNN | Halt 12 | 13 | -- Instructions 14 | type Instr = Bit 8 15 | 16 | -- Register identifiers 17 | type RegId = Bit 2 18 | 19 | -- Extract opcode 20 | opcode :: Instr -> Bit 2 21 | opcode instr = slice @7 @6 instr 22 | 23 | -- Extract register A 24 | rA :: Instr -> RegId 25 | rA instr = slice @3 @2 instr 26 | 27 | -- Extract register B 28 | rB :: Instr -> RegId 29 | rB instr = slice @1 @0 instr 30 | 31 | -- Extract destination register 32 | rD :: Instr -> RegId 33 | rD instr = slice @5 @4 instr 34 | 35 | -- Extract immediate 36 | imm :: Instr -> Bit 4 37 | imm instr = slice @3 @0 instr 38 | 39 | -- Extract branch offset 40 | offset :: Instr -> Bit 4 41 | offset instr = slice @5 @2 instr 42 | 43 | -- CPU 44 | makeCPU :: Module () 45 | makeCPU = do 46 | -- Instruction memory 47 | instrMem :: RAM (Bit 8) Instr <- makeRAMInit "instrs.hex" 48 | 49 | -- Two block RAMs allows two operands to be read, 50 | -- and one result to be written, on every cycle 51 | regFileA :: RAM RegId (Bit 8) <- makeDualRAMForward 52 | regFileB :: RAM RegId (Bit 8) <- makeDualRAMForward 53 | 54 | -- Instruction register 55 | instr :: Reg (Bit 8) <- makeReg dontCare 56 | 57 | -- Instruction operand registers 58 | opA :: Reg (Bit 8) <- makeReg dontCare 59 | opB :: Reg (Bit 8) <- makeReg dontCare 60 | 61 | -- Program counter 62 | pcNext :: Wire (Bit 8) <- makeWire 0 63 | let pc = reg 0 pcNext.val 64 | 65 | -- Result of the execute stage 66 | result :: Wire (Bit 8) <- makeWire 0 67 | 68 | -- Wire to trigger a pipeline flush 69 | flush :: Wire (Bit 1) <- makeWire 0 70 | 71 | -- Cycle counter 72 | count :: Reg (Bit 32) <- makeReg 0 73 | always do count <== count.val + 1 74 | 75 | -- Trigger for each pipeline stage 76 | go1 :: Reg (Bit 1) <- makeDReg 0 77 | go2 :: Reg (Bit 1) <- makeDReg 0 78 | go3 :: Reg (Bit 1) <- makeDReg 0 79 | 80 | always do 81 | -- Stage 0: Instruction Fetch 82 | -- ========================== 83 | 84 | -- Index the instruction memory 85 | instrMem.load pcNext.val 86 | 87 | -- Start the pipeline after one cycle 88 | go1 <== 1 89 | 90 | -- Stage 1: Operand Fetch 91 | -- ====================== 92 | 93 | when go1.val do 94 | when (inv flush.val) do 95 | pcNext <== pc + 1 96 | go2 <== 1 97 | 98 | regFileA.load (rA instrMem.out) 99 | regFileB.load (rB instrMem.out) 100 | 101 | -- Stage 2: Latch Operands 102 | -- ======================= 103 | 104 | -- Latch instruction 105 | instr <== old instrMem.out 106 | 107 | -- Register forwarding logic 108 | let forward rS other = 109 | (result.active .&. (rD instr.val .==. rS (old instrMem.out))) ? 110 | (result.val, other) 111 | 112 | -- Latch operands 113 | opA <== forward rA regFileA.out 114 | opB <== forward rB regFileB.out 115 | 116 | -- Trigger stage 3 117 | when (inv flush.val) do 118 | go3 <== go2.val 119 | 120 | -- Stage 3: Execute 121 | -- ================ 122 | 123 | -- Instruction dispatch 124 | when go3.val do 125 | switch (opcode instr.val) 126 | [ 127 | -- Load-immediate instruction 128 | 0b00 --> result <== zeroExtend (imm instr.val), 129 | -- Add instruction 130 | 0b01 --> result <== opA.val + opB.val, 131 | -- Branch instruction 132 | 0b10 --> when (opB.val .!=. 0) do 133 | pcNext <== pc - zeroExtend (offset instr.val) - 2 134 | -- Control hazard 135 | flush <== 1, 136 | -- Halt instruction 137 | 0b11 --> finish 138 | ] 139 | 140 | -- Writeback 141 | when (result.active) do 142 | regFileA.store (rD instr.val) result.val 143 | regFileB.store (rD instr.val) result.val 144 | display (formatDec 8 count.val) 145 | ": rf[" (rD instr.val) "] := " result.val 146 | 147 | -- Main function 148 | main :: IO () 149 | main = do 150 | args <- getArgs 151 | if | "--simulate" `elem` args -> simulate makeCPU 152 | | otherwise -> writeVerilogTop makeCPU "CPU" "CPU-Verilog/" 153 | -------------------------------------------------------------------------------- /Examples/CPU/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = CPU.hs Spec.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/CPU/Spec.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.BitPat 3 | import System.Process 4 | import System.Environment 5 | 6 | -- Tiny 8-bit CPU specification 7 | -- 8 | -- Opcode | Meaning 9 | -- ----------+-------------------------------------------------------- 10 | -- 00ZZNNNN | Write value 0000NNNN to register ZZ 11 | -- 01ZZXXYY | Add register XX to register YY and store in register ZZ 12 | -- 10NNNNYY | Branch back by NNNN instructions if YY is non-zero 13 | -- 11NNNNNN | Halt 14 | 15 | makeCPUSpec :: Module () 16 | makeCPUSpec = do 17 | -- Instruction memory (containing 32 instructions) 18 | instrMem :: RAM (Bit 5) (Bit 8) <- makeRAMInit "instrs.hex" 19 | 20 | -- Register file (containing 4 registers) 21 | regFile :: RegFile (Bit 2) (Bit 8) <- makeRegFile 22 | 23 | -- Program counter 24 | pc :: Reg (Bit 5) <- makeReg 0 25 | 26 | -- Are we fetching (1) or executing (0) 27 | fetch :: Reg (Bit 1) <- makeReg 1 28 | 29 | -- Load immediate instruction 30 | let li rd imm = do 31 | regFile.update rd (zeroExtend imm) 32 | pc <== pc.val + 1 33 | display "rf[" rd "] := 0x" (formatHex 2 (zeroExtend imm :: Bit 8)) 34 | 35 | -- Add instruction 36 | let add rd rs0 rs1 = do 37 | let sum = regFile!rs0 + regFile!rs1 38 | regFile.update rd sum 39 | pc <== pc.val + 1 40 | display "rf[" rd "] := 0x" (formatHex 2 sum) 41 | 42 | -- Branch instruction 43 | let bnz offset rs = do 44 | if regFile!rs .==. 0 45 | then pc <== pc.val + 1 46 | else pc <== pc.val - zeroExtend offset 47 | 48 | -- Halt instruction 49 | let halt imm = finish 50 | 51 | always do 52 | -- Fetch 53 | when fetch.val do 54 | instrMem.load pc.val 55 | fetch <== 0 56 | 57 | -- Execute 58 | when (inv fetch.val) do 59 | match instrMem.out 60 | [ 61 | literal 0b00 <#> variable @2 <#> variable @4 ==> li, 62 | literal 0b01 <#> variable @2 <#> variable @2 <#> variable @2 ==> add, 63 | literal 0b10 <#> variable @4 <#> variable @2 ==> bnz, 64 | literal 0b11 <#> variable @6 ==> halt 65 | ] 66 | fetch <== 1 67 | 68 | main :: IO () 69 | main = do 70 | args <- getArgs 71 | if | "--simulate" `elem` args -> simulate makeCPUSpec 72 | | otherwise -> writeVerilogTop makeCPUSpec "Spec" "Spec-Verilog/" 73 | -------------------------------------------------------------------------------- /Examples/CPU/Spec.out: -------------------------------------------------------------------------------- 1 | rf[0] := 0x00 2 | rf[1] := 0x01 3 | rf[0] := 0x01 4 | rf[0] := 0x02 5 | rf[0] := 0x03 6 | rf[0] := 0x04 7 | rf[0] := 0x05 8 | rf[0] := 0x06 9 | rf[0] := 0x07 10 | rf[0] := 0x08 11 | rf[0] := 0x09 12 | rf[0] := 0x0a 13 | rf[0] := 0x0b 14 | rf[0] := 0x0c 15 | rf[0] := 0x0d 16 | rf[0] := 0x0e 17 | rf[0] := 0x0f 18 | rf[0] := 0x10 19 | rf[0] := 0x11 20 | rf[0] := 0x12 21 | rf[0] := 0x13 22 | rf[0] := 0x14 23 | rf[0] := 0x15 24 | rf[0] := 0x16 25 | rf[0] := 0x17 26 | rf[0] := 0x18 27 | rf[0] := 0x19 28 | rf[0] := 0x1a 29 | rf[0] := 0x1b 30 | rf[0] := 0x1c 31 | rf[0] := 0x1d 32 | rf[0] := 0x1e 33 | rf[0] := 0x1f 34 | rf[0] := 0x20 35 | rf[0] := 0x21 36 | rf[0] := 0x22 37 | rf[0] := 0x23 38 | rf[0] := 0x24 39 | rf[0] := 0x25 40 | rf[0] := 0x26 41 | rf[0] := 0x27 42 | rf[0] := 0x28 43 | rf[0] := 0x29 44 | rf[0] := 0x2a 45 | rf[0] := 0x2b 46 | rf[0] := 0x2c 47 | rf[0] := 0x2d 48 | rf[0] := 0x2e 49 | rf[0] := 0x2f 50 | rf[0] := 0x30 51 | rf[0] := 0x31 52 | rf[0] := 0x32 53 | rf[0] := 0x33 54 | rf[0] := 0x34 55 | rf[0] := 0x35 56 | rf[0] := 0x36 57 | rf[0] := 0x37 58 | rf[0] := 0x38 59 | rf[0] := 0x39 60 | rf[0] := 0x3a 61 | rf[0] := 0x3b 62 | rf[0] := 0x3c 63 | rf[0] := 0x3d 64 | rf[0] := 0x3e 65 | rf[0] := 0x3f 66 | rf[0] := 0x40 67 | rf[0] := 0x41 68 | rf[0] := 0x42 69 | rf[0] := 0x43 70 | rf[0] := 0x44 71 | rf[0] := 0x45 72 | rf[0] := 0x46 73 | rf[0] := 0x47 74 | rf[0] := 0x48 75 | rf[0] := 0x49 76 | rf[0] := 0x4a 77 | rf[0] := 0x4b 78 | rf[0] := 0x4c 79 | rf[0] := 0x4d 80 | rf[0] := 0x4e 81 | rf[0] := 0x4f 82 | rf[0] := 0x50 83 | rf[0] := 0x51 84 | rf[0] := 0x52 85 | rf[0] := 0x53 86 | rf[0] := 0x54 87 | rf[0] := 0x55 88 | rf[0] := 0x56 89 | rf[0] := 0x57 90 | rf[0] := 0x58 91 | rf[0] := 0x59 92 | rf[0] := 0x5a 93 | rf[0] := 0x5b 94 | rf[0] := 0x5c 95 | rf[0] := 0x5d 96 | rf[0] := 0x5e 97 | rf[0] := 0x5f 98 | rf[0] := 0x60 99 | rf[0] := 0x61 100 | rf[0] := 0x62 101 | rf[0] := 0x63 102 | rf[0] := 0x64 103 | rf[0] := 0x65 104 | rf[0] := 0x66 105 | rf[0] := 0x67 106 | rf[0] := 0x68 107 | rf[0] := 0x69 108 | rf[0] := 0x6a 109 | rf[0] := 0x6b 110 | rf[0] := 0x6c 111 | rf[0] := 0x6d 112 | rf[0] := 0x6e 113 | rf[0] := 0x6f 114 | rf[0] := 0x70 115 | rf[0] := 0x71 116 | rf[0] := 0x72 117 | rf[0] := 0x73 118 | rf[0] := 0x74 119 | rf[0] := 0x75 120 | rf[0] := 0x76 121 | rf[0] := 0x77 122 | rf[0] := 0x78 123 | rf[0] := 0x79 124 | rf[0] := 0x7a 125 | rf[0] := 0x7b 126 | rf[0] := 0x7c 127 | rf[0] := 0x7d 128 | rf[0] := 0x7e 129 | rf[0] := 0x7f 130 | rf[0] := 0x80 131 | rf[0] := 0x81 132 | rf[0] := 0x82 133 | rf[0] := 0x83 134 | rf[0] := 0x84 135 | rf[0] := 0x85 136 | rf[0] := 0x86 137 | rf[0] := 0x87 138 | rf[0] := 0x88 139 | rf[0] := 0x89 140 | rf[0] := 0x8a 141 | rf[0] := 0x8b 142 | rf[0] := 0x8c 143 | rf[0] := 0x8d 144 | rf[0] := 0x8e 145 | rf[0] := 0x8f 146 | rf[0] := 0x90 147 | rf[0] := 0x91 148 | rf[0] := 0x92 149 | rf[0] := 0x93 150 | rf[0] := 0x94 151 | rf[0] := 0x95 152 | rf[0] := 0x96 153 | rf[0] := 0x97 154 | rf[0] := 0x98 155 | rf[0] := 0x99 156 | rf[0] := 0x9a 157 | rf[0] := 0x9b 158 | rf[0] := 0x9c 159 | rf[0] := 0x9d 160 | rf[0] := 0x9e 161 | rf[0] := 0x9f 162 | rf[0] := 0xa0 163 | rf[0] := 0xa1 164 | rf[0] := 0xa2 165 | rf[0] := 0xa3 166 | rf[0] := 0xa4 167 | rf[0] := 0xa5 168 | rf[0] := 0xa6 169 | rf[0] := 0xa7 170 | rf[0] := 0xa8 171 | rf[0] := 0xa9 172 | rf[0] := 0xaa 173 | rf[0] := 0xab 174 | rf[0] := 0xac 175 | rf[0] := 0xad 176 | rf[0] := 0xae 177 | rf[0] := 0xaf 178 | rf[0] := 0xb0 179 | rf[0] := 0xb1 180 | rf[0] := 0xb2 181 | rf[0] := 0xb3 182 | rf[0] := 0xb4 183 | rf[0] := 0xb5 184 | rf[0] := 0xb6 185 | rf[0] := 0xb7 186 | rf[0] := 0xb8 187 | rf[0] := 0xb9 188 | rf[0] := 0xba 189 | rf[0] := 0xbb 190 | rf[0] := 0xbc 191 | rf[0] := 0xbd 192 | rf[0] := 0xbe 193 | rf[0] := 0xbf 194 | rf[0] := 0xc0 195 | rf[0] := 0xc1 196 | rf[0] := 0xc2 197 | rf[0] := 0xc3 198 | rf[0] := 0xc4 199 | rf[0] := 0xc5 200 | rf[0] := 0xc6 201 | rf[0] := 0xc7 202 | rf[0] := 0xc8 203 | rf[0] := 0xc9 204 | rf[0] := 0xca 205 | rf[0] := 0xcb 206 | rf[0] := 0xcc 207 | rf[0] := 0xcd 208 | rf[0] := 0xce 209 | rf[0] := 0xcf 210 | rf[0] := 0xd0 211 | rf[0] := 0xd1 212 | rf[0] := 0xd2 213 | rf[0] := 0xd3 214 | rf[0] := 0xd4 215 | rf[0] := 0xd5 216 | rf[0] := 0xd6 217 | rf[0] := 0xd7 218 | rf[0] := 0xd8 219 | rf[0] := 0xd9 220 | rf[0] := 0xda 221 | rf[0] := 0xdb 222 | rf[0] := 0xdc 223 | rf[0] := 0xdd 224 | rf[0] := 0xde 225 | rf[0] := 0xdf 226 | rf[0] := 0xe0 227 | rf[0] := 0xe1 228 | rf[0] := 0xe2 229 | rf[0] := 0xe3 230 | rf[0] := 0xe4 231 | rf[0] := 0xe5 232 | rf[0] := 0xe6 233 | rf[0] := 0xe7 234 | rf[0] := 0xe8 235 | rf[0] := 0xe9 236 | rf[0] := 0xea 237 | rf[0] := 0xeb 238 | rf[0] := 0xec 239 | rf[0] := 0xed 240 | rf[0] := 0xee 241 | rf[0] := 0xef 242 | rf[0] := 0xf0 243 | rf[0] := 0xf1 244 | rf[0] := 0xf2 245 | rf[0] := 0xf3 246 | rf[0] := 0xf4 247 | rf[0] := 0xf5 248 | rf[0] := 0xf6 249 | rf[0] := 0xf7 250 | rf[0] := 0xf8 251 | rf[0] := 0xf9 252 | rf[0] := 0xfa 253 | rf[0] := 0xfb 254 | rf[0] := 0xfc 255 | rf[0] := 0xfd 256 | rf[0] := 0xfe 257 | rf[0] := 0xff 258 | rf[0] := 0x00 259 | -------------------------------------------------------------------------------- /Examples/CPU/instrs.hex: -------------------------------------------------------------------------------- 1 | 00 2 | 11 3 | 41 4 | 41 5 | 41 6 | 41 7 | 90 8 | c0 9 | -------------------------------------------------------------------------------- /Examples/CheckAdder/CheckAdder.hs: -------------------------------------------------------------------------------- 1 | import System.Directory 2 | 3 | import Blarney 4 | 5 | -- | Half adder taking two bits and returning a tuple with the carry bit first 6 | -- and the sum second 7 | halfAdder :: Bit 1 -> Bit 1 -> (Bit 1, Bit 1) 8 | halfAdder a b = (a .&. b, a .^. b) 9 | 10 | -- | Full adder taking two bits and an input carry and returning a tuple with 11 | -- the output carry bit first and the sum second 12 | fullAdder :: Bit 1 -> Bit 1 -> Bit 1 -> (Bit 1, Bit 1) 13 | fullAdder a b cIn = (cOut, s1) 14 | where (c0, s0) = halfAdder a b 15 | (c1, s1) = halfAdder s0 cIn 16 | cOut = c0 .|. c1 17 | 18 | -- | Bit-list adder 19 | listAdder :: Bit 1 -> [Bit 1] -> [Bit 1] -> [Bit 1] 20 | listAdder c_in _ [] = [] 21 | listAdder c_in [] _ = [] 22 | listAdder c_in (a:as) (b:bs) = 23 | sum : listAdder c_out as bs 24 | where 25 | (c_out, sum) = fullAdder a b c_in 26 | 27 | -- | Bit-vector adder 28 | adder :: KnownNat n => Bit n -> Bit n -> Bit n 29 | adder x y = fromBitList $ listAdder 0 (toBitList x) (toBitList y) 30 | 31 | -- | N-bit bugged adder 32 | doom_adder :: KnownNat n => Bit n -> Bit n -> Bit n 33 | doom_adder x y = fromBitList $ listAdder 1 (toBitList x) (toBitList y) 34 | 35 | -- | Adder property 36 | prop_add :: KnownNat n => (Bit n -> Bit n -> Bit n) -> Bit n -> Bit n 37 | -> Action () 38 | prop_add adder_imp x y = assert (adder_imp x y .==. x + y) 39 | "Adder equivalent to blarney '+' operator" 40 | 41 | -------------------------------------------------------------------------------- 42 | 43 | -- | Sequential full adder 44 | adderSeq x y = res 45 | where c_in = delay 0 c_out 46 | res@(c_out, _) = fullAdder x y c_in 47 | doom_adderSeq x y = res 48 | where c_in = delay 0 s 49 | res@(c_out, s) = fullAdder x y c_in 50 | -- | prop 51 | prop_addSeq x y = assert (adderSeq x y === adderSeq x y) 52 | "Sequential adder equivalent to itself" 53 | prop_brokenAddSeq x y = assert (adderSeq x y === doom_adderSeq x y) 54 | "Broken seq adder is equivalent to working one" 55 | 56 | -------------------------------------------------------------------------------- 57 | 58 | main :: IO () 59 | main = do 60 | -- path to script output directory 61 | cwd <- getCurrentDirectory 62 | let smtDir = cwd ++ "/CheckAdder-SMT/" 63 | -- generate smt2 scripts 64 | writeSMTScript verifConf (prop_add @2 adder) "goodAdder2" smtDir 65 | writeSMTScript verifConf (prop_add @16 adder) "goodAdder16" smtDir 66 | writeSMTScript verifConf (prop_add @2 doom_adder) "brokenAdder2" smtDir 67 | writeSMTScript verifConf (prop_add @16 doom_adder) "brokenAdder16" smtDir 68 | writeSMTScript verifConf (prop_addSeq) "goodAddSeq" smtDir 69 | writeSMTScript verifConf (prop_brokenAddSeq) "brokenAddSeq" smtDir 70 | where verifConf = dfltVerifyConf 71 | -------------------------------------------------------------------------------- /Examples/CheckAdder/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = CheckAdder.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/CheckBasicCircuits/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = CheckBasicCircuits.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/CheckFirstHot/CheckFirstHot.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | 3 | -- | Check that 'firstHot' isolates a bit that is indeed hot 4 | prop_hotCommon :: KnownNat n => Bit n -> Bit 1 5 | prop_hotCommon x = (x .&. firstHot x) .==. firstHot x 6 | 7 | -- | Count the number of ones in a bit vector 8 | countOnes :: (KnownNat n, 1 <= n) => Bit n -> Bit n 9 | countOnes x = tree (+) 0 $ map zeroExtend $ toBitList x 10 | 11 | -- | Check that 'firstHot' returns a one-hot vector 12 | prop_oneHot :: (KnownNat n, 1 <= n) => Bit n -> Bit 1 13 | prop_oneHot x = countOnes (firstHot x) .==. (if x .==. 0 then 0 else 1) 14 | 15 | -- | Assert properties for 8-bit vectors 16 | prop_firstHot :: Bit 8 -> Module () 17 | prop_firstHot x = always do 18 | assert (prop_oneHot x) "prop_oneHot" 19 | assert (prop_hotCommon x) "prop_hotCommon" 20 | 21 | main :: IO () 22 | main = do 23 | writeSMTScript dfltVerifyConf prop_firstHot "prop_firstHot" "./" 24 | --verifyWith dfltVerifyConf prop_firstHot 25 | -------------------------------------------------------------------------------- /Examples/CheckFirstHot/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = CheckFirstHot.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/CheckQueue/CheckQueue.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Queue 3 | 4 | -- Test some queue properties 5 | data QueueCmd a = 6 | QueueCmd { 7 | cmdEnq :: a -> Action () 8 | , cmdDeq :: Action () 9 | } 10 | deriving (Generic, Interface) 11 | 12 | cosim :: (Num a, Bits a) => Queue a -> Queue a -> Module (QueueCmd a) 13 | cosim q1 q2 = do 14 | always do 15 | assert (nameBits "prop_notFull" $ q1.notFull .==. q2.notFull) 16 | "q1 and q2 notFull signal should be equal" 17 | assert (nameBits "prop_notEmpty" $ q1.notEmpty .==. q2.notEmpty) 18 | "q1 and q2 notEmtpy signal should be equal" 19 | assert (nameBits "prop_First" $ 20 | q1.canDeq .&. q2.canDeq .==>. q1.first === q2.first) 21 | "q1 and q2 first elements should be equal" 22 | return 23 | QueueCmd { 24 | cmdEnq = \x -> 25 | when (q1.notFull .&. q2.notFull) do 26 | enq q1 x 27 | enq q2 x 28 | , cmdDeq = 29 | when (q1.canDeq .&. q2.canDeq) do 30 | q1.deq 31 | q2.deq 32 | } 33 | 34 | prop_queueEquiv :: KnownNat n => Module (QueueCmd (Bit n)) 35 | prop_queueEquiv = do 36 | q <- makeQueue 37 | sq <- makeShiftQueue 2 38 | cosim q sq 39 | 40 | -- Main function 41 | main :: IO () 42 | main = writeSMTScript vCnf (prop_queueEquiv @1) 43 | "prop_queueEquiv" "CheckQueue-SMT" 44 | where vCnf = dfltVerifyConf { verifyConfMode = Induction (fixedDepth 8) True } 45 | -------------------------------------------------------------------------------- /Examples/CheckQueue/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = CheckQueue.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/CheckSklansky/CheckSklansky.hs: -------------------------------------------------------------------------------- 1 | import System.Directory 2 | 3 | import Blarney 4 | import qualified Blarney.Vector as V 5 | 6 | -- | Split a list into two halves 7 | halve :: [a] -> ([a], [a]) 8 | halve xs = (take n xs, drop n xs) 9 | where n = length xs `div` 2 10 | 11 | -- | Sklansky parallel prefix network (assumes power-of-2 list size) 12 | sklansky :: (a -> a -> a) -> [a] -> [a] 13 | sklansky op [x] = [x] 14 | sklansky op xs = ys' ++ map (last ys' `op`) zs' 15 | where 16 | (ys, zs) = halve xs 17 | ys' = sklansky op ys 18 | zs' = sklansky op zs 19 | 20 | -- | Broken Sklansky implementation 21 | buggy_sklansky :: (a -> a -> a) -> [a] -> [a] 22 | buggy_sklansky op [x] = [x] 23 | buggy_sklansky op xs = ys' ++ map (head ys' `op`) zs' 24 | where 25 | (ys, zs) = halve xs 26 | ys' = sklansky op ys 27 | zs' = sklansky op zs 28 | 29 | -- | Does parallel scan equal sequential scan for given operator? 30 | prop_scan :: forall n m. 31 | ((Bit n -> Bit n -> Bit n) -> [Bit n] -> [Bit n]) 32 | -> (Bit n -> Bit n -> Bit n) 33 | -> V.Vec m (Bit n) 34 | -> Action () 35 | prop_scan sklansky_imp op ins = assert equal "prop_scan" 36 | where 37 | res0 = sklansky_imp op (V.toList ins) 38 | res1 = scanl1 op (V.toList ins) 39 | equal = andList (zipWith (.==.) res0 res1) 40 | 41 | main :: IO () 42 | main = do 43 | -- path to script output directory 44 | cwd <- getCurrentDirectory 45 | let smtDir = cwd ++ "/Sklansky-SMT/" 46 | -- generate smt2 scripts 47 | let verifyConf = dfltVerifyConf 48 | writeSMTScript verifyConf (prop_scan @4 @4 sklansky (+)) 49 | "goodSklansky4_4" smtDir 50 | writeSMTScript verifyConf (prop_scan @4 @4 buggy_sklansky (+)) 51 | "brokenSklansky4_4" smtDir 52 | -- helper usage message 53 | putStrLn $ "SMT2 scripts generated under " ++ smtDir 54 | putStrLn $ "Run an SMT solver such as z3 with an SMT2 script as input:" 55 | putStrLn $ " $ z3 " ++ smtDir ++ "goodSklansky4_4.smt2" 56 | putStrLn $ "This should return \"unsat\". Running:" 57 | putStrLn $ " $ z3 " ++ smtDir ++ "brokenSklansky4_4.smt2" 58 | putStrLn $ "should return \"sat\". Run:" 59 | putStrLn $ " $ echo \"(get-model)\" >> " 60 | ++ smtDir ++ "brokenSklansky4_4.smt2" 61 | putStrLn $ " $ z3 " ++ smtDir ++ "brokenSklansky4_4.smt2" 62 | putStrLn $ "to get a set of input assignments for which the tested property" 63 | ++ " does not hold." 64 | -------------------------------------------------------------------------------- /Examples/CheckSklansky/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = CheckSklansky.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Counter/Counter.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Recipe 3 | import System.Environment 4 | 5 | data Counter n = 6 | Counter { 7 | inc :: Action () 8 | , dec :: Action () 9 | , val :: Bit n 10 | } 11 | 12 | makeCounter :: KnownNat n => Module (Counter n) 13 | makeCounter = do 14 | -- State 15 | count :: Reg (Bit n) <- makeReg 0 16 | 17 | -- Wires 18 | incWire :: Wire (Bit 1) <- makeWire 0 19 | decWire :: Wire (Bit 1) <- makeWire 0 20 | 21 | always do 22 | -- Increment 23 | when (incWire.val .&. inv decWire.val) do 24 | count <== count.val + 1 25 | 26 | -- Decrement 27 | when (inv incWire.val .&. decWire.val) do 28 | count <== count.val - 1 29 | 30 | -- Interface 31 | let inc = incWire <== 1 32 | let dec = decWire <== 1 33 | let val = count.val 34 | 35 | return (Counter inc dec val) 36 | 37 | -- Top-level module 38 | top :: Module () 39 | top = do 40 | -- 32 bit counter 41 | counter :: Counter 32 <- makeCounter 42 | 43 | -- Simple test sequence 44 | let testSeq = 45 | Seq [ 46 | Action do counter.inc, 47 | Action do counter.inc, 48 | Action do 49 | counter.inc 50 | counter.dec, 51 | Action do 52 | counter.inc, 53 | Action do 54 | counter.dec 55 | ] 56 | 57 | done <- runRecipeOn (reg 1 0) testSeq 58 | 59 | always do 60 | when done do 61 | display "Final count = " counter.val 62 | finish 63 | 64 | return () 65 | 66 | main :: IO () 67 | main = do 68 | args <- getArgs 69 | if | "--simulate" `elem` args -> simulate top 70 | | otherwise -> writeVerilogTop top "Counter" "Counter-Verilog/" 71 | -------------------------------------------------------------------------------- /Examples/Counter/Counter.out: -------------------------------------------------------------------------------- 1 | Final count = 2 2 | -------------------------------------------------------------------------------- /Examples/Counter/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Counter.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Derive/Derive.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import System.Environment 3 | 4 | data MemReq = 5 | MemReq { 6 | memOp :: Bit 1 -- Is it a load or a store request? 7 | , memAddr :: Bit 32 -- 32-bit address 8 | , memData :: Bit 32 -- 32-bit data for stores 9 | } 10 | deriving (Generic, Bits, FShow) 11 | 12 | -- Top-level module 13 | top :: Module () 14 | top = always do 15 | let req = MemReq { memOp = 0, memAddr = 100, memData = 0 } 16 | display "req = " req 17 | finish 18 | 19 | -- Main function 20 | main :: IO () 21 | main = do 22 | args <- getArgs 23 | if | "--simulate" `elem` args -> simulate top 24 | | otherwise -> writeVerilogTop top "Derive" "Derive-Verilog/" 25 | -------------------------------------------------------------------------------- /Examples/Derive/Derive.out: -------------------------------------------------------------------------------- 1 | req = MemReq { memOp = 0, memAddr = 100, memData = 0 } 2 | -------------------------------------------------------------------------------- /Examples/Derive/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Derive.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Either/Either.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE UndecidableInstances #-} 2 | 3 | import Blarney 4 | import Blarney.Option 5 | import Blarney.TaggedUnion 6 | import System.Environment 7 | 8 | type MyEither a b = 9 | TaggedUnion [ 10 | "left" ::: a 11 | , "right" ::: b 12 | ] 13 | 14 | newtype NewEither a b = 15 | NewEither ( 16 | TaggedUnion [ 17 | "left" ::: a 18 | , "right" ::: b 19 | ] 20 | ) 21 | deriving newtype (IsTaggedUnion, Bits, FShow) 22 | 23 | --type Foo = MyEither (Option (Bit 8)) (Bit 4) 24 | type Foo = NewEither (Option (Bit 8)) (Bit 4) 25 | 26 | top :: Module () 27 | top = do 28 | always do 29 | let foo :: Foo = tag #left (some 100) 30 | display "[foo] isLeft: " (foo `is` #left) 31 | " isRight: " (foo `is` #right) 32 | " left: " (untag #left foo) 33 | " size: " (sizeOf foo) 34 | let bar :: Foo = tag #right 15 35 | display "[bar] isLeft: " (bar `is` #left) 36 | " isRight: " (bar `is` #right) 37 | " right: " (untag #right bar) 38 | display "foo = " foo 39 | display "bar = " bar 40 | finish 41 | 42 | main :: IO () 43 | main = do 44 | args <- getArgs 45 | if | "--simulate" `elem` args -> simulate top 46 | | otherwise -> writeVerilogTop top "Either" "Either-Verilog/" 47 | -------------------------------------------------------------------------------- /Examples/Either/Either.out: -------------------------------------------------------------------------------- 1 | [foo] isLeft: 1 isRight: 0 left: Option { valid = 1, val = 100 } size: 10 2 | [bar] isLeft: 0 isRight: 1 right: 15 3 | foo = #left(Option { valid = 1, val = 100 }) 4 | bar = #right(15) 5 | -------------------------------------------------------------------------------- /Examples/Either/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Either.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/FIFO/FIFO.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import System.Environment 3 | 4 | -- Single-element FIFO 5 | 6 | -- FIFO interface 7 | data FIFO a = 8 | FIFO { 9 | notFull :: Bit 1 10 | , notEmpty :: Bit 1 11 | , enq :: a -> Action () 12 | , deq :: Action () 13 | , first :: a 14 | } 15 | 16 | -- FIFO module (simple one-element FIFO) 17 | makeFIFO :: Bits a => Module (FIFO a) 18 | makeFIFO = do 19 | -- Register holding the one element 20 | reg :: Reg a <- makeReg dontCare 21 | 22 | -- Register defining whether or not FIFO is full 23 | full :: Reg (Bit 1) <- makeReg 0 24 | 25 | -- Methods 26 | let notFull = full.val .==. 0 27 | 28 | let notEmpty = full.val .==. 1 29 | 30 | let enq a = do 31 | reg <== a 32 | full <== 1 33 | 34 | let deq = full <== 0 35 | 36 | let first = val reg 37 | 38 | -- Return interface 39 | return (FIFO notFull notEmpty enq deq first) 40 | 41 | -- Top-level module 42 | top :: Module () 43 | top = do 44 | -- Counter 45 | timer :: Reg (Bit 8) <- makeReg 0 46 | 47 | -- Instantiate a FIFO 48 | fifo :: FIFO (Bit 8) <- makeFIFO 49 | 50 | always do 51 | timer <== timer.val + 1 52 | 53 | -- Writer side 54 | when (fifo.notFull) $ do 55 | fifo.enq timer.val 56 | display "Enqueued " timer.val 57 | 58 | -- Reader side 59 | when (fifo.notEmpty) $ do 60 | fifo.deq 61 | display "Dequeued " fifo.first 62 | 63 | -- Terminate after 100 cycles 64 | when (timer.val .==. 100) finish 65 | 66 | -- Main function 67 | main :: IO () 68 | main = do 69 | args <- getArgs 70 | if | "--simulate" `elem` args -> simulate top 71 | | otherwise -> writeVerilogTop top "FIFO" "FIFO-Verilog/" 72 | -------------------------------------------------------------------------------- /Examples/FIFO/FIFO.out: -------------------------------------------------------------------------------- 1 | Enqueued 0 2 | Dequeued 0 3 | Enqueued 2 4 | Dequeued 2 5 | Enqueued 4 6 | Dequeued 4 7 | Enqueued 6 8 | Dequeued 6 9 | Enqueued 8 10 | Dequeued 8 11 | Enqueued 10 12 | Dequeued 10 13 | Enqueued 12 14 | Dequeued 12 15 | Enqueued 14 16 | Dequeued 14 17 | Enqueued 16 18 | Dequeued 16 19 | Enqueued 18 20 | Dequeued 18 21 | Enqueued 20 22 | Dequeued 20 23 | Enqueued 22 24 | Dequeued 22 25 | Enqueued 24 26 | Dequeued 24 27 | Enqueued 26 28 | Dequeued 26 29 | Enqueued 28 30 | Dequeued 28 31 | Enqueued 30 32 | Dequeued 30 33 | Enqueued 32 34 | Dequeued 32 35 | Enqueued 34 36 | Dequeued 34 37 | Enqueued 36 38 | Dequeued 36 39 | Enqueued 38 40 | Dequeued 38 41 | Enqueued 40 42 | Dequeued 40 43 | Enqueued 42 44 | Dequeued 42 45 | Enqueued 44 46 | Dequeued 44 47 | Enqueued 46 48 | Dequeued 46 49 | Enqueued 48 50 | Dequeued 48 51 | Enqueued 50 52 | Dequeued 50 53 | Enqueued 52 54 | Dequeued 52 55 | Enqueued 54 56 | Dequeued 54 57 | Enqueued 56 58 | Dequeued 56 59 | Enqueued 58 60 | Dequeued 58 61 | Enqueued 60 62 | Dequeued 60 63 | Enqueued 62 64 | Dequeued 62 65 | Enqueued 64 66 | Dequeued 64 67 | Enqueued 66 68 | Dequeued 66 69 | Enqueued 68 70 | Dequeued 68 71 | Enqueued 70 72 | Dequeued 70 73 | Enqueued 72 74 | Dequeued 72 75 | Enqueued 74 76 | Dequeued 74 77 | Enqueued 76 78 | Dequeued 76 79 | Enqueued 78 80 | Dequeued 78 81 | Enqueued 80 82 | Dequeued 80 83 | Enqueued 82 84 | Dequeued 82 85 | Enqueued 84 86 | Dequeued 84 87 | Enqueued 86 88 | Dequeued 86 89 | Enqueued 88 90 | Dequeued 88 91 | Enqueued 90 92 | Dequeued 90 93 | Enqueued 92 94 | Dequeued 92 95 | Enqueued 94 96 | Dequeued 94 97 | Enqueued 96 98 | Dequeued 96 99 | Enqueued 98 100 | Dequeued 98 101 | Enqueued 100 102 | -------------------------------------------------------------------------------- /Examples/FIFO/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = FIFO.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Factorial/Factorial.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Recipe 3 | import System.Environment 4 | 5 | fact :: Module () 6 | fact = do 7 | -- State 8 | n :: Reg (Bit 32) <- makeReg 0 9 | acc :: Reg (Bit 32) <- makeReg 1 10 | 11 | -- Compute factorial of 10 12 | let recipe = 13 | Seq [ 14 | Action do 15 | n <== 10 16 | , While (n.val .>. 0) ( 17 | Action do 18 | n <== n.val - 1 19 | acc <== acc.val * n.val 20 | ) 21 | , Action do 22 | display "fact(10) = " acc.val 23 | finish 24 | ] 25 | 26 | runRecipe recipe 27 | 28 | main :: IO () 29 | main = do 30 | args <- getArgs 31 | if | "--simulate" `elem` args -> simulate fact 32 | | otherwise -> writeVerilogTop fact "Factorial" "Factorial-Verilog/" 33 | -------------------------------------------------------------------------------- /Examples/Factorial/Factorial.out: -------------------------------------------------------------------------------- 1 | fact(10) = 3628800 2 | -------------------------------------------------------------------------------- /Examples/Factorial/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Factorial.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/GCDFarm/GCDFarm.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stmt 3 | import Blarney.Queue 4 | import Blarney.Stream 5 | import System.Environment 6 | 7 | -- Server for computing GCDs using Euclid's algorithm 8 | makeGCDServer :: (Bits a, Cmp a, Num a) => Stream (a, a) -> Module (Stream a) 9 | makeGCDServer reqs = do 10 | -- State 11 | answers <- makeQueue 12 | a <- makeReg dontCare 13 | b <- makeReg dontCare 14 | 15 | runStmt do 16 | while true do 17 | -- Consume request 18 | wait reqs.canPeek 19 | action do 20 | let (numA, numB) = reqs.peek 21 | a <== numA 22 | b <== numB 23 | reqs.consume 24 | -- Compute GCD 25 | while (a.val .!=. b.val) do 26 | action do 27 | if a.val .>. b.val 28 | then a <== a.val - b.val 29 | else b <== b.val - a.val 30 | -- Produce answer 31 | wait answers.notFull 32 | action do 33 | answers.enq a.val 34 | 35 | return (toStream answers) 36 | 37 | -- Model of a server using functions over streams 38 | type Server req resp = Stream req -> Module (Stream resp) 39 | 40 | makeServerFarm :: Interface resp => Int -> Server req resp -> Server req resp 41 | makeServerFarm n server reqs = 42 | splitStream n reqs >>= mapM server >>= mergeStreams 43 | 44 | splitStream :: Int -> Stream a -> Module [Stream a] 45 | splitStream n s = do 46 | -- Which output stream to feed next? 47 | next :: [Reg (Bit 1)] <- 48 | mapM makeReg ([true] ++ replicate (n-1) false) 49 | 50 | -- When an output stream is consumed, move to the next one 51 | return 52 | [ s { 53 | canPeek = s.canPeek .&&. active.val 54 | , consume = s.consume >> rotate next 55 | } 56 | | active <- next ] 57 | 58 | rotate :: Bits a => [Reg a] -> Action () 59 | rotate xs = zipWithM_ (<==) xs (drop 1 vals ++ take 1 vals) 60 | where vals = map (.val) xs 61 | 62 | mergeStreams :: Interface a => [Stream a] -> Module (Stream a) 63 | mergeStreams ss = do 64 | -- Which input stream to consume next? 65 | next :: [Reg (Bit 1)] <- 66 | mapM makeReg ([true] ++ replicate (length ss - 1) false) 67 | 68 | -- Select stream using general indexing operator 69 | let s = ss ! OneHotList (map (.val) next) 70 | 71 | -- When output is consumed, move to the next input stream 72 | return 73 | s { consume = s.consume >> rotate next } 74 | 75 | -- Top-level test bench 76 | top :: Module () 77 | top = do 78 | -- Input buffer of size 32 79 | inputs <- makeSizedQueue 5 80 | 81 | -- Instantiate farm of 4 servers 82 | outputs <- makeServerFarm 4 makeGCDServer (toStream inputs) 83 | 84 | -- Timer 85 | timer :: Reg (Bit 32) <- makeReg 0 86 | always do timer <== timer.val + 1 87 | 88 | runStmt do 89 | wait inputs.notFull 90 | action do inputs.enq (693 :: Bit 32, 700) 91 | 92 | wait inputs.notFull 93 | action do inputs.enq (81, 27) 94 | 95 | wait inputs.notFull 96 | action do inputs.enq (500, 495) 97 | 98 | replicateM 3 do 99 | wait outputs.canPeek 100 | action do 101 | display outputs.peek 102 | outputs.consume 103 | 104 | action do 105 | display "Finished at time " timer.val 106 | finish 107 | 108 | main :: IO () 109 | main = do 110 | args <- getArgs 111 | if | "--simulate" `elem` args -> simulate top 112 | | otherwise -> writeVerilogTop top "GCDFarm" "GCDFarm-Verilog/" 113 | -------------------------------------------------------------------------------- /Examples/GCDFarm/GCDFarm.out: -------------------------------------------------------------------------------- 1 | 7 2 | 27 3 | 5 4 | Finished at time 106 5 | -------------------------------------------------------------------------------- /Examples/GCDFarm/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = GCDFarm.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Heat/Heat.hs: -------------------------------------------------------------------------------- 1 | import Mesh 2 | import Blarney 3 | import Data.List 4 | import System.Environment 5 | 6 | -- Heat diffusion on a 2D mesh 7 | 8 | -- Temperature type 9 | type Temp = Bit 32 10 | 11 | -- Update cell using values of neighbours 12 | step :: Reg Temp -> [Temp] -> Action () 13 | step me neighbours = 14 | me <== sumList neighbours .>>. (2 :: Bit 2) 15 | 16 | -- Top-level 17 | top :: Integer -> Int -> Int -> Module () 18 | top t w h = do 19 | -- North and east borders (initialised hot) 20 | north <- replicateM w (makeReg 0xff0000) 21 | east <- replicateM (h-2) (makeReg 0xff0000) 22 | -- South and west borders (initialised cold) 23 | south <- replicateM w (makeReg 0x2a0000) 24 | west <- replicateM (h-2) (makeReg 0x2a0000) 25 | -- Remaining cells 26 | cells <- replicateM (h-2) (replicateM (w-2) (makeReg 0)) 27 | -- Count time steps 28 | timer :: Reg (Bit 32) <- makeReg 0 29 | -- Overall grid 30 | let grid = [north] 31 | ++ transpose ([east] ++ transpose cells ++ [west]) 32 | ++ [south] 33 | always do 34 | -- Mesh 35 | mesh step grid 36 | -- Increment time 37 | timer <== timer.val + 1 38 | -- Termination 39 | when (timer.val .==. fromInteger t) do 40 | forM_ (zip [0..] grid) $ \(i, row) -> 41 | forM_ (zip [0..] row) $ \(j, cell) -> do 42 | let out = cell.val .>>. (16 :: Bit 5) 43 | when (out .!=. 0) do 44 | display (show i) "," (show j) ":" out 45 | finish 46 | 47 | -- Main function 48 | main :: IO () 49 | main = do 50 | args <- getArgs 51 | if | "--simulate" `elem` args -> simulate (top 10 128 128) 52 | | otherwise -> writeVerilogTop (top 10 128 128) "Heat" "Heat-Verilog/" 53 | -------------------------------------------------------------------------------- /Examples/Heat/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Heat.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Heat/Mesh.hs: -------------------------------------------------------------------------------- 1 | -- 2D Mesh combinators 2 | 3 | module Mesh where 4 | 5 | import Prelude 6 | import Data.List 7 | import qualified Blarney as B 8 | 9 | type Mesh a = [[a]] 10 | 11 | on :: (a -> b) -> Mesh a -> Mesh b 12 | on f m = map (map f) m 13 | 14 | onM_ :: Monad m => (a -> m b) -> Mesh a -> m () 15 | onM_ f m = mapM_ (mapM_ f) m 16 | 17 | merge :: (a -> b -> c) -> Mesh a -> Mesh b -> Mesh c 18 | merge f = zipWith (zipWith f) 19 | 20 | overlay :: Mesh [a] -> Mesh [a] -> Mesh [a] 21 | overlay = merge (++) 22 | 23 | neighbours :: Mesh a -> Mesh [a] 24 | neighbours m = right m `overlay` left m `overlay` above m `overlay` below m 25 | 26 | right :: Mesh a -> Mesh [a] 27 | right m = [map (:[]) xs ++ [[]] | x:xs <- m] 28 | 29 | left :: Mesh a -> Mesh [a] 30 | left = map reverse . right . map reverse 31 | 32 | above :: Mesh a -> Mesh [a] 33 | above = transpose . left . transpose 34 | 35 | below :: Mesh a -> Mesh [a] 36 | below = transpose . right . transpose 37 | 38 | trim :: Mesh a -> Mesh a 39 | trim = map tail . map init . tail . init 40 | 41 | mesh :: B.Bits a => (B.Reg a -> [a] -> B.Action ()) -> 42 | Mesh (B.Reg a) -> B.Action () 43 | mesh f m = uncurry f `onM_` trim (merge (,) m (map B.val `on` neighbours m)) 44 | -------------------------------------------------------------------------------- /Examples/Interface/Interface.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Queue 3 | import Blarney.Stream 4 | import System.Environment 5 | 6 | -- Single-element FIFO 7 | 8 | -- Module that increments each element in a stream 9 | inc :: Stream (Bit 8) -> Module (Stream (Bit 8)) 10 | inc xs = do 11 | -- Output buffer 12 | buffer <- makeQueue 13 | 14 | always do 15 | -- Incrementer 16 | when (xs.canPeek .&&. buffer.notFull) do 17 | xs.consume 18 | buffer.enq (xs.peek + 1) 19 | 20 | -- Convert buffer to a stream 21 | return (toStream buffer) 22 | 23 | -- This function creates an instance of a Verilog module called "inc" 24 | makeIncS :: Stream (Bit 8) -> Module (Stream (Bit 8)) 25 | makeIncS = makeInstance "inc" 26 | 27 | top :: Module () 28 | top = do 29 | -- Counter 30 | count :: Reg (Bit 8) <- makeReg 0 31 | 32 | -- Input buffer 33 | buffer <- makeQueue 34 | 35 | -- Create an instance of inc 36 | out <- makeIncS (toStream buffer) 37 | 38 | always do 39 | -- Fill input 40 | when buffer.notFull do 41 | buffer.enq count.val 42 | count <== count.val + 1 43 | 44 | -- Consume 45 | when out.canPeek do 46 | out.consume 47 | display "Got " out.peek 48 | when (out.peek .==. 100) finish 49 | 50 | -- Main function 51 | main :: IO () 52 | main = do 53 | args <- getArgs 54 | if | "--simulate" `elem` args -> simulate top 55 | | otherwise -> do writeVerilogModule inc "inc" "Interface-Verilog/" 56 | writeVerilogTop top "Interface" "Interface-Verilog/" 57 | -------------------------------------------------------------------------------- /Examples/Interface/Interface.out: -------------------------------------------------------------------------------- 1 | Got 1 2 | Got 2 3 | Got 3 4 | Got 4 5 | Got 5 6 | Got 6 7 | Got 7 8 | Got 8 9 | Got 9 10 | Got 10 11 | Got 11 12 | Got 12 13 | Got 13 14 | Got 14 15 | Got 15 16 | Got 16 17 | Got 17 18 | Got 18 19 | Got 19 20 | Got 20 21 | Got 21 22 | Got 22 23 | Got 23 24 | Got 24 25 | Got 25 26 | Got 26 27 | Got 27 28 | Got 28 29 | Got 29 30 | Got 30 31 | Got 31 32 | Got 32 33 | Got 33 34 | Got 34 35 | Got 35 36 | Got 36 37 | Got 37 38 | Got 38 39 | Got 39 40 | Got 40 41 | Got 41 42 | Got 42 43 | Got 43 44 | Got 44 45 | Got 45 46 | Got 46 47 | Got 47 48 | Got 48 49 | Got 49 50 | Got 50 51 | Got 51 52 | Got 52 53 | Got 53 54 | Got 54 55 | Got 55 56 | Got 56 57 | Got 57 58 | Got 58 59 | Got 59 60 | Got 60 61 | Got 61 62 | Got 62 63 | Got 63 64 | Got 64 65 | Got 65 66 | Got 66 67 | Got 67 68 | Got 68 69 | Got 69 70 | Got 70 71 | Got 71 72 | Got 72 73 | Got 73 74 | Got 74 75 | Got 75 76 | Got 76 77 | Got 77 78 | Got 78 79 | Got 79 80 | Got 80 81 | Got 81 82 | Got 82 83 | Got 83 84 | Got 84 85 | Got 85 86 | Got 86 87 | Got 87 88 | Got 88 89 | Got 89 90 | Got 90 91 | Got 91 92 | Got 92 93 | Got 93 94 | Got 94 95 | Got 95 96 | Got 96 97 | Got 97 98 | Got 98 99 | Got 99 100 | Got 100 101 | -------------------------------------------------------------------------------- /Examples/Interface/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Interface.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Iterator/Iterator.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stmt 3 | import Blarney.SourceSink 4 | import Blarney.ClientServer 5 | import System.Environment 6 | 7 | makeIterator :: Bits a => 8 | (a -> a) -> (a -> Bit 1) -> Module (Server a a) 9 | makeIterator step done = do 10 | -- State 11 | busy <- makeReg false 12 | state <- makeReg dontCare 13 | 14 | -- Result ready? 15 | let ready = done state.val 16 | 17 | -- Update state 18 | always do 19 | when (busy.val .&&. inv ready) do 20 | state <== step state.val 21 | 22 | return 23 | Server { 24 | reqs = Sink { 25 | canPut = inv busy.val 26 | , put = \req -> do busy <== true 27 | state <== req 28 | } 29 | , resps = Source { 30 | canPeek = busy.val .&&. ready 31 | , peek = state.val 32 | , consume = busy <== false 33 | } 34 | } 35 | 36 | makeRemServer :: (Bits a, Num a, Cmp a) => Module (Server (a, a) (a, a)) 37 | makeRemServer = makeIterator step done 38 | where 39 | step (x, y) = (x-y, y) 40 | done (x, y) = x .<. y .||. y .==. 0 41 | 42 | makeGCDServer :: (Bits a, Num a, Cmp a) => Module (Server (a, a) (a, a)) 43 | makeGCDServer = makeIterator step done 44 | where 45 | step (x, y) = if x .>. y then (x - y, y) else (x, y - x) 46 | done (x, y) = x .==. y 47 | 48 | 49 | top :: Module () 50 | top = do 51 | gcd <- makeGCDServer @(Bit 8) 52 | 53 | runStmt do 54 | wait gcd.reqs.canPut 55 | action do 56 | gcd.reqs.put (110, 66) 57 | wait gcd.resps.canPeek 58 | action do 59 | display "gcd=" (fst gcd.resps.peek) 60 | gcd.resps.consume 61 | finish 62 | 63 | main :: IO () 64 | main = do 65 | args <- getArgs 66 | if | "--simulate" `elem` args -> simulate top 67 | | otherwise -> writeVerilogTop top "Iterator" "Iterator-Verilog/" 68 | -------------------------------------------------------------------------------- /Examples/Iterator/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Iterator.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Lookup/Lookup.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Queue 3 | import System.Environment 4 | 5 | top :: Module () 6 | top = do 7 | -- Create a list of 4 queues 8 | queues :: [Queue (Bit 8)] <- replicateM 4 makeQueue 9 | 10 | -- Cycle count 11 | cycleCount :: Reg (Bit 8) <- makeReg 0 12 | 13 | always do 14 | cycleCount <== cycleCount.val + 1 15 | 16 | -- Create index using lower 2 bits of cycle count 17 | let ind :: Bit 2 = truncate cycleCount.val 18 | 19 | -- Pick a queue using the index 20 | let q = queues ! ind 21 | 22 | -- Write to queue 23 | when q.notFull do 24 | q.enq (zeroExtend ind) 25 | 26 | -- Consume from queue 27 | when q.canDeq do 28 | q.deq 29 | display cycleCount.val ": " q.first 30 | 31 | -- Terminate simulation when count reaches 16 32 | when (cycleCount.val .==. 16) do 33 | display "Finished" 34 | finish 35 | 36 | main :: IO () 37 | main = do 38 | args <- getArgs 39 | if | "--simulate" `elem` args -> simulate top 40 | | otherwise -> writeVerilogTop top "Lookup" "Lookup-Verilog/" 41 | -------------------------------------------------------------------------------- /Examples/Lookup/Lookup.out: -------------------------------------------------------------------------------- 1 | 4: 0 2 | 5: 1 3 | 6: 2 4 | 7: 3 5 | 8: 0 6 | 9: 1 7 | 10: 2 8 | 11: 3 9 | 12: 0 10 | 13: 1 11 | 14: 2 12 | 15: 3 13 | 16: 0 14 | Finished 15 | -------------------------------------------------------------------------------- /Examples/Lookup/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Lookup.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | .PHONY: clean 4 | clean: 5 | make -C CheckAdder clean 6 | make -C CheckBasicCircuits clean 7 | make -C CheckSklansky clean 8 | make -C CheckQueue clean 9 | make -C Background clean 10 | make -C BasicRTL clean 11 | make -C Bit0 clean 12 | make -C BitPat clean 13 | make -C BitScan clean 14 | make -C CPU clean 15 | make -C Derive clean 16 | make -C Either clean 17 | make -C Factorial clean 18 | make -C FIFO clean 19 | make -C GCDFarm clean 20 | make -C Interface clean 21 | make -C Iterator clean 22 | make -C Lookup clean 23 | make -C MasterSlave clean 24 | make -C Heat clean 25 | make -C NameBits clean 26 | make -C NoC clean 27 | make -C Option clean 28 | make -C Queue clean 29 | make -C RAM clean 30 | make -C RAMQuad clean 31 | make -C Sorter clean 32 | make -C SourceSink clean 33 | make -C Stack clean 34 | make -C SizedStack clean 35 | make -C StackTesting clean 36 | make -C Counter clean 37 | make -C Vectors clean 38 | make -C RAMBE clean 39 | -------------------------------------------------------------------------------- /Examples/MasterSlave/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = MasterSlave.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/MasterSlave/MasterSlave.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stream 3 | import Blarney.Queue 4 | import System.Environment 5 | 6 | type MulReq = (Bit 32, Bit 32) 7 | type MulResp = Bit 32 8 | 9 | slave :: Stream MulReq -> Module (Stream MulResp) 10 | slave reqs = do 11 | buffer <- makeQueue 12 | 13 | always do 14 | when (reqs.canPeek .&&. buffer.notFull) do 15 | reqs.consume 16 | buffer.enq (fst reqs.peek * snd reqs.peek) 17 | 18 | return (toStream buffer) 19 | 20 | master :: Stream MulResp -> Module (Stream MulReq) 21 | master resps = do 22 | buffer <- makeQueue 23 | 24 | always do 25 | when buffer.notFull do 26 | buffer.enq (16, 4) 27 | 28 | when resps.canPeek do 29 | resps.consume 30 | display "Response: 0x" (formatHex 8 resps.peek) 31 | finish 32 | 33 | return (toStream buffer) 34 | 35 | makeSlave :: Stream MulReq -> Module (Stream MulResp) 36 | makeSlave = makeBoundary "slave" slave 37 | 38 | makeMaster :: Stream MulResp -> Module (Stream MulReq) 39 | makeMaster = makeBoundary "master" master 40 | 41 | top :: Module () 42 | top = mdo 43 | resps <- makeMaster reqs 44 | reqs <- makeSlave resps 45 | return () 46 | 47 | main :: IO () 48 | main = do 49 | args <- getArgs 50 | if | "--simulate" `elem` args -> simulate top 51 | | otherwise -> do writeVerilogModule slave "slave" "MasterSlave-Verilog/" 52 | writeVerilogModule master "master" "MasterSlave-Verilog/" 53 | writeVerilogTop top "MasterSlave" "MasterSlave-Verilog/" 54 | -------------------------------------------------------------------------------- /Examples/MasterSlave/MasterSlave.out: -------------------------------------------------------------------------------- 1 | Response: 0x00000040 2 | -------------------------------------------------------------------------------- /Examples/NameBits/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = NameBits.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/NameBits/NameBits.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import System.Environment 3 | 4 | top :: Module () 5 | top = do 6 | -- Create a register 7 | cycleCount :: Reg (Bit 4) <- makeReg 0 8 | let a = nameBits "AAA" cycleCount.val 9 | let b = nameBits "BBB" cycleCount.val 10 | 11 | always do 12 | -- Increment on every cycle 13 | cycleCount <== b + 1 14 | 15 | -- Display value an every cycle 16 | display "cycleCount = " cycleCount.val 17 | display "cycleCount(a) = " a 18 | display "cycleCount(b) = " b 19 | 20 | -- Terminate simulation when count reaches 10 21 | when (cycleCount.val .==. 10) do 22 | display "Finished" 23 | finish 24 | 25 | main :: IO () 26 | main = do 27 | args <- getArgs 28 | if | "--simulate" `elem` args -> simulate top 29 | | otherwise -> writeVerilogTop top "NameBits" "NameBits-Verilog/" 30 | -------------------------------------------------------------------------------- /Examples/NameBits/NameBits.out: -------------------------------------------------------------------------------- 1 | cycleCount = 0 2 | cycleCount(a) = 0 3 | cycleCount(b) = 0 4 | cycleCount = 1 5 | cycleCount(a) = 1 6 | cycleCount(b) = 1 7 | cycleCount = 2 8 | cycleCount(a) = 2 9 | cycleCount(b) = 2 10 | cycleCount = 3 11 | cycleCount(a) = 3 12 | cycleCount(b) = 3 13 | cycleCount = 4 14 | cycleCount(a) = 4 15 | cycleCount(b) = 4 16 | cycleCount = 5 17 | cycleCount(a) = 5 18 | cycleCount(b) = 5 19 | cycleCount = 6 20 | cycleCount(a) = 6 21 | cycleCount(b) = 6 22 | cycleCount = 7 23 | cycleCount(a) = 7 24 | cycleCount(b) = 7 25 | cycleCount = 8 26 | cycleCount(a) = 8 27 | cycleCount(b) = 8 28 | cycleCount = 9 29 | cycleCount(a) = 9 30 | cycleCount(b) = 9 31 | cycleCount = 10 32 | cycleCount(a) = 10 33 | cycleCount(b) = 10 34 | Finished 35 | -------------------------------------------------------------------------------- /Examples/NoC/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = NoC.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Option/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Option.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Option/Option.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Option 3 | import System.Environment 4 | 5 | testModule :: Module (Option (Bit 32), Bit 32) 6 | testModule = do 7 | testReg :: Reg (Bit 32) <- makeReg 0 8 | always do testReg <== testReg.val + 1 9 | let optVal = if testReg.val .%. 5 === 0 then some testReg.val else none 10 | return (optVal, testReg.val) 11 | 12 | top :: Module () 13 | top = do 14 | -- Create a testModule 15 | (opt, noopt) <- testModule 16 | cnt :: Reg (Bit 32) <- makeReg 0 17 | always do 18 | -- Display values 19 | display "opt = " opt ", noopt = " noopt 20 | display "cnt = " (cnt.val) 21 | -- update counter 22 | when (isSome opt) do cnt <== cnt.val + 1 23 | -- Terminate simulation 24 | when (cnt.val .==. 5) do 25 | display "Finished" 26 | finish 27 | 28 | main :: IO () 29 | main = do 30 | args <- getArgs 31 | if | "--simulate" `elem` args -> simulate top 32 | | otherwise -> do 33 | writeVerilogModule testModule "testModule" "Option-Verilog/" 34 | writeVerilogTop top "Option" "Option-Verilog/" 35 | -------------------------------------------------------------------------------- /Examples/Option/Option.out: -------------------------------------------------------------------------------- 1 | opt = Option { valid = 1, val = 0 }, noopt = 0 2 | cnt = 0 3 | opt = Option { valid = 0, val = 0 }, noopt = 1 4 | cnt = 1 5 | opt = Option { valid = 0, val = 0 }, noopt = 2 6 | cnt = 1 7 | opt = Option { valid = 0, val = 0 }, noopt = 3 8 | cnt = 1 9 | opt = Option { valid = 0, val = 0 }, noopt = 4 10 | cnt = 1 11 | opt = Option { valid = 1, val = 5 }, noopt = 5 12 | cnt = 1 13 | opt = Option { valid = 0, val = 0 }, noopt = 6 14 | cnt = 2 15 | opt = Option { valid = 0, val = 0 }, noopt = 7 16 | cnt = 2 17 | opt = Option { valid = 0, val = 0 }, noopt = 8 18 | cnt = 2 19 | opt = Option { valid = 0, val = 0 }, noopt = 9 20 | cnt = 2 21 | opt = Option { valid = 1, val = 10 }, noopt = 10 22 | cnt = 2 23 | opt = Option { valid = 0, val = 0 }, noopt = 11 24 | cnt = 3 25 | opt = Option { valid = 0, val = 0 }, noopt = 12 26 | cnt = 3 27 | opt = Option { valid = 0, val = 0 }, noopt = 13 28 | cnt = 3 29 | opt = Option { valid = 0, val = 0 }, noopt = 14 30 | cnt = 3 31 | opt = Option { valid = 1, val = 15 }, noopt = 15 32 | cnt = 3 33 | opt = Option { valid = 0, val = 0 }, noopt = 16 34 | cnt = 4 35 | opt = Option { valid = 0, val = 0 }, noopt = 17 36 | cnt = 4 37 | opt = Option { valid = 0, val = 0 }, noopt = 18 38 | cnt = 4 39 | opt = Option { valid = 0, val = 0 }, noopt = 19 40 | cnt = 4 41 | opt = Option { valid = 1, val = 20 }, noopt = 20 42 | cnt = 4 43 | opt = Option { valid = 0, val = 0 }, noopt = 21 44 | cnt = 5 45 | Finished 46 | -------------------------------------------------------------------------------- /Examples/Queue/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Queue.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Queue/Queue.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Queue 3 | import System.Environment 4 | 5 | -- Top-level module 6 | top :: Module () 7 | top = do 8 | -- Queue 9 | queue :: Queue (Bit 32) <- makeSizedQueue 3 10 | 11 | -- Counter 12 | count :: Reg (Bit 32) <- makeReg 0 13 | 14 | always do 15 | count <== count.val + 1 16 | 17 | -- Feed queue 18 | when queue.notFull do 19 | queue.enq count.val 20 | 21 | -- Consume queue 22 | when (queue.canDeq .&&. count.val .>. 50) do 23 | queue.deq 24 | display "Got " queue.first 25 | when (queue.first .>. 100) finish 26 | 27 | -- Main function 28 | main :: IO () 29 | main = do 30 | args <- getArgs 31 | if | "--simulate" `elem` args -> simulate top 32 | | otherwise -> writeVerilogTop top "Queue" "Queue-Verilog/" 33 | -------------------------------------------------------------------------------- /Examples/Queue/Queue.out: -------------------------------------------------------------------------------- 1 | Got 0 2 | Got 1 3 | Got 2 4 | Got 3 5 | Got 4 6 | Got 5 7 | Got 6 8 | Got 7 9 | Got 8 10 | Got 52 11 | Got 53 12 | Got 54 13 | Got 55 14 | Got 56 15 | Got 57 16 | Got 58 17 | Got 59 18 | Got 60 19 | Got 61 20 | Got 62 21 | Got 63 22 | Got 64 23 | Got 65 24 | Got 66 25 | Got 67 26 | Got 68 27 | Got 69 28 | Got 70 29 | Got 71 30 | Got 72 31 | Got 73 32 | Got 74 33 | Got 75 34 | Got 76 35 | Got 77 36 | Got 78 37 | Got 79 38 | Got 80 39 | Got 81 40 | Got 82 41 | Got 83 42 | Got 84 43 | Got 85 44 | Got 86 45 | Got 87 46 | Got 88 47 | Got 89 48 | Got 90 49 | Got 91 50 | Got 92 51 | Got 93 52 | Got 94 53 | Got 95 54 | Got 96 55 | Got 97 56 | Got 98 57 | Got 99 58 | Got 100 59 | Got 101 60 | -------------------------------------------------------------------------------- /Examples/RAM/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = RAM.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/RAM/RAM.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stmt 3 | import System.Environment 4 | 5 | -- Top-level module 6 | top :: Module () 7 | top = do 8 | -- RAM 9 | ram :: RAM (Bit 8) (Bit 128) <- makeRAM 10 | 11 | -- Counter 12 | i :: Reg (Bit 8) <- makeReg 0 13 | 14 | -- Simple test sequence 15 | runStmt do 16 | while (i.val .<. 100) do 17 | action do 18 | ram.store i.val (1 .<<. i.val) 19 | i <== i.val + 1 20 | action do 21 | i <== 0 22 | while (i.val .<. 100) do 23 | action do 24 | ram.load i.val 25 | action do 26 | display "ram[" i.val "] = 0x" (formatHex 32 ram.out) 27 | i <== i.val + 1 28 | action do 29 | finish 30 | 31 | return () 32 | 33 | -- Main function 34 | main :: IO () 35 | main = do 36 | args <- getArgs 37 | if | "--simulate" `elem` args -> simulate top 38 | | otherwise -> writeVerilogTop top "RAM" "RAM-Verilog/" 39 | -------------------------------------------------------------------------------- /Examples/RAM/RAM.out: -------------------------------------------------------------------------------- 1 | ram[0] = 0x00000000000000000000000000000001 2 | ram[1] = 0x00000000000000000000000000000002 3 | ram[2] = 0x00000000000000000000000000000004 4 | ram[3] = 0x00000000000000000000000000000008 5 | ram[4] = 0x00000000000000000000000000000010 6 | ram[5] = 0x00000000000000000000000000000020 7 | ram[6] = 0x00000000000000000000000000000040 8 | ram[7] = 0x00000000000000000000000000000080 9 | ram[8] = 0x00000000000000000000000000000100 10 | ram[9] = 0x00000000000000000000000000000200 11 | ram[10] = 0x00000000000000000000000000000400 12 | ram[11] = 0x00000000000000000000000000000800 13 | ram[12] = 0x00000000000000000000000000001000 14 | ram[13] = 0x00000000000000000000000000002000 15 | ram[14] = 0x00000000000000000000000000004000 16 | ram[15] = 0x00000000000000000000000000008000 17 | ram[16] = 0x00000000000000000000000000010000 18 | ram[17] = 0x00000000000000000000000000020000 19 | ram[18] = 0x00000000000000000000000000040000 20 | ram[19] = 0x00000000000000000000000000080000 21 | ram[20] = 0x00000000000000000000000000100000 22 | ram[21] = 0x00000000000000000000000000200000 23 | ram[22] = 0x00000000000000000000000000400000 24 | ram[23] = 0x00000000000000000000000000800000 25 | ram[24] = 0x00000000000000000000000001000000 26 | ram[25] = 0x00000000000000000000000002000000 27 | ram[26] = 0x00000000000000000000000004000000 28 | ram[27] = 0x00000000000000000000000008000000 29 | ram[28] = 0x00000000000000000000000010000000 30 | ram[29] = 0x00000000000000000000000020000000 31 | ram[30] = 0x00000000000000000000000040000000 32 | ram[31] = 0x00000000000000000000000080000000 33 | ram[32] = 0x00000000000000000000000100000000 34 | ram[33] = 0x00000000000000000000000200000000 35 | ram[34] = 0x00000000000000000000000400000000 36 | ram[35] = 0x00000000000000000000000800000000 37 | ram[36] = 0x00000000000000000000001000000000 38 | ram[37] = 0x00000000000000000000002000000000 39 | ram[38] = 0x00000000000000000000004000000000 40 | ram[39] = 0x00000000000000000000008000000000 41 | ram[40] = 0x00000000000000000000010000000000 42 | ram[41] = 0x00000000000000000000020000000000 43 | ram[42] = 0x00000000000000000000040000000000 44 | ram[43] = 0x00000000000000000000080000000000 45 | ram[44] = 0x00000000000000000000100000000000 46 | ram[45] = 0x00000000000000000000200000000000 47 | ram[46] = 0x00000000000000000000400000000000 48 | ram[47] = 0x00000000000000000000800000000000 49 | ram[48] = 0x00000000000000000001000000000000 50 | ram[49] = 0x00000000000000000002000000000000 51 | ram[50] = 0x00000000000000000004000000000000 52 | ram[51] = 0x00000000000000000008000000000000 53 | ram[52] = 0x00000000000000000010000000000000 54 | ram[53] = 0x00000000000000000020000000000000 55 | ram[54] = 0x00000000000000000040000000000000 56 | ram[55] = 0x00000000000000000080000000000000 57 | ram[56] = 0x00000000000000000100000000000000 58 | ram[57] = 0x00000000000000000200000000000000 59 | ram[58] = 0x00000000000000000400000000000000 60 | ram[59] = 0x00000000000000000800000000000000 61 | ram[60] = 0x00000000000000001000000000000000 62 | ram[61] = 0x00000000000000002000000000000000 63 | ram[62] = 0x00000000000000004000000000000000 64 | ram[63] = 0x00000000000000008000000000000000 65 | ram[64] = 0x00000000000000010000000000000000 66 | ram[65] = 0x00000000000000020000000000000000 67 | ram[66] = 0x00000000000000040000000000000000 68 | ram[67] = 0x00000000000000080000000000000000 69 | ram[68] = 0x00000000000000100000000000000000 70 | ram[69] = 0x00000000000000200000000000000000 71 | ram[70] = 0x00000000000000400000000000000000 72 | ram[71] = 0x00000000000000800000000000000000 73 | ram[72] = 0x00000000000001000000000000000000 74 | ram[73] = 0x00000000000002000000000000000000 75 | ram[74] = 0x00000000000004000000000000000000 76 | ram[75] = 0x00000000000008000000000000000000 77 | ram[76] = 0x00000000000010000000000000000000 78 | ram[77] = 0x00000000000020000000000000000000 79 | ram[78] = 0x00000000000040000000000000000000 80 | ram[79] = 0x00000000000080000000000000000000 81 | ram[80] = 0x00000000000100000000000000000000 82 | ram[81] = 0x00000000000200000000000000000000 83 | ram[82] = 0x00000000000400000000000000000000 84 | ram[83] = 0x00000000000800000000000000000000 85 | ram[84] = 0x00000000001000000000000000000000 86 | ram[85] = 0x00000000002000000000000000000000 87 | ram[86] = 0x00000000004000000000000000000000 88 | ram[87] = 0x00000000008000000000000000000000 89 | ram[88] = 0x00000000010000000000000000000000 90 | ram[89] = 0x00000000020000000000000000000000 91 | ram[90] = 0x00000000040000000000000000000000 92 | ram[91] = 0x00000000080000000000000000000000 93 | ram[92] = 0x00000000100000000000000000000000 94 | ram[93] = 0x00000000200000000000000000000000 95 | ram[94] = 0x00000000400000000000000000000000 96 | ram[95] = 0x00000000800000000000000000000000 97 | ram[96] = 0x00000001000000000000000000000000 98 | ram[97] = 0x00000002000000000000000000000000 99 | ram[98] = 0x00000004000000000000000000000000 100 | ram[99] = 0x00000008000000000000000000000000 101 | -------------------------------------------------------------------------------- /Examples/RAMBE/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = RAMBE.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/RAMBE/RAMBE.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stmt 3 | import System.Environment 4 | 5 | -- Top-level module 6 | top :: Module () 7 | top = do 8 | -- RAM 9 | ram :: RAMBE 10 4 <- makeRAMBE 10 | 11 | -- Counter 12 | i :: Reg (Bit 10) <- makeReg 0 13 | 14 | -- Simple test sequence 15 | runStmt do 16 | while (i.val .<. 1000) do 17 | action do 18 | ram.storeBE i.val 1 (zeroExtend i.val) 19 | i <== i.val + 1 20 | action do 21 | i <== 0 22 | while (i.val .<. 1000) do 23 | action do 24 | ram.loadBE i.val 25 | action do 26 | display "ram[" i.val "] = " ram.outBE 27 | i <== i.val + 1 28 | action do 29 | finish 30 | 31 | return () 32 | 33 | -- Main function 34 | main :: IO () 35 | main = do 36 | args <- getArgs 37 | if | "--simulate" `elem` args -> simulate top 38 | | otherwise -> writeVerilogTop top "RAMBE" "RAMBE-Verilog/" 39 | -------------------------------------------------------------------------------- /Examples/RAMQuad/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = RAMQuad.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/RAMQuad/RAMQuad.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stmt 3 | import Blarney.QuadPortRAM 4 | 5 | -- Top-level module 6 | top :: Module () 7 | top = do 8 | -- Quad-port RAM 9 | (ramA, ramB) :: (RAM (Bit 8) (Bit 32), 10 | RAM (Bit 8) (Bit 32)) <- makeQuadRAM 11 | 12 | -- Counter 13 | i :: Reg (Bit 8) <- makeReg 0 14 | 15 | -- Simple test sequence 16 | runStmt do 17 | while (i.val .<. 30) do 18 | action do 19 | let writeVal = 1 .<<. i.val 20 | ramA.store i.val writeVal 21 | ramB.store (100 + i.val) (inv writeVal) 22 | i <== i.val + 1 23 | action do 24 | i <== 0 25 | while (i.val .<. 30) do 26 | action do 27 | ramA.load (100 + i.val) 28 | ramB.load i.val 29 | action do 30 | display "ramA[100+" i.val "] = 0x" (formatHex 8 ramA.out) 31 | display "ramB[" i.val "] = 0x" (formatHex 8 ramB.out) 32 | i <== i.val + 1 33 | action do 34 | finish 35 | 36 | return () 37 | 38 | -- Main function 39 | main :: IO () 40 | main = writeVerilogTop top "RAMQuad" "RAMQuad-Verilog/" 41 | -------------------------------------------------------------------------------- /Examples/RAMQuad/RAMQuad.out: -------------------------------------------------------------------------------- 1 | ramA[100+0] = 0xfffffffe 2 | ramB[0] = 0x00000001 3 | ramA[100+1] = 0xfffffffd 4 | ramB[1] = 0x00000002 5 | ramA[100+2] = 0xfffffffb 6 | ramB[2] = 0x00000004 7 | ramA[100+3] = 0xfffffff7 8 | ramB[3] = 0x00000008 9 | ramA[100+4] = 0xffffffef 10 | ramB[4] = 0x00000010 11 | ramA[100+5] = 0xffffffdf 12 | ramB[5] = 0x00000020 13 | ramA[100+6] = 0xffffffbf 14 | ramB[6] = 0x00000040 15 | ramA[100+7] = 0xffffff7f 16 | ramB[7] = 0x00000080 17 | ramA[100+8] = 0xfffffeff 18 | ramB[8] = 0x00000100 19 | ramA[100+9] = 0xfffffdff 20 | ramB[9] = 0x00000200 21 | ramA[100+10] = 0xfffffbff 22 | ramB[10] = 0x00000400 23 | ramA[100+11] = 0xfffff7ff 24 | ramB[11] = 0x00000800 25 | ramA[100+12] = 0xffffefff 26 | ramB[12] = 0x00001000 27 | ramA[100+13] = 0xffffdfff 28 | ramB[13] = 0x00002000 29 | ramA[100+14] = 0xffffbfff 30 | ramB[14] = 0x00004000 31 | ramA[100+15] = 0xffff7fff 32 | ramB[15] = 0x00008000 33 | ramA[100+16] = 0xfffeffff 34 | ramB[16] = 0x00010000 35 | ramA[100+17] = 0xfffdffff 36 | ramB[17] = 0x00020000 37 | ramA[100+18] = 0xfffbffff 38 | ramB[18] = 0x00040000 39 | ramA[100+19] = 0xfff7ffff 40 | ramB[19] = 0x00080000 41 | ramA[100+20] = 0xffefffff 42 | ramB[20] = 0x00100000 43 | ramA[100+21] = 0xffdfffff 44 | ramB[21] = 0x00200000 45 | ramA[100+22] = 0xffbfffff 46 | ramB[22] = 0x00400000 47 | ramA[100+23] = 0xff7fffff 48 | ramB[23] = 0x00800000 49 | ramA[100+24] = 0xfeffffff 50 | ramB[24] = 0x01000000 51 | ramA[100+25] = 0xfdffffff 52 | ramB[25] = 0x02000000 53 | ramA[100+26] = 0xfbffffff 54 | ramB[26] = 0x04000000 55 | ramA[100+27] = 0xf7ffffff 56 | ramB[27] = 0x08000000 57 | ramA[100+28] = 0xefffffff 58 | ramB[28] = 0x10000000 59 | ramA[100+29] = 0xdfffffff 60 | ramB[29] = 0x20000000 61 | -------------------------------------------------------------------------------- /Examples/SizedStack/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = SizedStack.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/SizedStack/SizedStack.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Stmt 3 | import Blarney.Stack 4 | import System.Environment 5 | 6 | -- Test bench 7 | -- ========== 8 | 9 | topLevel :: Module () 10 | topLevel = do 11 | -- Create 256-element stack 12 | stk :: Stack (Bit 8) <- makeSizedStack 4 13 | 14 | -- Sample test sequence 15 | runStmt do 16 | action do 17 | stk.push 1 18 | action do 19 | stk.push 2 20 | display stk.top 21 | action do 22 | stk.push 3 23 | display stk.top 24 | action do 25 | stk.push 4 26 | display stk.top 27 | action do 28 | stk.pop 29 | display stk.top 30 | action do 31 | stk.pop 32 | display stk.top 33 | action do 34 | stk.push 5 35 | stk.pop 36 | display stk.top 37 | action do 38 | stk.pop 39 | display stk.top 40 | action do 41 | display stk.top 42 | action do 43 | display stk.top 44 | finish 45 | 46 | -- Code generation 47 | -- =============== 48 | 49 | main :: IO () 50 | main = do 51 | args <- getArgs 52 | if | "--simulate" `elem` args -> simulate topLevel 53 | | otherwise -> 54 | writeVerilogTop topLevel "SizedStack" "SizedStack-Verilog/" 55 | -------------------------------------------------------------------------------- /Examples/SizedStack/SizedStack.out: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 3 6 | 2 7 | 5 8 | 1 9 | 1 10 | -------------------------------------------------------------------------------- /Examples/Sorter/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Sorter.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Sorter/Sorter.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Vector (Vec, fromList, toList, vectorise) 3 | import System.Environment 4 | 5 | twoSort :: (Bit 8, Bit 8) -> (Bit 8, Bit 8) 6 | twoSort (a, b) = if a .<. b then (a, b) else (b, a) 7 | 8 | {- 9 | top :: Module () 10 | top = do 11 | display "twoSort (1,2) = " (twoSort (1,2)) 12 | display "twoSort (2,1) = " (twoSort (2,1)) 13 | finish 14 | -} 15 | 16 | insert :: Bit 8 -> [Bit 8] -> [Bit 8] 17 | insert x [] = [x] 18 | insert x (y:ys) = small : insert big ys 19 | where (small, big) = twoSort (x, y) 20 | 21 | sort :: [Bit 8] -> [Bit 8] 22 | sort [] = [] 23 | sort (x:xs) = insert x (sort xs) 24 | 25 | top :: Module () 26 | top = always do 27 | let inputs = [3, 4, 1, 0, 2] 28 | display "sort " inputs " = " (sort inputs) 29 | finish 30 | 31 | main :: IO () 32 | main = do 33 | args <- getArgs 34 | if | "--simulate" `elem` args -> simulate top 35 | | otherwise -> writeVerilogTop top "Sorter" "Sorter-Verilog/" 36 | 37 | vecSort :: Vec n (Bit 8) -> Vec n (Bit 8) 38 | vecSort = vectorise sort 39 | 40 | gen :: IO () 41 | gen = writeVerilogModule (vecSort @8) "Sorter8" "Sorter8-Verilog/" 42 | -------------------------------------------------------------------------------- /Examples/Sorter/Sorter.out: -------------------------------------------------------------------------------- 1 | sort [3,4,1,0,2] = [0,1,2,3,4] 2 | -------------------------------------------------------------------------------- /Examples/SourceSink/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = SourceSink.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/SourceSink/SourceSink.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.Queue 3 | import Blarney.Stream 4 | import Blarney.SourceSink 5 | import System.Environment 6 | 7 | -- Top-level module 8 | top :: Module () 9 | top = do 10 | -- counter 11 | count :: Reg (Bit 32) <- makeReg 0 12 | -- queues 13 | q0 :: Queue (Bit 32) <- makeSizedQueue 3 14 | q1 :: Queue (Bit 32) <- makeSizedQueue 3 15 | q2 :: Queue (Bit 32) <- makeSizedQueue 3 16 | -- Sink/Source handles on the queue 17 | let (q0snk, q0src) = (toSink q0, toSource q0) 18 | -- queue as StreamProcessor from Queue itself 19 | let sp1 = toSP q1 20 | -- queue as StreamProcessor from (Sink, Source) pair 21 | let sp2 = toSP (toSink q2, toSource q2) 22 | 23 | -- example composition of stream processors 24 | s1 <- sp1 (toStream q0src) -- turn q0's source into a sink, an pass it to 25 | -- q1's stream processor, and bind the output 26 | -- stream to s1 27 | s2 <- sp2 s1 -- pass s1 to the q2's stream processor and bind 28 | -- the output stream to s2 29 | 30 | -- feed chain of queues 31 | always do 32 | -- chain queues 33 | when (canPut q0snk) do q0snk.put count.val -- put count in q0's sink 34 | let q2src = toSource s2 -- example use of toSource 35 | -- Consume from q2 36 | when (q2src.canPeek .&&. count.val .>. 50) do 37 | q2src.consume 38 | display "Got " q2src.peek 39 | when (q2src.peek .>. 100) finish 40 | count <== count.val + 1 41 | 42 | -- Main function 43 | main :: IO () 44 | main = do 45 | args <- getArgs 46 | if | "--simulate" `elem` args -> simulate top 47 | | otherwise -> do 48 | writeVerilogTop top "SourceSink" "SourceSink-Verilog/" 49 | -------------------------------------------------------------------------------- /Examples/SourceSink/SourceSink.out: -------------------------------------------------------------------------------- 1 | Got 0 2 | Got 1 3 | Got 2 4 | Got 3 5 | Got 4 6 | Got 5 7 | Got 6 8 | Got 7 9 | Got 8 10 | Got 9 11 | Got 10 12 | Got 11 13 | Got 12 14 | Got 13 15 | Got 14 16 | Got 15 17 | Got 16 18 | Got 17 19 | Got 18 20 | Got 19 21 | Got 20 22 | Got 21 23 | Got 22 24 | Got 23 25 | Got 24 26 | Got 25 27 | Got 26 28 | Got 54 29 | Got 55 30 | Got 56 31 | Got 57 32 | Got 58 33 | Got 59 34 | Got 60 35 | Got 61 36 | Got 62 37 | Got 63 38 | Got 64 39 | Got 65 40 | Got 66 41 | Got 67 42 | Got 68 43 | Got 69 44 | Got 70 45 | Got 71 46 | Got 72 47 | Got 73 48 | Got 74 49 | Got 75 50 | Got 76 51 | Got 77 52 | Got 78 53 | Got 79 54 | Got 80 55 | Got 81 56 | Got 82 57 | Got 83 58 | Got 84 59 | Got 85 60 | Got 86 61 | Got 87 62 | Got 88 63 | Got 89 64 | Got 90 65 | Got 91 66 | Got 92 67 | Got 93 68 | Got 94 69 | Got 95 70 | Got 96 71 | Got 97 72 | Got 98 73 | Got 99 74 | Got 100 75 | Got 101 76 | -------------------------------------------------------------------------------- /Examples/Stack/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Stack.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Stack/Stack.out: -------------------------------------------------------------------------------- 1 | 3 2 2 | 4 3 3 | 1 4 4 | 4 3 5 | 4 3 6 | 10 3 7 | 11 10 8 | 2 1 9 | -------------------------------------------------------------------------------- /Examples/StackTesting/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = StackTesting.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/StackTesting/StackTesting.hs: -------------------------------------------------------------------------------- 1 | -- Blarney imports 2 | import Blarney 3 | import Blarney.Queue 4 | import Blarney.Recipe 5 | -- Standard imports 6 | import Data.Proxy 7 | import System.Environment 8 | 9 | -- Stack interface 10 | data Stack a = 11 | Stack { 12 | push :: a -> Action () 13 | , pop :: Action () 14 | , top :: a 15 | , isEmpty :: Bit 1 16 | , clear :: Action () 17 | } 18 | 19 | -- Buggy stack implementation 20 | -- (Parallel push and pop not supported) 21 | makeStack :: Bits a => Int -> Module (Stack a) 22 | makeStack logSize = do 23 | -- Lift size to type-level number 24 | liftNat logSize $ \(_ :: Proxy n) -> do 25 | 26 | -- RAM, wide enough to hold entire stack 27 | ram :: RAM (Bit n) a <- makeDualRAMForward 28 | 29 | -- Stack pointer 30 | sp :: Reg (Bit n) <- makeReg 0 31 | 32 | -- Top stack element 33 | topReg :: Reg a <- makeReg dontCare 34 | 35 | -- Speculative read address 36 | speculateReg :: Reg (Bit n) <- makeReg 0 37 | speculateWire :: Wire (Bit n) <- makeWire (sp.val) 38 | 39 | -- Read top element from RAM 40 | always do 41 | ram.load (speculateWire.active ? (speculateWire.val, speculateReg.val)) 42 | when speculateWire.active do 43 | speculateReg <== speculateWire.val 44 | 45 | return 46 | Stack { 47 | push = \a -> do 48 | topReg <== a 49 | ram.store sp.val topReg.val 50 | speculateWire <== sp.val 51 | sp <== sp.val + 1 52 | , pop = do 53 | topReg <== ram.out 54 | speculateWire <== sp.val - 1 -- BUG: should be sp.val - 2 55 | sp <== sp.val - 1 56 | , top = topReg.val 57 | , isEmpty = sp.val .==. 0 58 | , clear = sp <== 0 59 | } 60 | 61 | -- Stack specification 62 | -- (Parallel push and pop not supported) 63 | makeStackSpec :: Bits a => Int -> Module (Stack a) 64 | makeStackSpec logSize = 65 | -- Lift size to type-level number 66 | liftNat logSize $ \(_ :: Proxy n) -> do 67 | 68 | -- List of register, big enough to hold stack elements 69 | elems :: [Reg a] <- replicateM (2^logSize) (makeReg dontCare) 70 | 71 | -- Size of stack 72 | size :: Reg (Bit n) <- makeReg 0 73 | 74 | return 75 | Stack { 76 | push = \a -> do 77 | head elems <== a 78 | zipWithM_ (<==) (tail elems) (map val elems) 79 | size <== size.val + 1 80 | , pop = do 81 | zipWithM_ (<==) elems (tail (map val elems)) 82 | size <== size.val - 1 83 | , top = (head elems).val 84 | , isEmpty = size.val .==. 0 85 | , clear = size <== 0 86 | } 87 | 88 | -- Top-level module 89 | testBench :: Module () 90 | testBench = do 91 | -- Create 256-element stack 92 | stk :: Stack (Bit 8) <- makeStack 8 93 | 94 | -- Sample test sequence 95 | let test = 96 | Seq [ 97 | Action do 98 | push stk 1 99 | , Action do 100 | push stk 2 101 | , Action do 102 | push stk 3 103 | , Action do 104 | pop stk 105 | , Action do 106 | pop stk 107 | , Action do 108 | display (stk.top) 109 | finish 110 | ] 111 | 112 | runOnce test 113 | 114 | -- Main function 115 | main :: IO () 116 | main = do 117 | args <- getArgs 118 | if | "--simulate" `elem` args -> simulate testBench 119 | | otherwise -> writeVerilogTop testBench "StackTesting" "StackTesting-Verilog/" 120 | -------------------------------------------------------------------------------- /Examples/Vectors/Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath ../../) 2 | 3 | SRCS = Vectors.hs 4 | 5 | include $(BLARNEY_ROOT)/Examples/blarneyTest.mk 6 | -------------------------------------------------------------------------------- /Examples/Vectors/Vectors.hs: -------------------------------------------------------------------------------- 1 | import Blarney 2 | import Blarney.SourceSink 3 | import Blarney.Vector hiding (elem) 4 | import System.Environment 5 | 6 | makeElement :: KnownNat n => Integer -> Module (Source (Bit n)) 7 | makeElement i = do 8 | reg :: Reg (Bit n) <- makeReg $ fromInteger i 9 | let src :: Source (Bit n) = Source { canPeek = true 10 | , peek = reg.val 11 | , consume = reg <== reg.val + 1 12 | } 13 | return $ debugSource src (fshow $ "src"++show i) 14 | 15 | testVecModule :: Module (Vec 4 (Source (Bit 3))) 16 | testVecModule = genWithM makeElement 17 | 18 | testVecReg :: Module (Vec 4 (Reg (Bit 3))) 19 | testVecReg = genWithM (makeReg . fromInteger) 20 | 21 | top :: Module () 22 | top = do 23 | -- check zipAny type errors 24 | let a :: Vec 4 () = newVec 25 | let b :: Vec 5 () = newVec 26 | let c :: Vec 6 () = newVec 27 | let x :: Vec 4 _ = zipWithAny3 (\x y z -> ()) a b c 28 | -- check instance of Vector of Sources 29 | cycleCount :: Reg (Bit 4) <- makeReg 0 30 | srcs <- testVecModule 31 | always do 32 | -- increment cycle count 33 | cycleCount <== cycleCount.val + 1 34 | -- consume from each source on each cycle 35 | forM_ [0..3] \(i :: Int) -> do 36 | (srcs ! i).consume 37 | -- terminate simulation when count reaches 10 38 | when (cycleCount.val .==. 10) do 39 | display "Finished" 40 | finish 41 | 42 | main :: IO () 43 | main = do 44 | args <- getArgs 45 | if | "--simulate" `elem` args -> simulate top 46 | | otherwise -> do 47 | writeVerilogModule testVecModule "testVecModule" "Vectors-Verilog/" 48 | writeVerilogModule testVecReg "testVecReg" "Vectors-Verilog/" 49 | writeVerilogTop top "Vectors" "Vectors-Verilog/" 50 | -------------------------------------------------------------------------------- /Examples/Vectors/Vectors.out: -------------------------------------------------------------------------------- 1 | src0 - Source consume - canPeek: 1 - 0 2 | src1 - Source consume - canPeek: 1 - 1 3 | src2 - Source consume - canPeek: 1 - 2 4 | src3 - Source consume - canPeek: 1 - 3 5 | src0 - Source consume - canPeek: 1 - 1 6 | src1 - Source consume - canPeek: 1 - 2 7 | src2 - Source consume - canPeek: 1 - 3 8 | src3 - Source consume - canPeek: 1 - 4 9 | src0 - Source consume - canPeek: 1 - 2 10 | src1 - Source consume - canPeek: 1 - 3 11 | src2 - Source consume - canPeek: 1 - 4 12 | src3 - Source consume - canPeek: 1 - 5 13 | src0 - Source consume - canPeek: 1 - 3 14 | src1 - Source consume - canPeek: 1 - 4 15 | src2 - Source consume - canPeek: 1 - 5 16 | src3 - Source consume - canPeek: 1 - 6 17 | src0 - Source consume - canPeek: 1 - 4 18 | src1 - Source consume - canPeek: 1 - 5 19 | src2 - Source consume - canPeek: 1 - 6 20 | src3 - Source consume - canPeek: 1 - 7 21 | src0 - Source consume - canPeek: 1 - 5 22 | src1 - Source consume - canPeek: 1 - 6 23 | src2 - Source consume - canPeek: 1 - 7 24 | src3 - Source consume - canPeek: 1 - 0 25 | src0 - Source consume - canPeek: 1 - 6 26 | src1 - Source consume - canPeek: 1 - 7 27 | src2 - Source consume - canPeek: 1 - 0 28 | src3 - Source consume - canPeek: 1 - 1 29 | src0 - Source consume - canPeek: 1 - 7 30 | src1 - Source consume - canPeek: 1 - 0 31 | src2 - Source consume - canPeek: 1 - 1 32 | src3 - Source consume - canPeek: 1 - 2 33 | src0 - Source consume - canPeek: 1 - 0 34 | src1 - Source consume - canPeek: 1 - 1 35 | src2 - Source consume - canPeek: 1 - 2 36 | src3 - Source consume - canPeek: 1 - 3 37 | src0 - Source consume - canPeek: 1 - 1 38 | src1 - Source consume - canPeek: 1 - 2 39 | src2 - Source consume - canPeek: 1 - 3 40 | src3 - Source consume - canPeek: 1 - 4 41 | src0 - Source consume - canPeek: 1 - 2 42 | src1 - Source consume - canPeek: 1 - 3 43 | src2 - Source consume - canPeek: 1 - 4 44 | src3 - Source consume - canPeek: 1 - 5 45 | Finished 46 | -------------------------------------------------------------------------------- /Examples/blarneyTest.mk: -------------------------------------------------------------------------------- 1 | ifndef BLARNEY_ROOT 2 | $(error "the BLARNEY_ROOT environment variable must be set") 3 | endif 4 | 5 | include $(BLARNEY_ROOT)/blarneyDirs.mk 6 | 7 | BLC = $(BLARNEY_ROOT)/Scripts/blc 8 | GENS = $(basename $(SRCS)) 9 | 10 | all: $(GENS) 11 | 12 | %-test-verilog: %-Verilog 13 | make -C $*-Verilog/ 14 | $*-Verilog/$* 15 | 16 | %-test-simulation: % 17 | ./$< --simulate 18 | 19 | %: %.hs 20 | BLARNEY_ROOT=$(BLARNEY_ROOT) $(BLC) -O --make -hidir $(HI_DIR) -odir $(O_DIR) $(BLC_FLAGS) $< 21 | 22 | .SECONDARY: $(addsuffix -Verilog, $(GEN)) 23 | %-Verilog: % 24 | ./$< --verilog 25 | 26 | .PHONY: clean mrproper 27 | clean: 28 | rm -rf $(GENS) *-Verilog *-SMT 29 | 30 | mrproper: clean 31 | rm -rf $(BUILD_DIR) 32 | -------------------------------------------------------------------------------- /Haskell/Blarney.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney 3 | Description : Hardware description in Haskell 4 | Copyright : (c) Matthew Naylor, 2019 5 | (c) Alexandre Joannou, 2019-2021 6 | License : MIT 7 | Maintainer : mattfn@gmail.com 8 | Stability : experimental 9 | 10 | This is the top-level of the Blarney library. It essentially exports a set of 11 | other Blarney modules. Note that it also re-exports the Haskell 'Prelude'. 12 | -} 13 | 14 | module Blarney ( 15 | -- * Exported Blarney modules 16 | module Blarney.Core 17 | , module Blarney.Netlist 18 | , module Blarney.Backend 19 | -- * Re-exported Haskell modules 20 | , module Blarney.Prelude 21 | ) where 22 | 23 | import Blarney.Core 24 | import Blarney.Netlist 25 | import Blarney.Backend 26 | import Blarney.Prelude 27 | -------------------------------------------------------------------------------- /Haskell/Blarney/BitPat.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | {-# LANGUAGE DataKinds #-} 3 | {-# LANGUAGE TypeOperators #-} 4 | 5 | {-| 6 | Module : Blarney.BitPat 7 | Description : Bit-string pattern matching combinators 8 | Copyright : (c) Matthew Naylor, 2019 9 | License : MIT 10 | Maintainer : mattfn@gmail.com 11 | Stability : experimental 12 | 13 | Inspired by Morten Rhiger's "Type-Safe Pattern Combinators". 14 | -} 15 | module Blarney.BitPat 16 | ( BP -- Bit patterns 17 | , literal -- Literal pattern 18 | , variable -- Variable pattern 19 | , (<#>) -- Sequential composition of patterns 20 | , (==>) -- Case alternative 21 | , match -- Match case subject against set of a case alternatives 22 | ) where 23 | 24 | import Blarney 25 | 26 | -- |Continuation combinators 27 | success k = (1, k) 28 | failure k = (0, k) 29 | one v k = (1, k v) 30 | app m n k = (b0 .&. b1, k1) 31 | where 32 | (b0, k0) = m k 33 | (b1, k1) = n k0 34 | 35 | -- |Bit pattern 36 | type BP n t0 t1 = Bit n -> t0 -> (Bit 1, t1) 37 | 38 | -- |Bit pattern to match literal 39 | literal :: forall n t. KnownNat n => Bit n -> BP n t t 40 | literal a = \b k -> (a .==. b, k) 41 | 42 | -- |Bit pattern to bind a variable 43 | variable :: forall n t. BP n (Bit n -> t) t 44 | variable = one 45 | 46 | -- |Sequentially combine bit patterns 47 | infixl 9 <#> 48 | (<#>) :: KnownNat n0 => BP n0 t0 t1 -> BP n1 t1 t2 -> BP (n0+n1) t0 t2 49 | p0 <#> p1 = \n -> 50 | let (upper, lower) = split n in app (p0 upper) (p1 lower) 51 | 52 | -- |A case alternative (pattern plus a right-hand-side) 53 | infix 7 ==> 54 | (==>) :: BP n t (Action ()) -> t -> Bit n -> Action () 55 | p ==> rhs = \sub -> let (b, act) = p sub rhs in when b act 56 | 57 | -- |Match case subject against set of a case alternatives 58 | match :: Bit n -> [Bit n -> Action ()] -> Action () 59 | match sub alts = sequence_ [ alt sub | alt <- alts ] 60 | -------------------------------------------------------------------------------- /Haskell/Blarney/ClientServer.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE MultiParamTypeClasses #-} 2 | {-# LANGUAGE FlexibleInstances #-} 3 | {-# LANGUAGE FunctionalDependencies #-} 4 | {-# LANGUAGE BlockArguments #-} 5 | {-# LANGUAGE DataKinds #-} 6 | {-# LANGUAGE NoImplicitPrelude #-} 7 | {-# LANGUAGE DeriveGeneric #-} 8 | {-# LANGUAGE DeriveAnyClass #-} 9 | {-# LANGUAGE OverloadedRecordDot #-} 10 | {-# LANGUAGE DuplicateRecordFields #-} 11 | 12 | {-| 13 | Module : Blarney.ClientServer 14 | Description : Client and Server interfaces for control flow 15 | Copyright : (c) Matthew Naylor 2021, Alexandre Joannou 2021 16 | License : MIT 17 | Maintainer : mattfn@gmail.com 18 | Stability : experimental 19 | 20 | This module defines the 'Client' and 'Server' types. 21 | 22 | -} 23 | module Blarney.ClientServer where 24 | 25 | -- Standard imports 26 | import GHC.Generics 27 | import Control.Monad hiding (when) 28 | 29 | -- Blarney imports 30 | import Blarney 31 | import Blarney.SourceSink 32 | import Blarney.Connectable 33 | 34 | -- Interfaces 35 | -- ========== 36 | 37 | -- | Clients produce requests and consume responses 38 | data Client req_t resp_t = 39 | Client { 40 | reqs :: Source req_t 41 | , resps :: Sink resp_t 42 | } deriving (Generic, Interface) 43 | 44 | -- | Servers consume requests and produce responses 45 | data Server req_t resp_t = 46 | Server { 47 | reqs :: Sink req_t 48 | , resps :: Source resp_t 49 | } deriving (Generic, Interface) 50 | 51 | -- Instances 52 | -- ========= 53 | 54 | instance Connectable (Client req_t resp_t) (Server req_t resp_t) where 55 | makeConnection c s = do 56 | makeConnection c.reqs s.reqs 57 | makeConnection s.resps c.resps 58 | 59 | -- Helpers 60 | -- ======= 61 | 62 | -- | Add debug displays to client's source and sink 63 | debugClient :: (FShow req_t, FShow resp_t) => 64 | Client req_t resp_t -> Format -> Client req_t resp_t 65 | debugClient c msg = 66 | Client { 67 | reqs = debugSource c.reqs msg 68 | , resps = debugSink c.resps msg 69 | } 70 | 71 | -- | Add debug displays to servers's source and sink 72 | debugServer :: (FShow req_t, FShow resp_t) => 73 | Server req_t resp_t -> Format -> Server req_t resp_t 74 | debugServer s msg = 75 | Server { 76 | reqs = debugSink s.reqs msg 77 | , resps = debugSource s.resps msg 78 | } 79 | 80 | -- | Server that ignores all requests and generates no responses 81 | nullServer :: Bits resp_t => Server req_t resp_t 82 | nullServer = Server { reqs = nullSink, resps = nullSource } 83 | 84 | -- | Client that ignores all responses and generates no requests 85 | nullClient :: Bits req_t => Client req_t resp_t 86 | nullClient = Client { reqs = nullSource, resps = nullSink } 87 | -------------------------------------------------------------------------------- /Haskell/Blarney/Connectable.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE MultiParamTypeClasses #-} 2 | {-# LANGUAGE FlexibleInstances #-} 3 | 4 | {-| 5 | Module : Blarney.Connectable 6 | Description : Module to connect interfaces 7 | Copyright : (c) Alexandre Joannou, 2019 8 | License : MIT 9 | Maintainer : alexandre.joannou@gmail.com 10 | Stability : experimental 11 | 12 | The 'Connectable' class provides a standard way to connect hardware modules 13 | -} 14 | module Blarney.Connectable 15 | ( -- * Connectable class 16 | Connectable(..) 17 | ) where 18 | 19 | -- Blarney import 20 | import Blarney 21 | 22 | -- | 'Connectable' class 23 | class Connectable a b where 24 | -- | Connects two interfaces that can be connected 25 | makeConnection :: a -- ^ First interface to connect 26 | -> b -- ^ Second interface to connect 27 | -> Module () -- ^ 'Module' with no interface, implementing the 28 | -- connection 29 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : Blarney.Core 3 | Description : Core module for the blarney hardware description library 4 | Copyright : (c) Matthew Naylor, 2019 5 | (c) Alexandre Joannou, 2019-2021 6 | License : MIT 7 | Maintainer : mattfn@gmail.com 8 | Stability : experimental 9 | 10 | This module re-exports some Blarney internals. It should not be imported 11 | directly, but the 'Blarney' module which re-exports it should be imported 12 | instead. 13 | 14 | -} 15 | module Blarney.Core ( 16 | module Blarney.Core.Bit 17 | , module Blarney.Core.RAM 18 | , module Blarney.Core.Bits 19 | , module Blarney.Core.Utils 20 | , module Blarney.Core.FShow 21 | , module Blarney.Core.Module 22 | , module Blarney.Core.Lookup 23 | , module Blarney.Core.Common 24 | , module Blarney.Core.Interface 25 | , module Blarney.Core.IfThenElse 26 | , module Blarney.Core.ClockReset 27 | ) where 28 | 29 | import Blarney.Core.Bit 30 | import Blarney.Core.Bits 31 | import Blarney.Core.RAM 32 | import Blarney.Core.Utils 33 | import Blarney.Core.FShow 34 | import Blarney.Core.Module 35 | import Blarney.Core.Lookup 36 | import Blarney.Core.Common 37 | import Blarney.Core.Interface 38 | import Blarney.Core.IfThenElse 39 | import Blarney.Core.ClockReset 40 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/Bits.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DefaultSignatures #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE TypeOperators #-} 4 | {-# LANGUAGE FlexibleContexts #-} 5 | {-# LANGUAGE DataKinds #-} 6 | {-# LANGUAGE KindSignatures #-} 7 | {-# LANGUAGE TypeOperators #-} 8 | {-# LANGUAGE TypeFamilies #-} 9 | {-# LANGUAGE UndecidableInstances #-} 10 | {-# LANGUAGE FlexibleContexts #-} 11 | {-# LANGUAGE ConstraintKinds #-} 12 | {-# LANGUAGE PartialTypeSignatures #-} 13 | 14 | {-| 15 | Module : Blarney.Core.Bits 16 | Description : Convert types to bit vectors and back 17 | Copyright : (c) Matthew Naylor, 2019 18 | (c) Alexandre Joannou, 2019 19 | License : MIT 20 | Maintainer : mattfn@gmail.com 21 | Stability : experimental 22 | 23 | Any type in the 'Bits' class can be represented in hardware at runtime. 24 | For example, values of a type in the 'Bits' class can be stored in a 25 | register, or carried along a wire. The 'Bits' class supports generic 26 | deriving. 27 | -} 28 | module Blarney.Core.Bits where 29 | 30 | -- Typed bit vectors 31 | import Blarney.Core.Bit 32 | 33 | -- Standard imports 34 | import Prelude 35 | import GHC.TypeLits 36 | import GHC.Generics 37 | 38 | class Bits a where 39 | -- |Type-level size of bit-vector 40 | type SizeOf a :: Nat 41 | -- |Value-level size of bit-vector 42 | sizeOf :: a -> Int 43 | -- |Convert to a bit-vector 44 | pack :: a -> Bit (SizeOf a) 45 | -- |Convert from a bit-vector 46 | unpack :: Bit (SizeOf a) -> a 47 | -- |Name a 'Bits' 48 | nameBits :: String -> a -> a 49 | 50 | -- Defaults 51 | type SizeOf a = GSizeOf (Rep a) 52 | default sizeOf :: (Generic a, GBits (Rep a), 53 | GSizeOf (Rep a) ~ SizeOf a) 54 | => a -> Int 55 | sizeOf x = gsizeOf (from x) 56 | default pack :: (Generic a, GBits (Rep a), 57 | GSizeOf (Rep a) ~ SizeOf a) 58 | => a -> Bit (SizeOf a) 59 | pack x = gpack (from x) 60 | default unpack :: (Generic a, GBits (Rep a), 61 | GSizeOf (Rep a) ~ SizeOf a) 62 | => Bit (SizeOf a) -> a 63 | unpack x = to (gunpack x) 64 | default nameBits :: (Generic a, GBits (Rep a), 65 | GSizeOf (Rep a) ~ SizeOf a) 66 | => String -> a -> a 67 | nameBits nm x = to (gnameBits nm (from x)) 68 | 69 | -- Generic deriving for Bits 70 | -- ========================= 71 | 72 | class GBits f where 73 | type GSizeOf f :: Nat 74 | gsizeOf :: f a -> Int 75 | gpack :: f a -> Bit (GSizeOf f) 76 | gunpack :: Bit (GSizeOf f) -> f a 77 | gnameBits :: String -> f a -> f a 78 | 79 | instance GBits U1 where 80 | type GSizeOf U1 = 0 81 | gsizeOf ~U1 = 0 82 | gpack ~U1 = 0 83 | gunpack bs = U1 84 | gnameBits nm ~U1 = U1 85 | 86 | instance (GBits a, GBits b) => GBits (a :*: b) where 87 | type GSizeOf (a :*: b) = GSizeOf a + GSizeOf b 88 | gsizeOf ~(a :*: b) = gsizeOf a + gsizeOf b 89 | gpack ~(a :*: b) = gpack a # gpack b 90 | gunpack bs = a :*: b 91 | where 92 | a = gunpack (unsafeSlice (wa+wb-1, wb) bs) 93 | b = gunpack (unsafeSlice (wb-1, 0) bs) 94 | wa = gsizeOf a 95 | wb = gsizeOf b 96 | gnameBits nm ~(a :*: b) = (gnameBits nm a) :*: (gnameBits nm b) 97 | 98 | instance GBits a => GBits (M1 i c a) where 99 | type GSizeOf (M1 i c a) = GSizeOf a 100 | gpack ~(M1 x) = gpack x 101 | gsizeOf ~(M1 x) = gsizeOf x 102 | gunpack x = M1 (gunpack x) 103 | gnameBits nm ~(M1 x) = M1 (gnameBits nm x) -- TODO here pass field name ? 104 | 105 | instance Bits a => GBits (K1 i a) where 106 | type GSizeOf (K1 i a) = SizeOf a 107 | gsizeOf ~(K1 x) = sizeOf x 108 | gpack ~(K1 x) = pack x 109 | gunpack x = K1 (unpack x) 110 | gnameBits nm ~(K1 x) = K1 (nameBits nm x) 111 | 112 | -- Standard instances 113 | -- ================== 114 | 115 | instance KnownNat n => Bits (Bit n) where 116 | type SizeOf (Bit n) = n 117 | sizeOf = widthOf 118 | pack = id 119 | unpack = id 120 | nameBits = nameBit 121 | 122 | instance KnownNat n => Bits (Signed n) where 123 | type SizeOf (Signed n) = n 124 | sizeOf x = widthOf (fromSigned x) 125 | pack x = fromSigned x 126 | unpack x = toSigned x 127 | nameBits s x = toSigned $ nameBit s $ fromSigned x 128 | 129 | instance Bits () 130 | 131 | instance (Bits a, Bits b) => Bits (a, b) 132 | 133 | instance (Bits a, Bits b, Bits c) => Bits (a, b, c) 134 | 135 | instance (Bits a, Bits b, Bits c, Bits d) => Bits (a, b, c, d) 136 | 137 | instance (Bits a, Bits b, Bits c, Bits d, Bits e) => Bits (a, b, c, d, e) 138 | 139 | instance (Bits a, Bits b, Bits c, Bits d, 140 | Bits e, Bits f) => Bits (a, b, c, d, e, f) 141 | 142 | instance (Bits a, Bits b, Bits c, Bits d, 143 | Bits e, Bits f, Bits g) => Bits (a, b, c, d, e, f, g) 144 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/ClockReset.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE TypeOperators #-} 4 | 5 | {-| 6 | Module : Blarney.Core.ClockReset 7 | Description : Types for clocks and resets 8 | Copyright : (c) Matthew Naylor, 2021 9 | License : MIT 10 | Maintainer : mattfn@gmail.com 11 | Stability : experimental 12 | -} 13 | module Blarney.Core.ClockReset where 14 | 15 | -- Standard imports 16 | import Prelude 17 | import GHC.Generics 18 | 19 | -- Blarney imports 20 | import Blarney.Core.Bit 21 | 22 | newtype Clock = Clock (Bit 1) deriving Generic 23 | 24 | newtype Reset = Reset (Bit 1) deriving Generic 25 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/Flatten.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BlockArguments #-} 2 | {-# LANGUAGE RecordWildCards #-} 3 | {-# LANGUAGE PatternSynonyms #-} 4 | {-# LANGUAGE FlexibleInstances #-} 5 | {-# LANGUAGE ScopedTypeVariables #-} 6 | {-# LANGUAGE MultiParamTypeClasses #-} 7 | 8 | {-| 9 | Module : Blarney.Flatten 10 | Description : Flatten BV into Net 11 | Copyright : (c) Matthew Naylor, 2019 12 | (c) Alexandre Joannou, 2019-2021 13 | License : MIT 14 | Maintainer : mattfn@gmail.com 15 | Stability : experimental 16 | -} 17 | 18 | module Blarney.Core.Flatten ( 19 | ToNetlist(..) -- re-export the ToNetlist class 20 | ) where 21 | 22 | import Prelude 23 | import Data.IntSet 24 | import Data.Array.ST 25 | import Control.Monad 26 | import qualified Data.Set 27 | import Data.Array.Unboxed 28 | import Control.Monad.Trans 29 | import Data.Functor.Identity 30 | import Control.Monad.Trans.State 31 | import Control.Monad.Trans.Writer 32 | 33 | import Blarney.Core.BV 34 | import Blarney.Core.Prim 35 | import Blarney.Core.NetHelpers 36 | import Blarney.Core.Module (Module(..)) 37 | import qualified Blarney.Core.RTL as RTL 38 | import qualified Blarney.Core.JList as JL 39 | 40 | -- | A state/writer monad for accumulating the netlist 41 | type Flatten = StateT FlattenS (WriterT FlattenW Identity) 42 | 43 | -- | The state component contains the set of visited nodes 44 | type FlattenS = IntSet 45 | 46 | -- | The writer component contains the accumulated netlist and name hints 47 | type FlattenW = (JL.JList Net, JL.JList (InstId, NameHints)) 48 | 49 | -- | run the 'Flatten' monad and return a tuple with the final state, the final 50 | -- writer accumulator and a return value 51 | execFlatten :: Flatten a -> FlattenS -> (FlattenS, FlattenW, a) 52 | execFlatten m s0 = (s, w, x) 53 | where f = runIdentity . runWriterT . (flip runStateT) s0 54 | ((x, s), w) = f m 55 | 56 | -- | Get the set of visited nodes 57 | getVisited :: Flatten FlattenS 58 | getVisited = get 59 | 60 | -- | set the set of visited nodes 61 | putVisited :: FlattenS -> Flatten () 62 | putVisited = put 63 | 64 | -- | Add a net to the netlist 65 | addNet :: Net -> Flatten () 66 | addNet net = lift $ tell (JL.One net, mempty) 67 | 68 | -- | Add name hints to the list 69 | addNameHints :: (InstId, NameHints) -> Flatten () 70 | addNameHints hints = lift $ tell (mempty, JL.One hints) 71 | 72 | -- | Flatten a root 'BV' to a netlist 73 | flatten :: BV -> Flatten NetInput 74 | flatten BV{bvPrim=p@(Const w v)} = return $ InputTree p [] 75 | flatten BV{bvPrim=p@(DontCare w)} = return $ InputTree p [] 76 | flatten BV{..} = do 77 | 78 | -- handle potential new name hints. TODO can we do this on first visit only? 79 | when (not $ Data.Set.null bvNameHints) $ addNameHints (bvInstId, bvNameHints) 80 | 81 | -- retrieve the set of visited nodes from the state 82 | visited <- getVisited 83 | 84 | -- Upon first visit of the current 'BV' 85 | when (not $ bvInstId `member` visited) do 86 | -- add current 'BV' to the set of visited nodes 87 | putVisited $ insert bvInstId visited 88 | -- recursively explore curent 'BV' 's inputs and generate and add a new 89 | -- 'Net' to the accumulation netlist 90 | ins <- mapM flatten bvInputs 91 | addNet Net { netPrim = bvPrim 92 | , netInstId = bvInstId 93 | , netInputs = ins 94 | , netNameHints = mempty } 95 | 96 | -- return a handle to the visited 'Net' 97 | return $ InputWire (bvInstId, bvOutput) 98 | 99 | -- | Convert RTL monad to a netlist 100 | instance ToNetlist (RTL.RTL ()) where 101 | toNetlist rtl = runSTArray do 102 | mnl <- newListArray (0, length nl - 1) 103 | [remapNetInstId (mapping !) n | n <- nl] 104 | -- update netlist with gathered names 105 | forM_ (JL.toList nms) $ \(idx, hints) -> do 106 | let idx' = mapping ! idx 107 | net@Net{ netNameHints = oldHints } <- readArray mnl (idx') 108 | writeArray mnl idx' net{ netNameHints = oldHints <> hints } 109 | -- return final netlist 110 | return mnl 111 | ------------------------ 112 | where 113 | -- flatten BVs into a Netlist 114 | (visited, (jlnl, nms), _) = execFlatten flattenRoots empty 115 | nl = JL.toList jlnl 116 | -- for remapping instance ids to a compact range starting from 0 117 | minInstId = findMin visited 118 | maxInstId = findMax visited 119 | mapping :: UArray InstId InstId = array (minInstId, maxInstId) 120 | (zip (fmap netInstId nl) [0..]) 121 | flattenRoots = mapM flatten $ RTL.evalRTLRoots rtl 122 | 123 | -- | Convert Module monad to a netlist 124 | instance ToNetlist (Module ()) where 125 | toNetlist = toNetlist . runModule 126 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/IfThenElse.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RebindableSyntax #-} 2 | {-# LANGUAGE NoImplicitPrelude #-} 3 | {-# LANGUAGE FlexibleInstances #-} 4 | {-# LANGUAGE ImportQualifiedPost #-} 5 | {-# LANGUAGE MultiParamTypeClasses #-} 6 | 7 | {-| 8 | Module : Blarney.Core.IfThenElse 9 | Description : Overloaded if-then-else and when conditionals 10 | Copyright : (c) Matthew Naylor, 2019, 2021 11 | (c) Alexandre Joannou, 2019 12 | License : MIT 13 | Maintainer : mattfn@gmail.com 14 | Stability : experimental 15 | -} 16 | module Blarney.Core.IfThenElse where 17 | 18 | import Prelude 19 | import Control.Monad qualified as M 20 | 21 | -- | Overloaded if-then-else 22 | class IfThenElse b a where 23 | ifThenElse :: b -> a -> a -> a 24 | 25 | instance IfThenElse Bool a where 26 | ifThenElse False a b = b 27 | ifThenElse True a b = a 28 | 29 | -- | If-then-else chain, with fallthrough case 30 | priorityIf :: IfThenElse cond ret => [(cond, ret)] -> ret -> ret 31 | priorityIf [] ft = ft 32 | priorityIf ((a, b):rest) ft = 33 | if a then b else priorityIf rest ft 34 | 35 | -- | Overloaded conditionals without an else part 36 | class When cond act where 37 | when :: cond -> act () -> act () 38 | 39 | instance Applicative app => When Bool app where 40 | when cond body = M.when cond body 41 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/JList.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : Blarney.Core.JList 3 | Description : Join lists 4 | Copyright : (c) Matthew Naylor, 2019 5 | (c) Alexandre Joannou, 2019 6 | License : MIT 7 | Maintainer : mattfn@gmail.com 8 | Stability : experimental 9 | 10 | A small library for join-lists, providing constant-time append. 11 | -} 12 | module Blarney.Core.JList 13 | ( JList(..) -- data JList a = Zero | One a | JList a :+: JList a 14 | , fromList -- :: [a] -> Jlist a 15 | , toList -- :: JList a -> [a] 16 | , map -- :: (a -> b) -> JList a -> JList b 17 | , mapM -- :: Monad m => (a -> m b) -> JList a -> m (JList b) 18 | , concat -- :: JList (JList a) -> JList a 19 | , zipWith -- :: (a -> b -> c) -> JList a -> JList b -> JList c 20 | , lazyZipWith -- :: (a -> b -> c) -> JList a -> JList b -> JList c 21 | , (++) -- :: JList a -> JList a -> JList a 22 | ) where 23 | 24 | import Prelude hiding (map, mapM, concat, zipWith, (++)) 25 | import Control.Monad hiding (mapM) 26 | 27 | data JList a = Zero | One a | JList a :+: JList a 28 | deriving (Show, Eq) 29 | 30 | fromList :: [a] -> JList a 31 | fromList as = foldr (:+:) Zero [One a | a <- as] 32 | 33 | toList :: JList a -> [a] 34 | toList a = flatten a [] 35 | where 36 | flatten Zero rest = rest 37 | flatten (One a) rest = a:rest 38 | flatten (a :+: b) rest = flatten a (flatten b rest) 39 | 40 | instance Semigroup (JList a) where 41 | (<>) = (++) 42 | 43 | instance Monoid (JList a) where 44 | mempty = Zero 45 | 46 | instance Functor JList where 47 | fmap f Zero = Zero 48 | fmap f (One a) = One (f a) 49 | fmap f (as :+: bs) = fmap f as :+: fmap f bs 50 | 51 | instance Monad JList where 52 | return = pure 53 | Zero >>= f = Zero 54 | One a >>= f = f a 55 | (as :+: bs) >>= f = (as >>= f) :+: (bs >>= f) 56 | 57 | instance Applicative JList where 58 | pure a = One a 59 | (<*>) = ap 60 | 61 | map :: (a -> b) -> JList a -> JList b 62 | map = fmap 63 | 64 | mapM :: Monad m => (a -> m b) -> JList a -> m (JList b) 65 | mapM f Zero = return Zero 66 | mapM f (One a) = liftM One (f a) 67 | mapM f (as :+: bs) = liftM2 (:+:) (mapM f as) (mapM f bs) 68 | 69 | concat :: JList (JList a) -> JList a 70 | concat Zero = Zero 71 | concat (One as) = as 72 | concat (as :+: bs) = concat as :+: concat bs 73 | 74 | zipWith :: (a -> b -> c) -> JList a -> JList b -> JList c 75 | zipWith f Zero Zero = Zero 76 | zipWith f (One a) (One b) = One (f a b) 77 | zipWith f (a0 :+: a1) (b0 :+: b1) = zipWith f a0 b0 :+: zipWith f a1 b1 78 | zipWith f _ _ = error "JList.zipWith: incompatible structures" 79 | 80 | lazyZipWith :: (a -> b -> c) -> JList a -> JList b -> JList c 81 | lazyZipWith f Zero x = Zero 82 | lazyZipWith f (One a) x = let One b = x in One (f a b) 83 | lazyZipWith f (a0 :+: a1) x = 84 | let b0 :+: b1 = x in lazyZipWith f a0 b0 :+: lazyZipWith f a1 b1 85 | 86 | (++) :: JList a -> JList a -> JList a 87 | Zero ++ ys = ys 88 | xs ++ Zero = xs 89 | xs ++ ys = xs :+: ys 90 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/Lookup.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BlockArguments #-} 2 | {-# LANGUAGE DefaultSignatures #-} 3 | {-# LANGUAGE DeriveGeneric #-} 4 | {-# LANGUAGE TypeOperators #-} 5 | {-# LANGUAGE FlexibleContexts #-} 6 | {-# LANGUAGE DataKinds #-} 7 | {-# LANGUAGE KindSignatures #-} 8 | {-# LANGUAGE TypeOperators #-} 9 | {-# LANGUAGE TypeFamilies #-} 10 | {-# LANGUAGE UndecidableInstances #-} 11 | {-# LANGUAGE FlexibleContexts #-} 12 | {-# LANGUAGE FlexibleInstances #-} 13 | {-# LANGUAGE ConstraintKinds #-} 14 | {-# LANGUAGE ScopedTypeVariables #-} 15 | {-# LANGUAGE MultiParamTypeClasses #-} 16 | {-# LANGUAGE FunctionalDependencies #-} 17 | 18 | {-| 19 | Module : Blarney.Core.Lookup 20 | Description : Provide a generic lookup operator 21 | Copyright : (c) Matthew Naylor, 2019 22 | License : MIT 23 | Maintainer : mattfn@gmail.com 24 | Stability : experimental 25 | 26 | -} 27 | module Blarney.Core.Lookup 28 | ( Lookup(..) 29 | ) where 30 | 31 | -- Standard imports 32 | import Prelude 33 | import GHC.TypeLits 34 | import GHC.Generics 35 | import Control.Monad.Fix 36 | import Control.Monad hiding (when) 37 | import Data.List (transpose) 38 | 39 | -- Blarney imports 40 | import Blarney.Core.BV 41 | import Blarney.Core.Bit 42 | import Blarney.Core.Bits 43 | import Blarney.Core.Prim 44 | import Blarney.Core.Module 45 | import Blarney.Core.Common 46 | import Blarney.Core.Interface 47 | 48 | -- |Index a collection 'c' of elements 'e' using index 'i' 49 | class Lookup c i e | c -> e where 50 | (!) :: c -> i -> e 51 | 52 | infixl 8 ! 53 | 54 | -- |Index a list using a bit vector 55 | instance (Interface a, KnownNat n) => Lookup [a] (Bit n) a where 56 | (!) = lookupInterface 57 | 58 | -- |Index a list using a one-hot bit list 59 | instance Interface a => Lookup [a] OneHotList a where 60 | (!) = lookupInterfaceOneHot 61 | 62 | -- |Index a list using an 'Int' 63 | instance Lookup [a] Int a where 64 | rs ! i = rs !! i 65 | 66 | -- |Index a list using an 'Integer' 67 | instance Lookup [a] Integer a where 68 | rs ! i = rs !! fromIntegral i 69 | 70 | -- |Index a register file 71 | instance Lookup (RegFile a d) a d where 72 | rf ! i = index rf i 73 | 74 | -- |Index a bit vector using a bit vector 75 | instance KnownNat m => Lookup (Bit n) (Bit m) (Bit 1) where 76 | b ! i = unsafeToBitList b ! i 77 | 78 | -- |Index a bit vector using a one-hot bit list 79 | instance Lookup (Bit n) OneHotList (Bit 1) where 80 | b ! i = unsafeToBitList b ! i 81 | 82 | -- |Index a bit vector using an Int 83 | instance Lookup (Bit n) Int (Bit 1) where 84 | b ! i = unsafeToBitList b ! i 85 | 86 | -- |Index a bit vector using an Integer 87 | instance Lookup (Bit n) Integer (Bit 1) where 88 | b ! i = unsafeToBitList b ! i 89 | 90 | -- |Index a list of interfaces using binary-encoded bit-vector 91 | lookupInterface :: (KnownNat n, Interface a) => [a] -> Bit n -> a 92 | lookupInterface ifcs i = fromIfcTerm (idx $ toIfcTerm <$> ifcs) 93 | where 94 | -- All elements in 'ifcs' have the same type, and hence all elements 95 | -- in the argument to 'idx' are the same constructor. 96 | idx [] = error "Blarney.Core.Lookup: looking up an empty list" 97 | idx (terms@(IfcTermBV{}:_)) = 98 | IfcTermBV $ muxBV (toBV i) [ x | (IfcTermBV x) <- terms ] 99 | idx (terms@(IfcTermAction{}:_)) = IfcTermAction do 100 | rets <- sequence [ whenAction (i .==. fromInteger j) act 101 | | (j, IfcTermAction act) <- zip [0..] terms ] 102 | return (idx rets) 103 | idx (terms@(IfcTermProduct{}:_)) = 104 | IfcTermProduct (idx [x0 | IfcTermProduct x0 _ <- terms]) 105 | (idx [x1 | IfcTermProduct _ x1 <- terms]) 106 | idx (terms@(IfcTermFun{}:_)) = 107 | IfcTermFun $ \x -> idx [f x | IfcTermFun f <- terms] 108 | 109 | -- |Index a list of interfaces using one-hot list of bits 110 | lookupInterfaceOneHot :: Interface a => [a] -> OneHotList -> a 111 | lookupInterfaceOneHot ifcs (OneHotList bs) = 112 | fromIfcTerm (idx $ toIfcTerm <$> ifcs) 113 | where 114 | -- All elements in 'ifcs' have the same type, and hence all elements 115 | -- in the argument to 'idx' are the same constructor. 116 | idx [] = error "Blarney.Core.Lookup: looking up an empty list" 117 | idx (terms@(IfcTermBV{}:_)) = 118 | IfcTermBV $ tree1 orBV 119 | [ maskBV b x 120 | | (b, IfcTermBV x) <- zip bs terms ] 121 | idx (terms@(IfcTermAction{}:_)) = IfcTermAction do 122 | rets <- sequence [ whenAction b act 123 | | (b, IfcTermAction act) <- zip bs terms ] 124 | return (idx rets) 125 | idx (terms@(IfcTermProduct{}:_)) = 126 | IfcTermProduct (idx [x0 | IfcTermProduct x0 _ <- terms]) 127 | (idx [x1 | IfcTermProduct _ x1 <- terms]) 128 | idx (terms@(IfcTermFun{}:_)) = 129 | IfcTermFun $ \x -> idx [f x | IfcTermFun f <- terms] 130 | 131 | maskBV c x = muxBV (toBV c) [constBV w 0, x] 132 | where w = bvPrimOutWidth x 133 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/Opts.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BlockArguments #-} 2 | 3 | {-| 4 | Module : Blarney.Core.Opts 5 | Description : Blarney options and command-line parser 6 | Copyright : (c) Matthew Naylor, 2020 7 | License : MIT 8 | Maintainer : mattfn@gmail.com 9 | Stability : experimental 10 | -} 11 | 12 | module Blarney.Core.Opts 13 | ( Opts(..) 14 | , defaultOpts 15 | , parseOpts 16 | , getOpts 17 | ) where 18 | 19 | -- Standard imports 20 | import Prelude 21 | import System.Environment 22 | import System.Console.GetOpt 23 | 24 | -- Blarney options 25 | data Opts = 26 | Opts { 27 | optEnableSimplifier :: Bool 28 | , optEnableNamePropagation :: Bool 29 | , optEnableDontCareDeInline :: Bool 30 | } 31 | deriving (Show) 32 | 33 | defaultOpts :: Opts 34 | defaultOpts = Opts 35 | { optEnableSimplifier = False 36 | , optEnableNamePropagation = False 37 | , optEnableDontCareDeInline = False 38 | } 39 | 40 | options :: [OptDescr (Opts -> Opts)] 41 | options = 42 | [ Option [] ["enable-simplifier"] 43 | (NoArg \opts -> opts { optEnableSimplifier = True }) 44 | "Netlist simplification passes" 45 | , Option [] ["enable-name-prop"] 46 | (NoArg \opts -> opts { optEnableNamePropagation = True }) 47 | "Name propagation pass" 48 | , Option [] ["enable-dont-care-de-inline"] 49 | (NoArg \opts -> opts { optEnableDontCareDeInline = True }) 50 | "DontCare de-inline pass (avoid if possible)" 51 | ] 52 | 53 | -- Parse command line options 54 | -- And return leftover (unrecognised) options 55 | parseOpts :: [String] -> (Opts, [String]) 56 | parseOpts args = 57 | case getOpt' Permute options args of 58 | (opts, unused0, unused1, []) -> 59 | (foldl (flip id) defaultOpts opts, unused1 ++ unused0) 60 | (_, _, _, errs) -> 61 | error (concat errs ++ usageInfo "Blarney options: " options) 62 | 63 | -- Extract options from the command line 64 | -- And return leftover (unrecognised) options 65 | getOpts :: IO (Opts, [String]) 66 | getOpts = parseOpts <$> getArgs 67 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/Ternary.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney.Core.Ternary 3 | Description : Ternary bit-vectors 4 | Copyright : (c) Matthew Naylor, 2024 5 | License : MIT 6 | Maintainer : mattfn@gmail.com 7 | Stability : experimental 8 | -} 9 | 10 | module Blarney.Core.Ternary 11 | ( Ternary 12 | , dontCare 13 | , integerToTernary 14 | , ternaryToInteger 15 | , concat 16 | , take 17 | , drop 18 | , select 19 | ) where 20 | 21 | import Prelude hiding (concat, take, drop) 22 | import Data.List qualified as L 23 | import Data.Bits 24 | 25 | -- | Ternary bit vectors represented as a list of width/value pairs. 26 | -- 'Nothing' values represent don't care values. Least significant 27 | -- bits come first. 28 | type Ternary = [(Int, Maybe Integer)] 29 | 30 | -- | Construct don't care bit-vector of given width 31 | dontCare :: Int -> Ternary 32 | dontCare 0 = [] 33 | dontCare w = [(w, Nothing)] 34 | 35 | -- | Convert non-negative integer to ternary bit-vector of given width 36 | integerToTernary :: Int -> Integer -> Ternary 37 | integerToTernary w i 38 | | i < 0 = error "integerToTernary: non-negative integer expected" 39 | | w == 0 = [] 40 | | otherwise = [(w, Just i)] 41 | 42 | -- | Convert ternary bit-vector to an integer, with don't cares converted to 0s 43 | ternaryToInteger :: Ternary -> Integer 44 | ternaryToInteger [] = 0 45 | ternaryToInteger ((w, x):rest) = val .|. (ternaryToInteger rest `shiftL` w) 46 | where val = case x of { Nothing -> 0; Just val -> val } 47 | 48 | -- | Concatenate ternary bit-vectors 49 | concat :: Ternary -> Ternary -> Ternary 50 | concat xs [] = xs 51 | concat [] ys = ys 52 | concat ((wx, x):xs) [(wy, y)] = 53 | case (x, y) of 54 | (Nothing, Nothing) -> (wx+wy, Nothing) : xs 55 | (Just x, Just y) -> (wx+wy, Just ((x `shiftL` wy) .|. y)) : xs 56 | other -> (wy, y) : (wx, x) : xs 57 | concat xs (y:ys) = y : concat xs ys 58 | 59 | -- | Drop lower bits of bit vector 60 | drop :: Int -> Ternary -> Ternary 61 | drop 0 xs = xs 62 | drop n [] = [] 63 | drop n ((w, x):rest) 64 | | n >= w = drop (n-w) rest 65 | | otherwise = 66 | case x of 67 | Nothing -> (w-n, Nothing) : rest 68 | Just val -> (w-n, Just (val `shiftR` n)) : rest 69 | 70 | -- | Obtain lower bits of bit vector 71 | take :: Int -> Ternary -> Ternary 72 | take 0 xs = xs 73 | take n [] = [] 74 | take n ((w, x):rest) 75 | | n >= w = (w, x) : take (n-w) rest 76 | | otherwise = 77 | case x of 78 | Nothing -> [(n, Nothing)] 79 | Just val -> [(n, Just (val .&. ((1 `shiftL` n) - 1)))] 80 | 81 | -- | Bit-range selection of ternary bit-vector 82 | select :: Int -> Int -> Ternary -> Ternary 83 | select hi lo = take (hi-lo+1) . drop lo 84 | -------------------------------------------------------------------------------- /Haskell/Blarney/Core/Utils.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : Blarney.Core.Utils 3 | Description : Utility functions 4 | Copyright : (c) Matthew Naylor, 2019 5 | (c) Alexandre Joannou, 2019 6 | License : MIT 7 | Maintainer : mattfn@gmail.com 8 | Stability : experimental 9 | -} 10 | module Blarney.Core.Utils where 11 | 12 | import Prelude 13 | 14 | log2 :: Int -> Int 15 | log2 n 16 | | n <= 0 = error "log2: argument <= 0" 17 | | n == 1 = 0 18 | | otherwise = 1 + log2 (n `div` 2) 19 | 20 | log2ceil :: Int -> Int 21 | log2ceil n 22 | | n < 0 = error "log2ceil: argument < 0" 23 | | n == 0 = 0 24 | | n == 1 = 1 25 | | otherwise = 1 + log2 (n-1) 26 | -------------------------------------------------------------------------------- /Haskell/Blarney/Misc/MonadLoops.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoRebindableSyntax #-} 2 | 3 | {- | 4 | Module : Blarney.Netlist.Misc.MonadLoops 5 | Description : Monadic loops non provided in base 6 | Copyright : (c) Alexandre Joannou, 2020-2021 7 | License : MIT 8 | Stability : experimental 9 | 10 | This module provides monadic loop helpers non present in base. 11 | Inspired by Control.Monad.Loops 12 | 13 | -} 14 | 15 | module Blarney.Misc.MonadLoops ( 16 | untilPredM 17 | , untilPredM_ 18 | , untilM 19 | , untilM_ 20 | ) where 21 | 22 | import Prelude 23 | 24 | infixr 0 `untilPredM` 25 | -- | Repeat computation until a predicate holds 26 | untilPredM :: Monad m => m a -> (a -> Bool) -> m [a] 27 | untilPredM act pred = do 28 | x <- act 29 | if pred x then return [x] else do xs <- untilPredM act pred 30 | return $ x:xs 31 | 32 | infixr 0 `untilPredM_` 33 | -- | Same as 'untilPredM' but discard the final result 34 | untilPredM_ :: Monad m => m a -> (a -> Bool) -> m () 35 | untilPredM_ act pred = untilPredM act pred >> return () 36 | 37 | infixr 0 `untilM` 38 | -- | Repeat computation until the second monadic computation returns 'True' 39 | untilM :: Monad m => m a -> m Bool -> m [a] 40 | untilM act predM = do 41 | x <- act 42 | cond <- predM 43 | if cond then return [x] else do xs <- untilM act predM 44 | return $ x:xs 45 | 46 | infixr 0 `untilM_` 47 | -- | Same as 'untilM' but discard the final result 48 | untilM_ :: Monad m => m a -> m Bool -> m () 49 | untilM_ act predM = untilM act predM >> return () 50 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : Blarney.Netlist.Passes 3 | Description : Blarney netlist passes 4 | Copyright : (c) Alexandre Joannou, 2020-2021 5 | License : MIT 6 | Stability : experimental 7 | 8 | This module simply re-exports individual 'MNetlistPass'es. 9 | 10 | -} 11 | 12 | module Blarney.Netlist.Passes ( 13 | module Blarney.Netlist.Passes.Types 14 | , module Blarney.Netlist.Passes.Utils 15 | , module Blarney.Netlist.Passes.Prune 16 | , module Blarney.Netlist.Passes.NetInline 17 | , module Blarney.Netlist.Passes.ConstantFold 18 | , module Blarney.Netlist.Passes.NamePropagate 19 | , module Blarney.Netlist.Passes.DeadNetEliminate 20 | , module Blarney.Netlist.Passes.ConstantPropagate 21 | , module Blarney.Netlist.Passes.ConstantEliminate 22 | , module Blarney.Netlist.Passes.ZeroWidthNetIgnore 23 | , module Blarney.Netlist.Passes.DontCareDeInline 24 | ) where 25 | 26 | import Blarney.Netlist.Passes.Types 27 | import Blarney.Netlist.Passes.Utils 28 | import Blarney.Netlist.Passes.Prune 29 | import Blarney.Netlist.Passes.NetInline 30 | import Blarney.Netlist.Passes.ConstantFold 31 | import Blarney.Netlist.Passes.NamePropagate 32 | import Blarney.Netlist.Passes.DeadNetEliminate 33 | import Blarney.Netlist.Passes.ConstantPropagate 34 | import Blarney.Netlist.Passes.ConstantEliminate 35 | import Blarney.Netlist.Passes.ZeroWidthNetIgnore 36 | import Blarney.Netlist.Passes.DontCareDeInline 37 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/ConstantEliminate.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney.Netlist.Passes.ConstantEliminate 3 | Description : A blarney netlist pass to eliminate constants 4 | Copyright : (c) Alexandre Joannou, 2020-2021 5 | License : MIT 6 | Stability : experimental 7 | 8 | 'MNetlistPass' to eliminate constants, making use of the 'constantFold' and the 9 | 'constantPropagate' passes in a sequence until a fixed point is reached. 10 | 11 | -} 12 | 13 | module Blarney.Netlist.Passes.ConstantEliminate ( 14 | constantEliminate 15 | ) where 16 | 17 | import Prelude 18 | 19 | import Blarney.Misc.MonadLoops 20 | import Blarney.Netlist.Passes.Types 21 | import Blarney.Netlist.Passes.Utils 22 | import Blarney.Netlist.Passes.ConstantFold 23 | import Blarney.Netlist.Passes.ConstantPropagate 24 | 25 | -- | Constant elimination pass 26 | constantEliminate :: MNetlistPass s () 27 | constantEliminate mnlRef = constElim `untilPredM_` not 28 | where constElim = do a <- constantFold mnlRef 29 | b <- constantPropagate mnlRef 30 | return $ a || b 31 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/ConstantPropagate.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney.Netlist.Passes.ConstantPropage 3 | Description : A blarney netlist pass to propagate constant values 4 | Copyright : (c) Alexandre Joannou, 2020-2021 5 | License : MIT 6 | Stability : experimental 7 | 8 | 'MNetlistPass' propagating constant 'Net's as 'InputTree' 'NetInput's to the 9 | 'Net's using them, and return whether such propagation occured during the pass. 10 | 11 | -} 12 | 13 | module Blarney.Netlist.Passes.ConstantPropagate ( 14 | constantPropagate 15 | ) where 16 | 17 | import Prelude 18 | import Data.STRef 19 | import Control.Monad 20 | import Data.Array.MArray 21 | 22 | import Blarney.Netlist.Passes.Types 23 | import Blarney.Netlist.Passes.Utils 24 | 25 | -- | Constant propagation pass 26 | constantPropagate :: MNetlistPass s Bool 27 | constantPropagate mnlRef = do 28 | mnl <- readSTRef mnlRef -- expose the 'MNetlist' 29 | pairs <- getAssocs mnl -- list of nets with their index 30 | changed <- newSTRef False -- keep track of modifications to the 'Netlist' 31 | -- Turn constant 'InputWire' for each 'Net' into constant 'InputTree' 32 | forM_ [(a, b) | x@(a, Just b) <- pairs] $ \(idx, net) -> do 33 | -- process each 'NetInput' for the current 'Net' 34 | inputs' <- forM (netInputs net) $ \inpt -> do 35 | case inpt of 36 | InputWire (instId, _) -> do 37 | inptNet <- readNet instId mnlRef 38 | -- keep track of change when transforming into an 'InputTree' 39 | case netPrim inptNet of 40 | p@(Const _ _) -> writeSTRef changed True >> return (InputTree p []) 41 | p@(DontCare _) -> writeSTRef changed True >> return (InputTree p []) 42 | _ -> return inpt 43 | _ -> return inpt 44 | -- update the current 'Net' in the 'Netlist' 45 | writeArray mnl idx (Just net { netInputs = inputs' }) 46 | -- finish pass 47 | -- DEBUG HELP -- x <- readSTRef changed 48 | -- DEBUG HELP -- putStrLn $ "propagateConstant pass changed? " ++ show x 49 | readSTRef changed 50 | 51 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/DeadNetEliminate.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney.Netlist.Passes.DeadNetEliminate 3 | Description : A blarney netlist pass to eliminate Nets that are not referenced 4 | Copyright : (c) Alexandre Joannou, 2020-2021 5 | License : MIT 6 | Stability : experimental 7 | 8 | 'MNetlistPass' replacing the 'Maybe' entries for 'Net's which are not referenced 9 | into 'Nothing', and returns whether such replacements occurred during the pass. 10 | 11 | -} 12 | 13 | module Blarney.Netlist.Passes.DeadNetEliminate ( 14 | deadNetEliminate 15 | ) where 16 | 17 | import Prelude 18 | import Data.STRef 19 | import Control.Monad 20 | import Data.Array.MArray 21 | 22 | import Blarney.Netlist.Passes.Types 23 | import Blarney.Netlist.Passes.Utils 24 | 25 | -- | Dead Net elimination pass 26 | deadNetEliminate :: MNetlistPass s Bool 27 | deadNetEliminate mnlRef = do 28 | mnl <- readSTRef mnlRef -- expose the 'MNetlist' 29 | refCounts <- countNetRef mnlRef -- reference count for each 'Net' 30 | pairs <- getAssocs mnl -- list of nets with their index 31 | changed <- newSTRef False -- keep track of modifications to the 'Netlist' 32 | -- kill Nets with a null reference count 33 | forM_ [(a,b) | x@(a, Just b) <- pairs] $ \(idx, net) -> do 34 | refCnt <- readArray refCounts idx 35 | when (refCnt == 0 && (not . netIsRoot) net && (not . netDontKill) net) $ do 36 | writeArray mnl idx Nothing 37 | writeSTRef changed True 38 | -- finish pass 39 | -- DEBUG HELP -- x <- readSTRef changed 40 | -- DEBUG HELP -- putStrLn $ "deadNetEliminate pass changed? " ++ show x 41 | readSTRef changed 42 | where alsoDontKill Net{netPrim=Output _ _} = True 43 | alsoDontKill Net{netPrim=RegFileWrite _} = True 44 | alsoDontKill _ = False 45 | 46 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/DontCareDeInline.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney.Netlist.Passes.DontCareDeInline 3 | Description : A blarney netlist pass to "de-inline" don't care primitives. 4 | Copyright : (c) Alexandre Joannou, 2020-2021 5 | License : MIT 6 | Stability : experimental 7 | 8 | This pass "de-inlines" 'DontCare' primitives that are otherwise inlined in an 9 | 'InputTree'. This undoes some of the work performed by the pass in the 10 | 'Blarney.Netlist.Passes.NetInline' module. 11 | This pass exists to avoid backends generating code that might be too compact for 12 | certain tools (specifically, verilator 4.202 cannot consume verilog that tries 13 | to concatenate a don't care literal with a value literal). 14 | This pass should be avoided if possible. 15 | 16 | -} 17 | 18 | module Blarney.Netlist.Passes.DontCareDeInline ( 19 | dontCareDeInline 20 | ) where 21 | 22 | import Prelude 23 | import Data.List 24 | import Data.STRef 25 | import Control.Monad 26 | import Data.Array.MArray 27 | 28 | import Blarney.Netlist.Passes.Types 29 | import Blarney.Netlist.Passes.Utils 30 | 31 | -- | 'DontCare' "de-inline" 32 | dontCareDeInline :: MNetlistPass s Bool 33 | dontCareDeInline mnlRef = do 34 | mnl <- readSTRef mnlRef -- expose the 'MNetlist' 35 | pairs <- getAssocs mnl -- list of nets with their index 36 | -- prepare a new 'DontCare' 'Net' generator 37 | (_, hi) <- getBounds mnl 38 | newInstId <- newSTRef $ hi + 1 39 | newDontCares <- newSTRef [] 40 | let genNewDontCare w = do 41 | newId <- readSTRef newInstId 42 | modifySTRef' newInstId (+1) 43 | modifySTRef' newDontCares 44 | (\xs -> Just (Net (DontCare w) newId [] mempty) : xs) 45 | return $ InputWire (newId, Nothing) 46 | let updateInputTree inpt = case inpt of 47 | InputWire _ -> return inpt 48 | InputTree (DontCare w) _ -> genNewDontCare w 49 | InputTree p ins -> do ins' <- mapM updateInputTree ins 50 | return $ InputTree p ins' 51 | -- explore netlist for possible de-inline spots 52 | allExtracted <- forM [ (a, b) | x@(a, Just b) <- pairs ] $ 53 | \(idx, net) -> do netInputs' <- mapM updateInputTree (netInputs net) 54 | writeArray mnl idx $ Just net { netInputs = netInputs' } 55 | -- append all extracted 'DontCare' 'Net's to the netlist 56 | updatedOldNets <- getElems mnl 57 | newNets <- readSTRef newDontCares 58 | case newNets of 59 | [] -> return False 60 | Just (Net { netInstId = newHi }) : _ -> do 61 | newNets' <- newListArray (0, newHi) (updatedOldNets ++ reverse newNets) 62 | writeSTRef mnlRef newNets' 63 | return True 64 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/NamePropagate.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | {-# LANGUAGE NoRebindableSyntax #-} 3 | {-# LANGUAGE ScopedTypeVariables #-} 4 | 5 | {- | 6 | Module : Blarney.Netlist.Passes.NamePropagate 7 | Description : A blarney netlist pass to propagate names 8 | Copyright : (c) Alexandre Joannou, 2020-2021 9 | License : MIT 10 | Stability : experimental 11 | 12 | 'MNetlistPass' propagating through the netlist the name of the current 13 | "destination" (register, bram, output...), augmenting individual 'Net's' name 14 | hints. 15 | 16 | -} 17 | 18 | module Blarney.Netlist.Passes.NamePropagate ( 19 | namePropagate 20 | ) where 21 | 22 | import Prelude 23 | import Data.STRef 24 | import Data.Array.ST 25 | import Control.Monad 26 | import Control.Monad.ST 27 | import Data.Set (insert, toList) 28 | 29 | import Blarney.Netlist.Passes.Types 30 | import Blarney.Netlist.Passes.Utils 31 | 32 | -- | Name propagation pass 33 | namePropagate :: forall s. MNetlistPass s () 34 | namePropagate mnlRef = do 35 | mnl <- readSTRef mnlRef -- expose the 'MNetlist' 36 | bounds <- getBounds mnl 37 | visited :: STUArray s InstId Bool <- newArray bounds False 38 | -- Push destination name down through netlist 39 | let visit destName instId = do 40 | isVisited <- readArray visited instId 41 | if not isVisited then do 42 | net@Net{ netPrim = prim 43 | , netInputs = inpts 44 | , netNameHints = hints 45 | } <- readNet instId mnlRef 46 | let inpts' = [instId | x@(InputWire (instId, _)) <- inpts] 47 | writeArray visited instId True 48 | -- Detect new destination and update destination name in recursive call 49 | if isDest prim then mapM_ (visit $ bestName net) inpts' 50 | else do 51 | let newHints = insert (NmSuffix 10 destName) hints 52 | writeArray mnl instId $ Just net{netNameHints = newHints} 53 | mapM_ (visit destName) inpts' 54 | else return () 55 | -- 56 | pairs <- getAssocs mnl -- list of nets with their index 57 | forM_ [i | x@(i, Just n) <- pairs, netIsRoot n] $ \instId -> do 58 | net <- readNet instId mnlRef 59 | visit (bestName net) instId 60 | -- 61 | where bestName Net{ netPrim = prim 62 | , netNameHints = hints 63 | , netInstId = instId 64 | } = "DEST_" ++ nm 65 | where nm = if null nms 66 | then primStr prim ++ "_id" ++ show instId 67 | else head nms 68 | nms = [y | x@(NmRoot _ y) <- toList hints] 69 | -- 70 | isDest Register{} = True 71 | isDest RegisterEn{} = True 72 | isDest BRAM{} = True 73 | isDest Custom{} = True 74 | isDest Input{} = True 75 | isDest Output{} = True 76 | isDest Display{} = True 77 | isDest Finish = True 78 | isDest TestPlusArgs{} = True 79 | isDest RegFileMake{} = True 80 | isDest RegFileRead{} = True 81 | isDest RegFileWrite{} = True 82 | isDest _ = False 83 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/NetInline.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoRebindableSyntax #-} 2 | 3 | {- | 4 | Module : Blarney.Netlist.Passes.NetInline 5 | Description : A blarney netlist pass to inline a Net into an other Net's inputs 6 | Copyright : (c) Alexandre Joannou, 2020-2021 7 | License : MIT 8 | Stability : experimental 9 | 10 | 'MNetlistPass' embedding 'Net's with a single reference into the 'NetInput's of 11 | the referencing 'Net' if possible, and returns whether such embedding occurred. 12 | 13 | -} 14 | 15 | module Blarney.Netlist.Passes.NetInline ( 16 | singleRefNetInline 17 | ) where 18 | 19 | import Prelude 20 | import Data.STRef 21 | import Control.Monad 22 | import Control.Monad.ST 23 | import Data.Array.MArray 24 | 25 | import Blarney.Netlist.Passes.Types 26 | import Blarney.Netlist.Passes.Utils 27 | 28 | -- | Helper to inline a 'Net''s inputs 29 | netInputInline :: MNetlistRef s -> NetCounts s -> NetInput 30 | -> ST s (NetInput, Bool) 31 | netInputInline mnlRef nc inpt@(InputWire (instId, _)) = do 32 | -- read ref count for our referenced 'Net' 33 | cnt <- readArray nc instId 34 | -- read netPrim and netInputs for our referenced 'Net' 35 | Net{ netPrim = prim, netInputs = inpts } <- readNet instId mnlRef 36 | -- attempt inlining our referenced 'Net', and its inputs recursively, also 37 | -- returning if inlining could happen as a Bool 38 | if cnt == 1 && canInline prim then do 39 | (inpts', changes) <- unzip <$> mapM 40 | (\x -> if canInlineInput prim then 41 | do (x', _) <- netInputInline mnlRef nc x 42 | return (x', True) 43 | else return (x, False)) inpts 44 | return (InputTree prim inpts', or changes) 45 | else return (inpt, False) 46 | netInputInline mnlRef nc (InputTree prim inpts) = do 47 | (inpts', changes) <- unzip <$> mapM (netInputInline mnlRef nc) inpts 48 | return $ (InputTree prim inpts', or changes) 49 | 50 | -- | Single-reference 'Net' inlining pass 51 | singleRefNetInline :: MNetlistPass s Bool 52 | singleRefNetInline mnlRef = do 53 | mnl <- readSTRef mnlRef -- expose the 'MNetlist' 54 | refCounts <- countNetRef mnlRef -- reference count for each 'Net' 55 | pairs <- getAssocs mnl -- list of nets with their index 56 | changed <- newSTRef False -- keep track of modifications to the 'Netlist' 57 | -- Inline each "inlinable" (that is with a supported combinational underlying 58 | -- primitive) 'Net' 59 | forM_ [(a,b) | x@(a, Just b) <- pairs, canInlineInput (netPrim b)] $ 60 | \(idx, net) -> do 61 | (netInputs', changes) <- unzip <$> mapM (netInputInline mnlRef refCounts) 62 | (netInputs net) 63 | when (or changes) $ do -- on change, update 'Netlist' and keep track 64 | writeArray mnl idx (Just net { netInputs = netInputs' }) 65 | writeSTRef changed True 66 | -- finish pass 67 | -- DEBUG HELP -- x <- readSTRef changed 68 | -- DEBUG HELP -- putStrLn $ "netInputInline pass changed? " ++ show x 69 | readSTRef changed 70 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/Prune.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ScopedTypeVariables #-} 2 | 3 | {- | 4 | Module : Blarney.Netlist.Passes.Prune 5 | Description : A blarney netlist pass to prune a netlist 6 | Copyright : (c) Alexandre Joannou, 2020-2021 7 | License : MIT 8 | Stability : experimental 9 | 10 | -- | 'MNetlistPass' pruning the netlist, dropping all 'Nothing' entries and 11 | -- remapping the remaining 'Net's' 'InstId's appropriately. 12 | 13 | -} 14 | 15 | module Blarney.Netlist.Passes.Prune ( 16 | prune 17 | ) where 18 | 19 | import Prelude 20 | import Data.Maybe 21 | import Data.STRef 22 | import Data.Array.ST 23 | import Data.Array.Unboxed 24 | 25 | import Blarney.Netlist.Passes.Types 26 | import Blarney.Netlist.Passes.Utils 27 | 28 | -- | 'Netlist' pruning pass 29 | prune :: MNetlistPass s () 30 | prune mnlRef = do 31 | mnl <- readSTRef mnlRef -- expose the 'MNetlist' 32 | assocs <- getAssocs mnl 33 | let usedAssocs = [(i, n) | (i, Just n) <- assocs] 34 | let oldIds = map fst usedAssocs 35 | let oldNets = map snd usedAssocs 36 | -- Mapping from old ids to new ids 37 | bounds <- getBounds mnl 38 | let mapping :: UArray InstId InstId = 39 | array bounds (zip oldIds [0..]) 40 | -- Compute compact netlist 41 | pruned <- newListArray (0, length oldNets - 1) 42 | [ Just (remapNetInstId (mapping !) net) 43 | | net <- oldNets ] 44 | writeSTRef mnlRef pruned 45 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/Types.hs: -------------------------------------------------------------------------------- 1 | {-| 2 | Module : Blarney.Netlist.Passes.Types 3 | Description : Types used for netlist passes 4 | Copyright : (c) Alexandre Joannou, 2020-2021 5 | License : MIT 6 | Stability : experimental 7 | 8 | This module defines the notions of mutable netlists 'MNetlist's and passes 9 | 'MNetlistPass'es which can be used to write 'Netlist' optimisation passes. 10 | 11 | -} 12 | 13 | module Blarney.Netlist.Passes.Types ( 14 | -- * Mutable netlist types 15 | MNetlist 16 | , MNetlistRef 17 | , MNetlistPass 18 | ) where 19 | 20 | import Data.Maybe 21 | import Data.STRef 22 | import Data.Array.ST 23 | import Control.Monad.ST 24 | 25 | import Blarney.Core.Prim 26 | import Blarney.Core.NetHelpers 27 | 28 | -- | A helper type for mutable 'Netlist' 29 | type MNetlist s = STArray s InstId (Maybe Net) 30 | 31 | -- | A reference to an 'MNetlist' 32 | type MNetlistRef s = STRef s (MNetlist s) 33 | 34 | -- | A pass over an 'MNetlist' 35 | type MNetlistPass s a = MNetlistRef s -> ST s a 36 | -------------------------------------------------------------------------------- /Haskell/Blarney/Netlist/Passes/Utils.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoRebindableSyntax #-} 2 | 3 | {- | 4 | Module : Blarney.Netlist.Passes.Utils 5 | Description : Utility functions for netlist passes 6 | Copyright : (c) Alexandre Joannou, 2020-2021 7 | License : MIT 8 | Stability : experimental 9 | 10 | This module provides helper functions to write netlist passes. 11 | 12 | -} 13 | 14 | module Blarney.Netlist.Passes.Utils ( 15 | -- * Queries on individual 'Net's 16 | netIsRoot 17 | , netDontKill 18 | , readNet 19 | -- * Basic 'MNetlistPass'es 20 | , NetCounts 21 | , countNetRef 22 | -- * Exported 'Blarney' modules 23 | , module Blarney.Core.Prim 24 | , module Blarney.Core.NetHelpers 25 | ) where 26 | 27 | import Prelude 28 | import Data.Maybe 29 | import Control.Monad 30 | import Control.Monad.ST 31 | import Data.STRef 32 | import Data.Array.ST 33 | 34 | import Blarney.Core.Prim 35 | import Blarney.Core.NetHelpers 36 | import Blarney.Netlist.Passes.Types 37 | 38 | -- | A helper function to tell if a 'Net' is a netlist root 39 | netIsRoot :: Net -> Bool 40 | netIsRoot Net{netPrim=prim} = primIsRoot prim 41 | 42 | -- | A helper function to tell if a 'Net' should not be optimised away 43 | netDontKill :: Net -> Bool 44 | netDontKill Net{netPrim=prim} = primDontKill prim 45 | 46 | -- | A helper function to read a 'Net' from a 'MNetlist' 47 | readNet :: InstId -> MNetlistPass s Net 48 | readNet instId mnlRef = do 49 | mnl <- readSTRef mnlRef 50 | fromMaybe (error "encountered InstId with no matching Net") 51 | <$> readArray mnl instId 52 | 53 | -- | A helper type for 'Net' reference counting 54 | type NetCounts s = STUArray s InstId Int 55 | 56 | -- | A 'Net' reference counting helper function 57 | countNetRef :: MNetlistPass s (NetCounts s) 58 | countNetRef mnlRef = do 59 | mnl <- readSTRef mnlRef 60 | bounds <- getBounds mnl 61 | refCounts <- newArray bounds 0 62 | es <- getElems mnl 63 | -- count references for each Net 64 | let innerCount (InputWire (instId, _)) = do 65 | cnt <- readArray refCounts instId 66 | writeArray refCounts instId $! (cnt + 1) 67 | innerCount (InputTree _ inpts) = mapM_ innerCount inpts 68 | forM_ [e | Just e <- es] $ \net -> mapM_ innerCount (netInputs net) 69 | -- return reference counts 70 | return refCounts 71 | -------------------------------------------------------------------------------- /Haskell/Blarney/Option.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleInstances #-} 2 | {-# LANGUAGE MultiParamTypeClasses #-} 3 | {-# LANGUAGE DataKinds #-} 4 | {-# LANGUAGE NoImplicitPrelude #-} 5 | {-# LANGUAGE DeriveGeneric #-} 6 | {-# LANGUAGE DeriveAnyClass #-} 7 | {-# LANGUAGE OverloadedRecordDot #-} 8 | 9 | {- | 10 | Module : Blarney.Option 11 | Description : An 'Option' type, similar to 'Maybe' in functionality 12 | Copyright : (c) Alexandre Joannou, 2019 13 | License : MIT 14 | Maintainer : alexandre.joannou@gmail.com 15 | Stability : experimental 16 | 17 | An 'Option' type, similar to 'Maybe' in functionality but represented as a pair 18 | of a flag and a value. 19 | -} 20 | module Blarney.Option 21 | ( -- * Option type 22 | Option(..), some, none, isSome, isNone, fromOption 23 | ) where 24 | 25 | -- Blarney imports 26 | import Blarney 27 | 28 | {- | 29 | 'Option' type to wrap a value. An 'Option t' is represented as a pair of a 30 | 'Bit 1' indicating whether the value held is valid, and a value of type 't'. 31 | -} 32 | 33 | data Option t = 34 | Option { 35 | valid :: Bit 1 36 | , val :: t 37 | } deriving (Generic, Bits, Interface, FShow, Cmp) 38 | 39 | instance Functor Option where 40 | fmap f (Option valid value) = Option valid (f value) 41 | 42 | -- | Builds an 'Option' with a valid value 43 | some :: Bits t => t -> Option t 44 | some val = Option true val 45 | 46 | -- | Builds an invalid 'Option' 47 | none :: Bits t => Option t 48 | none = Option false dontCare 49 | 50 | -- | Tests if an 'Option' is a 'some' 51 | isSome :: Bits t => Option t -> Bit 1 52 | isSome opt = opt.valid 53 | 54 | -- | Tests if an 'Option' is a 'none' 55 | isNone :: Bits t => Option t -> Bit 1 56 | isNone opt = inv opt.valid 57 | 58 | -- | Gets the value from a valid 'Option', or a given default value otherwise 59 | fromOption :: Bits t => t -> Option t -> t 60 | fromOption dflt opt = opt.valid ? (opt.val, dflt) 61 | -------------------------------------------------------------------------------- /Haskell/Blarney/Prelude.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : Blarney.Prelude 3 | Description : Hardware description in Haskell 4 | Copyright : (c) Matthew Naylor, 2024 5 | License : MIT 6 | Maintainer : mattfn@gmail.com 7 | Stability : experimental 8 | 9 | Re-export (most of) the Haskell Prelude and other important standard 10 | Haskell modules. 11 | -} 12 | 13 | module Blarney.Prelude ( 14 | module Control.Monad 15 | , module Control.Monad.Fix 16 | , HasField(..) 17 | , Generic(..) 18 | , module GHC.TypeLits 19 | , module P 20 | ) where 21 | 22 | import Control.Monad hiding (when) 23 | import Control.Monad.Fix 24 | import GHC.Records (HasField(..)) 25 | import GHC.Generics (Generic(..)) 26 | import GHC.TypeLits 27 | import Prelude as P hiding (truncate) 28 | -------------------------------------------------------------------------------- /Haskell/Blarney/PulseReg.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleInstances #-} 2 | {-# LANGUAGE MultiParamTypeClasses #-} 3 | {-# LANGUAGE DataKinds #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE DeriveGeneric #-} 6 | {-# LANGUAGE DeriveAnyClass #-} 7 | {-# LANGUAGE OverloadedRecordDot #-} 8 | {-# LANGUAGE DuplicateRecordFields #-} 9 | 10 | {-| 11 | Module : Blarney.PulseReg 12 | Description : Like PulseWire, but delayed by a cycle 13 | Copyright : (c) Matthew Naylor, 2022 14 | License : MIT 15 | Maintainer : mattfn@gmail.com 16 | Stability : experimental 17 | 18 | An assignment to a PulseReg is visible only for one cycle, on the 19 | cycle after which the assignment is made. 20 | 21 | -} 22 | 23 | module Blarney.PulseReg 24 | ( PulseReg(..) 25 | , makePulseReg 26 | ) where 27 | 28 | -- Blarney imports 29 | import Blarney 30 | 31 | -- | Emits a pulse on the cycle after the pulse method is called 32 | data PulseReg = 33 | PulseReg { 34 | pulse :: Action () 35 | -- ^ Trigger pulse on next cycle 36 | , val :: Bit 1 37 | -- ^ Is the register currently pulsing? 38 | } deriving (Generic, Interface) 39 | 40 | makePulseReg :: Module PulseReg 41 | makePulseReg = do 42 | -- Implement using a wire that is delayed by one cycle 43 | w <- makeWire false 44 | return 45 | PulseReg { 46 | pulse = do w <== true 47 | , val = delay false w.val 48 | } 49 | -------------------------------------------------------------------------------- /Haskell/Blarney/PulseWire.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleInstances #-} 2 | {-# LANGUAGE MultiParamTypeClasses #-} 3 | {-# LANGUAGE DataKinds #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE DeriveGeneric #-} 6 | {-# LANGUAGE DeriveAnyClass #-} 7 | {-# LANGUAGE OverloadedRecordDot #-} 8 | {-# LANGUAGE DuplicateRecordFields #-} 9 | 10 | {-| 11 | Module : Blarney.PulseWire 12 | Description : A PulseWire hardware module 13 | Copyright : (c) Alexandre Joannou, 2019 14 | License : MIT 15 | Maintainer : alexandre.joannou@gmail.com 16 | Stability : experimental 17 | 18 | A PulseWire hardware module 19 | -} 20 | module Blarney.PulseWire 21 | ( -- * PulseWire 22 | PulseWire(..), makePulseWire 23 | ) where 24 | 25 | -- Blarney imports 26 | import Blarney 27 | 28 | -- | 'PulseWire' type 29 | data PulseWire = 30 | PulseWire { 31 | pulse :: Action () 32 | -- ^ Sends a pulse on the wire 33 | , val :: Bit 1 34 | -- ^ Checks whether a pulse was sent this cycle 35 | } deriving (Generic, Interface) 36 | 37 | -- | 'Val' instance for 'PulseWire', returning whether the wire was pulsed 38 | instance Val PulseWire (Bit 1) where 39 | val w = w.val 40 | 41 | -- | Single-bit wire that emits 0 unless pulsed 42 | makePulseWire :: Module PulseWire 43 | makePulseWire = do 44 | w :: Wire (Bit 0) <- makeWire dontCare 45 | return 46 | PulseWire { 47 | pulse = do w <== dontCare 48 | , val = active w 49 | } 50 | -------------------------------------------------------------------------------- /Haskell/Blarney/Recipe.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE BlockArguments #-} 3 | 4 | {-| 5 | Module : Blarney.Recipe 6 | Description : Basic imperative programming on top of RTL 7 | Copyright : (c) 2019 Matthew Naylor, Dillon Huff 8 | License : MIT 9 | Maintainer : mattfn@gmail.com 10 | Stability : experimental 11 | 12 | Recipe is a lightweight imperative language, aiding concise 13 | definitions of complex state machines. 14 | -} 15 | module Blarney.Recipe 16 | ( Recipe(..) 17 | , runOnce 18 | , runRecipe 19 | , runRecipeOn 20 | ) where 21 | 22 | -- Standard imports 23 | import Prelude 24 | import Data.Maybe 25 | 26 | -- Blarney imports 27 | import Blarney.Core 28 | 29 | -- |Abstract syntax of Recipe 30 | data Recipe = 31 | Skip 32 | | Tick 33 | | Action (Action ()) 34 | | Seq [Recipe] 35 | | Par [Recipe] 36 | | Wait (Bit 1) 37 | | When (Bit 1) Recipe 38 | | If (Bit 1) Recipe Recipe 39 | | While (Bit 1) Recipe 40 | | Background Recipe 41 | 42 | -- Is time taken by given statement known? 43 | known :: Recipe -> Bool 44 | known r = isJust (time r) 45 | 46 | -- Static timing analysis 47 | time :: Recipe -> Maybe Int 48 | time Skip = Just 0 49 | time Tick = Just 1 50 | time (Action act) = Just 1 51 | time (Seq rs) = sum `fmap` mapM time rs 52 | time (Par rs) = foldr max 0 `fmap` mapM time rs 53 | time other = Nothing 54 | 55 | -- Return index of the slowest recipe 56 | slowest :: [Recipe] -> Int 57 | slowest = snd . maximum . flip zip [0..] . map time 58 | 59 | -- |Run a recipe. Take a go pulse and return a finish pulse. 60 | run :: Bit 1 -> Recipe -> Module (Bit 1) 61 | run go Skip = return go 62 | run go Tick = return (reg 0 go) 63 | run go (Action act) = always (when go act) >> return (reg 0 go) 64 | run go (Seq []) = return go 65 | run go (Seq (r:rs)) = do { done <- run go r; run done (Seq rs) } 66 | run go (Par rs) = do 67 | dones <- mapM (run go) rs 68 | return (if all known rs then dones !! slowest rs else sync dones) 69 | run go (Wait c) = run go (While (inv c) Tick) 70 | run go (When c r) = run (go .&. c) r 71 | run go (If c r1 r2) = do 72 | done1 <- run (go .&. c) r1 73 | done2 <- run (go .&. inv c) r2 74 | return (done1 .|. done2) 75 | run go (While c r) = do 76 | ready <- makeWire dontCare 77 | done <- run (val ready .&. c) r 78 | always do 79 | ready <== go .|. done 80 | return (val ready .&. inv c) 81 | run go (Background r) = do 82 | done <- run go r 83 | return go 84 | 85 | sync :: [Bit 1] -> Bit 1 86 | sync [x] = x 87 | sync xs = let done = andList [setReset x done | x <- xs] in done 88 | 89 | setReset :: Bit 1 -> Bit 1 -> Bit 1 90 | setReset s r = let out = s .|. reg 0 (out .&. inv r) in out 91 | 92 | -- |Run a recipe with a start pulse that is high only on the first 93 | -- cycle of execution, and ignore the finish pulse. 94 | runRecipe :: Recipe -> Module () 95 | runRecipe r = run (reg 1 0) r >> return () 96 | 97 | -- |Same as 'runRecipe'. For backwards compatibility. 98 | runOnce :: Recipe -> Module () 99 | runOnce = runRecipe 100 | 101 | -- |Run a recipe, triggered by the given start pulse. 102 | -- Returns the finish pulse. 103 | runRecipeOn :: Bit 1 -> Recipe -> Module (Bit 1) 104 | runRecipeOn = run 105 | -------------------------------------------------------------------------------- /Haskell/Blarney/Stack.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE Rank2Types #-} 3 | {-# LANGUAGE DeriveGeneric #-} 4 | {-# LANGUAGE DeriveAnyClass #-} 5 | {-# LANGUAGE BlockArguments #-} 6 | {-# LANGUAGE RebindableSyntax #-} 7 | {-# LANGUAGE FlexibleInstances #-} 8 | {-# LANGUAGE ScopedTypeVariables #-} 9 | {-# LANGUAGE OverloadedRecordDot #-} 10 | {-# LANGUAGE MultiParamTypeClasses #-} 11 | 12 | {-| 13 | Module : Blarney.Stack 14 | Description : Library of various stack implementations 15 | Copyright : (c) Matthew Naylor, 2021 16 | License : MIT 17 | Maintainer : mattfn@gmail.com 18 | Stability : experimental 19 | -} 20 | module Blarney.Stack where 21 | 22 | -- Blarney imports 23 | import Blarney 24 | import Blarney.Stream 25 | import Blarney.Option 26 | import Blarney.PulseWire 27 | import Blarney.SourceSink 28 | 29 | -- Standard imports 30 | import Data.Proxy 31 | 32 | -- | Stack interface 33 | data Stack a = 34 | Stack { 35 | notEmpty :: Bit 1 36 | , notFull :: Bit 1 37 | , push :: a -> Action () 38 | , pop :: Action () 39 | , top :: a 40 | , clear :: Action () 41 | } deriving (Generic, Interface) 42 | 43 | instance ToSource (Stack t) t where 44 | toSource s = Source { canPeek = s.notEmpty 45 | , peek = s.top 46 | , consume = s.pop 47 | } 48 | 49 | instance ToSink (Stack t) t where 50 | toSink s = Sink { canPut = s.notFull 51 | , put = s.push 52 | } 53 | 54 | -- | Sized queue of given size, backed by RAM, with top element cached 55 | -- in a register 56 | makeSizedStack :: Bits a => 57 | Int 58 | -- ^ Log of the capacity of the stack 59 | -> Module (Stack a) 60 | makeSizedStack logSize = do 61 | -- Lift size to type-level address-width 62 | liftNat logSize $ \(_ :: Proxy aw) -> do 63 | 64 | -- A dual-port RAM, big enough to hold entire stack 65 | ram :: RAM (Bit aw) a <- makeDualRAMForward 66 | 67 | -- Stack pointer 68 | sp :: Reg (Bit aw) <- makeReg 0 69 | 70 | -- Top of stack cached in register 71 | topReg :: Reg a <- makeReg dontCare 72 | 73 | -- Stack full/empty? 74 | empty <- makeReg true 75 | full <- makeReg false 76 | 77 | -- Interface wires 78 | popWire <- makePulseWire 79 | pushWire <- makeWire dontCare 80 | clearWire <- makePulseWire 81 | 82 | always do 83 | if clearWire.val 84 | then do 85 | empty <== true 86 | full <== false 87 | sp <== 0 88 | else do 89 | let spMinus1 = sp.val - 1 90 | -- On push, always update topReg 91 | when pushWire.active do 92 | topReg <== pushWire.val 93 | -- When pushing but not popping 94 | when (pushWire.active .&&. inv popWire.val) do 95 | ram.store sp.val topReg.val 96 | ram.load sp.val 97 | sp <== sp.val + 1 98 | empty <== false 99 | full <== sp.val .==. ones 100 | -- When popping but not pushing 101 | when (inv pushWire.active .&&. popWire.val) do 102 | topReg <== ram.out 103 | ram.load (sp.val - 2) 104 | sp <== spMinus1 105 | empty <== sp.val .==. 1 106 | full <== false 107 | 108 | return 109 | Stack { 110 | notEmpty = inv empty.val 111 | , notFull = inv full.val 112 | , push = \x -> do pushWire <== x 113 | , pop = popWire.pulse 114 | , top = topReg.val 115 | , clear = clearWire.pulse 116 | } 117 | -------------------------------------------------------------------------------- /Haskell/Blarney/Stmt.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE FlexibleInstances #-} 3 | {-# LANGUAGE MultiParamTypeClasses #-} 4 | 5 | {-| 6 | Module : Blarney.Stmt 7 | Description : Monadic wrapper for the Recipe language 8 | Copyright : (c) 2020 Matthew Naylor 9 | License : MIT 10 | Maintainer : mattfn@gmail.com 11 | Stability : experimental 12 | -} 13 | module Blarney.Stmt 14 | ( Stmt 15 | , tick 16 | , skip 17 | , action 18 | , wait 19 | , par 20 | , while 21 | , background 22 | , runStmt 23 | , runStmtOn 24 | ) where 25 | 26 | -- Standard imports 27 | import Prelude 28 | import Control.Monad 29 | 30 | -- Blarney imports 31 | import Blarney.Core 32 | import Blarney.Recipe 33 | 34 | -- |Statement monad, with mondic bind for sequential composition. 35 | data Stmt a = Stmt Recipe a 36 | 37 | instance Monad Stmt where 38 | return = pure 39 | Stmt r1 a >>= f = Stmt (Seq [r1, r2]) b 40 | where Stmt r2 b = f a 41 | 42 | instance Functor Stmt where 43 | fmap = liftM 44 | 45 | instance Applicative Stmt where 46 | pure a = Stmt Skip a 47 | (<*>) = ap 48 | 49 | skip :: Stmt () 50 | skip = Stmt Skip () 51 | 52 | tick :: Stmt () 53 | tick = Stmt Tick () 54 | 55 | action :: Action () -> Stmt () 56 | action act = Stmt (Action act) () 57 | 58 | par :: [Stmt ()] -> Stmt () 59 | par stmts = Stmt (Par [r | Stmt r _ <- stmts]) () 60 | 61 | wait :: Bit 1 -> Stmt () 62 | wait c = Stmt (Wait c) () 63 | 64 | while :: Bit 1 -> Stmt () -> Stmt () 65 | while c (Stmt r _) = Stmt (While c r) () 66 | 67 | ifThenElseStmt :: Bit 1 -> Stmt () -> Stmt () -> Stmt () 68 | ifThenElseStmt c (Stmt r1 _) (Stmt r2 _) = 69 | Stmt (If c r1 r2) () 70 | 71 | instance IfThenElse (Bit 1) (Stmt ()) where 72 | ifThenElse = ifThenElseStmt 73 | 74 | whenStmt :: Bit 1 -> Stmt () -> Stmt () 75 | whenStmt c s = ifThenElseStmt c s skip 76 | 77 | instance When (Bit 1) Stmt where 78 | when = whenStmt 79 | 80 | background :: Stmt () -> Stmt () 81 | background (Stmt r _) = Stmt (Background r) () 82 | 83 | -- |Run a statement with a start pulse that is high only on the first 84 | -- cycle of execution, and ignore the finish pulse. 85 | runStmt :: Stmt () -> Module () 86 | runStmt (Stmt r _) = runRecipe r 87 | 88 | -- |Run a statement, triggered by the given start pulse. 89 | -- Returns the finish pulse. 90 | runStmtOn :: Bit 1 -> Stmt () -> Module (Bit 1) 91 | runStmtOn pulse (Stmt r _) = runRecipeOn pulse r 92 | -------------------------------------------------------------------------------- /Haskell/Blarney/Stream.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE DeriveAnyClass #-} 4 | {-# LANGUAGE MultiParamTypeClasses #-} 5 | {-# LANGUAGE FlexibleInstances #-} 6 | {-# LANGUAGE FunctionalDependencies #-} 7 | 8 | {-| 9 | Module : Blarney.Stream 10 | Description : Stream library 11 | Copyright : (c) Matthew Naylor, 2019 12 | License : MIT 13 | Maintainer : mattfn@gmail.com 14 | Stability : experimental 15 | -} 16 | module Blarney.Stream 17 | ( Stream(..), Source(..) 18 | , toStream 19 | , nullStream 20 | , guardStream 21 | , SP(..) 22 | , ToSP(..) 23 | ) where 24 | 25 | import Blarney 26 | import Blarney.SourceSink 27 | import Blarney.Connectable 28 | 29 | -- | Stream interface 30 | type Stream a = Source a 31 | 32 | -- | Convert to a Stream 33 | toStream :: (ToSource a b) => a -> Stream b 34 | toStream = toSource 35 | 36 | -- | Null stream 37 | nullStream :: Bits a => Stream a 38 | nullStream = nullSource 39 | 40 | -- | Apply a guard to a stream 41 | guardStream :: (a -> Bit 1) -> Stream a -> Stream a 42 | guardStream = guardSource 43 | 44 | -- | StreamProcessor type 45 | type SP t0 t1 = Stream t0 -> Module (Stream t1) 46 | 47 | -- | Convert to a StreamProcessor 48 | class ToSP a t0 t1 | a -> t0 t1 where 49 | toSP :: a -> SP t0 t1 50 | 51 | -- | ToSP instance for StreamProcessor itself 52 | instance ToSP (SP t0 t1) t0 t1 where 53 | toSP = id 54 | 55 | -- | ToSP instance for (Sink, Source) pairs 56 | instance ToSP (Sink t0, Source t1) t0 t1 where 57 | toSP (inSnk, outSrc) = \inStream -> do makeConnection inStream inSnk 58 | return outSrc 59 | -------------------------------------------------------------------------------- /Haskell/Blarney/TypeFamilies.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE NoImplicitPrelude #-} 3 | {-# LANGUAGE TypeFamilies #-} 4 | {-# LANGUAGE UndecidableInstances #-} 5 | 6 | {-| 7 | Module : Blarney.TypeFamilies 8 | Description : Common type families 9 | Copyright : (c) Matthew Naylor, 2021 10 | License : MIT 11 | Maintainer : mattfn@gmail.com 12 | Stability : experimental 13 | This module defines commonly used type families, not available in base. 14 | -} 15 | module Blarney.TypeFamilies where 16 | 17 | import Blarney 18 | 19 | -- GHC imports 20 | import GHC.Types 21 | import Data.Type.Bool 22 | import Data.Type.Equality 23 | 24 | -- | Type function for computing the min of two type-level nats 25 | type family Min (x :: Nat) (y::Nat) :: Nat where 26 | Min x y = If (CmpNat x y == LT) x y 27 | 28 | -- | Type function for computing the max of two type-level nats 29 | type family Max (a :: Nat) (b :: Nat) :: Nat where 30 | Max a b = If (CmpNat a b == GT) a b 31 | 32 | -- | Type function to compute the length of a list 33 | type family Length (ts :: [Type]) :: Nat where 34 | Length '[] = 0 35 | Length (u ': us) = 1 + Length us 36 | 37 | -- | Min number of bits needed to hold given nat 38 | type family Log2Ceil (n :: Nat) :: Nat where 39 | Log2Ceil n = If (n <=? 1) n (1 + Log2 (n-1)) 40 | -------------------------------------------------------------------------------- /Haskell/BlarneyPlugins/Namer/blarney-plugins-namer.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 2.4 2 | -- Initial package description 'Namer.cabal' generated by 'cabal init'. 3 | -- For further documentation, see http://haskell.org/cabal/users-guide/ 4 | 5 | name: blarney-plugins-namer 6 | version: 0.1.0.0 7 | 8 | library 9 | exposed-modules: BlarneyPlugins.Namer 10 | exposed: False 11 | build-depends: base >= 4.12.0.0, syb >= 0.7.1, ghc >= 9.2.1 12 | default-language: Haskell2010 13 | ghc-options: -O2 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License below applies to all files in this repository, unless 2 | otherwise stated, except those in Verilog/Altera directory. 3 | 4 | MIT License 5 | 6 | Copyright (c) 2019 Matthew Naylor 7 | Copyright (c) 2019 Alexandre Joannou 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BLARNEY_ROOT ?= $(realpath .) 2 | 3 | include $(BLARNEY_ROOT)/blarneyDirs.mk 4 | 5 | BLARNEY_TOP_MODULES_SRC = $(SRC_DIR)/Blarney.hs 6 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/BitPat.hs 7 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/BitScan.hs 8 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/ClientServer.hs 9 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Connectable.hs 10 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Interconnect.hs 11 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Option.hs 12 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/PulseWire.hs 13 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/PulseReg.hs 14 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Queue.hs 15 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Recipe.hs 16 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/SourceSink.hs 17 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Stmt.hs 18 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Stack.hs 19 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Stream.hs 20 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/TaggedUnion.hs 21 | BLARNEY_TOP_MODULES_SRC += $(SRC_DIR)/Blarney/Vector.hs 22 | 23 | all: ghc-build blc-build 24 | 25 | ghc-build: 26 | ghc --make \ 27 | -hidir $(HI_DIR) -odir $(O_DIR) -i$(SRC_DIR) \ 28 | -Wno-partial-type-signatures \ 29 | $(BLARNEY_TOP_MODULES_SRC) 30 | 31 | blc-build: 32 | BLARNEY_ROOT=$(BLARNEY_ROOT) blc --make \ 33 | -hidir $(HI_DIR) -odir $(O_DIR) -i$(SRC_DIR) \ 34 | $(BLARNEY_TOP_MODULES_SRC) 35 | 36 | .PHONY: clean 37 | clean: 38 | #rm -f $(shell find Haskell -regex ".*\.\(hi\|o\)$$") 39 | rm -rf $(BUILD_DIR) 40 | rm -rf Haskell/BlarneyPlugins/Namer/dist 41 | make -C Examples clean 42 | cabal clean 43 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :source-highlighter: 2 | 3 | ++++ 4 |
5 | ++++ 6 | 7 | image::blarney-logo.svg#gh-light-mode-only[Blarney logo, width=275] 8 | image::blarney-logo-dark.svg#gh-dark-mode-only[Blarney logo, width=275] 9 | 10 | ++++ 11 |
12 | ++++ 13 | 14 | Blarney is a Haskell library for hardware description that builds a 15 | range of HDL abstractions on top of a small set of pure functional 16 | circuit primitives. It is a modern variant of 17 | http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.110.5587&rep=rep1&type=pdf[Lava] 18 | using many of the latest features of GHC. Some aspects of the library 19 | are also inspired by https://github.com/B-Lang-org/bsc[Bluespec], such 20 | as first-class actions and method-based interfaces. 21 | 22 | == Prerequisites 23 | 24 | We'll need Verilator and GHC 9.2.1 or later. 25 | 26 | On Ubuntu 20.04, we can do: 27 | 28 | [source, shell] 29 | ---- 30 | $ sudo apt install verilator libgmp-dev 31 | ---- 32 | 33 | For GHC 9.2.1 or later, https://www.haskell.org/ghcup/[ghcup] can be 34 | used. 35 | 36 | == Quick start 37 | 38 | To clone the repo: 39 | 40 | [source, shell] 41 | ---- 42 | $ git clone --recursive https://github.com/blarney-lang/blarney 43 | ---- 44 | 45 | To simulate the 46 | https://github.com/blarney-lang/blarney/tree/master/Examples/Sorter/Sorter.hs[Sorter] 47 | example from Blarney's 48 | https://github.com/blarney-lang/blarney/tree/master/Examples[Examples] 49 | directory: 50 | 51 | [source, shell] 52 | ---- 53 | $ cd blarney/Examples/Sorter 54 | $ make # Build the example using GHC 55 | $ ./Sorter # Generate Verilog for the example 56 | $ cd Sorter-Verilog # Go to the generated Verilog 57 | $ make # Compile the generated Verilog using Verilator 58 | $ ./Sorter # Simulate the generated Verilog 59 | ---- 60 | 61 | You should see the output: 62 | 63 | ---- 64 | sort [3,4,1,0,2] = [0,1,2,3,4] 65 | ---- 66 | 67 | To run the regression test suite: 68 | 69 | [source, shell] 70 | ---- 71 | $ cd blarney/Test 72 | $ ./test.sh --run-all 73 | ---- 74 | 75 | To start development of your own Blarney application or library, take 76 | a look at the 77 | https://github.com/blarney-lang/template-project/[Blarney template project]. 78 | 79 | == Documentation 80 | 81 | See 82 | https://github.com/blarney-lang/blarney/blob/master/Doc/ByExample.adoc[Blarney 83 | by Example], our introduction to Blarney, which supplements the 84 | http://blarney-lang.github.io/blarney/index.html[Haddock docs]. 85 | 86 | == Applications 87 | 88 | Our current list of applications developed using Blarney: 89 | 90 | * https://github.com/blarney-lang/actora/[Actora]: A 3-stage stack 91 | processor that runs code written a subset of Erlang. It has higher 92 | performance density than Intel's register-based NIOS-II core for 93 | compiled Erlang code. 94 | 95 | * https://github.com/CTSRD-CHERI/SIMTight/[SIMTight]: A 96 | https://cheri-cpu.org[CHERI]-enabled 97 | RISC-V GPGPU with dynamic scalarisation features and high performance 98 | density on Intel's Stratix 10 FPGA. 99 | 100 | * https://github.com/blarney-lang/five/[Five]: A formally verified 101 | implementation of the classic 5-stage RISC pipeline as an abstract component, 102 | largely independent of any specific instruction set. 103 | 104 | * https://github.com/blarney-lang/five-alive/[FiveAlive]: A proof-of-concept 105 | instantiation of the https://github.com/blarney-lang/five/[Five] pipeline with 106 | the RISC-V instruction set to give a simple 32-bit microcontroller. 107 | -------------------------------------------------------------------------------- /Scripts/blc: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | if [ -z "$BLARNEY_ROOT" ]; then 4 | echo "Please set BLARNEY_ROOT" 5 | exit 1 6 | fi 7 | 8 | # Extract command-line flags/arguments 9 | POSITIONAL=() 10 | while [[ $# -gt 0 ]]; do 11 | key="$1" 12 | case $key in 13 | --enable-namer-plugin) 14 | USE_NAMER_PLUGIN="YES" 15 | shift # past argument 16 | ;; 17 | *) 18 | POSITIONAL+=("$1") # save it in an array for later 19 | shift # past argument 20 | ;; 21 | esac 22 | done 23 | set -- "${POSITIONAL[@]}" # restore positional parameters 24 | 25 | if [ -z "$1" ]; then 26 | echo "Usage: blc [FLAGS] [FILE].hs" 27 | echo "Supported flags:" 28 | echo " --enable-namer-plugin Enable Namer plugin" 29 | exit 1 30 | fi 31 | 32 | GHC="ghc --make" 33 | if [ `basename $0` == "blci" ]; then 34 | GHC="ghci" 35 | fi 36 | EXTS="-XGHC2021 \ 37 | -XBlockArguments \ 38 | -XDataKinds \ 39 | -XDeriveAnyClass \ 40 | -XDerivingStrategies \ 41 | -XDuplicateRecordFields \ 42 | -XMultiWayIf \ 43 | -XNoImplicitPrelude \ 44 | -XNoStarIsType \ 45 | -XOverloadedRecordDot \ 46 | -XOverloadedLabels \ 47 | -XPartialTypeSignatures \ 48 | -XRebindableSyntax \ 49 | -XRecursiveDo \ 50 | -XTypeFamilies \ 51 | " 52 | WARN="-Wno-partial-type-signatures" 53 | FLAGS="-fno-cse -fno-full-laziness" 54 | if [ "$USE_NAMER_PLUGIN" = "YES" ]; then 55 | FLAGS="$FLAGS -package blarney-plugins-namer -fplugin=BlarneyPlugins.Namer" 56 | fi 57 | INC="$BLARNEY_ROOT/Haskell" 58 | INC_H="$BLARNEY_ROOT/Haskell/Blarney/:./" 59 | 60 | $GHC $FLAGS $WARN -cpp -I$INC_H $EXTS -i$INC $@ 61 | -------------------------------------------------------------------------------- /Scripts/blci: -------------------------------------------------------------------------------- 1 | blc -------------------------------------------------------------------------------- /Verilog/Altera/BlockRAM.v: -------------------------------------------------------------------------------- 1 | // Copyright (C) 1991-2016 Altera Corporation 2 | // 3 | // Your use of Altera Corporation's design tools, logic functions 4 | // and other software and tools, and its AMPP partner logic 5 | // functions, and any output files from any of the foregoing 6 | // (including device programming or simulation files), and any 7 | // associated documentation or information are expressly subject 8 | // to the terms and conditions of the Altera Program License 9 | // Subscription Agreement, Altera MegaCore Function License 10 | // Agreement, or other applicable license agreement, including, 11 | // without limitation, that your use is for the sole purpose of 12 | // programming logic devices manufactured by Altera and sold by 13 | // Altera or its authorized distributors. Please refer to the 14 | // applicable agreement for further details. 15 | 16 | // Generated by Quartus. 17 | // With edits from Matthew Naylor, June 2016. 18 | 19 | // Single-port block RAM 20 | // ===================== 21 | 22 | module BlockRAM ( 23 | CLK, // Clock 24 | DI, // Data in 25 | ADDR, // Read address 26 | WE, // Write enable 27 | RE, // Read enable 28 | DO // Data out 29 | ); 30 | 31 | parameter ADDR_WIDTH = 1; 32 | parameter DATA_WIDTH = 1; 33 | parameter NUM_ELEMS = 1; 34 | parameter DO_REG = "UNREGISTERED"; // Or: "CLOCK0" 35 | parameter INIT_FILE = "UNUSED"; 36 | parameter DEV_FAMILY = "Stratix V"; 37 | 38 | input CLK; 39 | input [DATA_WIDTH-1:0] DI; 40 | input [ADDR_WIDTH-1:0] ADDR; 41 | input WE, RE; 42 | output [DATA_WIDTH-1:0] DO; 43 | `ifndef ALTERA_RESERVED_QIS 44 | // synopsys translate_off 45 | `endif 46 | tri1 CLK, RE; 47 | tri0 WE; 48 | `ifndef ALTERA_RESERVED_QIS 49 | // synopsys translate_on 50 | `endif 51 | 52 | altsyncram altsyncram_component ( 53 | .address_a (ADDR), 54 | .clock0 (CLK), 55 | .data_a (DI), 56 | .wren_a (WE), 57 | .q_a (DO), 58 | .aclr0 (1'b0), 59 | .aclr1 (1'b0), 60 | .address_b (1'b1), 61 | .addressstall_a (1'b0), 62 | .addressstall_b (1'b0), 63 | .byteena_a (1'b1), 64 | .byteena_b (1'b1), 65 | .clock1 (1'b1), 66 | .clocken0 (1'b1), 67 | .clocken1 (1'b1), 68 | .clocken2 (1'b1), 69 | .clocken3 (1'b1), 70 | .data_b (1'b1), 71 | .eccstatus (), 72 | .q_b (), 73 | .rden_a (RE), 74 | .rden_b (1'b1), 75 | .wren_b (1'b0)); 76 | defparam 77 | altsyncram_component.clock_enable_input_a = "BYPASS", 78 | altsyncram_component.clock_enable_output_a = "BYPASS", 79 | altsyncram_component.init_file = INIT_FILE, 80 | altsyncram_component.intended_device_family = DEV_FAMILY, 81 | altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", 82 | altsyncram_component.lpm_type = "altsyncram", 83 | altsyncram_component.numwords_a = 2**ADDR_WIDTH, 84 | altsyncram_component.operation_mode = "SINGLE_PORT", 85 | altsyncram_component.outdata_aclr_a = "NONE", 86 | altsyncram_component.outdata_reg_a = DO_REG, 87 | altsyncram_component.power_up_uninitialized = "FALSE", 88 | altsyncram_component.read_during_write_mode_port_a = "DONT_CARE", 89 | altsyncram_component.widthad_a = ADDR_WIDTH, 90 | altsyncram_component.width_a = DATA_WIDTH, 91 | altsyncram_component.width_byteena_a = 1; 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /Verilog/Altera/BlockRAMBE.v: -------------------------------------------------------------------------------- 1 | // Copyright (C) 1991-2016 Altera Corporation 2 | // 3 | // Your use of Altera Corporation's design tools, logic functions 4 | // and other software and tools, and its AMPP partner logic 5 | // functions, and any output files from any of the foregoing 6 | // (including device programming or simulation files), and any 7 | // associated documentation or information are expressly subject 8 | // to the terms and conditions of the Altera Program License 9 | // Subscription Agreement, Altera MegaCore Function License 10 | // Agreement, or other applicable license agreement, including, 11 | // without limitation, that your use is for the sole purpose of 12 | // programming logic devices manufactured by Altera and sold by 13 | // Altera or its authorized distributors. Please refer to the 14 | // applicable agreement for further details. 15 | 16 | // Generated by Quartus. 17 | // With edits from Matthew Naylor, June 2016. 18 | 19 | // Single-port block RAM with byte enables 20 | // ======================================= 21 | 22 | module BlockRAMBE ( 23 | CLK, // Clock 24 | DI, // Data in 25 | ADDR, // Read address 26 | WE, // Write enable 27 | RE, // Read enable 28 | BE, // Byte enable 29 | DO // Data out 30 | ); 31 | 32 | parameter ADDR_WIDTH = 1; 33 | parameter DATA_WIDTH = 1; 34 | parameter BE_WIDTH = DATA_WIDTH/8; 35 | parameter NUM_ELEMS = 1; 36 | parameter DO_REG = "UNREGISTERED"; // Or: "CLOCK0" 37 | parameter INIT_FILE = "UNUSED"; 38 | parameter DEV_FAMILY = "Stratix V"; 39 | 40 | input CLK; 41 | input [DATA_WIDTH-1:0] DI; 42 | input [ADDR_WIDTH-1:0] ADDR; 43 | input WE, RE; 44 | input [BE_WIDTH-1:0] BE; 45 | output [DATA_WIDTH-1:0] DO; 46 | `ifndef ALTERA_RESERVED_QIS 47 | // synopsys translate_off 48 | `endif 49 | tri1 CLK, RE; 50 | tri0 WE; 51 | `ifndef ALTERA_RESERVED_QIS 52 | // synopsys translate_on 53 | `endif 54 | 55 | altsyncram altsyncram_component ( 56 | .address_a (ADDR), 57 | .clock0 (CLK), 58 | .data_a (DI), 59 | .wren_a (WE), 60 | .q_a (DO), 61 | .aclr0 (1'b0), 62 | .aclr1 (1'b0), 63 | .address_b (1'b1), 64 | .addressstall_a (1'b0), 65 | .addressstall_b (1'b0), 66 | .byteena_a (BE), 67 | .byteena_b (1'b1), 68 | .clock1 (1'b1), 69 | .clocken0 (1'b1), 70 | .clocken1 (1'b1), 71 | .clocken2 (1'b1), 72 | .clocken3 (1'b1), 73 | .data_b (1'b1), 74 | .eccstatus (), 75 | .q_b (), 76 | .rden_a (RE), 77 | .rden_b (1'b1), 78 | .wren_b (1'b0)); 79 | defparam 80 | altsyncram_component.clock_enable_input_a = "BYPASS", 81 | altsyncram_component.clock_enable_output_a = "BYPASS", 82 | altsyncram_component.init_file = INIT_FILE, 83 | altsyncram_component.intended_device_family = DEV_FAMILY, 84 | altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", 85 | altsyncram_component.lpm_type = "altsyncram", 86 | altsyncram_component.numwords_a = 2**ADDR_WIDTH, 87 | altsyncram_component.operation_mode = "SINGLE_PORT", 88 | altsyncram_component.outdata_aclr_a = "NONE", 89 | altsyncram_component.outdata_reg_a = DO_REG, 90 | altsyncram_component.power_up_uninitialized = "FALSE", 91 | altsyncram_component.read_during_write_mode_port_a = "DONT_CARE", 92 | altsyncram_component.widthad_a = ADDR_WIDTH, 93 | altsyncram_component.width_a = DATA_WIDTH, 94 | altsyncram_component.width_byteena_a = BE_WIDTH; 95 | 96 | endmodule 97 | -------------------------------------------------------------------------------- /Verilog/Altera/BlockRAMDual.v: -------------------------------------------------------------------------------- 1 | // Copyright (C) 1991-2016 Altera Corporation 2 | // 3 | // Your use of Altera Corporation's design tools, logic functions 4 | // and other software and tools, and its AMPP partner logic 5 | // functions, and any output files from any of the foregoing 6 | // (including device programming or simulation files), and any 7 | // associated documentation or information are expressly subject 8 | // to the terms and conditions of the Altera Program License 9 | // Subscription Agreement, Altera MegaCore Function License 10 | // Agreement, or other applicable license agreement, including, 11 | // without limitation, that your use is for the sole purpose of 12 | // programming logic devices manufactured by Altera and sold by 13 | // Altera or its authorized distributors. Please refer to the 14 | // applicable agreement for further details. 15 | 16 | // Generated by Quartus. 17 | // With edits from Matthew Naylor, June 2016. 18 | 19 | // Dual-port block RAM 20 | // =================== 21 | 22 | module BlockRAMDual ( 23 | CLK, // Clock 24 | DI, // Data in 25 | RD_ADDR, // Read address 26 | WR_ADDR, // Write address 27 | WE, // Write enable 28 | RE, // Read enable 29 | DO // Data out 30 | ); 31 | 32 | parameter ADDR_WIDTH = 1; 33 | parameter DATA_WIDTH = 1; 34 | parameter NUM_ELEMS = 2**ADDR_WIDTH; 35 | parameter RD_DURING_WR = "DONT_CARE"; // Or: "OLD_DATA" 36 | parameter DO_REG = "UNREGISTERED"; // Or: "CLOCK0" 37 | parameter INIT_FILE = "UNUSED"; 38 | parameter DEV_FAMILY = "Stratix V"; 39 | parameter STYLE = "AUTO"; 40 | 41 | input CLK; 42 | input [DATA_WIDTH-1:0] DI; 43 | input [ADDR_WIDTH-1:0] RD_ADDR; 44 | input [ADDR_WIDTH-1:0] WR_ADDR; 45 | input WE, RE; 46 | output [DATA_WIDTH-1:0] DO; 47 | `ifndef ALTERA_RESERVED_QIS 48 | // synopsys translate_off 49 | `endif 50 | tri1 CLK, RE; 51 | tri0 WE; 52 | `ifndef ALTERA_RESERVED_QIS 53 | // synopsys translate_on 54 | `endif 55 | 56 | altsyncram altsyncram_component ( 57 | .address_a (WR_ADDR), 58 | .byteena_a (1'b1), 59 | .clock0 (CLK), 60 | .data_a (DI), 61 | .wren_a (WE), 62 | .address_b (RD_ADDR), 63 | .q_b (DO), 64 | .aclr0 (1'b0), 65 | .aclr1 (1'b0), 66 | .addressstall_a (1'b0), 67 | .addressstall_b (1'b0), 68 | .byteena_b (-1), 69 | .clock1 (1'b1), 70 | .clocken0 (1'b1), 71 | .clocken1 (1'b1), 72 | .clocken2 (1'b1), 73 | .clocken3 (1'b1), 74 | .data_b (-1), 75 | .eccstatus (), 76 | .q_a (), 77 | .rden_a (1'b1), 78 | .rden_b (RE), 79 | .wren_b (1'b0)); 80 | defparam 81 | altsyncram_component.address_aclr_b = "NONE", 82 | altsyncram_component.address_reg_b = "CLOCK0", 83 | altsyncram_component.clock_enable_input_a = "BYPASS", 84 | altsyncram_component.clock_enable_input_b = "BYPASS", 85 | altsyncram_component.clock_enable_output_b = "BYPASS", 86 | altsyncram_component.init_file = INIT_FILE, 87 | altsyncram_component.intended_device_family = DEV_FAMILY, 88 | altsyncram_component.lpm_type = "altsyncram", 89 | altsyncram_component.numwords_a = NUM_ELEMS, 90 | altsyncram_component.numwords_b = NUM_ELEMS, 91 | altsyncram_component.operation_mode = "DUAL_PORT", 92 | altsyncram_component.outdata_aclr_b = "NONE", 93 | altsyncram_component.outdata_reg_b = DO_REG, 94 | altsyncram_component.rdcontrol_reg_b = "CLOCK0", 95 | altsyncram_component.power_up_uninitialized = "FALSE", 96 | altsyncram_component.read_during_write_mode_mixed_ports = RD_DURING_WR, 97 | altsyncram_component.widthad_a = ADDR_WIDTH, 98 | altsyncram_component.widthad_b = ADDR_WIDTH, 99 | altsyncram_component.width_a = DATA_WIDTH, 100 | altsyncram_component.width_b = DATA_WIDTH, 101 | altsyncram_component.width_byteena_a = 1, 102 | altsyncram_component.ram_block_type = STYLE; 103 | endmodule 104 | -------------------------------------------------------------------------------- /Verilog/Altera/BlockRAMDualBE.v: -------------------------------------------------------------------------------- 1 | // Copyright (C) 1991-2016 Altera Corporation 2 | // 3 | // Your use of Altera Corporation's design tools, logic functions 4 | // and other software and tools, and its AMPP partner logic 5 | // functions, and any output files from any of the foregoing 6 | // (including device programming or simulation files), and any 7 | // associated documentation or information are expressly subject 8 | // to the terms and conditions of the Altera Program License 9 | // Subscription Agreement, Altera MegaCore Function License 10 | // Agreement, or other applicable license agreement, including, 11 | // without limitation, that your use is for the sole purpose of 12 | // programming logic devices manufactured by Altera and sold by 13 | // Altera or its authorized distributors. Please refer to the 14 | // applicable agreement for further details. 15 | 16 | // Generated by Quartus. 17 | // With edits from Matthew Naylor, June 2016. 18 | 19 | // Dual-port block RAM with byte enables 20 | // ===================================== 21 | 22 | module BlockRAMDualBE ( 23 | CLK, // Clock 24 | DI, // Data in 25 | RD_ADDR, // Read address 26 | WR_ADDR, // Write address 27 | WE, // Write enable 28 | RE, // Read enable 29 | BE, // Byte enable 30 | DO // Data out 31 | ); 32 | 33 | parameter ADDR_WIDTH = 1; 34 | parameter DATA_WIDTH = 1; 35 | parameter BE_WIDTH = DATA_WIDTH/8; 36 | parameter NUM_ELEMS = 2**ADDR_WIDTH; 37 | parameter RD_DURING_WR = "DONT_CARE"; // Or: "OLD_DATA" 38 | parameter DO_REG = "UNREGISTERED"; // Or: "CLOCK0" 39 | parameter INIT_FILE = "UNUSED"; 40 | parameter DEV_FAMILY = "Stratix V"; 41 | parameter STYLE = "AUTO"; 42 | 43 | input CLK; 44 | input [DATA_WIDTH-1:0] DI; 45 | input [ADDR_WIDTH-1:0] RD_ADDR; 46 | input [ADDR_WIDTH-1:0] WR_ADDR; 47 | input WE, RE; 48 | input [BE_WIDTH-1:0] BE; 49 | output [DATA_WIDTH-1:0] DO; 50 | `ifndef ALTERA_RESERVED_QIS 51 | // synopsys translate_off 52 | `endif 53 | tri1 CLK, RE; 54 | tri0 WE; 55 | `ifndef ALTERA_RESERVED_QIS 56 | // synopsys translate_on 57 | `endif 58 | 59 | altsyncram altsyncram_component ( 60 | .address_a (WR_ADDR), 61 | .byteena_a (BE), 62 | .clock0 (CLK), 63 | .data_a (DI), 64 | .wren_a (WE), 65 | .address_b (RD_ADDR), 66 | .q_b (DO), 67 | .aclr0 (1'b0), 68 | .aclr1 (1'b0), 69 | .addressstall_a (1'b0), 70 | .addressstall_b (1'b0), 71 | .byteena_b (-1), 72 | .clock1 (1'b1), 73 | .clocken0 (1'b1), 74 | .clocken1 (1'b1), 75 | .clocken2 (1'b1), 76 | .clocken3 (1'b1), 77 | .data_b (-1), 78 | .eccstatus (), 79 | .q_a (), 80 | .rden_a (1'b1), 81 | .rden_b (RE), 82 | .wren_b (1'b0)); 83 | defparam 84 | altsyncram_component.address_aclr_b = "NONE", 85 | altsyncram_component.address_reg_b = "CLOCK0", 86 | altsyncram_component.clock_enable_input_a = "BYPASS", 87 | altsyncram_component.clock_enable_input_b = "BYPASS", 88 | altsyncram_component.clock_enable_output_b = "BYPASS", 89 | altsyncram_component.init_file = INIT_FILE, 90 | altsyncram_component.intended_device_family = DEV_FAMILY, 91 | altsyncram_component.lpm_type = "altsyncram", 92 | altsyncram_component.numwords_a = NUM_ELEMS, 93 | altsyncram_component.numwords_b = NUM_ELEMS, 94 | altsyncram_component.operation_mode = "DUAL_PORT", 95 | altsyncram_component.outdata_aclr_b = "NONE", 96 | altsyncram_component.outdata_reg_b = DO_REG, 97 | altsyncram_component.power_up_uninitialized = "FALSE", 98 | altsyncram_component.rdcontrol_reg_b = "CLOCK0", 99 | altsyncram_component.read_during_write_mode_mixed_ports = RD_DURING_WR, 100 | altsyncram_component.widthad_a = ADDR_WIDTH, 101 | altsyncram_component.widthad_b = ADDR_WIDTH, 102 | altsyncram_component.width_a = DATA_WIDTH, 103 | altsyncram_component.width_b = DATA_WIDTH, 104 | altsyncram_component.width_byteena_a = BE_WIDTH, 105 | altsyncram_component.ram_block_type = STYLE; 106 | endmodule 107 | -------------------------------------------------------------------------------- /Verilog/Altera/BlockRAMTrueDual.v: -------------------------------------------------------------------------------- 1 | // Copyright (C) 1991-2016 Altera Corporation 2 | // 3 | // Your use of Altera Corporation's design tools, logic functions 4 | // and other software and tools, and its AMPP partner logic 5 | // functions, and any output files from any of the foregoing 6 | // (including device programming or simulation files), and any 7 | // associated documentation or information are expressly subject 8 | // to the terms and conditions of the Altera Program License 9 | // Subscription Agreement, Altera MegaCore Function License 10 | // Agreement, or other applicable license agreement, including, 11 | // without limitation, that your use is for the sole purpose of 12 | // programming logic devices manufactured by Altera and sold by 13 | // Altera or its authorized distributors. Please refer to the 14 | // applicable agreement for further details. 15 | 16 | // Generated by Quartus. 17 | // With edits from Matthew Naylor, June 2016. 18 | 19 | // True dual-port block RAM 20 | // ======================== 21 | 22 | module BlockRAMTrueDual ( 23 | CLK, // Clock 24 | DI_A, // Data in 25 | ADDR_A, // Read address 26 | WE_A, // Write enable 27 | RE_A, // Read enable 28 | DO_A, // Data out 29 | DI_B, // Data in 30 | ADDR_B, // Read address 31 | WE_B, // Write enable 32 | RE_B, // Read enable 33 | DO_B // Data out 34 | ); 35 | 36 | parameter ADDR_WIDTH = 1; 37 | parameter DATA_WIDTH = 1; 38 | parameter NUM_ELEMS = 1; 39 | parameter RD_DURING_WR = "DONT_CARE"; 40 | parameter DO_REG_A = "UNREGISTERED"; // Or: "CLOCK0" 41 | parameter DO_REG_B = "UNREGISTERED"; // Or: "CLOCK0" 42 | parameter INIT_FILE = "UNUSED"; 43 | parameter DEV_FAMILY = "Stratix V"; 44 | 45 | input [(DATA_WIDTH-1):0] DI_A, DI_B; 46 | input [(ADDR_WIDTH-1):0] ADDR_A, ADDR_B; 47 | input WE_A, WE_B, RE_A, RE_B, CLK; 48 | output [(DATA_WIDTH-1):0] DO_A, DO_B; 49 | `ifndef ALTERA_RESERVED_QIS 50 | // synopsys translate_off 51 | `endif 52 | tri1 CLK, RE_A, RE_B; 53 | tri0 WE_A, WE_B; 54 | `ifndef ALTERA_RESERVED_QIS 55 | // synopsys translate_on 56 | `endif 57 | 58 | altera_syncram altsyncram_component ( 59 | .address_a (ADDR_A), 60 | .address_b (ADDR_B), 61 | .byteena_a (1'b1), 62 | .byteena_b (1'b1), 63 | .clock0 (CLK), 64 | .data_a (DI_A), 65 | .data_b (DI_B), 66 | .rden_a (RE_A), 67 | .rden_b (RE_B), 68 | .wren_a (WE_A), 69 | .wren_b (WE_B), 70 | .q_a (DO_A), 71 | .q_b (DO_B), 72 | .aclr0 (1'b0), 73 | .aclr1 (1'b0), 74 | .address2_a (1'b1), 75 | .address2_b (1'b1), 76 | .addressstall_a (1'b0), 77 | .addressstall_b (1'b0), 78 | .clock1 (1'b1), 79 | .clocken0 (1'b1), 80 | .clocken1 (1'b1), 81 | .clocken2 (1'b1), 82 | .clocken3 (1'b1), 83 | .eccencbypass (1'b0), 84 | .eccencparity (8'b0), 85 | .eccstatus (), 86 | .sclr (1'b0)); 87 | defparam 88 | altsyncram_component.address_reg_b = "CLOCK0", 89 | altsyncram_component.byteena_reg_b = "CLOCK0", 90 | altsyncram_component.byte_size = 8, 91 | altsyncram_component.clock_enable_input_a = "BYPASS", 92 | altsyncram_component.clock_enable_input_b = "BYPASS", 93 | altsyncram_component.clock_enable_output_a = "BYPASS", 94 | altsyncram_component.clock_enable_output_b = "BYPASS", 95 | altsyncram_component.init_file = INIT_FILE, 96 | altsyncram_component.init_file_layout = "PORT_A", 97 | altsyncram_component.indata_reg_b = "CLOCK0", 98 | altsyncram_component.intended_device_family = DEV_FAMILY, 99 | altsyncram_component.lpm_type = "altera_syncram", 100 | altsyncram_component.numwords_a = 2**ADDR_WIDTH, 101 | altsyncram_component.numwords_b = 2**ADDR_WIDTH, 102 | altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", 103 | altsyncram_component.outdata_aclr_a = "NONE", 104 | altsyncram_component.outdata_aclr_b = "NONE", 105 | altsyncram_component.outdata_reg_a = DO_REG_A, 106 | altsyncram_component.outdata_reg_b = DO_REG_B, 107 | altsyncram_component.power_up_uninitialized = "FALSE", 108 | altsyncram_component.read_during_write_mode_mixed_ports = RD_DURING_WR, 109 | altsyncram_component.read_during_write_mode_port_a = "DONT_CARE", 110 | altsyncram_component.read_during_write_mode_port_b = "DONT_CARE", 111 | altsyncram_component.widthad_a = ADDR_WIDTH, 112 | altsyncram_component.widthad_b = ADDR_WIDTH, 113 | altsyncram_component.width_a = DATA_WIDTH, 114 | altsyncram_component.width_b = DATA_WIDTH, 115 | altsyncram_component.width_byteena_a = 1, 116 | altsyncram_component.width_byteena_b = 1; 117 | 118 | endmodule 119 | -------------------------------------------------------------------------------- /Verilog/Altera/BlockRAMTrueDualBE.v: -------------------------------------------------------------------------------- 1 | // Copyright (C) 1991-2016 Altera Corporation 2 | // 3 | // Your use of Altera Corporation's design tools, logic functions 4 | // and other software and tools, and its AMPP partner logic 5 | // functions, and any output files from any of the foregoing 6 | // (including device programming or simulation files), and any 7 | // associated documentation or information are expressly subject 8 | // to the terms and conditions of the Altera Program License 9 | // Subscription Agreement, Altera MegaCore Function License 10 | // Agreement, or other applicable license agreement, including, 11 | // without limitation, that your use is for the sole purpose of 12 | // programming logic devices manufactured by Altera and sold by 13 | // Altera or its authorized distributors. Please refer to the 14 | // applicable agreement for further details. 15 | 16 | // Generated by Quartus. 17 | // With edits from Matthew Naylor, June 2016. 18 | 19 | // True dual-port block RAM with byte enables 20 | // ========================================== 21 | 22 | module BlockRAMTrueDualBE ( 23 | CLK, // Clock 24 | DI_A, // Data in 25 | ADDR_A, // Read address 26 | WE_A, // Write enable 27 | RE_A, // Read enable 28 | BE_A, // Byte enable 29 | DO_A, // Data out 30 | DI_B, // Data in 31 | ADDR_B, // Read address 32 | WE_B, // Write enable 33 | RE_B, // Read enable 34 | BE_B, // Byte enable 35 | DO_B // Data out 36 | ); 37 | 38 | parameter ADDR_WIDTH = 1; 39 | parameter DATA_WIDTH = 1; 40 | parameter BE_WIDTH = DATA_WIDTH/8; 41 | parameter NUM_ELEMS = 1; 42 | parameter RD_DURING_WR = "DONT_CARE"; 43 | parameter DO_REG_A = "UNREGISTERED"; // Or: "CLOCK0" 44 | parameter DO_REG_B = "UNREGISTERED"; // Or: "CLOCK0" 45 | parameter INIT_FILE = "UNUSED"; 46 | parameter DEV_FAMILY = "Stratix V"; 47 | 48 | input [(DATA_WIDTH-1):0] DI_A, DI_B; 49 | input [(ADDR_WIDTH-1):0] ADDR_A, ADDR_B; 50 | input WE_A, WE_B, RE_A, RE_B, CLK; 51 | input [BE_WIDTH-1:0] BE_A, BE_B; 52 | output [(DATA_WIDTH-1):0] DO_A, DO_B; 53 | `ifndef ALTERA_RESERVED_QIS 54 | // synopsys translate_off 55 | `endif 56 | tri1 CLK, RE_A, RE_B; 57 | tri0 WE_A, WE_B; 58 | `ifndef ALTERA_RESERVED_QIS 59 | // synopsys translate_on 60 | `endif 61 | 62 | altera_syncram altsyncram_component ( 63 | .address_a (ADDR_A), 64 | .address_b (ADDR_B), 65 | .byteena_a (BE_A), 66 | .byteena_b (BE_B), 67 | .clock0 (CLK), 68 | .data_a (DI_A), 69 | .data_b (DI_B), 70 | .rden_a (RE_A), 71 | .rden_b (RE_B), 72 | .wren_a (WE_A), 73 | .wren_b (WE_B), 74 | .q_a (DO_A), 75 | .q_b (DO_B), 76 | .aclr0 (1'b0), 77 | .aclr1 (1'b0), 78 | .address2_a (1'b1), 79 | .address2_b (1'b1), 80 | .addressstall_a (1'b0), 81 | .addressstall_b (1'b0), 82 | .clock1 (1'b1), 83 | .clocken0 (1'b1), 84 | .clocken1 (1'b1), 85 | .clocken2 (1'b1), 86 | .clocken3 (1'b1), 87 | .eccencbypass (1'b0), 88 | .eccencparity (8'b0), 89 | .eccstatus (), 90 | .sclr (1'b0)); 91 | defparam 92 | altsyncram_component.address_reg_b = "CLOCK0", 93 | altsyncram_component.byteena_reg_b = "CLOCK0", 94 | altsyncram_component.byte_size = 8, 95 | altsyncram_component.clock_enable_input_a = "BYPASS", 96 | altsyncram_component.clock_enable_input_b = "BYPASS", 97 | altsyncram_component.clock_enable_output_a = "BYPASS", 98 | altsyncram_component.clock_enable_output_b = "BYPASS", 99 | altsyncram_component.init_file = INIT_FILE, 100 | altsyncram_component.init_file_layout = "PORT_A", 101 | altsyncram_component.indata_reg_b = "CLOCK0", 102 | altsyncram_component.intended_device_family = DEV_FAMILY, 103 | altsyncram_component.lpm_type = "altera_syncram", 104 | altsyncram_component.numwords_a = 2**ADDR_WIDTH, 105 | altsyncram_component.numwords_b = 2**ADDR_WIDTH, 106 | altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", 107 | altsyncram_component.outdata_aclr_a = "NONE", 108 | altsyncram_component.outdata_aclr_b = "NONE", 109 | altsyncram_component.outdata_reg_a = DO_REG_A, 110 | altsyncram_component.outdata_reg_b = DO_REG_B, 111 | altsyncram_component.power_up_uninitialized = "FALSE", 112 | altsyncram_component.read_during_write_mode_mixed_ports = RD_DURING_WR, 113 | altsyncram_component.read_during_write_mode_port_a = "DONT_CARE", 114 | altsyncram_component.read_during_write_mode_port_b = "DONT_CARE", 115 | altsyncram_component.widthad_a = ADDR_WIDTH, 116 | altsyncram_component.widthad_b = ADDR_WIDTH, 117 | altsyncram_component.width_a = DATA_WIDTH, 118 | altsyncram_component.width_b = DATA_WIDTH, 119 | altsyncram_component.width_byteena_a = BE_WIDTH, 120 | altsyncram_component.width_byteena_b = BE_WIDTH; 121 | 122 | endmodule 123 | -------------------------------------------------------------------------------- /Verilog/BlockRAM.v: -------------------------------------------------------------------------------- 1 | // Single-port block RAM 2 | // ===================== 3 | 4 | module BlockRAM ( 5 | CLK, // Clock 6 | DI, // Data in 7 | ADDR, // Read address 8 | WE, // Write enable 9 | RE, // Read enable 10 | DO // Data out 11 | ); 12 | 13 | parameter ADDR_WIDTH = 1; 14 | parameter DATA_WIDTH = 1; 15 | parameter INIT_FILE = "UNUSED"; 16 | 17 | input CLK; 18 | input [DATA_WIDTH-1:0] DI; 19 | input [ADDR_WIDTH-1:0] ADDR; 20 | input WE, RE; 21 | output reg [DATA_WIDTH-1:0] DO; 22 | reg [DATA_WIDTH-1:0] RAM[2**ADDR_WIDTH-1:0]; 23 | 24 | generate 25 | if (INIT_FILE != "UNUSED") begin 26 | initial $readmemh(INIT_FILE, RAM); 27 | end else begin 28 | integer i; 29 | initial 30 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 31 | RAM[i] = 0; 32 | end 33 | endgenerate 34 | 35 | always @(posedge CLK) 36 | begin 37 | if (WE) begin 38 | RAM[ADDR] <= DI; 39 | end 40 | if (RE) begin 41 | if (WE) begin 42 | DO <= {DATA_WIDTH{1'hx}}; 43 | end else begin 44 | DO <= RAM[ADDR]; 45 | end 46 | end 47 | end 48 | 49 | endmodule 50 | -------------------------------------------------------------------------------- /Verilog/BlockRAMBE.sv: -------------------------------------------------------------------------------- 1 | // Single-port block RAM with byte enables 2 | // ======================================= 3 | 4 | module BlockRAMBE ( 5 | CLK, // Clock 6 | DI, // Data in 7 | ADDR, // Read address 8 | WE, // Write enable 9 | RE, // Read enable 10 | BE, // Byte enable 11 | DO // Data out 12 | ); 13 | 14 | parameter ADDR_WIDTH = 1; 15 | parameter DATA_WIDTH = 1; 16 | parameter INIT_FILE = "UNUSED"; 17 | parameter BE_WIDTH = DATA_WIDTH/8; 18 | 19 | input CLK; 20 | input [DATA_WIDTH-1:0] DI; 21 | input [ADDR_WIDTH-1:0] ADDR; 22 | input WE, RE; 23 | input [BE_WIDTH-1:0] BE; 24 | output reg [DATA_WIDTH-1:0] DO; 25 | logic [BE_WIDTH-1:0][7:0] RAM[2**ADDR_WIDTH-1:0]; 26 | 27 | generate 28 | if (INIT_FILE != "UNUSED") begin 29 | initial $readmemh(INIT_FILE, RAM); 30 | end else begin 31 | integer i; 32 | initial 33 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 34 | RAM[i] = 0; 35 | end 36 | endgenerate 37 | 38 | generate 39 | for (genvar b = 0; b < BE_WIDTH; b++) begin 40 | always_ff@(posedge CLK) begin 41 | if (WE) begin 42 | if(BE[b]) RAM[ADDR][b] <= DI[((b+1)*8-1):b*8]; 43 | end 44 | end 45 | end 46 | endgenerate 47 | 48 | always_ff@(posedge CLK) begin 49 | if (RE) begin 50 | if (WE) begin 51 | DO <= {DATA_WIDTH{1'hx}}; 52 | end else begin 53 | DO <= RAM[ADDR]; 54 | end 55 | end 56 | end 57 | 58 | endmodule 59 | -------------------------------------------------------------------------------- /Verilog/BlockRAMDual.v: -------------------------------------------------------------------------------- 1 | // Dual-port block RAM 2 | // =================== 3 | 4 | module BlockRAMDual ( 5 | CLK, // Clock 6 | DI, // Data in 7 | RD_ADDR, // Read address 8 | WR_ADDR, // Write address 9 | WE, // Write enable 10 | RE, // Read enable 11 | DO // Data out 12 | ); 13 | 14 | parameter ADDR_WIDTH = 1; 15 | parameter DATA_WIDTH = 1; 16 | parameter INIT_FILE = "UNUSED"; 17 | 18 | input [(DATA_WIDTH-1):0] DI; 19 | input [(ADDR_WIDTH-1):0] RD_ADDR, WR_ADDR; 20 | input WE, RE, CLK; 21 | output reg [(DATA_WIDTH-1):0] DO; 22 | reg [DATA_WIDTH-1:0] RAM[2**ADDR_WIDTH-1:0]; 23 | 24 | generate 25 | if (INIT_FILE != "UNUSED") begin 26 | initial $readmemh(INIT_FILE, RAM); 27 | end else begin 28 | integer i; 29 | initial 30 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 31 | RAM[i] = 0; 32 | end 33 | endgenerate 34 | 35 | always @(posedge CLK) 36 | begin 37 | // Write port 38 | if (WE) begin 39 | RAM[WR_ADDR] <= DI; 40 | end 41 | if (RE) begin 42 | // Read port 43 | DO <= (WE && RD_ADDR == WR_ADDR) ? {DATA_WIDTH{1'hx}} : RAM[RD_ADDR]; 44 | end 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /Verilog/BlockRAMDualBE.sv: -------------------------------------------------------------------------------- 1 | // Dual-port block RAM with byte enables 2 | // ===================================== 3 | 4 | module BlockRAMDualBE ( 5 | CLK, // Clock 6 | DI, // Data in 7 | RD_ADDR, // Read address 8 | WR_ADDR, // Write address 9 | WE, // Write enable 10 | RE, // Read enable 11 | BE, // Byte enable 12 | DO // Data out 13 | ); 14 | 15 | parameter ADDR_WIDTH = 1; 16 | parameter DATA_WIDTH = 1; 17 | parameter INIT_FILE = "UNUSED"; 18 | parameter BE_WIDTH = DATA_WIDTH/8; 19 | 20 | input CLK; 21 | input [DATA_WIDTH-1:0] DI; 22 | input [ADDR_WIDTH-1:0] RD_ADDR, WR_ADDR; 23 | input WE, RE; 24 | input [BE_WIDTH-1:0] BE; 25 | output reg [DATA_WIDTH-1:0] DO; 26 | logic [BE_WIDTH-1:0][7:0] RAM[2**ADDR_WIDTH-1:0]; 27 | 28 | generate 29 | if (INIT_FILE != "UNUSED") begin 30 | initial $readmemh(INIT_FILE, RAM); 31 | end else begin 32 | integer i; 33 | initial 34 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 35 | RAM[i] = 0; 36 | end 37 | endgenerate 38 | 39 | // Write port 40 | generate 41 | for (genvar b = 0; b < BE_WIDTH; b++) begin 42 | always_ff@(posedge CLK) begin 43 | if (WE) begin 44 | if(BE[b]) RAM[WR_ADDR][b] <= DI[((b+1)*8-1):b*8]; 45 | end 46 | end 47 | end 48 | endgenerate 49 | 50 | // Read port 51 | always_ff@(posedge CLK) begin 52 | if (RE) begin 53 | DO <= (WE && RD_ADDR == WR_ADDR) ? {DATA_WIDTH{1'hx}} : RAM[RD_ADDR]; 54 | end 55 | end 56 | 57 | endmodule 58 | -------------------------------------------------------------------------------- /Verilog/BlockRAMQuad.v: -------------------------------------------------------------------------------- 1 | // Quad-port block RAM 2 | // =================== 3 | 4 | module BlockRAMQuad ( 5 | clock, // Clock 6 | reset, // Reset 7 | 8 | DI_A, // Data in 9 | RD_ADDR_A, // Read address 10 | WR_ADDR_A, // Write address 11 | WE_A, // Write enable 12 | RE_A, // Read enable 13 | DO_A, // Data out 14 | 15 | RD_ADDR_B, // Read address 16 | WR_ADDR_B, // Write address 17 | DI_B, // Data in 18 | WE_B, // Write enable 19 | RE_B, // Read enable 20 | DO_B // Data out 21 | ); 22 | 23 | parameter ADDR_WIDTH = 1; 24 | parameter DATA_WIDTH = 1; 25 | parameter INIT_FILE = "UNUSED"; 26 | 27 | input [(DATA_WIDTH-1):0] DI_A, DI_B; 28 | input [(ADDR_WIDTH-1):0] RD_ADDR_A, RD_ADDR_B, WR_ADDR_A, WR_ADDR_B; 29 | input clock, reset, WE_A, WE_B, RE_A, RE_B; 30 | output reg [(DATA_WIDTH-1):0] DO_A; 31 | output reg [(DATA_WIDTH-1):0] DO_B; 32 | reg [DATA_WIDTH-1:0] RAM[2**ADDR_WIDTH-1:0]; 33 | 34 | generate 35 | if (INIT_FILE != "UNUSED") begin 36 | initial $readmemh(INIT_FILE, RAM); 37 | end else begin 38 | integer i; 39 | initial 40 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 41 | RAM[i] = 0; 42 | end 43 | endgenerate 44 | 45 | // Port A 46 | always @(posedge clock) begin 47 | if (WE_A) 48 | RAM[WR_ADDR_A] = DI_A; 49 | end 50 | 51 | always @(posedge clock) begin 52 | if (RE_A) 53 | DO_A <= (WE_A && RD_ADDR_A == WR_ADDR_A) ? 54 | {DATA_WIDTH{1'hx}} : RAM[RD_ADDR_A]; 55 | end 56 | 57 | // Port B 58 | always @(posedge clock) begin 59 | if (WE_B) 60 | RAM[WR_ADDR_B] = DI_B; 61 | end 62 | 63 | always @(posedge clock) begin 64 | if (RE_B) 65 | DO_B <= (WE_B && RD_ADDR_B == WR_ADDR_B) ? 66 | {DATA_WIDTH{1'hx}} : RAM[RD_ADDR_B]; 67 | end 68 | 69 | endmodule 70 | -------------------------------------------------------------------------------- /Verilog/BlockRAMTrueDual.v: -------------------------------------------------------------------------------- 1 | // True dual-port block RAM 2 | // ======================== 3 | 4 | module BlockRAMTrueDual ( 5 | CLK, // Clock 6 | DI_A, // Data in 7 | ADDR_A, // Read address 8 | WE_A, // Write enable 9 | RE_A, // Read enable 10 | DO_A, // Data out 11 | DI_B, // Data in 12 | ADDR_B, // Read address 13 | WE_B, // Write enable 14 | RE_B, // Read enable 15 | DO_B // Data out 16 | ); 17 | 18 | parameter ADDR_WIDTH = 1; 19 | parameter DATA_WIDTH = 1; 20 | parameter INIT_FILE = "UNUSED"; 21 | 22 | input [(DATA_WIDTH-1):0] DI_A, DI_B; 23 | input [(ADDR_WIDTH-1):0] ADDR_A, ADDR_B; 24 | input WE_A, WE_B, RE_A, RE_B, CLK; 25 | output reg [(DATA_WIDTH-1):0] DO_A, DO_B; 26 | reg [DATA_WIDTH-1:0] RAM[2**ADDR_WIDTH-1:0]; 27 | 28 | generate 29 | if (INIT_FILE != "UNUSED") begin 30 | initial $readmemh(INIT_FILE, RAM); 31 | end else begin 32 | integer i; 33 | initial 34 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 35 | RAM[i] = 0; 36 | end 37 | endgenerate 38 | 39 | // Port A 40 | always @(posedge CLK) 41 | begin 42 | if (WE_A) begin 43 | RAM[ADDR_A] <= DI_A; 44 | end 45 | if (RE_A) begin 46 | if (WE_A) begin 47 | DO_A <= {DATA_WIDTH{1'hx}};; 48 | end else begin 49 | DO_A <= (WE_B && ADDR_A == ADDR_B) ? {DATA_WIDTH{1'hx}} : RAM[ADDR_A]; 50 | end 51 | end 52 | end 53 | 54 | // Port B 55 | always @(posedge CLK) 56 | begin 57 | if (WE_B) begin 58 | RAM[ADDR_B] <= DI_B; 59 | end 60 | if (RE_B) begin 61 | if (WE_B) begin 62 | DO_B <= {DATA_WIDTH{1'hx}}; 63 | end else begin 64 | DO_B <= (WE_A && ADDR_A == ADDR_B) ? {DATA_WIDTH{1'hx}} : RAM[ADDR_B]; 65 | end 66 | end 67 | end 68 | 69 | endmodule 70 | -------------------------------------------------------------------------------- /Verilog/BlockRAMTrueDualBE.sv: -------------------------------------------------------------------------------- 1 | // True dual-port block RAM with byte enables 2 | // ========================================== 3 | 4 | module BlockRAMTrueDualBE ( 5 | CLK, // Clock 6 | DI_A, // Data in 7 | ADDR_A, // Read address 8 | WE_A, // Write enable 9 | RE_A, // Read enable 10 | BE_A, // Byte enable 11 | DO_A, // Data out 12 | DI_B, // Data in 13 | ADDR_B, // Read address 14 | WE_B, // Write enable 15 | RE_B, // Read enable 16 | BE_B, // Byte enable 17 | DO_B // Data out 18 | ); 19 | 20 | parameter ADDR_WIDTH = 1; 21 | parameter DATA_WIDTH = 1; 22 | parameter INIT_FILE = "UNUSED"; 23 | parameter BE_WIDTH = DATA_WIDTH/8; 24 | 25 | input CLK; 26 | input [DATA_WIDTH-1:0] DI_A, DI_B; 27 | input [ADDR_WIDTH-1:0] ADDR_A, ADDR_B; 28 | input WE_A, WE_B, RE_A, RE_B; 29 | input [BE_WIDTH-1:0] BE_A, BE_B; 30 | output reg [DATA_WIDTH-1:0] DO_A, DO_B; 31 | logic [BE_WIDTH-1:0][7:0] RAM[2**ADDR_WIDTH-1:0]; 32 | 33 | generate 34 | if (INIT_FILE != "UNUSED") begin 35 | initial $readmemh(INIT_FILE, RAM); 36 | end else begin 37 | integer i; 38 | initial 39 | for (i = 0; i < 2**ADDR_WIDTH; i=i+1) 40 | RAM[i] = 0; 41 | end 42 | endgenerate 43 | 44 | // Port A 45 | generate 46 | for (genvar b = 0; b < BE_WIDTH; b++) begin 47 | always_ff@(posedge CLK) begin 48 | if (WE_A) begin 49 | if(BE_A[b]) RAM[ADDR_A][b] <= DI_A[((b+1)*8-1):b*8]; 50 | end 51 | end 52 | end 53 | endgenerate 54 | 55 | always_ff@(posedge CLK) begin 56 | if (RE_A) begin 57 | if (WE_A) begin 58 | DO_A <= {DATA_WIDTH{1'hx}}; 59 | end else begin 60 | DO_A <= (WE_B && ADDR_A == ADDR_B) ? {DATA_WIDTH{1'hx}} : RAM[ADDR_A]; 61 | end 62 | end 63 | end 64 | 65 | // Port B 66 | generate 67 | for (genvar b = 0; b < BE_WIDTH; b++) begin 68 | always_ff@(posedge CLK) begin 69 | if (WE_B) begin 70 | if(BE_B[b]) RAM[ADDR_B][b] <= DI_B[((b+1)*8-1):b*8]; 71 | end 72 | end 73 | end 74 | endgenerate 75 | 76 | always_ff@(posedge CLK) begin 77 | if (RE_B) begin 78 | if (WE_B) begin 79 | DO_B <= {DATA_WIDTH{1'hx}}; 80 | end else begin 81 | DO_B <= (WE_A && ADDR_A == ADDR_B) ? {DATA_WIDTH{1'hx}} : RAM[ADDR_B]; 82 | end 83 | end 84 | end 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /blarney.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 2.4 2 | name: blarney 3 | version: 0.1.0.0 4 | 5 | flag enable-namer-plugin 6 | description: Enable namer plugin 7 | manual: True 8 | default: False 9 | 10 | library 11 | default-language: GHC2021 12 | default-extensions: 13 | BlockArguments 14 | DataKinds 15 | DeriveAnyClass 16 | DerivingStrategies 17 | DuplicateRecordFields 18 | MultiWayIf 19 | NoImplicitPrelude 20 | NoStarIsType 21 | OverloadedRecordDot 22 | OverloadedLabels 23 | PartialTypeSignatures 24 | RebindableSyntax 25 | RecursiveDo 26 | TypeFamilies 27 | ghc-options: 28 | -fno-cse 29 | -fno-full-laziness 30 | -Wno-partial-type-signatures 31 | hs-source-dirs: Haskell 32 | exposed-modules: 33 | Blarney 34 | Blarney.BitPat 35 | Blarney.BitScan 36 | Blarney.ClientServer 37 | Blarney.Connectable 38 | Blarney.Interconnect 39 | Blarney.Option 40 | Blarney.Prelude 41 | Blarney.PulseReg 42 | Blarney.PulseWire 43 | Blarney.QuadPortRAM 44 | Blarney.Queue 45 | Blarney.Recipe 46 | Blarney.SourceSink 47 | Blarney.Stack 48 | Blarney.Stmt 49 | Blarney.Stream 50 | Blarney.TaggedUnion 51 | Blarney.TypeFamilies 52 | Blarney.Vector 53 | Blarney.Backend 54 | Blarney.Backend.NewSMT 55 | Blarney.Backend.SMT 56 | Blarney.Backend.SMT.BasicDefinitions 57 | Blarney.Backend.SMT.NetlistUtils 58 | Blarney.Backend.SMT.Utils 59 | Blarney.Backend.Simulation 60 | Blarney.Backend.Verilog 61 | Blarney.Core 62 | Blarney.Core.Bit 63 | Blarney.Core.Bits 64 | Blarney.Core.BV 65 | Blarney.Core.ClockReset 66 | Blarney.Core.Common 67 | Blarney.Core.Flatten 68 | Blarney.Core.FShow 69 | Blarney.Core.IfThenElse 70 | Blarney.Core.Interface 71 | Blarney.Core.JList 72 | Blarney.Core.Lookup 73 | Blarney.Core.Module 74 | Blarney.Core.NetHelpers 75 | Blarney.Core.Opts 76 | Blarney.Core.Prim 77 | Blarney.Core.RAM 78 | Blarney.Core.RTL 79 | Blarney.Core.Ternary 80 | Blarney.Core.Utils 81 | Blarney.Misc.ANSIEscapeSequences 82 | Blarney.Misc.MonadLoops 83 | Blarney.Netlist 84 | Blarney.Netlist.Passes 85 | Blarney.Netlist.Passes.ConstantEliminate 86 | Blarney.Netlist.Passes.ConstantFold 87 | Blarney.Netlist.Passes.ConstantPropagate 88 | Blarney.Netlist.Passes.DeadNetEliminate 89 | Blarney.Netlist.Passes.DontCareDeInline 90 | Blarney.Netlist.Passes.NamePropagate 91 | Blarney.Netlist.Passes.NetInline 92 | Blarney.Netlist.Passes.Prune 93 | Blarney.Netlist.Passes.Types 94 | Blarney.Netlist.Passes.Utils 95 | Blarney.Netlist.Passes.ZeroWidthNetIgnore 96 | build-depends: 97 | array 98 | , base 99 | , containers 100 | , async 101 | , ghc-prim 102 | , mtl 103 | , pretty 104 | , process 105 | , transformers 106 | if flag(enable-namer-plugin) 107 | build-depends: 108 | blarney-plugins-namer 109 | ghc-options: 110 | -fplugin BlarneyPlugins.Namer 111 | -------------------------------------------------------------------------------- /blarneyDirs.mk: -------------------------------------------------------------------------------- 1 | ifndef BLARNEY_ROOT 2 | $(error "the BLARNEY_ROOT environment variable must be set") 3 | endif 4 | 5 | SRC_DIR = $(BLARNEY_ROOT)/Haskell 6 | BUILD_DIR = $(BLARNEY_ROOT)/build 7 | O_DIR = $(BUILD_DIR)/odir 8 | HI_DIR = $(BUILD_DIR)/hidir 9 | --------------------------------------------------------------------------------