#!/usr/bin/awk -f # # File: gschemtoxschem.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 #### Translates a geda-gschem symbol or schematic into xschem equivalent. #### Usage: #### gschemtoxschem.awk geda_file.sch > xschem_file.sch #### gschemtoxschem.awk geda_file.sym > xschem_file.sym #### before processing file BEGIN{ halfpinsize=2.5 ret = 1 debug=0 # set to 1 to print debug info to stderr } #### on first line FNR==1{ if(FILENAME ~/\.sym$/) is_symbol = 1 sch = FILENAME sub(/\.[^.]+$/, ".sch", sch) if(file_exists(sch)) has_schematic = 1 dbg("has sch") pin = 0 net_assign = 0 pinseq=0 max_pinseq = 0 template_attrs="" extra = extra_format = extra_pinnumber = "" delete slotdef numslots="" } #### for every line in geda sch/sym file { while(ret > 0 ) { #### line objects if($0 ~ /^L/){ x1 = $2 / 10 y1 = $3 / 10 x2 = $4 / 10 y2 = $5 / 10 lines = lines "L 4 " order(x1, y1, x2, y2) " {}\n" } #### Text objects # T x y color size visibility show angle alignment num_lines # 1 2 3 4 5 6 7 8 9 10 # show 0:show both, 1:value only 2:name only # alignment: # 2-------------5--------------8 # | | # 1 T E(4) X T 7 # | | # 0-------------3--------------6 # num_lines starts at 1 else if($0 ~ /^T/){ xt = $2 / 10 yt = $3 / 10 size = $5 / 30 visibility = $6 show = $7 angle = $8 align = $9 nlines = $10 text = "" len = 0 for(i = 1; i<= nlines; i++) { getline if($0 ~/=/) { sub(/^refdes=/, "name=") if($0 ~/slotdef=/) { tmp = $0 sub(/slotdef=/,"", tmp) slotnum=tmp sub(/:.*/,"", slotnum) sub(/.*:/,"", tmp) slotdef[slotnum] = tmp # print "slotnum=" slotnum " slotdef=" slotdef[slotnum] > "/dev/stderr" continue } if($0 ~/numslots=/) { numslots = $0 sub(/numslots=/,"", numslots) template_attrs = template_attrs escape_chars($0) " " continue } if($0 ~/net=/) { tmp = $0 sub(/net=/,"", tmp) net[++net_assign] = tmp continue } template_attrs = template_attrs escape_chars($0) " " #### put into "extra" all attributes that are meaningless for spice netlisting #### if you need other attributes to filter out , add them below. #### however this will break slotted devices #### # if($0 ~ /^(device|description|footprint|source|numslots)=/) { # attributes = $0 # sub(/=.*/, "", attributes) # if(extra !="") extra = extra " " # if(extra_pinnumber !="") extra_pinnumber = extra_pinnumber " " # extra = extra attributes # extra_pinnumber = extra_pinnumber "-" # } save = $0 sub(/^device=/, "type=") if ($0 ~/^value=IO/) { # inconsistency in io-1.sym $0 = "type=IO" } if ($0 ~/^type=/) { if($0 ~/=INPUT/) {pin = 1; sub(/=.*/, "=ipin"); template_attrs = template_attrs "lab=xxx "} if($0 ~/=OUTPUT/) {pin = 1; sub(/=.*/, "=opin"); template_attrs = template_attrs "lab=xxx "} if($0 ~/=IO/) {pin = 1; sub(/=.*/, "=iopin"); template_attrs = template_attrs "lab=xxx "} if(is_symbol && has_schematic) global_attrs = "type=subcircuit\n" global_attrs else global_attrs = $0 "\n" global_attrs } $0 = save if(show == 1) { sub(/=.*/,"",$0) $0 = "@" $0 } if(show == 2) sub(/=.*/,"",$0) # print ">>> " $0 ": template_attrs = " template_attrs > "/dev/stderr" } if(length($0) > len) len = length($0) if(text != "") text = text "\n" text = text $0 } correct_align() if(visibility) { texts = texts "T {" text "} " xt " " (-yt) " " int(angle/90) " " flip " " size " " size " {" text_align "}\n" } } #### box objects else if($0 ~ /^B/){ x1 = $2 / 10 y1 = $3 / 10 x2 = x1 + $4 / 10 y2 = y1 + $5 / 10 boxes = boxes "L 4 " x1 " " (-y1) " " x2 " " (-y1) " {}\n" boxes = boxes "L 4 " x2 " " (-y2) " " x2 " " (-y1) " {}\n" boxes = boxes "L 4 " x1 " " (-y2) " " x2 " " (-y2) " {}\n" boxes = boxes "L 4 " x1 " " (-y2) " " x1 " " (-y1) " {}\n" } #### circle objects else if($0 ~ /^V/){ #circle circles = circles "A 4 " ($2/10) " " (-$3/10) " " ($4/10) " " 0 " " 360 " {}\n" } #### arc objects # A 1000 1000 100 90 180 3 0 0 0 -1 -1 else if($0 ~ /^A/){ #arc arcs = arcs "A 4 " ($2/10) " " (-$3/10) " " ($4/10) " " ($5) " " ($6) " {}\n" } #### path objects: use xschem polygon # H 3 0 0 0 -1 -1 1 -1 -1 -1 -1 -1 5 <--n_lines #path object --> simulate with polygon else if($0 ~ /^H/){ numlines =$NF polys = polys "P 4 " numlines " " for(i = 0; i < numlines; i++) { getline sub(/,/, " ", $0) if($0 == "z") { polyx[i] = polyx[0] polyy[i] = polyy[0] } else { polyx[i] = $2/10 polyy[i] = -$3/10 } polys = polys polyx[i] " " polyy[i] " " } polys = polys "{fill=true}\n" } #### net (wire) objects # N 39000 50400 39000 51000 4 else if($0 ~/^N/) { nx1 = $2/10 ny1 = -$3/10 nx2 = $4/10 ny2 = -$5/10 if(nx2 < nx1) {xxtmp=nx1;nx1=nx2;nx2=xxtmp;xxtmp=ny1;ny1=ny2;ny2=xxtmp} else if(nx2 == nx1 && ny2 < ny1) {xxtmp=ny1;ny1=ny2;ny2=xxtmp} propstring = "" ret = getline if($0 == "{") { getline while($0 !="}") { if($0 ~/^T/) { tx = $2/10 ty = -$3/10 } else { if($0 ~/netname=/) sub(/netname=/, "lab=") propstring = propstring $0 " " } getline } } else { wires = wires "N " nx1 " " ny1 " " nx2 " " ny2 " {" propstring "}\n" continue # process again last getlined line } wires = wires "N " nx1 " " ny1 " " nx2 " " ny2 " {" propstring "}\n" if(propstring!="") { if(ny1 == ny2) { # horizontal wire ty = ny1 if(tx < nx1) tx = nx1 if(tx > nx2) tx = nx2 } else if(nx1 == nx2) { # vertical line tx = nx1 if(ty < ny1) ty = ny1 if(ty > ny2) ty = ny2 } else { # oblique line tx = (nx1+nx2)/2 ty = (ny1+ny2)/2 } wires = wires "C {lab_wire.sym} " tx " " ty " 0 1 {" propstring "}\n" } } #### component instance object # selectable angle flip #C 36700 54700 1 90 0 resistor-1.sym #component else if($0 ~ /^C/){ cx = $2/10 cy=-$3/10 crot = $5/90 slot="" if(crot == 1) crot = 3 else if(crot == 3) crot = 1 cflip = $6 symbol = $NF propstring = "" ret = getline if($0 == "{") { getline while($0 !="}") { if($0 ~/^T /) { # do nothing for now } else { if($0 ~/net=/) { netname = pinnumber = $0 sub(/net=.*:/,"",pinnumber) sub(/net=/,"", netname) sub(/:.*/,"", netname) $0 = "net:" pinnumber "=" netname } if($0 ~ /slot=/) { slot = $0 sub(/slot=/,"", slot) getline continue } if($0 ~/refdes=/){ sub(/refdes=/, "name=") instname = $0 if(symbol ~/(in|out|io)-1\.sym/) { tmp = $0 sub(/name=/, "lab=", tmp) $0 = tmp } else { getline continue } } gsub(/ /, "\\\\\\\\ ", $0) # prefix spaces with double backslash propstring = propstring $0 "\n" # print propstring > "/dev/stderr" } getline } if(slot) { propstring = instname ":" slot "\n" propstring } else { propstring = instname "\n" propstring } } else { components = components "C {" symbol "} " cx " " cy " " crot " " cflip " {" propstring "}\n" continue # process again last getlined line } components = components "C {" symbol "} " cx " " cy " " crot " " cflip " {" propstring "}\n" } #### pin object # P 900 100 750 100 1 0 0 else if($0 ~ /^P/){ $2/=10; $3/=10; $4/=10; $5/=10 pin_idx++ pin_line[pin_idx] = "L 3 " order($2, $3, $4, $5) " {}" if($8 == 0) { pin_box[pin_idx] = "B 5 " $2-halfpinsize " " (-$3-halfpinsize) " " $2+halfpinsize " " (-$3+halfpinsize) } else { pin_box[pin_idx] = "B 5 " $4-halfpinsize " " (-$5-halfpinsize) " " $4+halfpinsize " " (-$5+halfpinsize) } ret = getline if($0 == "{") { nattr = 0 text = "" found_name = 0 found_pintype = 0 while($0 !="}") { getline if($1 == "T") { xt = $2/10 yt = $3/10 color = $4 size = $5/30 visible = $6 show = $7 angle = $8 align = $9 nlines = $10 for(i=1; i<= nlines; i++) { getline nattr++ pin_x[pin_idx, nattr] = xt pin_y[pin_idx, nattr] = yt pin_size[pin_idx, nattr] = size pin_visible[pin_idx, nattr] = visible pin_show[pin_idx, nattr] = show pin_angle[pin_idx, nattr] = angle pin_align[pin_idx, nattr] = align pin_lineno[pin_idx, nattr] = i attr = value = $0 sub(/=.*/, "", attr) sub(/.*=/, "", value) if(attr == "pinnumber") pinnumber = value if(attr == "pinlabel") { attr = "name" found_name = 1 } if(attr == "pintype") { found_pintype=1 attr = "dir" if(value=="clk") value = "in" if(value!="in" && value !="out") value = "inout" } if(attr == "pinseq") { pin_index[value] = pin_idx pinseq++ if(value > max_pinseq) max_pinseq = value } gsub(/\\/, "\\\\\\\\", value) # replace single slash with double backslash. gsub(/ /, "\\\\\\\\ ", value) # prefix spaces with double backslash gsub(/\\_/, "_", value) pin_attr[pin_idx, nattr] = attr pin_value[pin_idx, nattr] = value } } } if(!found_name) { nattr++ pin_attr[pin_idx, nattr] = "name" pin_value[pin_idx, nattr] = pinnumber } if(!found_pintype) { nattr++ pin_attr[pin_idx, nattr] = "dir" pin_value[pin_idx, nattr] = "inout" } pin_nattr[pin_idx] = nattr } else continue # process again last getlined line } break } # while(1) } function escape_chars(s, a, b) { a=b=s sub(/=.*/,"",a) sub(/.*=/,"",b) if(s!~/=/) b = "" sub(/"/, "\\\\\\\\", b) # prefix " with 2 backslashes if(b ~ / /) { b = "\\\\\"" b "\\\\\"" # escape " inside string with 2 backslashes } s = a "=" b return s } function print_header() { if(net_assign == 1 && pin_idx == 1) { pin = 2 tmp = net[1] sub(/:.*/, "", tmp) sub(/net=/, "", tmp) template_attrs = template_attrs "lab=" tmp "\n" } else if(net_assign >=1) { #symbol with attribute-defined connections for(i = 1; i <= net_assign; i++) { netname = pinnumber = net[i] sub(/:.*/,"", netname) sub(/.*:/, "", pinnumber) template_attrs = template_attrs netname "=" netname "\n" if(extra !="") extra = extra " " if(extra_format !="") extra_format = extra_format " " if(extra_pinnumber !="") extra_pinnumber = extra_pinnumber " " extra = extra netname extra_pinnumber = extra_pinnumber pinnumber extra_format = extra_format "@" netname } } if(extra) { extra = "extra=\"" extra "\"" } if(extra_pinnumber) { extra_pinnumber = "extra_pinnumber=\"" extra_pinnumber "\"" } if(pin == 1) spice_attrs = tedax_attrs="" else if(pin == 2) { spice_attrs = tedax_attrs="" sub(/type=[^ ]+\n/, "type=label\n", global_attrs) } else { if(is_symbol && has_schematic) { spice_attrs="format=\"@name @pinlist @symname " extra_format "\"\n" } else { spice_attrs="format=\"@name @pinlist @value " extra_format "\"\n" } tedax_attrs = "tedax_format=\"footprint @name @footprint\n" \ "value @name @value\n" \ "device @name @device\n" \ "@comptag\"\n" } print "v {xschem version=3.0.0 file_version=1.2}" template_attrs = "template=\"" template_attrs "\"\n" if(FILENAME ~/\.sym$/) { if(global_attrs !~ /type=/) if(pin == 2) { global_attrs = "type=label\n" global_attrs } else { global_attrs = "type=symbol\n" global_attrs } print "K {" global_attrs template_attrs tedax_attrs spice_attrs if(extra) { print extra } if(extra_pinnumber) { print extra_pinnumber } dbg("extra=" extra) print "}" } else { print "K {}" } print "G {}" print "V {}" print "S {}" print "E {}" } function file_exists(f, r, c) { r = getline c < f close(f) if(r==-1) return 0 else return 1 } function order(x1, y1, x2, y2, tmp) { y1 = -y1 y2 = -y2 if(x2 "/dev/stderr" } # 2-------------5--------------8 # | | # 1 T E(4) X T 7 # | | # 0-------------3--------------6 # # assumes xt, yt, angle, size, align, len are set globally # corrects angle, xt, yt, sets flip # sets also text_align function correct_align( hcorrect, vcorrect) { hcorrect = 17 vcorrect = 25 text_align="" if (angle == 0 && align == 0 ) { angle = 180; flip = 1} else if(angle == 90 && align == 0 ) { angle = 90; flip = 1} else if(angle == 180 && align == 0 ) { angle = 0; flip = 1} else if(angle == 270 && align == 0 ) { angle = 270; flip = 1} if (angle == 0 && align == 3 ) { angle = 180; flip = 1; text_align = " hcenter=true"} else if(angle == 90 && align == 3 ) { angle = 90; flip = 1; text_align = " hcenter=true"} else if(angle == 180 && align == 3 ) { angle = 0; flip = 1; text_align = " hcenter=true"} else if(angle == 270 && align == 3 ) { angle = 270; flip = 1; text_align = " hcenter=true"} else if(angle == 0 && align == 6 ) { angle = 180; flip = 0} else if(angle == 90 && align == 6 ) { angle = 90; flip = 0} else if(angle == 180 && align == 6 ) { angle = 0; flip = 0} else if(angle == 270 && align == 6 ) { angle = 270; flip = 0} else if(angle == 0 && align == 8 ) { angle = 0; flip = 1} else if(angle == 90 && align == 8 ) { angle = 270; flip = 1} else if(angle == 180 && align == 8 ) { angle = 180; flip = 1} else if(angle == 270 && align == 8 ) { angle = 90; flip = 1} else if(angle == 0 && align == 7 ) { angle = 0; flip = 1; text_align = " vcenter=true"} else if(angle == 90 && align == 7 ) { angle = 270; flip = 1; text_align = " vcenter=true"} else if(angle == 180 && align == 7 ) { angle = 180; flip = 1; text_align = " vcenter=true"} else if(angle == 270 && align == 7 ) { angle = 90; flip = 1; text_align = " vcenter=true"} else if(angle == 0 && align == 4 ) { angle = 0; flip = 1; text_align=" hcenter=true vcenter=true"} else if(angle == 90 && align == 4 ) { angle = 270; flip = 1; text_align=" hcenter=true vcenter=true"} else if(angle == 180 && align == 4 ) { angle = 180; flip = 1; text_align=" hcenter=true vcenter=true"} else if(angle == 270 && align == 4 ) { angle = 90; flip = 1; text_align=" hcenter=true vcenter=true"} else if(angle == 0 && align == 2 ) { angle = 0; flip = 0} else if(angle == 90 && align == 2 ) { angle = 270; flip = 0} else if(angle == 180 && align == 2 ) { angle = 180; flip = 0} else if(angle == 270 && align == 2 ) { angle = 90; flip = 0} else if(angle == 0 && align == 1 ) { angle = 0; flip = 0; text_align = " vcenter=true"} else if(angle == 90 && align == 1 ) { angle = 270; flip = 0; text_align = " vcenter=true"} else if(angle == 180 && align == 1 ) { angle = 180; flip = 0; text_align = " vcenter=true"} else if(angle == 270 && align == 1 ) { angle = 90; flip = 0; text_align = " vcenter=true"} else if(angle == 0 && align == 5 ) { angle = 0; flip = 0; text_align = " hcenter=true"} else if(angle == 90 && align == 5 ) { angle = 270; flip = 0; text_align = " hcenter=true"} else if(angle == 180 && align == 5 ) { angle = 180; flip = 0; text_align = " hcenter=true"} else if(angle == 270 && align == 5 ) { angle = 90; flip = 0; text_align = " hcenter=true"} } function dbg(s) { if(debug) print s > "/dev/stderr" } #### end processing geda file: print translated xschem file to stdout END{ print_header() print texts print boxes print lines print circles print arcs print polys print components print wires #### print pins npin = 0 # order of pins in xschem # i is the pinseq for(i = 1; i <= max_pinseq; i++) { if( i in pin_index) idx = pin_index[i] else continue print pin_line[idx] nattr = pin_nattr[idx] attr_string="" for(j = 1; j <= nattr; j++) { attr_string = attr_string pin_attr[idx,j] "=" pin_value[idx,j] "\n" } if(numslots > 1 ) { pinseq = attr_string sub(/.*pinseq=/,"", pinseq) sub(/[\n ].*/,"", pinseq) # print "pinseq=" pinseq > "/dev/stderr" sub(/pinnumber=[^ \n]+/,"", attr_string) # print "---\n" attr_string "\n---\n" > "/dev/stderr" slotted_pinnumber = "" for(j = 1; j<= numslots; j++) { # print "slotdef[" j "]=" slotdef[j] > "/dev/stderr" split(slotdef[j], slotdef_arr, ",") if(slotted_pinnumber !="") slotted_pinnumber = slotted_pinnumber ":" slotted_pinnumber = slotted_pinnumber slotdef_arr[pinseq] } # print "slotted_pinnumber=" slotted_pinnumber > "/dev/stderr" attr_string = attr_string "pinnumber=" slotted_pinnumber "\n" } print pin_box[idx] " {" attr_string "}" for(j = 1; j <= nattr; j++) { xt = pin_x[idx,j] yt = pin_y[idx, j] size = pin_size[idx, j] visible = pin_visible[idx, j] show = pin_show[idx, j] angle = pin_angle[idx, j] align = pin_align[idx, j] attr = "@#" npin ":" pin_attr[idx, j] len = length(pin_value[idx, j]) correct_align() if( visible ) { if(pin_attr[idx, j] ~/^pinnumber$/) text_attr="layer=13" else text_attr="" print "T {" attr "} " xt " " (-yt) " " int(angle/90) " " flip " " size " " size " {" text_attr text_align "}" } } npin++ } # end print pins }