summaryrefslogtreecommitdiff
path: root/lib/Language
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2024-09-05 23:18:48 +0200
committerEugen Wissner <belka@caraus.de>2024-09-05 23:18:48 +0200
commit042e4e8714263fe0568e1e382232dae56afa2ed1 (patch)
treef7c0b9d68a44565fac4903bf7447fdf20628c4b8 /lib/Language
parentbe73032b939486c6207b441fb7bdfb0bda172b5d (diff)
downloadelna-042e4e8714263fe0568e1e382232dae56afa2ed1.tar.gz
Add command line parser
Diffstat (limited to 'lib/Language')
-rw-r--r--lib/Language/Elna/Architecture/RiscV.hs286
-rw-r--r--lib/Language/Elna/CommandLine.hs44
-rw-r--r--lib/Language/Elna/Object/Elf.hs73
3 files changed, 381 insertions, 22 deletions
diff --git a/lib/Language/Elna/Architecture/RiscV.hs b/lib/Language/Elna/Architecture/RiscV.hs
new file mode 100644
index 0000000..5d8c247
--- /dev/null
+++ b/lib/Language/Elna/Architecture/RiscV.hs
@@ -0,0 +1,286 @@
+module Language.Elna.Architecture.RiscV
+ ( BaseOpcode(..)
+ , Funct3(..)
+ , Funct7(..)
+ , Funct12(..)
+ , Instruction(..)
+ , Type(..)
+ , XRegister(..)
+ , baseOpcode
+ , funct3
+ , funct12
+ , instruction
+ , xRegister
+ ) where
+
+import qualified Data.ByteString.Builder as ByteString.Builder
+import Data.Bits (Bits(..))
+import Data.Word (Word8, Word32)
+
+data XRegister
+ = Zero
+ | RA
+ | SP
+ | GP
+ | TP
+ | T0
+ | T1
+ | T2
+ | S0
+ | S1
+ | A0
+ | A1
+ | A2
+ | A3
+ | A4
+ | A5
+ | A6
+ | A7
+ | S2
+ | S3
+ | S4
+ | S5
+ | S6
+ | S7
+ | S8
+ | S9
+ | S10
+ | S11
+ | T3
+ | T4
+ | T5
+ | T6
+ deriving Eq
+
+data Funct3
+ = ADDI
+ | SLTI
+ | SLTIU
+ | ANDI
+ | ORI
+ | XORI
+ | SLLI
+ | SRLI
+ | SRAI
+ | ADD
+ | SLT
+ | SLTU
+ | AND
+ | OR
+ | XOR
+ | SLL
+ | SRL
+ | SUB
+ | SRA
+ | BEQ
+ | BNE
+ | BLT
+ | BLTU
+ | BGE
+ | BGEU
+ | FENCE
+ | FENCEI
+ | CSRRW
+ | CSRRS
+ | CSRRC
+ | CSRRWI
+ | CSRRSI
+ | CSRRCI
+ | PRIV
+ | SB
+ | SH
+ | SW
+ | LB
+ | LH
+ | LW
+ | LBU
+ | LHU
+ | JALR
+ | MUL
+ | MULH
+ | MULHSU
+ | MULHU
+ | DIV
+ | DIVU
+ | REM
+ | REMU
+ deriving Eq
+
+data Funct12
+ = ECALL
+ | EBREAK
+ deriving Eq
+
+newtype Funct7 = Funct7
+ { funct7 :: Word8
+ } deriving Eq
+
+data BaseOpcode
+ = OpImm
+ | Lui
+ | Auipc
+ | Op
+ | Jal
+ | Jalr
+ | Branch
+ | Load
+ | Store
+ | MiscMem
+ | System
+ deriving Eq
+
+data Type
+ = I XRegister Funct3 XRegister Word32
+ | S Word32 Funct3 XRegister XRegister
+ | B Word32 Funct3 XRegister XRegister
+ | R XRegister Funct3 XRegister XRegister Funct7
+ | U XRegister Word32
+ | J XRegister Word32
+
+data Instruction = Instruction BaseOpcode Type
+
+xRegister :: XRegister -> Word8
+xRegister Zero = 0
+xRegister RA = 1
+xRegister SP = 2
+xRegister GP = 3
+xRegister TP = 4
+xRegister T0 = 5
+xRegister T1 = 6
+xRegister T2 = 7
+xRegister S0 = 8
+xRegister S1 = 9
+xRegister A0 = 10
+xRegister A1 = 11
+xRegister A2 = 12
+xRegister A3 = 13
+xRegister A4 = 14
+xRegister A5 = 15
+xRegister A6 = 16
+xRegister A7 = 17
+xRegister S2 = 18
+xRegister S3 = 19
+xRegister S4 = 20
+xRegister S5 = 21
+xRegister S6 = 22
+xRegister S7 = 23
+xRegister S8 = 24
+xRegister S9 = 25
+xRegister S10 = 26
+xRegister S11 = 27
+xRegister T3 = 28
+xRegister T4 = 29
+xRegister T5 = 30
+xRegister T6 = 31
+
+funct3 :: Funct3 -> Word8
+funct3 ADDI = 0b000
+funct3 SLTI = 0b001
+funct3 SLTIU = 0b011
+funct3 ANDI = 0b111
+funct3 ORI = 0b110
+funct3 XORI = 0b100
+funct3 SLLI = 0b000
+funct3 SRLI = 0b101
+funct3 SRAI = 0b101
+funct3 ADD = 0b000
+funct3 SLT = 0b010
+funct3 SLTU = 0b011
+funct3 AND = 0b111
+funct3 OR = 0b110
+funct3 XOR = 0b100
+funct3 SLL = 0b001
+funct3 SRL = 0b101
+funct3 SUB = 0b000
+funct3 SRA = 0b101
+funct3 BEQ = 0b000
+funct3 BNE = 0b001
+funct3 BLT = 0b100
+funct3 BLTU = 0b110
+funct3 BGE = 0b101
+funct3 BGEU = 0b111
+funct3 FENCE = 0b000
+funct3 FENCEI = 0b001
+funct3 CSRRW = 0b001
+funct3 CSRRS = 0b010
+funct3 CSRRC = 0b011
+funct3 CSRRWI = 0b101
+funct3 CSRRSI = 0b110
+funct3 CSRRCI = 0b111
+funct3 PRIV = 0b000
+funct3 SB = 0b000
+funct3 SH = 0b001
+funct3 SW = 0b010
+funct3 LB = 0b000
+funct3 LH = 0b001
+funct3 LW = 0b010
+funct3 LBU = 0b100
+funct3 LHU = 0b101
+funct3 JALR = 0b000
+funct3 MUL = 0b000
+funct3 MULH = 0b001
+funct3 MULHSU = 0b010
+funct3 MULHU = 0b011
+funct3 DIV = 0b100
+funct3 DIVU = 0b101
+funct3 REM = 0b110
+funct3 REMU = 0b111
+
+funct12 :: Funct12 -> Word8
+funct12 ECALL = 0b000000000000
+funct12 EBREAK = 0b000000000001
+
+baseOpcode :: BaseOpcode -> Word8
+baseOpcode OpImm = 0b0010011
+baseOpcode Lui = 0b0110111
+baseOpcode Auipc = 0b0010111
+baseOpcode Op = 0b0110011
+baseOpcode Jal = 0b1101111
+baseOpcode Jalr = 0b1100111
+baseOpcode Branch = 0b1100011
+baseOpcode Load = 0b0000011
+baseOpcode Store = 0b0100011
+baseOpcode MiscMem = 0b0001111
+baseOpcode System = 0b1110011
+
+type' :: Type -> Word32
+type' (I rd funct3' rs1 immediate)
+ = (fromIntegral (xRegister rd) `shiftL` 7)
+ .|. (fromIntegral (funct3 funct3') `shiftL` 12)
+ .|. (fromIntegral (xRegister rs1) `shiftL` 15)
+ .|. (immediate `shiftL` 20);
+type' (S immediate funct3' rs1 rs2)
+ = ((immediate .&. 0x1f) `shiftL` 7)
+ .|. (fromIntegral (funct3 funct3') `shiftL` 12)
+ .|. (fromIntegral (xRegister rs1) `shiftL` 15)
+ .|. (fromIntegral (xRegister rs2) `shiftL` 20)
+ .|. ((immediate .&. 0xfe0) `shiftL` 20)
+type' (B immediate funct3' rs1 rs2)
+ = ((immediate .&. 0x800) `shiftR` 4)
+ .|. ((immediate .&. 0x1e) `shiftL` 7)
+ .|. (fromIntegral (funct3 funct3') `shiftL` 12)
+ .|. (fromIntegral (xRegister rs1) `shiftL` 15)
+ .|. (fromIntegral (xRegister rs2) `shiftL` 20)
+ .|. ((immediate .&. 0x7e0) `shiftL` 20)
+ .|. ((immediate .&. 0x1000) `shiftL` 19)
+type' (R rd funct3' rs1 rs2 funct7')
+ = (fromIntegral (xRegister rd) `shiftL` 7)
+ .|. (fromIntegral (funct3 funct3') `shiftL` 12)
+ .|. (fromIntegral (xRegister rs1) `shiftL` 15)
+ .|. (fromIntegral (xRegister rs2) `shiftL` 20)
+ .|. (fromIntegral (funct7 funct7') `shiftL` 25);
+type' (U rd immediate)
+ = (fromIntegral (xRegister rd) `shiftL` 7)
+ .|. (immediate `shiftL` 12)
+type' (J rd immediate)
+ = (fromIntegral (xRegister rd) `shiftL` 7)
+ .|. (immediate .&. 0xff000)
+ .|. ((immediate .&. 0x800) `shiftL` 9)
+ .|. ((immediate .&. 0x7fe) `shiftL` 20)
+ .|. ((immediate .&. 0x100000) `shiftL` 11);
+
+instruction :: Instruction -> ByteString.Builder.Builder
+instruction (Instruction base instructionType)
+ = ByteString.Builder.word32LE
+ $ fromIntegral (baseOpcode base)
+ .|. type' instructionType
diff --git a/lib/Language/Elna/CommandLine.hs b/lib/Language/Elna/CommandLine.hs
new file mode 100644
index 0000000..b23be7d
--- /dev/null
+++ b/lib/Language/Elna/CommandLine.hs
@@ -0,0 +1,44 @@
+module Language.Elna.CommandLine
+ ( CommandLine(..)
+ , commandLine
+ , execParser
+ ) where
+
+import Options.Applicative
+ ( Parser
+ , ParserInfo(..)
+ , argument
+ , execParser
+ , fullDesc
+ , help
+ , helper
+ , info
+ , long
+ , metavar
+ , optional
+ , progDesc
+ , short
+ , str
+ , strOption
+ )
+import Control.Applicative ((<**>))
+
+data CommandLine = CommandLine
+ { input :: FilePath
+ , output :: Maybe FilePath
+ } deriving (Eq, Show)
+
+parser :: Parser CommandLine
+parser = CommandLine
+ <$> argument str inFile
+ <*> optional (strOption outFile)
+ where
+ inFile = metavar "INFILE" <> help "Input file."
+ outFile = long "output"
+ <> short 'o'
+ <> metavar "OUTFILE"
+ <> help "Output file."
+
+commandLine :: ParserInfo CommandLine
+commandLine = info (parser <**> helper)
+ $ fullDesc <> progDesc "Elna compiler."
diff --git a/lib/Language/Elna/Object/Elf.hs b/lib/Language/Elna/Object/Elf.hs
index 1a4bcc8..4328f56 100644
--- a/lib/Language/Elna/Object/Elf.hs
+++ b/lib/Language/Elna/Object/Elf.hs
@@ -30,17 +30,23 @@ module Language.Elna.Object.Elf
, elf32Rel
, elf32Rela
, elf32Sym
+ , elfHeaderSize
, elfIdentification
+ , elfObject
, rInfo
, stInfo
) where
-import Control.Exception (Exception(..))
+import Control.Exception (Exception(..), throwIO)
import Data.Bits (Bits(..))
import qualified Data.ByteString.Builder as ByteString.Builder
import Data.Int (Int32)
import Data.Word (Word8, Word16, Word32)
import qualified Data.ByteString as ByteString
+import Data.Vector (Vector)
+import qualified Data.Vector as Vector
+import System.IO (Handle, IOMode(..), SeekMode(..), hSeek, withFile)
+import Data.Foldable (traverse_)
-- * Data types.
@@ -345,27 +351,6 @@ instance Enum ElfSectionType
fromEnum SHT_HIUSER = 0xffffffff
fromEnum (ElfSectionType x) = fromIntegral x
--- * Help types and functions.
-
-data ByteOrder = LSB | MSB
- deriving Eq
-
-data ElfEncodingError
- = ElfInvalidByteOrderError
- | ElfUnsupportedClassError ElfClass
- deriving Eq
-
-instance Show ElfEncodingError
- where
- show ElfInvalidByteOrderError = "Invalid byte order."
- show (ElfUnsupportedClassError class') =
- concat ["Elf class \"", show class', "\" is not supported."]
-
-instance Exception ElfEncodingError
-
-fromIntegralEnum :: (Enum a, Num b) => a -> b
-fromIntegralEnum = fromIntegral . fromEnum
-
-- * Encoding functions.
elf32Addr :: ByteOrder -> Elf32_Addr -> ByteString.Builder.Builder
@@ -462,3 +447,47 @@ stInfo binding type' = fromIntegralEnum binding `shiftL` 4
rInfo :: Elf32_Word -> Word8 -> Elf32_Word
rInfo symbol type' = symbol `shiftL` 8
.|. fromIntegralEnum type'
+
+-- * Help types and functions.
+
+data ByteOrder = LSB | MSB
+ deriving Eq
+
+data ElfEncodingError
+ = ElfInvalidByteOrderError
+ | ElfUnsupportedClassError ElfClass
+ deriving Eq
+
+instance Show ElfEncodingError
+ where
+ show ElfInvalidByteOrderError = "Invalid byte order."
+ show (ElfUnsupportedClassError class') =
+ concat ["Elf class \"", show class', "\" is not supported."]
+
+instance Exception ElfEncodingError
+
+fromIntegralEnum :: (Enum a, Num b) => a -> b
+fromIntegralEnum = fromIntegral . fromEnum
+
+elfHeaderSize :: Elf32_Off
+elfHeaderSize = 52
+
+-- Writes an ELF object with the given header to the provided file path.
+-- The callback writes the sections and returns headers for those sections.
+elfObject :: FilePath -> Elf32_Ehdr -> (Handle -> IO (Vector Elf32_Shdr)) -> IO ()
+elfObject outFile header putContents = withFile outFile WriteMode withObjectFile
+ where
+ withObjectFile objectHandle
+ = hSeek objectHandle AbsoluteSeek (fromIntegral elfHeaderSize)
+ >> putContents objectHandle
+ >>= afterContents objectHandle
+ afterContents objectHandle headers =
+ let headerEncodingResult = elf32Ehdr
+ $ header
+ { e_shoff = elfHeaderSize + Vector.foldr ((+) . sh_size) 0 headers
+ }
+ in traverse_ (ByteString.Builder.hPutBuilder objectHandle . elf32Shdr LSB) headers
+ >> either throwIO (putHeaders objectHandle) headerEncodingResult
+ putHeaders objectHandle encodedHeader
+ = hSeek objectHandle AbsoluteSeek 0
+ >> ByteString.Builder.hPutBuilder objectHandle encodedHeader