kararrr/go-dsn2pcb/dsn2pcb.go

558 lines
13 KiB
Go

///opt/local/bin/go run
// Copyright (C) 2014 Chris Hinsley.
//package name
package main
//package imports
import (
"./router"
"bufio"
"flag"
"fmt"
"math"
"os"
"strconv"
"strings"
)
type tree struct {
value *string
branches []*tree
}
type point struct {
x float64
y float64
}
type pin struct {
form *string
angle float64
name *string
x float64
y float64
}
type component struct {
name *string
pin_map map[string]*pin
}
type instance struct {
name *string
comp *string
x float64
y float64
side *string
angle float64
}
type rule struct {
radius float64
gap float64
shape *[]point
}
type circuit struct {
via *string
rule *rule
}
func shape_to_cords(shape *[]point, a1, a2 float64) *router.Cords {
cords := router.Cords{}
rads := math.Mod(a1+a2, 2*math.Pi)
s := math.Sin(rads)
c := math.Cos(rads)
for _, p := range *shape {
px := (c*p.x - s*p.y)
py := (s*p.x + c*p.y)
cords = append(cords, &router.Cord{float32(px), float32(py)})
}
return &cords
}
func cords_equal(pc1, pc2 *router.Cords) bool {
if pc1 == pc2 {
return true
}
c1 := *pc1
c2 := *pc2
if len(c1) != len(c2) {
return false
}
for i := 0; i < len(c1); i++ {
if c1[i].X != c2[i].X {
return false
}
if c1[i].Y != c2[i].Y {
return false
}
}
return true
}
func term_equal(pt1, pt2 *router.Terminal) bool {
if pt1 == pt2 {
return true
}
if !cords_equal(&pt1.Shape, &pt2.Shape) {
return false
}
if pt1.Radius != pt2.Radius {
return false
}
if pt1.Gap != pt2.Gap {
return false
}
if pt1.Term != pt2.Term {
return false
}
return true
}
func peek_char(r *bufio.Reader) (byte, bool) {
bytes, err := r.Peek(1)
if err != nil {
//eof
return ' ', true
}
return bytes[0], false
}
func read_char(r *bufio.Reader) (byte, bool) {
b, err := r.ReadByte()
if err != nil {
//eof
return ' ', true
}
return b, false
}
func read_whitespace(r *bufio.Reader) {
for {
b, eof := peek_char(r)
if eof {
return
}
if b != ' ' && b != '\t' && b != '\r' && b != '\n' {
return
}
read_char(r)
}
}
func peek_until(r *bufio.Reader, c byte) {
for {
b, eof := peek_char(r)
if eof {
return
}
if b == c {
return
}
read_char(r)
}
}
func read_until(r *bufio.Reader, c byte) {
for {
b, eof := read_char(r)
if eof {
return
}
if b == c {
return
}
}
}
func read_node_name(r *bufio.Reader) *string {
s := ""
for {
b, eof := peek_char(r)
if eof || b == '\t' || b == '\n' || b == '\r' || b == ' ' || b == ')' {
break
}
s += string(b)
read_char(r)
}
return &s
}
func read_string(r *bufio.Reader) *tree {
t := tree{nil, nil}
s := ""
for {
b, eof := peek_char(r)
if eof || b == '\t' || b == '\n' || b == '\r' || b == ' ' || b == ')' {
break
}
s += string(b)
read_char(r)
}
t.value = &s
return &t
}
func read_quoted_string(r *bufio.Reader) *tree {
t := tree{nil, nil}
s := ""
for {
b, eof := peek_char(r)
if eof || b == '"' {
break
}
s += string(b)
read_char(r)
}
t.value = &s
return &t
}
func read_tree(r *bufio.Reader) *tree {
read_until(r, '(')
read_whitespace(r)
t := tree{read_node_name(r), nil}
for {
read_whitespace(r)
b, eof := peek_char(r)
if eof {
break
}
if b == ')' {
read_char(r)
break
}
if b == '(' {
t.branches = append(t.branches, read_tree(r))
continue
}
if b == '"' {
read_char(r)
t.branches = append(t.branches, read_quoted_string(r))
read_char(r)
continue
}
t.branches = append(t.branches, read_string(r))
}
return &t
}
func search_tree(t *tree, s *string) *tree {
if t.value != nil {
if *t.value == *s {
return t
}
}
for _, ct := range t.branches {
st := search_tree(ct, s)
if st != nil {
return st
}
}
return nil
}
func print_tree(t *tree, indent int) {
if t.value != nil {
for i := 0; i < indent; i++ {
fmt.Print(" ")
}
fmt.Print(*t.value, "\n")
}
for _, ct := range t.branches {
print_tree(ct, indent+1)
}
}
func main() {
//command line flags and defaults etc
arg_infile := os.Stdin
var arg_b int
flag.IntVar(&arg_b, "b", 0, "border gap, default 0")
flag.Parse()
//input reader from default stdin or given file
if flag.NArg() > 0 {
//read access
file, err := os.Open(flag.Args()[0])
if err != nil {
os.Exit(1)
}
arg_infile = file
}
reader := bufio.NewReader(arg_infile)
//create tree from input
tree := read_tree(reader)
ss := "structure"
structure_root := search_tree(tree, &ss)
num_layers := 0
minx := 1000000.0
miny := 1000000.0
maxx := -1000000.0
maxy := -1000000.0
for _, structure_node := range structure_root.branches {
if *structure_node.value == "layer" {
num_layers++
}
if *structure_node.value == "boundary" {
for _, boundary_node := range structure_node.branches {
if *boundary_node.value == "path" {
cords := boundary_node.branches[2:]
for i := 0; i < len(cords); i += 2 {
px, _ := strconv.ParseFloat(*cords[i].value, 32)
py, _ := strconv.ParseFloat(*cords[i+1].value, 32)
px /= 1000.0
py /= -1000.0
if px < minx {
minx = px
}
if px > maxx {
maxx = px
}
if py < miny {
miny = py
}
if py > maxy {
maxy = py
}
}
}
}
}
}
ss = "library"
library_root := search_tree(tree, &ss)
component_map := map[string]*component{}
rule_map := map[string]*rule{}
for _, library_node := range library_root.branches {
if *library_node.value == "image" {
component_name := library_node.branches[0].value
component := component{component_name, map[string]*pin{}}
for _, image_node := range library_node.branches[1:] {
if *image_node.value == "pin" {
pin := pin{}
pin.form = image_node.branches[0].value
if *image_node.branches[1].value == "rotate" {
pin.angle, _ = strconv.ParseFloat(*image_node.branches[1].branches[0].value, 32)
pin.name = image_node.branches[2].value
pin.x, _ = strconv.ParseFloat(*image_node.branches[3].value, 32)
pin.y, _ = strconv.ParseFloat(*image_node.branches[4].value, 32)
pin.angle = pin.angle * (math.Pi / 180.0)
} else {
pin.angle = 0.0
pin.name = image_node.branches[1].value
pin.x, _ = strconv.ParseFloat(*image_node.branches[2].value, 32)
pin.y, _ = strconv.ParseFloat(*image_node.branches[3].value, 32)
}
pin.x /= 1000.0
pin.y /= -1000.0
component.pin_map[*pin.name] = &pin
}
}
component_map[*component_name] = &component
}
if *library_node.value == "padstack" {
for _, padstack_node := range library_node.branches[1:] {
if *padstack_node.value == "shape" {
points := []point{}
rule := rule{0.5, 0.125, nil}
if *padstack_node.branches[0].value == "circle" {
rule.radius, _ = strconv.ParseFloat(*padstack_node.branches[0].branches[1].value, 32)
rule.radius /= 2000.0
}
if *padstack_node.branches[0].value == "path" {
rule.radius, _ = strconv.ParseFloat(*padstack_node.branches[0].branches[1].value, 32)
rule.radius /= 2000.0
x1, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[2].value, 32)
y1, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[3].value, 32)
x2, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[4].value, 32)
y2, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[5].value, 32)
x1 /= 1000.0
y1 /= -1000.0
x2 /= 1000.0
y2 /= -1000.0
points = append(points, point{x1, y1})
points = append(points, point{x2, y2})
}
if *library_node.branches[1].branches[0].value == "rect" {
rule.radius = 0.0
x1, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[1].value, 32)
y1, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[2].value, 32)
x2, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[3].value, 32)
y2, _ := strconv.ParseFloat(*padstack_node.branches[0].branches[4].value, 32)
x1 /= 1000.0
y1 /= -1000.0
x2 /= 1000.0
y2 /= -1000.0
points = append(points, point{x1, y1})
points = append(points, point{x2, y1})
points = append(points, point{x2, y2})
points = append(points, point{x1, y2})
points = append(points, point{x1, y1})
}
rule.shape = &points
rule_map[*library_node.branches[0].value] = &rule
}
}
}
}
ss = "placement"
placement_root := search_tree(tree, &ss)
instance_map := map[string]*instance{}
for _, placement_node := range placement_root.branches {
if *placement_node.value == "component" {
component_name := placement_node.branches[0].value
for _, component_node := range placement_node.branches[1:] {
if *component_node.value == "place" {
instance := instance{}
instance_name := component_node.branches[0].value
instance.name = instance_name
instance.comp = component_name
instance.x, _ = strconv.ParseFloat(*component_node.branches[1].value, 32)
instance.y, _ = strconv.ParseFloat(*component_node.branches[2].value, 32)
instance.side = component_node.branches[3].value
instance.angle, _ = strconv.ParseFloat(*component_node.branches[4].value, 32)
instance.angle = instance.angle * (math.Pi / 180.0)
instance.x /= 1000.0
instance.y /= -1000.0
instance_map[*instance_name] = &instance
}
}
}
}
all_terminals := router.Terminals{}
for _, instance := range instance_map {
component := component_map[*instance.comp]
for _, pin := range component.pin_map {
x := pin.x
y := pin.y
if *instance.side != "front" {
x = -x
}
s := math.Sin(instance.angle)
c := math.Cos(instance.angle)
px := (c*x - s*y) + instance.x
py := (s*x + c*y) + instance.y
pin_rule := rule_map[*pin.form]
tp := router.Tpoint{float32(px), float32(py), 0.0}
cords := shape_to_cords(pin_rule.shape, pin.angle, instance.angle)
all_terminals = append(all_terminals, &router.Terminal{float32(pin_rule.radius), float32(pin_rule.gap), tp, *cords})
if px < minx {
minx = px
}
if px > maxx {
maxx = px
}
if py < miny {
miny = py
}
if py > maxy {
maxy = py
}
}
}
ss = "network"
network_root := search_tree(tree, &ss)
circuit_map := map[string]*circuit{}
for _, network_node := range network_root.branches {
if *network_node.value == "class" {
net_rule := rule{0.125, 0.125, nil}
circuit := circuit{nil, &net_rule}
for _, class_node := range network_node.branches {
if *class_node.value == "rule" {
for _, dims := range class_node.branches {
if *dims.value == "width" {
net_rule.radius, _ = strconv.ParseFloat(*dims.branches[0].value, 32)
net_rule.radius /= 2000.0
}
if *dims.value == "clearance" {
net_rule.gap, _ = strconv.ParseFloat(*dims.branches[0].value, 32)
net_rule.gap /= 2000.0
}
}
}
if *class_node.value == "circuit" {
for _, circuit_node := range class_node.branches {
if *circuit_node.value == "use_via" {
circuit.via = circuit_node.branches[0].value
}
}
}
}
for _, netname := range network_node.branches {
if netname.branches == nil {
circuit_map[*netname.value] = &circuit
}
}
}
}
tracks := make([]router.Track, 0)
for _, network_node := range network_root.branches {
if *network_node.value == "net" {
terminals := router.Terminals{}
for _, pin := range network_node.branches[1].branches {
pin_info := strings.Split(*pin.value, "-")
instance_name := pin_info[0]
pin_name := pin_info[1]
instance := instance_map[instance_name]
component := component_map[*instance.comp]
pin := component.pin_map[pin_name]
x := pin.x
y := pin.y
if *instance.side != "front" {
x = -x
}
s := math.Sin(instance.angle)
c := math.Cos(instance.angle)
px := (c*x - s*y) + instance.x
py := (s*x + c*y) + instance.y
pin_rule := rule_map[*pin.form]
tp := router.Tpoint{float32(px), float32(py), 0.0}
cords := shape_to_cords(pin_rule.shape, pin.angle, instance.angle)
term := router.Terminal{float32(pin_rule.radius), float32(pin_rule.gap), tp, *cords}
terminals = append(terminals, &term)
for i, t := range all_terminals {
if term_equal(t, &term) {
all_terminals = append(all_terminals[:i], all_terminals[i+1:]...)
break
}
}
}
circuit := circuit_map[*network_node.branches[0].value]
net_rule := circuit.rule
via_rule := rule_map[*circuit.via]
tracks = append(tracks, router.Track{float32(net_rule.radius), float32(via_rule.radius), float32(net_rule.gap), terminals})
}
}
tracks = append(tracks, router.Track{0.0, 0.0, 0.0, all_terminals})
border := float64(arg_b)
fmt.Print("[", int(maxx-minx+(border*2)+0.5), ",", int(maxy-miny+(border*2)+0.5), ",", num_layers, "]\n")
for _, track := range tracks {
fmt.Print("[", track.Radius, ",", track.Via, ",", track.Gap, ",[")
for i, term := range track.Terms {
fmt.Print("(", term.Radius, ",", term.Gap, ",(", term.Term.X-float32(minx-border), ",",
term.Term.Y-float32(miny-border), ",", term.Term.Z, "),[")
for j, cord := range term.Shape {
fmt.Print("(", cord.X, ",", cord.Y, ")")
if j != (len(term.Shape) - 1) {
fmt.Print(",")
}
}
fmt.Print("])")
if i != (len(track.Terms) - 1) {
fmt.Print(",")
}
}
fmt.Println("]]")
}
}