Giter VIP home page Giter VIP logo

yodl's Introduction

Yodl

This is a work in progress VHDL frontend for the Yosys toolchain.

8. Sept 2016

netlist

The last few weeks, I finished up the first experimental netlist synthesis algorithm for the use in my thesis. The latter, sadly, is due in about 14 days, hence I won't be able to develop Yodl for at least 2 weeks.

Here are some teasers what's currently possible. Note, that some example serve as illustration of how the synthesis algorithm produces netlists and aren't necessarily sound or even semantically correct (since there are no semantic checks yet :))

  1. Simple signal assignment synchronization
architecture behv of adder is
   function rising_edge(c : in std_logic) return std_logic;
begin
   process(A) is
   begin
      if rising_edge(clock) then
         A <= '0';
      end if;
   end process;
end behv;

netlist

  1. Nested synchonization
-- [...]
-- A and clock are both of type std_logic
architecture behv of adder is
   function rising_edge(c : in std_logic) return std_logic;
begin
   process(A) is
   begin
      if rising_edge(clock) then
         if rising_edge(clock) then
            A <= '0';
         end if;
      end if;
   end process;
end behv;

netlist

  1. Simple latched signal assignment
-- same libraries as above
-- A, B and C are of type std_logic
architecture behv of adder is
   function rising_edge(c : in std_logic) return boolean;
begin
   process(A) is
   begin
      if A = B then
         C <= '1';
      end if;
   end process;
end behv;

netlist

  1. Nested latched signal assignment
-- [...]
-- same preamble as above
   process(A) is
   begin
      if A = B then
         if not A then
             C <= '1';
         end if;
      end if;
   end process;
end behv;

netlist

  1. Simple case synthesis
-- same libraries as before
-- A is a std_logic and baz a std_logic_vector(2 downto 0)
architecture behv of caseT is
begin
   process(A) is
   begin
      case baz is
         when "000" => A <= '0';
         when "001" => A <= '1';
         when "010" => A <= '1';
         when "011" => A <= '1';
         when "100" => A <= '0';
         when "101" => A <= '1';
         when "110" => A <= '1';
         when "111" => A <= '1';
      end case;
   end process;
end behv;

netlist

  1. Nested case synthesis
-- same libraries as before
-- A, B, C and sum are ports of type std_logic
architecture behv of adder is
begin
   process(A) is
   begin
      case A is
         when '0' => case B is
                        when '0' => sum <= '0';
                        when '1' => sum <= '1';
                     end case;
         when '1' => case C is
                        when '0' => sum <= '0';
                        when '1' => sum <= '1';
                     end case;
      end case;
   end process;
end behv;

netlist

  1. Synchronized case statement
-- [...]
-- A, clock are ports of type std_logic and
-- sel is a std_logic_vector(2 downto 0)

architecture behv of syncCase is
   function rising_edge(c : in std_logic) return std_logic;
begin
   process(A) is
   begin
      if rising_edge(clock) then
         case sel is
            when "000" => A <= '0';
            when "001" => A <= '1';
            when "010" => A <= '1';
            when "011" => A <= '1';
            when "100" => A <= '0';
            when "101" => A <= '1';
            when "110" => A <= '1';
            when "111" => A <= '1';
         end case;
      end if;
   end process;
end behv;

netlist

  1. If statement with complete signal assignments
-- [...]
-- A, B and C are ports of type std_logic
architecture behv of adder is
   function rising_edge(c : in std_logic) return boolean;
begin
   process(A) is
   begin
      if A = B then
         C <= '0';
      else
         C <= '1';
      end if;
   end process;

netlist

  1. Complete nonsensical clusterfuck
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity clufu is
   port(A       : out std_logic;
        B       : out std_logic;
        Co      : out std_logic;
        sel    : in  std_logic_vector(1 downto 0);
        enable  : in  std_logic;
        enable2 : in  std_logic;
        clock    : in  std_logic);
end clufu;

architecture b of clufu is
   function rising_edge(c : in std_logic) return boolean;
begin
   process(A) is
   begin
      if A = B then
         if not A then
            if rising_edge(clock) then
               case sel is
                  when "00" =>
                     if rising_edge(clock) and enable = '1' and (not enable2 = '0') then
                        Co <= '0';
                     end if;
                  when "01" => Co <= '1';
                  when "10" => Co <= '1';
                  when "11" => Co <= '1';
               end case;
            end if;
         end if;
      end if;
   end process;
end b;

netlist

19. Aug 2016

Due to the current parser's limitations, a new parser needs to be written. I intend to use BNFC for this task. BNFC provides two things:

  1. A formalism for lexical and syntactic specifications: LBNF
  2. A program generator that transforms those specs from LBNF into a complete frontend for various languages (of course C/C++ is one ot the target languages)

I transcribed the official syntax (written in EBNF = Extended Backus Naur Form) into LBNF and tested out the frontend generation. In principle this is working now.

