From 91ba5fd1d37a2aee5147585875fc4b49ad15e61e Mon Sep 17 00:00:00 2001 From: Stefan Frederik Date: Sun, 16 Oct 2022 13:08:52 +0200 Subject: [PATCH] annotation of voltage and currents in (nested) LCC instances --- src/get_malloc_id.awk | 3 +- src/save.c | 51 ++++++++++++-- src/token.c | 86 +++++++++++++++++++++-- xschem_library/examples/LCC_instances.sch | 18 +++-- xschem_library/examples/bus_keeper.sch | 26 +++---- xschem_library/examples/cmos_inv.sch | 45 ++++++++---- 6 files changed, 187 insertions(+), 42 deletions(-) diff --git a/src/get_malloc_id.awk b/src/get_malloc_id.awk index 8a99d702..d7da08fc 100755 --- a/src/get_malloc_id.awk +++ b/src/get_malloc_id.awk @@ -52,7 +52,7 @@ xinit.c \ | sort -n \ | awk '{ if(n>0 && $1 <= prev) print ">>>>>>>>>>> ERROR >>>>>>>>> " $0 - else if(n++>0 && $1 != prev+1) { + else if(n>0 && $1 != prev+1) { if($1-1 > prev+1) print ">>>>>>>>>>> FREE >>>>>>>>> " prev+1 ":" $1-1 else @@ -60,6 +60,7 @@ xinit.c \ print } else print + n++ prev = $1 } END{ diff --git a/src/save.c b/src/save.c index b78bea56..2908121d 100644 --- a/src/save.c +++ b/src/save.c @@ -2784,7 +2784,7 @@ int load_sym_def(const char *name, FILE *embed_fd) symbols = xctx->symbols; dbg(1, "l_s_d(): recursion_counter=%d, name=%s\n", recursion_counter, name); recursion_counter++; - dbg(1, "l_s_d(): name=%s\n", name); + dbg(1, "l_s_d(): loading name=%s\n", name); lcc=NULL; my_realloc(647, &lcc, (level + 1) * sizeof(Lcc)); max_level = level + 1; @@ -3068,7 +3068,7 @@ int load_sym_def(const char *name, FILE *embed_fd) tt[i].txt_ptr=NULL; tt[i].font=NULL; load_ascii_string(&tt[i].txt_ptr, lcc[level].fd); - dbg(1, "l_s_d(): txt1: tt[i].txt_ptr=%s, i=%d\n", tt[i].txt_ptr, i); + dbg(1, "l_s_d(): txt1: level=%d tt[i].txt_ptr=%s, i=%d\n", level, tt[i].txt_ptr, i); if(fscanf(lcc[level].fd, "%lf %lf %hd %hd %lf %lf ",&tt[i].x0, &tt[i].y0, &tt[i].rot, &tt[i].flip, &tt[i].xscale, &tt[i].yscale) < 6 ) { fprintf(errfp,"l_s_d(): WARNING: missing fields for Text object, ignoring\n"); @@ -3081,6 +3081,49 @@ int load_sym_def(const char *name, FILE *embed_fd) rot = lcc[level].rot; flip = lcc[level].flip; if (tmp) my_strdup(651, &tt[i].txt_ptr, tmp); dbg(1, "l_s_d(): txt3: tt[i].txt_ptr=%s, i=%d\n", tt[i].txt_ptr, i); + /* allow annotation inside LCC instances. */ + if(tt[i].txt_ptr && !strcmp(tt[i].txt_ptr, "@spice_get_voltage")) { + /* prop_ptr is the attribute string of last loaded LCC component */ + const char *lab; + size_t new_size = 0; + char *path = NULL; + if(level > 1) { /* add parent LCC instance names (X1, Xinv etc) */ + int i; + for(i = 1; i tok_size + 21; /* @spice_get_voltage() */ + my_realloc(1587, &tt[i].txt_ptr, new_size); + my_snprintf(tt[i].txt_ptr, new_size, "@spice_get_voltage(%s%s)", path ? path : "", lab); + my_free(1589, &path); + dbg(1, " --> tt[i].txt_ptr=%s\n", tt[i].txt_ptr); + } + if(tt[i].txt_ptr && !strcmp(tt[i].txt_ptr, "@spice_get_current")) { + /* prop_ptr is the attribute string of last loaded LCC component */ + const char *dev; + size_t new_size = 0; + char *path = NULL; + if(level > 1) { /* add parent LCC instance names (X1, Xinv etc) */ + int i; + for(i = 1; i tok_size + 21; /* @spice_get_current() */ + my_realloc(1587, &tt[i].txt_ptr, new_size); + my_snprintf(tt[i].txt_ptr, new_size, "@spice_get_current(%s%s)", path ? path : "", dev); + my_free(1589, &path); + dbg(1, " --> tt[i].txt_ptr=%s\n", tt[i].txt_ptr); + } ROTATION(rot, flip, 0.0, 0.0, tt[i].x0, tt[i].y0, rx1, ry1); tt[i].x0 = lcc[level].x0 + rx1; tt[i].y0 = lcc[level].y0 + ry1; tt[i].rot = (tt[i].rot + ((lcc[level].flip && (tt[i].rot & 1)) ? @@ -3143,13 +3186,13 @@ int load_sym_def(const char *name, FILE *embed_fd) break; case 'C': load_ascii_string(&symname, lcc[level].fd); - dbg(1, "l_s_d(): C line: symname=%s\n", symname); if (fscanf(lcc[level].fd, "%lf %lf %hd %hd", &inst_x0, &inst_y0, &inst_rot, &inst_flip) < 4) { fprintf(errfp, "l_s_d(): WARNING: missing fields for COMPONENT object, ignoring\n"); read_line(lcc[level].fd, 0); continue; } load_ascii_string(&prop_ptr, lcc[level].fd); + dbg(1, "l_s_d() component: level=%d, sym=%s, prop_ptr = %s\n", level, symname, prop_ptr); if(level + 1 >=CADMAXHIER) { fprintf(errfp, "l_s_d(): Symbol recursively instantiating symbol: max depth reached, skipping\n"); if(has_x) tcleval("alert_ {xSymbol recursively instantiating symbol: max depth reached, skipping} {} 1"); @@ -3274,7 +3317,7 @@ int load_sym_def(const char *name, FILE *embed_fd) if( tag[0] == '{' ) ungetc(tag[0], lcc[level].fd); read_record(tag[0], lcc[level].fd, 0); break; - } + } /* switch(tag[0]) */ /* if a 'C' line was encountered and level was incremented, rest of line must be read with lcc[level-1].fd file pointer */ if(incremented_level) diff --git a/src/token.c b/src/token.c index 12480e23..00366e2b 100644 --- a/src/token.c +++ b/src/token.c @@ -3017,11 +3017,12 @@ const char *translate(int inst, const char* s) if(pin_prop_ptr) net = get_tok_value(pin_prop_ptr, "lab", 0); if(net == NULL || net[0] == '\0') net = net_name(inst,0, &multip, 0, 0); len = strlen(path) + strlen(net) + 1; - dbg(1, "net=%s\n", net); + dbg(1, "translate() @spice_get_voltage: inst=%s\n", xctx->inst[inst].instname); + dbg(1, " net=%s, pin_prop_ptr=%s\n", net, pin_prop_ptr); fqnet = my_malloc(1573, len); my_snprintf(fqnet, len, "%s%s", path, net); strtolower(fqnet); - dbg(1, "translate(): fqnet=%s start_level=%d\n", fqnet, start_level); + dbg(1, "translate() @spice_get_voltage: fqnet=%s start_level=%d\n", fqnet, start_level); idx = get_raw_index(fqnet); if(idx >= 0) { val = xctx->graph_values[idx][xctx->graph_annotate_p]; @@ -3069,12 +3070,12 @@ const char *translate(int inst, const char* s) n = sscanf(token + 19, "%[^)]", net); if(n == 1) { strtolower(net); - len = strlen(path) + strlen(net) + 1; + len = strlen(path) + strlen(xctx->inst[inst].instname) + strlen(net) + 2; dbg(1, "net=%s\n", net); fqnet = my_malloc(1548, len); - my_snprintf(fqnet, len, "%s%s", path, net); + my_snprintf(fqnet, len, "%s%s.%s", path, xctx->inst[inst].instname, net); strtolower(fqnet); - dbg(1, "translate(): fqnet=%s start_level=%d\n", fqnet, start_level); + dbg(1, "translate(): net=%s, fqnet=%s start_level=%d\n", net, fqnet, start_level); idx = get_raw_index(fqnet); if(idx >= 0) { val = xctx->graph_values[idx][xctx->graph_annotate_p]; @@ -3099,6 +3100,75 @@ const char *translate(int inst, const char* s) } } } + else if(strncmp(token,"@spice_get_current(", 19)==0 ) + { + int start_level; /* hierarchy level where waves were loaded */ + if((start_level = sch_waves_loaded()) >= 0 && xctx->graph_annotate_p>=0) { + char *fqdev = NULL; + const char *path = xctx->sch_path[xctx->currsch] + 1; + char *dev = NULL; + size_t len; + int idx, n; + double val; + const char *valstr; + tmp = strlen(token) + 1; + if(path) { + int skip = 0; + /* skip path components that are above the level where raw file was loaded */ + while(*path && skip < start_level) { + if(*path == '.') skip++; + path++; + } + dev = my_malloc(1550, tmp); + n = sscanf(token + 19, "%[^)]", dev); + if(n == 1) { + strtolower(dev); + len = strlen(path) + strlen(xctx->inst[inst].instname) + + strlen(dev) + 11; /* some extra chars for i(..) wrapper */ + dbg(1, "dev=%s\n", dev); + fqdev = my_malloc(1556, len); + if(!sim_is_xyce) { + int prefix, vsource; + char *ptr = dev; + char *prefix_ptr = dev; + while(*ptr) { /* since dev is something like X1.X2.V2 find last . before V */ + if(*ptr == '.') prefix_ptr = ptr + 1; + ptr++; + } + prefix = prefix_ptr[0]; /* character after last '.' */ + dbg(1, "prefix=%c, path=%s\n", prefix, path); + vsource = (prefix == 'v') || (prefix == 'e'); + if(vsource) my_snprintf(fqdev, len, "i(%c.%s%s.%s)", prefix, path, xctx->inst[inst].instname, dev); + else my_snprintf(fqdev, len, "i(@%c.%s%s.%s)", prefix, path, xctx->inst[inst].instname, dev); + } else { + my_snprintf(fqdev, len, "i(%s%s.%s)", path, xctx->inst[inst].instname, dev); + } + strtolower(fqdev); + dbg(1, "fqdev=%s\n", fqdev); + idx = get_raw_index(fqdev); + if(idx >= 0) { + val = xctx->graph_values[idx][xctx->graph_annotate_p]; + } + if(idx < 0) { + valstr = ""; + xctx->tok_size = 0; + len = 0; + } else { + valstr = dtoa_eng(val); + len = xctx->tok_size; + } + if(len) { + STR_ALLOC(&result, len + result_pos, &size); + memcpy(result+result_pos, valstr, len+1); + result_pos += len; + } + dbg(1, "inst %d, dev=%s, fqdev=%s idx=%d valstr=%s\n", inst, dev, fqdev, idx, valstr); + my_free(1557, &fqdev); + } /* if(n == 1) */ + my_free(1551, &dev); + } /* if(path) */ + } /* if((start_level = sch_waves_loaded()) >= 0 && xctx->graph_annotate_p>=0) */ + } else if(strcmp(token,"@spice_get_diff_voltage")==0 ) { int start_level; /* hierarchy level where waves were loaded */ @@ -3412,6 +3482,12 @@ const char *translate2(Lcc *lcc, int level, char* s) memcpy(result + result_pos, token, tmp + 1); result_pos += tmp; } + else if (strncmp(token, "@spice_get_current", 18) == 0) { /* return unchanged */ + tmp = strlen(token); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result + result_pos, token, tmp + 1); + result_pos += tmp; + } else if (strcmp(token, "@symname") == 0) { tmp_sym_name = lcc[level].symname ? get_cell(lcc[level].symname, 0) : ""; tmp = strlen(tmp_sym_name); diff --git a/xschem_library/examples/LCC_instances.sch b/xschem_library/examples/LCC_instances.sch index fd6ac47c..bd08b3f4 100644 --- a/xschem_library/examples/LCC_instances.sch +++ b/xschem_library/examples/LCC_instances.sch @@ -34,7 +34,7 @@ zzz" color="4 6 8" sweep="v(a)" dataset=-1} -B 2 10 -930 570 -700 {flags=graph +B 2 10 -950 570 -720 {flags=graph y1 = 0 y2 = 3 divy = 6 @@ -58,7 +58,7 @@ T {LCC schematics can be nested If only .sch is used there is no need for a .sym file at all} 840 -880 0 0 0.6 0.6 {} T {Select one or more graphs (and no other objects) -and use arrow keys to zoom / pan waveforms} 20 -980 0 0 0.3 0.3 {} +and use arrow keys to zoom / pan waveforms} 20 -1000 0 0 0.3 0.3 {} T {Butterfly diagram of a cmos latch} 620 -950 0 0 0.4 0.4 {layer=8} N 410 -100 410 -80 {lab=HALF} @@ -67,12 +67,15 @@ N 410 -190 410 -160 {lab=ZZZ} N 420 -400 420 -380 {lab=HALF} N 420 -490 700 -490 {lab=ZZ} N 420 -490 420 -460 {lab=ZZ} -N 700 -490 700 -240 {lab=ZZ} -N 700 -240 1450 -240 {lab=ZZ} +N 700 -240 1450 -240 {lab=#net1} N 320 -190 410 -190 {lab=ZZZ} N 330 -490 420 -490 {lab=ZZ} N 730 -860 730 -770 { lab=Z} N 650 -860 650 -770 { lab=A} +N 700 -320 700 -240 { +lab=#net1} +N 700 -490 700 -380 { +lab=ZZ} C {vsource.sym} 50 -140 0 0 {name=V1 value="pwl 0 0 1u 0 5u 3"} C {lab_pin.sym} 50 -170 0 0 {name=p4 lab=A} C {lab_pin.sym} 50 -110 0 0 {name=p5 lab=0} @@ -158,7 +161,7 @@ C {lab_pin.sym} 410 -80 0 0 {name=p10 lab=HALF} C {vsource.sym} 50 -340 0 0 {name=V3 value=1.5} C {lab_pin.sym} 50 -370 0 0 {name=p11 lab=HALF} C {lab_pin.sym} 50 -310 0 0 {name=p12 lab=0} -C {lab_pin.sym} 200 -490 0 0 {name=p13 lab=A} +C {lab_pin.sym} 120 -490 0 0 {name=p13 lab=A} C {res.sym} 420 -430 0 0 {name=R2 value=20k footprint=1206 @@ -166,7 +169,7 @@ device=resistor m=1} C {lab_pin.sym} 420 -380 0 0 {name=p15 lab=HALF} C {title.sym} 160 -30 0 0 {name=l1 author="Stefan Schippers"} -C {cmos_inv.sch} 140 -260 0 0 {name=Xinv WN=15u WP=45u LLN=3u LLP=3u} +C {cmos_inv.sch} 60 -260 0 0 {name=Xinv WN=15u WP=45u LLN=3u LLP=3u} C {cmos_inv.sym} 280 -190 0 0 {name=Xinv2 WN=15u WP=45u LLN=3u LLP=3u} C {bus_keeper.sch} 1200 60 0 0 {name=Xkeeper WN_FB=3u WP_FB=5u} C {lab_pin.sym} 700 -490 0 1 {name=p1 lab=ZZ} @@ -174,10 +177,11 @@ C {lab_pin.sym} 650 -770 0 0 {name=p14 lab=A} C {cmos_inv.sym} 690 -860 0 1 {name=Xinv3 WN=3u WP=5u LLN=3u LLP=3u} C {lab_pin.sym} 730 -770 0 1 {name=p2 lab=Z} C {cmos_inv.sym} 690 -770 0 0 {name=Xinv1 WN=3u WP=5u LLN=3u LLP=3u} -C {launcher.sym} 85 -1015 0 0 {name=h1 +C {launcher.sym} 85 -1035 0 0 {name=h1 descr="Select arrow and Ctrl-Left-Click to load/unload waveforms" tclcommand=" xschem raw_read $netlist_dir/[file tail [file rootname [xschem get current_name]]].raw " } +C {ammeter.sym} 700 -350 0 1 {name=Vmeas} diff --git a/xschem_library/examples/bus_keeper.sch b/xschem_library/examples/bus_keeper.sch index 38261809..3596b259 100644 --- a/xschem_library/examples/bus_keeper.sch +++ b/xschem_library/examples/bus_keeper.sch @@ -1,4 +1,5 @@ -v {xschem version=3.0.0 file_version=1.2 } +v {xschem version=3.1.0 file_version=1.2 +} G {} K {type=subcircuit format="@name @pinlist @symname WN_FB=@WN_FB WP_FB=@WP_FB" @@ -6,23 +7,24 @@ template="name=X1 WN_FB=1u WP_FB=2u"} V {} S {} E {} -P 2 5 250 -880 250 -120 480 -120 480 -880 250 -880 {dash=5} -T {@name} 250 -915 0 0 0.5 0.5 {} +P 2 5 250 -930 250 -120 610 -120 610 -930 250 -930 {dash=5} +T {@name} 250 -965 0 0 0.5 0.5 {} T {@symname} 253.75 -115 0 0 0.5 0.5 {} N 250 -300 300 -300 {lab=A} -N 280 -680 300 -680 {lab=A} -N 280 -680 280 -300 {lab=A} -N 430 -300 450 -300 {lab=#net1} -N 450 -680 450 -300 {lab=#net1} -N 430 -680 450 -680 {lab=#net1} -N 350 -500 390 -500 { lab=GND} +N 280 -690 300 -690 {lab=A} +N 280 -690 280 -300 {lab=A} +N 510 -300 550 -300 {lab=Y} +N 550 -690 550 -300 {lab=Y} +N 510 -690 550 -690 {lab=Y} +N 550 -240 550 -200 { lab=GND} C {cmos_inv.sch} 240 -70 0 0 {name=X2 WN=15u WP=45u LLN=3u LLP=3u} -C {cmos_inv.sch} 490 -450 0 1 {name=X1 WN=WN_FB WP=WP_FB LLN=3u LLP=3u} +C {cmos_inv.sch} 570 -460 0 1 {name=X1 WN=WN_FB WP=WP_FB LLN=3u LLP=3u} C {iopin.sym} 250 -300 0 1 {name=p1 lab=A} C {title.sym} 160 -30 0 0 {name=l1 author="Stefan Schippers"} -C {capa.sym} 420 -500 1 0 {name=C1 +C {capa.sym} 550 -270 0 0 {name=C1 m=1 value=10f footprint=1206 device="ceramic capacitor"} -C {gnd.sym} 350 -500 0 0 {name=l2 lab=GND} +C {gnd.sym} 550 -200 0 0 {name=l2 lab=0} +C {lab_pin.sym} 550 -550 0 0 {name=l3 sig_type=std_logic lab=Y} diff --git a/xschem_library/examples/cmos_inv.sch b/xschem_library/examples/cmos_inv.sch index 5e1fa800..9b3039f2 100644 --- a/xschem_library/examples/cmos_inv.sch +++ b/xschem_library/examples/cmos_inv.sch @@ -1,4 +1,5 @@ -v {xschem version=2.9.9 file_version=1.2 } +v {xschem version=3.1.0 file_version=1.2 +} G {} K {type=subcircuit function0="1 ~" @@ -8,22 +9,40 @@ template="name=X1 WN=15u WP=45u LLN=3u LLP=3u m=1" V {} S {} E {} -A 15 90 -350 14.14213562373095 135 360 {dash=2} -P 2 5 60 -390 190 -390 190 -90 60 -90 60 -390 {dash=5} -T {@name} 60 -405 0 0 0.2 0.2 {} +A 15 90 -410 14.14213562373095 135 360 {dash=2} +P 2 5 60 -450 270 -450 270 -90 60 -90 60 -450 {dash=5} +T {@name} 60 -465 0 0 0.2 0.2 {} T {@symname} 63.75 -85 0 0 0.2 0.2 {} -N 140 -260 140 -200 {lab=Z} -N 100 -290 100 -170 {lab=A} -N 60 -230 100 -230 {lab=A} -N 140 -230 190 -230 {lab=Z} -N 140 -340 140 -320 {lab=VDD} +N 80 -350 80 -170 {lab=A} +N 60 -230 80 -230 {lab=A} +N 140 -400 140 -380 {lab=VDD} N 140 -140 140 -120 {lab=0} -C {opin.sym} 190 -230 0 0 {name=p2 lab=Z} +N 240 -230 270 -230 { +lab=Z} +N 140 -230 180 -230 { +lab=D} +N 140 -320 140 -290 { +lab=#net1} +N 140 -230 140 -200 { +lab=D} +N 80 -350 100 -350 { +lab=A} +N 80 -170 100 -170 { +lab=A} +C {opin.sym} 270 -230 0 0 {name=p2 lab=Z} C {ipin.sym} 60 -230 0 0 {name=p1 lab=A goto=0} -C {vdd.sym} 140 -340 0 0 {name=l1 lab=VDD} +C {vdd.sym} 140 -400 0 0 {name=l1 lab=VDD} C {lab_pin.sym} 140 -120 0 0 {name=l2 sig_type=std_logic lab=0} -C {pmos4.sym} 120 -290 0 0 {name=M2 model=p w=WP l=LLP m=1 net_name=true} +C {pmos4.sym} 120 -350 0 0 {name=M2 model=p w=WP l=LLP m=1 net_name=true} C {nmos4.sym} 120 -170 0 0 {name=M1 model=n w=WN l=LLN m=1 net_name=true} C {lab_pin.sym} 140 -170 0 1 {name=l3 sig_type=std_logic lab=0} -C {lab_pin.sym} 140 -290 0 1 {name=l4 sig_type=std_logic lab=VDD} +C {lab_pin.sym} 140 -350 0 1 {name=l4 sig_type=std_logic lab=VDD} C {title.sym} 160 -30 0 0 {name=l5 author="Stefan Schippers"} +C {res.sym} 210 -230 1 0 {name=R1 +value=1k +footprint=1206 +device=resistor +m=1} +C {lab_pin.sym} 140 -220 0 1 {name=l6 sig_type=std_logic lab=D} +C {lab_pin.sym} 80 -320 0 1 {name=l7 sig_type=std_logic lab=A} +C {ammeter.sym} 140 -260 0 0 {name=V1}