gen::add_generator Verilog verilog_gen::generate

# Проблемы с оригинальным DRAKON:
# 1. Проблема с одинаковыми названиями состояний в разных автоматах
#    сейчас основная проблема с одинаковыми именами сообщений в
#    разных автоматах (original в get_message?)
# 2. Детекцию машин хотелось бы ещё и по тексту в start icon
# 3. Обработка полок должна быть до экстракции машин
# 4. Развёртка цикла for(;;) через if и while для верилога недопустима (
#    если в функциях ещё и может прокатить - в зависимости от синтезатора, то
#    в generate блоках точно не прокатит)
# 
# Возможные способы решения этих вещей можно посмотреть внизу этого файла

# перемещение выделения по иконам клавишами курсора
# горячие клавиши для вставки основных икон
# shift + клавиши курсора двигают иконы в smart режиме
# ctrl + клавиши курсора двигают иконы обычным способом
# alt + клавиши курсора меняют размер иконы


# TODO:
# 0. циклы
# 0b. repeat
# 1. init(ial)
# 2. инстанциация модулей
# 3. generate statements
# 7. tasks
# 8. Проблема в verify_all: если после патчинга происходит выкидывание 
#    исключения, то повторный патчинг потом невозможен
#     ^- вроде поправил, проверить

namespace eval verilog_gen {
    
