├── .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 |
--------------------------------------------------------------------------------