FPGA programming without Verilog/VHDL

Xilinx Zynq: PS + PL

Logic cells inside PL

Install Vivado HLx & Linux

 

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