FPGA programming without Verilog/VHDL


Xilinx Zynq: PS + PL

Logic cells inside PL


Install Vivado HLx & Linux
- Dockerfile HOWTO (optional)
- MicroZed board definition files
- petalinux SD image
Learn Haskell (if you haven't)
Clash pipeline


module MAC where
import Clash.Prelude
ma :: Int -> Int -> Int -> Int
ma acc x y = acc + x*y
mac (x,y) = z
where
s = register 0 s'
s' = ma <$> s <*> x <*> y
z = s
topEntity
:: Clock System
-> Reset System
-> Enable System
-> Signal System (Int,Int)
-> Signal System Int
topEntity = exposeClockResetEnable (mac . unbundle)
module COUNTDOWN where
import Clash.Prelude
import Data.Maybe
type Reg = Unsigned 32
{-# ANN topEntity
(Synthesize{
t_name = "countdown",
t_inputs = [
PortName "clk",
PortName "rst",
PortName "en",
PortProduct "" [PortName "oR", PortName "iV", PortName "i"]
],
t_output = PortProduct "" [PortName "iR", PortName "oV", PortName "o"]
}) #-}
topEntity
:: Clock System
-> Reset System
-> Enable System
-> Signal System (Bool, Bool, Reg)
-> Signal System (Bool, Bool, Reg)
topEntity = exposeClockResetEnable control
control :: (HiddenClockResetEnable dom)
=> Signal dom (Bool, Bool, Reg)
-> Signal dom (Bool, Bool, Reg)
control iBundled = bundle (iR, oV, o)
where
(oR, iV, i) = unbundle iBundled
(iR, oMaybe) = unbundle $ worker $ bundle (oR, mux iV (Just <$> i) (pure Nothing))
oV = isJust <$> oMaybe
o = fromMaybe 0 <$> oMaybe
data MyState = Empty | Busy | Full deriving (Eq,Generic,NFDataX,Show)
worker :: (HiddenClockResetEnable dom)
=> Signal dom (Bool, Maybe Reg)
-> Signal dom (Bool, Maybe Reg)
worker = moore t o (Empty, Nothing)
where
t :: (MyState, Maybe Reg) -> (Bool, Maybe Reg) -> (MyState, Maybe Reg)
t ( Full, _) (True, _) = ( Empty, Nothing)
t ( Empty, _) ( _, Just reg) = ( Busy, Just reg)
t ( Busy, Just 0) ( _, _) = ( Full, Just 1)
t ( Busy, Just reg) ( _, _) = ( Busy, Just (reg - 1))
t ( state, reg) ( _, _) = ( state, reg)
o :: (MyState, Maybe Reg) -> (Bool, Maybe Reg)
o ( Full, reg) = (False, reg)
o ( Empty, _) = (True, Nothing)
o ( _, _) = (False, Nothing)
stack --stack-yaml /path/to/clash-compiler/stack.yaml exec -- clash --verilog countdown.hs


Create Block Design

Add ZYNQ7 PS

Run Block Automation

Add GP Master AXI Interface

Create our own IP

Edit our own new IP

Patching the source
patch -p0 < /path/to/myip_v1_0_S00_AXI.v-diff
Re-package new IP

Create HDL wrapper

Remove bitstream header

Last but not least
- Synthesize, implement, and generate bitstream
- Copy to MicroZed the bitstream file, e.g.:
- Then write & poke at the right place:
scp -o ProxyCommand='ssh ssh@133.28.97.123 -W 192.168.88.253:22' \
project_1/project_1.runs/impl_1/design_1_wrapper.bin root@zynq:
ssh -o ProxyCommand='ssh ssh@133.28.97.123 -W 192.168.88.253:22' root@zynq
root@zynq:~# cat design_1_wrapper.bin > /dev/xdevcfg
root@zynq:~# devmem 0x43c00000
Thanks!
- Questions or comments?
FPGA tutorial
By Chen-Mou Cheng
FPGA tutorial
- 110