xschem/src/vhdl.awk

771 lines
19 KiB
Awk
Executable File

#!/usr/bin/awk -f
#
# File: vhdl.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
{ # default is to print the current line if any other rule is not executed.
no_print=0
}
# 20080213 packages are marked so they will be printed verbatim
/\/\/\/\/ begin package/, /\/\/\/\/ end package/{
if($0 ~ /^\/\/\/\//) next
else print $0
next
}
/\/\/\/\/ begin user declarations/, /\/\/\/\/ end user declarations/{
if($0 ~ /^\/\/\/\//) next
else user_declarations = user_declarations "\n" $0
next
}
/\/\/\/\/ begin user attributes/, /\/\/\/\/ end user attributes/{
if($0 ~ /^\/\/\/\//) next
else user_attributes = user_attributes "\n" $0
next
}
/---- start primitive/{primitive_line=""; primitive_mult=$4;primitive=1; next} # 20071217
/---- end primitive/{ # 20071217
primitive=0
# print "<<<<" primitive_line ">>>>"
$0 = primitive_line
gsub(/----pin\(/, " ----pin(",$0)
for(j=1;j<= primitive_mult; j++) {
for(i=1;i<=NF;i++) {
prim_field=$i
if($i ~ /^----pin\(.*\)/) {
sub(/----pin\(/,"",prim_field)
sub(/\)$/,"",prim_field)
pport_mult = split(prim_field, prim_field_array,/,/)
# 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 downto %s) ", 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", prim_field_array[s]
if(s<pport_mult) printf "&"
}
printf ") "
}
} else {
# printf "%s ", prim_field_array[1]
## 20170917
printf "%s ", to_round_brackets(prim_field_array[1+(j-1)%pport_mult])
}
}
else if($i ~ /^----name\(.*\)/) {
sub(/----name\(/,"",prim_field)
sub(/\)$/,"",prim_field)
split(prim_field, prim_field_array,/,/)
sub(/\[/,"_", prim_field_array[j])
sub(/\]/,"", prim_field_array[j])
printf "%s ", prim_field_array[j]
}
else printf "%s ", prim_field
} # end for i
printf "\n"
} # end for j
next
}
primitive==1{primitive_line=primitive_line " " $0; next } # 20071217
/^\/\/\/\/ begin user architecture code/{
begin_entity=0
next
}
##### JUST print things before first entity
(begin_entity!=1){
if($0 ~ /^entity .*is$/) begin_entity=1;
else
{
print $0
next
}
}
##### PRINT PROCESSES WITHOUT ANY CHANGES
/^[ \t]*([A-Za-z_][A-Za-z0-9_]*[ \t]*:)?[ \t]*process/, /^[ \t]*end[ \t]+process/{
print $0
next
}
#### BEGIN PRINT COMPONENT
/^component /{
component=1
component_name=$2
no_print=1
}
(component==1){
if($4==":=") $5=get_number($5)
if($5==":=") $6=get_number($6)
if($1 ~ /\[.*:.*\]/)
{
arch_sig_name[component_name,$1]=s_b($1) # array used to compare
# actual ports in instances, if they match
# avoid indexes (to/downto)
xx=s_i($1)
split(xx,xxx,":")
## don't add _vector if user defined type
if($4 ~ /^(boolean|bit|real|std_logic|integer)$/)
vector_type=$4 "_vector ("
else
vector_type=$4 " ("
if( (xxx[1]+0 > xxx[2]+0) || ( xxx[2]~/[01]/ && xxx[1]!~/^0$/) )
$4=vector_type xxx[1] " downto " xxx[2] ")"
else
$4=vector_type xxx[1] " to " xxx[2] ")"
$1=s_b($1)
print " " $0
}
else print $0
if($0 ~ /^end component/) component=0
no_print=1
}
#### BEGIN PRINT ENTITY
/^entity /{
delete entity_ports
user_declarations=""
user_attributes=""
entity=1
entity_name=$2
no_print=1
}
(entity==1){
if($4==":=") $5=get_number($5)
if($5==":=") $6=get_number($6)
if($1 ~ /\[.*:.*\]/)
{
xx=s_i($1)
split(xx,xxx,":")
## don't add _vector if user defined type
if($4 ~ /^(boolean|bit|real|std_logic|integer)$/)
vector_type=$4 "_vector ("
else
vector_type=$4 " ("
if( (xxx[1]+0 > xxx[2]+0) || (xxx[2]~/[01]/ && xxx[1] !~ /^0$/) )
$4=vector_type xxx[1] " downto " xxx[2] ")"
else
$4=vector_type xxx[1] " to " xxx[2] ")"
$1=s_b($1)
print " " $0
}
else print $0
entity_ports[$1]=1
if($1=="end" && $2==entity_name) entity=0
no_print=1
}
#### BEGIN RESOLVE SIGNALS
/^[ \t]*architecture[ \t]+.*[ \t]+is[ \t]*$/{
arch_rep=$2
arch=$4
delete arch_signal_dir
delete arch_index_array
delete arch_sig_type_array
delete arch_value_array
# omit bit ranges ( CNT => CNT(3 downto 0) --> CNT => CNT )
print $0
no_print=1
}
/^[ \t]*(signal|constant|variable)[ \t]+/{ ### dangerous <<< 07062002 added "variable"
if( $NF ~ /\[[^:,]+:[^:,]+\]$/) # 09112003, corrected to recognize only XXX[3:1] and not XXX[3:1],AA[3]
{
up=$NF
sub(/^.*\[/,"",up)
sub(/:.*$/,"",up)
up=up+0
low=$NF
sub(/^.*:/,"",low)
sub(/\].*$/,"",low)
low=low+0
if(up >=low) sig_dir = " downto "
else sig_dir = " to "
}
else sig_dir = " downto "
if( $2 ~ /.*\[[0-9]+\]/)
{
sig_basename=s_b($2)
sig_index=s_i($2)
# sig_dir not missing, it is set in the previous if-else 09112003
sig_type=$4
sig_class=$1
}
else
{
sig_basename=$2
sig_index="no_index" #11092003 set no_index to recognize non-buses
sig_type=$4
sig_dir=" downto " # just to have a value
sig_class=$1
}
arch_signal_dir[sig_basename]=sig_dir
arch_signal_class[sig_basename]=sig_class
arch_sig_type_array[sig_basename]=sig_type
if($0 ~ /:=/) {
# arch_value_array[sig_basename]=$(NF-2)
tmpval=$0 #04062002 allow spaces in value
sub(/^.* := /,"",tmpval)
sub(/ *;.*$/,"",tmpval)
arch_value_array[sig_basename]=tmpval
}
if(!(sig_basename in arch_index_array))
{
arch_index_array[sig_basename]= sig_index
}
else
{
arch_index_array[sig_basename]=arch_index_array[sig_basename] "," sig_index
}
no_print=1
}
/^begin$/{
if( user_declarations!="") print user_declarations
ttt[1]="constant"
ttt[2]="variable"
ttt[3]="signal"
for(tt=1;tt<=3;tt++)
for(i in arch_signal_dir)
if(arch_signal_class[i]==ttt[tt])
{
## 04062002 don't add _vector if user defined type
if(arch_sig_type_array[i] ~ /^(boolean|bit|real|std_logic|integer)$/)
vector_type=arch_sig_type_array[i] "_vector ("
else
vector_type=arch_sig_type_array[i] " ("
n=split(arch_index_array[i],tmp,",")
hsort(tmp, n)
if(n>1 || (arch_index_array[i] !~ /no_index/) ) #11092003 if not no_index treat as a bus
{
if(check(tmp,n))
{
if(arch_signal_dir[i] == " downto ")
{
arch_sig_name[entity_name, i "[" tmp[1] ":" tmp[n] "]"]=i
printf "%s",arch_signal_class[i] " " i " : " vector_type tmp[1] " downto " tmp[n] ")" #04062002
}
else
{
arch_sig_name[entity_name, i "[" tmp[n] ":" tmp[1] "]"]=i
printf "%s",arch_signal_class[i] " " i " : " vector_type tmp[n] " to " tmp[1] ")" #04062002
}
}
else print "\n**** ERROR >>>> " i " non contigous bus ->" n, "|" arch_index_array[i] "|"
}
else
{
# we do not declare parametrized subranges as normally will result in redeclaration
# of a port signal
if( i ~ /\[.*\]/)
{
range = s_i(i)
basename=s_b(i) # on exactly matching ranges
arch_sig_name[entity_name, basename "[" range "]"]=i # used later in port maps to avoid specifying ranges
if( !(basename in entity_ports) ) #09112003, eror corrected, basename instead of i in
{ #arch_sig_name[entity_name,...
if(range ~ /0:/)
sub(/:/, " to ", range)
else
sub(/:/, " downto ", range)
range= range ")"
printf "%s",arch_signal_class[i] " " basename " : " vector_type range #04062002
}
else continue
}
else
printf "%s",arch_signal_class[i] " " i " : " arch_sig_type_array[i]
}
if(arch_value_array[i] != "") { #08112004 add quotes on values
if(tolower( arch_sig_type_array[i]) ~ /std_logic/ || # if not present
tolower(arch_sig_type_array[i]) ~ /bit/ ) { # for verilog/VHDL compatiblity
# if(tolower(arch_sig_type_array[i]) ~ /vector/) sep="\""
if(n>1 || (arch_index_array[i] !~ /no_index/) ) sep="\""
else sep = "'"
if( arch_value_array[i] !~ sep)
arch_value_array[i] = sep arch_value_array[i] sep
}
printf "%s"," := " arch_value_array[i]
}
printf " ;\n"
}
if(user_attributes!="") print user_attributes
print $0
no_print=1
}
#### END RESOLVE SIGNALS
#### BEGIN RESOLVE INSTANCES
(NF==4 && $(NF-1)==":" && $(NF)!=";"){ ### dangerous <<<<<<<
instance=$2
gsub(/\[/,"_X_",instance)
gsub(/\]/,"",instance)
cell=$4
no_print=1
}
($1==");" && port_map==1){
nii=split(instance,ii,",")
for(j=0;j<p;j++) {
if(j>=g) { # do not split generics 06042005
actual_port_mult=split(inst_actual_port[j],actual_port_array,",")
}
else {
actual_port_mult=1
actual_port_array[1]=inst_actual_port[j]
}
ck2[j] = check2(actual_port_array,actual_port_mult)
}
for(i=1;i<=nii;i++) {
print ii[i] " : " cell
if(g>0)
print "generic map ("
else
print "port map (" # p= pin number of current instance
for(j=0;j<p;j++) { # g= flag for generic pin assignment
if(g>0 && j==g) printf "\n)\nport map ("
if(j>=g) { # do not split generics 06042005
actual_port_mult=split(inst_actual_port[j],actual_port_array,",")
}
else {
actual_port_mult=1
actual_port_array[1]=inst_actual_port[j]
}
# force to actual multiplicty unresolved (due to params) symbol pin multiplicity
parametrized_formal_range=0 # 20100408
if(inst_formal_port_mult[j]<0) {
parametrized_formal_range=1 # 20100408
inst_formal_port_mult[j] = actual_port_mult
inst_formal_up[j] = actual_port_mult -1 # 20100419 assume inst_formal_low=0 in case of parametrized vector port...
}
a=((i-1)*inst_formal_port_mult[j]) % actual_port_mult+1
b=(-1+i*inst_formal_port_mult[j]) % actual_port_mult+1
#print "\n-- a=" a " b=" b " formal port mult=" inst_formal_port_mult[j]
if(j>0 && j!=g) printf " ,\n"
else if(j>0) printf "\n"
if(inst_formal_port_mult[j]>1 && actual_port_mult>1 && ck2[j]) {
if( s_i(actual_port_array[a])+0 > s_i(actual_port_array[b])+0) {
actual_port= s_b(actual_port_array[a]) "(" s_i(actual_port_array[a]) " downto " s_i(actual_port_array[b]) ")"
}
else {
actual_port= s_b(actual_port_array[a]) "(" s_i(actual_port_array[a]) " to " s_i(actual_port_array[b]) ")"
}
}
else if( ck2[j] || inst_formal_port_mult[j]==1) {
actual_port = actual_port_array[a]
sub(/\[/,"(",actual_port)
sub(/\]/,")",actual_port)
sub(/:/," downto ",actual_port)
}
# these lines avoid specifying bit ranges (to/downto) for
# actual ports that exactly match declared signals or entity ports
tmp_port=actual_port
sub(/ (to|downto) /,":",tmp_port)
sub(/\(/,"[",tmp_port)
sub(/\)/,"]",tmp_port)
if( (entity_name,tmp_port) in arch_sig_name ) {
actual_port=arch_sig_name[entity_name,tmp_port]
}
if( ck2[j] || (inst_formal_port_mult[j]==1) ) { # contiguous bus or single bit
# 20100408 if formal range contains generic and actual port width is 1 specify formal bit index in assignment
if( (parametrized_formal_range || (inst_formal_port_mult[j]>1)) && actual_port_mult==1) {
# patch for single bit actual port
# assigned on vector formal port 23112002
# 20170920
if( parametrized_formal_range && inst_actual_port[j] ~/\[.*:.*\]/) {
printf "%s"," " inst_formal_port[j] " => " get_number(actual_port)
} else
# /20170920
for(num=inst_formal_low[j]; ; num+=sign(inst_formal_up[j] - inst_formal_low[j])) {
if(num !=inst_formal_low[j]) printf " ,\n"
printf "%s"," " inst_formal_port[j] "(" num ") => " get_number(actual_port)
if(num==inst_formal_up[j]) break
}
}
else printf "%s"," " inst_formal_port[j] " => " get_number(actual_port) #07062002 aggiunto get_number x generici
}
else { # non contiguous bus , specify assignments on single bits
for(num=a; ; num+= sign(b-a)) {
formal_index= (inst_formal_up[j] >= inst_formal_low[j]) ? \
remainder(inst_formal_up[j]-num+1+inst_formal_low[j], inst_formal_port_mult[j]) + inst_formal_low[j]: \
remainder(inst_formal_up[j]+num-1+inst_formal_up[j] , inst_formal_port_mult[j]) + inst_formal_up[j]
if(num !=a) printf " ,\n"
#07062002 aggiunto get_number x generici
printf "%s"," " inst_formal_port[j] "(" formal_index ") => " to_round_brackets(get_number(actual_port_array[num]))
if(num==b) break
}
}
}
printf "\n);\n"
}
port_map=0
print_arch_definition=1
no_print=1
}
(port_map==1 && $2=="=>" ){
inst_actual_port[p] = $0
sub(/.*=>[ \t]*/,"", inst_actual_port[p])
sub(/,[ \t]*$/,"", inst_actual_port[p])
if($1 ~ /\[.*:.*\]/) {
index_up=$1
sub(/^.*\[/,"",index_up)
sub(/:.*$/,"",index_up)
index_low=$1
sub(/^.*:/,"",index_low)
sub(/\].*$/,"",index_low)
if( (index_up !~/^[0-9]+$/) || (index_low !~/^[0-9]+$/) ) {
inst_formal_port_mult[p]=-1 # component port index contains parameter, multiplicity cant be resolved
inst_formal_up[p]=0
inst_formal_low[p]=0
}
else {
inst_formal_port_mult[p] = abs(index_up - index_low) + 1
inst_formal_up[p]=index_up
inst_formal_low[p]=index_low
#print "--port assignment: port " s_b($1) " formal idx hi=" index_up " lo=" index_low
}
}
else {
inst_formal_port_mult[p] = 1;
inst_formal_up[p]=0
inst_formal_low[p]=0
}
# if formal port = a[2:2] translate as a(2)
if(index_up == index_low && $1 ~ /\[.*:.*\]/)
inst_formal_port[p] = s_b($1) "(" index_up ")"
else
inst_formal_port[p] = s_b($1)
p++
no_print=1
}
(port_map==1 && $1~ /^\)/) { no_print=1 }
/^generic map/{
delete inst_actual_port
delete inst_formal_port
delete inst_formal_port_mult
p=0;g=0
port_map=1
no_print=1
}
/^port map/{
if(!port_map){
delete inst_actual_port
delete inst_formal_port
delete inst_formal_port_mult
p=0;g=0
port_map=1
}
else g=p
no_print=1
}
($1~ /^end$/ && $2==arch_rep){
arch_rep=""
print $0
no_print=1
}
(no_print==0){
print $0
}
#### UTILITY FUNCTIONS
function remainder(n,div, x) {
x=n%div
if(x<o) return x+div
return x
}
function abs(x)
{
if(x+0<0) return -x
else return x
}
function sign(x)
{
if(x+0<0) return -1
else return 1
}
# 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 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
}
# check if an array of indexes (sig[3]) arr[1],arr[2].....
# is contigous and decreeasing
function check2(arr,n ,a,name,i,start,ok)
{
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])
if(a+1 == start)
{
start=a
}
else
{
return 0
}
}
return 1
}
function s_i(a)
{
sub(/.*\[/,"",a)
sub(/\].*$/,"",a)
return a
}
function s_b(a)
{
sub(/\[.*$/,"",a)
return a
}
function get_number(n) # follows SPICE conventions
{
sub(/^[ \t]+/,"",n)
sub(/[ \t]+$/,"",n)
if(n !~ /^[-.0-9]/) return n # not a number
if( n ~ / / ) return n
n=toupper(n)
if(n ~ /A/) return vhdl_paranoia(n*1e-18)
if(n ~ /F/) return vhdl_paranoia(n*1e-15)
if(n ~ /P/) return vhdl_paranoia(n*1e-12)
if(n ~ /N/) return vhdl_paranoia(n*1e-9)
if(n ~ /U/) return vhdl_paranoia(n*1e-6)
if(n ~ /M[^E][^G]/) return vhdl_paranoia(n*1e-3)
if(n ~ /K/) return vhdl_paranoia(n*1e3)
if(n ~ /MEG/) return vhdl_paranoia(n*1e6)
if(n ~ /G/) return vhdl_paranoia(n*1e9)
if(n ~ /T/) return vhdl_paranoia(n*1e12)
return vhdl_paranoia(n)
}
# convert numbers like 4e-7 to 4.0e-7 as VHDL is stupid enough to
# complain about "integers with negative exponent...."
function vhdl_paranoia(n)
{
if(n ~ /^[0-9]+[eE]/)
sub(/[eE]/,".0e",n)
return n
}
function to_round_brackets(s) {
sub(/\[/,"(",s)
sub(/\]/,")",s)
return s
}
function compact_pinlist(pin, dir ,i,ii,base,curr,curr_n,np)
{
delete pin_ret
delete net_ret
delete dir_ret
np=pin["n"]
if(np) {
ii=1
for(i=1;i<=np;i++) {
base =s_b( pin[i] )
if(i==1) {curr=base; curr_n=i}
else {
if(base != curr) {
pin_ret[ii] = compact_label(pin,curr_n,i-1)
dir_ret[ii] = dir[i-1]
ii++
curr=base;curr_n=i
}
}
}
pin_ret[ii] = compact_label(pin,curr_n,np)
dir_ret[ii] = dir[np]
pin_ret["n"] = dir_ret["n"] = ii
}
}
# 1 2 3 4 5 6 7 8 9 10 11 12
# PP A[3] A[2] A[1] B C K[10] K[9] K[5] K[4] K[3] K[1]
function compact_label(ar,a,b, ret,start,i)
{
ret=""
for(i=a;i<=b;i++) {
if(i==a) {start=a}
else {
if(ar[i-1] !~ /\[/) {
if(ar[i-1] != ar[i]) {
if(start < i-1) { ret = ret (i-start) "*" ar[i-1] ","; start=i }
else {ret = ret ar[i-1] ","; start=i }
}
}
else if(s_b(ar[i])!=s_b(ar[i-1]) ||
( lab_index(ar[i]) != lab_index(ar[i-1])-1 &&
lab_index(ar[i]) != lab_index(ar[i-1])+1) ) {
if(start<i-1)
ret = ret s_b(ar[start]) "[" lab_index(ar[start]) ":" lab_index(ar[i-1]) "],"
else
ret = ret s_b(ar[start]) "[" lab_index(ar[start]) "],"
start=i
}
}
}
if(ar[b] !~ /\[/) {
if(start < b) ret = ret (b-start+1) "*" ar[b]
else ret = ret ar[b]
}
else if(start<b)
ret = ret s_b(ar[start]) "[" lab_index(ar[start]) ":" lab_index(ar[b]) "]"
else
ret = ret s_b(ar[b]) "[" lab_index(ar[b]) "]"
return ret
}
function lab_index(lab)
{
sub(/.*\[/,"",lab)
sub(/\].*/,"",lab)
return lab+0
}