오늘은 맑음

Pyverilog 실행하기 - 튜토리얼 본문

Tools/Pyverilog

Pyverilog 실행하기 - 튜토리얼

자전거 타는 구구 2024. 4. 9. 23:49
반응형

지난 번에는 Pyverilog와 관련된 모듈들을 설치해봤습니다.

자 그러면 Pyverilog가 뭔지 알아보고 튜토리얼을 진행해보도록 하겠습니다.

 

홈페이지에 나와있는 설명을 보면 다음과 같습니다.

 Pyverilog is an open-source hardware design processing toolkit for Verilog HDL. All source codes are written in Python.

Pyverilog includes (1) code parser, (2) dataflow analyzer, (3) control-flow analyzer and (4) code generator. You can create your own design analyzer, code translator and code generator of Verilog HDL based on this toolkit.

 

 정리해보면 Python을 이용한 Verilog HDL toolkit입니다. Code parser, dataflow analyzer, control-flow analyzer와 마지막으로 code generator 기능을 내장하고 있습니다. 4번 code generator가 궁금했기 때문에 이번에 설치를 해봤습니다.

 

먼저 첫 번째 기능인 code parser를 실행해보겠습니다.

 

테스트에 사용될 코드는 다음과 같습니다.

module top
  (
   input CLK, 
   input RST,
   input enable,
   input [31:0] value,
   output [7:0] led
  );
  reg [31:0] count;
  reg [7:0] state;
  assign led = count[23:16];
  always @(posedge CLK) begin
    if(RST) begin
      count <= 0;
      state <= 0;
    end else begin
      if(state == 0) begin
        if(enable) state <= 1;
      end else if(state == 1) begin
        state <= 2;
      end else if(state == 2) begin
        count <= count + value;
        state <= 0;
      end
    end
  end
endmodule

Coder parser

command

python3 pyverilog/examples/example_parser.py test.v

위의 명령어를 타이핑 하시면 아래와 같은 결과가 나옵니다.

 

result

더보기
Source:  (at 1)
  Description:  (at 1)
    ModuleDef: top (at 1)
      Paramlist:  (at 0)
      Portlist:  (at 2)
        Ioport:  (at 3)
          Input: CLK, False (at 3)
        Ioport:  (at 4)
          Input: RST, False (at 4)
        Ioport:  (at 5)
          Input: enable, False (at 5)
        Ioport:  (at 6)
          Input: value, False (at 6)
            Width:  (at 6)
              IntConst: 31 (at 6)
              IntConst: 0 (at 6)
        Ioport:  (at 7)
          Output: led, False (at 7)
            Width:  (at 7)
              IntConst: 7 (at 7)
              IntConst: 0 (at 7)
      Decl:  (at 9)
        Reg: count, False (at 9)
          Width:  (at 9)
            IntConst: 31 (at 9)
            IntConst: 0 (at 9)
      Decl:  (at 10)
        Reg: state, False (at 10)
          Width:  (at 10)
            IntConst: 7 (at 10)
            IntConst: 0 (at 10)
      Assign:  (at 11)
        Lvalue:  (at 11)
          Identifier: led (at 11)
        Rvalue:  (at 11)
          Partselect:  (at 11)
            Identifier: count (at 11)
            IntConst: 23 (at 11)
            IntConst: 16 (at 11)
      Always:  (at 12)
        SensList:  (at 12)
          Sens: posedge (at 12)
            Identifier: CLK (at 12)
        Block: None (at 12)
          IfStatement:  (at 13)
            Identifier: RST (at 13)
            Block: None (at 13)
              NonblockingSubstitution:  (at 14)
                Lvalue:  (at 14)
                  Identifier: count (at 14)
                Rvalue:  (at 14)
                  IntConst: 0 (at 14)
              NonblockingSubstitution:  (at 15)
                Lvalue:  (at 15)
                  Identifier: state (at 15)
                Rvalue:  (at 15)
                  IntConst: 0 (at 15)
            Block: None (at 16)
              IfStatement:  (at 17)
                Eq:  (at 17)
                  Identifier: state (at 17)
                  IntConst: 0 (at 17)
                Block: None (at 17)
                  IfStatement:  (at 18)
                    Identifier: enable (at 18)
                    NonblockingSubstitution:  (at 18)
                      Lvalue:  (at 18)
                        Identifier: state (at 18)
                      Rvalue:  (at 18)
                        IntConst: 1 (at 18)
                IfStatement:  (at 19)
                  Eq:  (at 19)
                    Identifier: state (at 19)
                    IntConst: 1 (at 19)
                  Block: None (at 19)
                    NonblockingSubstitution:  (at 20)
                      Lvalue:  (at 20)
                        Identifier: state (at 20)
                      Rvalue:  (at 20)
                        IntConst: 2 (at 20)
                  IfStatement:  (at 21)
                    Eq:  (at 21)
                      Identifier: state (at 21)
                      IntConst: 2 (at 21)
                    Block: None (at 21)
                      NonblockingSubstitution:  (at 22)
                        Lvalue:  (at 22)
                          Identifier: count (at 22)
                        Rvalue:  (at 22)
                          Plus:  (at 22)
                            Identifier: count (at 22)
                            Identifier: value (at 22)
                      NonblockingSubstitution:  (at 23)
                        Lvalue:  (at 23)
                          Identifier: state (at 23)
                        Rvalue:  (at 23)
                          IntConst: 0 (at 23)

 위에서 부터 읽어보면 ModuleDef부터 Ioport, Decl, Assign, Always등 parsing을 하면서 line 정보를 함께 주고 있습니다.

