From 8d155af82ff1221d9b2dde2f2b1a8b77034c3073 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Mon, 20 Nov 2023 17:53:28 +0100 Subject: [PATCH] `Alt-e` does a true descend sub-schematic and opens it in another window --- doc/xschem_man/developer_info.html | 35 ++++++++++------ src/actions.c | 41 +++++++++++++++---- src/callback.c | 5 ++- src/scheduler.c | 61 +++++++++++++++++++++++----- src/xinit.c | 16 ++++++-- src/xschem.h | 6 ++- src/xschem.tcl | 31 +++++++++++++- xschem_library/examples/poweramp.sch | 6 +-- 8 files changed, 158 insertions(+), 43 deletions(-) diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index dca9d276..b0d5f73f 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -510,16 +510,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" - - - - - - - - - - @@ -596,6 +586,9 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" if '3' argument is given combine '1' and '2'
  • copy
  •     Copy selection to clipboard 
    +
  • copy_hierarchy to from
  • +   Copy hierarchy info from tab/window "from" to tab/window "to"
    +   Example: xschem copy_hierarchy .drw .x1.drw 
  • copy_objects [deltax deltay [rot flip]]
  •     if deltax and deltay (and optionally rot and flip) are given copy selection
        to specified offset, otherwise start a GUI copy operation 
    @@ -699,6 +692,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
  • header_text header metadata (license info etc) present in schematic
  • infowindow_text ERC messages
  • instances number of instances in schematic
  • +
  • last_created_window return win_path of last created tab or window
  • lastsel number of selected objects
  • line_width get line width
  • lines (xschem get lines n) number of lines on layer 'n'
  • @@ -783,6 +777,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" ('inst' can be an instance name or instance number) ('pin' can be a pin name or pin number) +
  • get_sch_from_sym inst
  • +   get schematic associated with instance 'inst' 
  • get_tok str tok [with_quotes]
  •     get value of token 'tok' in string 'str'
        'with_quotes' (default:0) is an integer passed to get_tok_value() 
    @@ -1052,7 +1048,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" what = read | clear | info | switch | switch_back Load /clear / switch additional raw files
  • raw_clear
  • -   Delete loaded simulation raw file 
    + Unload all simulation raw files
  • raw_query loaded|value|index|values|datasets|vars|list
  •     xschem raw_query list: get list of saved simulation variables
        xschem raw_query vars: get number of simulation variables
    @@ -1140,13 +1136,14 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
        List a 2-item list of all pins  and directions of current schematic
        Example: xschem sch_pinlist
        -->  {PLUS} {in} {OUT} {out} {MINUS} {in} {VCC} {inout} {VSS} {inout}
    -
  • schematic_in_new_window [new_process] [nodraw]
  • +   
  • schematic_in_new_window [new_process] [nodraw] [force]
  •     When a symbol is selected edit corresponding schematic
        in a new tab/window if not already open.
        If nothing selected open another window of the second
        schematic (issues a warning).
        if 'new_process' is given start a new xschem process
    -   if 'nodraw' is given do not draw loaded schematic 
    + if 'nodraw' is given do not draw loaded schematic + returns '1' if a new schematic was opened, 0 otherwise
  • search regex|exact select tok val [match_case]
  •     Search instances / wires / rects / texts with attribute string containing 'tok'
        and value 'val'
    @@ -1422,6 +1419,18 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
     
     
     
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
     
     
     
    diff --git a/src/actions.c b/src/actions.c
    index 9ac3f44c..87408686 100644
    --- a/src/actions.c
    +++ b/src/actions.c
    @@ -1573,8 +1573,11 @@ void symbol_in_new_window(int new_process)
       }
     }
     
    -void copy_hierarchy_data(Xschem_ctx *from, Xschem_ctx *to)
    +int copy_hierarchy_data(const char *from_win_path, const char *to_win_path)
     {
    +  int n;
    +  Xschem_ctx **save_xctx;
    +  Xschem_ctx *from, *to;
       char **sch;
       char **sch_path;
       int *sch_path_hash;
    @@ -1585,7 +1588,18 @@ void copy_hierarchy_data(Xschem_ctx *from, Xschem_ctx *to)
       int i, j;
       Str_hashentry **fromnext;
       Str_hashentry **tonext;
    +
       
    +  if(!get_window_count()) { return 0; }
    +  save_xctx = get_save_xctx();
    +  n = get_tab_or_window_number(from_win_path);
    +  if(n >= 0) {
    +    from = save_xctx[n];
    +  } else return 0;
    +  n = get_tab_or_window_number(to_win_path);
    +  if(n >= 0) {
    +    to = save_xctx[n];
    +  } else return 0;
       sch = from->sch;
       sch_path = from->sch_path;
       sch_path_hash = from->sch_path_hash;
    @@ -1629,21 +1643,29 @@ void copy_hierarchy_data(Xschem_ctx *from, Xschem_ctx *to)
           }
         }
       }
    +  return 1;
     }
     
    - /*  20111007 duplicate current schematic if no inst selected */
    -void schematic_in_new_window(int new_process, int dr)
    +/*  20111007 duplicate current schematic if no inst selected */
    +/* if force set to 1 force opening another new schematic even if already open */
    +int schematic_in_new_window(int new_process, int dr, int force)
     {
       char filename[PATH_MAX];
       char win_path[WINDOW_PATH_SIZE];
       rebuild_selected_array();
    -  if(xctx->lastsel !=1 || xctx->sel_array[0].type!=ELEMENT) {
    +  if(xctx->lastsel == 0) {
         if(new_process) new_xschem_process(xctx->sch[xctx->currsch], 0);
    -    else new_schematic("create", "noalert", xctx->sch[xctx->currsch], dr);
    +    else new_schematic("create", force ? "noalert" : "", xctx->sch[xctx->currsch], dr);
    +    return 1;
       }
    -  else {
    +  else if(xctx->lastsel > 1) {
    +    return 0;
    +  }
    +  else { /* xctx->lastsel == 1 */
    +    if(xctx->inst[xctx->sel_array[0].n].ptr < 0 ) return 0;
    +    if(!(xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->type) return 0;
    +    if(xctx->sel_array[0].type != ELEMENT) return 0;
         if(                   /*  do not descend if not subcircuit */
    -       (xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->type &&
            strcmp(
               (xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->type,
                "subcircuit"
    @@ -1652,13 +1674,14 @@ void schematic_in_new_window(int new_process, int dr)
               (xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym)->type,
                "primitive"
            )
    -    ) return;
    +    ) return 0;
         get_sch_from_sym(filename, xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym, xctx->sel_array[0].n);
    -    if(!check_loaded(filename, win_path)) {
    +    if(force || !check_loaded(filename, win_path)) {
           if(new_process) new_xschem_process(filename, 0);
           else new_schematic("create", "noalert", filename, dr);
         }
       }
    +  return 1;
     }
     
     void launcher(void)
    diff --git a/src/callback.c b/src/callback.c
    index 464bd498..b68bf3f2 100644
    --- a/src/callback.c
    +++ b/src/callback.c
    @@ -1838,7 +1838,8 @@ int rstate; /* (reduced state, without ShiftMask) */
        {
         int save = xctx->semaphore;
         xctx->semaphore--; /* so semaphore for current context wll be saved correctly */
    -    schematic_in_new_window(0, 1);
    +    /*  schematic_in_new_window(0, 1, 0); */
    +    tcleval("open_sub_schematic");
         xctx->semaphore = save;
         break;
        }
    @@ -1847,7 +1848,7 @@ int rstate; /* (reduced state, without ShiftMask) */
        { 
         int save = xctx->semaphore;
         xctx->semaphore--; /* so semaphore for current context wll be saved correctly */
    -    schematic_in_new_window(1, 1);
    +    schematic_in_new_window(1, 1, 0);
         xctx->semaphore = save;
         break;
        }
    diff --git a/src/scheduler.c b/src/scheduler.c
    index 9ec21b2b..17aafc18 100644
    --- a/src/scheduler.c
    +++ b/src/scheduler.c
    @@ -547,6 +547,20 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           Tcl_ResetResult(interp);
         }
     
    +    
    +    /* copy_hierarchy to from
    +     *   Copy hierarchy info from tab/window "from" to tab/window "to"
    +     *   Example: xschem copy_hierarchy .drw .x1.drw */
    +    else if(!strcmp(argv[1], "copy_hierarchy"))
    +    { 
    +      int ret = 0;
    +      if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
    +      if(argc > 3) {
    +        ret = copy_hierarchy_data(argv[2], argv[3]);
    +      }
    +      Tcl_SetResult(interp, my_itoa(ret), TCL_VOLATILE);
    +    }
    +
         /* copy_objects [deltax deltay [rot flip]]
          *   if deltax and deltay (and optionally rot and flip) are given copy selection
          *   to specified offset, otherwise start a GUI copy operation */
    @@ -1088,7 +1102,10 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
               }
               break;
               case 'l':
    -          if(!strcmp(argv[2], "lastsel")) { /* number of selected objects */
    +          if(!strcmp(argv[2], "last_created_window")) { /* return win_path of last created tab or window */
    +            Tcl_SetResult(interp, get_last_created_window(), TCL_VOLATILE);
    +          }
    +          else if(!strcmp(argv[2], "lastsel")) { /* number of selected objects */
                 if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
                 rebuild_selected_array();
                 Tcl_SetResult(interp, my_itoa(xctx->lastsel),TCL_VOLATILE);
    @@ -1561,6 +1578,27 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           }
         }
         
    +    /* get_sch_from_sym inst
    +     *   get schematic associated with instance 'inst' */
    +    else if(!strcmp(argv[1], "get_sch_from_sym") )
    +    {
    +      int inst = -1;
    +      char filename[PATH_MAX];
    +      my_strncpy(filename,  "", S(filename));
    +      if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
    +      if(argc > 2) {
    +        if((inst = get_instance(argv[2])) < 0 ) {
    +          Tcl_SetResult(interp, "xschem get_sch_from_sym: instance not found", TCL_STATIC);
    +          return TCL_ERROR;
    +        } else {
    +          if( xctx->inst[inst].ptr >= 0 ) {
    +            get_sch_from_sym(filename, xctx->inst[inst].ptr+ xctx->sym, inst);
    +          }
    +        }
    +      }
    +      Tcl_SetResult(interp, filename, TCL_VOLATILE);
    +    }
    +
         /* get_tok str tok [with_quotes]
          *   get value of token 'tok' in string 'str'
          *   'with_quotes' (default:0) is an integer passed to get_tok_value() */
    @@ -3197,12 +3235,12 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
         }
     
         /* raw_clear 
    -     *   Delete loaded simulation raw file */
    +     *   Unload all simulation raw files */
         else if(!strcmp(argv[1], "raw_clear"))
         {
           if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
    -      extra_rawfile(3, NULL, NULL);
    -      free_rawfile(&xctx->raw, 1);
    +      extra_rawfile(3, NULL, NULL); /* unload additional raw files */
    +      free_rawfile(&xctx->raw, 1); /* unload base (current) raw file */
           Tcl_ResetResult(interp);
         }
     
    @@ -3762,25 +3800,29 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
           }
         }
     
    -    /* schematic_in_new_window [new_process] [nodraw]
    +    /* schematic_in_new_window [new_process] [nodraw] [force]
          *   When a symbol is selected edit corresponding schematic
          *   in a new tab/window if not already open.
          *   If nothing selected open another window of the second
          *   schematic (issues a warning).
          *   if 'new_process' is given start a new xschem process
    -     *   if 'nodraw' is given do not draw loaded schematic */
    +     *   if 'nodraw' is given do not draw loaded schematic
    +     *   returns '1' if a new schematic was opened, 0 otherwise */
         else if(!strcmp(argv[1], "schematic_in_new_window"))
         {
    +      int res = 0;
           int new_process = 0;
           int nodraw = 0;
    +      int force = 0;
           int i;
           if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
           for(i = 2; i < argc; i++) {
             if(!strcmp(argv[i], "new_process")) new_process = 1;
             if(!strcmp(argv[i], "nodraw")) nodraw = 1;
    +        if(!strcmp(argv[i], "force")) force = 1;
           }
    -      schematic_in_new_window(new_process, !nodraw);
    -      Tcl_ResetResult(interp);
    +      res = schematic_in_new_window(new_process, !nodraw, force);
    +      Tcl_SetResult(interp, my_itoa(res), TCL_VOLATILE);
         }
     
         /* search regex|exact select tok val [match_case]
    @@ -4764,8 +4806,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
             del_object_table();
           }
           else if(argc > 2 && atoi(argv[2]) == 2) {
    -        Xschem_ctx **save_xctx = get_save_xctx();
    -        copy_hierarchy_data(save_xctx[0], save_xctx[1]);
    +        copy_hierarchy_data(".drw", ".x1.drw");
           }
           else if(argc > 2 && atoi(argv[2]) == 3) {
             Xschem_ctx **save_xctx = get_save_xctx();
    diff --git a/src/xinit.c b/src/xinit.c
    index e81e3a85..60714f77 100644
    --- a/src/xinit.c
    +++ b/src/xinit.c
    @@ -42,6 +42,7 @@ static Xschem_ctx *save_xctx[MAX_NEW_WINDOWS]; /* save pointer to current schema
     static char window_path[MAX_NEW_WINDOWS][WINDOW_PATH_SIZE];
     /* ==0 if no additional windows/tabs, ==1 if one additional window/tab, ... */
     static int window_count = 0;
    +static int last_created_window = -1;
     
     /* ----------------------------------------------------------------------- */
     /* EWMH message handling routines 20071027... borrowed from wmctrl code */
    @@ -94,6 +95,15 @@ char *get_window_path(int i)
       return window_path[i];
     }
     
    +char *get_last_created_window(void)
    +{
    +  if(last_created_window >= 0) {
    +    return window_path[last_created_window];
    +  } else {
    +    return "";
    +  }
    +}
    +
     int get_window_count(void)
     {
       return window_count;
    @@ -1204,7 +1214,7 @@ void preview_window(const char *what, const char *win_path, const char *fname)
     }
     
     
    -static int get_tab_or_window_number(const char *win_path)
    +int get_tab_or_window_number(const char *win_path)
     {
       int i, n = -1;
       Xschem_ctx *ctx, **save_xctx = get_save_xctx();
    @@ -1522,7 +1532,7 @@ static void create_new_window(int *window_count, const char *noconfirm, const ch
       n = -1;
       for(i = 1; i < MAX_NEW_WINDOWS; ++i) { /* search 1st free slot */
         if(save_xctx[i] == NULL) {
    -      n = i;
    +      last_created_window = n = i;
           break;
         }
       }
    @@ -1627,6 +1637,7 @@ static void create_new_tab(int *window_count, const char *noconfirm, const char
         dbg(0, "new_schematic(\"newtab\"...): no more free slots\n");
         return;
       }
    +  last_created_window = i;
       /* tcl code to create the tab button */
       my_snprintf(nn, S(nn), "%d", i);
       if(has_x) {
    @@ -1911,7 +1922,6 @@ static void destroy_all_tabs(int *window_count, int force)
     int new_schematic(const char *what, const char *win_path, const char *fname, int dr)
     {
       int tabbed_interface;
    -
       tabbed_interface = tclgetboolvar("tabbed_interface");
       dbg(1, "new_schematic(): current_win_path=%s, what=%s, win_path=%s\n", xctx->current_win_path, what, win_path);
       if(!strcmp(what, "ntabs")) {
    diff --git a/src/xschem.h b/src/xschem.h
    index 459e06ff..299d9fa4 100644
    --- a/src/xschem.h
    +++ b/src/xschem.h
    @@ -1260,8 +1260,8 @@ extern int  check_lib(int what, const char *s);
     extern int floaters_from_selected_inst();
     extern void select_all(void);
     extern void change_linewidth(double w);
    -extern void copy_hierarchy_data(Xschem_ctx *from, Xschem_ctx *to);
    -extern void schematic_in_new_window(int new_process, int dr);
    +extern int copy_hierarchy_data(const char *from_win_path, const char *to_win_path);
    +extern int schematic_in_new_window(int new_process, int dr, int force);
     extern void symbol_in_new_window(int new_process);
     extern void new_xschem_process(const char *cell, int symbol);
     extern void ask_new_file(void);
    @@ -1456,9 +1456,11 @@ extern void mem_delete_undo(void);
     extern void mem_clear_undo(void);
     extern void load_schematic(int load_symbol, const char *fname, int reset_undo, int alert);
     /* check if filename already in an open window/tab */
    +extern int get_tab_or_window_number(const char *win_path);
     extern void swap_tabs(void);
     extern void swap_windows(int dr);
     extern int check_loaded(const char *f, char *win_path);
    +extern char *get_last_created_window(void);
     extern char *get_window_path(int i);
     extern int get_window_count(void);
     extern Xschem_ctx **get_save_xctx(void);
    diff --git a/src/xschem.tcl b/src/xschem.tcl
    index 2b4956c7..ba91db59 100644
    --- a/src/xschem.tcl
    +++ b/src/xschem.tcl
    @@ -2960,6 +2960,34 @@ proc save_file_dialog { msg ext global_initdir {initialf {}} {overwrt 1} } {
       return $r
     }
     
    +# opens indicated instance (or selected one) into a separate tab/window
    +# keeping the hierarchy path, as it was descended into (as with 'e' key).
    +proc open_sub_schematic {{inst {}} {inst_number 0}} {
    +  set one_sel [expr {[xschem get lastsel] == 1}]
    +  if { $inst eq {} && $one_sel} {
    +    set inst [lindex [xschem selected_set] 0]
    +    xschem unselect_all
    +  } else {
    +    set instlist {}
    +    # get list of instances (instance names only) 
    +    foreach {i s t} [xschem instance_list] {lappend instlist $i}
    +    # if provided $inst is not in the list return 0
    +    if {[lsearch -exact $instlist $inst] == -1} {return 0}
    +  }
    +  # open a new top level in another window / tab
    +  set schname [xschem get_sch_from_sym $inst]
    +  set res [xschem schematic_in_new_window force]
    +  # if successfull descend into indicated sub-schematic
    +  if {$res} {
    +    xschem new_schematic switch [xschem get last_created_window]
    +    xschem select instance $inst fast
    +    xschem descend
    +    return 1
    +  }
    +  return 0
    +}
    +
    +
     proc is_xschem_file {f} {
       if { ![file exists $f] } { return 0 
       } elseif { [file isdirectory $f] } { return 0 }
    @@ -6854,7 +6882,8 @@ proc build_widgets { {topwin {} } } {
       toolbar_add FileOpen "xschem load" "Open File" $topwin
     
       $topwin.menubar.file.menu add command -label "Open schematic in new window/tab" \
    -      -command "xschem schematic_in_new_window" -accelerator Alt+E
    +      -command "open_sub_schematic" -accelerator Alt+E
    +      # -command "xschem schematic_in_new_window" -accelerator Alt+E
       $topwin.menubar.file.menu add command -label "Open symbol in new window/tab" \
           -command "xschem symbol_in_new_window" -accelerator Alt+I
     
    diff --git a/xschem_library/examples/poweramp.sch b/xschem_library/examples/poweramp.sch
    index b3478ace..07df4d5c 100644
    --- a/xschem_library/examples/poweramp.sch
    +++ b/xschem_library/examples/poweramp.sch
    @@ -322,7 +322,7 @@ C {spice_probe.sym} 670 -1120 0 0 {name=p43 analysis=tran }
     C {spice_probe.sym} 950 -1200 0 0 {name=p44 analysis=tran }
     C {launcher.sym} 1000 -270 0 0 {name=h1
     descr="Backannotate"
    -tclcommand="xschem annotate_op $netlist_dir/poweramp_op.raw"}
    +tclcommand="xschem annotate_op $netlist_dir/poweramp.raw"}
     C {spice_probe.sym} 350 -1210 0 0 {name=p45 analysis=tran }
     C {spice_probe.sym} 350 -1050 0 0 {name=p46 analysis=tran }
     C {launcher.sym} 1145 -1165 0 0 {name=h5 
    @@ -354,11 +354,11 @@ vvss vss 0 dc 0
     .control
     save all
     op
    -write poweramp_op.raw
    +write poweramp.raw
    +set appendwrite
     tran  2e-7 0.025 uic
     * .FOUR 20k v(outm,outp)
     * .probe i(*) 
    -plot outp outm
     save p(r*) p(v*)
     write poweramp.raw
     quit 0