packages feed

clash-vexriscv-0.1: src/VexRiscv/FFI.hsc

-- SPDX-FileCopyrightText: 2022-2024 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0

{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module VexRiscv.FFI where

import Foreign.Storable
import Foreign.Ptr
import Prelude
import Clash.Prelude
import Data.Word

#include "ffi/interface.h"

data VexRiscvJtagBridge

foreign import ccall unsafe "vexr_jtag_bridge_init" vexrJtagBridgeInit :: Word16 -> IO (Ptr VexRiscvJtagBridge)
foreign import ccall unsafe "vexr_jtag_bridge_step" vexrJtagBridgeStep :: Ptr VexRiscvJtagBridge -> Ptr JTAG_OUTPUT -> Ptr JTAG_INPUT -> IO ()
foreign import ccall unsafe "vexr_jtag_bridge_shutdown" vexrJtagBridgeShutdown :: Ptr VexRiscvJtagBridge -> IO ()

-- | CPU input that cannot combinatorially depend on the CPU output
data NON_COMB_INPUT = NON_COMB_INPUT
  { reset :: Bit
  , timerInterrupt :: Bit
  , externalInterrupt :: Bit
  , softwareInterrupt :: Bit
  }

-- | CPU input that can combinatorially depend on the CPU output
data COMB_INPUT = COMB_INPUT
  { iBusWishbone_ACK :: Bit
  , iBusWishbone_DAT_MISO :: Word32
  , iBusWishbone_ERR :: Bit

  , dBusWishbone_ACK :: Bit
  , dBusWishbone_DAT_MISO :: Word32
  , dBusWishbone_ERR :: Bit

  , jtag_TCK :: Bit
  , jtag_TMS :: Bit
  , jtag_TDI :: Bit
  }
  deriving (Show)

data OUTPUT = OUTPUT
  { iBusWishbone_CYC :: Bit
  , iBusWishbone_STB :: Bit
  , iBusWishbone_WE :: Bit
  , iBusWishbone_ADR :: Word32
  , iBusWishbone_DAT_MOSI :: Word32
  , iBusWishbone_SEL :: Word8
  , iBusWishbone_CTI :: Word8
  , iBusWishbone_BTE :: Word8

  , dBusWishbone_CYC :: Bit
  , dBusWishbone_STB :: Bit
  , dBusWishbone_WE :: Bit
  , dBusWishbone_ADR :: Word32
  , dBusWishbone_DAT_MOSI :: Word32
  , dBusWishbone_SEL :: Word8
  , dBusWishbone_CTI :: Word8
  , dBusWishbone_BTE :: Word8

  , ndmreset :: Bit
  , stoptime :: Bit

  , jtag_TDO :: Bit
  }
  deriving (Show)

data JTAG_INPUT = JTAG_INPUT
  { tck :: Bit
  , tms :: Bit
  , tdi :: Bit
  }
  deriving (Show)

data JTAG_OUTPUT = JTAG_OUTPUT
  { tdo :: Bit
  }
  deriving (Show)

instance Storable Bit where
    alignment = alignment . bitToBool
    sizeOf = sizeOf . bitToBool
    peek = fmap boolToBit . peek . castPtr
    poke ptr = poke (castPtr ptr) . bitToBool

instance Storable NON_COMB_INPUT where
    alignment _ = #alignment NON_COMB_INPUT
    sizeOf _ = #size NON_COMB_INPUT
    {-# INLINE peek #-}
    peek ptr = const NON_COMB_INPUT <$> pure ()
      <*> (#peek NON_COMB_INPUT, reset) ptr
      <*> (#peek NON_COMB_INPUT, timerInterrupt) ptr
      <*> (#peek NON_COMB_INPUT, externalInterrupt) ptr
      <*> (#peek NON_COMB_INPUT, softwareInterrupt) ptr

    {-# INLINE poke #-}
    poke ptr this = do
      (#poke NON_COMB_INPUT, reset) ptr (reset this)
      (#poke NON_COMB_INPUT, timerInterrupt) ptr (timerInterrupt this)
      (#poke NON_COMB_INPUT, externalInterrupt) ptr (externalInterrupt this)
      (#poke NON_COMB_INPUT, softwareInterrupt) ptr (softwareInterrupt this)
      return ()

instance Storable COMB_INPUT where
    alignment _ = #alignment COMB_INPUT
    sizeOf _ = #size COMB_INPUT
    {-# INLINE peek #-}
    peek ptr = const COMB_INPUT <$> pure ()
      <*> (#peek COMB_INPUT, iBusWishbone_ACK) ptr
      <*> (#peek COMB_INPUT, iBusWishbone_DAT_MISO) ptr
      <*> (#peek COMB_INPUT, iBusWishbone_ERR) ptr
      <*> (#peek COMB_INPUT, dBusWishbone_ACK) ptr
      <*> (#peek COMB_INPUT, dBusWishbone_DAT_MISO) ptr
      <*> (#peek COMB_INPUT, dBusWishbone_ERR) ptr
      <*> (#peek COMB_INPUT, jtag_TCK) ptr
      <*> (#peek COMB_INPUT, jtag_TMS) ptr
      <*> (#peek COMB_INPUT, jtag_TDI) ptr

    {-# INLINE poke #-}
    poke ptr this = do
      (#poke COMB_INPUT, iBusWishbone_ACK) ptr (iBusWishbone_ACK this)
      (#poke COMB_INPUT, iBusWishbone_DAT_MISO) ptr (iBusWishbone_DAT_MISO this)
      (#poke COMB_INPUT, iBusWishbone_ERR) ptr (iBusWishbone_ERR this)

      (#poke COMB_INPUT, dBusWishbone_ACK) ptr (dBusWishbone_ACK this)
      (#poke COMB_INPUT, dBusWishbone_DAT_MISO) ptr (dBusWishbone_DAT_MISO this)
      (#poke COMB_INPUT, dBusWishbone_ERR) ptr (dBusWishbone_ERR this)

      (#poke COMB_INPUT, jtag_TCK) ptr (jtag_TCK this)
      (#poke COMB_INPUT, jtag_TMS) ptr (jtag_TMS this)
      (#poke COMB_INPUT, jtag_TDI) ptr (jtag_TDI this)
      return ()

instance Storable OUTPUT where
    alignment _ = #alignment OUTPUT
    sizeOf _ = #size OUTPUT
    {-# INLINE peek #-}
    peek ptr = const OUTPUT <$> pure ()
      <*> (#peek OUTPUT, iBusWishbone_CYC) ptr
      <*> (#peek OUTPUT, iBusWishbone_STB) ptr
      <*> (#peek OUTPUT, iBusWishbone_WE) ptr
      <*> (#peek OUTPUT, iBusWishbone_ADR) ptr
      <*> (#peek OUTPUT, iBusWishbone_DAT_MOSI) ptr
      <*> (#peek OUTPUT, iBusWishbone_SEL) ptr
      <*> (#peek OUTPUT, iBusWishbone_CTI) ptr
      <*> (#peek OUTPUT, iBusWishbone_BTE) ptr

      <*> (#peek OUTPUT, dBusWishbone_CYC) ptr
      <*> (#peek OUTPUT, dBusWishbone_STB) ptr
      <*> (#peek OUTPUT, dBusWishbone_WE) ptr
      <*> (#peek OUTPUT, dBusWishbone_ADR) ptr
      <*> (#peek OUTPUT, dBusWishbone_DAT_MOSI) ptr
      <*> (#peek OUTPUT, dBusWishbone_SEL) ptr
      <*> (#peek OUTPUT, dBusWishbone_CTI) ptr
      <*> (#peek OUTPUT, dBusWishbone_BTE) ptr

      <*> (#peek OUTPUT, ndmreset) ptr
      <*> (#peek OUTPUT, stoptime) ptr

      <*> (#peek OUTPUT, jtag_TDO) ptr

    {-# INLINE poke #-}
    poke ptr this = do
      (#poke OUTPUT, iBusWishbone_CYC) ptr (iBusWishbone_CYC this)
      (#poke OUTPUT, iBusWishbone_STB) ptr (iBusWishbone_STB this)
      (#poke OUTPUT, iBusWishbone_WE) ptr (iBusWishbone_WE this)
      (#poke OUTPUT, iBusWishbone_ADR) ptr (iBusWishbone_ADR this)
      (#poke OUTPUT, iBusWishbone_DAT_MOSI) ptr (iBusWishbone_DAT_MOSI this)
      (#poke OUTPUT, iBusWishbone_SEL) ptr (iBusWishbone_SEL this)
      (#poke OUTPUT, iBusWishbone_CTI) ptr (iBusWishbone_CTI this)
      (#poke OUTPUT, iBusWishbone_BTE) ptr (iBusWishbone_BTE this)

      (#poke OUTPUT, dBusWishbone_CYC) ptr (dBusWishbone_CYC this)
      (#poke OUTPUT, dBusWishbone_STB) ptr (dBusWishbone_STB this)
      (#poke OUTPUT, dBusWishbone_WE) ptr (dBusWishbone_WE this)
      (#poke OUTPUT, dBusWishbone_ADR) ptr (dBusWishbone_ADR this)
      (#poke OUTPUT, dBusWishbone_DAT_MOSI) ptr (dBusWishbone_DAT_MOSI this)
      (#poke OUTPUT, dBusWishbone_SEL) ptr (dBusWishbone_SEL this)
      (#poke OUTPUT, dBusWishbone_CTI) ptr (dBusWishbone_CTI this)
      (#poke OUTPUT, dBusWishbone_BTE) ptr (dBusWishbone_BTE this)

      (#poke OUTPUT, ndmreset) ptr (ndmreset this)
      (#poke OUTPUT, stoptime) ptr (stoptime this)

      (#poke OUTPUT, jtag_TDO) ptr (jtag_TDO this)
      return ()

instance Storable JTAG_OUTPUT where
    alignment _ = #alignment JTAG_OUTPUT
    sizeOf _ = #size JTAG_OUTPUT
    {-# INLINE peek #-}
    peek ptr = const JTAG_OUTPUT <$> pure ()
      <*> (#peek JTAG_OUTPUT, tdo) ptr

    {-# INLINE poke #-}
    poke ptr this = do
      (#poke JTAG_OUTPUT, tdo) ptr (tdo this)

instance Storable JTAG_INPUT where
    alignment _ = #alignment JTAG_INPUT
    sizeOf _ = #size JTAG_INPUT
    {-# INLINE peek #-}
    peek ptr = const JTAG_INPUT <$> pure ()
      <*> (#peek JTAG_INPUT, tck) ptr
      <*> (#peek JTAG_INPUT, tms) ptr
      <*> (#peek JTAG_INPUT, tdi) ptr

    {-# INLINE poke #-}
    poke ptr this = do
      (#poke JTAG_INPUT, tck) ptr (tck this)
      (#poke JTAG_INPUT, tms) ptr (tms this)
      (#poke JTAG_INPUT, tdi) ptr (tdi this)
      return ()