500 lines
11 KiB
Awk
Executable File
500 lines
11 KiB
Awk
Executable File
#!/usr/bin/awk -f
|
|
#
|
|
# File: verilog.awk
|
|
#
|
|
# This file is part of XSCHEM,
|
|
# a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
|
# simulation.
|
|
# Copyright (C) 1998-2021 Stefan Frederik Schippers
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
BEGIN{
|
|
net_types["wire"]=1
|
|
net_types["tri"]=1
|
|
net_types["wor"]=1
|
|
net_types["trior"]=1
|
|
net_types["wand"]=1
|
|
net_types["triand"]=1
|
|
net_types["tri0"]=1
|
|
net_types["tri1"]=1
|
|
net_types["supply1"]=1
|
|
net_types["supply0"]=1
|
|
net_types["trireg"]=1
|
|
net_types["reg"]=1
|
|
net_types["integer"]=1
|
|
net_types["time"]=1
|
|
net_types["real"]=1
|
|
net_types["logic"]=1
|
|
net_types["bool"]=1
|
|
direction["input"]=1
|
|
direction["inout"]=1
|
|
direction["output"]=1
|
|
}
|
|
|
|
/^---- start primitive/{primitive_line=""; primitive_mult=$4;primitive=1; next}
|
|
/^---- end primitive/{
|
|
primitive=0
|
|
$0 = primitive_line
|
|
gsub(/----pin\(/, " ----pin(",$0)
|
|
gsub(/----name\(/, " ----name(",$0)
|
|
for(j=1;j<= primitive_mult; j++) {
|
|
prefix=""
|
|
# print $0 > "/dev/stderr"
|
|
for(i=1;i<=NF;i++) {
|
|
if($i ~/^#[a-zA-Z_]+#$/) {
|
|
prefix=$i
|
|
sub(/^#/,"", prefix)
|
|
sub(/#$/,"", prefix)
|
|
continue
|
|
}
|
|
prim_field=$i
|
|
if($i ~ /^----pin\(.*\)/) {
|
|
sub(/----pin\(/,"",prim_field)
|
|
sub(/\)$/,"",prim_field)
|
|
pport_mult = split(prim_field, prim_field_array,/,/)
|
|
|
|
# 20060919 BEGIN
|
|
# if bussed port connected to primitive and primitive mult==1 print only basename of bus
|
|
if(primitive_mult==1 && pport_mult>1) {
|
|
if(check2(prim_field_array, pport_mult))
|
|
printf "%s[%s:%s] ", prefix s_b(prim_field_array[1]),
|
|
s_i(prim_field_array[1]), s_i(prim_field_array[pport_mult])
|
|
else {
|
|
printf " { "
|
|
for(s=1;s<= pport_mult; s++) {
|
|
printf "%s", prefix prim_field_array[s]
|
|
if(s<pport_mult) printf ","
|
|
}
|
|
printf "} "
|
|
}
|
|
}
|
|
else
|
|
# 20060919 end
|
|
|
|
printf "%s ", prim_field_array[1+(j-1) % pport_mult] # 20140401 1+(j-1) % pport_mult instead of j
|
|
}
|
|
else if($i ~ /^----name\(.*\)/) {
|
|
sub(/----name\(/,"",prim_field)
|
|
sub(/\)$/,"",prim_field)
|
|
sub(/:/, "_slot_", prim_field)
|
|
split(prim_field, prim_field_array,/,/)
|
|
sub(/\[/,"_", prim_field_array[j])
|
|
sub(/\]/,"", prim_field_array[j])
|
|
printf "%s ", prefix prim_field_array[j]
|
|
}
|
|
else printf "%s ", prim_field
|
|
prefix=""
|
|
} # end for i
|
|
printf "\n"
|
|
} # end for j
|
|
next
|
|
}
|
|
|
|
primitive==1{primitive_line=primitive_line " " $0; next }
|
|
|
|
# print signals/regs/variables
|
|
/---- end signal list/{
|
|
for(i in signal_basename) {
|
|
n=signal_basename[i]
|
|
split(signal_index[i],tmp)
|
|
hsort(tmp,n)
|
|
printf "%s ", signal_type[i]
|
|
|
|
# 20161118
|
|
ntypes = split(signal_type[i], sigtype_arr)
|
|
if(ntypes==2) {
|
|
if( i in signal_delay) printf "%s ", signal_delay[i]
|
|
printf "%s", i
|
|
if(signal_index[i] !~ /no_index/)
|
|
{
|
|
if(tmp[1] ~ /:/) printf "[%s] ",tmp[1]
|
|
else if(n==1) printf "[%s:%s] ",tmp[1], tmp[1]
|
|
else printf "[%s:%s] ",tmp[1], tmp[n]
|
|
}
|
|
if(i in signal_value) printf " = %s ", signal_value[i]
|
|
printf " ;\n"
|
|
} else {
|
|
if( i in signal_delay) printf "%s ", signal_delay[i]
|
|
if(signal_index[i] !~ /no_index/)
|
|
{
|
|
if(tmp[1] ~ /:/) printf "[%s] ",tmp[1]
|
|
else if(n==1) printf "[%s:%s] ",tmp[1], tmp[1]
|
|
else printf "[%s:%s] ",tmp[1], tmp[n]
|
|
}
|
|
printf "%s ", i
|
|
if(i in signal_value) printf " = %s ", signal_value[i]
|
|
printf " ;\n"
|
|
}
|
|
}
|
|
# /20161118
|
|
|
|
siglist=0;
|
|
print ""
|
|
netlist=1
|
|
next
|
|
}
|
|
|
|
# store signals
|
|
siglist==1 && ($1 in net_types) {
|
|
|
|
# 20070525 recognize "reg real" types and similar
|
|
if($2 in net_types) {
|
|
if($3 ~ /^#/) basename=s_b($4)
|
|
else basename=s_b($3)
|
|
signal_type[basename]=$1 " " $2
|
|
if($3 ~ /^#/) {
|
|
signal_delay[basename]=$3
|
|
$3=""; $0=$0;
|
|
}
|
|
if($4=="="){
|
|
val=$0
|
|
sub(/.*=/,"",val)
|
|
sub(/;.*/,"",val)
|
|
signal_value[basename]=val
|
|
}
|
|
signal_basename[basename]++
|
|
if($3 ~ /\[.*\]/) {
|
|
signal_index[basename]=signal_index[basename] " " s_i($3)
|
|
}
|
|
else signal_index[basename]="no_index"
|
|
|
|
}
|
|
# /20070525
|
|
|
|
else {
|
|
if($2 ~ /^#/) basename=s_b($3)
|
|
else basename=s_b($2)
|
|
signal_type[basename]=$1
|
|
if($2 ~ /^#/) {
|
|
signal_delay[basename]=$2
|
|
$2=""; $0=$0;
|
|
}
|
|
if($3=="="){
|
|
val=$0
|
|
sub(/.*=/,"",val)
|
|
sub(/;.*/,"",val)
|
|
signal_value[basename]=val
|
|
}
|
|
signal_basename[basename]++
|
|
if($2 ~ /\[.*\]/) {
|
|
signal_index[basename]=signal_index[basename] " " s_i($2)
|
|
}
|
|
else signal_index[basename]="no_index"
|
|
}
|
|
next
|
|
}
|
|
|
|
/---- begin signal list/{
|
|
siglist=1;
|
|
next
|
|
}
|
|
|
|
# print module ports
|
|
begin_module==1 {
|
|
$1=s_b($1)
|
|
}
|
|
|
|
# new module declaration
|
|
NF==3 && $3=="(" && $1=="module" {
|
|
begin_module=1
|
|
delete signal_basename
|
|
delete signal_index
|
|
delete signal_value
|
|
delete signal_type
|
|
delete signal_delay
|
|
}
|
|
|
|
begin_module && $1 ~/^\);$/ {
|
|
begin_module=0
|
|
}
|
|
netlist==0 && $0 ~ /^ *parameter +[^ ]+ += +/{ $4=get_number($4) }
|
|
|
|
/^---- instance / {
|
|
on_single_line()
|
|
## ---- instance xsl[0],xsl[1],xsl[2],xsl[3],xsl[4],xsl[5],xsl[6],xsl[7] ( ?32 I[0:31] DEL[0],DEL[1] ...
|
|
num=split($3,name,",")
|
|
for(j=7;j<=NF-1;j+=3)
|
|
{
|
|
arg_num[j]=split($j,tmp,",")
|
|
for(k=1;k<=arg_num[j]; k++) {
|
|
arg_name[j,k]=tmp[k]
|
|
}
|
|
}
|
|
for(i=1;i<=num;i++)
|
|
{
|
|
gsub(/[\[]/,"_",name[i])
|
|
gsub(/[\]]/,"",name[i])
|
|
printf "%s", previous # print module name (and params)
|
|
printf "%s ( ", name[i]
|
|
|
|
for(j=5;j<=NF-1;j++)
|
|
{
|
|
pin=""
|
|
if(j>7) {printf ","}
|
|
if($j !~ /^\?-?[0-9]+$/)
|
|
{
|
|
pin=pin $j # if not a node just print it
|
|
}
|
|
else
|
|
{
|
|
nmult=$(j++);j++
|
|
|
|
sub(/\?/,"",nmult)
|
|
nmult=nmult+0
|
|
if(nmult==-1) nmult=arg_num[j]
|
|
for(l=0;l<nmult;l++)
|
|
{
|
|
ii=(l+nmult*(i-1))%arg_num[j]+1
|
|
if(pin!="") pin=pin ","
|
|
pin=pin arg_name[j,ii]
|
|
}
|
|
}
|
|
if(nmult==1) printf "\n .%s( %s )" ,s_b($(j-1)),pin
|
|
else {
|
|
split(pin,pin_array,",")
|
|
basename=s_b(pin_array[1])
|
|
if(check2(pin_array,nmult) && net_ascending==0) { ## 20140416 if ascending nets print single bits
|
|
if(nmult==signal_basename[basename] )
|
|
printf "\n .%s( %s )", s_b($(j-1)),basename
|
|
else
|
|
printf "\n .%s( %s[%s:%s] )",s_b($(j-1)),basename,s_i(pin_array[1]),s_i(pin_array[nmult])
|
|
}
|
|
else printf "\n .%s( %s )", s_b($(j-1)), (nmult>1? "{" pin "}" : pin)
|
|
}
|
|
}
|
|
printf "\n);\n\n"
|
|
}
|
|
previous=""
|
|
next
|
|
}
|
|
|
|
# types of in/out/inout ports of module
|
|
netlist==0 && architecture==0 && ($1 in net_types) && ($2 in net_types) {
|
|
if($3 ~ /\[.*\]/) {$3= s_b($3) "[" s_i($3) "] "; $1=" " $1 }
|
|
}
|
|
|
|
netlist==0 && architecture==0 && ($1 in net_types) && !($2 in net_types) {
|
|
if($2 ~ /\[.*\]/) {$2= "[" s_i($2) "] " s_b($2); $1=" " $1 }
|
|
}
|
|
|
|
# module port directions
|
|
NF==3 && netlist==0 && architecture==0 && ($1 in direction) {
|
|
if($2 ~ /\[.*\]/) {$2= "[" s_i($2) "] " s_b($2); $1=" " $1 } ## 20080412 print range also in port decl as req by standard
|
|
#### $2= s_b($2); $1=" " $1
|
|
}
|
|
|
|
/^---- begin user architecture code/ {
|
|
netlist=0
|
|
architecture=1
|
|
next
|
|
}
|
|
|
|
/^---- end user architecture code/ {
|
|
architecture=0
|
|
next
|
|
}
|
|
|
|
/^---- start parameters/{
|
|
parameters=1
|
|
next
|
|
}
|
|
|
|
/^---- end parameters/{
|
|
parameters=0
|
|
next
|
|
}
|
|
|
|
|
|
$NF=="," && parameters==1 {
|
|
if($1 ~ /^[+-]?(([0-9]+\.?)|([0-9]*\.[0-9]+))(([aAfFpPnNuUgGtT])|([mM][eE]][gG]))/){
|
|
$1=" " get_number($1)
|
|
}
|
|
}
|
|
|
|
# parameters assignments on instance line
|
|
/ *\.[a-zA-Z_0-9]+ \( [^ ]+ \)/ && parameters==1{ $3=get_number($3) }
|
|
/ *\.[a-zA-Z_0-9]+\( [^ ]+ \)/ && parameters==1{ $2=get_number($2) }
|
|
|
|
netlist==1 {
|
|
previous=previous $0 "\n"
|
|
next
|
|
}
|
|
|
|
|
|
|
|
{
|
|
print
|
|
}
|
|
|
|
|
|
function get_number(n) # follows SPICE conventions
|
|
{
|
|
if(n !~ /^[-.0-9]/) return n # not a number
|
|
n=toupper(n)
|
|
if(n ~ /A/) return n*1e-18
|
|
if(n ~ /F/) return n*1e-15
|
|
if(n ~ /P/) return n*1e-12
|
|
if(n ~ /N/) return n*1e-9
|
|
if(n ~ /U/) return n*1e-6
|
|
if(n ~ /M[^E][^G]/) return n*1e-3
|
|
if(n ~ /K/) return n*1e3
|
|
if(n ~ /MEG/) return n*1e6
|
|
if(n ~ /G/) return n*1e9
|
|
if(n ~ /T/) return n*1e12
|
|
return n+0.0 # force a numeric ret. value
|
|
}
|
|
|
|
|
|
# heap sort, this is a N*log2(N) routine
|
|
function hsort(ra,n, l,j,ir,i,rra)
|
|
{
|
|
if(n<=1) return # bug fix: if only one element in array never returns
|
|
l=int(n/2)+1
|
|
ir=n
|
|
for(;;) {
|
|
if(l>1) {
|
|
rra=ra[--l]
|
|
}
|
|
else {
|
|
rra=ra[ir]
|
|
ra[ir]=ra[1]
|
|
if(--ir==1) {
|
|
ra[1]=rra
|
|
return
|
|
}
|
|
}
|
|
i=l
|
|
j=l*2
|
|
while(j<=ir) {
|
|
if(j<ir && ra[j] >ra[j+1]) ++j
|
|
if(rra>ra[j]) {
|
|
ra[i]=ra[j]
|
|
j+=(i=j)
|
|
}
|
|
else j=ir+1
|
|
}
|
|
ra[i]=rra
|
|
}
|
|
}
|
|
# check if an array of indexes (sig[3]) arr[1],arr[2].....
|
|
# is contigous and decreeasing
|
|
# 20140409 handle ascending order as well as descending
|
|
function check2(arr,n ,decreasing,a,name,i,start,ok)
|
|
{
|
|
decreasing=""
|
|
net_ascending=0 # 20140416 must be global var !
|
|
name=s_b(arr[1])
|
|
start=s_i(arr[1])
|
|
if(arr[1] !~ /[0-9]+/)
|
|
{
|
|
if(n>1) return 0
|
|
else return 1
|
|
}
|
|
for(i=2;i<=n;i++)
|
|
{
|
|
if(s_b(arr[i]) != name) return 0
|
|
if(arr[1] !~ /[0-9]+/) return 0
|
|
a= s_i(arr[i])+0
|
|
if(a+1 == start)
|
|
{
|
|
if(decreasing=="") {
|
|
start=a
|
|
decreasing=1
|
|
} else if(decreasing==1) {
|
|
start=a
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
else if(a-1 == start)
|
|
{
|
|
if(decreasing=="") {
|
|
start=a
|
|
decreasing=0
|
|
} else if(decreasing==0) {
|
|
start=a
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0
|
|
}
|
|
}
|
|
|
|
if(decreasing==0) net_ascending=1 # net_ascending is global 20140416
|
|
else net_ascending=0 # net_ascending is global 20140416
|
|
return 1
|
|
}
|
|
|
|
# check if an array of numbers arr[1],arr[2]..... is contigous and decreeasing
|
|
function check(arr,n ,i,start,ok)
|
|
{
|
|
start=arr[1]
|
|
for(i=2;i<=n;i++)
|
|
{
|
|
if(arr[i]+1 == start)
|
|
{
|
|
start=arr[i]
|
|
}
|
|
else
|
|
{
|
|
return 0
|
|
}
|
|
}
|
|
return 1
|
|
}
|
|
|
|
function s_b(n)
|
|
{
|
|
sub(/\[.*/,"",n)
|
|
return n;
|
|
}
|
|
|
|
function s_i(n)
|
|
{
|
|
if(n ~ /\[/) {
|
|
sub(/.*\[/,"",n)
|
|
sub(/\]/,"",n)
|
|
return n
|
|
} else return ""
|
|
}
|
|
|
|
function cleanup()
|
|
{
|
|
gsub(/\);/," );")
|
|
}
|
|
|
|
function on_single_line( i,a,count)
|
|
{
|
|
cleanup()
|
|
count=0
|
|
i=1
|
|
a=""
|
|
while(1) {
|
|
if(i>NF) { getline;cleanup();i=1 }
|
|
if(count) a=a " "
|
|
a=a $i
|
|
count++
|
|
if($i==");") break
|
|
i++
|
|
}
|
|
$0= a
|
|
}
|
|
|