However, the real difficult things are yet to come!. LBNF does not support ambiguous context free grammars in particular. That means that it has to be modified in order to resolve this issue. Bison can generate GLR parsers. A rule of thumb is: If your grammar only contains shift/reduce conflicts: Generate a GLR parser and you are golden. VHDL contains more shift/reduce conflicts than one can count and -- in addition to that -- a lot of reduce/reduce conflicts. Since RR-Conflicts makes a context free grammar produce more than one parse tree, the rule-of-thumb solution can't be applied here.

Every glr-ed bison grammar can be equipped with so called merge rules which deal with RR-conflicts. As the priviously mentioned article describes, the merge rules need to keep track of all scopes and all occuring type, variable, signal, and function declarations in order to be able to correctly resolve the conflicts. Stephen Williams' parse.y nicely shows, how this can be achived.

The remaining problem, again, regards the sr-conflicts. Are we really sure that they don't lift the grammar into the set of non-deterministically context free languages? In other words: How do we know for sure, that all remaining sr-conflicts can be resolved solely by the usage of a GLR parser?

This is a non-trivial question and it's answer can possibly constructed with:

  1. Knowledge of the GLR parsing algorithm. (GLR = LR(n) with n being unlimited)
  2. Does any parser split, provoked by a SR-conflict, ultimately lead to only one living parser for each path?

I'll elaborate on this topic as soon as I have understood the problem entirely.

16. Aug 2016

Today is a day to celebrate. First actual netlist has been created! Yodl translated this

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity adder is
   port(A        : in  std_logic;
        B        : in  std_logic;
        carryIn  : in  std_logic;
        carryOut : out std_logic;
        fnord    : out std_logic;
        sum      : out std_logic);
end adder;

architecture behv of adder is
begin
--   sum      <= A xor B xor carryIn;
   sum <= '0';
   carryOut <= (a and b) or
               (b and carryIn) or
               (a and carryIn);

   fnord <= ('1' or '0') and '1';
end behv;

into that:

netlist

4. Aug 2016

I did further research on the topic parse all of VHDL 2008. There is a project that automates away most of the hugely repetitive work of writing an compiler frontend. Moreover, I found a repository on github that contains a copy of VHDL-2008 bnf grammar. Sadly the author simply copy pasted it from the original reference manual. This is unformunate, because the BNF derivative the IEEE authors use in their manual is not at all copy paste friendly because of their glorious semantic rule prefixes. Hence the standard text contains grammar rules like: package_simple_name ::= foobar. A package_simple_name simply is a simple_name but prefixed for better understandability. Since there is no italic font for plain text files, I now manually have to check the complete grammar (1300 LoC) and remove the semantic prefixes.

Previous notes: Currently I'm able to completely evaluate generate statements and for loops (for and if; case generate is not supported, but will be). Speaking of for loops, there is a grain of salt. The VHDL synthesis standard from 2004 pinpoints that next and exit statements be explicitly allowed inside of for loops. This is a problem, because in certain cases an occuring statement of those two types can make the whole loop (statically) non-evaluable. Thus my current for loop unroller does not support them.

Furthermore I built appropriate infrastructure for AST traversals which is largely functor based and not very well documented at this point of time.

As of now, I also accomplished:

  • elsif elimination. The elsif eliminator transforms
    if (3=3) then
      s1;
    elsif (4=4) then
      s2;
    else
      s3;
    end if;

into

    if (3=3) then
      s1;
    else
      if (4=4) then
        s2;
      else
        s3;
      end if;
    end if;
  • if/else to case transformation. The functor BranchesToCases transforms
    if (3=3) then
      s1;
    else
      if (4=4) then
        s2;
      else
        s3;
      end if;
    end if;

into

  case (3=3) is
    when TRUE => s1;
    when FALSE =>
      case (4=4) is
        when TRUE => s2;
        when FALSE => s3;
      end case;
  end case;

Now the multiplexer structures that are modelled by if/elsif/else-clauses become obvious and are hopefully simple enough to translate to Cliffords RTLIL-API.

A rant about VHDL's grammar: . VHDL's grammar is utterly ambiguous. There are a lot of reduce/reduce (and even more shift/reduce) conflicts in the grammar. Reduce/reduce conflicts (in context LR(1)) usually is a very strong implication for the grammar being in the class of non-deterministic context free languages and this is bad news because it further implies, that parsing is very very hard.

There already is a pretty good article about this that I want to refer to.

Stephen Williams wrote a pretty slick parse.y that properly matches most of VHDL's syntax. Sadly, there are some ugly twists that he had to make in order to unambiguously construct just one parse tree for any given input. I thought a bit and came to the conclusion that it might be best, to rewrite the parser by using one of bisons newer features: GLR, Generalized LR, an algorithm for ambiguous grammars.

As an example what the current parser cannot (and probably will never be able to) parse is:

architecture beh of ent is
   -- some decls
begin
   -- this should be parsable, but produces syntax error
   result <= foo(fnord => 3, foobar => 4)(3);

   -- this is parsable
    result <= foo(4, 3)(3);
end beh;

