{-# LANGUAGE ScopedTypeVariables, TypeFamilies #-} module Hardware.KansasLava.Boards.Spartan3e ( -- * Class for the methods of the Spartan3e Spartan3e(..) -- * Initialization, and global settings. , clockRate , writeUCF -- * Data structures , Serial(..) -- * Utilities for Board and Simulation use , switchesP , buttonsP , ledsP ) where import Language.KansasLava as KL import Hardware.KansasLava.LCD.ST7066U import Hardware.KansasLava.RS232 import Hardware.KansasLava.Rate import Hardware.KansasLava.Boards.UCF import Data.Sized.Unsigned import Data.Sized.Ix hiding (all) import Data.Sized.Matrix hiding (all) import Data.Char import System.IO import Control.Applicative import Control.Monad.Fix ------------------------------------------------------------ -- The Spartan3e class ------------------------------------------------------------ class MonadFix fabric => Spartan3e fabric where ---------------------------------------------------------------------------- -- | 'board_init' sets up the use of the clock. -- Always call 'board_init' first. [Required]. board_init :: fabric () -- | 'rot_as_reset' sets up the rotary dial as a reset switch. rot_as_reset :: fabric () ---------------------------------------------------------------------------- -- | 'mm_lcdP' gives a memory mappped (mm) API to the LCD. -- Disables the StrataFlash (for now). mm_lcdP :: FabricPatch fabric (Seq (Enabled ((X2,X16),U8))) () (Seq Ack) () -- | 'rs232_txP' gives a patch level API for transmission of bytes -- over one of the serial links. rs232_txP :: Serial -- ^ port -> Integer -- ^ baud rate -> FabricPatch fabric (Seq (Enabled U8)) () (Seq Ack) () -- | 'rs232_rxP' gives a patch level API for reception of bytes -- over one of the serial links. Note there is no hand-shaking -- because the (implied) UART does no buffering; you better be -- ready. rs232_rxP :: Serial -- ^ port -> Integer -- ^ baud rate -> FabricPatch fabric () (Seq (Enabled U8)) () () ---------------------------------------------------------------------------- -- | 'tickTock' generates 'n' pulses per second, -- based on the expected simulation, or clockrate on the board. -- The purpose is for controlling real-time sampling, or for animations. -- tickTock :: (Size w) => Witness w -> Integer -> fabric (Seq Bool) ---------------------------------------------------------------------------- -- -- | 'lcd' give raw access to the lcd bus. Disables the StrataFlash (for now). -- lcd :: Seq U1 -> Seq U4 -> Seq Bool -> fabric () -- | 'switches' gives raw access to the position of the toggle switches. switches :: fabric (Matrix X4 (Seq Bool)) -- | 'buttons' gives raw access to the state of the buttons. buttons :: fabric (Matrix X4 (Seq Bool)) -- | 'leds' drives the leds leds :: Matrix X8 (Seq Bool) -> fabric () -- | 'dial_button' gives raw access to the state of the dial button dial_button :: fabric (Seq Bool) -- | 'dial_rot' gives Enabled packets when dial is rotated, -- and if the rotation was clockwise dial_rot :: fabric (Seq (Enabled Bool)) {- -- | 'mm_vgaP' gives a memory mapped API to the VGA port. -- Each charactor has an extra attribute mm_vgaP :: Patch (Seq (Enabled ((X40,X80),(VGA.Attr,U7)))) (fabric ()) (Seq Ack) () -} ------------------------------------------------------------ -- initialization ------------------------------------------------------------ -- | The clock rate on the Spartan3e (50MHz), in hertz. clockRate :: Integer clockRate = 50 * 1000 * 1000 -- | show out a suggested UCF file for Spartan3e, for a specific circuit. writeUCF :: FilePath -> KLEG -> IO () writeUCF = copyUCF "Spartan3e.ucf" (Just "CLK_50MHZ") ------------------------------------------------------------ -- instance ------------------------------------------------------------ instance Spartan3e Fabric where board_init = do -- we need to name and pull in the clock theClk "CLK_50MHZ" rot_as_reset = theRst "ROT_CENTER" ------------------------------------------------------------ -- Patches ------------------------------------------------------------ mm_lcdP = patchF (mm_LCD_Inst $$ init_LCD $$ phy_Inst_4bit_LCD) |$| buildF (\ (bus,_) -> do let (rs,sf_d,e) = unpack bus lcd rs sf_d e return ((),())) where lcd rs sf_d e = do outStdLogic "LCD_RS" rs outStdLogicVector "SF_D" (appendS (0 :: Seq (U8)) sf_d :: Seq U12) outStdLogic "LCD_E" e outStdLogic "LCD_RW" low outStdLogic "SF_CE0" high rs232_txP serial baud = patchF (rs232out baud clockRate) |$| buildF (\ (bus,_) -> do outStdLogic ("RS232_" ++ show serial ++ "_TX") bus return ((),())) rs232_rxP serial baud = buildF (\ ~(_,_) -> do inp :: Seq Bool <- inStdLogic ("RS232_" ++ show serial ++ "_RX") let (_,out) = execP (rs232in baud clockRate) (inp,()) return ((),out)) ------------------------------------------------------------ -- RAW APIs ------------------------------------------------------------ switches = do inp <- inStdLogicVector "SW" :: Fabric (Seq (Matrix X4 Bool)) return (unpack inp) buttons = do i0 <- inStdLogic "BTN_WEST" i1 <- inStdLogic "BTN_NORTH" i2 <- inStdLogic "BTN_EAST" i3 <- inStdLogic "BTN_SOUTH" return (matrix [i0,i1,i2,i3]) leds inp = outStdLogicVector "LED" (pack inp :: Seq (Matrix X8 Bool)) dial_button = inStdLogic "ROT_CENTER" dial_rot = error "dial_rot is not (yet) supported in the hardware" tickTock wit hz = do return (rate wit (1 / (fromIntegral clockRate / fromIntegral hz))) ------------------------------------------------------------- -- data structures ------------------------------------------------------------- data Serial = DCE | DTE deriving (Eq, Ord, Show) ------------------------------------------------------------- -- Utilites that can be shared ------------------------------------------------------------- -- | 'switchesP' gives a patch-level API for the toggle switches. switchesP :: (Spartan3e fabric) => fabric (Patch () (Matrix X4 (Seq Bool)) () (Matrix X4 ())) switchesP = do sws <- switches return (outputP sws $$ backwardP (\ _mat -> ()) $$ matrixStackP (pure emptyP)) -- | 'buttonsP' gives a patch-level API for the toggle switches. buttonsP :: (Spartan3e fabric) => fabric (Patch () (Matrix X4 (Seq Bool)) () (Matrix X4 ())) buttonsP = do sws <- buttons return (outputP sws $$ backwardP (\ _mat -> ()) $$ matrixStackP (pure emptyP)) -- | 'ledP' gives a patch-level API for the leds. ledsP :: (Spartan3e fabric) => Patch (Matrix X8 (Seq Bool)) (fabric ()) (Matrix X8 ()) () ledsP = backwardP (\ () -> pure ()) $$ forwardP leds