Close

Another method to create the wrapper

A project log for Libre Gates

A Libre VHDL framework for the static and dynamic analysis of mapped, gate-level circuits for FPGA and ASIC. Design For Test or nothing !

yann-guidon-ygdesYann Guidon / YGDES 09/09/2020 at 23:120 Comments

For now I manually create the "wrapper" unit that maps the inputs and outputs to a pair of unified vectors.

In private, Tristan told me there was some sort of Python thing that could do what I need but I'd rather avoid Python and experimental (like, less than 5 years old) features.

But there could be another way to extract the inputs and outputs from the compiled design : with the trace dumps ! GTKwave knows the type and direction of each port so maybe I can parse the trace dump to extract the info I want.

I'll have to test this ASAP, as I am currently contemplating how to make GetVectorsSize better.


Trying to play with GHDL in the LibreGates/tests/test2_INC8 directory:

> PA3="-P../../LibreGates -P../../LibreGates/proasic3"
> ghdl -a $PA3 INC8_ASIC.vhdl
> ghdl -e $PA3 INC8
> ./inc8 --vcd=inc8.vcd
> less inc8.vcd
____________________________
$date
  Sat Sep 12 05:18:00 2020
$end
$version
  GHDL v0
$end
$timescale
  1 fs
$end
$var reg 8 ! a[7:0] $end
$var reg 8 " y[7:0] $end
$var reg 1 # v $end
$var reg 8 $ ab[7:0] $end
$var reg 1 % a012 $end
$var reg 1 & a012a $end
$var reg 1 ' a012b $end
$var reg 1 ( a34 $end
$var reg 1 ) a345 $end
$var reg 1 * a3456 $end
$scope module (0) $end
$scope module x4 $end
$var reg 1 + a $end
$var reg 1 , y $end
$var reg 1 - t $end
$scope module e $end
......

OK....

I get a dump of signals but NO indication of type (which can only be assumed), direction or hierarchy...

From the doc:

"Currently, there is no way to select signals to be dumped: all signals are dumped, which can generate big files."

There could be more hope with the ./inc8 --wave=inc8.ghw command but that would require more efforts because the dump is in binary, undocumented and subject to change...


Another approach uses another underrated feature of GHDL :

ghdl --file-to-xml $PA3  INC8_ASIC.vhdl

The -a command is replaced here with --file-to-xml command which, as you can infer from the name, dumps a XML stream...

Here we find the definitions of the ports. This is contained in the "port_chain" tag :

<port_chain>
  <el kind="interface_signal_declaration" identifier="a" mode="in">
    <subtype_indication identifier="slv8"></subtype_indication>
  </el>
  <el kind="interface_signal_declaration" identifier="y" mode="out">
    <subtype_indication identifier="slv8"></subtype_indication>
  </el>
  <el kind="interface_signal_declaration" identifier="v" mode="out">
    <subtype_indication identifier="sl"></subtype_indication>
  </el>
</port_chain>

I have removed a LOT of text to get only what is required.

This allows the use of the wrapper types SLVx and SL, but now we need XML processing software to list and extract only the needed information...

Well, this is where it's getting interesting : at first I'd thought that using the wrapping types would make thing harder but looking at the XML, it looks like a great way to simplify the parsing because the std_logic_vectors use a complex system to define the bounds. OTOH the type SLV8 makes a static statement about the type and size, which is not flexible or generics-configurable but much more direct to extract.


Well, thanks to some unexpected hack found on StackOverflow, it seems that XML can be crudely parsed with some dirty-as-ever bash script.

#!/bin/bash

# LibreGates/wrap.sh
# created sam. sept. 12 09:29:47 CEST 2020

ReadTag () {
  IFS=\> read -d \< ENTITY
}

GetAttribute () {      #input list in $1
  LIST=($ATTRIBUTES)   # split string into array
  ATTRIBUTE=""
  for i in $(seq "${#LIST[@]}") ; do  # scan the list
    IFS='"' read -a ATTRIBUTE <<< "${LIST[$i]}"  # split the individual parameter in a sub-string
    #echo "  $ATTRIBUTE   -   ${ATTRIBUTE[1]}"
    if [[ $ATTRIBUTE = "$1" ]] ; then   # found the key
      echo -n "${ATTRIBUTE[1]}"         # return the value
    fi
  done
}

PORT_TYPE=""
PORTNAME=""
INOUT=""

FlushPort () {
  if [[ "$PORT_TYPE" != "" ]] ; then
    case "$INOUT" in
      "in")  ;;
      "out") ;;
      *) echo "wrong port direction for signal $PORTNAME"
         return
    esac
    echo "$PORTNAME $PORT_TYPE $INOUT"
  fi
}

# keep only the first "port_chain" block which should be the top-level interface
ghdl --file-to-xml $*        |  # transform the VHDL into XML
sed  '/ <\/port_chain>$/,$d' |  # drop everything after the first end of block
sed -n '/ <port_chain>$/,$p' |  # drop everything before the first start of block
while ReadTag; do               # parse the stream
  TAG_NAME=${ENTITY%% *}
  ATTRIBUTES=${ENTITY#* }

  if [[ $TAG_NAME = "el" ]] ; then
    FlushPort
    LIST=($ATTRIBUTES)               # split string into array
    INOUT=$(GetAttribute 'mode=')
    PORTNAME=$(GetAttribute 'identifier=')
  fi
  if [[ $TAG_NAME = "subtype_indication" ]] ; then
    PORT_TYPE=$(GetAttribute 'identifier=')
  fi
done

FlushPort

It could have been shorter but I wanted to avoid any collision (or worse) caused by eval.

And it works ! Here is the result when run on ALU8 :

$ ../../LibreGates/wrap.sh $PA3 ALU8_classic.vhdl
cin sl in
neg sl in
passmask sl in
orxor sl in
rop2mx sl in
cmps sl in
sri slv8 in
snd slv8 in
rop2 slv8 out
sum slv8 out

So now I just have to extract the size of each port and I'm almost done ;-)

Thank you GHDL :-P


Oh wait, the wrapper also needs the name of the entity to include. Hold my beer:

# Get the top level entity:
rm -f work-obj93.cf *.o
ghdl -a $* &&
TOP_ENTITY=$(ghdl --find-top $*)

 Sweet.


More head-desking caused by bash's insane system, and I can generate this :

architecture Wrap of Wrapper is
begin
  tb: entity alu8 port map (
    cin => VectIn(sl),
    neg => VectIn(sl),
    passmask => VectIn(sl),
    orxor => VectIn(sl),
    rop2mx => VectIn(sl),
    cmps => VectIn(sl),
    sri => VectIn(slv8),
    snd => VectIn(slv8),
    rop2 => VectOut(slv8),
    sum => VectOut(slv8),
    cout => VectOut(sl));
end Wrap;

Now I just have to manage the indices in the vectors.

But the whole system is upside down again because now the wrapper sets the sizes (nothing to probe) and must provide these values to the rest of the engine.


20201107 :

The scripts have worked but apparently it can't process files that include external gates.

I just found today that it works just OK when parsing the header/declaration !

Before, I had to parse the higher-level version of a unit without the inclusions, and flush all the intermediary results, but I can simply strip the (often duplicated) declaration and cut at the "architecture" line.

Discussions