    variable tdb ""


variable keywords {
always
and
assign
automatic
begin
buf
bufif0
bufif1
case
casex
casez
cell
cmos
config
deassign
default
defparam
design
disable
edge
else
end
endcase
endconfig
endfunction
endgenerate
endmodule
endprimitive
endspecify
endtable
endtask
event
for
force
forever
fork
function
generate
genvar
highz0
highz1
if
ifnone
incdir
include
initial
inout
input
instance
integer
join
large
liblist
library
localparam
macromodule
medium
module
nand
negedge
nmos
nor
noshowcancelledno
not
notif0
notif1
or
output
parameter
pmos
posedge
primitive
pull0
pull1
pulldown
pullup
pulsestyle_oneventglitch
pulsestyle_ondetectglitch
remos
real
realtime
reg
release
repeat
rnmos
rpmos
rtran
rtranif0
rtranif1
scalared
showcancelled
signed
small
specify
specparam
strong0
strong1
supply0
supply1
table
task
time
tran
tranif0
tranif1
tri
tri0
tri1
triand
trior
trireg
unsigned
use
vectored
wait
wand
weak0
weak1
while
wire
wor
xnor
xor
}

# Autogenerated with DRAKON Editor 1.29

proc build_always_block { name keyword parameters extra_reset body } {
    #item 729
    set indent \
    [ make_indent 1 ]
    #item 786
    set indent_next \
    [ make_indent 2 ]
    #item 722
    set result \
    ""
    #item 1868
    if {[ dict exists $parameters parameters ]} {
        #item 1871
        set parameters_list \
        [ dict get $parameters parameters ]
        #item 1873
        set params_declarations \
        [ build_signal_declarations \
          "${indent}localparam" $parameters_list ]
        #item 1872
        append result \
          "$params_declarations\n"
    } else {
        
    }
    #item 723
    if {[ dict exists $parameters wires ]} {
        #item 726
        set wires_list \
        [ dict get $parameters wires ]
        #item 728
        set signal_declarations \
        [ build_signal_declarations \
          "${indent}wire" $wires_list ]
        #item 727
        append result \
          "$signal_declarations\n"
    } else {
        
    }
    #item 730
    if {[ dict exists $parameters regs ]} {
        #item 733
        set regs_list \
        [ dict get $parameters regs ]
        #item 735
        set signal_declarations \
        [ build_signal_declarations \
          "${indent}reg" $regs_list ]
        #item 734
        append result \
          "$signal_declarations\n"
    } else {
        
    }
    #item 736
    append result "${indent}$keyword "
    #item 737
    if {[ dict exists $parameters sensitivity ]} {
        #item 741
        set sens_list \
        [ dict get $parameters sensitivity ]
    } else {
        #item 740
        set sens_list \
        "*"
    }
    #item 742
    set sens_list \
    [ build_sensitivity_list $sens_list ]
    #item 743
    append result "@($sens_list)\n"
    #item 744
    set reset_block \
    [ build_reset_block \
        $parameters \
        $extra_reset \
        2]
    #item 745
    set has_name \
    [ dict exists $parameters name ]
    #item 746
    if {$has_name} {
        #item 749
        set name \
        [ dict get $parameters name ]
        #item 1703
        set name \
        [ string trim $name ]
        #item 750
        append result \
          "${indent}begin: $name\n"
    } else {
        
    }
    #item 751
    if {$reset_block == ""} {
        #item 754
        set n_indent \
        2
        #item 758
        if {$has_name} {
            
        } else {
            #item 761
            append result \
              "${indent}begin\n"
        }
    } else {
        #item 755
        set n_indent \
        3
        #item 756
        append result \
          "$reset_block"
        #item 757
        append result \
          "begin\n"
    }
    #item 765
    set sync \
    [ regexp \
      "posedge|negedge" \
      $sens_list]
    #item 766
    if {$sync} {
        #item 769
        set operator \
        " <= "
    } else {
        #item 770
        set operator \
        " = "
    }
    #item 771
    set body \
    [ transform_shelf \
      "" \
      $operator \
      $body ]
    #item 772
    append result \
      [ get_body \
        $body \
        $n_indent ]
    
    append result "\n"
    #item 773
    if {$reset_block == ""} {
        #item 776
        if {$has_name} {
            
        } else {
            #item 779
            append result \
              "${indent}end\n"
        }
    } else {
        #item 780
        append result \
          "${indent_next}end\n"
    }
    #item 781
    if {$has_name} {
        #item 784
        append result \
          "${indent}end // $name\n"
    } else {
        
    }
    #item 785
    return $result
}

proc build_assign_block { name parameters body } {
    #item 1923
    set indent \
    [ make_indent 1 ]
    #item 1977
    set indent_next \
    [ make_indent 2 ]
    #item 1916
    set result \
    ""
    #item 1979
    if {[ dict exists $parameters parameters ]} {
        #item 1982
        set parameters_list \
        [ dict get $parameters parameters ]
        #item 1984
        set params_declarations \
        [ build_signal_declarations \
          "${indent}localparam" $parameters_list ]
        #item 1983
        append result \
          "$params_declarations\n"
    } else {
        
    }
    #item 1917
    if {[ dict exists $parameters wires ]} {
        #item 1920
        set wires_list \
        [ dict get $parameters wires ]
        #item 1922
        set signal_declarations \
        [ build_signal_declarations \
          "${indent}wire" $wires_list ]
        #item 1921
        append result \
          "$signal_declarations\n"
    } else {
        
    }
    #item 1924
    if {[ dict exists $parameters regs ]} {
        #item 1927
        set regs_list \
        [ dict get $parameters regs ]
        #item 1929
        set signal_declarations \
        [ build_signal_declarations \
          "${indent}reg" $regs_list ]
        #item 1928
        append result \
          "$signal_declarations\n"
    } else {
        
    }
    #item 1962
    set body \
    [ transform_shelf \
      "assign" \
      " = " \
      $body ]
    #item 1963
    append result \
      [ get_body \
        $body \
        1 ]
    
    append result "\n"
    #item 1976
    return $result
}

proc build_declaration { name signature body start_text } {
    #item 875
    set indent \
    [ make_indent 1 ]
    #item 867
    lassign $signature \
      type \
      access \
      raw_parameters \
      returns
    #item 868
    set result \
    ""
    #item 869
    set parameters \
    [ parse_block_parameters \
        $raw_parameters ]
    #item 870
    if {[ is_always_block \
    $start_text \
    $raw_parameters ]} {
        #item 873
        set keyword \
        [ get_always_keyword \
            $start_text \
            $raw_parameters ]
        #item 874
        append result \
        "${indent}// '$keyword'" \
        " block from diagram '$name'\n\n" \
        [ build_always_block \
            $name \
            $keyword \
            $parameters \
            "" \
            $body ]
    } else {
        #item 1994
        if {[ is_assign_block \
    $start_text \
    $raw_parameters ]} {
            #item 1997
            append result \
            "${indent}// 'assign'" \
            " block from diagram '$name'\n\n" \
            [ build_assign_block \
                $name \
                $parameters \
                $body ]
        } else {
            #item 876
            append result \
              [ build_function \
                  $start_text \
                  $name \
                  $parameters \
                  $body]
        }
    }
}

proc build_function { func_name diagram_name parameters body } {
    #item 813
    set indent \
    [ make_indent 1 ]
    #item 807
    if {[ dict exists $parameters returns ]} {
        #item 811
        set returns \
        [ lindex \
          [ dict get \
              $parameters returns ] \
          0 ]
    } else {
        #item 810
        set returns \
        ""
    }
    #item 812
    append result \
      "${indent}" \
      "// function " \
      "'$func_name'" \
      " from diagram " \
      "'$diagram_name'\n\n" \
      "${indent}function" \
      " $returns " \
      "$func_name;\n"
    #item 836
    append result \
      [ make_declarations \
          $parameters \
          parameters \
          parameter \
          1 ]
    #item 837
    append result \
      [ make_declarations \
          $parameters \
          inputs \
          input \
          1 ]
    #item 838
    append result \
      [ make_declarations \
          $parameters \
          regs \
          reg \
          1 ]
    #item 839
    append result \
      [ make_declarations \
          $parameters \
          integers \
          integer \
          1 ]
    #item 858
    set body \
    [ transform_shelf "" " = " $body ]
    #item 859
    set body \
    [ get_body $body 2 ]
    #item 860
    append result \
      "${indent}begin\n" \
        "${body}\n" \
      "${indent}end\n" \
      "${indent}endfunction"
    #item 861
    return $result
}

proc build_reset_block { parameters onreset_extra indent_n } {
    #item 635
    set result \
    ""
    #item 636
    set indent \
    [ make_indent $indent_n ]
    #item 637
    set indent_next \
    [ make_indent [ expr "$indent_n + 1" ] ]
    #item 642
    if {[ dict exists $parameters reset ]} {
        #item 645
        set resets \
        [ dict get $parameters reset ]
        #item 646
        set reset_expr \
        [ build_reset_expression $resets ]
        #item 647
        append result\
          "${indent}if ($reset_expr) begin\n"
        #item 651
        if {[ dict exists $parameters setup ]} {
            #item 656
            set onreset_list \
            [ dict get $parameters setup ]
            foreach line $onreset_list {
                #item 657
                append result "${indent_next}$line;\n"
            }
        } else {
            
        }
        foreach line $onreset_extra {
            #item 662
            append result "${indent_next}$line;\n"
        }
        #item 663
        append result "${indent}end else "
    } else {
        
    }
    #item 638
    return $result
}

proc build_reset_expression { reset_list } {
    #item 511
    set signals \
    {}
    foreach line $reset_list {
        #item 514
        set signal \
        [ remove_comment $line ]
        #item 523
        set last_char \
        [ string index $signal end ]
        #item 515
        if {$last_char == "+"} {
            #item 518
            set signal \
            "[string range $signal 0 end-1]"
        } else {
            #item 519
            if {$last_char == "-"} {
                #item 520
                set signal \
                "![string range $signal 0 end-1]"
            } else {
                
            }
        }
        #item 524
        lappend signals $signal
    }
    #item 525
    return [ join $signals " || " ]
}

proc build_sensitivity_list { sens_list } {
    #item 491
    set signals \
    {}
    foreach line $sens_list {
        #item 494
        set signal \
        [ remove_comment $line ]
        #item 503
        set last_char \
        [ string index $signal end ]
        #item 495
        if {$last_char == "+"} {
            #item 498
            set signal \
            "posedge [string range $signal 0 end-1]"
        } else {
            #item 499
            if {$last_char == "-"} {
                #item 500
                set signal \
                "negedge [string range $signal 0 end-1]"
            } else {
                
            }
        }
        #item 504
        lappend signals $signal
    }
    #item 505
    return [ join $signals " or " ]
}

proc build_signal_declarations { keyword text } {
    #item 903
    set decls \
    {}
    foreach line $text {
        #item 2042
        if {[ info exists comment ]} {
            #item 2041
            unset comment
        } else {
            
        }
        #item 907
        regexp "((\[^/\]\[^/\])+)//(.*)$" \
          $line _ _ _ comment
        #item 908
        regsub -all {//.*$} \
          $line "" line
        #item 909
        set line \
        [ string trim "$line" " \t;" ]
        #item 910
        regsub -all {[ \t]+} \
          "$line" " " line
        #item 911
        if {$line == ""} {
            
        } else {
            #item 915
            if {([ info exists comment ]) && (!($comment == ""))} {
                #item 920
                set comment \
                " // $comment"
            } else {
                #item 919
                set comment \
                ""
            }
            #item 914
            set decls \
            "${decls}${keyword} ${line};$comment\n"
        }
    }
    #item 904
    return $decls
}

proc build_state_codes { fsm_encoding num_states } {
    #item 1083
    set state_codes \
    {}
    #item 10840001
    set i 0
    while { 1 } {
        #item 10840002
        if {[expr "$i < $num_states"]} {
            
        } else {
            break
        }
        #item 10860001
        if {$fsm_encoding == "normal"} {
            #item 1092
            lappend state_codes $i
        } else {
            #item 10860002
            if {$fsm_encoding == "onehot"} {
                
            } else {
                #item 10860003
                error "Unexpected switch value: $fsm_encoding"
            }
            #item 1093
            lappend state_codes \
              [ expr "2**$i" ]
        }
        #item 10840003
        incr i
    }
    #item 1094
    return $state_codes
}

proc change_state { state dname } {
    #item 2006
    set state \
    [ normalize_state_name $state ]
    #item 257
    if {$state == ""} {
        #item 260
        set state "___halt_state___"
    } else {
        
    }
    #item 262
    return "##@@next_state:$state@@##"
}

proc check_insertions { insertions } {
    #item 1847
    dict map \
    { norm_name name_body } \
    $insertions \
    {
    #item 1850
    if {$name_body == ""} {
        #item 1860
        set result \
        0
        #item 1862
        variable ::mw::s_needle
        variable ::mw::s_case
        variable ::mw::s_whole_word
        variable ::mw::s_current_only
        set ::mw::s_needle $norm_name
        set ::mw::s_case 0
        set ::mw::s_whole_word 1
        set ::mw::s_current_only all
        ::mw::find_all
        ::mw::show_search
        #item 1861
        error \
        "Unresolved insertion icon: '$norm_name'"
        #item 1863
        return 0
    } else {
        
    }
    #item 1849
    }
    #item 1854
    return 1
}

proc complain_dia { name message } {
    #item 1413
    variable tdb
    #item 1414
    set id \
    [ $tdb onecolumn {
        select diagram_id
        from diagrams
        where name = :name } ]
    #item 1415
    graph::p.error $id {} $message
}

proc do_monkey_patch { } {
    #item 2126
    set direction "forward"
    #item 2127
    monkey_patch_gen $direction
    monkey_patch_graph $direction
    monkey_patch_sma $direction
}

proc enforce_nogoto { name } {
    #item 1421
    complain_dia $name \
    "Could not generate code for function '$name'.\nTry splitting it into smaller parts."
}

proc extract_signature { text name } {
    #item 1439
    set lines \
    [ gen::separate_from_comments \
        $text ]
    #item 1440
    set count \
    [ llength $lines ]
    #item 1452
    set access \
    "internal"
    #item 1444
    set parameters \
    {}
    #item 1443
    set type \
    "function"
    #item 1441
    if {$count == 0} {
        
    } else {
        #item 1445
        set first_line \
        [ lindex $lines 0 ]
        #item 1446
        set first \
        [ lindex $first_line 0 ]
        #item 1447
        if {$first == "#comment"} {
            #item 1451
            set type \
            "comment"
        } else {
            #item 14530001
            set i 0
            while { 1 } {
                #item 14530002
                if {$i < $count} {
                    
                } else {
                    break
                }
                #item 1455
                set current \
                [ lindex $lines $i ]
                #item 1456
                lappend parameters $current
                #item 14530003
                incr i
            }
        }
    }
    #item 1457
    set result \
    [ list {} \
      [ gen::create_signature \
        $type \
        $access \
        $parameters "" ] ]
    #item 1458
    return $result
}

proc for_declare { item_id first second } {
    #item 251
    return ""
}

proc foreach_check { item_id first second } {
    #item 38
    return ""
}

proc foreach_current { item_id first second } {
    #item 44
    return ""
}

proc foreach_incr { item_id first second } {
    #item 50
    return ""
}

proc foreach_init { item_id first second } {
    #item 56
    return ""
}

proc form_ascii_state_name { name len } {
    #item 1074
    set spaces_num \
    [expr "$len - [string bytelength $name]" ]
    #item 1075
    set spaces \
    [ string repeat " " $spaces_num ]
    #item 1076
    set str \
    "${name}${spaces}"
    #item 1077
    return $str
}

proc generate { db gdb filename } {
    #item 2137
    do_monkey_patch
    
    if { [ catch {
    	generate_kernel $db $gdb $filename
    } message ] } {
    	undo_monkey_patch
    	error $message
    } else {
    	undo_monkey_patch
    }
}

proc generate_body { gdb diagram_id start_item node_list sorted incoming } {
    #item 1464
    set callbacks \
    [ make_callbaks ]
    #item 1465
    return [ cbody::generate_body \
                 $gdb \
                 $diagram_id \
                 $start_item \
                 $node_list \
                 $sorted \
                 $incoming \
                 $callbacks ]
}

proc generate_kernel { db gdb filename } {
    #item 307
    variable tdb
    #item 308
    set tdb \
    $gdb
    #item 309
    set callbacks \
    [ make_callbacks ]
    #item 310
    lassign [ gen::scan_file_description \
              $db { header\
                    parameters\
                    inputs\
                    outputs\
                    inouts\
                    footer } ]\
              header\
              parameters\
              inputs\
              outputs\
              inouts\
              footer
    #item 311
    set diagrams \
    [ $gdb eval {\
       select diagram_id\
       from diagrams } ]
    foreach diagram_id $diagrams {
        #item 314
        if {[mwc::is_drakon $diagram_id]} {
            #item 317
            gen::fix_shelves\
              $gdb $callbacks 1 $diagram_id
        } else {
            
        }
    }
    #item 326
    set machines \
    [ sma::extract_many_machines\
      $gdb $callbacks ]
    #item 327
    set diagrams \
    [ $gdb eval {\
       select diagram_id\
       from diagrams } ]
    foreach diagram_id $diagrams {
        #item 337
        if {[mwc::is_drakon $diagram_id]} {
            #item 340
            gen::fix_graph_for_diagram\
              $gdb $callbacks 1 $diagram_id
        } else {
            
        }
    }
    #item 342
    set use_nogoto \
    1
    #item 343
    set functions \
    [ gen::generate_functions\
        $db $gdb $callbacks $use_nogoto ]
    #item 344
    if {[ graph::errors_occured ]} {
        
    } else {
        #item 347
        set hfile \
        [ replace_extension $filename "v" ]
        #item 348
        set module \
        [ file tail \
          [ string map \
            {".drn" ""} $filename ] ]
        #item 349
        set f \
        [open_output_file $hfile]
        #item 350
        catch {
         p.print_to_file \
         $gdb $f \
         $functions \
         $header \
         $parameters \
         $inputs \
         $outputs \
         $inouts \
         $footer \
         $module \
         $machines
        } error_message
        #item 351
        catch { close $f }
        #item 352
        if {$error_message != ""} {
            #item 355
            error $error_message
        } else {
            
        }
    }
}

proc get_all_insertions { functions } {
    #item 1816
    set insertions \
    {}
    foreach fun $functions {
        #item 1819
        lassign $fun \
          _ name _ body
        #item 1820
        set insertions_refs \
        [ get_insertions_refs $body ]
        foreach ins_ref $insertions_refs {
            #item 1823
            dict set insertions $ins_ref {}
        }
    }
    foreach fun $functions {
        #item 1826
        lassign $fun \
          _ name _ body
        #item 2010
        set norm_name \
        [ normalize_insertion_name \
            $name ]
        #item 1828
        if {[ dict exists \
  $insertions $norm_name ]} {
            #item 1827
            dict set insertions \
             $norm_name \
             [ list $name $body ]
        } else {
            
        }
    }
    while { 1 } {
        #item 1835
        set result \
        {}
        #item 1840
        set refs \
        ""
        #item 2099
        dict map \
        {norm_name name_body} \
        $insertions \
        {
        #item 2105
        if {$name_body == ""} {
            #item 2108
            dict set result \
              $norm_name {}
        } else {
            #item 2101
            lassign $name_body \
              name body
            #item 2102
            set body \
            [ process_insertions_refs \
                $insertions \
                $body ]
            #item 2103
            dict set result $norm_name \
                [ list $name $body ]
            #item 2104
            append refs \
             [ get_insertions_refs $body ]
        }
        #item 2100
        }
        #item 1837
        set insertions \
        $result
        #item 1838
        if {$refs == ""} {
            break
        } else {
            
        }
    }
    #item 1841
    return $result
}

proc get_always_keyword { start_text parameters } {
    #item 1704
    set start_text \
    [ string trim $start_text ]
    #item 686
    set first_line \
    [lindex [ lindex $parameters 0 ] 0]
    #item 688
    if {(($start_text == "always") || ($start_text == "always_ff")) || ($start_text == "always_comb")} {
        #item 694
        return $start_text
    } else {
        #item 695
        return $first_line
    }
}

proc get_body { body indent } {
    #item 1685
    set lines \
    [ gen::indent \
      $body \
      $indent ]
    #item 1686
    return $lines
}

proc get_cases { gdb state original_diagram } {
    #item 1352
    set result \
    [ $gdb eval {
        select diagram_id
        from diagrams
        where state = :state
        and original = :original_diagram
        and is_default = 0
        order by ordinal } ]
    #item 1353
    return $result
}

proc get_default { gdb state } {
    #item 1067
    set found \
    [ $gdb onecolumn {
      select diagram_id
        from diagrams
        where state = :state
        and is_default = 1 } ]
    #item 1068
    return $found
}

proc get_final_state_code { fhandle state state_var indent } {
    #item 1663
    return [ list \
    "${indent}$state: $state_var <= $state;" ]
}

proc get_first_state_name { machine } {
    #item 1268
    set boiler \
    [ dict get \
      $machine \
      boiler ]
    #item 1269
    return [ lindex $boiler 0 ]
}

proc get_indent_from_string { str } {
    #item 2051
    set str \
    [regsub -all "\t" $str \
      [ make_indent 4 ]]
    #item 2050
    regexp "^(\[ \t\]+)" $str \
      _ indent_str
    #item 2058
    if {[ info exists indent_str ]} {
        #item 2052
        set indent_n \
        [ string length \
           $indent_str ]
    } else {
        #item 2061
        set indent_n \
        0
    }
    #item 2053
    set indent_n \
    [ expr "$indent_n / 4" ]
    #item 2054
    return $indent_n
}

proc get_insertions_refs { body } {
    #item 1731
    set result \
    {}
    foreach line $body {
        #item 1734
        if {[ regexp "##@@insertion:(.*)@@##" \
    $line _ name ]} {
            #item 1737
            lappend result $name
        } else {
            
        }
    }
    #item 1739
    return $result
}

proc get_message { gdb diagram_id } {
    #item 1345
    set result \
    [ $gdb onecolumn {
        select message_type
        from diagrams
        where diagram_id = :diagram_id } ]
    #item 1346
    return $result
}

proc get_signal_names { text } {
    #item 882
    set names \
    {}
    #item 883
    set lines \
    [ split "$text" "\n" ]
    foreach line $lines {
        #item 888
        regsub -all {//.*$} $line "" line
        #item 890
        regsub -all {\[[^\]]*\]} $line  "" line
        #item 892
        set line \
        [ string trim "$line" " \t;" ]
        #item 893
        regsub -nocase {^reg|^wire} \
          $line "" line
        #item 886
        regsub -all {[ \t;]+} \
        $line "" line
        #item 1864
        if {$line == ""} {
            
        } else {
            #item 895
            lappend names $line
        }
    }
    #item 887
    return $names
}

proc get_state_body { fhandle gdb functions state original_diagram vlog_state state_var states_rename_table indent_n } {
    #item 1628
    set indent \
    [ make_indent $indent_n ]
    #item 2077
    set indent_n_2 \
    [ expr "$indent_n + 1" ]
    #item 1629
    set indent_2 \
    [ make_indent \
      $indent_n_2]
    #item 2078
    set indent_n_3 \
    [ expr "$indent_n + 2" ]
    #item 1630
    set indent_3 \
    [ make_indent \
      $indent_n_3 ]
    #item 1624
    array set funs {}
    #item 1625
    set result \
    {}
    #item 1626
    set default_dia \
    [ get_default $gdb $state ]
    #item 1627
    append result \
    "${indent}$vlog_state:\n"
    foreach function $functions {
        #item 1633
        lassign $function \
          diagram_id \
          _ _ _
        #item 1634
        set funs($diagram_id) \
        $function
    }
    #item 1635
    set cases \
    [ get_cases $gdb $state $original_diagram]
    #item 2067
    set first_case \
    [ lindex $cases 0 ]
    #item 2076
    set message \
    [ get_message $gdb $first_case ]
    #item 2068
    if {$message == "##@@receive@@##"} {
        #item 2072
        lassign $funs($first_case) \
          _ _ _ body
        #item 2074
        set body \
        [ rename_states \
            $state_var \
            $states_rename_table \
            $body ]
        #item 2075
        append result \
          [ get_body \
              $body  \
              $indent_n_2 ]
    } else {
        #item 1636
        set felse \
        $indent_2
        foreach case $cases {
            #item 1639
            set message \
            [ get_message $gdb $case ]
            #item 1640
            lassign $funs($case) \
              _ _ _ body
            #item 1641
            append result \
            "${felse}if " \
            "($message) begin\n"
            #item 1642
            set body \
            [ rename_states \
                $state_var \
                $states_rename_table \
                $body ]
            #item 1643
            append result \
              [ get_body \
                  $body  \
                  [ expr "$indent_n + 2" ] ]
            #item 1644
            append result \
            "\n${indent_2}end"
            #item 1645
            set felse \
            " else "
        }
        #item 1646
        append result \
        "${felse}begin\n"
        #item 1647
        if {$default_dia == ""} {
            #item 1650
            append result \
            "${indent_3}" \
            "\$error(\"Default " \
            "handler for state " \
            "'$state' is not " \
            "defined!\");\n"
        } else {
            #item 1651
            lassign $funs($default_dia) \
              _ _ _ body
            #item 1652
            set body \
            [ rename_states \
                $state_var \
                $states_rename_table \
                $body ]
            #item 1653
            append result \
              [ get_body \
                  $body  \
                  $indent_n_3 ]
            #item 1654
            append result "\n"
        }
        #item 1655
        append result \
        "${indent_2}end"
    }
    #item 1656
    set result \
    [split $result "\n"]
    #item 1657
    return $result
}

proc get_state_width { fsm_encoding num_states } {
    #item 1100
    set state_width \
    0
    #item 11010001
    if {$fsm_encoding == "normal"} {
        #item 1109
        set state_width \
        [ expr \
          "int(ceil(log($num_states)/log(2)))" ]
    } else {
        #item 11010002
        if {$fsm_encoding == "onehot"} {
            
        } else {
            #item 11010003
            error "Unexpected switch value: $fsm_encoding"
        }
        #item 1108
        set state_width \
        $num_states
    }
    #item 1107
    return $state_width
}

proc has_init { gdb } {
    #item 1261
    set found \
    [ $gdb onecolumn {
        select count(*)
        from diagrams
        where name = 'init' } ]
    #item 1262
    return $found
}

proc highlight { tokens } {
    #item 2154
    set result {}
    #item 2155
    set state "idle"
    #item 2172
    variable keywords
    foreach token $tokens {
        #item 2214
        lassign $token type text
        #item 21560001
        if {$state == "idle"} {
            #item 2224
            set state [ idle_default \
              $keywords result $type $text ]
        } else {
            #item 21560002
            if {$state == "string"} {
                #item 21730001
                if {$text == "\""} {
                    #item 2180
                    lappend result \
                      $colors::syntax_string
                    #item 2181
                    set state "idle"
                } else {
                    #item 21730002
                    if {$text == "\\"} {
                        #item 2215
                        lappend result \
                          $colors::syntax_string
                        #item 2182
                        set state "escaping"
                    } else {
                        #item 21730003
                        if {$text == "\n"} {
                            #item 2216
                            lappend result \
                              $colors::syntax_string
                            #item 2185
                            set state "idle"
                        } else {
                            #item 2217
                            lappend result \
                              $colors::syntax_string
                        }
                    }
                }
            } else {
                #item 21560003
                if {$state == "escaping"} {
                    #item 2187
                    lappend result $colors::syntax_string
                    #item 2186
                    set state "string"
                } else {
                    #item 21560004
                    if {$state == "comment start"} {
                        #item 2221
                        if {$text == "/"} {
                            #item 2220
                            lappend result \
                              $colors::syntax_comment \
                              $colors::syntax_comment
                            #item 2223
                            set state "comment"
                        } else {
                            #item 2226
                            lappend result \
                             $colors::syntax_operator
                            #item 2225
                            set state [ idle_default \
                              $keywords result $type $text ]
                        }
                    } else {
                        #item 21560005
                        if {$state == "comment"} {
                            
                        } else {
                            #item 21560006
                            error "Unexpected switch value: $state"
                        }
                        #item 2209
                        lappend result \
                          $colors::syntax_comment
                        #item 2210
                        if {$text == "\n"} {
                            #item 2212
                            set state "idle"
                        } else {
                            
                        }
                    }
                }
            }
        }
    }
    #item 2227
    if {$state == "comment start"} {
        #item 2230
        lappend result \
         $colors::syntax_operator
    } else {
        
    }
    #item 2153
    return $result
}

proc idle_default { keywords result_name type text } {
    #item 2236
    upvar 1 $result_name result
    #item 22370001
    if {$text == "\""} {
        #item 2260
        lappend result \
          $colors::syntax_string
        #item 2244
        set state "string"
    } else {
        #item 22370002
        if {$text == "/"} {
            #item 2264
            set state "comment start"
        } else {
            #item 22460001
            if {$type == "op"} {
                #item 2254
                lappend result \
                  $colors::syntax_operator
                #item 2265
                set state "idle"
            } else {
                #item 22460002
                if {$type == "number"} {
                    #item 2253
                    lappend result \
                      $colors::syntax_number
                    #item 2266
                    set state "idle"
                } else {
                    #item 22460003
                    if {($type == "token") && ([contains $keywords $text])} {
                        #item 2258
                        lappend result \
                          $colors::syntax_keyword
                        #item 2269
                        set state "idle"
                    } else {
                        #item 2255
                        lappend result \
                          $colors::syntax_identifier
                        #item 2270
                        set state "idle"
                    }
                }
            }
        }
    }
    #item 2268
    return $state
}

proc inspect_tree { node name } {
    
}

proc is_always_block { start_text parameters } {
    #item 669
    set start_text_substr \
    [ string range $start_text 0 5 ]
    #item 670
    set first_line \
    [lindex [ lindex $parameters 0 ] 0]
    #item 671
    set first_line_substr \
    [ string range $first_line 0 5 ]
    #item 672
    if {($start_text_substr == "always") || ($first_line_substr == "always")} {
        #item 678
        return 1
    } else {
        #item 679
        return 0
    }
}

proc is_assign_block { start_text parameters } {
    #item 1879
    set start_text \
    [ string trim $start_text ]
    #item 1880
    set first_line \
    [lindex [ lindex $parameters 0 ] 0]
    #item 1881
    set first_line \
    [ string trim $first_line ]
    #item 1882
    if {($start_text == "assign") || ($first_line == "assign")} {
        #item 1888
        return 1
    } else {
        #item 1889
        return 0
    }
}

proc is_insertion { function_name insertions } {
    #item 2026
    set name \
    [ normalize_insertion_name \
        $function_name ]
    #item 2027
    set result \
    [ dict exists \
      $insertions $name ]
    #item 2028
    return $result
}

proc is_machine_proc { gdb diagram_id } {
    #item 1372
    set state \
    [ $gdb onecolumn {
        select state
        from diagrams
        where diagram_id = :diagram_id } ]
    #item 1373
    if {$state == ""} {
        #item 1377
        set result \
        0
    } else {
        #item 1376
        set result \
        1
    }
    #item 1378
    return $result
}

proc make_callbacks { } {
    #item 95
    set callbacks \
    {}
    #item 80
    gen::put_callback callbacks assign              verilog_gen::p.assign
    gen::put_callback callbacks compare             verilog_gen::p.compare
    gen::put_callback callbacks compare2            verilog_gen::p.compare2
    gen::put_callback callbacks while_start         verilog_gen::p.while_start
    gen::put_callback callbacks if_start            verilog_gen::p.if_start
    gen::put_callback callbacks elseif_start        verilog_gen::p.elseif_start
    gen::put_callback callbacks if_end              verilog_gen::p.if_end
    gen::put_callback callbacks else_start          verilog_gen::p.else_start
    gen::put_callback callbacks pass                verilog_gen::p.pass
    gen::put_callback callbacks continue            verilog_gen::p.continue
    gen::put_callback callbacks return_none         verilog_gen::p.return_none
    gen::put_callback callbacks block_close         verilog_gen::p.block_close
    gen::put_callback callbacks comment             verilog_gen::p.comment
    gen::put_callback callbacks bad_case            verilog_gen::p.bad_case
    gen::put_callback callbacks for_init            verilog_gen::foreach_init
    gen::put_callback callbacks for_check           verilog_gen::foreach_check
    gen::put_callback callbacks for_current         verilog_gen::foreach_current
    gen::put_callback callbacks for_incr            verilog_gen::foreach_incr
    gen::put_callback callbacks body                verilog_gen::generate_body
    gen::put_callback callbacks signature           verilog_gen::extract_signature
    gen::put_callback callbacks and                 verilog_gen::p.and
    gen::put_callback callbacks or                  verilog_gen::p.or
    gen::put_callback callbacks not                 verilog_gen::p.not
    gen::put_callback callbacks break               "break"
    gen::put_callback callbacks declare             verilog_gen::p.declare
    gen::put_callback callbacks for_declare         verilog_gen::for_declare
    
    gen::put_callback callbacks line_end            ""
    gen::put_callback callbacks enforce_nogoto      verilog_gen::enforce_nogoto
    gen::put_callback callbacks inspect_tree        verilog_gen::inspect_tree
    gen::put_callback callbacks shelf               verilog_gen::shelf
    
    gen::put_callback callbacks change_state        verilog_gen::change_state
    gen::put_callback callbacks fsm_merge           0
    #item 81
    return $callbacks
}

proc make_declarations { parameters keyword keyword_name N } {
    #item 850
    set indent \
    [ make_indent $N ]
    #item 845
    if {[ dict exists \
  $parameters $keyword ]} {
        #item 848
        set list \
        [ dict get \
          $parameters $keyword ]
        #item 849
        return \
          [ build_signal_declarations \
            "${indent}${keyword_name}" $list ]
    } else {
        #item 851
        return ""
    }
}

proc make_indent { N } {
    #item 1679
    set indent_length \
    [ expr "$N * 4" ]
    #item 1678
    set indent \
    [ string repeat " " $indent_length ]
    #item 1677
    return $indent
}

proc monkey_patch { direction fnames } {
    foreach fname $fnames {
        #item 2084
        if {$direction == "reverse"} {
            #item 2087
            rename "$fname" \
                   "${fname}_vlog"
            
            rename "${fname}_backup" \
                   "$fname"
        } else {
            #item 2089
            rename "$fname" \
                   "${fname}_backup"
            
            rename "${fname}_vlog" \
                   "$fname"
        }
    }
}

proc monkey_patch_gen { direction } {
    #item 2094
    set functions \
    [ list ::gen::p.rewire_for ]
    #item 2093
    monkey_patch $direction $functions
}

proc monkey_patch_graph { direction } {
    #item 2096
    set functions \
    [ list \
    ::graph::is_machine \
    ::graph::p.find_starts \
    ::graph::copy_from ]
    #item 2095
    monkey_patch $direction $functions
}

proc monkey_patch_sma { direction } {
    #item 2098
    set functions \
    [ list \
    ::sma::all_start_with_receive \
    ::sma::build_machine \
    ::sma::find_end \
    ::sma::message_types_for_select ]
    #item 2097
    monkey_patch $direction $functions
}

proc normalize_insertion_name { name } {
    #item 2018
    set norm_name \
    [ regsub -all {[[:cntrl:]]+} \
       $name " " ]
    #item 2019
    set norm_name \
    [ string trim $norm_name ]
    #item 2020
    return $norm_name
}

proc normalize_state_name { state_name } {
    #item 2003
    set state_name \
    [regsub -all {[[:cntrl:]]+} \
      $state_name " "]
    #item 2004
    return $state_name
}

proc p.and { left right } {
    #item 449
    return "($left) && ($right)"
}

proc p.assign { variable val } {
    #item 164
    return [ shelf $val $variable ]
}

proc p.assign2 { variable value } {
    #item 176
    return "$variable == $value"
}

proc p.bad_case { switch_var } {
    #item 245
    return ""
}

proc p.block_close { output depth } {
    #item 230
    upvar 1 $output result
    #item 231
    set line \
    [ gen::make_indent $depth ]
    #item 232
    append line "end"
    #item 233
    lappend result $line
}

proc p.comment { line } {
    #item 239
    return "// $line"
}

proc p.compare { variable value } {
    #item 170
    return "$variable == $value"
}

proc p.continue { } {
    #item 218
    return ""
}

proc p.declare { type name value } {
    #item 88
    return ""
}

proc p.else_start { } {
    #item 485
    return "end else begin"
}

proc p.elseif_start { } {
    #item 473
    return "end else if ("
}

proc p.if_end { } {
    #item 479
    return ") begin "
}

proc p.if_start { } {
    #item 467
    return "if ("
}

proc p.not { operand } {
    #item 461
    return "!($operand)"
}

proc p.or { left right } {
    #item 455
    return "($left) || ($right)"
}

proc p.pass { } {
    #item 212
    return ""
}

proc p.print_to_file { gdb fhandle functions header parameters inputs outputs inouts footer module machines } {
    #item 967
    set indent \
    [ make_indent 1 ]
    #item 961
    set version \
    [ version_string ]
    #item 962
    puts $fhandle \
      "// Autogenerated with DRAKON Editor $version\n"
    #item 971
    if {$header == ""} {
        
    } else {
        #item 974
        puts $fhandle $header
    }
    #item 963
    set input_signals \
    [ join [ get_signal_names $inputs] ", " ]
    #item 964
    set output_signals \
    [ join [ get_signal_names $outputs] ", " ]
    #item 965
    set inout_signals \
    [ join [ get_signal_names $inouts] ", " ]
    #item 966
    set input_declarations \
    [ build_signal_declarations \
      "${indent}input" \
      [ split $inputs "\n" ]]
    #item 968
    set output_declarations \
    [ build_signal_declarations \
      "${indent}output" \
      [ split $outputs "\n" ]]
    #item 969
    set inout_declarations \
    [ build_signal_declarations \
      "${indent}input" \
      [ split $inouts "\n" ]]
    #item 970
    set parameter_declarations \
    [ build_signal_declarations \
      "${indent}parameter" \
      [ split $parameters "\n" ]]
    #item 975
    puts -nonewline $fhandle "module ${module} ("
    #item 976
    if {$output_signals == ""} {
        
    } else {
        #item 979
        puts -nonewline $fhandle \
        "\n${indent}// Outputs\n${indent}$output_signals"
        #item 980
        if {($input_signals == "") && ($inout_signals == "")} {
            
        } else {
            #item 984
            puts -nonewline $fhandle ","
        }
    }
    #item 985
    if {$input_signals == ""} {
        
    } else {
        #item 988
        puts -nonewline $fhandle \
        "\n${indent}// Inputs\n${indent}$input_signals"
        #item 989
        if {$inout_signals == ""} {
            
        } else {
            #item 990
            puts -nonewline $fhandle ","
        }
    }
    #item 991
    if {$inout_signals == ""} {
        
    } else {
        #item 994
        puts -nonewline $fhandle \
        "\n${indent}// InOuts\n${indent}$inout_signals"
    }
    #item 995
    puts $fhandle ");\n"
    #item 1005
    if {$parameter_declarations == ""} {
        
    } else {
        #item 1017
        puts $fhandle \
        "${indent}// Parameters\n$parameter_declarations"
    }
    #item 1008
    if {$output_declarations == ""} {
        
    } else {
        #item 1018
        puts $fhandle \
        "${indent}// Outputs\n$output_declarations"
    }
    #item 1011
    if {$input_declarations == ""} {
        
    } else {
        #item 1019
        puts $fhandle \
        "${indent}// Inputs\n$input_declarations"
    }
    #item 1014
    if {$inout_declarations == ""} {
        
    } else {
        #item 1020
        puts $fhandle \
        "${indent}// InOuts\n$inout_declarations"
    }
    #item 1021
    puts $fhandle "\n"
    #item 1783
    set insertions \
    [ get_all_insertions $functions ]
    #item 1855
    if {[ check_insertions $insertions ]} {
        
    } else {
        #item 1858
        error \
          "Не все вставки удалось разрешить!"
    }
    #item 1786
    set old_functions \
    $functions
    #item 1787
    set functions \
    {}
    foreach function $old_functions {
        #item 1788
        lassign $function \
          diagram_id \
          name \
          signature \
          body
        #item 1789
        if {[ is_insertion $name $insertions ]} {
            
        } else {
            #item 1793
            set body \
            [ process_insertions_refs \
              $insertions \
              $body ]
            #item 1792
            lappend functions \
              [list \
               $diagram_id \
               $name \
               $signature \
               $body ]
        }
    }
    foreach function $functions {
        #item 1024
        lassign $function \
          diagram_id \
          name \
          signature \
          body
        #item 1025
        set info \
        [ $gdb eval {
            select state, message_type, ordinal, is_default
            from diagrams
            where diagram_id = :diagram_id } ]
        #item 1026
        lassign $info \
          state \
          message \
          ordinal \
          is_default
        #item 1027
        if {[ is_machine_proc $gdb $diagram_id ]} {
            
        } else {
            #item 1030
            set type \
            [ lindex $signature 0 ]
            #item 1031
            if {$type == "comment"} {
                
            } else {
                #item 1032
                puts $fhandle ""
                #item 1033
                set start_id \
                [ lindex [ graph::p.find_starts $diagram_id ] 0]
                #item 1034
                set start_text \
                [string trim \
                  [ gen::p.vertex_text gdb $start_id ]]
                #item 1035
                set declaration \
                [ build_declaration \
                    $name \
                    $signature \
                    $body \
                    $start_text ]
                #item 1036
                puts $fhandle $declaration
            }
        }
    }
    foreach machine $machines {
        #item 1039
        print_machine_methods \
          $fhandle \
          $gdb \
          $machine \
          $functions
    }
    #item 1040
    puts $fhandle ""
    puts $fhandle "endmodule // $module"
    puts $fhandle $footer
}

proc p.return_none { } {
    #item 224
    return ""
}

proc p.while_start { } {
    #item 182
    return "while (1) begin"
}

proc parse_block_parameters { parameters } {
    #item 433
    set result \
    {}
    foreach param $parameters {
        #item 436
        lappend result \
          [ lindex $param 0 ]
    }
    #item 437
    return [ parse_parameters $result ]
}

proc parse_machine_parameters { parameters } {
    #item 443
    return [ parse_parameters $parameters ]
}

proc parse_parameters { parameters } {
    #item 409
    set result \
    {}
    #item 410
    set current_key \
    ""
    foreach param $parameters {
        #item 1692
        set param \
        [ string trimleft $param " \t" ]
        #item 1687
        if {[ regexp {^([a-z_]+):} \
  $param \
  _ key ]} {
            #item 1691
            regsub {^[a-z_]+:[ \t]*} \
              $param "" param
            #item 1694
            set current_key \
            ""
            #item 1695
            set items \
            [trim_lines \
              [ split $param ";" ] \
              " \t;" ]
            #item 1696
            if {[ dict exists $result $current_key ]} {
                #item 1699
                set old \
                [ dict get $result $key ]
            } else {
                #item 1700
                set old \
                ""
            }
            #item 1702
            set value \
            [ concat $old $items ]
            #item 1701
            dict set result $key $value
        } else {
            #item 1693
            set param \
            [ string trimright $param " \t;" ]
            #item 413
            regsub -all \
                   {[ \t]+} \
                   $param \
                   " " param
            #item 414
            if {[ regexp "=== (\\S+) ===" \
  $param temp key ]} {
                #item 417
                set current_key \
                $key
            } else {
                #item 418
                if {($current_key == "") || ($param == "")} {
                    
                } else {
                    #item 421
                    if {[ dict exists $result $current_key ]} {
                        #item 425
                        set old \
                        [ dict get $result $current_key ]
                    } else {
                        #item 426
                        set old \
                        ""
                    }
                    #item 424
                    lappend old $param
                    dict set result $current_key $old
                }
            }
        }
    }
    #item 427
    return $result
}

proc print_machine_methods { fhandle gdb machine functions } {
    #item 1502
    set indent \
    [ make_indent 1 ]
    #item 1503
    set indent_next \
    [ make_indent 2 ]
    #item 1575
    set indent_3 \
    [ make_indent 3 ]
    #item 1489
    if {$machine == ""} {
        
    } else {
        #item 1492
        set states \
        [ dict get $machine states ]
        #item 1493
        set original_diagram \
        [ dict get $machine name ]
        #item 1494
        set has_final_state \
        [ dict get $machine "last" ]
        #item 1495
        set parameters \
        [ parse_machine_parameters \
          [ dict get $machine parameters ]]
        #item 1496
        if {[ dict exists \
  $parameters name ]} {
            #item 1500
            set name \
            [ dict get $parameters name]
            #item 1501
            puts $fhandle [ join [ list \
            "${indent}// FSM '$name'" \
            " from diagram '$original_diagram'" ]]
        } else {
            #item 1504
            puts $fhandle [join \
            [ list \
            "${indent}// FSM from " \
            "diagram '$original_diagram'" ]]
            #item 1505
            set name \
            [ transliterate $original_diagram ]
        }
        #item 1506
        if {[ dict exists $parameters encoding ]} {
            #item 1509
            set fsm_encoding \
            [ lindex \
              [ dict get $parameters encoding ] \
              0 ]
        } else {
            #item 1510
            set fsm_encoding \
            "normal"
        }
        #item 1511
        set num_states \
        [ llength $states ]
        #item 1512
        if {$has_final_state} {
            #item 1515
            set num_states \
            [ expr "$num_states + 1" ]
        } else {
            
        }
        #item 1517
        set state_width \
        [ get_state_width \
          $fsm_encoding $num_states ]
        #item 1516
        set state_codes \
        [ build_state_codes \
          $fsm_encoding $num_states ]
        #item 1518
        set states_rename_table \
        {}
        #item 1519
        set state_names_table \
        {}
        foreach state $states {
            #item 2007
            set state \
            [ normalize_state_name $state ]
            #item 1522
            set state_wo_prefix \
            [ regsub {^[0-9]+_} $state "" ]
            #item 1523
            set vlog_state_name \
            [ string toupper \
              [ to_verilog_name \
                "${name}_${state_wo_prefix}" ] ]
            #item 1524
            lappend state_names_table \
              [list $vlog_state_name \
                    $state_wo_prefix]
            #item 1525
            dict set states_rename_table \
              $state $vlog_state_name
            #item 1526
            dict set states_rename_table \
              $state_wo_prefix $vlog_state_name
        }
        #item 1527
        set vlog_halt_state_name \
        [ string toupper \
          [ to_verilog_name \
            "${name}_halt_state" ] ]
        #item 1528
        if {$has_final_state} {
            #item 1531
            dict set states_rename_table \
              "___halt_state___" \
              $vlog_halt_state_name
        } else {
            
        }
        #item 2038
        set first_state \
        [ get_first_state_name $machine ]
        #item 2040
        set first_state \
        [ normalize_state_name $first_state ]
        #item 2039
        set first_state_name \
        [ dict get \
          $states_rename_table \
          $first_state ]
        #item 1532
        puts $fhandle ""
        #item 1533
        puts $fhandle [ join [ list \
        "${indent}localparam " \
        "\[[expr "$state_width-1"]:0\]" \
        " // state codes of FSM '$name'" ]]
        #item 1545
        set last \
        [ expr \
          "[ llength $state_names_table ] - 1" ]
        #item 15340001
        set i 0
        while { 1 } {
            #item 15340002
            if {$i <= $last} {
                
            } else {
                break
            }
            #item 1546
            set state \
            [ lindex \
              $state_names_table $i]
            #item 1536
            set vlog_state_name \
            [ lindex $state 0 ]
            #item 1544
            set state_name \
            [ lindex $state 1 ]
            #item 1537
            if {$i == $last} {
                #item 1541
                set delim \
                ";"
            } else {
                #item 1540
                set delim \
                ","
            }
            #item 1543
            set state_code \
            [ lindex $state_codes $i ]
            #item 1542
            puts $fhandle [ join [ list \
            "${indent_next}$vlog_state_name = " \
            "$state_width'd${state_code}$delim" \
            " // [ normalize_state_name $state_name ]" ]]
            #item 15340003
            incr i
        }
        #item 1547
        if {$has_final_state} {
            #item 1551
            set last_code \
            [ lindex $state_codes end ]
            #item 1550
            puts $fhandle [ join [ list \
            "${indent}localparam " \
            "\[[expr "$state_width-1"]:0\] " \
            "$vlog_halt_state_name = " \
            "$state_width'd${last_code}; " \
            "// HALT state" ]]
        } else {
            
        }
        #item 1552
        set state_var \
        [ string tolower \
          [ to_verilog_name \
            "${name}_state" ] ]
        #item 1553
        puts $fhandle [ join [ list \
        "\n${indent}reg " \
        "\[[expr "$state_width-1"]:0\] " \
        "$state_var;\n" ]]
        #item 1554
        if {[dict exists \
  $parameters \
  ascii_state_names ]} {
            #item 1558
            puts $fhandle ""
            #item 1557
            set state_var_str \
            "${state_var}_name"
            #item 1559
            set max_len \
            0
            foreach state $state_names_table {
                #item 2030
                set state \
                [ lindex $state 1]
                #item 2031
                set state \
                [ normalize_state_name $state ]
                #item 1562
                set sl \
                [ string bytelength $state ]
                #item 1563
                if {$sl > $max_len} {
                    #item 1566
                    set max_len \
                    $sl
                } else {
                    
                }
            }
            #item 1567
            puts $fhandle [ join [ list \
            "${indent}reg " \
            "\[[expr "$max_len*8-1"]:0\] " \
            "${state_var_str}; " \
            "// ASCII decode of ${state_var}\n" ]]
            #item 1568
            puts $fhandle \
            "${indent}always @($state_var) begin"
            
            puts $fhandle \
            "${indent_next}case ($state_var)"
            foreach s $state_names_table {
                #item 1572
                set vlog_state_name \
                [ lindex $s 0 ]
                #item 1574
                set state_name \
                [ lindex $s 1 ]
                #item 1573
                set ascii_name \
                [ form_ascii_state_name \
                  $state_name \
                  $max_len ]
                #item 1571
                puts $fhandle [ join [ list \
                "${indent_3}" \
                "$vlog_state_name: " \
                "$state_var_str = " \
                "\"${ascii_name}\";" ]]
            }
            #item 1576
            if {$has_final_state} {
                #item 1580
                set ascii_halt \
                [ form_ascii_state_name \
                  "!HLT" \
                  $max_len ]
                #item 1579
                puts $fhandle [ join [ list \
                "${indent_3}" \
                "${vlog_halt_state_name}: " \
                "$state_var_str = " \
                "\"${ascii_halt}\";" ]]
            } else {
                
            }
            #item 1582
            set ascii_error \
            [ form_ascii_state_name \
              "!ERR" \
              $max_len ]
            #item 1581
            puts $fhandle [ join [ list \
            "${indent_3}default: " \
            "$state_var_str = " \
            "\"${ascii_error}\";" ]]
            #item 1583
            puts $fhandle \
            "${indent_next}endcase"
            #item 1584
            puts $fhandle [join [ list \
            "${indent}end " \
            "// decode of $state_var\n" ]]
        } else {
            
        }
        #item 1585
        set body \
        {}
        #item 1586
        lappend body \
        "case ($state_var)"
        foreach state $states {
            #item 2008
            set norm_state \
            [ normalize_state_name $state ]
            #item 1589
            set vlog_state_name \
            [ dict get \
              $states_rename_table \
              $norm_state ]
            #item 1590
            append body " "
            #item 1591
            append body \
              [ get_state_body \
                  $fhandle \
                  $gdb \
                  $functions \
                  $state \
                  $original_diagram \
                  $vlog_state_name \
                  $state_var \
                  $states_rename_table \
                  1 ]
        }
        #item 1595
        append body " "
        #item 1592
        if {$has_final_state} {
            #item 1597
            set halt_state_name \
            [dict get \
              $states_rename_table \
              "___halt_state___" ]
            #item 1596
            append body \
              [ get_final_state_code \
                  $fhandle \
                  $halt_state_name \
                  $state_var \
                  $indent ]
            #item 1598
            append body " "
            #item 2032
            lappend body \
            "${indent}default: "
            
            lappend body \
            "${indent_next}$state_var <= $halt_state_name;"
        } else {
            #item 2037
            lappend body \
            "${indent}default: "
            
            lappend body \
            "${indent_next}$state_var <= $first_state_name;"
        }
        #item 1599
        lappend body \
          "endcase // case ($state_var)"
        #item 1601
        set setup_first_state \
        "$state_var <= $first_state_name"
        #item 1602
        set always_block \
        [ build_always_block \
          $name \
          "always" \
          $parameters \
          [ list "$setup_first_state" ] \
          $body ]
        #item 1603
        puts $fhandle $always_block
    }
}

proc process_insertions_refs { insertions body } {
    #item 1746
    set result \
    {}
    foreach line $body {
        #item 1749
        if {[ regexp "##@@insertion:(.*)@@##" \
    $line _ name ]} {
            #item 2055
            set indent_n \
            [ get_indent_from_string \
              $line ]
            #item 2011
            set name_body \
            [ dict get $insertions $name ]
            #item 2029
            set body \
            [ lindex $name_body 1 ]
            #item 2109
            set body \
            [concat \
              [list "// sub: '$name'" ] \
              $body \
              [list "// end: '$name'" ]]
            #item 2056
            set body \
            [ get_body $body $indent_n]
            #item 2057
            set body \
            [ split $body "\n" ]
            #item 1755
            set result \
            [concat $result $body]
        } else {
            #item 1752
            lappend result $line
        }
    }
    #item 1754
    return $result
}

proc remove_comment { line } {
    #item 1669
    regsub -all {//.*$} $line "" line
    #item 1670
    set line \
    [ string trim "$line" " \t;" ]
    #item 1671
    return $line
}

proc rename_states { state_var states_rename_table body } {
    #item 1275
    set result \
    {}
    foreach line $body {
        #item 1279
        set needs_rename \
        [ regexp \
          "##@@next_state:(.+)@@##" \
          $line \
          _ \
          state]
        #item 1280
        if {$needs_rename} {
            #item 2062
            set indent_n \
            [ get_indent_from_string $line ]
            #item 2063
            set indent \
            [ make_indent $indent_n ]
            #item 1283
            set state \
            [ dict get \
              $states_rename_table \
              $state ]
            #item 1284
            set line \
            "${indent}$state_var <= $state;"
        } else {
            
        }
        #item 1285
        lappend result $line
    }
    #item 1276
    return $result
}

proc shelf { primary secondary } {
    #item 531
    return "##@@shelfstart@@##$secondary##@@shelfop@@##$primary##@@shelfend@@##"
}

proc to_verilog_name { name } {
    #item 1867
    set name \
    [ transliterate $name ]
    #item 1053
    set name \
    [ regsub -all "\[^0-9A-Za-z\]" \
        $name "_" ]
    #item 1054
    return $name
}

proc transform_shelf { keyword operator body } {
    #item 543
    set text \
    {}
    #item 544
    if {$keyword == ""} {
        
    } else {
        #item 547
        set keyword \
        "$keyword "
    }
    #item 548
    if {$operator == ""} {
        
    } else {
        #item 551
        set operator \
        " $operator "
    }
    foreach line $body {
        #item 555
        regsub -all "##@@shelfstart@@##" "$line" "$keyword" line_new
        #item 556
        regsub -all "##@@shelfop@@##" "$line_new" "$operator" line_new
        #item 557
        regsub -all "##@@shelfend@@##" "$line_new" ";" line
        #item 558
        lappend text $line
    }
    #item 559
    return $text
}

proc transliterate { text } {
    #item 2121
    set map \
    [concat \
    "\u0410\u0020\u0041\u0020\u0411\u0020\u0042\u0020\u0020\u0412\u0020" \
    "\u0056\u0020\u0413\u0020\u0047\u0020\u0020\u0414\u0020\u0044\u0020" \
    "\u0020\u0415\u0020\u0045\u0020\u0401\u0020\u0059\u004F\u0020\u0416" \
    "\u0020\u004A\u0020\u0020\u0417\u0020\u005A\u0020\u0020\u0418\u0020" \
    "\u0049\u0020\u0020\u0419\u0020\u0059\u0020\u0020\u041A\u0020\u004B" \
    "\u0020\u041B\u0020\u004C\u0020\u0020\u041C\u0020\u004D\u0020\u041D" \
    "\u0020\u004E\u0020\u0020\u041E\u0020\u004F\u0020\u0020\u041F\u0020" \
    "\u0050\u0020\u0020\u0420\u0020\u0052\u0020\u0421\u0020\u0053\u0020" \
    "\u0020\u0422\u0020\u0054\u0020\u0020\u0423\u0020\u0055\u0020\u0020" \
    "\u0424\u0020\u0046\u0020\u0020\u0425\u0020\u0048\u0020\u0020\u0426" \
    "\u0020\u0043\u0020\u0427\u0020\u0043\u0048\u0020\u0428\u0020\u0053\u0048" \
    "\u0020\u0429\u0020\u0053\u0048\u0020\u042A\u0020\u004A\u0020" \
    "\u0020\u042B\u0020\u0049\u0020\u0020\u042C\u0020\u004A\u0020\u042D" \
    "\u0020\u0045\u0020\u0020\u042E\u0020\u0059\u0055\u0020\u042F\u0020" \
    "\u0059\u0041\u0020\u0430\u0020\u0061\u0020\u0020\u0431\u0020\u0062" \
    "\u0020\u0020\u0432\u0020\u0076\u0020\u0433\u0020\u0067\u0020\u0434" \
    "\u0020\u0064\u0020\u0435\u0020\u0065\u0020\u0451\u0020\u0065\u0020" \
    "\u0436\u0020\u0067\u0020\u0437\u0020\u007A\u0020\u0020\u0438\u0020" \
    "\u0069\u0020\u0439\u0020\u006A\u0020\u043A\u0020\u006B\u0020\u043B" \
    "\u0020\u006C\u0020\u043C\u0020\u006D\u0020\u043D\u0020\u006E\u0020" \
    "\u043E\u0020\u006F\u0020\u043F\u0020\u0070\u0020\u0440\u0020\u0072" \
    "\u0020\u0441\u0020\u0073\u0020\u0442\u0020\u0074\u0020\u0443\u0020" \
    "\u0075\u0020\u0444\u0020\u0066\u0020\u0445\u0020\u0068\u0020\u0446" \
    "\u0020\u0063\u0020\u0447\u0020\u0063\u0068\u0020\u0448\u0020\u0073\u0068" \
    "\u0020\u0449\u0020\u0073\u0068\u0020\u044A\u0020\u006A\u0020" \
    "\u0020\u044B\u0020\u0069\u0020\u0020\u044C\u0020\u006A\u0020\u044D" \
    "\u0020\u0065\u0020\u044E\u0020\u0079\u0075\u0020\u044F\u0020\u0079\u0061\u0020"]
    #item 1060
    set text \
    [ string map  $map $text ]
    #item 1061
    return $text
}

proc trim_lines { lines trim_chars } {
    #item 2117
    set result \
    {}
    foreach line $lines {
        #item 2118
        set line \
        [string trim \
          $line \
          $trim_chars ]
        #item 2119
        lappend result $line
    }
    #item 2120
    return $result
}

proc undo_monkey_patch { } {
    #item 2131
    set direction "reverse"
    #item 2132
    monkey_patch_gen $direction
    monkey_patch_graph $direction
    monkey_patch_sma $direction
}

# end of namespace verilog_gen
} 

namespace eval sma {

    variable g_last_present
    set g_last_present 0

proc all_start_with_receive_vlog { gdb diagram_id } {
	variable g_last_present
	set g_last_present 0
	#item 270
	set headers [ get_headers $gdb $diagram_id ]
	#item 271
	set count [ llength $headers ]
	#item 272
	set last \
	    [expr {$count - 1}]
	#item 2820001
	set i 0
	while { 1 } {
	    #item 2820002
	    if {$i < $last} {
		
	    } else {
		#item 294
		set last_header [ lindex $headers $last ]
		#item 295
		if {[starts_with_receive $gdb $last_header]} {
		    #item 299
		    #                bad_vertex $gdb $header \
								  #                 "Exit branch should not start with a 'receive'."
		    #item 298
		    set g_last_present 0
		    set result 1
		} else {
		    #item 300
		    set g_last_present 1
		    set result 1
		}
		break
	    }
	    #item 284
	    set header [ lindex $headers $i ]
	    #item 289
	    if {[starts_with_receive $gdb $header]} {
		
	    } else {
		#item 293
		bad_vertex $gdb $header \
		    "State branch should start with a 'receive'."
		#item 292
		set result 0
		break
	    }
	    #item 2820003
	    incr i
	}
	#item 288
	return $result
    }

proc build_machine_vlog { gdb diagram_id callbacks } {
    variable g_last_present
    #item 164
    clear_last
    #item 262
    set receives [ get_receives $gdb $diagram_id ]
    #item 263
    if {$receives == {}} {
        #item 264
        bad_diagram $diagram_id \
         "No 'receive' statements found."
    } else {
        #item 165
        if {(([has_branches $gdb $diagram_id]) && ([receives_are_first $gdb $receives])) && ([all_start_with_receive $gdb $diagram_id])} {
            #item 344
            set parameters [ get_params_text $gdb $diagram_id ]
            #item 352
            set headers [ get_headers $gdb $diagram_id ]
	          if { $g_last_present  } {
		           set state_headers [ lrange $headers 0 end-1 ]
		           set last_branch [ lindex $headers end ]
		           set last_name [ get_text $gdb $last_branch ]
		        } else {
		           set state_headers [ lrange $headers 0 end ]
		           set last_branch -1
		           set last_name "##@@Unused@@##"
		        }
            #item 353
            set message_types [ find_message_types $gdb $state_headers ]
            set state_names {}
            #item 755
            set boiler {}
            #item 3540001
            set _col354 $state_headers
            set _len354 [ llength $_col354 ]
            set _ind354 0
            while { 1 } {
                #item 3540002
                if {$_ind354 < $_len354} {
                    
                } else {
                    break
                }
                #item 3540004
                set header [ lindex $_col354 $_ind354 ]
                #item 754
                lassign \
                [create_sub_diagrams $gdb $diagram_id $header $message_types \
                 $parameters $last_name $callbacks] \
                state good bad
                #item 756
                lappend boiler $state \
                 [ list "good" $good "bad" $bad ]
                lappend state_names $state
                #item 3540003
                incr _ind354
            }
        } else {
            
        }
    }
    #item 757
    set last [ is_last_used ]
    #item 766
    set param_names [ get_param_names $parameters ]
    #item 870
    set dia_name [ diagram_name $gdb $diagram_id ]
    #item 758
    return [ list "last" $last "boiler" $boiler \
     "states" $state_names "messages" $message_types \
     "parameters" $parameters "param_names" $param_names \
     "name" $dia_name ]
}

proc find_end_vlog { gdb diagram_id } {
	#item 659
	$gdb eval {
	    select item_id, text
	    from vertices
	    where diagram_id = :diagram_id
	} {
	    if { [ graph::p.is_end $text ] } {
    		return $item_id
	    }
	}
	return [ insert_vertex $gdb $diagram_id "beginend" "End" ]
}

proc message_types_for_select_vlog { gdb select } {
	lassign [ get_type_text $gdb $select ] icon_type _
	if { $icon_type == "action" } { return [list ""] }
	#item 408
	set next [ find_next $gdb $select ]
	#item 409
	set result {}
	#item 4110001
	set _col411 $next
	set _len411 [ llength $_col411 ]
	set _ind411 0
	while { 1 } {
	    #item 4110002
	    if {$_ind411 < $_len411} {
		
	    } else {
		break
	    }
	    #item 4110004
	    set case [ lindex $_col411 $_ind411 ]
	    #item 413
	    set text [ get_text $gdb $case ]
	    #item 417
	    lappend result $text
	    #item 4110003
	    incr _ind411
	}
	#item 410
	return $result
    }

}

namespace eval gen {

proc p.rewire_for_vlog { gdb start end parts append_semicolon } {
	set diagram_id [ p.vertex_diagram $gdb $start ]
	lassign $parts init check advance
	set item_id [ p.vertex_item $gdb $start ]
	set for_id [ p.insert_vertex $gdb $diagram_id [ append_digits $item_id 0002 ] "action" "for($init;$check;$advance) begin" "" 0 ]
	set endfor_id [ p.insert_vertex $gdb $diagram_id [ append_digits $item_id 0003 ] "action" "end" "" 0 ]
	set loop [ p.get_next $gdb $start 2 ]
	set after_loop [ p.get_next $gdb $start 1 ]
	p.relink $gdb $start $for_id
	p.link $gdb $for_id 1 $loop
	p.relink $gdb $end $endfor_id
	p.link $gdb $endfor_id 1 $after_loop
	$gdb eval {
	    delete from links where src = :start;
	    delete from vertices where vertex_id in (:start, :end);
	}	
}


proc fix_shelves { gdb callbacks append_semicolon diagram_id } {
	set shelf_proc [ get_callback $callbacks shelf ]
	
	set shelves [ $gdb eval {
	    select item_id
	    from items
	    where diagram_id = :diagram_id
	    and type = 'shelf'
	} ]
	
	foreach shelf $shelves {
	    process_shelf $gdb $shelf $shelf_proc
	}
}
    
}

namespace eval graph {

proc p.find_starts_vlog { diagram_id } {
	variable end_text_rus
	set ends_count 0
	set starts {}
	gdb eval {
	    select vertex_id, type, text, up, left, right, down, item_id
	    from vertices
	    where diagram_id = :diagram_id
	    and type = 'beginend'
	    order by x
	} {
	    if { $left != "" } {
		p.unexpected_edge $left
	    } elseif { $down == "" && $right != "" } {
		p.unexpected_edge $right
	    } elseif { $down != "" && $up != "" } {
		p.unexpected_edge $up
	    } elseif { $down == "" && $up == "" } {
		p.error $diagram_id [ list $item_id ] [ mc2 "Disconnected icon." ]
	    }
	    
	    if { $down == "" } {
		if { [ p.is_end $text ] } {
		    incr ends_count
		} else {
		    set end [texts::get end]
		    p.error $diagram_id $item_id [ mc2 "'End' icon should have the text '\$end'" ]
		}
	    } else {
		lappend starts $vertex_id
	    }
	}
	
	#	if { $ends_count != 1 } {
	#		p.error $diagram_id {} [ mc2 "The diagram must have exactly one end." ]
	#	}
	if { [ llength $starts ] == 0 } {
	    p.error $diagram_id {} [ mc2 "The diagram must have one or more starts." ]
	}
	return $starts
}

proc is_machine_vlog { diagram_id } {

	if { ![ mwc::is_drakon $diagram_id ] } { return 0 }

	set name [ gdb onecolumn { 
	    select name
	    from diagrams
	    where diagram_id = :diagram_id } ]
	
	set name [ string tolower $name ]
	if { $name == "state machine" } { return 1 }

	
	set starts [ p.find_starts $diagram_id ]
	set start [ lindex $starts 0 ]
	
	set text [ gen::p.vertex_text gdb $start ]
	set trimmed [ string trim $text ]

	if { [ string match "state machine*" $trimmed ] } {
	    return 1
	}
	
	set params_icon [ p.get_params $start ]
	if { $params_icon == "" } { return 0 }

	set text [ gen::p.vertex_text gdb $params_icon ]
	set trimmed [ string trim $text ]

	if { [ string match "state machine*" $trimmed ] } {
	    return 1
	}

	return 0
}


proc copy_from_vlog { db } {
	graph2::reset.counter
	
	p.create_db
	$db eval {
	    select item_id, diagram_id, type, text, text2, x, y, w, h, a, b
	    from items
	} {
	    if { $type == "parallel" } {
		set message [ mc2 "Elements of type '\$type' are not supported by the verifier yet." ]
		p.error $diagram_id $item_id $message
	    }
	    if { $type == "process" } {
		set type "action"
	    }
	    
	    if { $type == "output" } {
		set type "shelf"
	    }
	    
	    if { $type == "input" } {
		set type "shelf"
		set tmp $text2
		set text2 $text
		set text $tmp 
	    }

	    if { $type == "insertion" } {
		set type "action"
		set text [::verilog_gen::normalize_insertion_name $text]
		set text "##@@insertion:${text}@@##"
	    }

	    gdb eval {
		insert into items(item_id, diagram_id, type, text, text2, x, y, w, h, a, b)
		values (:item_id, :diagram_id, :type, :text, :text2, :x, :y, :w, :h, :a, :b)
	    }
	}
	
	$db eval {
	    select diagram_id, name
	    from diagrams
	} {
	    gdb eval {
		insert into diagrams (diagram_id, name)
		values (:diagram_id, :name)
	    }
	}
}

# спец обработка графа для верилога
proc verify_all_vlog { db } {
	verilog_gen::do_monkey_patch
	
	if { [ catch {
		verify_all_std $db
	} message ] } {
		verilog_gen::undo_monkey_patch
		error $message
	} else {
		verilog_gen::undo_monkey_patch
	}
}

}
