diff options
-rw-r--r-- | app/Main.hs | 149 | ||||
-rw-r--r-- | bugs/vivado/1_generated.v | 31 | ||||
-rw-r--r-- | bugs/vivado/1_minimal.v | 8 | ||||
-rw-r--r-- | bugs/vivado/1_original.v | 501 | ||||
-rw-r--r-- | bugs/vivado/2_minimal.v | 28 | ||||
-rw-r--r-- | bugs/vivado/2_original.v | 44 | ||||
-rw-r--r-- | scripts/setup.sh | 6 | ||||
-rw-r--r-- | src/VeriFuzz.hs | 21 | ||||
-rw-r--r-- | src/VeriFuzz/Circuit.hs | 1 | ||||
-rw-r--r-- | src/VeriFuzz/Circuit/Gen.hs | 8 | ||||
-rw-r--r-- | src/VeriFuzz/Config.hs | 175 | ||||
-rw-r--r-- | src/VeriFuzz/Internal.hs | 5 | ||||
-rw-r--r-- | src/VeriFuzz/RecursionScheme.hs | 84 | ||||
-rw-r--r-- | src/VeriFuzz/Sim/Icarus.hs | 3 | ||||
-rw-r--r-- | src/VeriFuzz/Sim/Internal.hs | 6 | ||||
-rw-r--r-- | src/VeriFuzz/Sim/Reduce.hs | 4 | ||||
-rw-r--r-- | src/VeriFuzz/Sim/Template.hs | 2 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog.hs | 10 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/AST.hs | 336 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/CodeGen.hs | 115 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/Gen.hs | 336 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/Internal.hs | 25 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/Mutate.hs | 46 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/Parser.hs | 14 | ||||
-rw-r--r-- | src/VeriFuzz/Verilog/Preprocess.hs | 7 | ||||
-rw-r--r-- | test/Property.hs | 10 |
26 files changed, 1451 insertions, 524 deletions
diff --git a/app/Main.hs b/app/Main.hs index 8b5605b..f20bc59 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -23,10 +23,8 @@ data Opts = Fuzz { fuzzOutput :: {-# UNPACK #-} !Text , forced :: !Bool , keepAll :: !Bool } - | Rerun { tools :: [Tool] - , input :: {-# UNPACK #-} !S.FilePath - } - | Generate { fileName :: {-# UNPACK #-} !S.FilePath + | Generate { mFileName :: !(Maybe FilePath) + , configFile :: !(Maybe FilePath) } | Parse { fileName :: {-# UNPACK #-} !S.FilePath } @@ -59,70 +57,47 @@ parseSim val | val == "icarus" = Just Icarus | otherwise = Nothing fuzzOpts :: Parser Opts -fuzzOpts = Fuzz <$> textOption - ( long "output" - <> short 'o' - <> metavar "DIR" - <> help "Output directory that the fuzz run takes place in." - <> showDefault - <> value "output" - ) <*> (optional . strOption $ - long "config" - <> short 'c' - <> metavar "FILE" - <> help "Config file for the current fuzz run." - ) - <*> (switch $ - long "force" - <> short 'f' - <> help "Overwrite the specified directory." - ) - <*> (switch $ - long "keep" - <> short 'k' - <> help "Keep all the directories." - ) - -rerunOpts :: Parser Opts -rerunOpts = - Rerun - <$> some - ( option - (optReader parseSynth) - ( long "synth" - <> metavar "SYNTH" - <> help "Rerun using a synthesiser (yosys|xst)." - <> showDefault - <> value Yosys - ) - <|> option - (optReader parseSim) - ( long "sim" - <> metavar "SIM" - <> help "Rerun using a simulator (icarus)." - <> showDefault - <> value Icarus - ) - ) - <*> (S.fromText <$> textOption - ( long "input" - <> short 'i' - <> metavar "FILE" - <> help "Verilog file input." +fuzzOpts = + Fuzz + <$> textOption + ( long "output" + <> short 'o' + <> metavar "DIR" + <> help "Output directory that the fuzz run takes place in." <> showDefault - <> value "rtl.v" + <> value "output" ) + <*> ( optional + . strOption + $ long "config" + <> short 'c' + <> metavar "FILE" + <> help "Config file for the current fuzz run." + ) + <*> (switch $ long "force" <> short 'f' <> help + "Overwrite the specified directory." + ) + <*> (switch $ long "keep" <> short 'k' <> help + "Keep all the directories." ) genOpts :: Parser Opts -genOpts = Generate . S.fromText <$> textOption - ( long "output" - <> short 'o' - <> metavar "FILE" - <> help "Verilog output file." - <> showDefault - <> value "main.v" - ) +genOpts = + Generate + <$> ( optional + . strOption + $ long "output" + <> short 'o' + <> metavar "FILE" + <> help "Output to a verilog file instead." + ) + <*> ( optional + . strOption + $ long "config" + <> short 'c' + <> metavar "FILE" + <> help "Config file for the generation run." + ) parseOpts :: Parser Opts parseOpts = Parse . S.fromText . T.pack <$> strArgument @@ -145,12 +120,14 @@ reduceOpts = configOpts :: Parser Opts configOpts = - Config <$> (optional . strOption $ - long "output" - <> short 'o' - <> metavar "FILE" - <> help "Output to a TOML Config file." - ) + Config + <$> ( optional + . strOption + $ long "output" + <> short 'o' + <> metavar "FILE" + <> help "Output to a TOML Config file." + ) argparse :: Parser Opts argparse = @@ -167,17 +144,6 @@ argparse = ) <|> hsubparser ( command - "rerun" - (info - rerunOpts - (progDesc - "Rerun a Verilog file with a simulator or a synthesiser." - ) - ) - <> metavar "rerun" - ) - <|> hsubparser - ( command "generate" (info genOpts @@ -228,10 +194,13 @@ opts = info "VeriFuzz - A hardware simulator and synthesiser Verilog fuzzer." ) +getConfig :: Maybe FilePath -> IO V.Config +getConfig = maybe (return V.defaultConfig) V.parseConfigFile + handleOpts :: Opts -> IO () handleOpts (Fuzz out configF force keep) = do - num <- getNumCapabilities - config <- maybe (return V.defaultConfig) V.parseConfigFile configF + num <- getNumCapabilities + config <- getConfig configF S.shellyFailDir $ do when force . S.rm_rf $ S.fromText out S.mkdir_p $ S.fromText out @@ -245,14 +214,18 @@ handleOpts (Fuzz out configF force keep) = do ) <$> [1 .. num] sequence_ $ takeMVar <$> vars -handleOpts (Generate _) = error "Not implemented" -handleOpts (Parse f) = do +handleOpts (Generate f c) = do + config <- getConfig c + source <- V.proceduralIO config + maybe (T.putStrLn $ V.genSource source) + (flip T.writeFile (V.genSource source)) + f +handleOpts (Parse f) = do verilogSrc <- readFile file case V.parseVerilog file verilogSrc of Left l -> print l Right v -> print $ V.GenVerilog v where file = T.unpack . S.toTextIgnore $ f -handleOpts (Rerun _ _) = undefined handleOpts (Reduce f t) = do verilogSrc <- readFile file case V.parseVerilog file verilogSrc of @@ -262,8 +235,10 @@ handleOpts (Reduce f t) = do vreduced <- V.runReduce (V.SourceInfo t v) writeFile "reduced.v" . T.unpack $ V.genSource vreduced where file = T.unpack $ S.toTextIgnore f -handleOpts (Config c) = maybe (T.putStrLn . V.configEncode $ V.defaultConfig) - (`V.configToFile` V.defaultConfig) c +handleOpts (Config c) = maybe + (T.putStrLn . V.configEncode $ V.defaultConfig) + (`V.configToFile` V.defaultConfig) + c main :: IO () main = do diff --git a/bugs/vivado/1_generated.v b/bugs/vivado/1_generated.v new file mode 100644 index 0000000..de68529 --- /dev/null +++ b/bugs/vivado/1_generated.v @@ -0,0 +1,31 @@ +// Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. +// -------------------------------------------------------------------------------- +// Tool Version: Vivado v.2018.3 (lin64) Build 2405991 Thu Dec 6 23:36:41 MST 2018 +// Date : Thu Apr 11 19:11:05 2019 +// Host : yann-arch running 64-bit unknown +// Command : write_verilog -force syn_vivado.v +// Design : top +// Purpose : This is a Verilog netlist of the current design or from a specific cell of the design. The output is an +// IEEE 1364-2001 compliant Verilog HDL file that contains netlist information obtained from the input +// design files. +// Device : xc7k70tfbg676-3 +// -------------------------------------------------------------------------------- +`timescale 1 ps / 1 ps + +(* use_dsp = "no" *) +(* STRUCTURAL_NETLIST = "yes" *) +module top + (y, + wire0); + output y; + input wire0; + + wire \<const0> ; + wire y; + + GND GND + (.G(\<const0> )); + OBUF y_OBUF_inst + (.I(\<const0> ), + .O(y)); +endmodule diff --git a/bugs/vivado/1_minimal.v b/bugs/vivado/1_minimal.v new file mode 100644 index 0000000..59cec6c --- /dev/null +++ b/bugs/vivado/1_minimal.v @@ -0,0 +1,8 @@ +(* use_dsp48="no" *) module top + (y, wire0); + output wire y; + input wire wire0; + wire [1:0] wire4; + assign wire4 = 1'b1; + assign y = (wire4 <<< 1'h1) && wire0; +endmodule diff --git a/bugs/vivado/1_original.v b/bugs/vivado/1_original.v new file mode 100644 index 0000000..594b361 --- /dev/null +++ b/bugs/vivado/1_original.v @@ -0,0 +1,501 @@ +(* use_dsp48="no" *) module top +#( +parameter param209 = ((2'ha) ^~ (1'h4)), +param210 = ((9'hc) ~^ (~^((param209 <<< param209) > (^(9'h9))))), +param211 = ((((~&(8'h6)) & param210) && param210) ^~ (!((+param209) > (~¶m210)))) +) +(y, clk, wire0, wire1, wire2); +output wire [1662:0] y; +input wire clk; +input wire [2:0] wire0; +input wire signed [13:0] wire1; +input wire signed [9:0] wire2; +reg signed [9:0] reg208 = (32'h0); +reg signed [2:0] reg207 = (32'h0); +reg [8:0] reg206 = (32'h0); +reg signed [4:0] reg205 = (32'h0); +reg signed [1:0] reg204 = (32'h0); +reg signed [4:0] reg203 = (32'h0); +reg signed [3:0] reg202 = (32'h0); +reg reg201 = (32'h0); +reg [7:0] reg200 = (32'h0); +reg [8:0] reg199 = (32'h0); +reg [14:0] reg198 = (32'h0); +reg signed [12:0] reg197 = (32'h0); +reg signed [6:0] reg196 = (32'h0); +wire signed wire195; +reg signed [5:0] reg194 = (32'h0); +reg signed [4:0] reg193 = (32'h0); +reg signed [1:0] reg192 = (32'h0); +reg signed [12:0] reg191 = (32'h0); +reg signed [11:0] reg190 = (32'h0); +reg signed [7:0] reg189 = (32'h0); +reg signed reg188 = (32'h0); +reg signed [5:0] reg187 = (32'h0); +reg [10:0] reg186 = (32'h0); +reg signed [9:0] reg185 = (32'h0); +reg [3:0] reg184 = (32'h0); +reg signed [6:0] reg183 = (32'h0); +reg [12:0] reg182 = (32'h0); +reg reg181 = (32'h0); +reg signed [7:0] reg180 = (32'h0); +reg signed [5:0] reg179 = (32'h0); +reg signed [2:0] reg178 = (32'h0); +reg signed [5:0] reg177 = (32'h0); +reg [12:0] reg176 = (32'h0); +reg [12:0] reg175 = (32'h0); +reg signed [1:0] reg174 = (32'h0); +reg signed [14:0] reg173 = (32'h0); +reg [14:0] reg172 = (32'h0); +reg [7:0] reg171 = (32'h0); +reg [10:0] reg170 = (32'h0); +reg signed [3:0] reg169 = (32'h0); +reg [12:0] reg168 = (32'h0); +reg [4:0] reg167 = (32'h0); +reg [12:0] reg166 = (32'h0); +reg [4:0] reg165 = (32'h0); +reg [6:0] reg164 = (32'h0); +reg signed [8:0] reg163 = (32'h0); +reg signed [2:0] reg162 = (32'h0); +reg signed [6:0] reg161 = (32'h0); +reg signed reg160 = (32'h0); +reg [14:0] reg159 = (32'h0); +reg [14:0] reg158 = (32'h0); +reg signed [8:0] reg157 = (32'h0); +reg [5:0] reg156 = (32'h0); +reg [5:0] reg155 = (32'h0); +reg [2:0] reg154 = (32'h0); +reg [2:0] reg153 = (32'h0); +reg [7:0] reg152 = (32'h0); +reg signed [1:0] reg151 = (32'h0); +reg signed [9:0] reg150 = (32'h0); +reg signed [2:0] reg149 = (32'h0); +reg [10:0] reg148 = (32'h0); +reg [9:0] reg147 = (32'h0); +reg signed [14:0] reg146 = (32'h0); +reg signed [14:0] reg145 = (32'h0); +reg [14:0] reg144 = (32'h0); +reg reg143 = (32'h0); +reg [9:0] reg142 = (32'h0); +reg [4:0] reg141 = (32'h0); +reg [12:0] reg140 = (32'h0); +reg [7:0] reg139 = (32'h0); +reg [3:0] reg138 = (32'h0); +reg signed [2:0] reg137 = (32'h0); +reg [14:0] reg136 = (32'h0); +reg [8:0] reg135 = (32'h0); +reg [4:0] reg134 = (32'h0); +reg [10:0] reg133 = (32'h0); +reg [9:0] reg132 = (32'h0); +reg [6:0] reg131 = (32'h0); +reg [1:0] reg130 = (32'h0); +reg signed [5:0] reg129 = (32'h0); +reg [14:0] reg128 = (32'h0); +reg [5:0] reg127 = (32'h0); +reg signed [2:0] reg126 = (32'h0); +reg signed [12:0] reg125 = (32'h0); +reg signed [7:0] reg124 = (32'h0); +reg [5:0] reg123 = (32'h0); +reg signed [3:0] reg122 = (32'h0); +reg [10:0] reg121 = (32'h0); +reg [13:0] reg120 = (32'h0); +reg [5:0] reg119 = (32'h0); +reg signed [8:0] reg118 = (32'h0); +reg [5:0] reg117 = (32'h0); +reg signed [14:0] reg116 = (32'h0); +reg signed [10:0] reg115 = (32'h0); +reg reg114 = (32'h0); +reg signed [10:0] reg113 = (32'h0); +reg [1:0] reg112 = (32'h0); +reg [6:0] reg111 = (32'h0); +reg signed [5:0] reg110 = (32'h0); +reg signed [10:0] reg109 = (32'h0); +reg signed [11:0] reg108 = (32'h0); +reg signed [7:0] reg107 = (32'h0); +reg signed [1:0] reg106 = (32'h0); +reg [13:0] reg105 = (32'h0); +reg signed [4:0] reg104 = (32'h0); +reg [2:0] reg103 = (32'h0); +reg signed [10:0] reg102 = (32'h0); +reg signed [9:0] reg101 = (32'h0); +reg [9:0] reg100 = (32'h0); +reg [12:0] reg99 = (32'h0); +reg [9:0] reg98 = (32'h0); +reg reg97 = (32'h0); +reg [1:0] reg96 = (32'h0); +reg [1:0] reg95 = (32'h0); +reg [2:0] reg94 = (32'h0); +reg [6:0] reg93 = (32'h0); +reg [12:0] reg92 = (32'h0); +reg signed [13:0] reg91 = (32'h0); +reg [11:0] reg90 = (32'h0); +reg signed [13:0] reg89 = (32'h0); +reg signed [12:0] reg88 = (32'h0); +reg [13:0] reg87 = (32'h0); +reg [13:0] reg86 = (32'h0); +reg [3:0] reg85 = (32'h0); +reg [5:0] reg84 = (32'h0); +reg signed [11:0] reg83 = (32'h0); +reg signed [10:0] reg82 = (32'h0); +reg signed [7:0] reg81 = (32'h0); +reg [8:0] reg80 = (32'h0); +reg signed [9:0] reg79 = (32'h0); +reg signed [4:0] reg78 = (32'h0); +reg signed [7:0] reg77 = (32'h0); +reg [5:0] reg76 = (32'h0); +reg signed [7:0] reg75 = (32'h0); +reg signed [5:0] reg74 = (32'h0); +reg [9:0] reg73 = (32'h0); +reg signed [6:0] reg72 = (32'h0); +reg [5:0] reg71 = (32'h0); +reg [5:0] reg70 = (32'h0); +reg signed [10:0] reg69 = (32'h0); +reg signed [2:0] reg68 = (32'h0); +reg [10:0] reg67 = (32'h0); +reg signed [14:0] reg66 = (32'h0); +reg [4:0] reg65 = (32'h0); +reg signed reg64 = (32'h0); +reg [12:0] reg63 = (32'h0); +reg [7:0] reg62 = (32'h0); +reg [14:0] reg61 = (32'h0); +reg [14:0] reg60 = (32'h0); +reg signed [9:0] reg59 = (32'h0); +reg signed reg58 = (32'h0); +reg signed [4:0] reg57 = (32'h0); +reg signed [3:0] reg56 = (32'h0); +reg [2:0] reg55 = (32'h0); +reg [8:0] reg54 = (32'h0); +reg signed [13:0] reg53 = (32'h0); +reg signed [8:0] reg52 = (32'h0); +reg [10:0] reg51 = (32'h0); +reg [13:0] reg50 = (32'h0); +reg signed [12:0] reg49 = (32'h0); +reg [13:0] reg48 = (32'h0); +reg [4:0] reg47 = (32'h0); +reg signed [11:0] reg46 = (32'h0); +reg [10:0] reg45 = (32'h0); +reg [8:0] reg44 = (32'h0); +reg [2:0] reg43 = (32'h0); +reg signed [3:0] reg42 = (32'h0); +reg signed [8:0] reg41 = (32'h0); +reg signed [6:0] reg40 = (32'h0); +reg signed [13:0] reg39 = (32'h0); +reg [3:0] reg38 = (32'h0); +reg [3:0] reg37 = (32'h0); +reg [3:0] reg36 = (32'h0); +reg signed [7:0] reg35 = (32'h0); +reg [8:0] reg34 = (32'h0); +reg signed [10:0] reg33 = (32'h0); +reg signed [14:0] reg32 = (32'h0); +reg [13:0] reg31 = (32'h0); +reg signed [9:0] reg30 = (32'h0); +reg [13:0] reg29 = (32'h0); +reg signed [8:0] reg28 = (32'h0); +reg signed [8:0] reg27 = (32'h0); +reg [1:0] reg26 = (32'h0); +reg signed [13:0] reg25 = (32'h0); +reg [4:0] reg24 = (32'h0); +reg signed [8:0] reg23 = (32'h0); +reg signed [8:0] reg22 = (32'h0); +reg signed [3:0] reg21 = (32'h0); +reg signed [10:0] reg20 = (32'h0); +reg signed [3:0] reg19 = (32'h0); +reg signed [13:0] reg18 = (32'h0); +reg signed [4:0] reg17 = (32'h0); +reg [9:0] reg16 = (32'h0); +reg signed [3:0] reg15 = (32'h0); +reg signed reg14 = (32'h0); +reg [8:0] reg13 = (32'h0); +reg signed [4:0] reg12 = (32'h0); +reg signed [11:0] reg11 = (32'h0); +reg signed reg10 = (32'h0); +reg signed [2:0] reg9 = (32'h0); +reg signed [10:0] reg8 = (32'h0); +reg [3:0] reg7 = (32'h0); +reg [1:0] reg6 = (32'h0); +wire [3:0] wire5; +wire signed [13:0] wire4; +wire [9:0] wire3; +assign wire3 = (&(~^wire2)); +assign wire4 = $unsigned($signed((+$unsigned((-6'h1))))); +assign wire5 = (($signed($signed(wire4)) <<< (~(2'h1))) && $signed(wire3)); +always @(posedge clk) begin +reg6 = wire5; +reg7 = reg6; +reg8 = $signed(wire4); +reg9 = $signed($unsigned((-2'h1))); +reg10 = $signed((-15'h7)); +reg11 <= wire1; +reg12 <= (+wire1); +reg13 = (wire1 ^ (+$signed($signed(reg7)))); +reg14 <= $signed(($unsigned((reg10 - reg7)) ^ $signed($unsigned((9'ha))))); +reg15 = wire0; +reg16 = $unsigned($unsigned($unsigned(reg9))); +reg17 = (reg10 >>> $signed($signed($unsigned((-8'h6))))); +if(($unsigned((~((-wire4) >>> $unsigned(wire5)))) == (32'h0))) +begin +reg18 = ((^~(-15'h3)) ~^ (5'h7)); +reg19 <= $signed($signed(wire1)); +reg20 = (-14'h1); +reg21 <= ((-6'ha) < $signed($signed(wire5))); +reg22 <= (-((^~(^reg20)) < $signed($signed(reg10)))); +reg23 = wire0; +if((((reg20 & reg7) ~^ ((!(9'h8)) >>> $signed((!reg11)))) == (32'h0))) +begin +reg24 = $signed((-4'h9)); +reg25 = $signed($signed(reg10)); +reg26 <= (!((!(+reg19)) >= reg6)); +end +reg27 = ((+reg18) || (^~reg22)); +reg28 <= (($signed((~|reg16)) <= (~&(®6))) >>> $signed($unsigned(reg14))); +reg29 = $signed($signed($unsigned((-8'hd)))); +end +else +begin +reg30 = $signed(reg6); +reg31 = $unsigned((15'he)); +reg32 <= $signed((reg12 ^~ $unsigned(reg8))); +reg33 <= (-7'h1); +reg34 = ((|wire2) >= (reg28 ^ $unsigned($unsigned(reg18)))); +reg35 = $unsigned((10'h8)); +reg36 <= ((~|((12'h1) && reg12)) <= (-3'h4)); +reg37 <= (1'h1); +reg38 <= (2'h6); +reg39 <= (~^wire4); +reg40 <= $unsigned($signed($unsigned($unsigned((-11'hc))))); +reg41 <= $unsigned((~&$signed($signed((7'h7))))); +reg42 = $unsigned($unsigned((!(reg25 || reg29)))); +reg43 <= reg31; +end +end +always @(posedge clk) begin +if((((reg33 << (9'hc)) >> $unsigned((~$unsigned((14'hd))))) == (32'h0))) +begin +reg44 <= $signed($unsigned((-14'hc))); +reg45 = (3'h2); +reg46 <= $signed($unsigned($signed((^~(-11'hb))))); +reg47 <= ($unsigned((~(reg8 >= reg38))) < (7'h6)); +reg48 <= (wire3 > reg13); +reg49 = $signed($signed((~$unsigned((-4'hf))))); +reg50 <= $unsigned($unsigned($unsigned(((15'he) <= (6'hc))))); +reg51 = $signed((4'h9)); +reg52 <= $signed((2'h9)); +if(((10'h3) == (32'h0))) +begin +if(((~^(~$unsigned($signed(reg33)))) == (32'h0))) +begin +reg53 <= (7'ha); +reg54 <= ((wire2 << $signed((-14'hd))) && $unsigned($unsigned((~(9'h3))))); +reg55 = (-3'h8); +reg56 = ((-9'hb) ^ $signed(((~|(-3'hd)) >> $signed(reg28)))); +reg57 <= $signed(reg40); +reg58 <= (~((&(1'h5)) * $signed($unsigned(reg42)))); +end +else +begin +reg59 = ((&$unsigned($unsigned((1'h4)))) ^ (&($signed((2'h3)) <= $unsigned(wire3)))); +reg60 = $unsigned((-7'h3)); +end +reg61 <= reg29; +reg62 = reg12; +reg63 <= reg10; +reg64 = (-2'h7); +reg65 = wire2; +reg66 = $signed((-6'h6)); +reg67 = $unsigned((-10'he)); +end +else +begin +reg68 = $signed($unsigned(($unsigned(reg44) ^~ $signed((-8'h1))))); +reg69 = $signed((^~((reg51 <= reg13) || ((3'h4) <= reg8)))); +end +reg70 = (~|$unsigned((-2'hf))); +reg71 = (-3'h2); +end +else +begin +reg72 = wire2; +reg73 <= ((~|$signed(reg41)) ^~ reg58); +reg74 <= reg65; +reg75 = (~^wire1); +reg76 = $unsigned(reg27); +reg77 = $signed((7'hc)); +reg78 <= $unsigned(reg8); +reg79 <= $unsigned($signed(((12'hc) - ((6'hb) == reg36)))); +reg80 = $signed(((~^reg45) << $unsigned($signed((-10'h6))))); +reg81 = reg75; +end +reg82 <= $unsigned((^~wire1)); +reg83 = (-14'h5); +if(((-15'h9) == (32'h0))) +begin +reg84 = reg37; +reg85 = (7'h9); +reg86 = ((2'h2) ^~ ($signed($unsigned((4'he))) << reg67)); +end +else +begin +reg87 = $signed(((+$signed(reg80)) < ((-14'h3) > $unsigned((2'h5))))); +reg88 <= $unsigned($signed(reg30)); +reg89 <= (((!(-10'h4)) ^ reg17) && (+(~reg59))); +reg90 <= ($signed(((!reg23) - (-5'he))) & ((-$unsigned(reg77)) >>> ($signed((-15'h9)) < $signed(reg27)))); +reg91 <= (-4'h9); +if(((reg28 | (4'hf)) == (32'h0))) +begin +reg92 <= reg87; +reg93 = (!(~^$unsigned((~|wire5)))); +end +else +begin +reg94 <= $unsigned(reg13); +reg95 = $signed($unsigned($unsigned(wire5))); +reg96 = $signed(reg73); +reg97 <= $unsigned((($unsigned((14'hf)) ^~ (12'hf)) == (((-2'h9) > reg45) || (-9'h4)))); +reg98 = $unsigned($unsigned(reg36)); +reg99 <= $signed(((3'h6) * reg69)); +reg100 = $signed($unsigned((5'hf))); +reg101 = (-12'h2); +reg102 <= ((($signed((14'hf)) ^~ reg76) & $unsigned($unsigned((6'h1)))) ~^ $signed(((reg60 >> reg54) ^ $signed(reg70)))); +reg103 = $unsigned((|(-7'he))); +reg104 = ($unsigned(($unsigned((12'hc)) && (-13'h1))) - (|$unsigned(((-6'ha) <<< reg45)))); +reg105 = ((-11'hb) ~^ (-3'hf)); +reg106 = (~^(+reg75)); +end +end +reg107 = reg49; +reg108 <= reg15; +reg109 = $signed(reg33); +if(((~(11'h1)) == (32'h0))) +begin +reg110 = $unsigned(reg91); +reg111 <= (-(-5'h2)); +end +else +begin +reg112 <= $unsigned(($signed($signed(reg58)) ~^ reg20)); +reg113 <= (~^$signed(reg23)); +reg114 <= reg25; +reg115 <= (-5'h8); +if(($signed(($unsigned(reg10) >= (4'ha))) == (32'h0))) +begin +reg116 = (^((9'h7) == (~reg95))); +reg117 = (+((10'hd) <= (-3'ha))); +reg118 <= (~(reg109 & $unsigned((^~reg55)))); +reg119 <= (|$signed(reg69)); +end +else +begin +reg120 = (4'hd); +reg121 = (&(~^(((-5'h7) * reg92) < $unsigned((11'h2))))); +reg122 <= $unsigned((&$unsigned(((9'h7) ^ reg68)))); +reg123 <= (-$unsigned((reg91 | $signed((10'ha))))); +if(($unsigned((-2'hd)) == (32'h0))) +begin +reg124 <= $signed((8'h0)); +reg125 <= (-((~®41) != $signed((~&(-14'ha))))); +reg126 <= $unsigned(reg63); +reg127 <= ((3'hc) ^~ reg80); +reg128 <= (|(-5'h1)); +reg129 = reg45; +reg130 <= reg110; +reg131 <= ((-9'h8) > $unsigned(((9'h8) <= ((-3'h6) && (-14'h2))))); +reg132 = (14'h2); +reg133 <= (-(+reg120)); +reg134 = (-8'hf); +end +else +begin +reg135 = (-1'h1); +reg136 = reg133; +reg137 = $signed((-2'h5)); +reg138 <= $unsigned(((-8'h2) * reg84)); +reg139 <= (-((reg119 >> $unsigned((4'h1))) & $unsigned((reg133 << (8'hc))))); +reg140 <= (12'h1); +reg141 = $signed(reg100); +reg142 <= reg85; +reg143 = $signed(reg103); +reg144 = (+(~|($signed((14'h9)) + (-15'h8)))); +reg145 = ((-reg34) <= reg125); +reg146 <= ($signed((-4'h4)) <= (~&(-3'h6))); +reg147 <= (-(6'h6)); +end +reg148 <= reg144; +reg149 = $unsigned((+(6'h1))); +reg150 <= ($signed(($signed((4'hb)) >>> $unsigned((3'h5)))) <= $signed((~&(reg20 >>> reg111)))); +reg151 = $signed($unsigned(((11'h3) && $signed((7'ha))))); +reg152 <= reg63; +end +reg153 = (-7'h3); +if(($signed((reg47 | (((-13'hf) ~^ reg129) >>> ((9'hf) - reg18)))) == (32'h0))) +begin +reg154 = (-2'h7); +reg155 <= reg69; +reg156 <= $signed($signed(((^~(-1'h3)) > (7'he)))); +reg157 <= $signed(reg120); +reg158 <= (^(12'hc)); +reg159 <= $signed($signed($unsigned((&(12'h3))))); +reg160 = ((6'h7) || $signed(((|(9'h1)) - $unsigned(reg76)))); +reg161 <= (~(13'hb)); +reg162 = (~|($signed((reg104 * reg59)) ^~ reg151)); +reg163 <= (-14'hd); +reg164 <= ($signed($signed($unsigned((-11'h8)))) >= (~($signed((3'h8)) ^ $unsigned(reg150)))); +reg165 = $signed($signed(($signed((-9'hd)) >> $signed((-1'he))))); +reg166 = (|(~&(-6'h6))); +reg167 = (7'h2); +reg168 = reg20; +end +else +begin +reg169 = (1'h9); +reg170 <= (4'h7); +reg171 = reg47; +reg172 <= $unsigned((~$signed((reg81 >>> reg114)))); +reg173 = (~|$unsigned((~(~|(-8'ha))))); +reg174 = (1'hd); +reg175 = ((-3'h8) ^ (-1'h6)); +reg176 <= (~|$signed($unsigned((~^(-15'hd))))); +reg177 = ((((-7'h7) >> (~|reg86)) + (~^reg38)) && (14'h3)); +reg178 <= reg154; +if(((2'h1) == (32'h0))) +begin +reg179 <= $unsigned($signed($signed((^~(11'h2))))); +reg180 = $unsigned(reg46); +reg181 = (14'h7); +reg182 <= (($signed((reg164 * reg143)) > $signed((reg49 < reg7))) << (+$signed(reg66))); +reg183 = $unsigned((((13'h6) * (reg15 ^ reg124)) >> ((^(11'hb)) <<< $unsigned((-13'h6))))); +reg184 <= ((1'h5) * $unsigned(reg174)); +end +else +begin +reg185 <= wire4; +reg186 = reg70; +reg187 <= reg51; +reg188 <= $unsigned(reg123); +reg189 = $signed((^$unsigned(reg163))); +end +reg190 = $signed($unsigned((-13'h5))); +reg191 = $signed((8'h2)); +reg192 <= reg70; +end +reg193 = $unsigned($unsigned(reg14)); +reg194 <= $unsigned(($unsigned((reg147 && (5'h9))) & $unsigned($signed((7'he))))); +end +end +assign wire195 = reg108; +always @(posedge clk) begin +reg196 = (!(!reg63)); +reg197 = $unsigned((~(&$unsigned((6'hf))))); +reg198 = (15'h1); +reg199 <= wire1; +reg200 = (!reg41); +reg201 = reg160; +reg202 <= $unsigned(((^~(~|(9'h9))) ^ (reg104 >= (^(-11'h8))))); +reg203 <= $unsigned((-(-8'h7))); +reg204 = (7'h0); +reg205 = (9'h8); +reg206 <= (($signed(reg148) ^~ $unsigned($signed(reg65))) <<< $unsigned($signed((!reg176)))); +reg207 = $unsigned(reg205); +reg208 = wire3; +end +assign y = {reg208, reg207, reg206, reg205, reg204, reg203, reg202, reg201, reg200, reg199, reg198, reg197, reg196, wire195, reg194, reg193, reg192, reg191, reg190, reg189, reg188, reg187, reg186, reg185, reg184, reg183, reg182, reg181, reg180, reg179, reg178, reg177, reg176, reg175, reg174, reg173, reg172, reg171, reg170, reg169, reg168, reg167, reg166, reg165, reg164, reg163, reg162, reg161, reg160, reg159, reg158, reg157, reg156, reg155, reg154, reg153, reg152, reg151, reg150, reg149, reg148, reg147, reg146, reg145, reg144, reg143, reg142, reg141, reg140, reg139, reg138, reg137, reg136, reg135, reg134, reg133, reg132, reg131, reg130, reg129, reg128, reg127, reg126, reg125, reg124, reg123, reg122, reg121, reg120, reg119, reg118, reg117, reg116, reg115, reg114, reg113, reg112, reg111, reg110, reg109, reg108, reg107, reg106, reg105, reg104, reg103, reg102, reg101, reg100, reg99, reg98, reg97, reg96, reg95, reg94, reg93, reg92, reg91, reg90, reg89, reg88, reg87, reg86, reg85, reg84, reg83, reg82, reg81, reg80, reg79, reg78, reg77, reg76, reg75, reg74, reg73, reg72, reg71, reg70, reg69, reg68, reg67, reg66, reg65, reg64, reg63, reg62, reg61, reg60, reg59, reg58, reg57, reg56, reg55, reg54, reg53, reg52, reg51, reg50, reg49, reg48, reg47, reg46, reg45, reg44, reg43, reg42, reg41, reg40, reg39, reg38, reg37, reg36, reg35, reg34, reg33, reg32, reg31, reg30, reg29, reg28, reg27, reg26, reg25, reg24, reg23, reg22, reg21, reg20, reg19, reg18, reg17, reg16, reg15, reg14, reg13, reg12, reg11, reg10, reg9, reg8, reg7, reg6, wire5, wire4, wire3}; +endmodule diff --git a/bugs/vivado/2_minimal.v b/bugs/vivado/2_minimal.v new file mode 100644 index 0000000..227550e --- /dev/null +++ b/bugs/vivado/2_minimal.v @@ -0,0 +1,28 @@ +(* use_dsp48="no" *) module top + (y, clk, wire0, wire1, wire2, wire3); + output wire [163:0] y; + input wire clk; + input wire signed [11:0] wire0; + input wire [13:0] wire1; + input wire signed [7:0] wire2; + input wire signed [3:0] wire3; + wire signed [12:0] wire19; + wire [6:0] wire18; + wire [4:0] wire17; + wire signed [12:0] wire16; + wire signed [19:0] wire15; + wire [7:0] wire14; + wire wire13; + wire [10:0] wire12; + wire signed [9:0] wire11; + wire signed [16:0] wire10; + reg [15:0] reg9; + reg signed [11:0] reg8; + wire [6:0] wire7; + wire signed [6:0] wire6; + wire [10:0] wire5; + wire [5:0] wire4; + assign wire13 = {wire0, $unsigned(((-17'hd) ? wire0 : (-18'he))), (((9'h8) ? (11'he) : reg8) <<< (~&(-8'h2))), ({reg9, wire1, (3'h12), (-5'hc)} | (&(-1'h12)))}; + assign wire17 = ((wire13 ? 1'b1 : ( 1'b1 ? (14'he) : wire0)) ? $unsigned($unsigned(((-2'h5)))) : $unsigned($unsigned((wire13 || wire2)))); + assign y = {wire17}; +endmodule diff --git a/bugs/vivado/2_original.v b/bugs/vivado/2_original.v new file mode 100644 index 0000000..f60b789 --- /dev/null +++ b/bugs/vivado/2_original.v @@ -0,0 +1,44 @@ +(* use_dsp48="no" *) module top + (y, clk, wire0, wire1, wire2, wire3); + output wire [163:0] y; + input wire clk; + input wire signed [11:0] wire0; + input wire [13:0] wire1; + input wire signed [7:0] wire2; + input wire signed [3:0] wire3; + wire signed [12:0] wire19; + wire [6:0] wire18; + wire [4:0] wire17; + wire signed [12:0] wire16; + wire signed [19:0] wire15; + wire [7:0] wire14; + wire wire13; + wire [10:0] wire12; + wire signed [9:0] wire11; + wire signed [16:0] wire10; + reg [15:0] reg9; + reg signed [11:0] reg8; + wire [6:0] wire7; + wire signed [6:0] wire6; + wire [10:0] wire5; + wire [5:0] wire4; + assign wire4 = $unsigned(($unsigned((-6'h11)) ? ((wire3 ? wire3 : (8'h0)) && $signed(wire2)) : (19'he))); + assign wire5 = wire0; + assign wire6 = (5'h4); + assign wire7 = (wire4 ? {wire2, wire3, wire0, (-9'h6), (20'h10), wire1, (-1'hd), (-2'h10), (6'hc), (-16'hd), wire0} : $unsigned($unsigned((16'h5)))); + always @(posedge clk) begin + reg8 = wire6; + reg9 = wire0; + end + assign wire10 = (+wire0); + assign wire11 = $unsigned({(wire6 || (1'h2))}); + assign wire12 = (12'h7); + assign wire13 = {wire5, $unsigned(((-17'hd) ? wire5 : (-18'he))), (((9'h8) ? (11'he) : reg8) <<< (~&(-8'h2))), ({reg9, wire1, (3'h12), (-5'hc)} | (&(-1'h12)))}; + assign wire14 = ((3'h5) >>> ($unsigned((wire6 ? reg9 : (-16'hb))) > ((wire2 ^ (-20'h1)) ? ((11'h14) ? wire12 : (-10'h13)) : {(-15'h11), wire0, (-3'he), (-12'h14), (-3'hd), (-19'h11)}))); + assign wire15 = $unsigned(wire14); + assign wire16 = ({((-15'hc) >= (2'ha)), (wire15 || reg8), $signed(wire12), {(-10'h12), wire7, wire1, (-19'h14), (5'ha), wire0, wire4, (15'h2), (14'hc), reg9, (19'hb), wire5, (8'h8), wire11, (-11'hc), wire5, wire2, (17'h0), (13'hb), wire2}, (1'h13), (11'hc), (9'h13), (-5'h2), $signed((1'hf)), (reg9 << wire2), {(11'h6), reg8, wire15, wire5, (16'ha), (20'ha), (-5'h8), wire14, (-4'h7), wire4, (4'ha), reg9, (-1'h2)}, $unsigned(reg9), ((-12'h1) ? wire3 : (11'h0)), (|(3'h3)), reg9, {(-13'h2), (-16'h13)}, wire2, (^~wire1), $signed(reg8)} == $signed({(-12'hf), wire11, (-14'h2), (13'he), wire4, reg8, (6'h7), reg9, reg8, wire4, wire3})); + assign wire17 = ((wire13 ? ((7'h14) ? (-14'hb) : (-9'h7)) : (wire6 ? (14'he) : wire0)) ? $unsigned($unsigned(((-2'h5) * wire7))) : $unsigned($unsigned((wire13 || wire2)))); + assign wire18 = wire3; + assign wire19 = wire2; + assign y = {wire19, wire18, wire17, wire16, wire15, wire14, wire13, wire12, wire11, wire10, reg9, reg8, wire7, wire6, wire5, wire4}; +endmodule diff --git a/scripts/setup.sh b/scripts/setup.sh index bd07b12..4006f99 100644 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -1,19 +1,19 @@ #!/bin/sh sudo yum -y update -sudo yum -y install git gcc gcc-c++ tcl-devel python3 \ +sudo yum -y install git gcc gcc-c++ tcl-devel python36 \ graphviz xdot gperf gmp-devel make bison flex autoconf \ tmux sudo mkdir -p /mnt/tools -sudo mount /dev/sdf1 /mnt/tools +sudo mount /dev/nvme2n1p1 /mnt/tools sudo chown -R $USER:$USER /mnt/tools/home/ec2-user curl -sSL https://get.haskellstack.org/ | sh { cat <<EOF -export PATH="\${PATH}:/mnt/tools/bin:/mnt/tools/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/" +export PATH="\${PATH}:/mnt/tools/bin:/mnt/tools/opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/:/mnt/tools/opt/Xilinx/Vivado/2018.3/bin" EOF } >> $HOME/.bashrc diff --git a/src/VeriFuzz.hs b/src/VeriFuzz.hs index ebedb0d..9486537 100644 --- a/src/VeriFuzz.hs +++ b/src/VeriFuzz.hs @@ -55,8 +55,7 @@ generateByteString n = do return $ randomByteString gen n [] makeSrcInfo :: ModDecl -> SourceInfo -makeSrcInfo m = - SourceInfo (m ^. modId . getIdentifier) (Verilog [Description m]) +makeSrcInfo m = SourceInfo (m ^. modId . getIdentifier) (Verilog [m]) -- | Draw a randomly generated DAG to a dot file and compile it to a png so it -- can be seen. @@ -107,18 +106,20 @@ checkEquivalence src dir = shellyFailDir $ do setenv "VERIFUZZ_ROOT" curr cd (fromText dir) catch_sh - (runEquiv defaultYosys defaultYosys (Just defaultVivado) src >> return True + ( runEquiv defaultYosys defaultYosys (Just defaultVivado) src + >> return True ) ((\_ -> return False) :: RunFailed -> Sh Bool) -- | Run a fuzz run and check if all of the simulators passed by checking if the -- generated Verilog files are equivalent. -runEquivalence :: Gen Verilog -- ^ Generator for the Verilog file. - -> Text -- ^ Name of the folder on each thread. - -> Text -- ^ Name of the general folder being used. - -> Bool -- ^ Keep flag. - -> Int -- ^ Used to track the recursion. - -> IO () +runEquivalence + :: Gen Verilog -- ^ Generator for the Verilog file. + -> Text -- ^ Name of the folder on each thread. + -> Text -- ^ Name of the general folder being used. + -> Bool -- ^ Keep flag. + -> Int -- ^ Used to track the recursion. + -> IO () runEquivalence gm t d k i = do m <- Hog.sample gm let srcInfo = SourceInfo "top" m @@ -129,7 +130,7 @@ runEquivalence gm t d k i = do setenv "VERIFUZZ_ROOT" curr cd (fromText "output" </> fromText n) catch_sh - ( runEquiv defaultYosys defaultYosys (Just defaultVivado) srcInfo + (runEquiv defaultYosys defaultYosys (Just defaultVivado) srcInfo >> echoP "Test OK" ) $ onFailure n diff --git a/src/VeriFuzz/Circuit.hs b/src/VeriFuzz/Circuit.hs index 37e25ac..d385d32 100644 --- a/src/VeriFuzz/Circuit.hs +++ b/src/VeriFuzz/Circuit.hs @@ -43,4 +43,3 @@ fromGraph = do $ nestUpTo 5 (generateAST gr) ^.. getVerilog . traverse - . getDescription diff --git a/src/VeriFuzz/Circuit/Gen.hs b/src/VeriFuzz/Circuit/Gen.hs index 817d2f8..1e31e56 100644 --- a/src/VeriFuzz/Circuit/Gen.hs +++ b/src/VeriFuzz/Circuit/Gen.hs @@ -38,7 +38,7 @@ inputsC :: Circuit -> [Node] inputsC c = inputs (getCircuit c) genPortsAST :: (Circuit -> [Node]) -> Circuit -> [Port] -genPortsAST f c = port . frNode <$> f c where port = Port Wire False 4 +genPortsAST f c = port . frNode <$> f c where port = Port Wire False 0 4 -- | Generates the nested expression AST, so that it can then generate the -- assignment expressions. @@ -67,13 +67,13 @@ genAssignAST c = catMaybes $ genContAssignAST c <$> nodes nodes = G.labNodes gr genModuleDeclAST :: Circuit -> ModDecl -genModuleDeclAST c = ModDecl i output ports $ combineAssigns yPort a +genModuleDeclAST c = ModDecl i output ports (combineAssigns yPort a) [] where i = Identifier "gen_module" ports = genPortsAST inputsC c output = [] a = genAssignAST c - yPort = Port Wire False 90 "y" + yPort = Port Wire False 0 90 "y" generateAST :: Circuit -> Verilog -generateAST c = Verilog [Description $ genModuleDeclAST c] +generateAST c = Verilog [genModuleDeclAST c] diff --git a/src/VeriFuzz/Config.hs b/src/VeriFuzz/Config.hs index d812248..66c5aa2 100644 --- a/src/VeriFuzz/Config.hs +++ b/src/VeriFuzz/Config.hs @@ -15,17 +15,36 @@ Configuration file format and parser. module VeriFuzz.Config ( Config(..) , defaultConfig + , configProbability + , configProperty , Probability(..) - , probBlock - , probNonBlock - , probAssign - , probAlways - , probCond + , probModItem + , probStmnt + , probExpr + , ProbExpr(..) + , probExprNum + , probExprId + , probExprUnOp + , probExprBinOp + , probExprCond + , probExprConcat + , probExprStr + , probExprSigned + , probExprUnsigned + , ProbModItem(..) + , probModItemAssign + , probModItemAlways + , probModItemInst + , ProbStatement(..) + , probStmntBlock + , probStmntNonBlock + , probStmntCond + , probStmntFor , propSize , propSeed - , propDepth - , configProbability - , configProperty + , propStmntDepth + , propModDepth + , propMaxModules , parseConfigFile , parseConfig , configEncode @@ -42,29 +61,55 @@ import qualified Data.Text.IO as T (writeFile) import Toml (TomlCodec, (.=)) import qualified Toml -data Probability = Probability { _probAssign :: {-# UNPACK #-} !Int - , _probAlways :: {-# UNPACK #-} !Int - , _probBlock :: {-# UNPACK #-} !Int - , _probNonBlock :: {-# UNPACK #-} !Int - , _probCond :: {-# UNPACK #-} !Int +data ProbExpr = ProbExpr { _probExprNum :: {-# UNPACK #-} !Int + , _probExprId :: {-# UNPACK #-} !Int + , _probExprUnOp :: {-# UNPACK #-} !Int + , _probExprBinOp :: {-# UNPACK #-} !Int + , _probExprCond :: {-# UNPACK #-} !Int + , _probExprConcat :: {-# UNPACK #-} !Int + , _probExprStr :: {-# UNPACK #-} !Int + , _probExprSigned :: {-# UNPACK #-} !Int + , _probExprUnsigned :: {-# UNPACK #-} !Int + } + deriving (Eq, Show) + +data ProbModItem = ProbModItem { _probModItemAssign :: {-# UNPACK #-} !Int + , _probModItemAlways :: {-# UNPACK #-} !Int + , _probModItemInst :: {-# UNPACK #-} !Int } deriving (Eq, Show) -makeLenses ''Probability +data ProbStatement = ProbStatement { _probStmntBlock :: {-# UNPACK #-} !Int + , _probStmntNonBlock :: {-# UNPACK #-} !Int + , _probStmntCond :: {-# UNPACK #-} !Int + , _probStmntFor :: {-# UNPACK #-} !Int + } + deriving (Eq, Show) -data Property = Property { _propSize :: {-# UNPACK #-} !Int - , _propSeed :: !(Maybe Int) - , _propDepth :: {-# UNPACK #-} !Int +data Probability = Probability { _probModItem :: {-# UNPACK #-} !ProbModItem + , _probStmnt :: {-# UNPACK #-} !ProbStatement + , _probExpr :: {-# UNPACK #-} !ProbExpr + } + deriving (Eq, Show) + +data Property = Property { _propSize :: {-# UNPACK #-} !Int + , _propSeed :: !(Maybe Int) + , _propStmntDepth :: {-# UNPACK #-} !Int + , _propModDepth :: {-# UNPACK #-} !Int + , _propMaxModules :: {-# UNPACK #-} !Int } deriving (Eq, Show) -makeLenses ''Property - data Config = Config { _configProbability :: {-# UNPACK #-} !Probability , _configProperty :: {-# UNPACK #-} !Property } deriving (Eq, Show) +makeLenses ''ProbExpr +makeLenses ''ProbModItem +makeLenses ''ProbStatement +makeLenses ''Probability +makeLenses ''Property makeLenses ''Config defaultValue @@ -75,29 +120,81 @@ defaultValue defaultValue x = Toml.dimap Just (fromMaybe x) . Toml.dioptional defaultConfig :: Config -defaultConfig = Config (Probability 5 1 5 1 1) (Property 20 Nothing 3) +defaultConfig = Config (Probability defModItem defStmnt defExpr) + (Property 20 Nothing 3 2 5) + where + defModItem = ProbModItem 5 1 1 + defStmnt = ProbStatement 5 5 1 1 + defExpr = ProbExpr 1 1 1 1 1 1 0 1 1 twoKey :: Toml.Piece -> Toml.Piece -> Toml.Key twoKey a b = Toml.Key (a :| [b]) +int :: Toml.Piece -> Toml.Piece -> TomlCodec Int +int a = Toml.int . twoKey a + +exprCodec :: TomlCodec ProbExpr +exprCodec = + ProbExpr + <$> defaultValue (defProb probExprNum) (intE "number") + .= _probExprNum + <*> defaultValue (defProb probExprId) (intE "variable") + .= _probExprId + <*> defaultValue (defProb probExprUnOp) (intE "unary") + .= _probExprUnOp + <*> defaultValue (defProb probExprBinOp) (intE "binary") + .= _probExprBinOp + <*> defaultValue (defProb probExprCond) (intE "ternary") + .= _probExprCond + <*> defaultValue (defProb probExprConcat) (intE "concatenation") + .= _probExprConcat + <*> defaultValue (defProb probExprStr) (intE "string") + .= _probExprStr + <*> defaultValue (defProb probExprSigned) (intE "signed") + .= _probExprSigned + <*> defaultValue (defProb probExprUnsigned) (intE "unsigned") + .= _probExprUnsigned + where + defProb i = defaultConfig ^. configProbability . probExpr . i + intE = int "expr" + +stmntCodec :: TomlCodec ProbStatement +stmntCodec = + ProbStatement + <$> defaultValue (defProb probStmntBlock) (intS "blocking") + .= _probStmntBlock + <*> defaultValue (defProb probStmntNonBlock) (intS "nonblocking") + .= _probStmntNonBlock + <*> defaultValue (defProb probStmntCond) (intS "conditional") + .= _probStmntCond + <*> defaultValue (defProb probStmntFor) (intS "forloop") + .= _probStmntFor + where + defProb i = defaultConfig ^. configProbability . probStmnt . i + intS = int "statement" + +modItemCodec :: TomlCodec ProbModItem +modItemCodec = + ProbModItem + <$> defaultValue (defProb probModItemAssign) (intM "assign") + .= _probModItemAssign + <*> defaultValue (defProb probModItemAlways) (intM "always") + .= _probModItemAlways + <*> defaultValue (defProb probModItemInst) (intM "instantiation") + .= _probModItemInst + where + defProb i = defaultConfig ^. configProbability . probModItem . i + intM = int "moditem" + probCodec :: TomlCodec Probability probCodec = Probability - <$> defaultValue (defProb probAssign) - (Toml.int $ twoKey "moditem" "assign") - .= _probAssign - <*> defaultValue (defProb probAlways) - (Toml.int $ twoKey "moditem" "always") - .= _probAlways - <*> defaultValue (defProb probBlock) - (Toml.int $ twoKey "statement" "blocking") - .= _probBlock - <*> defaultValue (defProb probNonBlock) - (Toml.int $ twoKey "statement" "nonblocking") - .= _probNonBlock - <*> defaultValue (defProb probNonBlock) - (Toml.int $ twoKey "statement" "conditional") - .= _probCond + <$> defaultValue (defProb probModItem) modItemCodec + .= _probModItem + <*> defaultValue (defProb probStmnt) stmntCodec + .= _probStmnt + <*> defaultValue (defProb probExpr) exprCodec + .= _probExpr where defProb i = defaultConfig ^. configProbability . i propCodec :: TomlCodec Property @@ -107,8 +204,12 @@ propCodec = .= _propSize <*> Toml.dioptional (Toml.int "seed") .= _propSeed - <*> defaultValue (defProp propDepth) (Toml.int "depth") - .= _propDepth + <*> defaultValue (defProp propStmntDepth) (int "statement" "depth") + .= _propStmntDepth + <*> defaultValue (defProp propModDepth) (int "module" "depth") + .= _propModDepth + <*> defaultValue (defProp propMaxModules) (int "module" "max") + .= _propMaxModules where defProp i = defaultConfig ^. configProperty . i configCodec :: TomlCodec Config diff --git a/src/VeriFuzz/Internal.hs b/src/VeriFuzz/Internal.hs index 51bb52c..22efa92 100644 --- a/src/VeriFuzz/Internal.hs +++ b/src/VeriFuzz/Internal.hs @@ -15,6 +15,7 @@ module VeriFuzz.Internal safe , showT , comma + , commaNL ) where @@ -33,3 +34,7 @@ showT = T.pack . show -- | Inserts commas between '[Text]' and except the last one. comma :: [Text] -> Text comma = T.intercalate ", " + +-- | Inserts commas and newlines between '[Text]' and except the last one. +commaNL :: [Text] -> Text +commaNL = T.intercalate ",\n" diff --git a/src/VeriFuzz/RecursionScheme.hs b/src/VeriFuzz/RecursionScheme.hs new file mode 100644 index 0000000..7d89498 --- /dev/null +++ b/src/VeriFuzz/RecursionScheme.hs @@ -0,0 +1,84 @@ +{-| +Module : VeriFuzz.RecursionScheme +Description : Recursion scheme implementation for the AST. +Copyright : (c) 2019, Yann Herklotz Grave +License : GPL-3 +Maintainer : ymherklotz [at] gmail [dot] com +Stability : experimental +Portability : POSIX + +Recursion scheme implementation for the AST. +-} + +module VeriFuzz.RecursionScheme + ( Term(..) + , Attr(..) + , Algebra + , bottomUp + , topDown + , cata + , ana + , para + , apo + ) +where + +import Control.Arrow ((&&&), (>>>), (|||)) +import Data.Function ((&)) + +newtype Term f = In { out :: f (Term f) } + +data Attr f a = Attr + { attribute :: a + , hole :: f (Attr f a) + } + +type Algebra f a = f a -> a + +type RAlgebra f a = f (Term f, a) -> a + +type RAlgebra' f a = Term f -> f a -> a + +type CVAlgebra f a = f (Attr f a) -> a + +type Coalgebra f a = a -> f a + +type RCoalgebra f a = a -> f (Either (Term f) a) + +bottomUp :: Functor a => (Term a -> Term a) -> Term a -> Term a +bottomUp fn = cata $ In >>> fn + +topDown :: Functor a => (Term a -> Term a) -> Term a -> Term a +topDown fn = ana $ fn >>> out + +cata :: Functor f => Algebra f a -> Term f -> a +cata fn = para' $ const fn + +ana :: Functor f => Coalgebra f a -> a -> Term f +ana fn = + fn + >>> fmap (ana fn) + >>> In + +para :: Functor f => RAlgebra f a -> Term f -> a +para ralg = + out + >>> fmap (id &&& para ralg) + >>> ralg + +para' :: Functor f => RAlgebra' f a -> Term f -> a +para' ralg t = out t & fmap (para' ralg) & ralg t + +apo :: Functor f => RCoalgebra f a -> a -> Term f +apo rcoalg = + rcoalg + >>> fmap (id ||| apo rcoalg) + >>> In + +histo :: Functor f => CVAlgebra f a -> Term f -> a +histo cv = + out + >>> fmap worker + >>> cv + where + worker t = undefined diff --git a/src/VeriFuzz/Sim/Icarus.hs b/src/VeriFuzz/Sim/Icarus.hs index 14023b7..8876706 100644 --- a/src/VeriFuzz/Sim/Icarus.hs +++ b/src/VeriFuzz/Sim/Icarus.hs @@ -93,8 +93,9 @@ runSimIcarus sim rinfo bss = do $ fold (addDisplay $ assignFunc (_modInPorts m) <$> bss) <> (SysTaskEnable $ Task "finish" []) ] + [] let newtb = instantiateMod m tb - let modWithTb = Verilog $ Description <$> [newtb, m] + let modWithTb = Verilog [newtb, m] writefile "main.v" $ genSource modWithTb runSimWithFile sim "main.v" bss where m = rinfo ^. mainModule diff --git a/src/VeriFuzz/Sim/Internal.hs b/src/VeriFuzz/Sim/Internal.hs index 062035c..145042a 100644 --- a/src/VeriFuzz/Sim/Internal.hs +++ b/src/VeriFuzz/Sim/Internal.hs @@ -73,10 +73,10 @@ mainModule = lens get_ set_ where set_ (SourceInfo top main) v = SourceInfo top (main & getModule %~ update top v) - update top v m@(ModDecl (Identifier i) _ _ _) | i == top = v - | otherwise = m + update top v m@(ModDecl (Identifier i) _ _ _ _) | i == top = v + | otherwise = m get_ (SourceInfo top main) = head . filter (f top) $ main ^.. getModule - f top (ModDecl (Identifier i) _ _ _) = i == top + f top (ModDecl (Identifier i) _ _ _ _) = i == top rootPath :: Sh FilePath rootPath = do diff --git a/src/VeriFuzz/Sim/Reduce.hs b/src/VeriFuzz/Sim/Reduce.hs index 5684ed5..361df3e 100644 --- a/src/VeriFuzz/Sim/Reduce.hs +++ b/src/VeriFuzz/Sim/Reduce.hs @@ -67,8 +67,8 @@ filterExpr ids (Id i) = if i `notElem` ids then Number 1 0 else Id i filterExpr _ e = e filterDecl :: [Identifier] -> ModItem -> Bool -filterDecl ids (Decl Nothing (Port _ _ _ i)) = i `elem` ids -filterDecl _ _ = True +filterDecl ids (Decl Nothing (Port _ _ _ _ i) _) = i `elem` ids +filterDecl _ _ = True filterAssigns :: [Port] -> ModItem -> Bool filterAssigns out (ModCA (ContAssign i _)) = diff --git a/src/VeriFuzz/Sim/Template.hs b/src/VeriFuzz/Sim/Template.hs index 0fc74a0..f630ea6 100644 --- a/src/VeriFuzz/Sim/Template.hs +++ b/src/VeriFuzz/Sim/Template.hs @@ -91,7 +91,7 @@ sbyConfig bd sim1 sim2 (SourceInfo top src) = [st|[options] mode prove [engines] -smtbmc +smtbmc z3 [script] #{readL} diff --git a/src/VeriFuzz/Verilog.hs b/src/VeriFuzz/Verilog.hs index fdf2ac0..4d3b82c 100644 --- a/src/VeriFuzz/Verilog.hs +++ b/src/VeriFuzz/Verilog.hs @@ -14,12 +14,11 @@ module VeriFuzz.Verilog ( Verilog(..) , parseVerilog , procedural + , proceduralIO , randomMod , GenVerilog(..) , genSource , getVerilog - , Description(..) - , getDescription -- * Primitives -- ** Identifier , Identifier(..) @@ -69,8 +68,6 @@ module VeriFuzz.Verilog , exprFunc , exprBody , exprStr - , exprWithContext - , traverseExpr , ConstExpr(..) , constNum , Function(..) @@ -91,7 +88,6 @@ module VeriFuzz.Verilog , statements , stmntBA , stmntNBA - , stmntCA , stmntTask , stmntSysTask , stmntCondExpr @@ -118,10 +114,6 @@ module VeriFuzz.Verilog -- * Useful Lenses and Traversals , getModule , getSourceId - -- * Arbitrary - , Arb - , arb - , genPositive ) where diff --git a/src/VeriFuzz/Verilog/AST.hs b/src/VeriFuzz/Verilog/AST.hs index 405b712..007b3b5 100644 --- a/src/VeriFuzz/Verilog/AST.hs +++ b/src/VeriFuzz/Verilog/AST.hs @@ -18,8 +18,6 @@ module VeriFuzz.Verilog.AST ( -- * Top level types Verilog(..) , getVerilog - , Description(..) - , getDescription -- * Primitives -- ** Identifier , Identifier(..) @@ -50,6 +48,7 @@ module VeriFuzz.Verilog.AST , Port(..) , portType , portSigned + , portSizeLower , portSize , portName -- * Expression @@ -69,10 +68,20 @@ module VeriFuzz.Verilog.AST , exprFunc , exprBody , exprStr - , exprWithContext - , traverseExpr , ConstExpr(..) + , constSize , constNum + , constParamId + , constConcat + , constUnOp + , constPrim + , constLhs + , constBinOp + , constRhs + , constCond + , constTrue + , constFalse + , constStr , Function(..) -- * Assignment , Assign(..) @@ -82,6 +91,13 @@ module VeriFuzz.Verilog.AST , ContAssign(..) , contAssignNetLVal , contAssignExpr + -- ** Parameters + , Parameter(..) + , paramIdent + , paramValue + , LocalParam(..) + , localParamIdent + , localParamValue -- * Statment , Statement(..) , statDelay @@ -91,26 +107,33 @@ module VeriFuzz.Verilog.AST , statements , stmntBA , stmntNBA - , stmntCA , stmntTask , stmntSysTask , stmntCondExpr , stmntCondTrue , stmntCondFalse + , forAssign + , forExpr + , forIncr + , forStmnt -- * Module , ModDecl(..) , modId , modOutPorts , modInPorts , modItems + , modParams , ModItem(..) , modContAssign , modInstId , modInstName , modInstConns + , paramDecl + , localParamDecl , traverseModItem , declDir , declPort + , declVal , ModConn(..) , modConn , modConnName @@ -118,25 +141,16 @@ module VeriFuzz.Verilog.AST -- * Useful Lenses and Traversals , getModule , getSourceId - -- * Arbitrary - , Arb - , arb - , genPositive ) where import Control.Lens -import Control.Monad (replicateM) import Data.Data import Data.Data.Lens -import Data.List.NonEmpty (toList) +import Data.List.NonEmpty (NonEmpty) import Data.String (IsString, fromString) import Data.Text (Text) -import qualified Data.Text as T import Data.Traversable (sequenceA) -import Hedgehog (Gen) -import qualified Hedgehog.Gen as Hog -import qualified Hedgehog.Range as Hog -- | Identifier in Verilog. This is just a string of characters that can either -- be lowercase and uppercase for now. This might change in the future though, @@ -199,7 +213,7 @@ data UnaryOperator = UnPlus -- ^ @+@ deriving (Eq, Show, Ord, Data) data Function = SignedFunc - | UnSignedFunc + | UnsignedFunc deriving (Eq, Show, Ord, Data) -- | Verilog expression, which can either be a primary expression, unary @@ -250,17 +264,49 @@ instance IsString Expr where instance Plated Expr where plate = uniplate -traverseExpr :: (Applicative f) => (Expr -> f Expr) -> Expr -> f Expr -traverseExpr f (Concat e ) = Concat <$> sequenceA (f <$> e) -traverseExpr f (UnOp u e ) = UnOp u <$> f e -traverseExpr f (BinOp l o r) = BinOp <$> f l <*> pure o <*> f r -traverseExpr f (Cond c l r) = Cond <$> f c <*> f l <*> f r -traverseExpr f (Func fn e ) = Func fn <$> f e -traverseExpr _ e = pure e +-- | Constant expression, which are known before simulation at compile time. +data ConstExpr = ConstNum { _constSize :: Int + , _constNum :: Integer + } + | ParamId { _constParamId :: {-# UNPACK #-} !Identifier } + | ConstConcat { _constConcat :: [ConstExpr] } + | ConstUnOp { _constUnOp :: !UnaryOperator + , _constPrim :: ConstExpr + } + | ConstBinOp { _constLhs :: ConstExpr + , _constBinOp :: !BinaryOperator + , _constRhs :: ConstExpr + } + | ConstCond { _constCond :: ConstExpr + , _constTrue :: ConstExpr + , _constFalse :: ConstExpr + } + | ConstStr { _constStr :: {-# UNPACK #-} !Text } + deriving (Eq, Show, Ord, Data) + +instance Num ConstExpr where + a + b = ConstBinOp a BinPlus b + a - b = ConstBinOp a BinMinus b + a * b = ConstBinOp a BinTimes b + negate = ConstUnOp UnMinus + abs = undefined + signum = undefined + fromInteger = ConstNum 32 . fromInteger + +instance Semigroup ConstExpr where + (ConstConcat a) <> (ConstConcat b) = ConstConcat $ a <> b + (ConstConcat a) <> b = ConstConcat $ a <> [b] + a <> (ConstConcat b) = ConstConcat $ a : b + a <> b = ConstConcat [a, b] --- | Constant expression, which are known before simulation at compilation time. -newtype ConstExpr = ConstExpr { _constNum :: Int } - deriving (Eq, Show, Ord, Data, Num) +instance Monoid ConstExpr where + mempty = ConstConcat [] + +instance IsString ConstExpr where + fromString = ConstStr . fromString + +instance Plated ConstExpr where + plate = uniplate data Task = Task { _taskName :: {-# UNPACK #-} !Identifier , _taskExpr :: [Expr] @@ -306,10 +352,11 @@ data PortType = Wire -- -- This is now implemented inside 'ModDecl' itself, which uses a list of output -- and input ports. -data Port = Port { _portType :: !PortType - , _portSigned :: !Bool - , _portSize :: {-# UNPACK #-} !Int - , _portName :: {-# UNPACK #-} !Identifier +data Port = Port { _portType :: !PortType + , _portSigned :: !Bool + , _portSizeLower :: {-# UNPACK #-} !Int + , _portSize :: {-# UNPACK #-} !Int + , _portName :: {-# UNPACK #-} !Identifier } deriving (Eq, Show, Ord, Data) -- | This is currently a type because direct module declaration should also be @@ -343,13 +390,17 @@ data Statement = TimeCtrl { _statDelay :: {-# UNPACK #-} !Delay | SeqBlock { _statements :: [Statement] } -- ^ Sequential block (@begin ... end@) | BlockAssign { _stmntBA :: !Assign } -- ^ blocking assignment (@=@) | NonBlockAssign { _stmntNBA :: !Assign } -- ^ Non blocking assignment (@<=@) - | StatCA { _stmntCA :: !ContAssign } -- ^ Statement continuous assignment. May not be correct. | TaskEnable { _stmntTask :: !Task } | SysTaskEnable { _stmntSysTask :: !Task } | CondStmnt { _stmntCondExpr :: Expr , _stmntCondTrue :: Maybe Statement , _stmntCondFalse :: Maybe Statement } + | ForLoop { _forAssign :: !Assign + , _forExpr :: Expr + , _forIncr :: !Assign + , _forStmnt :: Statement + } -- ^ Loop bounds shall be statically computable for a for loop. deriving (Eq, Show, Ord, Data) instance Semigroup Statement where @@ -361,6 +412,19 @@ instance Semigroup Statement where instance Monoid Statement where mempty = SeqBlock [] +-- | Parameter that can be assigned in blocks or modules using @parameter@. +data Parameter = Parameter { _paramIdent :: {-# UNPACK #-} !Identifier + , _paramValue :: ConstExpr + } + deriving (Eq, Show, Ord, Data) + +-- | Local parameter that can be assigned anywhere using @localparam@. It cannot +-- be changed by initialising the module. +data LocalParam = LocalParam { _localParamIdent :: {-# UNPACK #-} !Identifier + , _localParamValue :: ConstExpr + } + deriving (Eq, Show, Ord, Data) + -- | Module item which is the body of the module expression. data ModItem = ModCA { _modContAssign :: !ContAssign } | ModInst { _modInstId :: {-# UNPACK #-} !Identifier @@ -371,7 +435,10 @@ data ModItem = ModCA { _modContAssign :: !ContAssign } | Always !Statement | Decl { _declDir :: !(Maybe PortDir) , _declPort :: !Port + , _declVal :: Maybe ConstExpr } + | ParamDecl { _paramDecl :: NonEmpty Parameter } + | LocalParamDecl { _localParamDecl :: NonEmpty LocalParam } deriving (Eq, Show, Ord, Data) -- | 'module' module_identifier [list_of_ports] ';' { module_item } 'end_module' @@ -379,7 +446,9 @@ data ModDecl = ModDecl { _modId :: {-# UNPACK #-} !Identifier , _modOutPorts :: [Port] , _modInPorts :: [Port] , _modItems :: [ModItem] - } deriving (Eq, Show, Ord, Data) + , _modParams :: [Parameter] + } + deriving (Eq, Show, Ord, Data) traverseModConn :: (Applicative f) => (Expr -> f Expr) -> ModConn -> f ModConn traverseModConn f (ModConn e ) = ModConn <$> f e @@ -391,12 +460,8 @@ traverseModItem f (ModInst a b e) = ModInst a b <$> sequenceA (traverseModConn f <$> e) traverseModItem _ e = pure e --- | Description of the Verilog module. -newtype Description = Description { _getDescription :: ModDecl } - deriving (Eq, Show, Ord, Data) - -- | The complete sourcetext for the Verilog module. -newtype Verilog = Verilog { _getVerilog :: [Description] } +newtype Verilog = Verilog { _getVerilog :: [ModDecl] } deriving (Eq, Show, Ord, Data, Semigroup, Monoid) makeLenses ''Identifier @@ -412,206 +477,15 @@ makeLenses ''Assign makeLenses ''ContAssign makeLenses ''Statement makeLenses ''ModItem +makeLenses ''Parameter +makeLenses ''LocalParam makeLenses ''ModDecl -makeLenses ''Description makeLenses ''Verilog getModule :: Traversal' Verilog ModDecl -getModule = getVerilog . traverse . getDescription +getModule = getVerilog . traverse {-# INLINE getModule #-} getSourceId :: Traversal' Verilog Text getSourceId = getModule . modId . getIdentifier {-# INLINE getSourceId #-} - -listOf1 :: Gen a -> Gen [a] -listOf1 a = toList <$> Hog.nonEmpty (Hog.linear 0 100) a - -listOf :: Gen a -> Gen [a] -listOf = Hog.list (Hog.linear 0 100) - -genPositive :: Gen Int -genPositive = Hog.filter (>= 0) $ Hog.int (Hog.linear 1 99) - -integral :: Gen Integer -integral = Hog.integral (Hog.linear 0 100) - -class Arb a where - arb :: Gen a - -instance Arb Identifier where - arb = do - l <- genPositive - Identifier . T.pack <$> replicateM (l + 1) (Hog.element ['a'..'z']) - -instance Arb Delay where - arb = Delay <$> genPositive - -instance Arb Event where - arb = EId <$> arb - -instance Arb BinaryOperator where - arb = Hog.element - [ BinPlus - , BinMinus - , BinTimes - -- , BinDiv - -- , BinMod - , BinEq - , BinNEq - -- , BinCEq - -- , BinCNEq - , BinLAnd - , BinLOr - , BinLT - , BinLEq - , BinGT - , BinGEq - , BinAnd - , BinOr - , BinXor - , BinXNor - , BinXNorInv - -- , BinPower - , BinLSL - , BinLSR - , BinASL - , BinASR - ] - -instance Arb UnaryOperator where - arb = Hog.element - [ UnPlus - , UnMinus - , UnNot - , UnLNot - , UnAnd - , UnNand - , UnOr - , UnNor - , UnXor - , UnNxor - , UnNxorInv - ] - -instance Arb Function where - arb = Hog.element - [ SignedFunc - , UnSignedFunc - ] - -instance Arb Expr where - arb = Hog.sized expr - -exprSafeList :: [Gen Expr] -exprSafeList = [Number <$> genPositive <*> integral] - -exprRecList :: (Hog.Size -> Gen Expr) -> [Gen Expr] -exprRecList subexpr = - [ Number <$> genPositive <*> integral - , Concat <$> listOf1 (subexpr 8) - , UnOp - <$> arb - <*> subexpr 2 - -- , Str <$> arb - , BinOp <$> subexpr 2 <*> arb <*> subexpr 2 - , Cond <$> subexpr 3 <*> subexpr 3 <*> subexpr 3 - , Func <$> arb <*> subexpr 2 - ] - -expr :: Hog.Size -> Gen Expr -expr n | n == 0 = Hog.choice $ (Id <$> arb) : exprSafeList - | n > 0 = Hog.choice $ (Id <$> arb) : exprRecList subexpr - | otherwise = expr 0 - where subexpr y = expr (n `div` y) - -exprWithContext :: [Identifier] -> Hog.Size -> Gen Expr -exprWithContext [] n | n == 0 = Hog.choice exprSafeList - | n > 0 = Hog.choice $ exprRecList subexpr - | otherwise = exprWithContext [] 0 - where subexpr y = exprWithContext [] (n `div` y) -exprWithContext l n - | n == 0 = Hog.choice $ (Id <$> Hog.element l) : exprSafeList - | n > 0 = Hog.choice $ (Id <$> Hog.element l) : exprRecList subexpr - | otherwise = exprWithContext l 0 - where subexpr y = exprWithContext l (n `div` y) - -instance Arb Int where - arb = Hog.int (Hog.linear 0 100) - -instance Arb ConstExpr where - arb = ConstExpr <$> Hog.int (Hog.linear 0 100) - -instance Arb Task where - arb = Task <$> arb <*> listOf arb - -instance Arb LVal where - arb = Hog.choice [ RegId <$> arb - , RegExpr <$> arb <*> arb - , RegSize <$> arb <*> arb <*> arb - ] - -instance Arb PortDir where - arb = Hog.element [PortIn, PortOut, PortInOut] - -instance Arb PortType where - arb = Hog.element [Wire, Reg] - -instance Arb Port where - arb = Port <$> arb <*> arb <*> genPositive <*> arb - -instance Arb ModConn where - arb = ModConn <$> arb - -instance Arb Assign where - arb = Assign <$> arb <*> Hog.maybe arb <*> arb - -instance Arb ContAssign where - arb = ContAssign <$> arb <*> arb - -instance Arb Statement where - arb = Hog.sized statement - -statement :: Hog.Size -> Gen Statement -statement n - | n == 0 = Hog.choice - [ BlockAssign <$> arb - , NonBlockAssign <$> arb - -- , StatCA <$> arb - , TaskEnable <$> arb - , SysTaskEnable <$> arb - ] - | n > 0 = Hog.choice - [ TimeCtrl <$> arb <*> (Just <$> substat 2) - , SeqBlock <$> listOf1 (substat 4) - , BlockAssign <$> arb - , NonBlockAssign <$> arb - -- , StatCA <$> arb - , TaskEnable <$> arb - , SysTaskEnable <$> arb - ] - | otherwise = statement 0 - where substat y = statement (n `div` y) - -instance Arb ModItem where - arb = Hog.choice [ ModCA <$> arb - , ModInst <$> arb <*> arb <*> listOf arb - , Initial <$> arb - , Always <$> (EventCtrl <$> arb <*> Hog.maybe arb) - , Decl <$> pure Nothing <*> arb - ] - -modPortGen :: Gen Port -modPortGen = Port <$> arb <*> arb <*> arb <*> arb - -instance Arb ModDecl where - arb = ModDecl <$> arb <*> listOf arb <*> listOf1 modPortGen <*> listOf arb - -instance Arb Description where - arb = Description <$> arb - -instance Arb Verilog where - arb = Verilog <$> listOf1 arb - -instance Arb Bool where - arb = Hog.element [True, False] diff --git a/src/VeriFuzz/Verilog/CodeGen.hs b/src/VeriFuzz/Verilog/CodeGen.hs index a05309f..3a8d14a 100644 --- a/src/VeriFuzz/Verilog/CodeGen.hs +++ b/src/VeriFuzz/Verilog/CodeGen.hs @@ -23,6 +23,7 @@ where import Control.Lens (view, (^.)) import Data.Foldable (fold) +import Data.List.NonEmpty (NonEmpty (..), toList) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T @@ -44,30 +45,44 @@ defMap = maybe ";\n" statement -- | Convert the 'Verilog' type to 'Text' so that it can be rendered. verilogSrc :: Verilog -> Text -verilogSrc source = fold $ description <$> source ^. getVerilog - --- | Generate the 'Description' to 'Text'. -description :: Description -> Text -description desc = moduleDecl $ desc ^. getDescription +verilogSrc (Verilog modules) = fold $ moduleDecl <$> modules -- | Generate the 'ModDecl' for a module and convert it to 'Text'. moduleDecl :: ModDecl -> Text -moduleDecl m = +moduleDecl (ModDecl i outP inP items ps) = "module " - <> m - ^. modId - . getIdentifier + <> identifier i + <> params ps <> ports <> ";\n" <> modI <> "endmodule\n" where - ports | noIn && noOut = "" - | otherwise = "(" <> comma (modPort <$> outIn) <> ")" - modI = fold $ moduleItem <$> m ^. modItems - noOut = null $ m ^. modOutPorts - noIn = null $ m ^. modInPorts - outIn = (m ^. modOutPorts) ++ (m ^. modInPorts) + ports | null outP && null inP = "" + | otherwise = "(" <> comma (modPort <$> outIn) <> ")" + modI = fold $ moduleItem <$> items + outIn = outP ++ inP + params [] = "" + params (p : pps) = "\n#(\n" <> paramList (p :| pps) <> "\n)\n" + +-- | Generates a parameter list. Can only be called with a 'NonEmpty' list. +paramList :: NonEmpty Parameter -> Text +paramList ps = "parameter " <> (commaNL . toList $ parameter <$> ps) + +-- | Generates a localparam list. Can only be called with a 'NonEmpty' list. +localParamList :: NonEmpty LocalParam -> Text +localParamList ps = "localparam " <> (commaNL . toList $ localParam <$> ps) + +-- | Generates the assignment for a 'Parameter'. +parameter :: Parameter -> Text +parameter (Parameter name val) = identifier name <> " = " <> constExpr val + +-- | Generates the assignment for a 'LocalParam'. +localParam :: LocalParam -> Text +localParam (LocalParam name val) = identifier name <> " = " <> constExpr val + +identifier :: Identifier -> Text +identifier (Identifier i) = i -- | Conversts 'Port' to 'Text' for the module list, which means it only -- generates a list of identifiers. @@ -76,13 +91,11 @@ modPort p = p ^. portName . getIdentifier -- | Generate the 'Port' description. port :: Port -> Text -port p = t <> sign <> size <> name +port (Port tp sgn low sz (Identifier name)) = t <> sign <> size <> name where - t = flip mappend " " . pType $ p ^. portType - size | p ^. portSize > 1 = "[" <> showT (p ^. portSize - 1) <> ":0] " - | otherwise = "" - name = p ^. portName . getIdentifier - sign = signed $ p ^. portSigned + t = flip mappend " " $ pType tp + size = "[" <> showT (low+sz-1) <> ":" <> showT low <> "] " + sign = signed sgn signed :: Bool -> Text signed True = "signed " @@ -101,8 +114,13 @@ moduleItem (ModInst (Identifier i) (Identifier name) conn) = i <> " " <> name <> "(" <> comma (mConn <$> conn) <> ")" <> ";\n" moduleItem (Initial stat) = "initial " <> statement stat moduleItem (Always stat) = "always " <> statement stat -moduleItem (Decl dir p ) = maybe "" makePort dir <> port p <> ";\n" - where makePort = (<> " ") . portDir +moduleItem (Decl dir p ini) = + maybe "" makePort dir <> port p <> maybe "" makeIni ini <> ";\n" + where + makePort = (<> " ") . portDir + makeIni = (" = " <>) . constExpr +moduleItem (ParamDecl p) = paramList p <> ";\n" +moduleItem (LocalParamDecl p) = localParamList p <> ";\n" mConn :: ModConn -> Text mConn (ModConn c ) = expr c @@ -116,17 +134,13 @@ contAssign (ContAssign val e) = -- | Generate 'Function' to 'Text' func :: Function -> Text func SignedFunc = "$signed" -func UnSignedFunc = "$unsigned" +func UnsignedFunc = "$unsigned" -- | Generate 'Expr' to 'Text'. expr :: Expr -> Text expr (BinOp eRhs bin eLhs) = "(" <> expr eRhs <> binaryOp bin <> expr eLhs <> ")" -expr (Number s n) = - "(" <> minus <> showT s <> "'h" <> T.pack (showHex (abs n) "") <> ")" - where - minus | signum n >= 0 = "" - | otherwise = "-" +expr (Number s n) = showNum s n expr (Id i ) = i ^. getIdentifier expr (Concat c ) = "{" <> comma (expr <$> c) <> "}" expr (UnOp u e ) = "(" <> unaryOp u <> expr e <> ")" @@ -134,6 +148,24 @@ expr (Cond l t f) = "(" <> expr l <> " ? " <> expr t <> " : " <> expr f <> ")" expr (Func f e ) = func f <> "(" <> expr e <> ")" expr (Str t ) = "\"" <> t <> "\"" +showNum :: Int -> Integer -> Text +showNum s n = + "(" <> minus <> showT s <> "'h" <> T.pack (showHex (abs n) "") <> ")" + where + minus | signum n >= 0 = "" + | otherwise = "-" + +constExpr :: ConstExpr -> Text +constExpr (ConstNum s n ) = showNum s n +constExpr (ParamId i) = identifier i +constExpr (ConstConcat c) = "{" <> comma (constExpr <$> c) <> "}" +constExpr (ConstUnOp u e) = "(" <> unaryOp u <> constExpr e <> ")" +constExpr (ConstBinOp eRhs bin eLhs) = + "(" <> constExpr eRhs <> binaryOp bin <> constExpr eLhs <> ")" +constExpr (ConstCond l t f) = + "(" <> constExpr l <> " ? " <> constExpr t <> " : " <> constExpr f <> ")" +constExpr (ConstStr t) = "\"" <> t <> "\"" + -- | Convert 'BinaryOperator' to 'Text'. binaryOp :: BinaryOperator -> Text binaryOp BinPlus = " + " @@ -196,9 +228,6 @@ lVal (RegSize i msb lsb) = i ^. getIdentifier <> " [" <> constExpr msb <> ":" <> constExpr lsb <> "]" lVal (RegConcat e) = "{" <> comma (expr <$> e) <> "}" -constExpr :: ConstExpr -> Text -constExpr (ConstExpr num) = showT num - pType :: PortType -> Text pType Wire = "wire" pType Reg = "reg" @@ -212,12 +241,20 @@ statement (EventCtrl e stat ) = event e <> " " <> defMap stat statement (SeqBlock s) = "begin\n" <> fold (statement <$> s) <> "end\n" statement (BlockAssign a ) = genAssign " = " a <> ";\n" statement (NonBlockAssign a ) = genAssign " <= " a <> ";\n" -statement (StatCA a ) = contAssign a statement (TaskEnable t ) = task t <> ";\n" statement (SysTaskEnable t ) = "$" <> task t <> ";\n" statement (CondStmnt e t Nothing) = "if(" <> expr e <> ")\n" <> defMap t statement (CondStmnt e t f) = "if(" <> expr e <> ")\n" <> defMap t <> "else\n" <> defMap f +statement (ForLoop a e incr stmnt) = + "for(" + <> genAssign " = " a + <> "; " + <> expr e + <> "; " + <> genAssign " = " incr + <> ")\n" + <> statement stmnt task :: Task -> Text task (Task name e) | null e = i @@ -275,19 +312,13 @@ instance Source Port where instance Source ModDecl where genSource = moduleDecl -instance Source Description where - genSource = description - instance Source Verilog where genSource = verilogSrc +instance Source SourceInfo where + genSource (SourceInfo _ src) = genSource src + newtype GenVerilog a = GenVerilog { unGenVerilog :: a } instance (Source a) => Show (GenVerilog a) where show = T.unpack . genSource . unGenVerilog - -instance (Arb a) => Arb (GenVerilog a) where - arb = GenVerilog <$> arb - -instance Source SourceInfo where - genSource (SourceInfo _ src) = genSource src diff --git a/src/VeriFuzz/Verilog/Gen.hs b/src/VeriFuzz/Verilog/Gen.hs index 87a0a31..c325f66 100644 --- a/src/VeriFuzz/Verilog/Gen.hs +++ b/src/VeriFuzz/Verilog/Gen.hs @@ -15,6 +15,7 @@ Various useful generators. module VeriFuzz.Verilog.Gen ( -- * Generation methods procedural + , proceduralIO , randomMod ) where @@ -25,9 +26,11 @@ import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Reader hiding (local) import Control.Monad.Trans.State.Lazy import Data.Foldable (fold) +import Data.List.NonEmpty (toList) import qualified Data.Text as T import Hedgehog (Gen) import qualified Hedgehog.Gen as Hog +import qualified Hedgehog.Range as Hog import VeriFuzz.Config import VeriFuzz.Internal import VeriFuzz.Verilog.AST @@ -35,8 +38,11 @@ import VeriFuzz.Verilog.Internal import VeriFuzz.Verilog.Mutate data Context = Context { _variables :: [Port] - , _nameCounter :: Int - , _stmntDepth :: Int + , _parameters :: [Parameter] + , _modules :: [ModDecl] + , _nameCounter :: {-# UNPACK #-} !Int + , _stmntDepth :: {-# UNPACK #-} !Int + , _modDepth :: {-# UNPACK #-} !Int } makeLenses ''Context @@ -48,7 +54,7 @@ toId = Identifier . ("w" <>) . T.pack . show toPort :: Identifier -> Gen Port toPort ident = do - i <- genPositive + i <- Hog.int $ Hog.linear 1 100 return $ wire i ident sumSize :: [Port] -> Int @@ -56,7 +62,7 @@ sumSize ps = sum $ ps ^.. traverse . portSize random :: [Identifier] -> (Expr -> ContAssign) -> Gen ModItem random ctx fun = do - expr <- Hog.sized (exprWithContext ctx) + expr <- Hog.sized (exprWithContext (ProbExpr 1 1 1 1 1 1 0 1 1) ctx) return . ModCA $ fun expr --randomAssigns :: [Identifier] -> [Gen ModItem] @@ -74,7 +80,11 @@ randomMod inps total = do let other = drop inps ident let y = ModCA . ContAssign "y" . fold $ Id <$> drop inps ids let yport = [wire (sumSize other) "y"] - return . declareMod other . ModDecl "test_module" yport inputs_ $ x ++ [y] + return . declareMod other $ ModDecl "test_module" + yport + inputs_ + (x ++ [y]) + [] where ids = toId <$> [1 .. total] end = drop inps ids @@ -83,9 +93,136 @@ randomMod inps total = do gen :: Gen a -> StateGen a gen = lift . lift +listOf1 :: Gen a -> Gen [a] +listOf1 a = toList <$> Hog.nonEmpty (Hog.linear 0 100) a + +--listOf :: Gen a -> Gen [a] +--listOf = Hog.list (Hog.linear 0 100) + +largeNum :: Gen Int +largeNum = Hog.int Hog.linearBounded + +wireSize :: Gen Int +wireSize = Hog.int $ Hog.linear 2 200 + +binOp :: Gen BinaryOperator +binOp = + Hog.element + [ BinPlus + , BinMinus + , BinTimes + -- , BinDiv + -- , BinMod + , BinEq + , BinNEq + -- , BinCEq + -- , BinCNEq + , BinLAnd + , BinLOr + , BinLT + , BinLEq + , BinGT + , BinGEq + , BinAnd + , BinOr + , BinXor + , BinXNor + , BinXNorInv + -- , BinPower + , BinLSL + , BinLSR + , BinASL + , BinASR + ] + +unOp :: Gen UnaryOperator +unOp = + Hog.element + [ UnPlus + , UnMinus + , UnNot + , UnLNot + , UnAnd + , UnNand + , UnOr + , UnNor + , UnXor + , UnNxor + , UnNxorInv + ] + +constExprWithContext :: [Parameter] -> ProbExpr -> Hog.Size -> Gen ConstExpr +constExprWithContext ps prob size + | size == 0 = Hog.frequency + [ (prob ^. probExprNum, ConstNum <$> wireSize <*> fmap fromIntegral largeNum) + , ( if null ps then 0 else prob ^. probExprId + , ParamId . view paramIdent <$> Hog.element ps + ) + ] + | size > 0 = Hog.frequency + [ (prob ^. probExprNum, ConstNum <$> wireSize <*> fmap fromIntegral largeNum) + , ( if null ps then 0 else prob ^. probExprId + , ParamId . view paramIdent <$> Hog.element ps + ) + , (prob ^. probExprUnOp, ConstUnOp <$> unOp <*> subexpr 2) + , ( prob ^. probExprBinOp + , ConstBinOp <$> subexpr 2 <*> binOp <*> subexpr 2 + ) + , ( prob ^. probExprCond + , ConstCond <$> subexpr 3 <*> subexpr 3 <*> subexpr 3 + ) + , (prob ^. probExprConcat, ConstConcat <$> listOf1 (subexpr 8)) + ] + | otherwise = constExprWithContext ps prob 0 + where subexpr y = constExprWithContext ps prob $ size `div` y + +exprSafeList :: ProbExpr -> [(Int, Gen Expr)] +exprSafeList prob = + [ ( prob ^. probExprNum + , Number <$> wireSize <*> fmap fromIntegral largeNum + ) + ] + +exprRecList :: ProbExpr -> (Hog.Size -> Gen Expr) -> [(Int, Gen Expr)] +exprRecList prob subexpr = + [ ( prob ^. probExprNum + , Number <$> wireSize <*> fmap fromIntegral largeNum + ) + , (prob ^. probExprConcat , Concat <$> listOf1 (subexpr 8)) + , (prob ^. probExprUnOp , UnOp <$> unOp <*> subexpr 2) + , (prob ^. probExprStr, Str <$> Hog.text (Hog.linear 0 100) Hog.alphaNum) + , (prob ^. probExprBinOp , BinOp <$> subexpr 2 <*> binOp <*> subexpr 2) + , (prob ^. probExprCond , Cond <$> subexpr 3 <*> subexpr 3 <*> subexpr 3) + , (prob ^. probExprSigned , Func <$> pure SignedFunc <*> subexpr 2) + , (prob ^. probExprUnsigned, Func <$> pure UnsignedFunc <*> subexpr 2) + ] + +exprWithContext :: ProbExpr -> [Identifier] -> Hog.Size -> Gen Expr +exprWithContext prob [] n | n == 0 = Hog.frequency $ exprSafeList prob + | n > 0 = Hog.frequency $ exprRecList prob subexpr + | otherwise = exprWithContext prob [] 0 + where subexpr y = exprWithContext prob [] $ n `div` y +exprWithContext prob l n + | n == 0 + = Hog.frequency + $ (prob ^. probExprId, Id <$> Hog.element l) + : exprSafeList prob + | n > 0 + = Hog.frequency + $ (prob ^. probExprId, Id <$> Hog.element l) + : exprRecList prob subexpr + | otherwise + = exprWithContext prob l 0 + where subexpr y = exprWithContext prob l $ n `div` y + some :: StateGen a -> StateGen [a] some f = do - amount <- gen genPositive + amount <- gen $ Hog.int (Hog.linear 1 100) + replicateM amount f + +many :: StateGen a -> StateGen [a] +many f = do + amount <- gen $ Hog.int (Hog.linear 0 100) replicateM amount f makeIdentifier :: T.Text -> StateGen Identifier @@ -98,32 +235,28 @@ makeIdentifier prefix = do newPort :: PortType -> StateGen Port newPort pt = do ident <- makeIdentifier . T.toLower $ showT pt - p <- gen $ Port pt <$> arb <*> genPositive <*> pure ident + p <- gen $ Port pt <$> Hog.bool <*> pure 0 <*> wireSize <*> pure ident variables %= (p :) return p -choose :: PortType -> Port -> Bool -choose ptype (Port a _ _ _) = ptype == a - scopedExpr :: StateGen Expr scopedExpr = do context <- get - gen - . Hog.sized - . exprWithContext - $ context - ^.. variables - . traverse - . portName + prob <- askProbability + gen . Hog.sized . exprWithContext (prob ^. probExpr) $ vars context + where + vars cont = + (cont ^.. variables . traverse . portName) + <> (cont ^.. parameters . traverse . paramIdent) contAssign :: StateGen ContAssign contAssign = do expr <- scopedExpr - p <- newPort Wire + p <- newPort Wire return $ ContAssign (p ^. portName) expr lvalFromPort :: Port -> LVal -lvalFromPort (Port _ _ _ i) = RegId i +lvalFromPort (Port _ _ _ _ i) = RegId i probability :: Config -> Probability probability c = c ^. configProbability @@ -137,23 +270,51 @@ assignment = do lval <- lvalFromPort <$> newPort Reg return $ Assign lval Nothing expr -conditional :: StateGen Statement -conditional = do - expr <- scopedExpr +seqBlock :: StateGen Statement +seqBlock = do stmntDepth -= 1 tstat <- SeqBlock <$> some statement - fstat <- Hog.maybe $ SeqBlock <$> some statement stmntDepth += 1 - return $ CondStmnt (BinOp expr BinEq 0) (Just tstat) fstat + return tstat + +conditional :: StateGen Statement +conditional = do + expr <- scopedExpr + tstat <- seqBlock + fstat <- Hog.maybe seqBlock + return $ CondStmnt expr (Just tstat) fstat + +--constToExpr :: ConstExpr -> Expr +--constToExpr (ConstNum s n ) = Number s n +--constToExpr (ParamId i ) = Id i +--constToExpr (ConstConcat c ) = Concat $ constToExpr <$> c +--constToExpr (ConstUnOp u p ) = UnOp u (constToExpr p) +--constToExpr (ConstBinOp a b c) = BinOp (constToExpr a) b (constToExpr c) +--constToExpr (ConstCond a b c) = +-- Cond (constToExpr a) (constToExpr b) (constToExpr c) +--constToExpr (ConstStr s) = Str s + +forLoop :: StateGen Statement +forLoop = do + num <- Hog.int (Hog.linear 0 20) + var <- lvalFromPort <$> newPort Reg + stats <- seqBlock + return $ ForLoop (Assign var Nothing 0) + (BinOp (varId var) BinLT $ fromIntegral num) + (Assign var Nothing $ BinOp (varId var) BinPlus 1) + stats + where varId v = Id (v ^. regId) statement :: StateGen Statement statement = do prob <- askProbability cont <- get + let defProb i = prob ^. probStmnt . i Hog.frequency - [ (prob ^. probBlock , BlockAssign <$> assignment) - , (prob ^. probNonBlock , NonBlockAssign <$> assignment) - , (onDepth cont (prob ^. probCond), conditional) + [ (defProb probStmntBlock , BlockAssign <$> assignment) + , (defProb probStmntNonBlock , NonBlockAssign <$> assignment) + , (onDepth cont (defProb probStmntCond), conditional) + , (onDepth cont (defProb probStmntFor) , forLoop) ] where onDepth c n = if c ^. stmntDepth > 0 then n else 0 @@ -162,26 +323,98 @@ always = do stat <- SeqBlock <$> some statement return $ Always (EventCtrl (EPosEdge "clk") (Just stat)) +instantiate :: ModDecl -> StateGen ModItem +instantiate (ModDecl i outP inP _ _) = do + context <- get + outs <- + fmap (Id . view portName) <$> (replicateM (length outP) $ newPort Wire) + ins <- + (Id "clk" :) + . fmap (Id . view portName) + . take (length inP - 1) + <$> (Hog.shuffle $ context ^. variables) + ident <- makeIdentifier "modinst" + Hog.choice + [ return . ModInst i ident $ ModConn <$> outs <> ins + , ModInst i ident <$> Hog.shuffle + (zipWith ModConnNamed (view portName <$> outP <> inP) (outs <> ins)) + ] + +-- | Generates a module instance by also generating a new module if there are +-- not enough modules currently in the context. It keeps generating new modules +-- for every instance and for every level until either the deepest level is +-- achieved, or the maximum number of modules are reached. +-- +-- If the maximum number of levels are reached, it will always pick an instance +-- from the current context. The problem with this approach is that at the end +-- there may be many more than the max amount of modules, as the modules are +-- always set to empty when entering a new level. This is to fix recursive +-- definitions of modules, which are not defined. +-- +-- One way to fix that is to also decrement the max modules for every level, +-- depending on how many modules have already been generated. This would mean +-- there would be moments when the module cannot generate a new instance but +-- also not take a module from the current context. A fix for that may be to +-- have a default definition of a simple module that is used instead. +-- +-- Another different way to handle this would be to have a probability of taking +-- a module from a context or generating a new one. +modInst :: StateGen ModItem +modInst = do + prob <- lift ask + context <- get + let maxMods = prob ^. configProperty . propMaxModules + if length (context ^. modules) < maxMods + then do + let currMods = context ^. modules + let params = context ^. parameters + let vars = context ^. variables + modules .= [] + variables .= [] + parameters .= [] + modDepth -= 1 + chosenMod <- moduleDef Nothing + ncont <- get + let genMods = ncont ^. modules + modDepth += 1 + parameters .= params + variables .= vars + modules .= chosenMod : currMods <> genMods + instantiate chosenMod + else Hog.element (context ^. modules) >>= instantiate + -- | Generate a random module item. modItem :: StateGen ModItem modItem = do - prob <- askProbability + prob <- askProbability + context <- get + let defProb i = prob ^. probModItem . i Hog.frequency - [ (prob ^. probAssign, ModCA <$> contAssign) - , (prob ^. probAlways, always) + [ (defProb probModItemAssign, ModCA <$> contAssign) + , (defProb probModItemAlways, always) + , ( if context ^. modDepth > 0 then defProb probModItemInst else 0 + , modInst + ) ] moduleName :: Maybe Identifier -> StateGen Identifier moduleName (Just t) = return t -moduleName Nothing = gen arb +moduleName Nothing = makeIdentifier "module" -initialBlock :: StateGen ModItem -initialBlock = do +constExpr :: StateGen ConstExpr +constExpr = do + prob <- askProbability context <- get - let l = filter (choose Reg) $ context ^.. variables . traverse - return . Initial . SeqBlock $ makeAssign <$> l - where - makeAssign p = NonBlockAssign $ Assign (lvalFromPort p) Nothing 0 + gen . Hog.sized $ constExprWithContext (context ^. parameters) + (prob ^. probExpr) + +parameter :: StateGen Parameter +parameter = do + ident <- makeIdentifier "param" + cexpr <- constExpr + let param = Parameter ident cexpr + parameters %= (param :) + return param -- | Generates a module definition randomly. It always has one output port which -- is set to @y@. The size of @y@ is the total combination of all the locally @@ -191,22 +424,29 @@ moduleDef :: Maybe Identifier -> StateGen ModDecl moduleDef top = do name <- moduleName top portList <- some $ newPort Wire - mi <- some modItem + mi <- Hog.list (Hog.linear 4 100) modItem context <- get - initBlock <- initialBlock let local = filter (`notElem` portList) $ context ^. variables let size = sum $ local ^.. traverse . portSize - let clock = Port Wire False 1 "clk" - let yport = Port Wire False size "y" - let comb = combineAssigns_ yport local - return . declareMod local . ModDecl name [yport] (clock:portList) $ initBlock : mi <> [comb] + let clock = Port Wire False 0 1 "clk" + let yport = Port Wire False 0 size "y" + let comb = combineAssigns_ yport local + declareMod local + . ModDecl name [yport] (clock : portList) (mi <> [comb]) + <$> many parameter -- | Procedural generation method for random Verilog. Uses internal 'Reader' and -- 'State' to keep track of the current Verilog code structure. procedural :: Config -> Gen Verilog -procedural config = Verilog . (: []) . Description <$> Hog.resize - num - (runReaderT (evalStateT (moduleDef (Just "top")) context) config) +procedural config = do + (mainMod, st) <- Hog.resize num + $ runReaderT (runStateT (moduleDef (Just "top")) context) config + return . Verilog $ mainMod : st ^. modules where - context = Context [] 0 $ config ^. configProperty . propDepth - num = fromIntegral $ config ^. configProperty . propSize + context = + Context [] [] [] 0 (confProp propStmntDepth) $ confProp propModDepth + num = fromIntegral $ confProp propSize + confProp i = config ^. configProperty . i + +proceduralIO :: Config -> IO Verilog +proceduralIO = Hog.sample . procedural diff --git a/src/VeriFuzz/Verilog/Internal.hs b/src/VeriFuzz/Verilog/Internal.hs index 5999a31..63072b1 100644 --- a/src/VeriFuzz/Verilog/Internal.hs +++ b/src/VeriFuzz/Verilog/Internal.hs @@ -16,7 +16,7 @@ module VeriFuzz.Verilog.Internal , emptyMod , setModName , addModPort - , addDescription + , addModDecl , testBench , addTestBench , defaultPort @@ -33,14 +33,14 @@ import Data.Text (Text) import VeriFuzz.Verilog.AST regDecl :: Identifier -> ModItem -regDecl = Decl Nothing . Port Reg False 1 +regDecl i = Decl Nothing (Port Reg False 0 1 i) Nothing wireDecl :: Identifier -> ModItem -wireDecl = Decl Nothing . Port Wire False 1 +wireDecl i = Decl Nothing (Port Wire False 0 1 i) Nothing -- | Create an empty module. emptyMod :: ModDecl -emptyMod = ModDecl "" [] [] [] +emptyMod = ModDecl "" [] [] [] [] -- | Set a module name for a module declaration. setModName :: Text -> ModDecl -> ModDecl @@ -50,8 +50,8 @@ setModName str = modId .~ Identifier str addModPort :: Port -> ModDecl -> ModDecl addModPort port = modInPorts %~ (:) port -addDescription :: Description -> Verilog -> Verilog -addDescription desc = getVerilog %~ (:) desc +addModDecl :: ModDecl -> Verilog -> Verilog +addModDecl desc = getVerilog %~ (:) desc testBench :: ModDecl testBench = ModDecl @@ -76,24 +76,25 @@ testBench = ModDecl -- , SysTaskEnable $ Task "finish" [] ] ] + [] addTestBench :: Verilog -> Verilog -addTestBench = addDescription $ Description testBench +addTestBench = addModDecl testBench defaultPort :: Identifier -> Port -defaultPort = Port Wire False 1 +defaultPort = Port Wire False 0 1 portToExpr :: Port -> Expr -portToExpr (Port _ _ _ i) = Id i +portToExpr (Port _ _ _ _ i) = Id i modName :: ModDecl -> Text modName = view $ modId . getIdentifier yPort :: Identifier -> Port -yPort = Port Wire False 90 +yPort = Port Wire False 0 90 wire :: Int -> Identifier -> Port -wire = Port Wire False +wire = Port Wire False 0 reg :: Int -> Identifier -> Port -reg = Port Reg False +reg = Port Reg False 0 diff --git a/src/VeriFuzz/Verilog/Mutate.hs b/src/VeriFuzz/Verilog/Mutate.hs index 03ee1d0..536ebef 100644 --- a/src/VeriFuzz/Verilog/Mutate.hs +++ b/src/VeriFuzz/Verilog/Mutate.hs @@ -72,7 +72,7 @@ idTrans _ _ e = e -- | Replaces the identifier recursively in an expression. replace :: Identifier -> Expr -> Expr -> Expr -replace = (transformOf traverseExpr .) . idTrans +replace = (transform .) . idTrans -- | Nest expressions for a specific 'Identifier'. If the 'Identifier' is not -- found, the AST is not changed. @@ -107,8 +107,8 @@ allVars m = -- $setup -- >>> import VeriFuzz.Verilog.CodeGen --- >>> let m = (ModDecl (Identifier "m") [Port Wire False 5 (Identifier "y")] [Port Wire False 5 "x"] []) --- >>> let main = (ModDecl "main" [] [] []) +-- >>> let m = (ModDecl (Identifier "m") [Port Wire False 0 5 (Identifier "y")] [Port Wire False 0 5 "x"] [] []) +-- >>> let main = (ModDecl "main" [] [] [] []) -- | Add a Module Instantiation using 'ModInst' from the first module passed to -- it to the body of the second module. It first has to make all the inputs into @@ -124,11 +124,14 @@ allVars m = instantiateMod :: ModDecl -> ModDecl -> ModDecl instantiateMod m main = main & modItems %~ ((out ++ regIn ++ [inst]) ++) where - out = Decl Nothing <$> m ^. modOutPorts - regIn = Decl Nothing <$> (m ^. modInPorts & traverse . portType .~ Reg) - inst = ModInst (m ^. modId) - (m ^. modId <> (Identifier . showT $ count + 1)) - conns + out = Decl Nothing <$> m ^. modOutPorts <*> pure Nothing + regIn = + Decl Nothing + <$> (m ^. modInPorts & traverse . portType .~ Reg) + <*> pure Nothing + inst = ModInst (m ^. modId) + (m ^. modId <> (Identifier . showT $ count + 1)) + conns count = length . filter (== m ^. modId) @@ -185,8 +188,8 @@ filterChar t ids = initMod :: ModDecl -> ModDecl initMod m = m & modItems %~ ((out ++ inp) ++) where - out = Decl (Just PortOut) <$> (m ^. modOutPorts) - inp = Decl (Just PortIn) <$> (m ^. modInPorts) + out = Decl (Just PortOut) <$> (m ^. modOutPorts) <*> pure Nothing + inp = Decl (Just PortIn) <$> (m ^. modInPorts) <*> pure Nothing -- | Make an 'Identifier' from and existing Identifier and an object with a -- 'Show' instance to make it unique. @@ -196,7 +199,7 @@ makeIdFrom a i = (i <>) . Identifier . ("_" <>) $ showT a -- | Make top level module for equivalence verification. Also takes in how many -- modules to instantiate. makeTop :: Int -> ModDecl -> ModDecl -makeTop i m = ModDecl (m ^. modId) ys (m ^. modInPorts) modIt +makeTop i m = ModDecl (m ^. modId) ys (m ^. modInPorts) modIt [] where ys = yPort . flip makeIdFrom "y" <$> [1 .. i] modIt = instantiateModSpec_ "_" . modN <$> [1 .. i] @@ -206,17 +209,20 @@ makeTop i m = ModDecl (m ^. modId) ys (m ^. modInPorts) modIt -- | Make a top module with an assert that requires @y_1@ to always be equal to -- @y_2@, which can then be proven using a formal verification tool. makeTopAssert :: ModDecl -> ModDecl -makeTopAssert = (modItems %~ (++ [assert])) . makeTop - 2 +makeTopAssert = (modItems %~ (++ [assert])) . makeTop 2 where assert = Always . EventCtrl e . Just $ SeqBlock [TaskEnable $ Task "assert" [BinOp (Id "y_1") BinEq (Id "y_2")]] - e = EPosEdge "clk" + e = EPosEdge "clk" --- | Provide declarations for all the ports that are passed to it. +-- | Provide declarations for all the ports that are passed to it. If they are +-- registers, it should assign them to 0. declareMod :: [Port] -> ModDecl -> ModDecl declareMod ports = initMod . (modItems %~ (decl ++)) - where decl = Decl Nothing <$> ports + where + decl = declf <$> ports + declf p@(Port Reg _ _ _ _) = Decl Nothing p (Just 0) + declf p = Decl Nothing p Nothing -- | Simplify an 'Expr' by using constants to remove 'BinaryOperator' and -- simplify expressions. To make this work effectively, it should be run until @@ -273,4 +279,10 @@ combineAssigns p a = combineAssigns_ :: Port -> [Port] -> ModItem combineAssigns_ p ps = - ModCA . ContAssign (p ^. portName) . fold $ Id <$> ps ^.. traverse . portName + ModCA + . ContAssign (p ^. portName) + . fold + $ Id + <$> ps + ^.. traverse + . portName diff --git a/src/VeriFuzz/Verilog/Parser.hs b/src/VeriFuzz/Verilog/Parser.hs index a072ce8..518bcb9 100644 --- a/src/VeriFuzz/Verilog/Parser.hs +++ b/src/VeriFuzz/Verilog/Parser.hs @@ -106,7 +106,7 @@ systemFunc s = satisfy' matchId parseFunction :: Parser Function parseFunction = systemFunc "$unsigned" - $> UnSignedFunc + $> UnsignedFunc <|> systemFunc "$signed" $> SignedFunc @@ -259,7 +259,7 @@ parseNetDecl pd = do range <- option 1 parseRange name <- identifier tok' SymSemi - return . Decl pd . Port t sign range $ name + return $ Decl pd (Port t sign 0 range name) Nothing where type_ = tok KWWire $> Wire <|> tok KWReg $> Reg parsePortDir :: Parser PortDir @@ -281,8 +281,8 @@ parseModList :: Parser [Identifier] parseModList = list <|> return [] where list = parens $ commaSep identifier filterDecl :: PortDir -> ModItem -> Bool -filterDecl p (Decl (Just p') _) = p == p' -filterDecl _ _ = False +filterDecl p (Decl (Just p') _ _) = p == p' +filterDecl _ _ = False modPorts :: PortDir -> [ModItem] -> [Port] modPorts p mis = filter (filterDecl p) mis ^.. traverse . declPort @@ -298,14 +298,12 @@ parseModDecl = do (modPorts PortOut modItem) (modPorts PortIn modItem) modItem - -parseDescription :: Parser Description -parseDescription = Description <$> parseModDecl + [] -- | Parses a 'String' into 'Verilog' by skipping any beginning whitespace -- and then parsing multiple Verilog source. parseVerilogSrc :: Parser Verilog -parseVerilogSrc = Verilog <$> many parseDescription +parseVerilogSrc = Verilog <$> many parseModDecl -- | Parse a 'String' containing verilog code. The parser currently only supports -- the subset of Verilog that is being generated randomly. diff --git a/src/VeriFuzz/Verilog/Preprocess.hs b/src/VeriFuzz/Verilog/Preprocess.hs index fead5f0..6e9305a 100644 --- a/src/VeriFuzz/Verilog/Preprocess.hs +++ b/src/VeriFuzz/Verilog/Preprocess.hs @@ -20,7 +20,9 @@ module VeriFuzz.Verilog.Preprocess ) where --- | Remove comments from code. +-- | Remove comments from code. There is no difference between @(* *)@ and +-- @/* */@, therefore in this implementation, @*/@ could close @(*@ and vice-versa, +-- This will be fixed in an upcoming version. uncomment :: FilePath -> String -> String uncomment file = uncomment' where @@ -28,6 +30,7 @@ uncomment file = uncomment' "" -> "" '/' : '/' : rest -> " " ++ removeEOL rest '/' : '*' : rest -> " " ++ remove rest + '(' : '*' : rest -> " " ++ remove rest '"' : rest -> '"' : ignoreString rest b : rest -> b : uncomment' rest @@ -43,6 +46,7 @@ uncomment file = uncomment' '\n' : rest -> '\n' : remove rest '\t' : rest -> '\t' : remove rest '*' : '/' : rest -> " " ++ uncomment' rest + '*' : ')' : rest -> " " ++ uncomment' rest _ : rest -> " " ++ remove rest removeString a = case a of @@ -105,4 +109,3 @@ ppLine env ('`' : a) = case lookup name env of a rest = drop (length name) a ppLine env (a : b) = a : ppLine env b - diff --git a/test/Property.hs b/test/Property.hs index ba961cf..431a155 100644 --- a/test/Property.hs +++ b/test/Property.hs @@ -3,7 +3,7 @@ module Property ) where -import Data.Either (fromRight, isRight) +import Data.Either (either, isRight) import qualified Data.Graph.Inductive as G import Hedgehog (Gen, (===)) import qualified Hedgehog as Hog @@ -42,11 +42,9 @@ parserIdempotent' = Hog.property $ do p sv === (p . p) sv where vshow = show . GenVerilog - p = - vshow - . fromRight (error "Failed idempotent test") - . parse parseModDecl "idempotent_test.v" - . alexScanTokens + p sv = either (\x -> show x <> "\n" <> sv) vshow + . parse parseModDecl "idempotent_test.v" + $ alexScanTokens sv parserInput :: TestTree parserInput = testProperty "parser input" parserInput' |