413 lines
14 KiB
Awk
Executable File
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
|
|
}
|