parser가 정상적으로 동작하는지 궁금하여 다음과 같이 오타를 발생시켰습니다.

module top
  (
   input CLK,
   input RST,
   input enable,
   input [31:0] value,
   output [7:0] led,
  );

 마지막 output 선언에 쉼표를 추가한 후 다시 parser를 실행시키니 많은 에러 메시지와 함께 다음과 같이 에러 정보가 출력됩니다.

pyverilog.vparser.parser.ParseError:  line:8: before: ")"

 vcs를 사용할 때 발생하는 에러 메시지와 비슷하게 출력 되는 것으로 보아 parser는 정상적으로 동작을 하는 것 같습니다.

 

다음은 Dataflow analyzer를 실행시켜보겠습니다.

Dataflow analyzer

command

python3 pyverilog/examples/example_dataflow_analyzer.py -t top test.v

result

Directive:
Instance:
(top, 'top')
Term:
(Term name:top.led type:{'Output'} msb:(IntConst 7) lsb:(IntConst 0))
(Term name:top.enable type:{'Input'} msb:(IntConst 0) lsb:(IntConst 0))
(Term name:top.CLK type:{'Input'} msb:(IntConst 0) lsb:(IntConst 0))
(Term name:top.count type:{'Reg'} msb:(IntConst 31) lsb:(IntConst 0))
(Term name:top.state type:{'Reg'} msb:(IntConst 7) lsb:(IntConst 0))
(Term name:top.RST type:{'Input'} msb:(IntConst 0) lsb:(IntConst 0))
(Term name:top.value type:{'Input'} msb:(IntConst 31) lsb:(IntConst 0))
Bind:
(Bind dest:top.count tree:(Branch Cond:(Terminal top.RST) True:(IntConst 0) False:(Branch Cond:(Operator Eq Next:(Terminal top.state),(IntConst 0)) False:(Branch Cond:(Operator Eq Next:(Terminal top.state),(IntConst 1)) False:(Branch Cond:(Operator Eq Next:(Terminal top.state),(IntConst 2)) True:(Operator Plus Next:(Terminal top.count),(Terminal top.value)))))))
(Bind dest:top.state tree:(Branch Cond:(Terminal top.RST) True:(IntConst 0) False:(Branch Cond:(Operator Eq Next:(Terminal top.state),(IntConst 0)) True:(Branch Cond:(Terminal top.enable) True:(IntConst 1)) False:(Branch Cond:(Operator Eq Next:(Terminal top.state),(IntConst 1)) True:(IntConst 2) False:(Branch Cond:(Operator Eq Next:(Terminal top.state),(IntConst 2)) True:(IntConst 0))))))
(Bind dest:top.led tree:(Partselect Var:(Terminal top.count) MSB:(IntConst 23) LSB:(IntConst 16)))

 실행시키면 위와 같이 출력되는 것을 볼 수 있습니다.

 Term에서는 top에서 사용되는 각종 신호들의 정보가 출력됩니다.

 Bind에서는 각 데이터의 흐름이 어떻게 흘러가는지 설명해주고 있습니다.

 예를 들어  count를 보겠습니다.

RST이 참인 경우에는 count에 0을 할당합니다.
RST이 거짓인 경우에는 branch condition으로 else로 빠지게 됩니다.
top.state가 0이 아닌 경우 top.state가 1이 아닌지 확인합니다.
만약 top.state가 1이 아닌 경우 2와 같은지 비교합니다.
만약 top.state가 2라면 top.count와 top.value를 더하는 연산을 수행합니다.

