class RubyRTL::VhdlGenerator

Constants

VHDL_OP

expressions ===

Attributes

archi_elements[RW]
entity[RW]
ios[RW]

Public Instance Methods

adapt_name(name,kind) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 205
def adapt_name name,kind
  name=name.to_s
  case kind
  when :comb
    name+="_c"
  when :reg
    name+="_r"
  when :var
    name+="_v"
  end
  name
end
clean_vhdl(code) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 42
def clean_vhdl(code)
  txt=code.finalize
  txt.gsub! /;(\s*)\)/,")"
  txt.gsub! /,(\s*)\)/,")"
  (code=Code.new) << txt
  return code
end
default_init(type) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 523
def default_init type
  case type
  when BitType
    return "'0'"
  when BitVectorType
    return "(others=>'0')"
  when UintType
    return "to_unsigned(0,#{type.bitwidth})"
  when IntType
    return "to_signed(0,#{type.bitwidth})"
  else
    raise "Cannot provide default init value for type #{type}"
  end
  ret
end
gen_archi(circuit) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 141
def gen_archi circuit
  body=circuit.ast.body
  archi_elements=body.stmts.collect{|stmt| stmt.accept(self)}
  archi=Code.new
  archi << "architecture rtl of #{circuit.name.downcase}_c is"
  archi.indent=2
  @fsm_defs.each do |decl|
    archi << decl
  end
  @typedecls.each do |typedecl|
    archi << typedecl.accept(self)
  end
  @sigs.each do |sig,name|
    archi << "signal #{name} : #{sig.type.accept(self)};"
  end
  archi.indent=0
  archi << "begin"
  archi.indent=2
  archi.newline
  archi_elements.each do |element|
    archi << element
    archi.newline
  end
  archi.indent=0
  archi.newline
  archi << "end rtl;"
  archi
end
gen_entity(circuit) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 124
def gen_entity circuit
  entity=Code.new
  entity << "entity #{name=circuit.name.downcase}_c is"
  entity.indent=2
  entity << "port ("
  entity.indent=4
  if circuit.has_sequential_statements
    entity << "reset_n : in std_logic;"
    entity << "clk     : in std_logic;"
  end
  ios.each{|io| entity << io}
  entity.indent=2
  entity << ");"
  entity.indent=0
  entity << "end #{name}_c;"
end
gen_ieee_header() click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 105
def gen_ieee_header
  header=Code.new
  header << "-- automatically generated by RubyRTL"
  header << "library ieee;"
  header << "use ieee.std_logic_1164.all;"
  header << "use ieee.numeric_std.all;"
  header.newline
  header
end
gen_package_call(circuit) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 115
def gen_package_call circuit
  name=circuit.name.downcase
  code=Code.new
  code << "library #{name}_lib;"
  code << "use #{name}_lib.#{name}_package.all;"
  code.newline
  code
end
gen_ruby_rtl_package_call() click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 50
def gen_ruby_rtl_package_call
  code=Code.new
  code << "library ruby_rtl;"
  code << "use ruby_rtl.ruby_rtl_package.all;"
  code.newline
  code
end
gen_ruby_rtl_type_package() click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 58
def gen_ruby_rtl_type_package
  code=Code.new
  code << gen_ieee_header
  code << "package ruby_rtl_type_package is "
  code.newline
  code.indent=2
  $typedefs.each do |name,definition|
    case definition
    when RecordType
      code << definition_s=definition.accept(self,name)
    else
      definition_s=definition.accept(self)
      case definition
      when IntType,UIntType,BitType
        header="sub"
      else
        header=""
      end
      code << "#{header}type #{name} is #{definition_s};"
    end
    code.newline
  end
  code.indent=0
  code << "end package;"
  code.save_as "ruby_rtl_type_package.vhd"
end
gen_type_package() click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 85
def gen_type_package
  name=@circuit.name.downcase
  return unless ast=@circuit.ast
  typdecls=ast.decls.select{|decl| decl.is_a?(TypeDecl)}
  package=Code.new
  package << gen_ieee_header
  package << "package #{name}_package is"
  package.indent=2
  package.newline
  typdecls.each do |decl|
    definition=decl.definition.accept(self,decl.name)
    package << definition
    package.newline
  end
  package.indent=0
  package << "end package;"
  puts package.finalize
  package.save_as "#{name}_package.vhd"