The problem is that the alterations of VHDL's grammar also affected how names (identifiers, array indexing, ...) are matched. The standard dictates that a name is parsed as

name ->   prefix ( expression {, expression } )
        | prefix . suffix
        | operator_symbol
        | identifier

prefix -> name | function_call

function_call -> name ( association_list )

suffix consists solely of terminal symbols

whereas parse.y specifies prefixes as

prefix -> name

and emulates function calls inside of expressions by misusing the

prefix ( expression {, expression } )

rule.

Current milestone

Be able to generate RTLIL from a subset of VHDL.

Ultimate goal

Be able to generate (correct) RTLIL from VHDL as specified in IEEE 1076.6-2004.

yodl's People

Contributors

forflo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yodl's Issues

No Makefile in the directory after running configure script

Hi Florian,

First of all thank you for starting this project!

I've tried to install it and unfortunately was stopped at the first step. After I ran
./configure
at my system I was not able to find any Makefile in the projects directory.

I am not waiting that you completely solve my problem, but could you please give some hints where to search for the issue? Probably with your 5 minutes time you can save me hours.

The config.log is attached (zipped):
config.zip

Thank you in advance.
Best regards,
Dmitry

Tool architecture question

Hi Florian,

Reading through your thesis I got a question and didn't really find the answer.

On the figure 1.3 "Main Yosys components and data structures" you mention that there are two possible places where the VHDL frontend can be placed. You write in your thesis: "Yosys makes it possible to add the VHDL frontend component at two places. First, the frontend could produce an abstract syntax tree using the predefined AST format from Yosys, thus the component would be placed above AST. Second, the VHDL component could emit an RTLIL netlist serialized to normal ASCII text. Said text would then be put into the ilang frontend that does the deserialization."

Why did you decide to develop the VHDL frontend using the second option, not the first option?

Thank you in advance for the answer.

Best regards,
Dmitry

No Makefile in . dir after running .configure, clang errors after running make in vhdlpp dir.

Also from my side thanks for this project, about time yosys had a vhdl backend.
Unfortunately, I actually also have the problem that no Makefile is created upon calling .configure, or rather, only one in ./vhdlpp is created. Calling make here very quickly results in some clang errors, after having installed clang-3.5, I get the following errors:

`clang++ -I. -I.. -I../libmisc -Isimple_tree -Imach7 -Imach7/patterns -Icatch -I/usr/local/share/yosys/include -I/usr/lib/libffi-3.2.1/include -I/usr/include/tcl8.6 -DYOSYS_ENABLE_READLINE -DYOSYS_ENABLE_PLUGINS -DYOSYS_ENABLE_TCL -DYOSYS_ENABLE_ABC -DYOSYS_ENABLE_COVER -D_YOSYS_ -DHAVE_CONFIG_H "-ggdb" "-O0" "--std=c++14" "-g" -Wall -Wextra -Wshadow -c architec.cc -o architec.o

In file included from architec.cc:22:
In file included from ./architec.h:24:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/map:61:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_map.h:63:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/tuple:39:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/array:38:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/stdexcept:39:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/string:52:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:2815:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ext/string_conversions.h:43:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/cstdio:120:11: error: no member named 'gets' in the global namespace
using ::gets;
~~^
1 error generated.
make: *** [architec.o] Error 1
`

Attacked also the config log.

It would be great to get a hint what may be wrong. Thanks!

config_log.zip

Relicense to ISC?

Hi @forflo,

The fact that yodl is licensed under GPLv3 makes it impossible to incorporate it into yosys (which is licensed under ISC).

Are you aware of this?
How do you think about relicensing yodl to ISC?

No need to dynamic_cast upon successful match

Hi Florian,

Accidentally wondered into your code today and saw you do a dynamic_cast on the subject inside Case statements as for example here:

Case(C<Entity>()){
currentEntity = dynamic_cast<Entity*>(n);
}
Case(C<ScopeBase>()){
currentScope = dynamic_cast<ScopeBase *>(n);
}

This is redundant and kills performance as you already have the properly cast subject inside a variable match0, which is local to each Case clause. The type of match0 in the first clause in the above example is Entity& and in the second clause - ScopeBase&.

If you have Match statement on multiple subjects, they are available via match0, match1 etc. respectively. One of the big contributions of Mach7 was not just the concise syntax, but also a very efficient type switch statement in which you get the results of essentially invoking dynamic_cast, which is extremely slow, at the cost of a direct jump.

Yuriy

'backends/dot/dot.h' file not found

I would like to test yodl for synthesizing a VHDL "hello world" program and upload it into the icestick board (or compatible). I am compiling yodl, but I have not found the dot backend. I've pulled the latests yosys (from master), but the dot backend is not there. It would be great if you could point me were to download it. Thanks a lot for this wonderful project! :-)

...
main.cc:24:10: fatal error: 'backends/dot/dot.h' file not found
#include <backends/dot/dot.h>
         ^
21 warnings and 1 error generated.
Makefile:143: recipe for target 'main.o' failed
make: *** [main.o] Error 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.