생각보다 알아보기 쉽게 정보를 출력해주는 것 같습니다.

 

다음은 dataflow를 graph로 그려주는 예제를 실행해보려고 했는데 에러가 발생해서 실패했습니다.

command

python3 pyverilog/examples/example_graphgen.py -t top -s top.led test.v

함수 문법 오류인지... 다음에 찾게 되면 업데이트 해보겠습니다.

TypeError: VerilogGraphGenerator.generate() got an unexpected keyword argument 'reorder'

 

다음은 가장 궁금했던 code generator입니다.

Code generator

test.py라는 파일을 생성하고 아래의 코드를 복사해줍니다.

from __future__ import absolute_import
from __future__ import print_function
import sys
import os
import pyverilog.vparser.ast as vast
from pyverilog.ast_code_generator.codegen import ASTCodeGenerator

def main():
    datawid = vast.Parameter( 'DATAWID', vast.Rvalue(vast.IntConst('32')) )
    params = vast.Paramlist( [datawid] )
    clk = vast.Ioport( vast.Input('CLK') )
    rst = vast.Ioport( vast.Input('RST') )
    width = vast.Width( vast.IntConst('7'), vast.IntConst('0') )
    led = vast.Ioport( vast.Output('led', width=width) )
    ports = vast.Portlist( [clk, rst, led] )

    width = vast.Width( vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('1')), vast.IntConst('0') )
    count = vast.Reg('count', width=width)

    assign = vast.Assign(
        vast.Lvalue(vast.Identifier('led')), 
        vast.Rvalue(
            vast.Partselect(
                vast.Identifier('count'), # count
                vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('1')), # [DATAWID-1:
                vast.Minus(vast.Identifier('DATAWID'), vast.IntConst('8'))))) # :DATAWID-8]

    sens = vast.Sens(vast.Identifier('CLK'), type='posedge')
    senslist = vast.SensList([ sens ])

    assign_count_true = vast.NonblockingSubstitution(
        vast.Lvalue(vast.Identifier('count')),
        vast.Rvalue(vast.IntConst('0')))
    if0_true = vast.Block([ assign_count_true ])

    # count + 1
    count_plus_1 = vast.Plus(vast.Identifier('count'), vast.IntConst('1'))
    assign_count_false = vast.NonblockingSubstitution(
        vast.Lvalue(vast.Identifier('count')),
        vast.Rvalue(count_plus_1))
    if0_false = vast.Block([ assign_count_false ])

    if0 = vast.IfStatement(vast.Identifier('RST'), if0_true, if0_false)
    statement = vast.Block([ if0 ])

    always = vast.Always(senslist, statement)

    items = []
    items.append(count)
    items.append(assign)
    items.append(always)

    ast = vast.ModuleDef("top", params, ports, items)
    
    codegen = ASTCodeGenerator()
    rslt = codegen.visit(ast)
    print(rslt)

if __name__ == '__main__':
    main()

그 다음 아래의 커맨드를 입력해줍니다.

 

command

python3 test.py

입력하게 되면 다음과 같이 생성된 코드가 커맨드창에 뜹니다.

 

result

module top #
(
  parameter DATAWID = 32
)
(
  input CLK,
  input RST,
  output [7:0] led
);

  reg [DATAWID-1:0] count;
  assign led = count[DATAWID-1:DATAWID-8];

  always @(posedge CLK) begin
    if(RST) begin
      count <= 0;
    end else begin
      count <= count + 1;
    end
  end


endmodule

생성된 코드는 문제가 없어 보입니다.

 

조금 복잡해 보이지만 잘 이해 한다면 뭔가 코드를 생성할 수 있을 것 같습니다.

 

다음에는 스크립트를 이용해 직접 간단한 코드를 생성해보는 것을 목표로 해보겠습니다.

 

https://wh00300.tistory.com/298

 

Pyverilog 설치하기

오랫동안 미뤄왔던 Pyverilog를 설치해보려고 합니다. 아래 github에 자세한 설치법이 나와있으니 참고 바랍니다. 새 노트북에서 환경을 다시 잡는지라 python도 새로운 버전으로 업데이트를 해주고 a

wh00300.tistory.com

 

반응형

'Tools > Pyverilog' 카테고리의 다른 글

Pyverilog 설치하기  (0) 2024.03.30
Comments