end
generate(circuit) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 11
def generate circuit
  puts "[+] VHDL code generation"

  code=Code.new
  @circuit=circuit
  @ios,@archi_elements=[],[]
  @sigs={}
  @fsm_defs=[]
  @sequentials=[]
  @states={}
  gen_ruby_rtl_type_package
  root=circuit.ast
  return unless root

  gen_type_package()
  #root.ios.each{|io| io.accept(self)}
  @typedecls=root.decls.select{|decl| decl.is_a? TypeDecl}
  non_typedecls=root.decls.reject{|decl| decl.is_a? TypeDecl}
  non_typedecls.each{|decl| decl.accept(self)}

  code << gen_ieee_header()
  code << gen_ruby_rtl_package_call()
  code << gen_package_call(circuit)
  code << gen_entity(circuit)
  code.newline
  code << gen_archi(circuit)
  code=clean_vhdl(code)
  puts code.finalize
  code.save_as "#{name=circuit.name.downcase}.vhd"
end
state_body(state) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 451
def state_body state
  code=Code.new
  state.body.each{|stmt| code << stmt.accept(self)}
  code
end
state_cases(fsm) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 434
def state_cases fsm
  code=Code.new
  code << "case #{fsm.name}_state is"
  code.indent=2
  fsm.states.each do |state|
    code << "when #{state.name} =>"
    code.indent=4
    code << state_body(state)
    code.indent=2
  end
  code << "when others =>"
  code << "  null;"
  code.indent=0
  code << "end case;"
  code
end
visitAssign(assign,args=nil) click to toggle source
body stuff ========

statements ===

# File lib/ruby_rtl/vhdl_generator.rb, line 262
def visitAssign assign,args=nil
  lhs=assign.lhs.accept(self)
  rhs=assign.rhs.accept(self)
  "#{lhs} <= #{rhs};"
