xschem/src/symgen.awk

413 lines
14 KiB
Awk
Executable File

#!/usr/bin/awk -f
#
# File: symgen.awk
#
# This file is part of XSCHEM,
# a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
# simulation.
# Copyright (C) 1998-2023 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
#
# create a symbol file from a symdef file, like the geda djboxsym utility
BEGIN{
debug = 1
symbolx1 = 0
symbolx2 = 700 # recalculated when number of top/bottom pins is known
symboly1 = 0
symboly2 = 700 # recalculated when number of left/right pins is known
firstpinyoffset = 40 # recalculated when top pin max label length is known
lastpinyoffset = 40 # recalculated when bottom pin max label length is known
pinspacing = 40
pinbusspacing = 20
pintextoffset = 11
pintextpadding = 18
pinboxhalfsize = 2.5
pinlinelength = 40
pintextsize = 0.4
overbaroffset = 6 * pintextsize
pintextcenteroffset = 24 * pintextsize
pintextheight = 56.6 * pintextsize
pincharspacing = 35 * pintextsize
pinnumbertextsize = 0.25
pinnumbercenteroffset = 16
pinnumberoffset = 12
labeltextsize = 0.6
labelspacing = 40 # vertical spacing of label strings
labelcharspacing = 30 * labeltextsize
labeloffset = 20 # extra space to put around labels to avoid collision with pin text labels
labelcenteroffset = 20 * labeltextsize
negradius = 5
triggerxsize = 8
triggerysize = 8
grid = 20
start_pin=0
nlines = 0
bus = 0
pos = 0 ## default if no [position] field specified
horizontal = 1 # default orient. for top/bottom pins, can be changed with --vertical
}
/^--/{
if(/^--auto[-_]pinnumber/) { enable_autopinnumber = 1 }
if(/^--hide[-_]pinnumber/) { hide_pinnumber = 1 }
if(/^--vmode/) { horizontal = 0 } # force horizontal top/bottom labels
next
}
/^[ \t]*#/{
next
}
/^[ \t]*\[labels\]/ {
start_labels = 1
next
}
start_labels == 1 {
if(/^\[/) start_labels = 0
else if(/^! /) {
if(attributes) attributes = attributes "\n"
attributes = attributes substr($0, 3)
dbg("attributes=" attributes)
next
} else if(NF > 0){
labn = label["n"]++
label[labn] = $0
if( length($0) > label["maxlength"] ) label["maxlength"] = length($0)
dbg("label: " $0)
next
}
}
/^[ \t]*\[left\]/ { pos = 0 }
/^[ \t]*\[top\]/ { pos = 1 }
/^[ \t]*\[right\]/ { pos = 2 }
/^[ \t]*\[bottom\]/ { pos = 3 }
/^[ \t]*\[[^][]*\][ \t]*$/ {
start_labels = 0
posseq[seqidx++] = pos
pin[pos, "n"] = 0;
start_pin = 1;
coord = 0;
next
}
/^\./{
if(/^\.bus/) {
if( !horizontal || (pos == 0 || pos == 2) ) {
bus = 1
firstbus=1
}
}
next
}
## typical pin line is as follows
## 26 i!> CLK
start_pin {
if(NF > 0 && enable_autopinnumber) $0 = ++autopinnumber " " $0
n = pin[pos, "n"]
if(NF == 0) {
if(bus == 1) coord += delta1
else coord += pinspacing
bus = 0
dbg("spacer")
pin[pos, n, "spacer"] = 1
pin[pos, "n"]++
} else if(NF == 2) { $0 = $1 " io " $2 } ## backward compatibility with 'djboxsym' format
if(NF == 3) {
trig = 0
neg = 0
dir = "inout" ## default if (mandatory) direction forgotten
if($2 ~ />/) trig = 1
if($2 ~ /!/) neg = 1
if($2 ~ /io/) dir = "inout"
else if($2 ~ /i/) dir = "in"
else if($2 ~ /o/) dir = "out"
else if($2 ~ /p/) dir = "inout" # xschem has no special attrs for power so set direction as inout
pinnumber = $1
pinname = $3
if(pinname ~ /^\\_.*\\_$/) {
pin[pos, n, "overbar"] = 1
sub(/^\\/, "", pinname)
sub(/\\_$/, "_", pinname)
}
pin[pos, n, "pinname"] = pinname
pin[pos, n, "pinnumber"] = pinnumber
pin[pos, n, "dir"] = dir
pin[pos, n, "neg"] = neg
pin[pos, n, "trigger"] = trig
pin[pos, n, "bus"] = bus
if((pos == 1 || pos == 3 ) && horizontal ) {
delta1 = delta2 = round((length(pin[pos, n, "pinname"]) * pincharspacing + pintextpadding)) / 2
} else {
if(bus) {
if(!firstbus) delta1 = pinbusspacing / 2
else delta1 = pinspacing / 2
delta2 = pinbusspacing / 2
firstbus = 0
} else {
delta1 = delta2 = pinspacing / 2
}
}
coord += delta1
pin[pos, n, "coord"] = round(coord)
dbg("pin[" pos ", " n ", coord]: " pin[pos, n, "coord"] " pinname: " \
pinname " bus: " bus " delta: " delta1 ":" delta2 " coord: " coord)
# dbg("delta1: " delta1 " delta2: " delta2)
coord += delta2
pin[pos, "maxcoord"] = coord
if( length(pinname) > pin[pos, "maxlength"] ) pin[pos, "maxlength"] = length(pinname)
pin[pos, "n"]++
}
}
## GENERATOR
END{
header()
attrs(attributes)
if(horizontal !=1) {
firstpinyoffset = round(pintextoffset + pincharspacing * pin[1, "maxlength"])
lastpinyoffset = round(pintextoffset + pincharspacing * pin[3, "maxlength"])
}
dbg("pin[1, maxlength]: " pin[1, "maxlength"])
dbg("pin[3, maxlength]: " pin[3, "maxlength"])
dbg("firstpinyoffset: " firstpinyoffset)
dbg("lastpinyoffset: " lastpinyoffset)
## round to double grid so half size is grid-aligned when centering
symboly2 = round(max(pin[0,"maxcoord"], pin[2, "maxcoord"]) / 2) * 2 + firstpinyoffset + lastpinyoffset
dbg("symboly2: " symbolx2)
dbg("pin[3, maxcoord]: " pin[3, "maxcoord"])
dbg("pin[1, maxcoord]: " pin[1, "maxcoord"])
dbg("pin[0, maxcoord]: " pin[0, "maxcoord"])
dbg("pin[2, maxcoord]: " pin[2, "maxcoord"])
topbotpinsize = max(pin[1,"maxcoord"], pin[3, "maxcoord"]) + pintextpadding / 2
labsize = ( (labelcharspacing * label["maxlength"] + labeloffset)/2 \
+ max(pincharspacing * pin[0, "maxlength"], pincharspacing * pin[2, "maxlength"])) * 2
dbg("topbotpinsize: " topbotpinsize)
dbg("labsize: " labsize)
dbg("pincharspacing * pin[0, maxlength]: " pincharspacing * pin[0, "maxlength"])
dbg("pincharspacing * pin[2, maxlength]: " pincharspacing * pin[2, "maxlength"])
symbolx2 = round( max(topbotpinsize, labsize) / 2) * 2 ## round to double grid so half size is grid-aligned when centering
dbg("symbolx2: " symbolx2)
## center symbol after size calculations are done
symbolx1 -= round(symbolx2/2)
symbolx2 += symbolx1
symboly1 -= round(symboly2/2)
symboly2 += symboly1
pinseq = 0;
for(i = 0; i < 4; i++) {
p = posseq[i]
for(n = 0; n < pin[p,"n"]; n++) {
dir = pin[p, n, "dir"]
plinelay = (dir =="in") ? 4 : (dir == "inout") ? 3 : 2
if(p == 0 ) {
x = symbolx1 - pinlinelength
y = symboly1 + pin[p, n, "coord"] + firstpinyoffset
}
else if(p == 1 ) {
x = symbolx1 + pin[p, n, "coord"]
y = symboly1 - pinlinelength
}
else if(p == 2 ) {
x = symbolx2 + pinlinelength
y = symboly1 + pin[p, n, "coord"] + firstpinyoffset
}
else if(p == 3 ) {
x = symbolx1 + pin[p, n, "coord"]
y = symboly2 + pinlinelength
}
if(pin[p, n, "spacer"] != 1) {
pinbox(p, n, x, y)
neg = pin[p, n, "neg"]
trig = pin[p, n, "trigger"]
pinname = pin[p, n, "pinname"]
if(pin[p, n, "overbar"] == 1) {
sub(/^_/,"", pinname)
sub(/_$/,"", pinname)
}
if(p == 0) {
line(x, y, x + (neg ? pinlinelength - 2 * negradius : pinlinelength), y, plinelay, "")
text(pinname, x + pinlinelength + pintextoffset, y - pintextcenteroffset, 0, 0, pintextsize, "")
if(pin[p, n, "overbar"] == 1) {
obx = x + pinlinelength + pintextoffset
oby = y - pintextcenteroffset - overbaroffset
obl = (length(pin[p, n, "pinname"]) - 2 ) * pincharspacing
line(obx, oby, obx + obl, oby, 3, "")
}
if(!hide_pinnumber)text(pinnumber_id(pinseq), x + pinlinelength - pinnumberoffset, \
y - pinnumbercenteroffset, 0, 1, pinnumbertextsize, "layer=13")
if(neg) circle(x + pinlinelength - negradius, y, negradius, plinelay, "")
} else if(p == 1) {
line(x, y, x, y + (neg ? pinlinelength - 2 * negradius : pinlinelength) , plinelay, "")
if(horizontal) {
halflabwidth = length(pinname) * pincharspacing / 2
text(pinname, x - halflabwidth, y + pinlinelength + pintextoffset, 0, 0, pintextsize, "")
if(pin[p, n, "overbar"] == 1) {
obx = x - halflabwidth
oby = y + pinlinelength + pintextoffset - overbaroffset
obl = (length(pin[p, n, "pinname"]) - 2 ) * pincharspacing
line(obx, oby, obx + obl, oby, 3, "")
}
} else {
text(pinname, x + pintextcenteroffset, y + pinlinelength + pintextoffset, 1, 0, pintextsize, "")
if(pin[p, n, "overbar"] == 1) {
obx = x + pintextcenteroffset - pintextheight - overbaroffset
oby = y + pinlinelength + pintextoffset
obl = (length(pin[p, n, "pinname"]) - 2 ) * pincharspacing
line(obx, oby + obl, obx, oby, 3, "")
}
}
if(!hide_pinnumber)text(pinnumber_id(pinseq), x - pinnumbercenteroffset, \
y + pinlinelength - pinnumberoffset, 3, 0, pinnumbertextsize, "layer=13")
if(neg) circle(x, y + pinlinelength - negradius, negradius, plinelay, "")
} else if(p == 2) {
line(x - (neg ? pinlinelength -2 * negradius :pinlinelength), y, x, y, plinelay, "")
text(pinname, x - pinlinelength - pintextoffset, y - pintextcenteroffset, 0, 1, pintextsize, "")
if(pin[p, n, "overbar"] == 1) {
obx = x - pinlinelength - pintextoffset
oby = y - pintextcenteroffset - overbaroffset
obl = (length(pin[p, n, "pinname"]) - 2) * pincharspacing
line(obx - obl, oby, obx, oby, 3, "")
}
if(!hide_pinnumber)text(pinnumber_id(pinseq), x - pinlinelength + pinnumberoffset, \
y - pinnumbercenteroffset, 0, 0, pinnumbertextsize, "layer=13")
if(neg) circle(x - pinlinelength + negradius, y, negradius, plinelay, "")
} else if(p == 3) {
line(x, y - (neg ? pinlinelength -2 * negradius :pinlinelength), x, y, plinelay, "")
if(horizontal) {
halflabwidth = length(pinname) * pincharspacing / 2
text(pinname, x - halflabwidth, y - pinlinelength - pintextoffset, 2, 1, pintextsize, "")
if(pin[p, n, "overbar"] == 1) {
obx = x - halflabwidth
oby = y - pinlinelength - pintextoffset - pintextheight - overbaroffset
obl = (length(pin[p, n, "pinname"]) - 2 ) * pincharspacing
line(obx, oby, obx + obl, oby, 3, "")
}
} else {
text(pinname, x + pintextcenteroffset, y - pinlinelength - pintextoffset, 1, 1, pintextsize, "")
if(pin[p, n, "overbar"] == 1) {
obx = x + pintextcenteroffset - pintextheight - overbaroffset
oby = y - pinlinelength - pintextoffset
obl = (length(pin[p, n, "pinname"]) - 2 ) * pincharspacing
line(obx, oby, obx, oby - obl, 3, "")
}
}
if(!hide_pinnumber)text(pinnumber_id(pinseq), x - pinnumbercenteroffset, \
y - pinlinelength + pinnumberoffset, 3, 1, pinnumbertextsize, "layer=13")
if(neg) circle(x, y - pinlinelength + negradius, negradius, plinelay, "")
}
if(trig) trigger(x, y, plinelay, p)
pinseq++
}
} # for(n)
} # for(p)
box(symbolx1, symboly1, symbolx2, symboly2, 4, "")
for(l = 0; l < label["n"]; l++) {
dbg("label: " l " : " label[l])
labx = (symbolx1 + symbolx2) / 2 - length(label[l]) * labelcharspacing /2
laby = (symboly1 + symboly2) / 2 + ( l - label["n"] / 2 ) * labelspacing + labelcenteroffset
text(label[l], labx, laby, 0, 0, labeltextsize, "")
}
}
function dbg(s)
{
if(debug) print s > "/dev/stderr"
}
function pinbox(p, n, x, y, arr)
{
print "B 5", x-pinboxhalfsize, y-pinboxhalfsize, x+pinboxhalfsize, y+pinboxhalfsize, \
"{name=" esc(pin[p, n, "pinname"]), \
"dir=" pin[p, n, "dir"], \
"pinnumber=" esc(pin[p, n, "pinnumber"]) "}"
}
function trigger(x, y, layer, pos)
{
if(pos == 0) {
line(x + pinlinelength, y - triggerysize, x + triggerxsize + pinlinelength, y, layer, "")
line(x + pinlinelength , y + triggerysize, x + pinlinelength + triggerxsize, y, layer, "")
} else if(pos == 2) {
line(x - pinlinelength - triggerxsize, y, x - pinlinelength, y - triggerysize, layer, "")
line(x - pinlinelength - triggerxsize, y , x - pinlinelength , y + triggerysize, layer, "")
} else if(pos == 1) {
line(x - triggerysize, y + pinlinelength, x, y + pinlinelength + triggerxsize, layer, "")
line(x , y + pinlinelength + triggerxsize, x + triggerysize, y + pinlinelength, layer, "")
} else if(pos == 3) {
line(x - triggerysize, y - pinlinelength, x, y - pinlinelength - triggerxsize, layer, "")
line(x , y - pinlinelength - triggerxsize, x + triggerysize, y - pinlinelength, layer, "")
}
}
function pinnumber_id(pinseq)
{
return("@#" pinseq ":pinnumber")
}
function circle(x, y, r, layer, props)
{
print "A", layer, x, y, r, 0, 360, "{" esc(props) "}"
}
function box(x1, y1, x2, y2, layer, props)
{
## closed polygon
print "P", layer, 5, x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, "{" esc(props) "}"
}
function line(x1, y1, x2, y2, layer, props)
{
print "L", layer, x1, y1, x2, y2, "{" esc(props) "}"
}
function text(t, x, y, rot, flip, size, props)
{
print "T {" esc(t) "}", x, y, rot, flip, size, size, "{" esc(props) "}"
}
function attrs(a)
{
print "G {" esc(a) "}"
}
function header()
{
print "v {xschem version=3.4.0 file_version=1.2}"
}
function round(n)
{
return n==0 ? 0 : (n > 0) ? (int( (n-0.001)/grid) +1) * grid : (int( (n+0.001)/grid) -1) * grid
}
function max(a, b) { return (a > b) ? a : b }
function esc(s)
{
gsub(/\\/, "\\\\", s)
gsub(/{/, "\\{", s)
gsub(/}/, "\\}", s)
return s
}