end
visitBinary(bin,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 475
def visitBinary bin,args=nil
  lhs=bin.lhs.accept(self)
  op=VHDL_OP[bin.op] || bin.op
  rhs=bin.rhs.accept(self)
  "(#{lhs} #{op} #{rhs})"
end
visitBitLit(bit_lit,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 548
def visitBitLit bit_lit,args=nil
  "'#{bit_lit.val}'"
end
visitBitType(bit,args=nil) click to toggle source

types

# File lib/ruby_rtl/vhdl_generator.rb, line 502
def visitBitType bit,args=nil
  "std_logic"
end
visitBitVectorLit(bit_lit,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 552
def visitBitVectorLit bit_lit,args=nil
  "\"#{bit_lit.val}\""
end
visitBitVectorType(bv,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 506
def visitBitVectorType bv,args=nil
  range="#{bv.bitwidth-1} downto 0"
  "std_logic_vector(#{range})"
end
visitBody(body,args=nil) click to toggle source

statement

# File lib/ruby_rtl/vhdl_generator.rb, line 326
def visitBody body,args=nil
  code=Code.new
  body.stmts.each{|stmt| code << stmt.accept(self)}
  code
end
visitCase(case_,args=nil) click to toggle source

case / switch

# File lib/ruby_rtl/vhdl_generator.rb, line 369
def visitCase case_,args=nil
  cond=case_.cond.accept(self)
  code=Code.new
  code << "case #{cond} is"
  code.indent=2
  code << case_.body.accept(self)
  code.indent=0
  code << "end case;"
  code
end
visitCombinatorial(comb,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 297
def visitCombinatorial comb,args=nil
  code=Code.new
  label=comb.label
  code << "#{label} : process(all) --VHDL'08"
  code << "begin"
  code.indent=2
  code << comb.body.accept(self)
  code.indent=0
  code << "end process;"
  code
end
visitComment(comment,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 170
def visitComment comment,args=nil
  "-- #{comment.str}"
end
visitCompDecl(comp_decl,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 268
def visitCompDecl comp_decl,args=nil
  comp=comp_decl.comp
  instance_name=comp_decl.name
  sig_decls=comp.ast.decls.select{|node| node.is_a? SigDecl}
  inputs =sig_decls.select{|decl| decl.sig.is_a? Input}.map(&:sig)
  outputs=sig_decls.select{|decl| decl.sig.is_a? Output}.map(&:sig)

  instanciation=Code.new
  instanciation << "#{instance_name} : entity work.#{comp.name}_c"
  instanciation.indent=2
  instanciation << "port map("
  instanciation.indent=4
  inputs.each do |input|
    actual_sig_name="#{instance_name}_#{input.name}"
    @sigs.merge!({input => actual_sig_name})
    instanciation << "#{input.name} => #{actual_sig_name},"
  end
  outputs.each do |output|
    actual_sig_name="#{instance_name}_#{output.name}"
    @sigs.merge!(output => actual_sig_name)
    instanciation << "#{output.name} => #{actual_sig_name},"
  end
  instanciation.indent=2
  instanciation << ");"
  instanciation.indent=0
  instanciation.newline
  instanciation
end
visitElse(else_,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 359
def visitElse else_,args=nil
  body=else_.body.accept(self)
  code=Code.new
  code << "else "
  code.indent=2
  code << body
  code.indent=0
  code
end
visitElsif(elsif_,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 348
def visitElsif elsif_,args=nil
  cond=elsif_.cond.accept(self)
  body=elsif_.body.accept(self)
  code=Code.new
  code << "elsif #{cond} then"
  code.indent=2
  code << body
  code.indent=0
  code
end
visitEnumType(enum_type,name) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 223
def visitEnumType enum_type,name
  if name
    "type #{name} is (#{enum_type.items.join(',')});"
  else
    idx=$typedefs.values.index(enum_type)
    $typedefs.keys[idx]
  end
end
visitFsm(fsm,args=nil) click to toggle source

FSM ===

# File lib/ruby_rtl/vhdl_generator.rb, line 393
def visitFsm fsm,args=nil
  @fsm=fsm
  state_names=fsm.states.map{|state| state.name}.join(",")
  @fsm_defs << "type #{fsm.name}_state_t is (#{state_names});"
  @fsm_defs << "signal #{fsm.name}_state : #{fsm.name}_state_t;"
  body=Code.new
  body << "#{fsm.name}_update : process(reset_n,clk)"
  body << "begin"
  body.indent=2
  body << "if reset_n='0' then"
  body.indent=4
  body << "#{fsm.name}_state <= #{fsm.states.first.name};"
  fsm.assignments.each do |assign|
    lhs=assign.lhs.accept(self)
    rhs=default_init(assign.lhs.type)
    body << "#{lhs} <= #{rhs};"
  end
  body.indent=2
  body << "elsif rising_edge(clk) then"
  body.indent=4
  body << "if sreset='1' then"
  body.indent=6
  body << "#{fsm.name}_state <= #{fsm.states.first.name};"
  fsm.assignments.each do |assign|
    lhs=assign.lhs.accept(self)
    rhs=default_init(assign.lhs.type)
    body << "#{lhs} <= #{rhs};"
  end
  body.indent=4
  body << "else "
  body.indent=6
  body << state_cases(fsm)
  body.indent=4
  body << "end if;"
  body.indent=2
  body << "end if;"
  body.indent=0
  body << "end process;"
  body
end
visitFuncCall(func,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 482
def visitFuncCall func,args=nil
  name=func.name
  argus=func.args.map{|arg| arg.accept(self)}.join(',')
  "#{name}(#{argus})"
end
visitIf(if_,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 332
def visitIf if_,args=nil
  cond=if_.cond.accept(self)
  if_body=if_.body.accept(self)
  code=Code.new
  code << "if #{cond} then"
  code.indent=2
  code << if_body
  code.indent=0
  if_.elsifs.each{|elsif_|
    code << elsif_.accept(self)
  }
  code << if_.else.accept(self) if if_.else
  code << "end if;"
  code
end
visitIndexed(indexed,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 488
def visitIndexed indexed,args=nil
  lhs=indexed.lhs.accept(self)
  rhs=indexed.rhs.accept(self)
  case indexed.rhs
  when RUIntLit
  else
    conv_int_start="to_integer("
    conv_int_end  =")"
  end
  puts indexed.rhs
  "#{lhs}(#{conv_int_start}#{rhs}#{conv_int_end})"
end
visitInput(input,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 174
def visitInput input,args=nil
  name=@sigs[input] || input.name
  adapt_name(name,args)
end
visitIntLit(int,args=nil) click to toggle source

literals

# File lib/ruby_rtl/vhdl_generator.rb, line 540
def visitIntLit int,args=nil
  "to_signed(#{int.val},#{int.type.bitwidth})"
end
visitIntType(int,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 516
def visitIntType int,args=nil
  range="#{int.bitwidth-1} downto 0"
  "signed(#{range})"
end
visitMemoryType(memtype,name) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 250
def visitMemoryType memtype,name
  if name
    range="0 to #{memtype.size-1}"
    type=memtype.type.accept(self)
    "array(#{range}) of #{type}"
  else
    idx=$typedefs.values.index(memtype)
    $typedefs.keys[idx]
  end
end
visitNext(next_state,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 462
def visitNext next_state,args=nil
  "#{@fsm.name}_state <= #{next_state.name};"
end
visitOutput(output,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 179
def visitOutput output,args=nil
  name=@sigs[output] || output.name
  adapt_name(name,args)
end
visitRIntLit(lit,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 556
def visitRIntLit lit,args=nil
  lit.val
end
visitRUIntLit(lit,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 560
def visitRUIntLit lit,args=nil
  lit.val
end
visitRecordType(rectype,name) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 232
def visitRecordType rectype,name
  if name
    code=Code.new
    code << "record"
    code.indent=2
    rectype.hash.each do |name,type|
      type_s=type.accept(self)
      code << "#{name} : #{type_s};"
    end
    code.indent=0
    code << "end record;"
    code
  else
    idx=$typedefs.values.index(rectype)
    $typedefs.keys[idx]
  end
end
visitSequential(sequential,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 309
def visitSequential sequential,args=nil
  code=Code.new
  label=sequential.label
  code << "#{label} : process(clk)"
  code << "begin"
  code.indent=2
  code << "if rising_edge(clk) then"
  code.indent=4
  code << sequential.body.accept(self)
  code.indent=2
  code << "end if;"
  code.indent=0
  code << "end process;"
  code
end
visitSig(sig,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 200
def visitSig sig,args=nil
  name=sig.name
  adapt_name(name,args)
end
visitSigDecl(decl,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 184
def visitSigDecl decl,args=nil
  name=decl.name
  name.sub!(/@/,'')
  type=decl.sig.type.accept(self)
  case decl.sig
  when Input
    ios << "#{name} : in  #{type};"
  when Output
    ios << "#{name} : out #{type};"
  when Sig
    @sigs.merge!(decl.sig => name)
  else
    raise "ERROR : visitSigDecl : neither input ou output"
  end
end
visitState(state,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 457
def visitState state,args=nil
  code << "when #{state.name}"
  code
end
visitTypeDecl(decl,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 218
def visitTypeDecl decl,args=nil
  definition=decl.definition.accept(self,decl.name)
  "type #{decl.name} is #{definition};"
end
visitUIntLit(uint,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 544
def visitUIntLit uint,args=nil
  "to_unsigned(#{uint.val},#{uint.type.bitwidth})"
end
visitUIntType(uint,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 511
def visitUIntType uint,args=nil
  range="#{uint.bitwidth-1} downto 0"
  "unsigned(#{range})"
end
visitWhen(when_,args=nil) click to toggle source
# File lib/ruby_rtl/vhdl_generator.rb, line 380
def visitWhen when_,args=nil
  unless (value=when_.value).is_a? Symbol
    value=when_.value.accept(self)
  end
  code=Code.new
  code << "when #{value} =>"
  code.indent=2
  code << when_.body.accept(self)
  code.indent=0
  code
end